← All memos
May 9, 2026platformgrowthsalesdeliveryrevenuecoachingFYI

Identity Contract v1 is production-live; canonical Person surface live in Postgres with 22 Persons + 38 PersonExternals seeded against org_sguild, all three v1 HTTP endpoints serving (Person-by-id, externals reverse-lookup, Guardian-aware comms-routing), mergePersons external reattachment per ADR-0010 Shape A landed and integration-tested, Q2 directive's v1-ship commitment closes 37 days early, the original P0 XL Identity v1 ledger entry on the platform-owed root flips from pending to completed

Tagsidentity, identity-contract-v1, person, person-external, guardian, mergePersons, adr-0003, adr-0010, platform-roadmap, ship-announcement, q2-directive

Identity Contract v1 is production-live; canonical Person surface live in Postgres with 22 Persons + 38 PersonExternals seeded against org_sguild, all three v1 HTTP endpoints serving (Person-by-id, externals reverse-lookup, Guardian-aware comms-routing), mergePersons external reattachment per ADR-0010 Shape A landed and integration-tested, Q2 directive's v1-ship commitment closes 37 days early, the original P0 XL Identity v1 ledger entry on the platform-owed root flips from pending to completed

Date: 2026-05-09 From: Platform To: Growth, Sales, Delivery, Revenue, Coaching Status: FYI. Ship announcement, no asks. The Q2 directive's Identity Contract v1 ship commitment (P0 XL, due 2026-06-15) closes today, 37 days early, and the merge-case response memo's mergePersons implementation commitment (P1 M, due 2026-06-15) closes alongside it.

What is live

Identity Contract v1's operational surface is live in Postgres against the Sguild Organization (org_sguild). The contract's three HTTP endpoints serve canonical-shape responses today:

GET /api/identity/v1/person/{personId} returns the canonical nine-field Person record per contracts/identity/person-canonical-fields.md. The route is wired through the per-domain module pattern at platform/modules/person/routes/person.routes.ts against the Postgres person table. Returns 200 with the canonical shape on hit, 404 on miss; resolves one alias_of hop transparently per Identity Contract §9.4.

GET /api/identity/v1/externals/lookup?provider=...&organization_id=...&external_id=... returns the canonical person_id for an inbound provider webhook payload per person-externals.md §5.2. Backed by the partial reverse-lookup index person_external_active_reverse_lookup shipped 2026-05-02 in prisma/migrations/20260502180000_person_external_partial_indexes/migration.sql. Returns null when no non-retired match exists; webhook handlers MUST handle null gracefully per the sub-spec §6.5.

GET /api/identity/v1/comms-routing/{personId} returns the Person who should receive outbound communications for the queried person_id (the Person themselves for adults, the Guardian for minors) per Identity Contract §10.6. Sales and Delivery both call this endpoint before any outbound send per the contract's comms-routing rule.

The data layer carries 22 canonical Persons (minted from legacy Airtable Clients via scripts/mint-persons-from-csv.ts on 2026-05-02 with the phone-based identity match) and 38 active PersonExternals (minted from legacy Client Externals via scripts/mint-externals-from-csv.ts on 2026-05-09 against org_sguild). The Sguild Organization itself was seeded as part of the Phase 2 mint via the --ensure-org bootstrap flag.

The mergePersons implementation in platform/modules/person/service.ts now wraps the canonical-field promotion, the alias mark-merged write, and the externals reattachment in a single Prisma $transaction per the contract guarantee in person-externals.md §5.4. The reattachment flow follows ADR-0010 Shape A (retire-then-rekey on (organization_id, provider, provider_environment) collision; plain-rekey otherwise; older created_at survives active when both pre-merge Persons hold externals on the same tuple). Three integration test scenarios in platform/scripts/test-identity-integration.ts cover the three branches: no externals on either side, alias-only externals with no canonical collision, and the colliding-tuple case with audit-trail coexistence on the canonical Person.

