Superseded as the living doc → the Eval & Testing Roadmap (this page stays as the frozen record, 2026-08-20).

Proposed — pending Fede's review · researched 2026-08-20 (8-agent context fleet over the repo + practice)

The Quality System Plan

One pipeline for measuring Clara, one CI check that tells a Claude builder they made things worse, and a rebuilt outbound checkpoint that sees the whole trace and can send / repair / hold. Sequenced for the next five weeks, ending in decisions made on measured numbers.

In one paragraph. We own many measuring instruments — the full census is the eval inventory (2026-08-20): ten separate testing systems, including 56 behavior suites, ~85 one-off eval scripts across two overlapping folders (one not even in git), 275 incident-pinning drift tests, a 140-scenario voice harness, the 385-label golden set, and 30+ copy-pasted judge implementations — but no single system: different graders, different corpora, no signal to a PR that it made Clara worse, and the outbound guard sees the least context of any component while carrying the most responsibility. This plan unifies measurement into one pipeline, gives CI a regression voice that Claude builders act on, and rebuilds the outbound checkpoint around the full trace and a truth ledger with a three-way disposition: send, repair, or hold for an internal human. It is sequenced for the next five weeks and ends in decisions made on measured numbers, not vibes.
1. The three layers, tonight's evidence
2. One measurement pipeline
3. CI that tells Claude it made things worse
4. Input layer — context receipts & truth diff
5. Outbound checkpoint v2
6. The hold queue
6b. Post-hoc prod judging — the daily reviewer, paused
7. Sequencing — the next five weeks
7b. The three-layer POC — complete, results
8. The decisions
9. What we are NOT doing
Method & caveats

TL;DR

2 pipelinestext and voice build Clara's context in two separate, independently-maintained code trees — a fix to one does not reach the other
5 minhow stale application status can be before the next AppFolio sync — the named mechanism behind wrong applicant context
6,374 linesthe single function that runs the whole text-channel agentic loop, guards included
20 messagesthe trailing window every live outbound guard sees — never the full conversation, never the full tool history
0 jobstoday, nothing runs the current code and a proposed change side by side on the same conversations to see which one does worse — every automated check compares new output against an old saved answer sheet
OFFthe outbound safety check is built and merged but switched off everywhere in prod — founder decision, stays off for now

Five weeks of work below: one measurement pipeline, a paired CI regression job that reports into the same review loop Claude builders already act on, structured context receipts with staleness disclosed, and an outbound checkpoint extension proven offline before any live step — six decisions gate what happens after.

1. The three layers, with tonight's evidence

The founder's taxonomy — INPUT (wrong context reaches Clara), LOOP (Clara reasons/calls tools wrong), OUTBOUND (a bad reply almost ships) — maps cleanly onto tonight's fleet findings.

INPUT

LOOP

OUTBOUND — post-P8 reality

