Skip to main content

Backend Verification

Canonical gates

cd kxinspect_backend_python
uv sync --locked
uv run ruff format --check .
uv run ruff check .
uv run mypy app # strict: disallow_any_generics, no_implicit_reexport
uv run pytest -q --cov=app --cov-fail-under=85
uv run python scripts/export_openapi.py --check docs/openapi-v1.json
uv run python scripts/verify_fixture_manifest.py

CI must run export_openapi --check before any deploy — a mismatch means contract drift and must be negotiated at G-01.

Test harness guarantees

  • No test writes to the real runtime/ — each constructs build_app(settings=Settings(runtime_root=tmp), clock=ManualClock(...), ...) with tmp_path and TemporaryDirectory.
  • No network — httpx TestClient wraps the in-process FastAPI app.
  • No wall clock — ManualClock.instant = parse_instant("2026-08-01T12:00:00Z"), advance(timedelta(...)) explicitly.
  • Deterministic ids — SequentialIdGenerator replaces UuidGenerator in unit/api tests.

Suites

PathWhat it covers
tests/unit/test_domain.pyexhaustive (status,event) transition matrix, actor_for, open/history tabs, deadlineAt arithmetic, inclusive boundary, grapheme min/max, contest payload
tests/unit/test_store.pyJsonStore commit, atomic replace, epoch/version checks, ring trim, idempotency ledger replay, OperationBarrier shared/exclusive, flock, marker guard, GC of uploads
tests/api/test_reads.pyGET /health, /bookings, /hub, /inspections, /charges, /notifications, /sync-snapshot + deadline reconciliation on read
tests/api/test_commands.pyaccept/contest/pay/task/notification read, Idempotency-Key required, RFC 8785 digest, expectedVersion/Epoch checks, race with deadline, error shapes
tests/api/test_attachments_events_dev.pyattachment staging/finalize/rollback, limits, multipart parse, SSE frames/heartbeat/replay with Last-Event-ID, dev reset/marker/chaos
tests/contract/test_contract_v1.pygolden docs/contracts/examples/*.json matches live responses byte-for-byte; OpenAPI snapshot invariants

Scripts

ScriptGate
scripts/export_fixtures.py --output <dir>validates seed, writes byte-stable bundle (app_state.json + manifest.json + media) with sorted keys
scripts/verify_fixture_manifest.py [--bundle <dir>]checks manifest SHA-256 vs actual bytes; default checks committed assets/fixtures/
scripts/export_openapi.py --check <path>diffs generated OpenAPI vs docs/openapi-v1.json
scripts/reset_runtime.py --runtime-root <path>destructive reset; refuses unless .kxinspect-runtime marker UUID matches

Coverage & typing

  • tool.coverage branch=true, source=[app], omit=[app/__main__.py]; fail_under=85.
  • tool.mypy strict=true, warn_unused_configs, disallow_any_generics; sse_starlette ignored via override; RuntimeLockedError paths marked # pragma: no cover only where filesystem guard cannot be exercised without a second process.

Manual spot-checks (for reviewers)

# deadline inclusive at boundary
KX_DEMO_NOW=2026-08-01T12:00:00Z uv run uvicorn app.main:create_app --factory &
sleep 2; curl -s http://127.0.0.1:8000/api/v1/charges/CHG-001 | python -m json.tool | grep deadlineAt
# expect CHG-001 that is 1s before deadline stays outstanding, at deadline becomes accepted

# idempotency replay
EPOCH=$(curl -s http://127.0.0.1:8000/api/v1/charges/CHG-002 | python -c 'import json,sys;print(json.load(sys.stdin)["meta"]["stateEpoch"])')
KEY=$(uuidgen)
for i in 1 2; do curl -s -X POST http://127.0.0.1:8000/api/v1/charges/CHG-002/accept -H 'Content-Type: application/json' -H "Idempotency-Key: $KEY" -d "{\"expectedStateEpoch\":\"$EPOCH\",\"expectedVersion\":1}" | python -m json.tool | grep storeRevision; done
# second storeRevision must not increment