Plan: ERR (UAS 542) Kinship-Subsidy Flow (#1069 program)
On this page
Status
| Step | Description | Status |
|---|---|---|
Step 0 |
GitLab filing: #1069 weight 3→8 + |
Done (2026-07-23) — all filed; decision comment on #1069 |
M0 (fix MR) |
Acting-worker office proofs ( |
Done (2026-07-23) — MR !1027 (impl 3c56030925d67b0779307e50b992ec4fa7251e09, merge 20269dde6045e7317c98d42fa45b393477b627dc); #1102 closed; J-record on the MR |
M1 (MR1) |
Generator months: |
Done (2026-07-23) — MR !1028 (merge 177cc273af8e2704c3c131ca181161d54ab43a5b); 5 commits, each J-reviewed with findings remediated pre-commit (DataGap touch-nothing; settle-as-claim closing the reviewer-found lost-signal window; month-granular recovery scan; honest ended-anchor scope). #1098 closed by the claim/settle rework; #1108 filed (devstack tick vs exact-assertion suites, pre-existing). Full battery green |
M2 (MR2) |
ERR creation: |
Done (2026-07-23) — MR !1029 (C1 59a485b0 / C2 a7df8983 / C3 7ae5bde6 / C4 81b85e33 / C5 7cddabf8 + budget-gate fixes c4d9f86f, 5b71446f; merge f56a799fd8f3e9ef56e987923eff2f9b1de87a6f). Each commit fresh-subagent J-reviewed with findings remediated pre-commit (J-record on the MR). Battery green incl. fresh keyed reseed (verify-seed OK, 50 invariants clean over the seeded partial row). Bonus: #1108 root cause fixed (nextest lease membership) |
M3 (MR3) |
Per-diem handoff: |
Done (2026-07-23) — MR !1032 (merge 6e393149c5c4418e1c5b9a9da1e4f4c9d690098b): two J-reviewed commits (5c1447c3 authority/schema/finalize-fix; 6f3da8ee engine + handshake) + two gate fixes. As-built deviations: the engine and wire commits FOLDED into one (enforcement and handshake interleave in the same files); detection facts write on EVERY scheduled scan posture, observe included (the third documented observe-run write; previews stay pure-read — execute upserts on enforce); the |
M4 (MR4) |
BFF + docs close-out: ERR create form (PRG; BFF-minted |
Done (2026-07-24) — MR !1033 (merge e9f4f49344b31a161efab9c44b09182ac581c7f4); program closed (#1069 closed, epic &70 ticked, ⁂ list on #1073, follow-up #1110 filed). As-built deviations: the e2e non-kinship refusal arm is replaced by the deterministic placement-not-found verbatim-flash arm (non-kinship + inactive shapes are API-covered by M2’s |
Issues: #1069 (tracking; M4 closes) · #1102 M0 (closed) · #1098 (M1 closes) · follow-ups #1103 #1104 #1105 #1106 #1107
Branches: fix/1102-acting-worker-proofs (merged) · feature/1069-generator-months (this plan = first commit) · feature/1069-err-create · feature/1069-perdiem-handoff · feature/1069-err-web
Provenance: 8-reader recon workflow + Plan-agent design + internal 3-lens pass (6 P1/7 P2/10 P3, reworked) + external stop-ship review (2026-07-22, ~47 findings — authoritative) driving the M0–M4 split and the F-series decisions. The full finding→disposition index is in the approved working plan (mirrored below in §Review dispositions).
Context
The subsidy ledger (ADR-052), review workflow + verified-office authority (ADR-054),
monthly generator (ADR-053), and BusinessClock exist — but no agreement can be created via
the API: ADR-052 deferred creation to the eligibility-bearing flows so "nothing payable can
exist unvalidated". ERR (Enhanced Relative Rate, UAS 542) is the first such flow: the
kinship subsidy paid while a relative caregiver awaits foster-home approval. GA 22.8:
creation requires an ACTIVE kinship placement; payments run from the FIRST DAY of
placement; a 120-day home-approval clock applies; ERR terminates when the caregiver’s
foster per diem begins; ERR carries no paper review (already encoded in
types_for_program).
Decisions
| # | Decision | Source |
|---|---|---|
U1 |
Prorate the first partial month; policy constants behind ONE jurisdiction-keyed seam ( |
user fork + review |
U2 |
120-day clock report-only + manual termination (new reason token through the existing transition endpoint) |
user fork |
U3 |
Per-diem handoff = third sweep enforcement leg — with a durable handoff-fact table, truth-dated terminations, suspended-head support, and a mixed-version execute handshake |
user fork + review |
U4 |
Full BFF surface in this program |
user fork |
F1 |
ONE-SHOT CREATE-ACTIVE (the strictly-after transition-date rule makes two-step activation structurally unable to start coverage on the placement date); generic |
forced + review |
F2 |
Backdating bounded at |
review |
F3 |
Dedicated |
forced + review |
F4 |
ERR feature gate |
review |
F5 |
The generator’s exclusivity-repair void arm is a STANDING policy (completes ADR-053’s per-diem-wins), not knob consent — declared openly, ⁂-confirmed |
review |
F6 |
Handoff termination |
review |
F7 |
Same-placement per diem auto-terminates ( |
review |
F8 |
Creation idempotency = client-supplied |
review |
F9 |
Expand/contract for the payments month identity: GENERATED |
review |
Design (per MR)
Authoritative detail for each MR lives in the M-row of the Status table plus the sections below; the externally reviewed working plan (approved 2026-07-22) is the drafting source.
M1 — generator months
-
Migration (EXPAND only):
payment_month DATE GENERATED ALWAYS AS date_trunc('month', period_start::timestamp::date) STORED— the cast makes the expression immutable (a baredate_trunc('month', DATE)resolves through the timezone-sensitivetimestamptzoverload and cannot back a unique index); v2 unique(agreement_id, payment_month) WHERE agreement_id IS NOT NULL AND status <> 'voided'; the calendar-month CHECK becomes the month-window CHECK (period_end= the month’s last day;period_startmay be mid-month). The legacy(agreement_id, period_start)index REMAINS this release so old replicas'ON CONFLICTstays bound (a transitional 23505 on a new-partial collision fails loud and re-enqueues); #1106 drops it after rollout. The unit-month CHECK is unchanged: a subsidy row is ONE unit of the month’s entitlement (day_count = 1,daily_rate = gross); the period columns state coverage; partial birth rows carry the prorated award (contracts + UI comments updated in M4). -
expected_month_row(tx, agreement, month) → Full(terms) | Partial{from, terms} | None(reason)— the ONLYstatus_as_of/terms_as_ofcaller in the month loop; used by the generate gate, the derivation compare (including expected-None), andreconcile_inactive_rows/reconcile_uncovered_month(expected-Partial months are COVERED — the churn-loop kill). Rule order: (1) live per-diem overlap → None(perdiem_exclusivity), checked BEFORE the existing-row match — the F5 repair arm: undisbursed subsidy rows voided (payments_voidedcauseperdiem_exclusivity), disbursed frozen +derivation_mismatch+ WARN; (2) active as of month start → Full pricedterms_as_of(month_start); (3) the agreement’s first ACTIVE interval — native ERR births only (imports and SG/RCS excluded; reinstatement months explicitly zero, ⁂) — starting in-month → Partial pricedterms_as_of(activation)(a term append inside the window prices from the NEXT month); (4) None(not_active). -
Candidacy = active-interval OVERLAP with the month, at
candidate_children’s intervals arm AND `child_active_agreements(the drain path). Arbitration replaces the exactly-one-agreement rule: expected rows are computed for EVERY overlapping agreement (cross-program included); exactly one non-None pays; two-plus → the agreement covering month start (the incumbent) wins and a successor’s birth month is None(superseded_month) (⁂); two-plus incumbents → anomaly, generate nothing + WARN + counter. -
Reconcile queue: transactional claim/settle — the SETTLE IS THE CLAIM (the repair transaction’s first statement flips
processed_at, so every concurrent enqueue waits on the whole tx; rollback restores the row live); the attempts bump commits independently so error loops converge on the dead-letter cap (10,subsidy_reconcile_queue_dead_letterinvariant + operator reset). Closes #1098. -
Recovery loops: per-diem lifecycle changes (placement.ended voids AND the per-diem writer’s reciprocal overlap check — no manual per-diem void endpoint exists, #1028) enqueue
perdiem_changemonths for the child’s covering agreements via a MONTH-granular scan (exclusivity judges whole months); below-floor months WARN at the enqueue site; placement.ended gains the subsidy arm — a transient WARN for every ended ERR anchor, durable invariant re-surfacing only for fully-voided anchors (financial holds no placement status; the cross-service check is #1107 territory). -
Invariants: month grouping via
payment_month; the disbursed-derivation pricing arm becomes proration-aware AND expected-row-parity based; a blocking partial-row provenance probe (mid-monthperiod_start⇒ the agreement’s first-active-interval start + program err + native provenance); the per-diem-overlap invariant’s remediation text rewritten; thewarn_on_subsidy_overlapNOTE in main.rs rewritten (J5). -
payment_createdemits the ROW’s gross (a partial row’s prorated award), never the term monthly amount.
M2 — ERR creation
See the Status row for the full inventory. Key contracts: creation is feature-gated (F4)
and idempotent by client_request_id + canonical hash BEFORE volatile checks (F8); all
attribution flows from the acting worker + the bound CreateActive proof through a
stamp-free CreateActiveParams; case_id/assigned_worker_sub derive from the placement
record; the S2S read is the NEW craig-placement subsidy-eligibility minimal endpoint
returning an Eastern-dated started_on (financial never converts timestamps); S2S
failures are 503 fail-closed pre-tx; a live per diem beginning at/after the proposed
effective date refuses creation (holdovers do not); the pay-excl child lock + in-tx
re-check close the create-vs-payment race; the −12-month floor refuses silently-unpayable
coverage; evidence keys are REQUIRED, honestly-unverified references.
M3 — per-diem handoff
See the Status row. Key contracts: the durable subsidy_perdiem_handoffs fact is the
authoritative "per diem began" record (detection insert-once; enforcement stamps
enforced_run_id; correction = state_office reinstatement + corrected_at, refused while
the per diem is live); the scan pins deterministic earliest (period_start, id) evidence
and re-verifies the PINNED payment in-tx; terminations are truth-dated (F6) so reconcile
months cover the overlap naturally; the execute handshake carries per-leg acknowledged
counts (mixed-version safety); a handoff-only scheduled run records executing/completed
via SweepConfig::any_writes(); completion-event staging failure never rewrites committed
run counters.
Review dispositions
The external stop-ship review (2026-07-22, ~47 findings) is fully dispositioned; the
finding → fix map lives in the approved working plan and is reflected in the M-row
inventories and F-decisions above. Highlights: the non-immutable date_trunc index →
generated column; the as-of-month-start selection gates → overlap candidacy
expected_month_row; the unreachable partial month and handoff repair → F5/F6 semantics;
mutable-row handoff evidence → the fact table; proof forgery vectors → M0; unsound
natural-key replay → F8; ungated money policy → F4; delivery shape → this M0–M4 split.
Verification
Per MR: fmt/clippy/nextest over touched crates → fresh-subagent J1–J8 per substantive
commit → token commit → full pre-push battery (budgets, axis, route-role, evil-corpus
advisory, e2e where applicable) → MR (Relates to #1069; M4 Closes) → merge per the
standing procedure → J-record note → closing/related comment → Status row here updated.
M1 additionally: the FULL existing generator lifecycle suite passes with only the sites
this plan names changed; forced month-identity collision test; queue crash-recovery test
(kill between claim and repair → the row survives). Program close: #1069 AC walk, epic
&70 tick, plan → archive, ⁂ list appended to #1073.