User stories — dual-run parity harness
Scope note: this is an internal tool. There is no buyer persona, no pricing, no churn in the SaaS sense — reinterpreted per the context brief: “buyer” = program gate approval (Tomas), “procurement” = Tomas’s lane-approval for adapter scope, “churn” = a fleet agent or builder routing around the harness (bypass), “pricing” = engineering time + token spend charged to Robert’s lane. No onboarding funnel, no trial, no upsell — skipped in full, not scaled down, because none of it maps to anything real here.
Personas
| Persona | Type | Primary interface | Owns |
|---|---|---|---|
| Fleet agent | Machine | CLI (harness verify), JSON verdict, work-ledger row |
Claims a unit, runs verification, consumes the verdict mechanically — never reads prose |
| Strike-unit builder | Human (4-person unit) | Evidence bundle (markdown/JSON), CLI | Resolves DIVERGED verdicts: real regression vs. acceptable difference vs. new normalization rule |
| Robert | Human — fleet operator/orchestrator | CLI, Grafana panel, repo | Harness investment decision, lab image lifecycle, fixture refresh cadence, adapter-scope calls day to day |
| Tomas | Human — program owner | Evidence bundle summaries, DONE-row report | Flagship gate approval (M2/M3/M4), adapter-scope expansion beyond Orders, “week 6 slip” call |
| QSA/SOX auditor | Human — evidence consumer | Evidence bundle + normalization ledger, read-only | DONE row 9 sign-off; needs falsifiable, replayable proof, not a dashboard |
| Security reviewer | Human — evidence consumer / gate | Fixture masking spec, lab isolation design | PII/PCI masking sign-off, legacy-credential isolation sign-off before any fixture leaves the lab |
Verdict contract (binding — referenced by every machine-persona story)
DESIGN, not yet implemented. JSON emitted by harness verify on stdout; one object per unit.
{
"verdict": "PARITY | DIVERGED | UNVERIFIABLE",
"unit_id": "string",
"adapter": "string (e.g. orders.read.get_order)",
"fixture_class": "string",
"evidence_bundle_uri": "string (file:// or content-hash path)",
"normalization_ledger_ref": "string (hash of the ruleset applied)",
"counterexample": { "request": {}, "legacy_response": {}, "candidate_response": {}, "diff": {} } | null,
"reason": "string | null (populated only for UNVERIFIABLE)",
"generated_at": "ISO8601"
}
Exit codes (DESIGN): 0 PARITY · 1 DIVERGED · 2 UNVERIFIABLE (lab unreachable, fixture missing, normalization rule ambiguous) · >2 harness internal error (not a verdict — CI must not treat this as a passing or failing unit, must retry or page Robert).
A unit cannot reach the PR lane in work-ledger without a verdict row carrying exit code 0. This is a structural gate, not a convention — see US-13.
Stage A — Bootstrap (legacy-runtime lab + adapter stand-up)
US-1 — As Robert, I want to boot a pinned-EOL legacy stack in an isolated lab image, so that the harness has a ground-truth system to record against.
- Job to be done: stand up one legacy runtime (e.g. Ruby 2.4.6/Rails 3.2.22.5 for Orders) as a reproducible, credential-isolated container.
- Preconditions: repo’s exact stack version identified (D5 stack table); base image or Dockerfile recipe exists or is built.
- Trigger: new adapter kickoff, or a pilot candidate (forex-ng, orders-ext, giftcard_service, consumer-data, getaways-accounting-service) chosen per D5’s ranked order.
- Main flow: pull/build pinned image → boot with seeded/masked fixture data → smoke-test one known request → confirm response matches a manually-verified oracle.
- Edge cases: Docker manifest-v1 deprecation blocks pulling a genuinely old image (D3 — live, unresolved risk for Ruby 1.9.3/JRuby 1.7 tier); RubyGems TLS 1.2 floor (since Jan 2018) blocks fresh
bundle installon stacks whose Gemfile.lock predates it — gems must be vendored, not installed live. - Failure states: image unpullable →
UNVERIFIABLE(lab_boot_failed), never silently falls back to a stub; native-extension gem build fails (mysql2/nokogiri OpenSSL mismatch) → same. - Acceptance criteria: lab boots deterministically from a pinned manifest (no
:latest, no livebundle installagainst upstream rubygems.org at boot time); one smoke request returns the expected oracle response. - Data requirements: seeded DB fixtures only — never a copy of production data (security note below).
- Security notes: legacy DB/API credentials live only inside the lab’s isolated network namespace, never in Encore secrets or in any fixture that leaves the lab (context brief, binding).
- Instrumentation: lab-boot duration, boot success/failure, image digest logged per boot (audit trail for “which lab produced this fixture”).
- Priority: MVP. Tag: operational, critical-path (nothing downstream works without a booted lab).
US-2 — As Robert, I want the hardest-boot stack (Ruby 1.9.3-on-JRuby-1.7/hand-patched Rails 3.2, voucher-inventory-service) attempted early as a pilot, not deferred to the flagship, so that the program learns the true cost before it is load-bearing.
- Job to be done: de-risk the worst-case boot before Orders week-6 depends on it.
- Preconditions: US-1 pattern proven on an easier stack first (forex-ng, per D5 pilot ranking).
- Trigger: Robert schedules the pilot explicitly, outside the Orders critical path.
- Main flow: attempt boot → log every workaround (vendored gems, archived apt sources, manifest-v1 fallback) → produce a reusable recipe.
- Edge cases: no source found anywhere (D3) demonstrating this solved end-to-end in 2025-2026 — this may simply fail; that is itself the finding.
- Failure states: if unboot-able within a capped time budget, escalate to Tomas as a scope risk on voucher-inventory-service specifically, not a harness-wide verdict.
- Acceptance criteria: either a working recipe, or a written, dated failure report with the exact blocker (manifest error / TLS error / gem-build error) — no silent abandonment.
- Data requirements: none beyond US-1.
- Security notes: same isolation as US-1.
- Instrumentation: time-to-boot, workaround count, logged as a cost data point for the 2-5 engineer-day setup-cost model (D3, MODELED).
- Priority: MVP (as a capped-time-box spike, not open-ended). Tag: operational.
US-3 — As a security reviewer, I want to approve fixture-masking rules before any recorded traffic leaves the lab, so that PII/PCI never lands in a harness fixture store outside the isolated boundary.
- Job to be done: sign off on a masking spec per adapter before recording starts.
- Preconditions: adapter’s PII/PCI surface enumerated (D5 §b — every Orders-chain fixture class touches PII/PCI somewhere: PAN/IBAN in billing-record-service, device fingerprints via accertify/iovation, GDPR-erasure payloads in orders_mbus_client/consumer-data).
- Trigger: new adapter’s first recording session is scheduled.
- Main flow: review field-level masking rules (card PAN, IBAN, address, device ID, email, OAuth tokens) → approve or reject → decision logged in the normalization ledger as an auditable scope decision (context brief, binding terminology).
- Edge cases: a field is ambiguous (is a hashed device fingerprint still PII?) → default to mask, escalate, never default to record raw.
- Failure states: recording proceeds without sign-off → treated as a security incident, not a process gap; the fixture must be quarantined and destroyed, not just deleted from the index.
- Acceptance criteria: no fixture is written to durable storage outside the lab network boundary until masking-rule sign-off exists for that fixture class; masking spec is itself versioned and hash-referenced from every fixture it applies to.
- Data requirements: the PII/PCI touchpoint inventory (D5 §b) is the input; there is no off-the-shelf masking tool for recorded HTTP fixtures (GoReplay’s masking is a paid feature not available to us, D3) — masking rules are a harness-owned normalization-ledger artifact, built not bought.
- Security notes: this story IS the security control, not a wrapper around one.
- Instrumentation: every fixture write logs its masking-ruleset hash; an unmasked-fixture scanner runs as a CI gate on the fixture store itself.
- Priority: MVP. Tag: trust-and-safety, critical-path (nothing records without this).
Stage B — Record (capture legacy ground truth)
US-4 — As Robert, I want to record ~100 requests through a recording proxy against a booted legacy lab, so that the harness has real fixtures instead of hand-written test cases.
- Job to be done: produce the first fixture set for a new adapter.
- Preconditions: US-1 and US-3 complete for this adapter.
- Trigger: adapter kickoff.
- Main flow: outside-in network-layer capture (mitmproxy or GoReplay-class, chosen per D3 — fits the “no legacy code modification” constraint better than in-process VCR, which needs Gemfile changes the harness must never make) → apply masking (US-3) → write content-addressed fixture files.
- Edge cases: legacy service reads/writes DB state mid-request (not just a stateless response) — fixture must capture pre/post DB state where the adapter’s verdict depends on it (D5 §d.1), not just the HTTP body.
- Failure states: recording proxy loses requests under load → fixture set is incomplete → flagged, not silently padded.
- Acceptance criteria: every recorded fixture is content-addressed (same input → same fixture identity) and passes the masking scanner (US-3) before being considered usable.
- Data requirements: representative request shapes per D5’s ~15-20 sync-HTTP equivalence classes for Orders (not 1:1 per raw route).
- Security notes: see US-3; recording happens inside the lab boundary only.
- Instrumentation: fixture count per class, recording session duration, masking-scan pass rate.
- Priority: MVP. Tag: critical-path.
US-5 — As a fleet agent, I want to record MBUS shadow-tap traffic (topic + envelope + outbox row) for topics a unit’s parity depends on, so that async event parity is provable, not just HTTP parity.
- Job to be done: capture the “message was durably queued exactly once” contract, not just payload shape (D5 §d.2 — Orders’ own outbox DB, users-service’s bespoke sweep daemon).
- Preconditions: adapter scope includes at least one MBUS topic; shadow-tap point identified inside the adapter (context brief — shadow-taps live inside adapters, the standalone MBUS bridge is dropped).
- Trigger:
harness record --adapter orders --include-mbusor equivalent. - Main flow: tap topic → capture envelope + body + corresponding outbox-DB row → mask per US-3 (GDPR-erasure topics are explicitly in scope, D5) → write fixture.
- Edge cases: two bus technologies in the same repo (STOMP/JMS legacy mbus + Kafka
txn.signals.high) — both must be tapped; tapping only one silently under-covers the adapter. - Failure states: outbox row and bus envelope disagree (at-least-once semantics violated) at recording time — this is a legacy-system finding, not a harness bug; logged and surfaced to Robert, not swallowed.
- Acceptance criteria: fixture asserts durable-queue-once, not just message-shape match.
- Data requirements: D5’s ~25-30 MBUS topic/schema fixture classes for Orders alone (MODELED).
- Security notes: GDPR-erasure and account-deactivation topics carry PII by construction — masked per US-3, never skipped because “it’s just an event.”
- Instrumentation: topics tapped vs. topics known-to-exist (coverage ratio), outbox-vs-envelope mismatch count.
- Priority: MVP for HTTP-adjacent topics touched by the Orders read path; post-MVP for the full 25+ topic surface (staged with the adapter, per context brief). Tag: critical-path (for in-scope topics).
US-6 — As Robert, I want batch/cron traffic (Resque jobs, Quartz-scheduled publishing) flagged as structurally uncapturable by the HTTP/MBUS recorder, so that nobody assumes DARK job classes are covered when they aren’t.
- Job to be done: make the coverage gap explicit instead of silently absent.
- Preconditions: none — this is a scoping story, not a build story.
- Trigger: adapter design review.
- Main flow: adapter’s coverage report states “batch/cron: UNVERIFIABLE by this recorder — DB-transaction-log tailing or direct job instrumentation required” rather than omitting the traffic class silently.
- Edge cases: getaways-accounting-service’s daily CSV export (D5 pilot candidate) is the cheapest available rehearsal of this class once someone builds the capture mechanism — not yet built.
- Failure states: N/A — this story’s job is to prevent a false sense of coverage.
- Acceptance criteria: every adapter’s evidence bundle includes an explicit “traffic classes not captured” line, not just a silent absence.
- Data requirements: none.
- Security notes: none additional.
- Instrumentation: coverage-gap count surfaced on the Grafana panel (US-19).
- Priority: MVP (the disclosure), post-MVP (an actual batch-capture mechanism). Tag: trust-and-safety (honesty about limits, per Rams-lens design principle in the initial recommendation).
Stage C — Verify (the main dual-run loop; this is the product)
US-7 — As a fleet agent, I want to run harness verify <unit> and receive a machine-readable verdict in under one CI-step timeout, so that I can promote or block a unit without reading prose.
- Job to be done: the core mechanical loop — the reason the harness exists.
- Preconditions: unit claimed from work-ledger; adapter and fixture set exist for the unit’s capability; lab is bootable.
- Trigger: agent finishes implementing a unit and calls
harness verify. - Main flow: replay recorded fixtures against booted legacy lab AND the new Encore.ts service → normalize (apply normalization ledger) → diff → emit verdict per the contract above → exit code set accordingly.
- Edge cases: legacy lab is down (US-1 failure) →
UNVERIFIABLE(lab_unreachable), exit 2, never treated as PARITY by default; fixture missing for this unit →UNVERIFIABLE(no_fixture). - Failure states: harness process crashes → exit code >2, CI must retry once then page Robert, never interpret as a passing unit (contract, binding).
- Acceptance criteria: verdict JSON matches the contract exactly; exit code is the sole signal CI depends on; verdict is deterministic — same unit + same fixture set + same normalization ledger version → same verdict, every run.
- Data requirements: fixtures (Stage B), normalization ledger (US-9).
- Security notes: verdict JSON must never embed unmasked PII even in the counterexample field — the masking applied at recording time (US-3) must survive into the evidence bundle.
- Instrumentation: per-unit verify latency, verdict distribution (PARITY/DIVERGED/UNVERIFIABLE rate) — the core North Star input.
- Priority: MVP, critical path. Tag: critical-path, activation-adjacent.
US-8 — As a fleet agent, I want the FIRST real PARITY verdict on a real Orders-chain unit (not a synthetic self-test) to be the activation event that proves the whole chain works end to end, so that the program has concrete evidence before week 6.
- Job to be done: activation — the harness’s first real win.
- Preconditions: US-1 through US-7 all functioning for one Orders read-path unit.
- Trigger: first unit in the Orders-adapter backlog reaches
harness verify. - Main flow: as US-7, on a real unit, with a real legacy lab, real recorded fixtures, real normalization ledger — not the forex-ng self-test.
- Edge cases: first attempt is DIVERGED due to normalization gaps, not a real regression — expected and not a failure of the harness; the second or third attempt reaching PARITY is the real activation event, and that iteration count is itself a useful metric.
- Failure states: if no unit reaches PARITY before week 6, this is the “if dual-run is not live, M4 slips, publicly” trigger (context brief) — a program-level failure state, not just a harness bug.
- Acceptance criteria: one evidence bundle exists, dated, showing PARITY on a real Orders unit with its full replay recipe (falsifiable by anyone who re-runs it).
- Data requirements: as US-4/US-5 for the chosen unit.
- Security notes: as US-3.
- Instrumentation: time-to-first-PARITY from adapter kickoff — this is the number Tomas will ask for.
- Priority: MVP. Tag: activation, critical-path.
US-9 — As Robert, I want a self-replay (record from the legacy lab, then replay against the SAME legacy instance) to always yield PARITY, so that I know the noise-normalization model is not producing false DIVERGED verdicts before I ever trust it against the new system.
- Job to be done: the harness’s own falsification recipe (initial-recommendation §11) — proves the diff engine, not the rewrite.
- Preconditions: US-1 and US-4 for any one adapter, ideally the simplest (forex-ng, per D5 — zero DB, zero MBUS, cleanest possible self-test).
- Trigger: run before trusting any new normalization rule change, and on every kernel/normalization-ledger version bump.
- Main flow: record fixture → replay same fixture against the same legacy instance → diff → must be PARITY, always.
- Edge cases: legacy service itself is non-deterministic (timestamps, incrementing IDs) — this is exactly what the normalization ledger exists to absorb; if self-replay is DIVERGED, the normalization ledger is wrong or incomplete, not the rewrite.
- Failure states: self-replay DIVERGED → kernel/normalization-ledger change is blocked from merge until fixed; this is a harder gate than a unit’s own verdict, because it protects the trustworthiness of every other verdict.
- Acceptance criteria: self-replay suite is green on every normalization-ledger change, run in CI, not just locally.
- Data requirements: any stable fixture set; forex-ng recommended as the cheapest.
- Security notes: none additional.
- Instrumentation: self-replay pass rate over time — a retention/trust metric, not just a CI gate (D2’s synthesis point 5: no published tool disclosed a false-positive rate anywhere; this self-test is the harness’s only evidence source for its own precision, per D6/verification-evidence).
- Priority: MVP. Tag: retention/trust, critical-path.
US-10 — As Robert, I want every change to the normalization ledger to be reviewed and logged with a rationale, so that “we ignored this field” is an auditable scope decision, not a silent workaround that erodes trust in the verdict.
- Job to be done: keep the normalization ledger honest (Scientist’s
ignoreblocks and Zalando’s header-filtering are the precedent — D2 §1/§3 — but both require the exclusion to be visible, not buried). - Preconditions: US-9 passing before any ledger change merges.
- Trigger: a builder or agent proposes ignoring a field/topic/header because it’s “just noise.”
- Main flow: proposed rule + rationale + affected fixture classes → reviewed (by Robert for MVP scope; by the strike unit for post-MVP scale) → merged with a version hash → every subsequent verdict cites which ledger version it used.
- Edge cases: a rule that looks like noise-suppression is actually hiding a real regression (the TSB lesson in reverse — D2 §9 — a rushed normalization rule under schedule pressure is exactly the failure mode a hard gate should prevent, not enable).
- Failure states: an unreviewed ledger change merges anyway → flagged retroactively by the audit trail (US-16), treated as a process violation.
- Acceptance criteria: every ledger entry has a stated field/topic, rationale, author, date, and which fixture classes it was validated against (self-replay, US-9).
- Data requirements: none beyond the ledger itself.
- Security notes: none additional.
- Instrumentation: ledger-change frequency and rejection rate.
- Priority: MVP (the review requirement); tooling to make review low-friction is post-MVP. Tag: retention/trust, critical-path.
Stage D — Divergence triage (the human exception path)
US-11 — As a strike-unit builder, I want to open an evidence bundle for a DIVERGED verdict and see the smallest failing counterexample first, so that I can decide real-regression / acceptable-difference / new-normalization-rule without reading the full diff.
- Job to be done: the human journey’s actual work — Ive-lens “verdict first, smallest counterexample next, everything else behind links” (initial recommendation §7).
- Preconditions: a DIVERGED verdict exists with
evidence_bundle_uripopulated. - Trigger: agent’s blocked unit surfaces a triage question (existing triage-service dedup applies here, per context brief).
- Main flow: open bundle → verdict + smallest counterexample rendered first → replay recipe available → normalization-ledger section shows what was already excluded and why → builder decides.
- Edge cases: counterexample minimization itself fails (diff too large/structural to shrink) — bundle states this rather than dumping the raw diff with no attempt at reduction.
- Failure states: builder cannot reproduce the divergence via the stated replay recipe → the bundle itself is broken, treated as a harness bug, escalated to Robert, not silently reclassified as “acceptable difference.”
- Acceptance criteria: a builder’s decision (regression / acceptable / new-rule) is captured and, if “new rule,” routes into US-10.
- Data requirements: the counterexample from US-7’s verdict.
- Security notes: masked fields stay masked in the bundle even when a human is reading it.
- Instrumentation: median time-to-triage-decision, decision-type distribution.
- Priority: MVP. Tag: critical-path.
US-12 — As a strike-unit builder, I want a DIVERGED verdict that turns out to be a real regression to mint a triage question automatically rather than requiring me to manually file one, so that the fix loop stays inside the fleet’s existing question/answer machinery.
- Job to be done: connect the harness to the program’s existing triage-dedup service rather than inventing a parallel ticketing surface.
- Preconditions: US-11 decision = “real regression.”
- Trigger: builder’s triage decision.
- Main flow: harness mints a triage question referencing the evidence-bundle URI → existing dedup logic applies (no new machinery built here — reuse, per the context brief’s explicit scope boundary excluding the triage product itself).
- Edge cases: duplicate regressions across multiple units hitting the same legacy bug → dedup handles it, not the harness.
- Failure states: triage service unavailable → question queued, not dropped.
- Acceptance criteria: one question per distinct regression, traceable back to its evidence bundle.
- Data requirements: none beyond the bundle URI.
- Security notes: none additional.
- Instrumentation: questions-minted-per-DIVERGED-verdict ratio.
- Priority: MVP (the integration point); the triage service itself is out of scope (separate plan, per README cross-references). Tag: operational.
Stage E — Promotion / gate
US-13 — As a fleet agent, I want work-ledger to structurally refuse to move a unit to the PR lane without a PARITY verdict row, so that “forgot to verify” cannot happen — the safe path is the only path.
- Job to be done: Norman-lens error prevention (initial recommendation §7) — the gate is structural, not a discipline reminder.
- Preconditions: work-ledger schema includes a verdict-row foreign key on unit-promotion.
- Trigger: any attempt to promote a unit.
- Main flow: promotion path checks for a verdict row with exit code 0 for this unit’s current fixture-set hash → allow; else block with the current verdict’s exit code surfaced as the block reason.
- Edge cases: unit’s implementation changed after verification (stale verdict) → verdict is invalidated by content hash mismatch, re-verify required — this prevents a stale PARITY from silently covering a later regression.
- Failure states: work-ledger itself unavailable → promotion blocked entirely (fail closed, not open).
- Acceptance criteria: no code path exists that promotes a unit without a matching, current verdict row; this is enforced in work-ledger, not merely documented as a convention.
- Data requirements: verdict rows keyed by unit + fixture-set hash + normalization-ledger version.
- Security notes: none additional.
- Instrumentation: blocked-promotion-attempt count (a leading indicator of bypass pressure — if this climbs, the harness is becoming a friction point worth investigating before agents route around it).
- Priority: MVP. Tag: critical-path, retention/trust (this is literally the anti-bypass mechanism).
US-14 — As Tomas, I want a rollup of DONE-row 8 (ledger reconciliation ≥99.999%) sourced from harness verdict rows plus Zaruba’s oracle reconciliation, so that the M2/M3 write-ramp gate decision has one evidence source, not two disagreeing dashboards.
- Job to be done: feed the flagship schedule’s binding numeric gate.
- Preconditions: Orders adapter live, write-ramp underway.
- Trigger: each write-ramp step (1%→100%, per the flagship doc).
- Main flow: harness verdict rows (functional parity) + merchant-accounting’s existing reconciliation oracle (financial parity) combine into one reported number; harness does NOT own the reconciliation math itself — that stays merchant-accounting’s (context brief: “Zaruba-lane decisions… researched as boundary questions only”).
- Edge cases: the two sources disagree (harness says PARITY, oracle says reconciliation gap) — surfaced as a named discrepancy, not silently reconciled by picking one.
- Failure states: if the harness cannot produce enough verdict volume to size a confidence interval at the ramp step’s traffic level, report UNVERIFIABLE for that step rather than a false PARITY (Uber’s ledger-migration model — D2 §6c — ~1 day of sampling at 1,000 comparisons/sec buys six-nines confidence; the harness’s write-ramp dwell time should size itself the same way, not use a flat N-days rule).
- Acceptance criteria: Tomas gets one number per ramp step with its confidence basis stated (sample count, window, source).
- Data requirements: verdict-row volume at the current ramp %.
- Security notes: none additional.
- Instrumentation: reconciliation-input freshness (staleness = risk to the gate decision).
- Priority: MVP for Orders; post-MVP for any second adapter. Tag: critical-path.
Stage F — Operational (lab lifecycle, fixture freshness)
US-15 — As Robert, I want a scheduled lab-image rebuild + fixture-freshness check, so that fixtures don’t go stale silently while the legacy system underneath them keeps changing (initial recommendation §10, second named risk).
- Job to be done: prevent the harness’s ground truth from drifting away from reality unnoticed.
- Preconditions: at least one adapter in steady-state use.
- Trigger: scheduled (weekly, DESIGN — not yet measured against actual legacy-change cadence) or triggered by a legacy repo’s own deploy (if that signal is available).
- Main flow: rebuild lab image from the pinned manifest → re-run self-replay (US-9) → if self-replay still PARITY, fixtures presumed current; if legacy behavior actually changed, self-replay against a fresh recording will surface it.
- Edge cases: legacy system is frozen (orders ~2017, per context brief) — for genuinely frozen systems, this check degrades to “did our lab recipe rot” (TLS/apt-source drift), not “did legacy behavior change” — worth distinguishing in the report.
- Failure states: rebuild fails → same as US-1 failure handling; existing fixtures are NOT invalidated automatically on a failed rebuild (avoid a cascading false-DIVERGED storm from an unrelated lab-infra problem).
- Acceptance criteria: rebuild cadence and its pass/fail history is visible on the Grafana panel (US-19).
- Data requirements: none beyond existing lab manifests.
- Security notes: rebuilt image goes through the same isolation as US-1.
- Instrumentation: rebuild success rate, staleness age of oldest live fixture set.
- Priority: MVP as a manual/scriptable command; post-MVP as a fully scheduled cron. Tag: operational.
US-16 — As Robert, I want every fixture, normalization-ledger change, and verdict to be content-addressed and append-only, so that the harness’s own audit trail is itself falsifiable and never silently rewritten.
- Job to be done: the harness proves itself by the same standard it applies to the rewrite (Rams-lens honesty, initial recommendation §7).
- Preconditions: none — foundational design constraint.
- Trigger: every write to fixtures, ledger, or verdicts.
- Main flow: content-address everything; no in-place mutation of a fixture or ledger entry — a “change” is a new version referencing the old one.
- Edge cases: a fixture must be destroyed (PII incident, US-3 failure state) — destruction is itself logged (what was destroyed, why, by whom), even though the content is gone.
- Failure states: any attempt to mutate history in place is a bug, not a feature — flagged in code review, not configurable.
- Acceptance criteria: any past verdict can be reproduced exactly from its cited fixture-set hash and normalization-ledger version, or the harness explicitly reports that it can no longer do so (e.g., post-destruction) — never silently returns a different answer for the “same” historical query.
- Data requirements: content-addressable storage for fixtures/ledger/verdicts.
- Security notes: append-only does not override US-3’s destruction requirement for PII incidents — destruction removes content, the log of the destruction event remains.
- Instrumentation: none beyond storage integrity checks.
- Priority: MVP. Tag: trust-and-safety, retention/trust.
Stage G — Audit / evidence (QSA/SOX)
US-17 — As a QSA/SOX auditor, I want to independently replay a PARITY verdict using only the evidence bundle’s stated recipe, without harness-team assistance, so that I can verify the claim myself rather than trust it on the program’s word.
- Job to be done: DONE row 9 sign-off — auditor-grade evidence (context brief).
- Preconditions: evidence bundle exists for the unit under audit; auditor has access to the fixture store and lab manifest (scoped, read-only).
- Trigger: SOX audit cycle, or spot-check on the ledger-reconciliation gate.
- Main flow: auditor pulls the bundle → follows the stated replay recipe → re-runs
harness verifyagainst the same fixture-set hash and normalization-ledger version → gets the same verdict. - Edge cases: auditor’s environment can’t boot the legacy lab (permissions, infra access) — a pre-recorded, signed replay transcript must suffice as a fallback, but the live-replay path is the gold standard and should be offered first.
- Failure states: auditor reproduces a DIFFERENT verdict than the bundle claims → treated as a critical incident, not an audit footnote; the harness’s determinism guarantee (US-7) has failed.
- Acceptance criteria: replay recipe requires no harness-team-specific tooling knowledge beyond documented CLI commands.
- Data requirements: full evidence bundle + normalization ledger + fixture set, scoped read access.
- Security notes: auditor access is read-only and scoped to masked fixtures only — never raw pre-mask recordings, even for audit purposes (masking sign-off, US-3, has no audit exception).
- Instrumentation: audit-replay success rate (should be 100%; any miss is a determinism bug).
- Priority: MVP by DONE row 9’s own deadline (M4). Tag: critical-path.
US-18 — As a QSA/SOX auditor, I want the normalization ledger presented as a plain, dated list of exclusions with rationale — not buried in code — so that I can assess whether any exclusion was used to paper over a real gap.
- Job to be done: the normalization ledger is the audit’s central artifact, not an implementation detail.
- Preconditions: US-10.
- Trigger: audit review.
- Main flow: ledger rendered as a human-readable, dated, attributed list; auditor can cross-reference any specific verdict to the exact ledger version it used.
- Edge cases: a rule was later reverted (found to be masking a real bug) — the reversion and its trigger stay visible in the append-only history (US-16), not erased.
- Failure states: an exclusion with no rationale recorded — fails audit by construction (US-10’s acceptance criteria already requires rationale, so this should be structurally impossible; if it happens, it’s a process breach worth its own finding).
- Acceptance criteria: every ledger entry answers “what, why, who, when, validated-against-what.”
- Data requirements: US-10’s ledger.
- Security notes: none additional.
- Instrumentation: none beyond US-16.
- Priority: MVP. Tag: critical-path.
Stage H — Trust signal (Robert, program-visible)
US-19 — As Robert, I want one Grafana panel showing parity coverage and divergence rate fed from work-ledger verdict rows, so that I have a standing trust signal without building a dashboard product.
- Job to be done: the one human surface beyond the evidence bundle the initial recommendation allows (§6) — deliberately minimal.
- Preconditions: US-7 producing verdict rows at volume.
- Trigger: always-on, not a per-request story.
- Main flow: existing Grafana/OTel fleet-monitor infrastructure (context brief — already exists, reused not built) ingests verdict rows; panel shows coverage % (units with a current verdict / total claimed units) and divergence rate over time.
- Edge cases: none beyond standard dashboard staleness.
- Failure states: panel shows stale data silently — flagged with a last-updated timestamp, not hidden.
- Acceptance criteria: one panel, reusing existing Grafana instance, no new dashboarding product built.
- Data requirements: verdict-row stream.
- Security notes: none additional (aggregate counts only, no PII on the panel).
- Instrumentation: this story IS the instrumentation for everything above it.
- Priority: MVP, deliberately scaled down — one panel, not a UI product (explicit call, per §6/§12 of the initial recommendation). Tag: operational.
Rejected for v1 (with reasons)
| Item | Reason rejected | Status |
|---|---|---|
| UI dashboard beyond one Grafana panel | The fleet is the primary user and reads structs, not screens; a dashboard product is scope the harness doesn’t need to win its bet (initial recommendation §6/§9). | Rejected v1, revisit only if a human-facing product need is separately justified. |
| LLM as verdict authority (pass/fail decided by an LLM judge) | 2024-2026 LLM-judge-for-code-equivalence literature is benchmark-stage, not production-reliability-stage (D6 — CETBench/AXIOM 2025 are calibration papers, not deployment evidence); cross-language LLM-judge consistency is unreliable even directionally. An LLM may triage/cluster/explain divergences, never grant PARITY. | Rejected v1 as a gate; experimental as a triage aid on DIVERGED bundles only (post-MVP, non-authoritative). |
| Live production shadow traffic owned by the harness | Every rigorous case study (Zalando, Uber, Slack) that used live shadow paid a real, admitted infra tax (doubled traffic, forked-request cost) and required side-effect-suppression machinery (Spy pattern) that overlaps with Zaruba’s oracle plane, not the harness’s. Recorded-fixture replay is the v1 default (D2 synthesis point 4/6); live shadow, if the ledger proof demands it, is a Zaruba-lane decision per the context brief’s open boundary question, not a harness feature to build preemptively. | Rejected v1 for harness ownership; open question, not a build decision, for whether it’s needed at all. |
| Embedding-based divergence clustering, auto-generated adapters, DB-state diffing beyond the oracle pattern, multi-region replay | Explicitly out of MVP per initial recommendation §9 — no evidence yet that the simple oracle-generalization pattern is insufficient. | Rejected v1, revisit only if Orders adapter proves the simple pattern inadequate. |
| Standalone MBUS bridge app | Already dropped in plan 001; shadow-taps live inside adapters only (context brief, binding). | Rejected, not reconsidered. |
| Performance-parity gating (p99 ≤ +10%) | Production telemetry owned by the program, not a functional-parity harness function (initial recommendation §9). | Rejected v1 for harness ownership. |
| Diffy’s A/A live self-comparison as the ONLY noise-detection mechanism (in place of a hand-curated normalization ledger) | Diffy’s real-world false-positive rate was never published anywhere found (D1, D6, Q2) — adopting its exact mechanism uncritically would import an unverified precision claim. The harness’s own self-replay (US-9) is a related but hand-auditable idea: it proves the ledger is complete for a given fixture set, it does not auto-learn exclusions the way Diffy claims to. | Rejected as sole mechanism; self-replay-as-validation (US-9) adopted instead, auto-noise-detection stays experimental, post-MVP. |
Story index by tag
- Critical-path: US-1, US-3, US-4, US-7, US-8, US-9, US-10, US-11, US-13, US-14, US-17, US-18
- Activation: US-8 (first real PARITY on an Orders-chain unit)
- Retention/trust: US-9 (self-replay always PARITY), US-10 (normalization changes audited), US-13, US-16
- Operational: US-1, US-2, US-12, US-15, US-19
- Trust-and-safety: US-3, US-6, US-16
- Rejected: see table above.
Open questions
- Live-shadow ownership (rejected-item row 3) is marked open, not closed — if the ≥99.999% ledger-reconciliation gate cannot be cleared by recorded-fixture replay alone (D6/D2’s convergent finding that every real financial-parity case uses live shadow, not fixtures), does the harness build a live-shadow mode later, or does that responsibility move entirely to Zaruba’s oracle plane? No evidence yet resolves this either way.
- US-15’s rebuild cadence (weekly, DESIGN) has no measured basis — no data exists yet on how often the frozen legacy stacks actually drift versus how often the lab recipe itself rots (TLS/apt-source decay). Needs a few rebuild cycles of real data before the cadence is more than a guess.
- US-2’s hardest-boot pilot (voucher-inventory-service’s Ruby 1.9.3-on-JRuby-1.7 stack) has no evidence anywhere (D3) that anyone has solved this exact combination end-to-end recently — this story may resolve as “infeasible, needs a different verification strategy for that one repo” rather than a working recipe. The user story is written to surface that outcome cleanly if it happens, not to presuppose success.
- US-6’s batch/cron capture mechanism (DB-transaction-log tailing or direct job instrumentation) has no chosen design yet — flagged as a gap, not a decision, pending a follow-up repo-level grep for Resque job classes (D5’s own open question).
- The exact review body for US-10 (normalization-ledger changes) is Robert alone at MVP scale — at what verdict volume does that become a bottleneck requiring strike-unit builder co-review? No volume threshold has been modeled yet.