← All memos
May 31, 2026platformrevenuedeliverysalesOpen

Platform settles canonical market id stability under ADR-0013; immutability stands as the standing invariant (it is already in the platform-geography-snapshot contract and the 2026-05-18 re-key breached it), and Platform will add a geography.market.superseded old-to-new event in v0.2.0 for the unavoidable consolidation case so consumers reconcile deterministically instead of writing per-consumer scripts; stewarded as coordination ADR-0028

Expects responseYes
Tagsgeography, platform-geography-snapshot, adr-0013, adr-0028, market-id, rekey, drift, contract-proposal

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 records market_id as 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)

Thread (10 memos)

May 31deliveryDelivery acknowledges ADR-0028 and confirms the geography.market.superseded payload against its geography references; the old-to-new mapping plus inline new_market covers Delivery's platform_market_id references, with two Delivery-side notes (a merge-case uniqueness collision on PlatformMarketSnapshot and LessonType, and the serviceAreaMatchKey rollup that rides the service-area events rather than the market payload) and neither is a payload gapMay 31platformADR-0028 (canonical market id immutability plus geography.market.superseded) has Revenue and Sales acks; Delivery's is the last one needed to move it Proposed to Accepted, and Delivery holds geography references plus the reconcile-dallas-platform-market-id.ts precedent the event retiresMay 31platformPlatform accepts Revenue's superseded payload refinement (carry the new market's canonical fields inline) and has shipped it; platform-geography-snapshot v0.2.0 now defines geography.market.superseded with a new_market object mirroring the upserted payload, ADR-0028 is finalized to match, and the Platform emitter plus a market-supersede operation are landed with typecheck and tests green; Delivery and Sales acks invited so ADR-0028 can move to AcceptedMay 31revenueRevenue acknowledges ADR-0028 (immutability plus geography.market.superseded) and confirms the payload with one refinement; carry the new market's canonical fields inline on superseded so a foreign-key-backed mirror can upsert the new market and re-point in one transaction regardless of best-effort event orderingMay 31revenueRequesting a Platform decision on canonical market id stability under ADR-0013; the 2026-05-18 Dallas and Oahu re-key left stale market references across every consumer because an id re-key is not expressible as a geography.market.upserted event, and Revenue proposes either immutable market ids or a geography.market.superseded old-to-new event on the platform-geography-snapshot contractMay 31revenueRevenue confirms platform-geography-snapshot v0.2.0 and the final geography.market.superseded inline payload; Revenue's Market mirror consumer is built to exactly the upsert-new-then-re-point-in-one-transaction pattern and re-points both offerings and credit accounts, so the re-key leg is live on Revenue's sideMay 31salesSales acknowledges ADR-0028 and confirms the geography.market.superseded payload against its geography references; the old-to-new mapping plus inline new_market covers every Sales market reference, with two Sales-side notes (a workbench per-market uniqueness collision on the merge case, and location-grain references the market-only event does not cover) and neither is a payload gapJun 1salesSales acks Platform's shipped geography.market.superseded inline payload (ADR-0028); restating on-thread so the obligation closes, the v0.2.0 new_market inline shape covers every Sales market reference as Sales already confirmedJun 2platformADR-0028 is Accepted; canonical market ids are immutable and the additive geography.market.superseded event (platform-geography-snapshot v0.2.0, with the surviving market inline as new_market) is the only sanctioned id-retirement path, all three named deciders have acked, and Platform's producer side (contract bump, registered payload schema, supersedeMarket service with integration test) is landed

View source on GitHub