The Harness Atlas

Decisions consolidated into the Clara-as-a-Coworker tracker, Phase 4 (single list) — answers there count.

Every test harness, eval rig, and replay system in the PropFlowAI codebase, in one place — plus the design for one shared skeleton so building a harness stays the house craft instead of the house sprawl.

Verified 2026-08-26 · direct find/grep/git-log against ~/.claude/propflowai (main) plus 4 named worktrees · cross-checked against the eval-quality trio (eval-inventory-2026-08-20, the eval deep inspection, the Eval & Testing Roadmap) and simplification-plan-2026-08-26 §2 bucket 4 · promptfoo layer: a separate audit is running, see promptfoo-audit.md — not redone here

Read this first — the one live fact that changes everything below it: quality-gate-poc/README.md says its "Regression Gate — Leasing (required)" job is deliberately held back from actually blocking merges, pending a burn-in campaign, and even names the exact command to flip it later. A live check tonight (gh api repos/.../branches/main/protection) shows that gate already IS in the required-checks list — it is, right now, the only harness/eval check in the whole repo that can block a merge. Either the flip happened without the README being updated, or someone flipped it early. Every CI-status pill below is calibrated against this live check, not against what a workflow's name or README claims.

The short version: at least 45 separate places in the codebase test, replay, or stress Clara's behavior — and they run on 5 different "is this actually true" answers for the same question ("did this conversation go right?"). Nine of them independently reinvent "replay a conversation and grade it." One tree of ~1,850 files isn't even in version control. A second confirmation pass tonight found four separate real-PII fixtures with zero scrubbing (not one) and the branch-protection discrepancy above. Nothing here proposes new architecture — it proposes one shared skeleton (a fixture shape, a runner, a grader list, two scrubbers, one coverage ledger, one proof-of-work stamp) that every existing harness can plug into without a rewrite, plus a doctrine and a build check so the next harness lands inside the skeleton instead of beside it.

45+harness/eval/replay/stress directories found tonight
9independent "replay a conversation and grade it" engines
2things independently named "Crucible" — different domains, same name
1,850files in model-evals-fleet/ with zero git history
3attestation mechanisms already invented tonight, in one branch, ready to become the standard
4real-PII fixtures with zero scrubbing found live tonight (after-call-harness, evals/gauntlet, data/eval, plus a scoped gap in Cerberus's own scanner)
5checks, repo-wide, that can actually block a merge — verified live via gh api branch protection

In plain terms: Fede loves building harnesses — that's a strength, not the problem. The problem is every harness gets built from scratch: its own way of describing a test case, its own way of running it, its own way of scrubbing private info out of it, its own way of proving the result is real and not stale. This page lists everything that exists today, shows the 9 "replay and grade" systems side by side so it's obvious which parts of which one are worth keeping, and proposes the one shared skeleton — so next time someone builds a harness, they build the SCENARIOS, not the plumbing underneath them.

1 · The atlas

Every harness/rig found tonight, one row each. Click a column header to sort; use the chips or the search box to filter. Evidence for every row: file count and last-commit date are from direct find/git log against the repo tonight; CI status is from a path-scoped grep against .github/workflows/ (not a basename substring match — several early basename hits turned out to be false positives and were corrected). Where a fact couldn't be confirmed tonight, the cell says so instead of guessing.

All layers Prompt/message Conversation Outcome/after-call Live-call Infra/CI-integrity

shown

NamePathProvesLayer Fixture formatRunnerGrader(s) ScrubberCorpusCI status Incident originOverlap with

2 · The 9 replay systems, side by side

Nine directories independently solve "load a fixture, run it through something, diff/grade the result." None has everything. This is what each has that the others lack.

#SystemInput sourceReplay mechanismGradingIsolation (can it write prod?)Unique strength
Read, updated after a deeper pass tonight: evals/replay-harness is the strongest single candidate — it's the only one of the 9 that enters at the real production entrypoint (not a stand-in for it) AND self-verifies its own isolation live against AWS STS rather than by code-comment assertion (see Decision 1). scripts/replay-harness has the cleanest neutral plumbing (corpus + policy + runner) for a fully deterministic, zero-LLM-cost mode. quality-replay/ has the most rigorous prod-write PREVENTION stack (deny-all-by-default + always-hard-block-outbound + an ephemeral bench conversation, three layers deep — but it does write real, sandboxed DDB rows, unlike replay-harness which writes nothing) and the only real cross-system grading reuse (imports quality-gate-poc's checker instead of inventing its own). scripts/tour-decider-replay is safest by construction for its slice — it replays a pure function, so it cannot reach the network at all. The other five are either downstream scorers/comparators over outputs someone else produced (turnover-replay, vendor-recognition-replay, tour-replay) or narrower, real-corpus drift guards (trace-replay, evals/replay) — genuinely useful, but not full engines in their own right. Nothing here is thrown away — section 2's "8 gaps vs the winner" list is exactly what a consolidation has to port in.

