# CleanedWeb data contract and provenance

This guide explains the semantics around the global `property-profile-v2` contract. The JSON Schema
remains authoritative for structure. The machine-readable field catalog is
`https://cleanedweb.com/schemas/property-profile-field-catalog-v2.json`.

## Identity

- `property_entity_id` is the canonical upsert key.
- `sources[].listings[].listing_id` is local to one source advertisement and must not replace
  canonical identity.
- Preserve `sources` with the canonical record. It is the provenance boundary for
  source URLs, listing identifiers, advertiser details, and contact channels.
- Derive source and listing counts from the grouped `sources` collection when needed.
  Neither count is a completeness guarantee for the market.

CleanedWeb can improve entity resolution over time. Consumers must treat a previously
unknown identifier as a new canonical entity and must not merge two identifiers based
only on address text, title, coordinates, or an agent name.

## Missing, unknown, hidden, and placeholder values

Optional values are omitted when no delivery-safe value exists. Do not turn an omitted
field into an empty string, zero, `false`, or an inferred fact.

Use explicit enum values only where the schema defines them:

- `location.precision: "unknown"` means location granularity is not established.
- `sources[].listings[].pricing.quality: "known"` authorizes use of a delivered numeric price.
- `sources[].listings[].pricing.quality: "hidden"` means the advertiser withheld the price.
- `sources[].listings[].pricing.quality: "placeholder"` means an observed value was not a usable asking price.
- `sources[].listings[].pricing.quality: "missing"` means no delivery-safe price was retained.
- Advertiser `unknown` values are classifications, not permission to guess a type.

## Units and normalization

- `property.floor_area` and `property.land_area` are delivered in square metres.
- Latitude and longitude use WGS84 decimal degrees.
- Currency is an uppercase ISO 4217 code. CleanedWeb does not imply currency conversion.
- Dates and timestamps use the formats declared by JSON Schema.
- Room definitions, floor conventions, and advertised area definitions can vary by
  source market. Normalization does not erase that real-world boundary.

## Freshness

`snapshot.dataUpdatedAt` is the latest successful rebuild time of the maintained serving
projection. It is not the API request time and it does not promise that every source was
observed at that instant.

Listing `first_observed_at` and `observed_at` values describe retained CleanedWeb
observations. They are not construction, transaction, publication, or legal event dates.

## Property facts and source assertions

Recurring building facts such as construction year, condition, energy class, structure,
heating, parking, and orientation are canonical only when one retained current source
reports the value or all reporting sources agree. When current sources conflict, the
canonical field is omitted and the source-specific values can remain under
`sources[].listings[].unit`.

`property.amenities`, `property.features`, and `property.construction_materials` are
deduplicated unions of current source advertisements. They mean that at least one retained
source reported the value; they are not independent physical inspections. Structure and
construction material are separate concepts and are not silently converted into each other.

## Area context and marketplace observations

Property profiles can store an immutable `context.area_profile_ref`, not a copied area
profile. Each referenced area fact retains its source, vintage, measurement geography,
derivation status, confidence, and limitation. Missing area context leaves the property
result usable and does not alter its availability.

Marketplace advertisements are grouped as `sources[].listings[]`. Every distinct
listing keeps its source-local ID, links, deal type, status, asking price, discounts and
fees, unit facts, content, availability actions, metrics, attribution, and advertiser or
contact details. Source media remains internal and is not exposed in the customer profile.
Official identifiers and records are included only where an authoritative source and a
defensible link to the property entity are available.

## Contact and source data

Delivered agency, agent, phone, email, website, and contact-form values are observations
from source advertisements. Presence does not prove current reachability, ownership,
consent, licensing, or a legal basis for a downstream communication. Consumers remain
responsible for their use of contact data.

## Acceptance requirements

Before persisting a response, require:

1. `returned === results.length`.
2. Every result uses `property-profile-v2`.
3. Every `property_entity_id` is non-empty and unique within the response.
4. `snapshot.dataUpdatedAt` meets the consumer's declared freshness policy.
5. `has_more === false` after aggregating cursor pages, or one complete
   unbounded response, when the workflow requires a complete result.
6. Source provenance is retained beside the canonical entity.

Do not infer readiness, entitlement, availability, completeness, or cost from this static
guide. Read runtime capabilities and authenticated market metadata.
