Skip to main content

Shared Contract — One Truth

Files that are frozen together

kxinspect_backend_python/docs/contract-v1.md ← prose contract, G-01
kxinspect_backend_python/docs/openapi-v1.json ← wire snapshot
kxinspect_backend_python/docs/contracts/examples/*.json (15) ← golden envelopes
kxinspect_backend_python/scripts/export_fixtures.py → bundle
kxinspect_backend_python/app/domain/charge_state.py + deadline.py → vectors
kxinspect_frontend_flutter/assets/fixtures/{app_state,manifest,vectors,media}
kxinspect_backend_python/app/schemas/* ← StrictModel definitions

Changing any of those without a new G-01 decision breaks cross-repo codegen and causes contract tests to fail on the other side.

Why app/domain being pure matters

app/domain/charge_state.py imports only enum/dataclasses; deadline.py imports only datetime. No FastAPI, Pydantic, filesystem or clock. That single rule lets:

  • charge_state_vectors.json (30 rows) and deadline_vectors.json be generated by python scripts/export_fixtures.py --output /tmp/bundle without importing the web layer,
  • the same JSON be replayed by tests/unit/test_domain.py and test/unit/charge_state_vectors_test.dart — two runtimes, one oracle.

Any future lifecycle field must land there first.

Digest highlights

ConceptFrozen detail
IdentifiersCHG-, BKG-, INS-, RPT-, NTF-, TCK- seed; task id client UUID; attachment att_<32 hex> opaque
MoneyamountMinor int + currency ISO 4217; floats rejected; totals per-currency
Textgrapheme 10–2000 via UAX #29; server graphemes.py = Dart package:characters
Enums11 frozen tables (inspectionType, chargeStatus, …) — unknown ⇒ protocol error
Envelope{data,meta} or {error,meta}; stateEpoch only on reset, storeRevision per commit
Idempotency(method, routeTemplate, resourceId, key) scope; RFC 8785 digest SHA-256(canonical JSON); only 2xx cached
DeadlinedeadlineAt = raisedAt + graceDays UTC, inclusive now >= deadlineAt, reconciliation under lock
SeedreferenceNow 2026-08-01T12:00:00Z; Europe/London; 30-day default grace

OpenAPI snapshot discipline

docs/openapi-v1.json is checked in. uv run python scripts/export_openapi.py --check docs/openapi-v1.json diffs the live FastAPI generation byte-for-byte. On mismatch you do not overwrite — you file a contract change, regenerate vectors/fixtures/examples, and update Dart api_models + domain_mapper lockstep.

Fixture bundle commitment

After any seed edit, the steward must run the export, verify via verify_fixture_manifest.py, and cp the bundle into kxinspect_frontend_flutter/assets/fixtures/ and commit. Fixture-mode review must stay network-free; the frontend FixtureHttpClientAdapter must render the same states as remote.

See Fixture Bundle for the file map and Decisions for frozen interpretations (Open vs History overlap, bottom nav dedup, etc.).