Plan: Action/Verb Coverage Matrix (epic &60)
On this page
Implements ADR-031 §2 for epic &60 (parent &58). Grounding below is code-verified (2026-06-09). Issues are cut from the Status rows per ADR-013 once this plan lands.
Status
| MR | Description | Status |
|---|---|---|
MR1 (schema + gate skeleton) |
Action-catalogue schema in |
Done (2026-06-09) — |
MR2 (SNAP catalogue) |
Author the SNAP action catalogue — the genuine policy-reading deliverable. Sources: 7 CFR 273 (intake 273.2 incl. expedited 273.2(i); reporting 273.12; ABAWD 273.24; claims 273.18; hearings 273.15), PAMMS SNAP volume. Review expansion (2026-06-09): also 273.13 (timely/adequate adverse-action notice), 273.17 (restoration of lost benefits), 7 CFR 274 (issuance/replacement/expungement), 272.4(b) (bilingual services), 272.8 (IEVS — rows live in |
Done (2026-06-10) — 153 SNAP rows authored from the PAMMS SNAP manual (98 cached pages) + 7 CFR 272-275 across 7 regulatory slices: 92 covered (every binding verified byte-exact against the snapshots — 0 operationId corrections needed), 61 honest gaps. Deviation (recorded): schema gained |
MR3 (CLI parity enforcement) |
Make ADR-007 enforceable: the gate parses the CLI command registry ( |
Done (2026-06-10) — |
MR4 (remaining programs) |
Same authoring discipline as MR2; each program lands as its own reviewable MR (TANF, Medicaid+CHIP, CAPS, WIC — four MRs, not one bundle; authoring effort is the real cost). Regulation pulls expanded by the 2026-06-09 review: TANF — 45 CFR 261-265 + PAMMS 1300s (work plans, sanctions, time limits, GRG) plus 45 CFR 260 (FVO good-cause waivers), 45 CFR 205.10 + 205.55-60 (notice/hearing baseline + IEVS), 42 USC 608 statutory bars (felon/fugitive, drug felony), IRP/TFSP (42 USC 608(b); PAMMS 1815), IV-D cooperation (45 CFR 264.30-31), cash issuance + ACF-196 expenditure basis. Medicaid/CHIP — 42 CFR 435 (MAGI/non-MAGI, ELE, TMA, hearings 431 Subpart E) plus 42 CFR 457 in full (CHIP/PeachCare — absent from the original plan despite being implemented), 435.916 ex parte + the renewal entity, 435.915 retroactive coverage, 435.1110 presumptive eligibility, 435.952 reasonable compatibility, 435.956 reasonable opportunity period, 433.137-138 TPL, SSA §1917(c) LTSS transfer-of-assets + patient liability, 431.224 expedited hearings, §1903(v) EMA, 435.1200 account transfer (rows in |
Done (2026-06-10) — all four program MRs landed same-day. TANF: 224 rows (91 covered / 133 gaps; 0 operationId corrections first-run; gap signature = unwired implementations: |
MR4b (cross-program/system catalogue, #763) |
|
Done (2026-06-10) — |
MR5 (triage + blocking flip) |
File an issue per un-allowlisted gap the full matrix exposes (linked under epic &60 or the owning program epic), allowlist each with its issue ref, then flip |
Done (2026-06-10) — 57 capability-level issues filed (#771-#827), 372-entry allowlist generated (375 total with pre-existing CLI/&56 entries), gate exits clean (335 covered / 372 allowlisted / 0 gaps / 0 stale). |
Design — grounded current state (code-verified)
-
Endpoint inventory already exists, machine-readable and committed:
docs/modules/ROOT/openapi/*.json— 16 services (incl.verification.jsonas of the review-amendment MR), 230+ operations with 100%operationIdcoverage, each path → verb →operationId(+ auth + schemas), maintained bycargo xtask api-docs(live-fetch + snapshot-diff,xtask/src/cmd/api_docs.rs:76-182). The gate consumes these offline; it never needs running services. canopy-exchange remains snapshot-less (stub — no annotated routes); the gate reports its rows as service-unsnapshotted, not path-absent. -
The only regulation→implementation artifact is prose:
federal-requirements.adoc(213 lines;| Citation | Requirement | Implementation | Service |rows, no verb/path). Per the 2026-06-09 review it is stale for four of five programs and is NOT the seed — the CFR + PAMMS reading is; the doc gets refreshed as a byproduct of catalogue authoring. -
ADR-007 parity is unenforced: ~16 CLI command modules / ~80-100 subcommands (
tools/canopy-cli/src/cmd/), no parity test of any kind. -
Gate pattern precedent:
compliance.rs(data-tenancy matrix),rules_lint.rs,policy.rsaudits — all: load schema-validated TOML → walk artifacts → cross-check allowlist (mandatory reason) → grouped report → exit 1.action-coveragemirrors this exactly; allowlist schema mirrorscompliance/adr-011-*-allowlist.toml. -
&56 as the canonical row: pre-Track-1, "worker records a reported change" / "worker accepts an IEVS match" had no endpoint — the catalogue row would have bound to nothing and the gate would have flagged it. Track-1 merged claim/author/provenance endpoints (#670/#671/#682); #672-678 remain open and become allowlist entries with issue refs.
Design — review findings (2026-06-09)
A full coverage review (9 parallel readers over the plan/ADRs, GitLab, the regulation-source pipeline, the gate’s input corpus, and every program’s CFR surface; ~105 candidate gaps verified) ran before MR1 started. Confirmed findings and their dispositions:
-
The gate’s ground truth was broken — repaired by the review-amendment MR itself: (a)
canopy-verificationwas absent from the api-docs SERVICES list, so its 6 documented routes (verifications CRUD/resolve, IEVS discrepancies) had no snapshot — added,verification.jsoncommitted; (b) `canopy-reporting’s ApiDoc registered only 8 of its 22 annotated routes — every TANF (ACF-199/196/WPR) and Medicaid (T-MSIS/CMS-64/CMS-416) federal-reporting path was silently missing from the committed snapshot — registration fixed, snapshot regenerated. (c) Snapshot freshness is pre-push-only with SKIP-if-not-running semantics and no CI job; the MR1 gate must treat snapshot staleness as a visible caveat in its report (a fresh-snapshot CI job is a candidate follow-up, not in scope here). -
Cross-program mandates had no home → MR4b (#763). Mass-change/COLA processing is the headline: zero capability today, and it is how every benefit table from the &59 indexing calendar actually reaches the caseload.
-
The per-program regulation pulls under-scoped every program (worst: 42 CFR 457 absent entirely while PeachCare is implemented; CAPS row listed only the already-built features; WIC omitted its processing standards, which are literally
return Nonein code today). MR2/MR4 rows now carry the expanded enumerations. -
actor=systemrows were unbindable (schedulers/event subscribers — renewal scheduler, ELE scheduler, EBT expungement, adverse-action timing). Schema gains thesystem-jobbinding kind (component + verified test ref). Mirrors the &61 tier rule: tier-appropriate coverage, no binding theater. -
BFF rule made explicit: worker/applicant actions bind to the service endpoint the BFF orchestrates (always snapshotted — canopy-web’s 30 action handlers and the portal flows are OpenAPI-invisible by design); UI-surface parity is &61’s job via journeys. ADR-007’s UI leg is intentionally deferred to &61 and recorded here.
-
Hollow-binding caveat recorded: program-agnostic endpoints (generic notices/appeals/renewals paths) "exist" for every program while the capability behind them may be SNAP-only (e.g. SNAP-only notice templates, SNAP-rooted certification creation). The catalogue’s per-row
test refis the honesty check — bind the row to a program-specific test, not just the shared path. -
Regulation-source pipeline gaps (the "are ALL state/federal regs flowing in?" half of the review) are &58-track follow-ups, filed: #764 (multi-agency
[policy_source]— CAPS/DECAL + WIC/DPH are outside sync/pin/drift entirely; all their citations are manual), #765 (4 phantom PAMMSsource_ref`s pass the audit; bare-section refs unpinnable; TANF has no `rulesets/federal/data file; CHIP has no namespace). -
Expected-scale note: the review’s program readers found dozens of genuinely absent mandated capabilities (TANF sanctions lifecycle + a 60-month clock that never accrues, Medicaid ex parte/renewal entity/retro/PE, CAPS redetermination, WIC processing deadlines). The catalogue will be born with a large allowlist; that is its purpose, and MR5’s triage converts it into the issue backlog.
Design — decisions
-
Catalogue is data, schema is code. Schema lives in
canopy-policy(xtask-only crate, zero runtime dependents — same placement as the citation schema); data lives undercompliance/action-catalogue/per program (sibling to the other compliance TOMLs), NOT inrulesets/— mandated actions are jurisdiction-agnostic federal/program facts; jurisdiction-specific actions get an optionalrulesets/{jurisdiction}/action-catalogue.tomloverlay later if ever needed. -
Derived status, not hand-maintained. A row never carries
status = "implemented"— the gate computes coverage from the OpenAPI snapshot on every run. The only hand-maintained exception surface is the allowlist, and every entry there carries a reason + issue ref. (Prevents the catalogue rotting into aspirational documentation.) -
operationIdis the stable join key (paths can be re-rooted); path+verb are verified too, and a mismatch between the three is itself a finding. -
Actions, not features. A row is "applicant reports a change of circumstances (7 CFR 273.12)", not "change-report page exists". UI coverage is not checked by this gate (BFF pages aren’t OpenAPI-described); the scenario inventory (epic &61) covers behavior through the UI — keeping each gate single-purpose.
-
Authoring effort is the real cost and is split per program (MR2, MR4) so each lands reviewably; an honest partial catalogue with allowlisted gaps beats a complete aspirational one (ADR-031 stance).
Verification
-
Unit/fixture tests for the gate (catalogue row binds to fixture OpenAPI → covered; missing verb → finding; allowlisted → suppressed-with-reason; CLI enum fixture → parity findings) following the quality-budgets fixture-tree test pattern.
-
Live:
cargo xtask policy action-coverageagainst the real committed snapshots; spot-audit 10 random SNAP rows against the actual PAMMS/CFR text in review. -
Each MR through the standard gate; CI flips to blocking only in MR5 after the gap triage.