The Guardian table is stood up at the schema layer (prisma/migrations/20260502170444_init_identity includes the guardian table). Guardian relationships are populated at runtime via the Person + Guardian APIs as new minors enroll per the existing scope decision in mint-persons-from-csv.ts (Students are not migrated from Airtable; minors enroll fresh in Postgres). The comms-routing endpoint already walks Guardian when is_minor=true is detected.

What this unblocks

Revenue's Square webhook handlers can call the reverse-lookup endpoint as the production identity-resolution path today. The 22 Persons + 38 externals cover the historical Square customer set; new webhook payloads referencing a previously-unknown customer_id resolve via the same endpoint after a registerExternal write happens (which Revenue's webhook handler does as part of its onboarding flow). Revenue's Q3/Q4 Postgres migration timeline per 2026-05-09-revenue-q2-airtable-sunset-scoping action items 6 and 7 stays as Revenue scoped it; v1 ship just gives Revenue an earlier-than-Q3 forward-looking-integration-test surface to wire against.

Sales' consumer-side intake.matched-driven Person attachment per 2026-05-09-sales-q2-airtable-sunset-scoping can now wire against the live Person-by-id endpoint. Sales' Lead pipeline migration per the Q2 directive can scaffold against canonical Person reads today; the mergePersons external reattachment landing means Sales does not need to defend against the Lead-merge-loses-externals failure mode separately.

Delivery's coach-day planner per 2026-05-13-delivery-q2-airtable-sunset-scoping reads of "this lesson's Person" for the customer-tracking record can hit the canonical surface today. The Tenancy Junction is the remaining piece for Delivery's Lessons-keyed reads of (Person, Organization) tenancy state; that lands during the CL-PLT-0002 cutover window 2026-06-22 to 2026-06-26 per the Q2 directive.

Coaching's coach-availability projection per 2026-05-09-coaching-airtable-sunset-scoping-commit consumes Person identity through the cut-over migration guide that ships with Dispatcher SDK Phase 3 (2026-06-29 per the Q2 directive). v1 ship today doesn't change Coaching's calendar; Coaching's projection-based reads cut over against canonical Person identity that is now live.

Growth's intake.matched consumer wiring per 2026-05-09-growth-q2-airtable-sunset-scoping reads the canonical Person on backfill; Growth's wiring is downstream of Dispatcher SDK Phase 2 ship (2026-06-22 per the directive). Identity v1 ship today is the upstream prerequisite Growth's consumer wiring assumes; that prerequisite is now satisfied.

What this does NOT change

The Q2 directive's broader ship calendar is unchanged. Dispatcher SDK Phase 2 still 2026-06-22, Phase 3 still 2026-06-29, CL-PLT-0002 cutover still 2026-06-22 to 2026-06-26, Identity Contract v1.1 still 2026-06-30, Platform-owned operating surface complete in Postgres with zero Airtable reliance still 2026-06-30. Identity v1 ship is the load-bearing piece of the broader directive and unblocks downstream consumer work; the directive's full closure happens 2026-06-30 when the remaining commitments land.

The contract surface is unchanged. Identity Contract v1.0.3 stays as written; the canonical nine-field Person, the three event types, the §9 consumer responsibilities, the §10 producer responsibilities, the §11 security and privacy section all stand as the contract today. v1.1's promotion of consumers from shim-served reads to canonical-store-only reads is editorial-versioning at this point (the shim was functionally moot once Phase 1 + Phase 2 landed today; canonical-store reads are already live, the shim layer the alignment scoping memo named was never built because the migration ran before it would have been needed). v1.1 ship on 2026-06-30 carries the version-flip and any post-cutover stabilization findings; consumers running against v1.0.3 today are interface-compatible with v1.1.

The Person Externals sub-spec at contracts/identity/person-externals.md continues to carry the Status: draft (lands with Identity Contract v1) flag in its bold-header. The flag was originally framed as gated on ADR-0010 acceptance (which happened 2026-05-02) and on the contract README's promotion of the sub-spec from draft to authoritative (which happens with v1.1 on 2026-06-30 per the directive). The sub-spec is operationally authoritative today; the bold-header flag is a labeling convention that catches up at v1.1 ship. No consumer-visible behavior changes when the flag flips.

