ADR-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 window
Date: 2026-05-02
From: Platform
To: Revenue (parent thread author), Delivery (added because Student Profiles and Client Lesson Summaries are Delivery-owned)
Status: Scoping memo per the four-week commitment in 2026-05-01-platform-schema-management-asks-sequencing. Three deliverables: scope spec, field-level consumer impact, real timeline. Identity Contract v1 holds at 2026-06-15; alignment runs in parallel as changeset CL-PLT-0002 over an eight-week window.
Summary
Platform commits to running the ADR-0003 alignment changeset (CL-PLT-0002) in parallel with the Identity Contract v1 ship rather than gating v1 on it. The trade-off favors honoring the consumer-facing commitment (June 15) over delivering v1 against the cleaner shape: v1 ships against the legacy Clients/Students hybrid; CL-PLT-0002 lands in mid-July; v1.1 promotes consumers to the post-alignment shape with an additive minor bump rather than a major. Recipients keep their existing rollups and surfaces working through both transitions; no consumer is asked to rewrite anything during the v1 window.
The alignment changeset's blast radius from Platform's seat: four source tables (Clients, Client Profiles, Students, Student Profiles), one new identity surface (Persons + Guardian relationships in Platform's Postgres-backed identity store), twenty-three Revenue rollups currently keyed off Clients or Client Profiles, eleven Delivery surfaces currently keyed off the same plus Student Profiles, and one Sales orphan (Client Conversion Summaries) that becomes a stitching opportunity rather than a blocker.
The eight-week window starts 2026-05-25 (after the build plan follow-up lands, after ADR-0009 decides) and ends 2026-07-20. The window includes a one-week pre-flight dedup pass against the legacy Clients table — that is the load-bearing risk per ADR-0003's "What becomes harder" section, and Platform front-loads it.
Decision: 2026-06-15 holds, alignment runs in parallel
The trade-off
Two configurations were considered for sequencing v1 against CL-PLT-0002. The trade-off framing is borrowed from the architecture skill's options-considered shape because the choice is genuinely a multi-axis decision, not a calendar question.
Option A: Slip v1 to ship against the post-alignment shape (rejected)
Hold v1 until CL-PLT-0002 has landed and stabilized, then ship v1 against canonical Person + Participant + Guardian + Coach. New ship-date estimate: 2026-08-03 (CL-PLT-0002's end of window plus two weeks of post-migration validation).
| Dimension | Assessment |
|---|---|
| Consumer trust | Negative. Identity Contract v1 has been at "due 2026-06-15" since ADR-0003 amendment. Slipping the headline date to absorb internal cleanup is exactly the failure mode the productivity-bar names. |
| Migration risk | Reduced. v1 ships against a known-clean shape; consumers integrate once. |
| Implementation cost | Reduced. The v1 schema doesn't have to maintain a backward-compatibility shim against the legacy Clients/Students hybrid for the gap weeks. |
| Coaching cut-over | Neutral. Coaching's stand-up under coach-availability v1.0.1 is independent of this; it consumes lock events from Revenue and is not gated on v1.1. |
| Revenue migration off Airtable | Negative. Revenue's Q3 migration plan assumes Identity v1 is in place by the time Revenue starts cutting tables over. v1 slipping six weeks compresses Revenue's Q3 window. |
Pros
- v1 ships once, against the right shape, and consumers integrate against the long-term contract surface from day one.
- No backward-compat shim layer to maintain during the gap weeks.
Cons
- Headline ship-date slip on a contract that consumers have been waiting for. Failure mode the productivity-bar warns against.
- Revenue's Airtable migration (Q3) loses six weeks of runway that depend on v1 being in place.
- The slip is forced by Platform's internal cleanup, which is not the kind of trade-off Platform should be asking consumers to absorb.
Option B: Hold v1, run alignment in parallel (chosen)
v1 ships 2026-06-15 against the legacy Clients/Students hybrid wrapped in the canonical contract surface. CL-PLT-0002 builds the canonical Person + Guardian + Participant + Coach tables in parallel and switches the contract's backing store on cutover. v1.1 (additive minor bump) carries any cleanup that the cutover surfaces.
| Dimension | Assessment |
|---|---|
| Consumer trust | Maintained. v1 ships on the committed date. |
| Migration risk | Higher. The contract surface has to abstract over a moving backing store during the gap weeks. Mitigated by the contract being read-mostly during the window (the Person-by-id API and person.* events; mutations are limited to mint and merge, both Platform-internal). |
| Implementation cost | Higher. Platform writes a backward-compatibility shim that lets the v1 API serve both pre- and post-alignment shapes during the cutover, and a translation layer in the migration script. |
| Coaching cut-over | Neutral. Same as Option A. |
| Revenue migration off Airtable | Positive. Identity v1 is available June 15 as planned; Revenue's Q3 migration window stays at full length. |
Pros
- v1 ships on the committed date. No external slip.
- Revenue and Delivery keep their Q3 migration runway.
- The alignment changeset's risk is contained inside Platform; consumers do not see the cutover except through one additive minor bump.
Cons
- Platform owns more implementation complexity (the shim layer, the cutover script, the backward-compat tests).
- v1.1 carries cleanup that v1 would have shipped clean. Documentation and onboarding examples have to track two shapes during the gap weeks.
Why Option B wins
The decisive axis is consumer trust. Identity v1 is the most-anticipated cross-domain contract Platform has shipped; slipping the date because Platform's own cleanup is not done would erode the credibility the contract is supposed to carry. Platform absorbs the implementation cost (shim layer, cutover script) so consumers keep their integration timelines.
The mitigating fact for migration risk is that Identity Contract v1's surface is read-mostly. Mints happen at Platform; merges happen at Platform; consumers read via API and react to events. The shim layer therefore serves a small surface (one read endpoint, three event types) rather than the full identity surface, which keeps the maintenance burden bounded.
What this means concretely
- Identity Contract v1 ships 2026-06-15 against the legacy Clients/Students hybrid wrapped in a canonical-shaped read surface. The nine-field Person record is constructed at read time from the legacy fields per a published mapping; the mapping is the shim. Consumers see the canonical contract; the legacy data is invisible to them.
- CL-PLT-0002 runs 2026-05-25 → 2026-07-20 as Platform-internal work, building the canonical Person + Guardian + Participant tables in Postgres and writing the cutover script.
- Identity Contract v1.1 ships 2026-08-03 (or earlier if cutover finishes ahead of window) as an additive minor bump that promotes consumers to read directly from the canonical store rather than through the shim. The contract surface does not change; the backing store does. v1.0.x consumers continue to work through the v1.1 minor.
What ADR-0003 alignment means in this base
The legacy Airtable schema in app1K2d9GZVsE7vWh represents humans across four tables that ADR-0003 collapses into one Person canonical entity plus three role records.
| Today (legacy) | ADR-0003 target | Owner of target |
|---|---|---|
| Clients (adult identity + payer fields + Lead pipeline fields) | Person + zero or more Lead records + Guardian relationships + optional Participant | Platform (Person, Guardian); Sales (Lead); Delivery (Participant) |
| Client Profiles (per-tenant junction with cross-domain rollups) | Pure tenancy junction (Person × Organization) with rollups extracted to consuming domains | Platform |
| Students (minor identity stub + parent link) | Person (with is_minor=true) + Participant records + inbound Guardian relationship from the parent's Person |
Platform (Person, Guardian); Delivery (Participant) |
| Student Profiles (per-tenant operational state for minors) | Participant record (Person × Organization) — already aligned per the manifest | Delivery |
Two structural shifts to call out, because they reshape what consumers read against:
Guardian becomes a real record. Today, the Student → Client link encodes "this child's guardian is this adult." Post-alignment, that becomes a gdn_<UUID v7> row in Platform's Guardian table with start and end dates, supporting custody-change cases the legacy schema cannot represent. Consumers reading "the parent of this minor" walk Platform's Guardian-aware comms-routing endpoint instead of doing a Student.Client lookup.
Lead pipeline fields move off Clients. Lead Key, Source/Stage/attempt-history fields on Clients move to Sales' Lead table per ADR-0003 action item 3. Sales has not yet stood up the Lead table; CL-PLT-0002 holds an extraction-only step (data is preserved on a transitional Sales-staging surface) and Sales' own Lead extraction is a separate sequenced piece of work. The fields are not lost; they migrate across two changesets.
Scope spec: tables, fields, and what CL-PLT-0002 touches
Source tables and field-level treatment
Clients (Platform, source tbl53WJLnUPde5auP, 42 fields)
| Field | Treatment under CL-PLT-0002 |
|---|---|
| First Name | Renamed given_name on canonical Person; carried through the shim during the v1 gap window. |
| Last Name | Renamed family_name on canonical Person. |
| Client Name (formula) | Translated to display_name with relaxed semantics (nullable, overridable). The legacy formula stays operational on the legacy table during the gap; the canonical record's display_name is constructed via the contract's default rule. |
| Phone | Internal-only; stays on the Person internal table, NOT on the canonical contract per person-canonical-fields.md §"NOT on the contract." |
| Phone Normalized (computed) | Becomes the dedup signal in the pre-flight pass; not exposed to consumers. |
| Internal-only; same treatment as Phone. | |
| Zip | Internal-only; same. |
| Status (Active, Inactive, Merged, Do Not Contact) | Remapped to canonical status enum (active, archived, merged) with do_not_contact becoming a Platform-internal flag. The four-value to three-value remap is the same one called out in the v0.1 validation. |
| Activation Ready (checkbox) | Drops out of canonical surface; legacy-internal operational helper. |
| Notes | Stays Platform-internal; not exposed on the canonical contract. |
| Lead Key + acquisition pipeline fields (Source, Stage, attempt history, callback fields) | Moved off Clients to a transitional Sales-staging surface in CL-PLT-0002; canonicalized to Sales' Lead table in a follow-up changeset (not in CL-PLT-0002). |
| Links: Students | Replaced by Guardian relationships in Platform's Guardian table. The link itself is consumed by the migration; downstream readers walk Guardian instead. |
| Links: Client Profiles | Reshaped: Client Profiles becomes pure (Person × Organization) tenancy. The link semantically becomes "Person → tenancy junction." |
| Links: Client Externals | Stays. Client Externals continues to map (provider, external_id) → person_id per ADR-0010. |
| Links: Activation Organization | Drops; subsumed by the Person × Organization tenancy junction. |
| Backlinks: Lesson Sites (Private) | Stays as a per-Person link surface; rekeys from Client to Person without a semantic change. |
| Lookups: Organizations (from Client Profiles) | Rebuilt against the new tenancy junction; same shape. |
| Rollups: Client External Count, Synced/Failed/Missing/Usable variants (5 rollups) | Rebuilt against the Person → Client Externals link. Same semantics. |
| Rollups: Profile Count | Replaced by Tenancy Count rollup (Person → tenancy junction). Same semantics, different field name. |
| Helpers: Has Contact Info, Primary Contact Method, Setup Status, Primary Org, Has Active Profiles (5 helpers) | Rebuilt against canonical fields. Has Contact Info and Primary Contact Method use Platform-internal contact data. Setup Status becomes a derived field on the tenancy junction, not on Person. |
| Checks: Missing Client Name, Missing Contact Info, No Client Profiles (3 checks) | Rebuilt; same semantics, against canonical fields. |
| Exception System (Has Identity Problem, Identity Problem, Has Setup Problem, Setup Problem, Has Exception, Exception Reason — 6 fields) | Rebuilt; same semantics. The exception surface is operational-internal and stays in the Platform identity service's admin tooling, not on the contract. |
| Audit: Created At, Modified At | Translated to canonical created_at and updated_at. The canonical updated_at semantics tighten per the contract (only canonical-field changes bump it). |
| Remaining unenumerated fields | The 42-field count exceeds what the Notion schema page lists by ~12 fields; the gap is operational helpers and view-layer formulas that drop off the migration boundary cleanly. The pre-flight inventory will reconcile field-by-field against the live Airtable schema. |
Client Profiles (Platform, per-tenant junction)
| Field | Treatment |
|---|---|
| Status (Active, Paused, Inactive) | Stays on the new tenancy junction. Three values preserved. |
| Notes | Stays on the new tenancy junction. |
| Links: Client (required) | Rekeyed to person_id. |
| Links: Organization (required) | Stays. |
| Backlinks: Lessons, Orders, Credit Account, Client Activation Summary, Student Profiles (5 backlinks) | All five rekey from "linked through Client Profile" to "linked through (Person, Organization) tenancy junction." Foreign keys on the linked tables update; the rollup semantics stay identical. |
| Lookups: Client Name, Client Phone | Replaced by lookups against canonical Person (display_name, internal phone). |
| Rollups: Lesson Count, Order Count | Same semantics; different upstream link path. |
| Helpers (4): Has Credit Account, Has Client Activation Summary, Has Activity, Needs Activation Summary Creation | Rebuilt; same semantics. |
| Checks (4): Missing Client, Missing Organization, Missing Credit Account, Missing Activation Summary | Rebuilt; same semantics. |
| Exception System (2 fields) | Rebuilt; same semantics. |
| Audit | Translated. |
Students (Platform)
The Notion schema page for Students is currently empty (a known data debt called out in §"Open data debts" below). Pre-flight inventory will pull the live Airtable schema into the Notion page as part of the changeset's pre-snapshot. The migration treatment from ADR-0003 is unchanged: each Students row becomes a Person record with is_minor=true plus Participant records plus an inbound Guardian relationship from the paying adult.
The link Students → Clients (encoding "guardian of") is consumed by the migration: each row produces one Guardian relationship row in Platform's Guardian table, with guardian_person_id = Client.person_id and dependent_person_id = Student.person_id, and start/end dates derived from the Students row's Created At plus a null end date (custody-change cases are not retroactively reconstructed; they begin tracking forward from cutover).
Student Profiles (Delivery, canonical Participant per the manifest)
Already aligned in shape per ADR-0003. CL-PLT-0002 rekeys the links: every Student Profiles row's Client link rekeys to person_id (the minor's Person, not the parent's), and the Client Profile link rekeys to the new tenancy junction. The Skill Level, Lesson Attendances, status fields, and primary coach link stay as-is. No semantic change to Delivery's surface; one foreign-key rewrite.
Target tables created by CL-PLT-0002
- Persons (Platform, Postgres-backed): canonical identity records with
per_<UUID v7>primary key. Hostsgiven_name,family_name,display_name,is_minor,status,alias_of,created_at,updated_at, plus Platform-internalphone,email,dob,birth_year,age_group,do_not_contact,notes. Referenced byperson_idfrom every other table that today references Clients or Students. - Guardian (Platform, Postgres-backed): directed relationships between Persons. Fields:
gdn_<UUID v7>,guardian_person_id,dependent_person_id,started_at,ended_at(nullable),relationship_kind(defaultparent; ADR-0003 §"What we will need to revisit" notes generalization is a future question). - Tenancy Junction (Platform): replaces Client Profiles in shape and purpose. Fields:
(person_id, organization_id)composite key,status,notes,created_at,updated_at. The five backlinks (Lessons, Orders, Credit Account, Activation Summary, Student Profiles) rekey to this junction.
Tables NOT touched by CL-PLT-0002
The changeset is scoped tightly. Tables that reference Clients or Students through the four affected tables (everything in the §"Consumer-impact assessment" sections below) get rollup/lookup rewrites only; their primary structure does not change. The Sales orphan Client Conversion Summaries does not move in CL-PLT-0002 — it rekeys to Person and the move to a Sales home is a separate piece of work tracked in the schema-management thread.
Consumer-impact assessment: Revenue
Twenty-three rollups across nine Revenue tables reference the four legacy identity tables today. Each rebuilds against the canonical Person + tenancy junction. Per the user's "field-level" depth ask, every rollup is enumerated below with its current and post-alignment shape. None of the rollups change semantics; all of them change their upstream link path.
The three groups below cluster by table.
Credit-account-keyed rollups (Credit Accounts, 5 rollups)
| Current | Post-alignment | Semantic change? |
|---|---|---|
| Credit Accounts → Client Profile → Client.Client Name (lookup) | Credit Accounts → Tenancy Junction → Person.display_name (lookup) | None. |
| Credit Accounts → Client Profile → Client.Phone (lookup) | Credit Accounts → Tenancy Junction → Person.phone (Platform-internal; the lookup stays scoped to admin views) | None. |
| Credit Accounts → Client Profile.Client Name (denorm) | Credit Accounts → Tenancy Junction.display_name (denorm) | None. |
| Credit Accounts.Active Credits (rollup over Credit Ledger Entries) | Unchanged. | None. |
| Credit Accounts.Reserved Credits (rollup over Credit Reservations) | Unchanged. | None. |
Order-keyed rollups (Orders, Order Items, Refunds, Refund Items — 11 rollups)
| Current | Post-alignment | Semantic change? |
|---|---|---|
| Orders → Client Profile → Client.Client Name | Orders → Tenancy Junction → Person.display_name | None. |
| Orders → Client Profile → Client.Phone | Orders → Tenancy Junction → Person.phone (admin-only) | None. |
| Orders → Client Profile → Organization | Orders → Tenancy Junction → Organization | None. |
| Orders.Order Total (rollup over Order Items) | Unchanged. | None. |
| Orders.Refund Total (rollup over Refunds) | Unchanged. | None. |
| Order Items → Order → Client Profile → Client.Client Name | Order Items → Order → Tenancy Junction → Person.display_name | None. |
| Order Items.Revenue Recognized (rollup over Revenue Recognitions) | Unchanged. | None. |
| Refunds → Order → Client Profile → Client.Client Name | Refunds → Order → Tenancy Junction → Person.display_name | None. |
| Refunds.Refund Total (rollup over Refund Items) | Unchanged. | None. |
| Refund Items → Refund → Order → Client Profile → Client.Client Name | Refund Items → Refund → Order → Tenancy Junction → Person.display_name | None. (Three-hop chain; same depth post-alignment.) |
| Promotion Redemptions → Client Profile → Client.Client Name | Promotion Redemptions → Tenancy Junction → Person.display_name | None. |
Pay-run-keyed rollups (Pay Runs, Pay Run Lines, Pay Run Allocations — 7 rollups)
| Current | Post-alignment | Semantic change? |
|---|---|---|
| Pay Run Lines → Coach (Coach Profile) → Person.display_name | Unchanged in shape; Coach Profile already keys to Person via the Coaching domain post-ADR-0003 amendment 2026-05-01. | None. |
| Pay Run Allocations → Lesson → Coach.Person.display_name | Unchanged. | None. |
| Pay Runs.Total Paid (rollup over Pay Run Lines) | Unchanged. | None. |
| Pay Run Lines.Allocated Total (rollup over Pay Run Allocations) | Unchanged. | None. |
| Pay Runs → Period → Organization | Unchanged. | None. |
| Coach Rates → Coach (Coach Profile) → Person | Unchanged. | None. |
| Payouts → Provider Account → Organization | Unchanged. | None. (Listed for completeness; this rollup does not touch the four affected tables but lives in the same Revenue surface.) |
The Pay Run group is mostly invariant under CL-PLT-0002 because Coach already routes through Coach Profiles → Person via Coaching's role record (ADR-0003 amendment 2026-05-01). The legacy Instructors → Instructor Profiles split is already migrated for the coach side; this changeset finishes the work on the client/student side.
What Revenue does (and does not) need to do
Read side (during the gap window, June 15 → July 20). Nothing. v1 ships the canonical contract surface; reads against Person.display_name resolve through the shim that translates from legacy Clients fields. Revenue's existing Airtable rollups continue to work because the legacy tables stay in place during the gap.
Read side (post-cutover, July 20 onward). Revenue's Airtable rollups rebuild against the new link paths over a one-week window included in CL-PLT-0002. Platform's migration script generates the rollup-rewrite SQL; Revenue reviews and applies. The work is mechanical, not architectural.
Migration coordination. Revenue's own migration off Airtable (Q3 deliverable per the Revenue domain doc) lands after CL-PLT-0002 cutover. The link paths Revenue's new Postgres schema uses are the post-alignment ones, so Revenue does not absorb any pre/post duality.
Consumer-impact assessment: Delivery
Eleven Delivery surfaces reference the four legacy identity tables today. Same enumeration shape as Revenue. The five Lessons-related surfaces, the three Coach-related surfaces, and the three Student-Profile-related surfaces are listed in turn.
Lessons-keyed surfaces (5)
| Current | Post-alignment | Semantic change? |
|---|---|---|
| Lessons → Client Profile → Client.Client Name | Lessons → Tenancy Junction → Person.display_name | None. |
| Lessons → Student Profile → Student.[name fields] | Lessons → Student Profile → Person (minor).display_name | None. The Student-side rekey is the load-bearing one; minor identity is now first-class. |
| Lessons.Coach (link → Coach Profile) | Unchanged. | None. (Coach side already aligned.) |
| Lesson Attendances → Lesson → Student Profile → Student | Lesson Attendances → Lesson → Student Profile → Person (minor) | None. |
| Lessons.Lesson Site (link) | Unchanged. | None. (No identity dependency.) |
Coach-related surfaces (3)
| Current | Post-alignment | Semantic change? |
|---|---|---|
| Coach Profiles → Coach.Person | Unchanged. | None. |
| Coach Profile Externals → Coach Profile → Person | Unchanged. | None. |
| Coach Rates → Coach Profile → Person (Revenue-owned but Delivery-readable) | Unchanged. | None. |
Student-Profile-related surfaces (3)
| Current | Post-alignment | Semantic change? |
|---|---|---|
| Student Profiles.Client (link) | Student Profiles.Person (link to minor's Person) + inferred Guardian via Platform's comms-routing endpoint when needed | Surface change visible to Delivery. Student Profiles.Client is the field readers walk today; post-alignment they walk Student Profiles.Person and call Platform's Guardian endpoint when comms routing requires the parent. |
| Student Profiles.Client Profile (link) | Student Profiles.Tenancy Junction (link) | None. (Field renames; semantic identical.) |
| Client Lesson Summaries.Client Profile (link, primary key) | Client Lesson Summaries.Tenancy Junction (link, primary key) | None. The aggregation semantics ("derived org-scoped summary of a Client Profile's lesson activity") become "derived org-scoped summary of a Person's lesson activity within a tenancy." Identical shape; clearer name. The summary table itself may rename in v1.1 (e.g., to Person Lesson Summaries) but the rename is editorial, not semantic. |
What Delivery does (and does not) need to do
Read side (during the gap window). Same as Revenue: nothing. The shim makes the canonical contract surface usable for any new code Delivery writes against v1; existing Airtable surfaces continue to work against legacy tables.
Read side (post-cutover). The Student Profiles.Client → Student Profiles.Person rekey is the only Delivery-visible change. Delivery's coach-day planner and any UI that surfaces "the parent of this student" today walks Student.Client; post-alignment it calls Platform's GET /identity/comms-routing/:person_id endpoint and receives the Guardian Person back. The endpoint is ready for v1.0.0 (per Identity Contract README §10.6).
Lock-aware availability projection (Coaching's adjacent work). Coaching's coach-availability v1.0.1 already consumes lock events from Revenue and is independent of CL-PLT-0002. The interim sync-query shape continues to work through the v1 gap window and the post-alignment cutover; Coaching's projection cut-over remains gated on the dispatcher SDK's Phase 2, not on this changeset.
Real timeline
Eight-week build window with named phases. Dates are firm from Platform's seat; per the productivity-bar framing, a slip is non-silent and triggers an explanation memo on this thread.
| Phase | Window | Work |
|---|---|---|
| Pre-flight | 2026-05-25 → 2026-05-31 (1 week) | Pull live Airtable schema for the four tables into the Notion schema pages (closes the Students/Student Profiles data debt). Run dedup pass against Clients on phone+email+name. Produce the merge report for human review. Identify any Clients rows where dedup signals are ambiguous and flag them. |
| Foundation | 2026-06-01 → 2026-06-14 (2 weeks) | Stand up Persons, Guardian, and Tenancy Junction tables in Platform's Postgres identity store. Author the canonical-contract shim that serves v1 reads from the legacy Airtable tables during the gap window. Author the cutover script (idempotent; can run in dry-run mode). |
| Identity v1 ships | 2026-06-15 | v1 ships against the shim. No CL-PLT-0002 schema changes are visible to consumers. Platform commits this date; this is the original 2026-06-15 commitment, honored. |
| Cutover prep | 2026-06-16 → 2026-07-05 (3 weeks) | Run the cutover script in dry-run repeatedly; reconcile any divergences between dry-run output and the merge report from pre-flight. Apply Lead-pipeline-field staging extraction (Sales' transitional surface). Write rollup-rewrite SQL for Revenue and Delivery; review with each domain. |
| Cutover | 2026-07-06 → 2026-07-12 (1 week) | Apply CL-PLT-0002 to the Airtable base. Snapshot pre and post per the per-table snapshot model. Switch the v1 contract's backing store from the shim to the canonical tables. Apply rollup rewrites for Revenue and Delivery. |
| Stabilization | 2026-07-13 → 2026-07-20 (1 week) | Watch for divergence between expected rollup values and observed values. Reconcile any drift. File the v1.1 amendment memo and ship the additive minor bump. |
Calendar end-to-end
- Today: 2026-05-02 (this memo files)
- Pre-flight starts: 2026-05-25 (after build plan follow-up lands 2026-05-15 and ADR-0009 decides 2026-05-29; the foundation phase overlaps with ADR-0009's decision week, which is fine because CL-PLT-0002 has no dispatcher SDK dependency)
- v1 ships: 2026-06-15 (committed)
- CL-PLT-0002 cutover: 2026-07-06 → 2026-07-12
- v1.1 ships: 2026-08-03 (estimated end of stabilization plus contract patch authoring)
Risks and mitigations
The pre-flight dedup pass is the load-bearing risk. Bad merges are hard to undo per ADR-0003 §"Trigger to revisit"; the contract's resolution semantics (person-resolution-semantics.md) make merge non-reversible by design. Two mitigations:
First, the dedup pass produces a merge report for human review before any mints commit. The Platform engineer running CL-PLT-0002 walks the report row by row and flags any ambiguous matches; ambiguous rows mint as separate Persons rather than merging, with the ambiguity flag preserved on the Person internal table. Operators can manually re-merge later if the ambiguity resolves.
Second, the cutover script is idempotent and runs in dry-run mode before commit. The dry-run produces the same output the real run would, against a snapshot of the legacy tables, without writing to canonical tables. Drift between dry-run and real-run output is the abort signal.
The shim layer is the secondary risk. A bug in the shim would expose the legacy Clients/Students hybrid through the canonical contract surface, which is exactly the failure the contract is supposed to prevent. The shim has its own test suite (covering the field translations, the Guardian-walking behavior for minors, and the merge-status mapping); CI fails on any regression.
Open data debts
Two known gaps the pre-flight phase closes.
Students and Student Profiles Notion schema pages are empty. The Notion pages exist (URLs are in the Tables by Domain manifest) but have no body content. Pre-flight pulls the live Airtable schema into both pages so the canonical Notion-side documentation matches the Airtable side before CL-PLT-0002 modifies either. This is mechanical work, two to three hours.
Clients table has 42 Airtable fields versus ~30 listed on the Notion schema page. The 12-ish-field gap is operational helpers and view-layer formulas that drop off the migration boundary cleanly; pre-flight reconciles field-by-field. Any field discovered in the gap that does NOT drop cleanly gets a per-field treatment decision logged in the pre-flight report.
Asks
Revenue: confirm that the rollup-rewrite plan in §"Consumer-impact assessment: Revenue" matches your read of the surfaces. Specifically, if any of the twenty-three rollups have a behavior in production that the table summaries miss, flag it before pre-flight starts (2026-05-25). After pre-flight begins, late rollup discoveries become drift signals that delay cutover.
Delivery: same ask for the eleven Delivery surfaces. The Student Profiles.Client → Student Profiles.Person rekey is the surface that most likely has UI dependencies Platform cannot see; if Delivery's coach-day planner or any other UI surfaces "the parent of this student" today, name the surface and the call shape so the migration script can produce a translation report.
Both: silent assent by 2026-05-23 is fine if the plans land cleanly. An explicit "no concerns from us" reply is helpful so Platform knows the input is in.
References
- Parent thread root:
2026-04-27-revenue-schema-management - Previous Platform reply on this thread (commits to this scoping memo):
2026-05-01-platform-schema-management-asks-sequencing - ADR-0003 (Person canonical entity, with role records per domain):
coordination/adrs/ADR-0003-person-canonical-entity.md - ADR-0002 (Person ID shape;
per_,gdn_,par_,coa_prefixes):coordination/adrs/ADR-0002-person-id-shape.md - ADR-0010 (provider externals at Platform; canonical mapping):
coordination/adrs/ADR-0010-provider-externals-at-platform.md - Identity Contract v1.0.3 (the 2026-06-15 commitment):
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 - Validate v0.1 against current Client table: https://www.notion.so/34a79d6107c68068a189e4e88eb2acdf
- Tables by Domain manifest: https://www.notion.so/34f79d6107c6811dba22ee5576c2e1bb
- Clients schema: https://www.notion.so/33779d6107c6809dad18d292b1076c62
- Client Profiles schema: https://www.notion.so/33979d6107c680209a90c599b08b3924
- Owed-ledger root memo (where this commitment lives):
2026-05-01-platform-owed-ledger