ADR-011: Policy-to-Rules Traceability Pipeline
On this page
Context
Canopy’s jurisdiction.toml and JDM rulesets encode policy values from two sources:
-
Federal regulations — 7 CFR (SNAP), 45 CFR (TANF/CCDF), 42 CFR (Medicaid), IRS Pub 1075 (FTI)
-
State policy manuals — each jurisdiction’s administrative interpretation and state-specific options
ADR-003 established that eligibility logic lives in rulesets, not code. ADR-006 established the rulesets/{jurisdiction}/ directory structure. Neither addresses the question: how does a value in jurisdiction.toml trace back to the authoritative regulation or policy manual section that produced it?
A comparison of Georgia’s jurisdiction.toml against PAMMS (Georgia DHS’s Policy and Manual Management System) revealed 15+ incorrect values in SNAP alone, a fundamentally wrong TANF income methodology (FPL-based instead of Standard-of-Need-based), and incorrect Medicaid thresholds. These errors existed because there was no mechanism to:
-
Trace a configuration value to its authoritative source document
-
Detect when the source document changed and the configuration was not updated
-
Validate completeness (every value has a citation) or staleness (every citation was recently verified)
Georgia uses PAMMS — an Antora site backed by AsciiDoc source repos on GitLab. Other jurisdictions may use PDF manuals, proprietary case management systems, or no formal policy management system at all. The traceability mechanism must be jurisdiction-agnostic.
Decision
1. Citation manifests
Every jurisdiction.toml and every federal parameter file MUST have a sibling citations.toml that maps each configuration key to its authoritative source, effective date, and last verification date.
rulesets/
├── federal/
│ ├── fpl-2026.json
│ ├── snap-allotments-2026.json
│ └── citations.toml ← federal parameter provenance
├── georgia/
│ ├── jurisdiction.toml
│ ├── citations.toml ← jurisdiction value provenance
│ └── ...
└── {other-jurisdiction}/
├── jurisdiction.toml
└── citations.toml
Each citation entry is structured TOML (machine-readable, not comments):
[citations."snap.standard_utility_allowance_hc_monthly_cents"]
value = 40500 # mirrors jurisdiction.toml
authority = "pamms" # pamms | federal_register | fns_memo | state_statute | manual
source_ref = "dfcs-snap/modules/snap/pages/3617.adoc"
section = "Heating/Cooling Standard Utility Allowance"
manual_transmittal = "MT-84"
effective_date = 2025-11-01
federal_citation = "7 CFR 273.9(d)(6)(iii)"
verified_date = 2026-04-07
notes = "H/C SUA = $405/month"
The authority field distinguishes source types, making the schema jurisdiction-agnostic. A non-PAMMS jurisdiction uses authority = "manual" with a different source_ref format (e.g., a PDF page reference or a statute section number).
2. Policy source abstraction
A PolicySource trait in a canopy-policy crate abstracts access to the authoritative policy system. This is a tooling abstraction — used by cargo xtask policy commands, never at runtime.
Georgia implements the trait for PAMMS (reads cloned AsciiDoc source repos from a local .policy-cache/ directory). The fallback ManualPolicySource returns "manual verification required" for jurisdictions without a parseable policy system.
3. Automated audit (cargo xtask policy audit)
A CI-integrated validation step enforces:
-
Completeness — every key in
jurisdiction.tomlhas a corresponding citation -
Consistency — citation
valuefield matches the actual value injurisdiction.toml -
Staleness — no citation’s
verified_dateis older than 365 days (warning, not error) -
Schema — all required citation fields are present
-
Ruleset coverage (#1168) — the jurisdiction family audits every
rulesets/*/directory carrying ajurisdiction.toml(discovered, not configured), so the baselinedefaultruleset is held to the same bar asgeorgia;--jurisdictionnarrows to one ruleset -
Allowlist inventory (#1168) — every entry in
compliance/adr-031-citation-orphan-allowlist.tomlmust name a live citation; a deleted allowlisted citation (or an obsolete allowlist entry) is an error, closing the one citation population the structural checks cannot see
The overall verdict is always the final line printed (a per-family
✓ No errors is not the audit passing). This runs without network access —
it validates the structural integrity of the citation manifests against the
local configuration files.
4. Drift detection (cargo xtask policy drift)
A developer tool that compares jurisdiction.toml values against the policy source (e.g., parsed PAMMS AsciiDoc tables). This is advisory, not blocking — policy interpretation requires human judgment. It is explicitly NOT a CI gate.
5. Optional workflow guidance templates
Policy manuals describe caseworker procedures. These can inform the worker portal UI through workflow templates in rulesets/{jurisdiction}/workflows/. Templates describe recommended steps but never gate or block worker actions:
[[steps]]
order = 1
label = "Screen for expedited service"
action = "auto" # system handles this
required = true # federal requirement
policy_ref = "dfcs-snap/modules/snap/pages/3110.adoc"
A jurisdiction that provides no workflow files gets no guidance in the portal; the portal functions identically.
Consequences
-
Citation maintenance overhead — every
jurisdiction.tomlchange requires acitations.tomlupdate. This overhead is proportional to the number of values that change (typically annual batch updates after FNS COLA or state legislative sessions). -
AsciiDoc table parsing is best-effort — PAMMS tables use varied formatting. The drift detection command is advisory specifically because exact matching requires per-field extraction rules.
-
Annual update process —
rulesets/federal/README.adocis extended with citation update requirements. The existing schedule (January: FPL, September: FNS COLA, October 1: state changes) remains; citation verification is added at each update point. -
New jurisdiction onboarding — a new state creates
citations.tomlalongsidejurisdiction.toml. If they have a PAMMS-like system, they implement thePolicySourcetrait. If not, they useauthority = "manual"citations and verify values through their own process. -
Workflow templates are explicitly non-prescriptive — the architecture separates action handlers (which execute operations) from workflow templates (which describe sequences). No action handler checks workflow state. Workers CAN follow the recommended workflow but are never forced to.
Amendment 2026-05-25: reference ruleset (rulesets/default/)
Stage 6 MR1a (#499 / epic &51) introduces rulesets/default/ — a verbatim copy of rulesets/georgia/ promoted as the canonical reference ruleset that ships with canopy-core. The promotion closes a bootstrap circular dependency: canopy-core services won’t START without a rulesets/{slug}/ directory referenced by CANOPY_*JURISDICTION, but a new operator has no way to author a jurisdiction’s rules before booting Studio. By shipping default as a reference, an operator can boot canopy-core with CANOPY_*JURISDICTION=default, run Studio’s onboarding wizard to scaffold their own rulesets/{their-slug}/, then flip the env var.
This split makes the reference vs jurisdiction distinction explicit in the rulesets directory:
-
rulesets/federal/— universal regulatory floor (existing per ADR-006); applied to every jurisdiction -
rulesets/default/— reference implementation (new); a working ruleset suitable only for bootstrapping. Georgia’s rules in California production is useless, sodefault/is not intended for production deployment by any non-Georgia jurisdiction -
rulesets/{jurisdiction}/(e.g.georgia/) — a jurisdiction’s owned, deployable ruleset. Per the operating model (single-tenant per deployment, config-only customization), this is where all jurisdiction-specific customization lives
rulesets/georgia/ continues to exist as a peer of default/ (not a symlink) so the Georgia test harness remains stable. Citation entries in rulesets/default/citations.toml are inherited verbatim from Georgia at the time of MR1a; downstream wizard-generated bundles inherit them as starting templates that the integrator regenerates as they author real jurisdiction policy values.
Amendment 2026-06-09: currency tooling as built (ADR-031 / epic &59)
ADR-031 §1 extended this ADR’s currency story, and epic &59 built it (plan: policy-currency-drift). Two of this ADR’s sections are superseded by the as-built design:
-
§4 drift detection described value-level comparison via parsed PAMMS AsciiDoc tables, advisory because "AsciiDoc table parsing is best-effort". As built,
cargo xtask policy driftis hash-based, not parsed: each citation carries a committedsource_sha256pin (the whole cited source file at verification time, back-filled bypolicy sync-cache --pin), and drift is a mechanical changed-since-verified comparison against the refreshed cache. No table parsing exists. The advisory stance is kept and sharpened: theadr-031-policy-driftCI job is permanentlyallow_failure: true(a live-upstream comparison must not block unrelated MRs), drift never edits values, and the human re-verification loop is documented in the Policy Currency Runbook. -
§2
PolicySourceis now code, not description:canopy_policy::source::PolicySource(resolve_section/content_hash/cache_sync), implemented byPammsGitSource(git-backed manuals cloned into.policy-cache/, hashed for pinning) andManualSource(every resolution answers manual-verification-required). The federal family deliberately does not implement the trait —rulesets/federal/*.jsonARE the verified snapshot (upstream is PDF/memo publications with no parseable source); federal currency assurance is theindexing.tomlwindow check plus the federal citation audit.
The audit itself (§3) also grew per ADR-031: federal source family, reverse completeness (orphaned citations are errors, allowlisted only with written reasons in compliance/adr-031-citation-orphan-allowlist.toml), source-pin schema checks, and annual indexing windows.
Amendment 2026-06-23: rule→regulation citation NOT introduced by T2-2 (#679)
The T2-2 derivation graph (ADR-028 Amendment 2) records, per derived fact, the RuleRef that produced it (ruleset_name + JDM node_id + node_kind + winning rule_id_in_node) at corpus_hash version granularity. This is rule traceability, not a rule→regulation citation: the graph does not link a fired JDM node to its CFR/PAMMS authority. A rule→citation capability — a rule-citations.toml keyed by RuleRef, complementing the existing per-value citation manifests (§1) — is a future ADR-011 extension explicitly NOT built by #679, recorded here so the next reader does not assume it landed.