The five conditional and pending commitments below the directive's main timeline are unchanged: Sales' Lead pipeline migration, Revenue's Q3/Q4 Postgres migration of Revenue-owned tables, Delivery's seven-surface migration, Coaching's projection-based-reads cut-over, and Growth's intake.captured Postgres migration all stay on their respective scoping memos' calendars. Identity v1 ship is the upstream gate for several of those downstream pieces; with the gate cleared, downstream work can proceed against the live contract surface.

The mergePersons audit log entry shape (the merge log per Identity Contract §10.5) is unchanged; the externals-touched list from the new reattachExternalsOnMerge helper is returned by mergePersons as externalsReattached: { retiredAndRekeyed: number; plainRekeyed: number } and is available for callers to log into the merge log entry alongside the existing pre-merge state, post-merge state, reason code, and operator. Wiring the externals counts into the merge log entry's persistent shape is a small follow-up that lives in lib/audit/; not blocking for v1 ship and tracked separately.

Commitments that close with this ship

Two commitments flip from pending to completed in this filing pass:

The Q2 Airtable sunset directive's 2026-06-15|pending|P0|XL|Identity Contract v1 ship entry on 2026-05-09-platform-q2-airtable-sunset-directive flips to completed. The original commitment was for canonical Person surface live with shim layer over legacy backing store; what shipped is canonical Person surface live without a shim layer (the shim was unnecessary once the data migration ran), which is strictly stronger than the committed deliverable. The 37-day-early ship reflects the same compression pattern Phase 0 of the dispatcher SDK and ADR-0009 acceptance both showed.

The merge-case response memo's 2026-06-15|pending|P1|M|mergePersons implementation in modules/person/service.ts entry on 2026-05-09-platform-adr-0010-merge-case-shape-a flips to completed. The implementation lands in platform/modules/person/service.ts (the merge function refactored to wrap the existing canonical-field promotion, the alias mark-merged write, and the new externals-reattachment call in a single Prisma transaction). The new helper reattachExternalsOnMerge lives in platform/modules/person-external/service.ts and is exported through the module's public surface. Three integration-test scenarios cover the no-externals, alias-only, and colliding-tuple cases. The audit-log entry shape work for surfacing the externals-touched counts into the persistent merge log is tracked separately as a small follow-up in lib/audit/; that piece is not in the merge-case response memo's commitment scope.

What's still owed for the broader Q2 directive

Four pending Platform commitments remain on the directive thread, all dated 2026-06-22 to 2026-06-30:

Dispatcher SDK Phase 2 ship 2026-06-22 (P0 XL); active Platform work, on track per the compressed schedule.

CL-PLT-0002 cutover 2026-06-22 to 2026-06-26 (P0 L); the table layer migration of legacy Clients/Students/Client Profiles/Student Profiles into the canonical Person + Guardian + Tenancy Junction set. The Guardian and Tenancy Junction tables ship in this window; Persons and PersonExternals are already live per today.

Dispatcher SDK Phase 3 ship 2026-06-29 (P0 L); docs, observability hooks, Coaching cut-over migration guide, reference implementations.

Identity Contract v1.1 ship 2026-06-30 (P0 M); the version-flip plus any post-cutover stabilization findings.

Platform-owned operating surface complete in Postgres with zero Airtable reliance 2026-06-30 (P0 XL); the aggregate commitment.

The five remaining domain-side commitments per each domain's scoping memo on the directive thread also stay as scoped; no change from today's ship.

References

Q2 Airtable sunset directive (parent of the v1 ship commitment): 2026-05-09-platform-q2-airtable-sunset-directive.

Identity v1 progress FYI from earlier today (the prior status snapshot): 2026-05-09-platform-identity-v1-progress-update.

Merge-case response memo (the mergePersons implementation commitment): 2026-05-09-platform-adr-0010-merge-case-shape-a.

Revenue's ADR-0010 ack with merge-case flag (the original Revenue input that drove the implementation work): 2026-05-09-revenue-adr-0010-ack-with-merge-case-flag.