3 · One shared skeleton

Not a rewrite. A thin, shared layer every existing harness maps onto through an adapter — the harness keeps its own scenario files, its own domain logic, its own name.

3.1 — One fixture format (superset)

Built directly from three real formats already in the repo: promise-harness/cases.ts, after-call-harness/manifest.ts (tonight's newest harness — already has two of the three attestation mechanisms below), and Cerberus's desk-row fixture format (quality-gate-poc/scripts/convert-desk-row-to-fixture.ts, per BUILD-SPEC.md §5).

interface HarnessFixture {
  id: string;                 // canonical id, e.g. "after-call-001"
  suite: string;               // owning harness, e.g. "after-call-harness", "promise-harness"
  kind: "case" | "invariant";  // "case" = replay a conversation/call; "invariant" = standing
                                 //   architecture check (e.g. voice-harness's live-tool-budget)
  layer: "prompt-message" | "conversation" | "outcome-after-call"
       | "live-call" | "infra-ci-integrity";
  subLayer?: string;           // domain vocab kept AS-IS, not renamed:
                                 //   Cerberus "input"|"loop"|"outbound", voice-harness "L1".."L4"

  provenance: {
    source: "real-transcript" | "synthetic" | "adversarial" | "prod-replay";
    sourceRef?: string;         // conversationId / call id / shard:line — byte-exact pointer
    incidentIds: string[];      // named incidents this fixture proves fixed
    piiVerified: boolean;       // required true before a real-transcript fixture can land
    scrubMethod: "log-mask" | "full-replace" | "none-needed";
  };

  input: unknown;              // opaque per-domain payload — untouched, whatever shape the
  expected: unknown;           //   suite already uses for its case/verdict

  confidence: "confirmed" | "unconfirmed";
  taxonomyRefs?: string[];      // e.g. classRef[] (systematic-pattern.md classes A-M), ["R42"]

  regressionStatus: "red-before-green-after" | "already-fixed" | "known-gap-not-fixed";
  liveDrivable: boolean;        // can this same case also run live against a real system

  addedBy: string;              // PR / commit / session that added it
  addedAt: string;               // ISO date
}

Sent to the build agent working PR 6373 / fede/after-call-poc tonight, ahead of this page, so the newest harness in the repo lands already compatible — its classRef/incidentRefs/liveDrivable/regressionStatus fields map 1:1 onto this shape with zero renaming inside its own manifest.ts.

3.2 — One runner CLI

npm run harness -- --suite promise-harness
npm run harness -- --suite after-call-harness --incident matter_849f19e9
npm run harness -- --suite all --layer outcome-after-call --ci

A single entry point that reads each suite's own fixtures (through its adapter, see 3.6) and reports pass/fail + the run-attestation stamp (3.5) in one shape, regardless of which of the 45 directories actually ran. Suites keep their own internal runner (run.ts, score.ts, whatever) — the shared CLI calls into it, it doesn't replace it.

3.3 — One grader registry

Not one grader — a registry naming which of the ~89 existing judge/grader/grade-named files is canonical for which fault class, so the next harness looks one up instead of writing #90. quality-replay/ already proves the pattern works (it imports quality-gate-poc's three-layer checker directly rather than inventing its own) — that's the model to generalize, not a new mechanism to build.

3.4 — Two scrubbers, not one (deliberately)

The prior inspection's "8 scrubbers → 1" instinct is wrong per Fede's own hot rule 7: a log-line masker and a committed-fixture replacer have genuinely different jobs. Two survive:

Log-mask
Redacts a live string inside a log line or console output — fast, partial, fine for something nobody commits. Target: src/lib/platform/security/scrub-pii-log-string.ts (already the production module; most of the 8 should import this instead of re-deriving their own regex).
Full-replace
Required for anything landing in a committed fixture — a real name/phone is replaced with an obviously-fake stand-in (Cerberus's "Solomon Brant" precedent), never partially masked, and requires an explicit piiVerified: true per row before the write happens (convert-desk-row-to-fixture.ts's existing contract). This is the harder, slower path, on purpose.

3.5 — One attestation mechanism (already invented tonight — not a proposal, a promotion)

All three pieces already exist in fede/after-call-poc, verified live tonight by an adversarial pass. The proposal is to make these the standard every suite adopts, not to invent something new.

3.6 — One coverage ledger

Incident → fixture → red-before → green-after, one row per incident, across every suite — not per-harness bookkeeping. This is what doc-index-of-harnesses (the prior inspection's cheapest, zero-risk recommendation) becomes once it's populated from the fixture format's own provenance.incidentIds + regressionStatus fields instead of hand-maintained. No such ledger exists today; every suite tracks its own incident list in its own README, which is exactly why the same regression class gets rediscovered more than once.

3.7 — Adapters, not rewrites

Existing harnessKeepsAdapter does
promise-harness/cases.tsIts own case shape, unchangedMaps caseId→id, channel→subLayer, expectedPromise/expectedStatus→expected
after-call-harness/manifest.tsclassRef/incidentRefs/liveDrivable/regressionStatus, unchangedAlready a 1:1 rename — see 3.1
Cerberus desk-row fixturesIts own 5-file case (context/ledger/inbound/trace/expected), unchangedMaps layer(input/loop/outbound)→subLayer, correctDisposition→expected
voice-harness scenario YAMLsAll 5 driver tiers, unchangedMaps each YAML's own layer tag into subLayer under live-call
evals/turnover-walk (turnover Crucible)capture-only-gauntlet.ts, false-promise-gauntlet.ts, unchangedWraps each gauntlet run as one HarnessFixture per scenario for the shared ledger only

3.8 — What gets deleted outright

4 · How we build a harness here

One page. Pin this next to the skeleton, not instead of it.

  1. Name the incident first. A harness that doesn't trace to a real bug, a real near-miss, or a named product invariant is a nice-to-have, not a gate. Write the incident ID down before writing any code.
  2. Write the fixture in the shared format (3.1). Not your own shape "for now, migrate later" — later never comes, which is the entire reason 45 directories exist today.
  3. Prove red-before, green-after. Run the fixture against the code as it was before your fix (red) and after (green), in the same commit's evidence. A fixture that was never actually red isn't proof of anything.
  4. Wire it as an enforced check with attestation (3.5). Fixture-deletion tripwire, run attestation, mutation control — all three, not the one that felt urgent tonight. If it can't be enforced yet, say so explicitly (advisory, burn-in) rather than silently leaving it manual-only forever.
  5. List it in the atlas (section 1). One row, same day it ships. The atlas is generated off the fixture format's own metadata, not hand-typed — so this step is "make sure your suite emits the metadata," not "go edit a doc."
The build check (G14-style): a pre-push check that fails a PR adding a new top-level or scripts/-level directory matching harness|replay|gauntlet|crucible|stress|eval in its name unless it (a) imports the shared runner CLI, (b) emits fixtures in the HarnessFixture shape, and (c) registers a mutation control for any new guard it ships — the same shape as the existing scripts/check-mutation-control.ts pre-push gate, extended to catch a new harness DIRECTORY the same way that check already catches a new GUARD. Until this exists, every doctrine step above is a request, not a rule — which is exactly the gap that produced tonight's finding that the newest harness in the repo doesn't yet meet the repo's own existing mutation-control rule.

5 · Decisions for Fede

D1 — Which replay engine is the base for the shared runner?

Nine systems do "replay + grade." None has everything (section 2). Picking one as the base doesn't delete the others tomorrow — it decides which plumbing new replay scenarios get written against from now on. Updated after a second, deeper pass tonight that read all 9 side by side in detail — see section 2's full comparison table.

A evals/replay-harness — the ONLY one of the 9 that enters at the real production entrypoint (runPipelinedispatchInboundhandleIncomingMessage, the same function Twilio/SQS call), runs against an audited 2,502-row/117-eligible-conversation census, grades cheapest-first (exact/tool-match, LLM judge only on divergence), and is the only one whose isolation is verified live against AWS STS at run time — independently proof-run with 0 prod writes. RECOMMENDED
B quality-replay/ — real tool-execution-layer interception (recorded results served under the REAL reasoning loop) with the most rigorous prod-write isolation stack, and the only one that already reuses another suite's grader (Cerberus's checker) instead of inventing its own. Its own README calls it "spike quality," advisory/manual-trigger only, and it DOES write real (sandboxed) DDB rows — A writes none at all.
C Neither — combine A's real-entrypoint/audited-corpus shape with B's grader-reuse pattern (port B's "import the checker directly" trick into A's grader registry, section 3.4) rather than picking a single winner outright.

Recommendation: A, with B's grader-reuse pattern folded into the shared grader registry rather than lost. Entering at the real dispatcher is the property hardest to retrofit later (it's an architectural choice, not a config flag), and A already proves the strongest isolation contract found in either system. B's genuinely valuable idea — grade by importing an existing checker instead of inventing a new one — ports cleanly into A via section 3.4's registry, so nothing gets thrown away, only re-homed.

