canopy-rules Data Model

On this page

Cross-link: canopy-rules API Reference · Source: migrations/

Tables

Table Purpose

rule_evaluations

Per-evaluation audit row. One row written every time POST /v1/rules/evaluate is served. Carries rule_set_name (text reference to the JDM file served from the filesystem via the NamedFilesystemLoader, not a foreign key — see ADR-003 / jdm-ruleset-rewrite Step 2.5), an optional (context_type, context_id) pair that callers use to tie an evaluation to a determination / case / application, the full input and output JSONB envelopes, and duration_ms for performance monitoring. This is the canopy-rules audit trail used to replay any historical determination against the same input.

event_outbox (ADR-018 + ADR-039)

Per-service transactional outbox (ADR-018), schema single-sourced in crates/canopy-mq/outbox-migrations/ and generated into this service (ADR-039). Columns, indexes, hold semantics, and the migration inventory are documented ONCE in the cross-cutting description — see the data-models index.

ruleset_corpus_versions

T2-7 (#680) corpus-version history for non-persisting dry-run replay (ADR-027 §6, ADR-028). One row per (corpus_hash, ruleset_name): the winning JDM content (JSONB) of each corpus version the service has booted with, keyed by the #682 SHA-256 corpus_hash. The current corpus is persisted idempotently (ON CONFLICT DO NOTHING) at startup, before the router serves traffic, so a determination minted in the same boot is immediately replayable (closes the startup race). POST /v1/evaluate?corpus_hash=<hash> replays that exact version from this table; an unknown hash → 422. Append-only — ADR-003 keeps rulesets as code with no runtime authoring path, so this is a record of versions seen, not an editing surface.

rule_sets no longer exists. The original schema (20260326000000) provisioned it as a startup-cache table that auto-imported JDM files; the JDM ruleset rewrite (see docs/modules/ROOT/pages/plans/jdm-ruleset-rewrite.adoc Step 2.5) replaced it with direct filesystem serving via a NamedFilesystemLoader wrapping zen-engine’s FilesystemLoader. Migration 20260412000000 drops the now-vestigial table; rule_evaluations.rule_set_name is intentionally a TEXT column (not an FK) so the drop is safe for the audit trail.

Relationships

Diagram

The three tables are independent — there is no relationship between the ruleset audit trail, the event outbox, and the corpus-version history. (rule_evaluations and ruleset_corpus_versions both reference a corpus hash, but only as a value — there is no FK.)

Cross-service FKs (ADR-001 boundary)

canopy-rules holds no Postgres-level foreign keys to other services. rule_evaluations.context_id is an opaque UUID supplied by the caller (canopy-snap, canopy-tanf, canopy-medicaid, canopy-caps, canopy-wic, canopy-eligibility); canopy-rules makes no attempt to validate it against any other database. The rule_set_name column is also unenforced — it refers to a logical name in the filesystem ruleset loader, not a DB row. This is intentional: rulesets evolve via JDM file revisions in rulesets/, and the audit trail must remain readable even after a ruleset is renamed or retired. event_outbox likewise holds no cross-service FKs — its payload is a self-contained JSON event envelope routed by routing_key, with no DB-level reference to any consumer.

Retention

The ruleset audit trail’s retention floor is the lifetime of any determination that referenced the ruleset. Determinations are retained for the case + appeal window across all program services (typically 3 years post-closure for SNAP per 7 CFR 272.1(f), 3 years post-final-claim for Medicaid per 42 CFR 433.32, longer for cases under audit or appeal), and a determination is only replayable while its corresponding rule_evaluations row survives. In practice this makes rule_evaluations an append-only, indefinitely-retained table in production. Archive moves are operator-driven and rare.

Indexes

  • idx_rule_evaluations_rule_set_name — per-ruleset evaluation listing (regression analysis, audit replay)

  • idx_rule_evaluations_context — composite (context_type, context_id) for retrieving the evaluation history of a specific determination

  • event_outbox_* — the three generated partial outbox indexes (drainer hot path, lease-aware claim, ADR-039 held-skip); documented once in the data-models index

Migration files

  • 20260326000000_create_rules_tables.sql — original schema (rule_sets startup cache + rule_evaluations audit trail) with per-rule-set-name and per-context indexes

  • 20260412000000_drop_rule_sets_table.sql — drops the rule_sets cache table after the JDM ruleset rewrite moved ruleset serving to the filesystem via NamedFilesystemLoader; rule_evaluations is untouched

  • 20260508000000_create_event_outbox.sql + 20260518004851_event_outbox_lease_columns.sql + 20260713000000_event_outbox_hold.sql — the generated ADR-039 single-sourced outbox migrations (cargo xtask outbox-migrations --write); documented once in the data-models index

  • 20260626000000_create_ruleset_corpus_versions.sql — T2-7 (#680) corpus-version history table, primary-keyed (corpus_hash, ruleset_name) for idempotent boot insert and corpus-version replay

All migrations are forward-only per ADR-016.

Edit this page · default