Design principle for this whole plan: layer attribution by construction, not by judge. Research shows post-hoc attribution is immature — the best benchmarked method names the responsible step correctly only 14.2% of the time (the Who&When benchmark, 127 annotated multi-agent failure logs; even frontier reasoning models don't reach practical usability). So each layer writes its own receipt — a context receipt, tool results, a guard verdict — and a failure's layer is read off the receipts deterministically, never guessed by a judge reading the whole trace after the fact. arxiv.org/abs/2505.00212 ("Who&When")

2. One measurement pipeline ("one ruler")

3. CI that tells Claude it made things worse

4. Input layer — context receipts and the truth diff

5. Outbound checkpoint v2 — full context, grounded, repair-not-rewrite

Do not build a new guard — extend the outbound safety check that is already built and merged but switched off. Three extensions: PR #5815; POLICY_GATE_MODE

(1) Grounding → truth ledger

Ledger v1, honestly scoped: wrap the 4 fields the merged-but-off safety check already carries (tourSnapshot, preparedOffer, currentRent, conversationEscalated — the only consolidation seam that exists today) behind one named accessor, redirect the renewal read through the canonical renewal accessor it currently bypasses, and stamp every field with its source and last-sync time. The remaining rows below are v2, each its own scoped change — the work-order aggregate is a state change the code itself says wants its own PR, and the escalation-matter and specials rows need new wiring (no guard reads them today), so billing them as "consolidation" would overstate what exists. The table is the full inventory with known holes:

Ledger rowFreshnessKnown hole
Tour snapshotImmediate — written synchronously by the tour tool handlers, no sync lagThe guard reads a single denormalized pointer on the prospect row; the prompt reads across every tour the person owns on any channel — they can, by design, see two different tours for the same person
preparedOffer / currentRent~60s poller for preparedOffer; currentRent depends on a manual rent-roll upload — could be stale for weeksA separate live-scraped pricing system (UnitPrice) is never written back onto Unit.rent — two "current rent" surfaces coexist unreconciled
Work-order status~1-minute PMS sync — the fastest cadence of any jobNo durable "current turnover state" aggregate exists; guards ground only against this turn's own tool outcome, so an honest failure can be wrongly re-blocked next turn with no memory of the prior one
Renewal saga stateSingle-writer, optimistic-version-locked — the best-governed object in this inventoryA canonical read-side accessor already exists (renewal-view.ts) but the guard's own snapshot assembly bypasses it today, a duplicate read path
Application status + staleness stamp5-minute poller — the known weak spotAn unbounded-staleness hole: once an application ages out of the PMS report window, the sync stops seeing the row and a stale status can persist indefinitely with nothing bounding its age
Specials, with source tagsOverwritten on every scraper watcher run unless manually enteredDual-writer risk — no per-entry freshness timestamp beyond the last write's origin tag
Escalation matter stateLive, per-question, durable — the modern systemNot read by the guard/policy-gate grounding object today; the guard still reads a coarser boolean that its own doc calls a weak signal ("auto-reopens on any inbound message, proves nothing about the team acting")

Structural risk to respect: core state types are declared twice in this repo (once under agents/, once under src/), a deliberate parallel tree that must be kept manually in sync — the ledger needs to live where both trees consume it. agents/clara/lib/data/types.ts:1-5 ("PARALLEL TREE — read this before adding or modifying types here")

(2) Full trace input, structured

The checkpoint sees the inbound message, the context receipt (section 4), the tool calls and their actual results, and the draft — as structured fields, not prose. OpenAI's own reference agent framework documents that its standard output guardrail sees only the final draft reply — not the question, the retrieval, or which tools ran — a real, named gap. And a 2026 benchmark built specifically for multi-step tool-calling guardrails found accuracy was driven more by whether the guard could correctly PARSE the structured trace than by its actual safety judgment — a "structural bottleneck." Keep the input schema boring. Scope note: checkpoint v2 stays turn-scoped — this turn's inbound, receipt, tools, and draft, on top of the existing trailing conversation window — full-conversation review remains the separate async reviewer's job, so this widening adds no new context-length cost. openai.github.io/openai-agents-python/guardrails/; arxiv.org/abs/2604.07223 (TraceSafe)

(3) Why-Clara-decided

The reply-rationale trace (ADR-0110's message-rationale machinery, already pinned by its own promptfoo suite) rides along so the judge sees Clara's own stated grounds for the reply, not just the reply text.

Repair, never rewrite

Span-level only: a claim that fails grounding is repaired to the ledger's truth or removed, each repair citing its ledger row; repaired drafts re-run the full check; no canned replacements, no whole-reply regeneration — P8's exact failure mode. Research backs this precisely: blind full regeneration broke 47 previously-correct answers out of ~1,300 test problems in one study while a version that only swaps in a fix when a separate checker can prove it's better broke close to zero. The repo's own live pattern is the template: the promise-backing "make it true" fixpoint rewrite and the escalation-claims repair, both grounded on the same shared detector, hold a combined zero false positives across a 2,594-turn replay and a 30-day, 515-conversation live production check. arxiv.org/abs/2605.24613 ("Guarded Repair"); src/lib/domain/compliance/policies/promise-backing-policy.ts:1-194 (PR #5915); agents/clara/lib/agent/policies/escalation-claims-policy.ts:1-52

Three-way disposition

PASS (send as-is) / REPAIR (send repaired, audit-marked — the live blockedDraft registry, already merged and covering 7 guard families, already records before/after) / HOLD (do not send; page a human). Confidence is one input weighted ≤~15% alongside deterministic rule hits and grounding results — production guidance converges on never trusting a model's self-reported confidence alone. Protected categories and legal/numbers lanes bias to hold; fail-closed on checker error for action-claiming or legal-adjacent drafts, fail-open only for low-stakes conversational lanes — the per-lane table is a founder decision below. src/lib/domain/messaging/blocked-draft.ts:1-81 (BLOCKED_DRAFT_GUARD_REGISTRY, PR #5764); confident-ai.com/blog/human-in-the-loop-ai-agent-evaluation (≤15% confidence weighting)

The false-positive law. Block-rate and false-block-rate correlate at ~0.878 in benchmark analysis — a filter made stricter to catch more real problems also blocks more good replies. Stacking five 90%-accurate checks in a row already means a legitimate reply has only about a 59% chance of getting through untouched, and once a guard's wrong-block rate passes roughly 2%, the trust it costs outweighs the safety it buys. Every widening of scope must re-prove precision on replay before it ships — already repo doctrine post-P8; this plan makes it the permanent rule for the checkpoint. tianpan.co/blog/2026-04-20-alignment-tax-product-ai-safety-guardrails

Voice: post-call reconciliation against the same ledger only — no inline latency, the standing founder rule. This matches converging practitioner guidance that guard checks belong async/post-call on anything latency-sensitive; a lean three-check guard stack alone measured 350-400ms.

6. The hold queue (human-in-the-loop for internal engineering)

6b. Post-hoc prod judging — the daily reviewer, paused Proposed — pending review

Every layer above checks a conversation before or during the send. This section is about the fourth check: something reading a whole conversation after it's over and grading whether Clara handled it well — the only layer that can catch a mistake none of the live guards were built to look for.

Who checks a conversation, and when
CI replay gate
before a code change ships
proven on a small surface
Policy gate
at send, turn by turn
built & merged, switched OFF
Daily reviewer
the day's conversations, after the fact
PAUSED since ~Aug 16
The gap sits at the third box. Nothing today reads a finished conversation and rules on whether Clara got it right — the two live checks above only ever see one code change or one turn at a time, never the whole story after it's done.

What we found (verified 2026-08-21/22, repo-side and Slack-side). The app already has a daily reviewer built for exactly this: conversation-review-daily (merged 2026-07-18). It runs on a schedule every afternoon, reads every conversation from the previous 24 hours in full — the transcript, the tool calls, the call analysis — and has an AI reviewer propose findings that must quote the exact message and cite it, then a second, independent AI checks and can strike down any finding that doesn't hold up. The result posts as a daily digest to the #agent-smith Slack channel. It was designed to run side by side with the team's existing daily list (Agent Smith) until it proved itself, then take over as the sole reviewer.

That handoff never happened. The schedule that fires the daily reviewer is paused — it last ran around August 16 and nobody restarted it. Separately, the team's plan for Agent Smith is to retire both daily lists (this reviewer and Agent Smith's own, which by design does nothing today) and replace them with a live feed of what's happening posted straight to #apartment-camellia as it happens. That feed is meant to eventually carry a 1–5 quality score per conversation — but a live feed of events is not the same thing as a judge; scoring needs a reviewer behind it, and today there isn't one running.

Net effect: since about August 16, nothing has reviewed a finished prod conversation and said whether Clara handled it well. Every live guard above still runs — this is a gap in the after-the-fact check, not in the in-conversation ones.

q-posthoc-next — What do we do about the paused daily reviewer?

The schedule is paused, not deleted — nobody should delete it before this is answered. Coordinate with the team planning the #apartment-camellia activity feed before touching it either way; that plan and this decision both claim the same territory.

In plain terms: right now nobody checks yesterday's conversations to see if Clara did a good job — the robot that used to do that got switched off about a week ago and nobody noticed until this week. Turning it back on costs nothing. Option C also makes its findings useful instead of just scrolling by in Slack: they become suggested teaching examples that a person still has to approve.

q-posthoc-desk — Once verdicts exist, what happens to them?

Only asked if C is chosen above.

7. Sequencing — the next five weeks

WeekThemeShipsTestbed
1
now – Aug 24
(a short week: ~3 working days)
One rulerCase format + LAYER tags; corpus fold-in (golden 385 + would-flag bed + top suites); baseline scoreboard number. Grader unification is deliberately NOT here — it crosses a live build boundary mid-migration (section 2); week 1 ships only the per-tree shim, and only if it stays a one-liner eachNone needed — offline
2
Aug 24 – 31
CI delta — prove the mechanismPaired base-vs-head spike on ONE lane (intent): sibling merge-base checkout working end to end, the four known traps answered (history depth, harness-version mismatch → honest "incomparable", fork-PR credential skip, measured cost of doubling), advisory output only. Parallel, small: context receipt on AgentTrace + the two deterministic input alarms (catch-all mapper alert, allowlist drift test)Intent corpus
3
Aug 31 – Sep 7
CI delta rollout + input truthPaired job extends to renewals; sticky delta comment + the underpowered-honesty check; nightly main sweep → #alerts; umbrella budget retirement (only once the spike's cost number is in hand); nightly truth-diff job → desk "wrong context" items; golden set layer-labeling passRenewals corpus; Camellia traffic samples, read-only — no writes, no effect on anything sent
4
Sep 7 – 14
Ledger + checkpoint + hold queueTruth ledger v1 (the honest 4-field scope above); checkpoint v2 trace-input widening; prompt-conflict lint v1; held_outbound queue built with the new engineering-only visibility gateThe Willows sandbox (synthetic)
5
Sep 14 – 21
Prove offline, drill the holdOffline subscription replay of checkpoint v2 over real recent traffic (policy-gate-spec doctrine: every flagged case individually reviewed) → measured precision/recall published; end-to-end hold drill on the Willows bench (synthetic traffic only — a real hold, page, approve/edit/reject, corpus capture, no real customer); blocked-draft UI revived from its stale branch (a real rebase, 200+ commits behind main)The Willows sandbox (synthetic)

Then: the decision gate (section 8). Nothing goes live on real traffic in these five weeks beyond receipts/logging — every live-behavior change waits for the decisions below. One more output of reviewing this page: the founders split ownership of the lanes above (almost everything in the inventory is single-author today) — the census to divide is the eval inventory; this page is where the split gets written down.

7b. The three-layer POC — COMPLETE, results published

Done 2026-08-20, same day: all four prototype lanes built, run, and independently re-verified against the five real Camellia failures. Full metrics, pros/cons per lane, the verified overfitting audit, and the CI regression design: Catching Clara's Mistakes — the POC results. Headline: every lane caught 5/5 with 0 false alarms and 2/2 regression kills (all independently reproduced); the audit's real finding is that structural truth-diff checks generalize and are solved today, while the semantic classes were only phrase-matched and belong to the AI-judge leg — the architecture verdict is compose (our checkers + promptfoo chassis + one shared before/after diff), not adopt a framework.

The founder's framing, 2026-08-20: single-number evals are shallow — like unit tests. Multi-turn suites are better, but neither says which layer broke. So before the five weeks above harden anything, a proof-of-concept is testing the three-layer idea on real life: five real Camellia conversations that actually failed, one per failure class, pulled from the founder-graded golden set and sanitized (fake names, fake numbers — the conversations and failures are verbatim otherwise).

Competing prototypes, one frozen scorecard. Up to four independent agent teams each build a small harness that must catch those five failures, attribute each to its layer by evidence (a receipt diff or a paired clean-twin diff — research puts cold-read judges at roughly 14–25% accuracy on "which step broke," so cold reads don't count), stay quiet on clean bait, and kill seeded mutations (the same conversation minimally worsened — the "did a change make things worse" primitive). The stacks, chosen from a four-lane research sweep of open-source frameworks and how agent companies (Anthropic, Sierra, Intercom, Decagon, Cursor) actually test — with one framing correction from the founder (2026-08-20): the research initially dinged every guardrail framework for grounding "text against text you hand it, not a live database," but the truth source is just a delivery mechanism — the truth ledger serializes into text at check time, so that objection evaporates and gets tested empirically instead of decided on paper. Four lanes: a hand-rolled TypeScript receipts-and-checkpoint harness (borrowing the frameworks' best ideas: a repair-not-just-block verdict vocabulary, span-level fixes, typed pass/hold/repair/block findings); an existing guardrail framework fed serialized truth as its source text (Guardrails AI, whose sentence-level provenance mode flags exactly which sentence is unsupported — the head-to-head the founder's poke demands); promptfoo extended with trace-path assertions (already in the stack, native subscription login); and a Python eval framework (inspect-ai, subscription-credential native) bringing trajectory scoring and full-transcript logs out of the box. The frameworks' remaining real differences — verdict vocabulary, span-level repair, regression diffing — are now things the scorecard measures, not assumptions.

The deliverable is the architecture plus the measured results: per prototype — catch rate on the five real failures, layer-attribution correctness, false alarms, mutation-kill rate, verdict quality, cost and wall time, maintenance burden — with pros and cons, and a concrete recommendation for how CI uses the winner to tell a builder "this change made Clara worse." Everything runs offline on sanitized fixtures under the subscription; nothing merges, nothing touches live traffic; whatever wins feeds the week-2/3 CI delta lanes above rather than replacing them.

8. The decisions — deferred until there is working software

Founder ruling, 2026-08-20: "I need working software before decisions." Nothing below blocks any build work, and none of these questions is being asked right now. Weeks 1–3 and the POC proceed on the do-nothing-live defaults (everything stays offline; nothing arms; the four held PRs stay held). Each question below comes back to the founders only when the working software that informs it exists — the POC results for the framework-shaped calls, the paired-CI spike numbers for the gating calls, the offline replay numbers for the checkpoint calls. The list stays here so the questions are pre-registered before the numbers exist — that is what keeps the eventual answers honest.

Answers save for everyone who opens this page; the recommended option is listed first and marked — recommendations become real asks only once the software behind them runs.

q-gate-lanes — Which suites become blocking first?

Blocking CI gates on AI behavior are already authorized in principle (D3, 2026-08-18) — this is about which checks go first. This same open call already sits on the eval inspection page; deciding it here supersedes that instance with the full five-week sequencing attached.

q-hold-host — Where do held messages live?

The fleet's ranked recommendation: extend the live /review queue rather than build a new surface — it already has the approve/reject mechanics, four prior extensions of the exact same pattern, and live polling; it just needs new platform_admin-only gating.

q-checkpoint-next — After the offline replay proves precision, what is the first live step?

The pre-send gate stays OFF today per the founder's standing decision. This decision only pre-registers what evidence would justify the next step — nothing moves without his explicit yes, even on green replay numbers.

Evidence for the leasing lane specifically: the leasing gate scorecard — full-population replay (45/45 conversations, 135 draws), 4/5 hand-read flags were true catches, cross-validated by a same-night production audit.

q-unlock-bar — The numeric bar that unlocks the four held promotion-pipeline PRs

Fede's decision on 2026-08-20: the four PRs (#5782, #5784, #5785, #5786 — distiller, corpus re-run gate, promotion arm, principle injection) stay held "until agentic quality and testing significantly improve." This turns that sentence into numbers.

q-repair-scope — What may the checkpoint repair automatically?

The live "make it true" pattern today only ever repairs a claim class where the repair tool's success and the claim's truth are the same event (an escalation claim, backed by actually calling the forwarding tool) — never an arbitrary fact.

q-input-fix-priority — Biggest input-layer fix to schedule right after the five weeks?

Three real candidates surfaced tonight, each already documented as a known, named gap in the code.

9. What we are NOT doing (scope fences)

Method & caveats

8-agent context fleet, 2026-08-20 (5 repo dives + 2 web research + this synthesis) — ~893K tokens, 419 tool calls across input-context, prompt-conflicts, guard-internals, hitl-surfaces, truth-ledger, ci-feedback, research-guardrails, and research-layers. Every claim above traces to a file:line, PR, or commit cited inline, or to the two named research lanes. No customer name, phone number, or email appears anywhere on this page. Builds on the 41-agent eval system inspection (2026-08-19 — the 54-suite inventory, the Sonnet 5 story, the same open which-suites-gate-first call this page's q-gate-lanes decision now carries forward) and the honesty-layer deep inspection (2026-08-16 — the P8 postmortem and the redesign doctrine this plan's outbound section builds on), both linked from the architecture source of truth. Companion census: the eval inventory (2026-08-20), produced by a parallel session as this plan's ground-truth inventory — its five consolidation moves are folded into sections 2–4 above.

PropFlow Docs