D2 — Migrate onto the skeleton incrementally, or freeze new harnesses until the port is done?

45 directories is a lot to move at once. The G14-style check (section 4) can land immediately either way — the question is what happens to the existing 45.

A Incremental: build the adapter for each suite one at a time, highest-incident-value first (after-call-harness and the turnover Crucible are already closest — both were touched or built this week), no stop-the-world rewrite. RECOMMENDED
B Freeze: no new harness work until every existing suite has an adapter — matches "finish this before starting that" but risks stalling tonight's live after-call-harness work, which is mid-flight right now.
C Wait for the promptfoo audit to land first, then plan both consolidations together as one pass.

Recommendation: A. The G14 check stops the bleeding immediately (no more sprawl); the adapters are additive and don't require touching a suite's own scenario files, so there's no real cost to doing them in parallel with live work instead of blocking it.

D3 — Who owns the atlas and the doctrine going forward?

The eval deep-inspection's own finding, two days ago: "today 'the standard' lives in one person's head" — nearly every mechanism here is single-author (Fede's automation account); Gera has one commit in the escalation Crucible, zero in the coworker harness.

A Status quo — Fede's automation account keeps building and maintaining new harnesses as they come up.
B Gera owns the doctrine + G14 check as the first named piece of "the standard"; the atlas table itself stays script-generated off each suite's fixture metadata (section 3.6), so it can't rot the way the 45 READMEs already have. RECOMMENDED
C No single owner — the atlas is a living doc anyone updates when they touch a harness (this is close to what happened to the 45 READMEs already, and is why none of them cross-link).

Recommendation: B. Naming an owner for the doctrine (not every harness — just the rule that new ones follow it) is the cheapest fix for the single-author problem; making the atlas itself generated rather than hand-maintained is what stops it becoming READMEs-with-extra-steps.

PropFlow Docs