Answer anything on file

Decision doc · Accepted 2026-08-03 · companions: deposit postmortem · channel-split decision

Decisions (Fede, 2026-08-03): Q1 = A, schema-derived injected knowledge block. Q2 = no output guard — rely on injection + generated evals (risk accepted: no runtime check stands between a small model's bad day and an outbox; the gauntlet and replay corpus are the containment). Q3 = straight to general — the narrow deposit-fix worktree is retired.

Ship gate (Fede): hard proof that the new solution is better than current prod — on all eligible real past conversations plus synthetic data — before anything ships. Protocol below; nothing merges until the proof artifacts are attached and reviewed.

The ask (Fede, 2026-08-03): stop fixing this one deposit field. Make Clara able to answer anything that's in the property knowledge base on email/SMS — and route anything that isn't — without hand-writing every fact into a tool description. Three premises are taken as direction, not open questions:

What the knowledge base actually holds

BlockShapeExamplesReaches email today?
pricingDetails~19 structured fields + customFees securityDeposit, petFee/Deposit/Rent, adminFee, applicationFee, parking, storageFee, holdingDeposit, transferFee, mtmFee, earlyTerminationMultiplier, nsfFee, utilitySetupFee, unauthorizedPetFee, keyFobDeposit, lateFee No — only via tools the model may not call
sectionsfree-text policy cards (doc-ingested, human-confirmed) Pet Policy, Smoking, Laundry, Lease Terms Yes — rendered as PROPERTY POLICIES
concessionsfree text"1 month free on 12-mo leases" Yes — LEASING SPECIALS
hours / links / phonesstructuredoffice hours, application link Yes

So the gap is precisely the structured facts block — the one with the dollar amounts, where being wrong hurts most. Voice already injects it ({{pricing_fees}}, INJECT-4); email deliberately excludes it from the prompt and reaches it only through tool selection.

In plain terms

Clara's email brain already gets handed the property's policies, specials, and office hours on a card. The fee sheet — the thing prospects ask about most — was left off the card, and she was told "go look it up if you think you need to," with a catalog whose labels didn't say where the deposit was. The fix is to put the whole fee sheet on the card, generated from the database so it can never go stale, and mark every blank line as "not on file" so she knows when to hand off to a human instead of guessing.

Q1 — How should knowledge-base facts reach the model on email/SMS?

Q2 — How do we enforce "only cite what's on file"?

Injection makes correct answers possible; it doesn't stop a small model from inventing a number anyway (Haiku fabricated "$1,350 = one month's rent" under the always-route rule). The hallucination guard already verifies dollar amounts against renewal offers — the same pattern can verify leasing replies: any dollar amount / numeric fact in an outbound email/SMS leasing reply must trace to the injected knowledge block or a tool result from this turn.

Q3 — Does the held deposit fix ship first, or fold into this?

The narrow fix (RULE 7.0 deposit clause + tool description + eval cases 13/13b) sits proven but unshipped in worktree propflowai-deposit-quote, with one Haiku tour-pushiness regression open. The general fix replaces most of it: the injection block supersedes the description edit, and a general "answer what's on file, route what isn't" rule supersedes the deposit-specific clause.

The eval that makes this stick — generated, not hand-written

"Deposit ON FILE → quote it" was one hand-authored case; the general fix gets a generated knowledge-grounding gauntlet:

What this closes structurally: the incident's three root causes each lose their mechanism. Descriptions can't under-describe (nothing behavioral lives in them); channels can't diverge on facts (both read the same rendered knowledge); and the eval can't lag the schema (cases are generated from it). The remaining human-authored surface is the route-vs-answer policy — one rule, stated once.

Proof protocol — the ship gate

Two arms, both run against the candidate build and current prod (baseline), same inputs, same graders. The PR does not merge until both pass and Fede has reviewed the artifacts.

Arm 1 — every eligible real conversation we've ever had

Arm 2 — synthetic, generated from the schema

Proof artifacts (parity report, divergence review, gauntlet JSONs both arms) attach to the cutover PR. This PR does not auto-merge regardless of green — Fede reviews the proof.

Team-side follow-through

Evidence base: prompt/tool paths verified in-repo 2026-08-03 (context builders conversation-manager.ts:3160/3348, voice injection leasing-context-injection.ts:371, no forced tool_choice or fee router anywhere in the conversation loop). Corpus and replay figures from evals/replay-harness/ README census 2026-08-02. Token-cost figure is an estimate until measured.
PropFlow Docs