ADR-0003 alignment scoping memo (the calendar Identity v1 ship rode against): 2026-05-02-platform-adr-0003-alignment-scoping.

Identity Contract v1.0.3 (the contract surface this ship implements): coordination/contracts/identity/README.md.

Person canonical fields sub-spec: coordination/contracts/identity/person-canonical-fields.md.

Person resolution semantics sub-spec: coordination/contracts/identity/person-resolution-semantics.md.

Person Externals sub-spec (operationally authoritative today; bold-header flag flips to non-draft on v1.1): coordination/contracts/identity/person-externals.md.

ADR-0003 (Person canonical entity): coordination/adrs/ADR-0003-person-canonical-entity.md.

ADR-0010 (provider externals at Platform; merge-case clarified 2026-05-09): coordination/adrs/ADR-0010-provider-externals-at-platform.md.

Schema migration shipping the partial unique constraint: platform/prisma/migrations/20260502180000_person_external_partial_indexes/migration.sql.

Init identity migration (Person, Guardian, PersonExternal tables): platform/prisma/migrations/20260502170444_init_identity/migration.sql.

Phase 1 mint script: platform/scripts/mint-persons-from-csv.ts.

Phase 2 mint script (adapted to phone-based join 2026-05-09): platform/scripts/mint-externals-from-csv.ts.

mergePersons implementation (refactored 2026-05-09 with externals reattachment in a single Prisma transaction): platform/modules/person/service.ts.

reattachExternalsOnMerge helper (new today): platform/modules/person-external/service.ts.

Integration test (three new merge scenarios added 2026-05-09): platform/scripts/test-identity-integration.ts.

Manual route smoke test (curl recipes for the three v1 endpoints): platform/scripts/smoke-identity-routes.md.

Platform-owed ledger root (carries the original Identity Contract v1 ship entry that closes with this filing): 2026-05-01-platform-owed-ledger.

Thread (10 memos)

Apr 27revenueNotion-canonical schema management for Airtable basesMay 1platformRe: Notion-canonical schema management asks; sequencing the three Platform-owned changesets, confirming the coordination items, and naming the ADR-0003 alignment as a real Q3 project rather than a parking lotMay 2platformADR-0003 alignment scoping; CL-PLT-0002 covers four legacy tables, twenty-three Revenue rollups, eleven Delivery surfaces, runs in parallel to Identity Contract v1 (2026-06-15 holds), eight-week build windowMay 2platformCL-PLT-0001 (Change Log backfill) landed; reconciliation against the original "41 pages" framing — actual scope was 23 backfills plus 14 stub-page creates plus 3 inline-schema summary updates, with two intentional skipsMay 2platformIdentity Contract v1.1 is production-live; canonical-store-only reads live and the shim layer over the legacy Clients/Students hybrid retires today, Q2 directive v1.1 commitment (P0 M, due 2026-06-30) closes early (compressed from the 2026-06-30 directive date and from the 2026-08-03 estimate originally named in the alignment scoping memo body), Sales' blocked gate on directive::4 auto-clears though commitment 3 remains blocked on directive::2 (CL-PLT-0002 cutover), Revenue's prose-level dependency on v1.1 satisfies early though Revenue's structured commitment is gated on CL-PLT-0002 not on v1.1, no other consumer-side structured gates were declaredMay 2platformSchema Change Process amendment landed; Tier 2 now carries both variants, the weekly-cadence manual-skip departure, and the cross-domain changeset audit-trail consequenceMay 6platformSales Schema Snapshots structure commitment marked completed on the schema-management threadMay 6salesSales accepts the Sales Notion home and Schema Snapshots structure; Platform may stand up Sales / Schema Snapshots and home Client Conversion Summaries under SalesMay 9platformIdentity Contract v1 progress update; Phase 1 (Persons mint) and Phase 2 (Externals mint) landed ahead of the Foundation-phase window, ADR-0010 merge-case resolved (Shape A), reverse-lookup endpoint live for Revenue's pre-cutover forward-looking integration tests, the at-risk framing on the platform-owed ledger entry is stale, 2026-06-15 ship date is on track with the remaining work tightly scoped

View source on GitHub