Plan: Closed-Cohort SHINES Conversion Import (#1071 program)
On this page
- Status
- Execution notes (living-spec deviations)
- Context
- The flow at a glance (one conversion run)
- Decisions
- Schema (MR-A migration)
- Batch state machine + finalize
- Replay semantics (canonical equivalence)
- Warning semantics (exact)
- Test matrix (all @axis-tagged)
- Risks
- ⁂ #1073 additions (ship with MR-B)
- Review dispositions
Status
| Step | Description | Status |
|---|---|---|
Step 0 |
GitLab filing: #1071 weight 2→5 + |
Done (2026-07-24) — weight/label/decision comment/links set; this plan = MR-A’s first commit |
A1 (MR-A) |
Migration: |
Done (2026-07-25) — migration + models + 10 typed errors (incl. the DuplicateParty addition) + classify() arms + constraint probes; rides the A1+A2 commit |
A2 (MR-A) |
Store rework: |
Done (2026-07-25) — the full store rework + ImportHistory at StateOffice + the craig-test-lib raw builder + every-call-site fixture migration; 381/381 store+api+constraints on the rebuilt devstack; rides the A1+A2 commit |
A3 (MR-A) |
Generator: |
Done (2026-07-25) — the BeforeCutover rule + counter + contract/event keys + the 4-test cutover battery (skip+void, cutover-month pays, future-cutover hold, drain-bounded); rides the A3–A5 commit |
A4 (MR-A) |
The deploy-first audit artifact: |
Done (2026-07-25) — parser arms + resolver tests (66/66) + ADR-003 catalog entries; rides the A3–A5 commit |
A5 (MR-A) |
Four new BLOCKING invariants ( |
Done (2026-07-25) — four BLOCKING invariants (green in the 57/57 devstack sweep) + the #1116 semantic sweep (6 doc/web sites reworded); rides the A3–A5 commit |
B1 (MR-B) |
Contracts ( |
Done (2026-07-25) — contracts (+the 3 pub canonical fns), the import_batch engine (stage/finalize/assess/convert), 6 handlers, events in payment_events, knob, the explicit-admin ruleset pair + ResourceType::SubsidyImport + 5 evaluation pins; the native ERR gate widened (guardianship exception recorded) |
B2 (MR-B) |
Typed test client; |
Done (2026-07-25) — typed client, the 3 suites + evil corpus + AC1 re-pin; financial battery 535/535 incl. 29 import tests |
B3 (MR-B) |
|
Done (2026-07-25) — |
B4 (MR-B) |
Seed family F via PARALLEL row types (families A–E render byte-unchanged): rcs, first Active 2013-06-01, two term revisions, ACTIVE head, current future dues, state-office stamps, batch + record rows, |
Done (2026-07-25) — family F (parallel row types; CASES+FINANCIAL re-bless; seed.ts + .seed-sql regen; exclusion + slot-mirror tests; fresh keyed seed verified 57/57 invariants), web read scope (7 tokens + provenance block), the admin read-only e2e |
B5 (MR-B) |
ADR-057 + ADR-054/052 amendments; deployment-guide conversion runbook (parser first → knob-OFF deploy → enable for the window → stage/reconcile/finalize → disable → verify 403-on-writes; SHINES pays < cutover, CRAIG ≥); data-model, testing-reference, api page, implementation-guide, configuration-reference, ACF-199 wording, CHANGELOG; ⁂ comment on #1073; AC walks + closing comments on #1071 AND #1116; epic tick; plan → archive; CLAUDE.md pointer |
Done (2026-07-25) — ADR-057 + ADR-052/054 amendments + the conversion runbook + data-model/config/api/implementation-guide/shared-crates/testing-reference/developer-guide (two source-verified doc passes) + the consolidated CHANGELOG entry (covering the MR-A miss); ⁂/closing comments/epic tick/archive ride the MR-B close-out |
Issues: #1071 (tracking; MR-B closes) · #1116 (closes with MR-B — the pending state becomes unrepresentable) · #1115 (stays open: below-floor backpay is orthogonal — the cutover only BOUNDS payment) · #1073 (⁂ readings)
Branches: feature/1071-import-substrate (this plan = first commit) · feature/1071-import-surface
Provenance: 3-explorer recon + Plan-agent design pass + the external review (2026-07-24, 10 stop-ships + G1–G17 — authoritative) + a second design pass dispositioning every finding. The finding→disposition index is in §Review dispositions.
Execution notes (living-spec deviations)
-
A2 lock widening (agent-discovered race): D8’s "sorted family locks" was insufficient for the ANY-program ActiveSibling gate — a non-terminal import now locks ALL THREE families in the canonical craig-reference token order (terminal imports lock only their own family);
create_guardianship_agreementrepointed to the same sharedlock_family_history, which is what keeps create-vs-import deadlock-free. -
A1 additions: a
DuplicatePartytyped error (no honest existing fit); the closure constants are apolicy.rsfn returningOption(aconst NaiveDateneeds a lint-deniedunwrapin const position; theNonearm doubles as the open-program signal) and the money cap a plain-Decimalfn. -
A1+A2 J-review remediations: the guardianship family GATES now read the family definition (
SubsidyProgramFamily::Guardianship.programs()+ the four-token SQL list) so gate matches the recreated index; the inter-family lock order became the canonicalSubsidyProgramFamily::ALLconst (deadlock-freedom needs ONE source, not an inlined copy); the store refuses a non-month-startcutover_monthtyped (not a raw DDL death); a terminal-beside-open-sibling PASS pin joined the family battery. Recorded, not fixed here: theclassify()family arms are reachable only by racing past the pre-checks (the conc tests accept them as an alternative; DDL probes pin the constraint names — a deterministic unit pin would need a constructiblePgDatabaseError, which sqlx does not offer); the records-tablematerialized_shapeCHECK tolerates a rejected row carryingagreement_id(unreachable through planned B1 paths). -
Carried to B1 (reviewer’s MEDIUM, latent until the surface exists): the NATIVE-side cross-family sibling question — a native ACTIVE ERR create beside an open imported rcs/ercs/ersg/enrsg head has no typed refusal and no cross-family index (natives could already coexist cross-family pre-#1071; the generator’s MultiProgram arbitration fails closed as the money backstop). B1 must either widen the native create gates to the any-program sibling rule or record the coexistence disposition with DFCS on #1073.
-
A2 signature:
import_agreement_history(conn, params, proof, created_by_name, snapshot_date, cutover_month) → (SubsidyAgreement, ImportedChainFacts)— arg order mirrorscreate_agreement_active. -
Vocabulary fix riding A2: the approvals matrix test minted
Pending→Withdrawn/Declinedwith the TERMINATION tokencaregiver_request(mint-side is un-validated, so it passed); re-tokened to the real per-status sets (caregiver_withdrew/eligibility_not_met). -
A3 battery notes: the reconcile queue settles by stamping
processed_at(rows retained); a drained pre-cutover pair is judged-and-skipped by the sharedexpected_month_rowrule while the run month (== cutover) legitimately pays. -
Discovered, filed: #1121 — the pre-existing
inbox_unprocessed_beyond_graceflake on the billing test’s poison envelopes (unrelated to #1071). -
B1 as-built decisions (agent-flagged, coordinator-signed-off): (1) the carried native-gate widening applied to
create_agreement_active(ALL-families locks + the any-program ActiveSibling refusal, pinned) but DELIBERATELY NOT tocreate_guardianship_agreement— the #1070 designed ERR→SG pre-transfer pendency requires a pending SG to mint beside the open ERR; activation’sopen_sibling_agreementowns the any-program money gate (disposition in the gate doc + a cross-family pendency pin). (2) Stage replay outranks batch state: a materialized/identical-staged resend answers from the record’s live claim regardless of the posted batch’s state — resume re-POSTs are progress; only writes requirestaging. (3) Two pre-existingerr_create.rspins updated for the refusal-precedence change (ActiveSibling now fires before coverage-overlap/lineage) — a deliberate product change, not weakening. (4) The import events publish frompayment_events.rs(the lib module the engine can reach; generator/sweep precedent) — the plan’sevents.rsnaming was the bin module. (5) NEWBatchConflictstore error +BATCH_CONFLICTproblem type (the replay table’s cross-batch 409 had no typed carrier). (6)validate_import_historyextracted pub so the stage probe runs EXACTLY the fn finalize materializes through (stage==finalize by construction). -
B3/B4 as-built: the tool’s canonicalization calls the SHARED contracts fns (parity by construction — proven live: the service’s manifest gate accepted a tool-computed checksum, 2 records staged→finalized→verified, replay-resume answered
already_imported×2 with the ORIGINAL stored report); fixture F split (identity/history rows) for the B2 budget; the e2e read spec rides the adminsubsidies.spec.ts(no testMatch churn).
Context
RCS/ERCS (UAS 553) closed to new enrollment 2014-01-01; ERSG/ENRSG closed 2014-08-01 (GA 22.8).
Existing recipients continue under 22.9 renewal reviews. CRAIG must carry the cohorts for
payment continuity and future ACF-199 reporting WITHOUT new enrollment. The #1070 tagged create
already refuses all four closed tokens with typed closed-program naming this import path
(AC1 = re-pin). The store primitive import_agreement_history exists but is proof-less,
event-less, and API-less — and the external review showed that wiring it per-record would let
money go live before a conversion batch is verified, with no machine cutover, no cohort-legality
check, no immutable replay evidence, and no correction path.
The rework: imports land in a CONVERSION LEDGER (staging tables), not the live ledger.
FINALIZE — manifest-verified, state-office-proofed, knob-gated — is the single money-consent
act that materializes records into subsidy_agreements, each row born with a persisted
payment_cutover_month the generator enforces on every path (scheduled, manual, reconcile).
Scope is CLOSED COHORTS ONLY; open-program conversion is out of scope (native re-enrollment).
The flow at a glance (one conversion run)
-
Deploy order — MR-A everywhere first (the audit parser must be live before any producer can emit); MR-B deploys knob-off inert.
-
Enable — flip
CRAIG_FINANCIALSUBSIDY_IMPORTENABLEDfor the cutover window (gates ALL import writes incl. finalize; GETs stay readable knob-off for post-conversion audit). -
Stage —
cargo xtask import-subsidy-history(device-code OAuth as the responsible state-office human; no service-principal mode) creates the batch{source_system, snapshot_date, cutover_month, expected_count, manifest_checksum}and stages each JSONL record: full validation runs NOW; outcomes persist on the record row (staged / rejected + typed blockers + warnings). Nothing touches the live ledger. Dry-run = stage
inspect + abort. -
Reconcile — the tool re-lists the batch (the records ledger IS the reconciliation export), writes the rejection manifest, and prompts.
-
Finalize — manifest gate (count + checksum + zero live rejections) → chunked per-record transactions materialize via the proof-carrying store primitive (crash-resumable; the batch id never changes) → each agreement born cutover-bounded, slots materialized, one audit event per record + one batch summary event.
-
Pay — the generator pays imported agreements from
cutover_monthforward and REFUSES every earlier month on every path (BeforeCutover, reconciling — stray pre-cutover rows void). SHINES owns pre-cutover months; the boundary is machine truth, not runbook hope. -
Close out — disable the knob, verify 403 on writes; corrections after money moved go through native amendments/transitions + #1028 adjustments (a corrected re-export is a designed 409).
Decisions
| # | Decision | Source |
|---|---|---|
D1 |
Staging LEDGER, not staged-flags: |
review SS1/SS10 |
D2 |
CLOSED COHORTS ONLY (rcs, ercs, ersg, enrsg — a serde enum makes open programs
unrepresentable); |
review SS3 (restriction option) |
D3 |
Cohort legality store-validated: qualifying date = first ACTIVE interval start, strictly
before the closure date (2014-01-01 / 2014-08-01); never-active chains qualify on
|
review SS2 |
D4 |
Immutable replay evidence: |
review SS4/SS5 |
D5 |
Persisted machine cutover: |
review SS1/SS5 |
D6 |
22.9 posture = refuse-beyond-grace, never auto-suspend: an ACTIVE head with any anchor overdue beyond the sweep’s exact 30-day grace is a stage/finalize BLOCKER (fix upstream in SHINES and re-export); within-grace = warning (native parity — the sweep itself would not act); suspended heads = warnings only |
review SS7 — rationale below |
D7 |
Term coverage of every Active interval required ( |
review SS6/SS5 |
D8 |
Family taxonomy |
review SS8/G10 |
D9 |
The wire drops all authz denorms + server facts: no |
review SS9/G3 |
D10 |
Store-level open-pending refusal (typed |
review G1 |
D11 |
Events: |
review G8/G9/Q3 |
D12 |
Authority + consent: |
review SS3/G3/Q2 |
Rationale for the non-obvious calls
-
D1 staging-table over staged-flags: flags on live rows would force "AND NOT staged" predicates into the generator, sweep, reads, and invariants — every miss a money bug. A separate ledger means abort is harmless row deletion, dry-run is free, pre-finalize correction is supersede-and-restage, and the canonical hash lives where lifecycle mutations can never touch it.
-
D6 refuse-vs-auto-suspend: auto-suspending at finalize would (1) mint a leg-1 enforcement act outside the sweep’s knob-consent model (
authorize_system— the knob IS the recorded authority), (2) append a CRAIG-fabricated interval, making the landed chain differ from the canonical payload that is this rework’s replay evidence, and (3) enforce on a deployment whose suspend knob may be OFF. The compliant inbound shapes are "active, anchors at most grace-deep overdue" or "suspended as recorded" — an export showing active-beyond-grace means the SOURCE is out of compliance at snapshot; the fix is upstream (complete or suspend in SHINES, re-export). Payment safety is total either way: post-finalize the worst importable state is within-grace overdue — a state native policy pays too. -
D2 closed-cohorts-only: kills the witness-bypass class outright (nothing the native ERR/SG/NRSG flows govern can be minted here), makes cohort-legality checkable, and shrinks the exclusivity surface. A deployment converting OPEN-program recipients re-enrolls them natively (real witnesses, real F8, correct 22.9 anchors) — pre-transfer pendency makes that strictly better, not merely acceptable.
-
D4 canonical-hash replay: live rows mutate (transitions append intervals, amendments append terms, assignment events touch denorms) — comparing a resend against them falsely 409s honest replays after any lifecycle action. The record row’s canonical payload + hash never change; a post-finalize resend compares in O(1) and answers with the ORIGINAL facts.
-
D5’s reconciling arm:
BeforeCutoverreconciles, so a stray undisbursed pre-cutover row (however it got there) is VOIDED by the same machinery that voids pre-boundary guardianship months — SHINES owns those months and the ledger self-corrects. -
D8’s index recreation is safe pre-1.0: no ersg/enrsg/rcs/ercs rows can exist before this MR (import is their only path; the #1070 index covered sg/nrsg only), so extending the guardianship index and adding the relative-care index cannot fail on existing data.
-
D10’s fixture migration: the store seam ("import accepts pending for tests") made API/store invariants diverge — an authority proof does not make an unactivatable production state safe. A raw-SQL test builder is honest about being a fixture.
-
Review history is a recorded NON-goal (G7): SHINES stays authoritative for pre-cutover review history;
batch.snapshot_dateis the named conversion baseline; the imported anchors ARE the baseline’s next-dues; cycle-1 slots materialize for active AND suspended heads (suspended recovery needs live slots). Importing completed-review history would force fabricatingresulting_term_idlinkages (composite FK to same-agreement terms) that were never recorded — an honest named baseline beats a fabricated chain. Every "full historical chain" phrase in docs becomes "full status/terms history; review history begins at the conversion baseline". -
The tool lives in xtask (G6): the house task-runner rule; xtask already ships reqwest (blocking + json) and has API-driving subcommand precedent. Device-code OAuth as the operator;
--bearer-tokenescape hatch for devstack; throttled, resumable, rejection-manifest output; the tool NEVER triggers generation (that authority stays with the ops runbook).
Schema (MR-A migration)
-
subsidy_import_batches: id,source_system(CHECK in {'shines'}),snapshot_date,cutover_month(month-start CHECK; > snapshot_date),expected_count(1..50000),manifest_checksum(sha256 over sorted(external_reference, canonical_hash)pairs),statusin {staging, finalizing, finalized, aborted}, created_by/name, timestamps. -
subsidy_import_records: id, batch FK,external_reference,canonical_payload JSONB,canonical_hash,statusin {staged, rejected, materialized, superseded},warnings JSONB,blockers JSONB,agreement_id?(+ materialized-shape CHECK), created_by, timestamps. Partial uniquesubsidy_import_records_live_reference (external_reference) WHERE status IN ('staged','materialized')— one live claim per source record across ALL batches; superseded/rejected rows free the key. Batch+status index. -
subsidy_agreements: +payment_cutover_month DATEwith CHECKs (present IFF imported; month-start); +import_batch_idpartial index. -
Family indexes: the guardianship one-open recreated over
('sg','nrsg','ersg','enrsg'); NEW relative-care one-open over('rcs','ercs').
Batch state machine + finalize
staging → finalizing → finalized; staging → aborted; a finalize pass that ends with fresh
rejections loops finalizing → staging (already-materialized rows stay live — individually
valid and cutover-bounded). Abort is forbidden from finalizing. Concurrency: a session
advisory lease subsidy-import-finalize:<batch_id> on a detached connection (the subsidy-gen
pattern); a second finalize gets 409.
Finalize: (0) lease; (1) tx — batch FOR UPDATE: finalized → 200 replay of the stored report;
staging → manifest gate (count == staged+materialized, checksum matches, zero live rejected;
else 409 MANIFEST_MISMATCH with the four numbers) → finalizing; finalizing → resume.
(2) mint the ImportHistory proof once. (3) keyset loop over staged records (chunk 100), ONE
TRANSACTION PER RECORD: re-run the full validation battery against in-tx truth (family locks
here) → import_agreement_history(conn, params, proof, cutover_month) (identity + provenance
payment_cutover_month + store-stamped imported_at, parties, chains; slot materialization
for active AND suspended heads) → flip the record materialized → stage the imported event.
Validation failure → rollback, then in a FRESH transaction mark rejected + blockers,
continue. Infra error → rollback, record stays staged, continue. (4) zero staged + zero new
rejections → batch finalized + summary event + full report; new rejections → back to
staging + rejection manifest; staged remain → stays finalizing, re-POST resumes.
Crash-resume is exactly-once: per-record txs + the provenance unique + the same-tx record flip;
the batch id never changes.
Replay semantics (canonical equivalence)
| Live record for the reference | Resend IDENTICAL | Resend DIFFERENT |
|---|---|---|
none (aborted / superseded / rejected-freed) |
201 staged fresh |
201 staged fresh |
staged, same batch |
200 |
200 |
staged, DIFFERENT live batch |
409 |
409 |
rejected (live batch) |
201 re-staged fresh |
201 re-staged fresh |
materialized |
200 |
409 |
Race loser on the live-reference unique: abort tx, FRESH transaction, re-read the winner, answer per the table. API-level concurrent test required.
Warning semantics (exact)
Assessment date A = business today at stage, RE-evaluated at finalize (finalize’s values
persist). Anchors from the OPEN terms revision. due = A → not overdue. Grace = the sweep’s
strict due < A − 30 days; suspension age = the sweep’s inclusive from ≤ A − 3 months
(chrono clamped month-add; a chrono-vs-SQL parity test pins February/leap boundaries).
| Token | Predicate | Heads | Class |
|---|---|---|---|
|
|
active, suspended |
warning |
|
|
active |
blocker |
(same predicate, suspended head) |
|
suspended |
warning (money-safe; the post-finalize sweep owns it) |
|
|
suspended |
warning |
terminal heads |
no evaluation |
— |
— |
already_imported replays return ORIGINAL persisted warnings, never re-evaluations.
Test matrix (all @axis-tagged)
| Layer | Case | Axis |
|---|---|---|
store |
pending head refused (typed); the fixture builder supplies the legacy shape for belt tests |
sad, replay |
store |
term chain not covering earliest Active → |
sad |
store |
cohort cutoffs ×4 programs × {day-before OK, day-of refused}; never-active qualifies on |
evil |
store |
family: ersg vs open sg (terminal OK / non-terminal |
evil |
store |
stamp battery (blank actor, |
evil |
store |
attribution: |
happy |
generator |
BeforeCutover: month < cutover skips + voids stray row; month == cutover pays; scheduled + MANUAL + reconcile all bounded; counter in report + event |
happy, sad, replay |
api |
batch lifecycle happy path end-to-end; knob-off 403 on writes with GETs readable; non-admin/service/readonly 403s; admin-without-state_office → office refusal naming state_office |
happy, sad, evil |
api |
the FULL replay table incl. replay-after-mutation (finalize → native suspend → resend → 200 with ORIGINAL facts) and canonicalization (key order, TZ form, |
replay |
api |
manifest: count/checksum/live-rejected mismatches → 409 with the four numbers; abort → supersede → fresh re-import in a new batch |
sad, replay |
api |
22.9 ordering: beyond-grace-active rejected at stage; within-grace staged + warned → finalize → generation pays (native parity) → knob-on sweep suspends later; cross-month batch: a warning at stage crosses grace by finalize → record flips rejected, batch loops, correct + re-finalize |
sad, replay |
api |
cross-service: unknown party/child/case, case-without-child → typed blockers; assessment blockers (not-active-at-cutover, no-terms-at-cutover, per-diem overlap, sibling conflict) |
fault, sad |
conc |
concurrent same-reference stages → one winner, loser answers from a FRESH tx (no 500); concurrent finalizes → lease 409; native create racing finalize → record rejected typed, batch loops |
conc |
fault |
kill mid-finalize after K records → resume completes exactly-once, same batch id, totals correct |
fault |
events |
imported payload key-set pinned (no external_reference, no notes, no money); batch summary counts-only; the parser resolves both keys |
happy, evil |
seed |
family F: first tick |
replay |
invariants |
all four new BLOCKING entries green on seed; red-harness per invariant fires |
evil |
e2e |
read-only: ersg/enrsg/ercs list tokens accepted; family-F detail renders provenance; no import mutation UI |
happy |
boundaries |
due=A / A−30 / A−31; suspension = 3mo exactly; Nov-30 → Feb-28 clamp; leap Feb-29; chrono-vs-SQL parity |
evil |
Risks
| # | Risk | Mitigation |
|---|---|---|
1 |
The finalize engine is the new complexity center |
Per-record txs + resumable state machine + fault-injection suite; the generator’s per-child error pattern reused |
2 |
Store-signature + pending-refusal churns ~40 test call sites |
Compile-driven; the test-lib builder absorbs the pending fixtures |
3 |
Family-index recreation on existing data |
Safe pre-1.0: no enhanced/rcs rows can exist (import is their only path); probe pins |
4 |
Canonicalization drift between tool and service |
ONE canonical form defined in the contracts crate; a parity vector test (tool-side hash == service-side hash) |
5 |
Seed family F determinism |
Pre-cutover pin (cutover = as_of + 1mo) keeps zero-generation; parallel row types keep A–E bytes |
6 |
Two-MR coordination |
A is surface-free (only test callers change); B is knob-off inert; the deploy order is the runbook’s anyway |
⁂ #1073 additions (ship with MR-B)
-
Closure constants + the qualifying-date rule (first Active strictly before 2014-01-01 rcs/ercs, 2014-08-01 ersg/enrsg;
signed_atfallback for never-active chains) — confirm against 22.8. -
Cutover protocol: SHINES pays every month <
cutover_month, CRAIG every month ≥ — the inter-system boundary agreement; CRAIG enforces its side by machine. -
Beyond-grace-active refusal posture: conversion refuses; DFCS completes-or-suspends in SHINES and re-exports.
-
Family taxonomy {sg, nrsg, ersg, enrsg} / {rcs, ercs} / {err} — the enhanced variants read as rate classifications of the same enrollment.
-
Post-finalize correction protocol: designed 409; corrections via native amendments + #1028 adjustments.
-
Imported money cap ≤ 10,000.00/month — confirm against COSTAR maxima.
-
Review baseline: SHINES authoritative pre-cutover;
snapshot_dateis the named baseline; the imported anchors are the next-dues; no review-history import. -
All four closed programs carry paper 6-month dues (only ERR exempt) — the invariant enforces it.
Review dispositions
| Finding | Disposition |
|---|---|
SS1 no machine cutover |
D1 staging (nothing live pre-finalize) + D5 persisted cutover written in the materializing insert + |
SS2 cohort legality |
D3 store rule + constants + ×4 boundary tests + blocking invariant |
SS3 authority too broad |
D2 closed-cohorts-only + source vocabulary + D12 explicit-admin ruleset + state-floor proof |
SS4 replay vs mutable data |
D4 canonical hash on the record row; "canonical equivalence" naming |
SS5 payable-month falsehood |
Deleted; D7 persisted per-record payment assessment + original-facts replay |
SS6 unpayable imports |
D7 term-coverage gate + assessment blockers + invariant |
SS7 overdue-active paid |
D6 refuse-beyond-grace (rationale recorded); within-grace = native parity |
SS8 family/lineage |
D8 taxonomy + extended/new indexes + locks + ActiveSibling + predecessor battery + typed conflicts |
SS9 caller-asserted refs |
D9 wire drops denorms; S2S child/party/case checks; caregiver floor |
SS10 no lifecycle |
D1 batch state machine + dry-run + rejection manifest + manifest gate + finalize + resume + correction semantics + the B3 tool |
G1 store pending seam |
D10 store refusal + test-lib builder + call-site migration |
G2 validation battery |
A2 (stamps, money, parties, caps) |
G3 attribution |
D9/D12 (store-stamped time; proof-derived identity; stamp hygiene) |
G4 race-loser fresh tx |
Replay-table note + the conc suite |
G5 batch verification |
The batch row is durable identity; the records ledger = the reconciliation export; resume never re-mints |
G6 operator path |
B3 xtask tool (OAuth, throttle, resume, manifest, closeout; no generation authority) |
G7 review provenance |
Recorded non-goal + named baseline + wording sweep |
G8 event fields |
D11 (no external_reference; |
G9 deploy ordering |
A4 parser in the substrate MR; the runbook order in B5 |
G10 schema/index/errors |
A1 migration + batch index + |
G11 seed models |
B4 parallel row types (model.rs + sql_row_impls.rs); the F pre-cutover pin; state-office stamps |
G12 invariants |
A5: four BLOCKING invariants incl. paper-slot coverage |
G13 web read scope |
B4: +3 program tokens, provenance render, e2e read-only spec, the no-mutation-UI statement |
G14 test wiring |
B2 registration + typed client + every named case in the matrix |
G15 #1116 sweep |
A5 semantic sweep of the five cited sites |
G16 docs inventory |
A4 ADR-003; B5 deployment guide / testing-reference / data-model / ACF-199 wording |
G17 exact semantics |
The warning-semantics table + the boundary suite + original-warnings replay |
Q1 cutover enforcement |
Answered by D5 (machine cutover) — nothing deferred |
Q2 consent posture |
The knob stays, gating all writes incl. finalize (D12) |
Q3 external_reference classification |
Events omit it (D11); the DB is the only surface |