Compliance API

Versioning

Each resource has its own monotonic integer version, incremented each time the underlying YAML changes. The public identifier is the integer; the underlying git SHA is kept in metadata for transparency.

Three ways to read a state

GET /api/v1/compliance/states/MO                       # current (live)
GET /api/v1/compliance/states/MO?version=4             # pin to version 4
GET /api/v1/compliance/states/MO?as_of=2026-03-01      # what it looked like on that date

All three return the same envelope shape. The meta block tells you which version you got:

{
  "data": { "abbreviation": "MO", "name": "Missouri", ... },
  "meta": {
    "api_version": "v1",
    "version": 4,
    "released_at": "2026-04-15",
    "git_sha": "abc12345"
  }
}

Why integers and not SHAs?

SHAs are great for internal audit but bad for customer-facing URLs:

  • SHAs aren't chronologically orderable at a glance
  • They aren't human-meaningful
  • They couple your code to our internal commit history

Integers solve all three. The SHA stays in meta.git_sha for anyone who wants to verify provenance.

Version history

GET /api/v1/compliance/states/MO/versions

Returns the full version list newest-first, each carrying the version number, release date, short SHA, commit author, commit message (as change_summary), provenance (source: human | llm_drafted | automated_sync), and a diff block listing which top-level keys changed vs the previous version.

GET /api/v1/compliance/states/MO/versions/4

Returns the historical payload at version 4 — exactly what a live GET /states/MO would have returned the day version 4 was published.

Caching

Every state response includes HTTP caching headers:

  • ETag: "MO-v4"
  • Last-Modified: <committed_at as HTTP date>

Honor them. Send If-None-Match: "MO-v4" and you'll get a 304 Not Modified with no body when the version hasn't changed — saves bandwidth on polling integrators.

How versions are minted

When the YAML file at data/compliance/states/<abbr>.yml changes (whether via a human PR, a future LLM-drafted PR, or an automated sync), a deploy-time compliance:reindex_history rake task walks git log for that file and writes one new compliance_snapshots row, with a monotonic version_number. There is no "version 0" — initial seeding creates version 1.

Schema evolution

The YAML schema is locked at data/compliance/state.schema.json. Renames bump the schema major version (a new file: state.schema.v2.json); every snapshot carries the payload_schema_version it was written under so historical reads stay correct.