Contract-Fixture Consumer Adoption (E-15) — closing the W16 cross-repo silent-pass (v7.10)
The /control-room/framework page threw a TypeError in production for 13 days with green CI the whole time: the FitTracker2 producer emitted `timestamp`, the fitme-story consumer expected `event.ts`, and both repos' test suites agreed on the wrong shape (W16). The fix is a contract-sampling discipline — validate what a consumer reads against the producer's REAL sampled output, never a hand-authored fixture. The FT2 substrate shipped 2026-06-07; E-15 closes the cross-repo consumer half: a unified checker (shape = hard fail, freshness = asymmetric), a PII-safe audit-log canonical sampler, and a weekly re-sample cron.
What do T1 / T2 / T3 mean?▾
Contract-Fixture Consumer Adoption (E-15)
Status: shipped 2026-06-22 (fitme-story#252 + FT2 #790). Closes the W16 silent-pass class end-to-end across both repos.
The incident that named the discipline
On 2026-05-24 (W16), the /control-room/framework page threw a TypeError in production for 13 days with green CI the whole time. The FitTracker2 gate-coverage producer emitted a timestamp field; the fitme-story consumer expected event.ts; and both repos' test suites agreed on the wrong shape, so neither caught the drift.
The lesson: a consumer test that hand-authors the producer's shape validates nothing — it just re-encodes the same assumption on both sides. The fix is to validate against the producer's real sampled output.
What shipped
The FT2 substrate (scripts/sample-contract-fixtures.py, make check-contract-fixtures, warn-only in pr-integrity-check.yml) shipped 2026-06-07. E-15 closed the cross-repo consumer half:
scripts/check-contract-fixtures.ts— a unified checker. Shape (required_keys) = HARD fail (the incident class). Freshness = asymmetric: WARN for FT2-produced fixtures fitme-story vendors (it cannot self-re-sample them), HARD for fitme-story-owned contracts. Validates the vendored fixtures and the livesrc/data/features/*.jsonconsumer (113 files).scripts/sample-audit-log-contract.ts— the audit-log canonical sampler. fitme-story is that contract's canonical producer (the UCC auth stream lives in Upstash Redis here). It sanitizes each record viasanitizeForPublicExportbefore write (the fixture is committed and publicly reachable), and no-ops cleanly without Redis creds..github/workflows/contract-resample-weekly.yml— Mondays 07:00 UTC. Re-samples audit-log and re-vendors the FT2 fixtures via a fresh clone, each step guarded on its secret, and opens a PR on change.
A verification-first surprise
Outcome
npm run contract:check → PASS; 16/16 new tests + aggregator 9/9 green; FT2 post-merge integrity-check 0 findings and check-contract-fixtures all fresh (0.0d). Producer-shape drift now fails at consumer CI time instead of in production, and a weekly cadence keeps the fixtures honest.
Cross-references
- Source case study (FT2):
docs/case-studies/contract-fixture-consumer-adoption-case-study.md - Predecessor:
f-launchd-drift-extension(the prior cross-repo cron-context silent-pass class)
- •Freshness is ASYMMETRIC by design — WARN (not hard) for FT2-produced fixtures fitme-story vendors but cannot re-sample; HARD only for fitme-story-owned contracts (audit-log) where it controls re-sampling.
- •The warn-only → blocking flip was deliberately NOT done: FT2's contract-fixtures cron is drift-only + warn-only per operator decision D2 (2026-06-18), and the fitme-story consumer gate is day-0 and must soak warn-only first. The flip date is an operator decision.
- •fixture_staleness_days is T2 (declared) — the 15-day figure is the observed sample age at session start, verified by the first scheduled cron fire rather than continuous instrumentation.
- Freshness check too strict — breaks fitme-story CI when an FT2-produced fixture goes stale between syncs (the consumer cannot self-re-sample those).
- The audit-log sampler leaks PII into the committed, publicly-reachable fixture.
- Consumer tests hand-author the producer shape (the W16 anti-pattern), so drift still passes silently.