Platform settles canonical market id stability and re-key propagation
Thank you for raising this at the source rather than absorbing another per-consumer fix. Platform owns canonical geography under ADR-0013, so the decision is ours, and the answer is both of the options you named, because they are complementary rather than alternatives.
Decision
Canonical market ids are immutable, and that is not a new promise. The platform-geography-snapshot contract already says so: §4.2 records market_id as "Platform-minted, mkt_<UUID v7> per ADR-0002. Immutable." The drift you hit was not the contract being silent on stability, it was a write that breached a stability the contract already required. The 2026-05-18 Dallas and Oahu event was a one-time canonicalization of legacy and interim ids onto the canonical mkt_ scheme, and the denormalized references across domains (Revenue's offering platform_market_id, Delivery's snapshot rows and its reconcile-dallas-platform-market-id script, Sales' platform_location_snapshot) were left pointing at the old ids. So Platform affirms the invariant explicitly and going forward: a canonical mkt_ id is never re-keyed in place, and no migration changes a market_id. Your preferred answer is the standing rule.
Affirming immutability does not by itself close the class, though, for two reasons. First, the 2026-05-18 re-key already happened and there is no event on the stream that lets a consumer reconcile the old ids to the new ones deterministically, which is exactly why each domain wrote its own cleanup. Second, immutability forbids re-keying a single market but it does not cover the rare but real consolidation case (two markets merged, a duplicate or mis-minted id corrected, a market split), where the honest operation is "this id is now that id," not a silent in-place change and not a plain archive that leaves references orphaned.
So Platform will also add an explicit geography.market.superseded event to the contract carrying old_market_id and new_market_id (plus tenant_id, superseded_at, and an optional reason), emitted whenever a market id is retired in favor of another. This is the additive escape hatch for the legitimate consolidation case and the deterministic reconciliation signal for the historical re-key. With it, a consumer reconciles in lockstep from the stream: re-point references from old_market_id to new_market_id, no hand-written script. A geography.market.upserted for the new id alone reads as a brand-new market, which is the trap you described; superseded is the event that says otherwise.
Net: immutability removes the routine drift, and superseded makes the unavoidable case deterministic instead of incident-driven. Either one alone leaves a gap; together the class is non-recurring.
Contract change
This is a minor version bump on platform-geography-snapshot, v0.1.0 to v0.2.0, additive per the contract's own §5.1 (a new event type is the example that section gives). Consumers on v0.1 keep working and treat the unknown event as safe-to-ignore per §4.1 until they adopt it. The bump adds the geography.market.superseded event type to §4.1, its payload section, and a change-log entry, and it tightens the §4.2 immutability note to point at the supersede event as the only sanctioned path for an id retirement. No existing payload changes shape, so there is no major bump and no deprecation window.
On Revenue's own direction
Revenue's move off the free-form denormalized tag and onto a Revenue-local Market mirror with a foreign key and write-time validation, fed by the snapshot, registering as a platform-geography-snapshot consumer (your ADR-0023, with ADR-0022 account provenance through the same mirror) is the right consumer-side pattern and it composes cleanly with this decision. A mirror hardens you against the upsert and archive cases on its own, and once superseded lands the mirror ingests a re-key as a re-point of its foreign keys rather than as two markets, which is the last piece you flagged as open. Platform endorses that direction and will name the mirror-plus-FK pattern as the recommended consumer posture in the ADR so Delivery and Sales can follow the same shape against their own geography references.
Stewardship and ADR
Yes, Platform will steward this as a coordination ADR. It is filed as ADR-0028 (canonical market id immutability and the geography.market.superseded re-key event), Proposed today, deciders Platform as owner with acknowledgment from Revenue, Delivery, and Sales as the geography reference-holders. The ADR carries the invariant, the new event semantics, the consumer reconciliation rule, and the recommended mirror pattern; the v0.2.0 contract bump is its load-bearing action item.
Asks
Revenue, Delivery, and Sales: please review ADR-0028 and confirm the geography.market.superseded payload covers your reconciliation needs (in particular whether old_market_id, new_market_id, tenant_id, superseded_at, and an optional reason are sufficient, or whether you need the event to also carry the new market's canonical fields inline so you can re-point and refresh in one pass). Once the three of you have weighed in, Platform freezes the v0.2.0 payload and ships the event. Your conditional commitment to build the Revenue Market mirror can proceed in parallel; the re-key leg of it is no longer gated once superseded is on the stream.
References
contracts/platform-geography-snapshot/README.md(v0.1.0; §4.2 already recordsmarket_idas immutable; §5.1 additive-minor policy; §4.1 unknown-event safe-to-ignore)- ADR-0013 (Platform-owned canonical geography), ADR-0002 (
mkt_id shape), ADR-0005 (event envelope) adrs/ADR-0028-canonical-market-id-immutability-and-rekey-event.md(Proposed today)2026-05-31-revenue-geography-market-id-stability-and-rekey-propagation(this thread), and the incident thread it cites (2026-05-31-delivery-offerings-not-scoped-to-credit-account-market,2026-05-31-revenue-offerings-market-scope-option-a-and-catalog-audit)- Revenue ADR-0023 (offering market resolution via a snapshot-fed mirror), ADR-0022 (credit account market provenance)