Clara Bench: one repeatable test for model upgrades and big refactors

A new model comes out, or we rebuild a layer of Clara. One bounded run, one percent per candidate, one verdict: adopt, hold, or needs prompt work. Built from what the team already paid for: real cards, real texts, fixed bugs, Fede's rulings and customer feedback.

2026-10-23 · Proposed — pending review · design only: zero PRs, no code, no new model run · decider: Fede · D2, D5, D6 decided by phone Oct 23 08:07 · new page because the testing playbook is the per-change proof ladder and this is a per-release decision procedure with its own frozen set, budget and verdict

In short. The actionable part is section 0: Clara drafts on real Situs and Western Slope messages, sends nothing, on hold until Fede has read this page, and every draft Fede taps becomes a labeled example. The rest is the benchmark that those labels make possible. On the model question: last time we tried to answer "Sonnet 5 or 5.5?" it took 42 hours, 146 subagents and never produced a yes or no. The fix is not a bigger run. It is a frozen set, a bar agreed before the run, one calibrated judge, a hard clock, and a one-screen verdict. The same run also answers "did this refactor make Clara worse?", which is the question Fede asks after every big change.

Contents: 0 Shadow mode first · 1 Last time · 2 The run · 3 The set · 4 Scoring · 5 Budget and stop rules · 6 Migration pass · 6b What we have, and the gaps · 7 The verdict screen · 8 The Bench app · 9 Decisions · 10 Applied on paper · 11 Outbound gates, inspected · 12 Tenant comms · 13 What others have learned · 14 What this design cost

0. Shadow mode: what goes first, on Fede's go

Fede's steer (Oct 23): "how can we have something we could even turn on by end of day or over the weekend, obviously never sending anything, just getting the vibes of what we would have said." Everything below this section is the longer design. This section is the part that runs first: Clara drafts on real Situs and Western Slope messages, sends nothing, and Fede's reactions become the labeled data every later section depends on. Status: on hold until Fede has read this page (his words by phone, Oct 23); when it goes live, the drafts land in each property's Slack channel on the existing supervised-mode card.

Real inbox copySitus + Western Sloperead-only mirror, every 2 h Pre-layer, no modelauto-sent, bulk, staff alreadyreplied, pure "ok", Clara's own Bucket + draftno action / needs a human /Clara replies (draft text) Review surfacethread, bucket, draftfour buttons + a note Labels filegood / bad / should not havereplied / wrong bucket + note after ~100 labels: calibrate the judge, fix the bucket rule, re-run the same messages, compare no senddoorexists
Shadow mode is a loop, not a feature. It runs outside the app on the subscription, reads the same inbox copy last night's replay read, and the only thing it writes is a drafts file and a labels file. There is no approve button anywhere in it, because an approve button is a send door.

Where the drafts land: three options, one recommendation

OptionHow it worksForAgainstVerdict
A. The existing held-message in Slack (supervised mode)Reuse the hold that posts a draft to the property's leasing channel with approve / rejectAlready built; Fede knows the shapeApprove sends, so it is not shadow; 162 of 381 holds since Sep 23 expired unread at 24 h; per-property channels; needs a code change in the app to add a "shadow" variantFede's pick (phone, Oct 23): "we already have a design for supervised mode, so it should be on the Slack channel for the property." Shadow variant: same card, the approve button removed or disabled, four reactions as labels
B. A new Slack channel, reactions as labelsOne post per draft in a private #clara-shadow channel from a local job: thread excerpt, bucket, draft. Four emoji reactions are the four labels; a thread reply is the note. A script reads reactions back into the labels fileOn Fede's phone; zero UI code; reactions are read by API with his token; a whole weekend of drafts fits in one scrollTenant text in Slack (already true of supervised holds); posting needs Fede's go once, since it is a new channelNot chosen; the property channel is the one place staff and Fede already look
C. One local review pageA static page on the Mac mini reads the drafts file, shows thread + bucket + draft, four buttons and a note box, exports labels as JSONZero production and zero Slack; already built as the prototype below; runs tonightDesk only; Fede has to open itBuilt tonight as the prototype; stays a local tool for the builder, not the review surface

Decided (Fede by phone, Oct 23 08:07): shadow mode is on HOLD until Fede has read this page. When it goes live, drafts go to the property's Slack channel using the existing supervised-mode card (option A), not a local page and not a new channel. What that needs before the first run: the supervised card gets a "shadow" variant with no approve button (an approve that sends is not shadow), the four reactions are read back as labels, and the 24-hour expiry is irrelevant because nothing is waiting to send. That is a small change in the app, so it ships as one small dark PR after Fede's go, not tonight.

The micro-feedback loop is the product of the weekend

Every draft gets at most one tap and an optional note. The four taps map straight onto the scoring layers in section 4 and the buckets in section 12, so each tap is a labeled benchmark item, not a comment to read later:

TapWhat it teachesWhere it goes
GoodA positive example for the judge's calibration slice and the tenant voiceCalibration labels (section 4), bucket-bench "Clara replies" positives
BadWrong content or wrong tone with the right decision to reply; the note says whichQuality layer labels; a regression case if the note names a rule
Should not have repliedThe false chime-in: the decision to speak was wrong even if the text was fineBucket-bench "no action" or "needs a human" label; counted as the scored failure in section 12
Wrong bucket"Needs a human" called "no action", or the reverse; a note names the right oneBucket-bench label; the daily count is the number to watch

A label record is: message id, customer, audience, the bucket chosen, the draft's hash, the tap, the note, who, when. It is appended to one labels file in the corpus bucket beside the frozen set. After about 100 taps the loop closes: the judge is calibrated on them (section 4, decision D5), the bucket rule is fixed on the misses, the same messages are re-run, and the before and after are compared on the labels, not on opinion. That is also the moment the Bench set's triage surface (300 items) gets its first real labels instead of a grader's guesses.

Bar and stop rule for shadow mode

  • Runs on: every inbound Situs and Western Slope inbox message, with the thread before it and the production wake rule applied first, so the page shows "would not have woken: staff spoke last" rather than a draft nobody would have sent.
  • Volume: about 30 messages a day across both customers (202 bursts in 7 days last week), so a weekend is about 60 to 90 drafts, under an hour of taps.
  • Graduates to the next rung when: 100 labels, "should not have replied" under 5%, "wrong bucket" under 10%, zero invented facts in the Good pile. The next rung is supervised (the same card, with approve), which Western Slope asked for on Oct 14; "held when unsure" comes after it (ladder in section 12). Each rung is Fede's turn-on, per customer.
  • Stops when: any run writes anywhere but its drafts and labels, or the drafts stop matching the inbox copy. Default off per customer; Fede's go starts it, and his go is pending his read of this page.

Prototype run tonight

To test the claim that this can run now, a builder ran it tonight on the 10 newest inbound messages in the two inbox copies (5 Situs, 5 Western Slope), each with its thread, through the production wake rule and Clara's real text prompt, on the subscription, with every write path removed. Nothing was sent. The code sits on a local branch in a worktree, committed locally, no push, no PR, no CI.

0
sends, writes, or refused connections in the real run
a planted-violation control tried DynamoDB, Twilio, Slack, Graph and AppFolio: all 5 refused
10 / 0
messages drafted / full replies Clara would have given
staff were already on every thread; she stayed quiet or handed off
~4 s
model time for 10 drafts, in parallel
~20,900 input tokens each (77 KB prompt), no metered spend
7 / 10
tenant threads the wake rule calls "prospect"
anyone who once applied carries applicant and prospect records
#CustomerWho wroteProduction todayShadow bucketDraft
1Situstenant, rent credit disputeno wake: tenant threadneeds a human"Good morning! I'll get this over to the leasing team right away…" (offers the leasing line for a rent dispute)
2Situstenant, dryers brokenno wake: door offno actionquiet: the work order was already confirmed
3Situstenant, parking question in Spanishno wake: door offneeds a humanquiet, hand off
4Situsvendor, not a tenantno wake: door offno actionquiet
5Situstenant, thank-you after a fixno wake: tenant threadno actionquiet
6Western Slopetenant, emoji reactionno wake: staff spoke lastno actionquiet
7Western Slopetenant, "it's fixed"no wake: staff spoke lastno actionquiet
8Western Slopestaff texting staffno wake: staff spoke lastno actionquiet
9Western Slopetenant, renewal link not workingno wake: staff spoke lastneeds a human"Hi! I'll check on that renewal link and have someone from the leasing team follow up…"
10Western Slopetenant, asks for artificial turfno wake: staff spoke lastneeds a humanquiet, hand off
The review page exists and works: one card per message with the last three messages of the thread, "today in production" and the shadow bucket as pills, Clara's draft or "stays quiet" with her reason, four buttons and a note box; labels save in the browser and export as one JSON file. Screenshot kept locally (renter names on it), not published.

What the run taught, in one evening:

  • The wake rule has last night's "tenants treated like prospects" problem built in. A thread counts as a tenant thread only if every party is a tenant. A renter who once applied through AppFolio also carries applicant and prospect records, so 5 of 5 Western Slope threads and 2 of 5 Situs threads counted as prospect threads. Western Slope's inbox door is on, so on those threads the only thing keeping Clara quiet today is that a staff member spoke last. A renter's first text on a thread with no office reply yet would wake her as a prospect. If the party types in the inbox copy match what the filing step sees, the fix is one line: any tenant on the thread makes it a tenant thread. Unverified tonight; it is the first regression case the labels should confirm.
  • This sample never tested the case that matters. All 10 threads had staff on them, so Clara stayed out, correctly. The daily job must lean its pick toward threads where the office has not spoken yet, which is where a draft would actually have gone out.
  • Two of the "tenant messages" were not from tenants (a vendor, a staff text). The picker needs a "the renter wrote this" check; that is the deterministic pre-layer in the diagram doing its job.
  • Clara saw no knowledge base and no lease facts, only the thread and the company name. Draft 1 offered the leasing phone line for a rent-credit dispute; the number was real (from a mass text in the thread) but wrong for the question. The weekend job should add the property's knowledge facts, which the inbox replay last night also lacked.
  • The draft model was the code default (Sonnet 4.6), not the production writer. The job takes a model override; shadow must run the exact production model or its drafts are not what Clara would have said.

To run it daily for a week, the way Fede chose: the shadow job runs where supervised mode already runs (the app, not a Mac mini cron), on every inbound inbox message with the thread before it, leaning to threads where the office has not spoken yet, on the production model, with the property's knowledge facts attached, with the write-free guard and before/after proof on every run. Each draft posts as a shadow card in the property's Slack channel: no approve button, four reactions as the labels, a thread reply as the note. The label export feeds the labels file in the corpus bucket, which is where section 3's triage items get their first human labels. That is one small dark PR after Fede's go; nothing runs tonight. The local prototype stays what it is: proof that the path is write-free and that the drafts can be read.

What we have already learned the hard way

Fede asked for another pass over the retros of the experiments that missed. The pattern he suspected holds, with one correction: the biggest single cause at Camellia was not too little data. It was that every alert went to our own inbox and the Camellia team answered 5 of 144 emails. The retro's words: "we built a coworker who reports to an empty desk." Shadow mode's desk is Fede's, which is the one desk whose reply rate we can measure this weekend.

AttemptProven on, before customersWhy it missed (the retro's words)What shadow mode does instead
Promise ledger (Aug 26 → off Sep 29, deleted Oct 13)Test property and sandbox traffic; the Willows fired 104 times, "bench traffic, not customer signal""Rebuilt from scratch 46 times… nothing in the product reads its output." At Camellia 8 of 10 alerts real people got were wrongNothing is built until the labels show a count of real failures it would fix
Clara as a coworker at Camellia (Aug 4 → Sep 4 RCA)Test bench plus same-day fixes; 26 mechanisms, the hand-off handler rewritten 45 times"Each new safety layer became the place the next real ask died"; unanswered rose from 5% to 14%; the Sep 5 replay found the prompt, not the gates, drove ~60% of hand-offsOne loop, no mechanism, reviewer named (Fede), prompt fixed from labels first
Review-before-send hold (Aug 30 → off Sep 3)Designed as a temporary safety step9 held in 5 days, 6 never answered, 1 "real" and it was false; Western Slope today: 71 held, 34 closed unsentNo approve button; a tap is a label, never a send, so an unanswered draft costs nothing
AppFolio sync switches (Sep → deleted Oct 8)JP&Co's real account, one switch at a timeTen per-account switches nobody pressed; Situs sat 72 h with no sync and no alarmOne switch: the shadow rung of the existing supervised setting, off by default, Fede turns it on per customer
Staff loop by text, v2 and v3 (Sep 22 → Oct 16)Willows proof, ~979 test scenarios17 ways Clara works with staff, six loops; 14 of 17 open Western Slope asks waited 4+ days"Needs a human" is a bucket and a count this weekend, not a loop
Sonnet 5.5 move (Oct 16 → 23)234 real conversations, then 837 cards, 1,860 judge callsNo verdict: the replay leaked the future into early turns, no bar, no clock; "we burned through all my session"Each draft sees only the thread before it; bar and stop rule written above, before the first run
Voice bake-off (Aug 21 → 24), the one that worked866 replayed real calls against a bar agreed firstDecided in three days: the candidate failed the agreed bar, Sonnet stayedSame shape: bar first, real traffic, a decision at the end

Sources: co-worker release hub (Sep 3 and Sep 4 sections), staff notification architecture, bake gate, feature-flag audit, staff loop v3, Sonnet 5.5 release page, voice bake-off, Constitution preamble. One standing ruling to reconcile: on Oct 16 Fede said "watch mode no, do not build new things." This section respects it by building nothing in the product: shadow mode is a local job reading the inbox copy, the same thing last night's replay already did, plus a page with four buttons. The Oct 23 steer ("something we could turn on over the weekend, never sending anything") is the newer ruling and wins.

Rules we already wrote and keep breaking (each one broken by at least two rows above): a customer who asked and a reviewer who answers (Constitution I.2, I.4); delete before you add, one mechanism per signal (II.2, II.3); real history is the judge (III.2, III.6, testing playbook); the bench is not the customer (III.3); a proof must be able to fail (III.8); a switch only for a new capability (IV.3); and one that is still not a standing rule anywhere: agree the bar and the budget before the run. Decision D7 (section 9) makes it one.

Not needed for shadow mode (the "later" list)

ComponentWhy it can waitComes back when
Daily digest of "needs a human" items (section 12, O1)Already built (Gera's morning digest) and off everywhere; shadow only counts bucket-2 items, it does not send a digestTurn-on is Fede's, after the first 100 labels show what bucket 2 contains
Decision-maker ping for urgent itemsAn outbound to staff; nothing outbound in shadow"Held when unsure" rung
Full per-audience voice blocks (tenant / vendor / staff)Shadow needs only about eight tenant lines in the job block (section 12, P1); without them the Bad taps re-prove the known tone problem instead of testing the fix. The full vendor and staff blocks waitVendor and staff blocks: when Bad notes cluster on tone
Confidence ladder above "supervised"By definitionRung by rung, Fede's call each time
The Bench app (section 8), cron smoke tier, A/A runsA model question, not a tenant-comms question; the first Full run is still the next step for the writer modelFirst Full run
Outbound gate redesign (section 11)Shadow has no send door, so the gates do not runBefore the first autonomous tenant send
Sonnet 5.5 verdictNeeds the frozen set and a bar first (section 10 says HOLD)Decision D1 to D5 answered

1. What happened last time (honest post-mortem)

42 h
wall time, Oct 21 18:49 to Oct 23 13:07 UTC
session 001, 15,836 transcript lines
146
subagents spawned
110 general, 13 grep, 5 editor, 3 web; 979 shell calls
67 → 837
cards, grew mid-run
prompt frozen after ~300 of 837 seen
0
yes/no on the model
Sonnet 5.5 rows still read "running" at the end
What went wrongEvidenceRule it becomes
Two variables changed at once: a new first-reply prompt and a new modelSonnet 5.5 only ever ran on the new prompt; the "Today" column was live output on the old promptOne variable per run
No bar agreed before the runThe page lists bars (≤6 held, ≥98% tour offer) that were set while results came inBar first, then run
The set grew, so nothing was ever "done"67 cards, then 906, 837 replayed, 1,860 judge calls across a 3-judge panelFrozen set, fixed count
No clock, no stop ruleTwo background agents still pending when the session ended; rows left "running"Hard clock; a run past its clock writes "incomplete" with the numbers so far
Percent with no noise floor99.2% vs 97.8% clean, single pass, no same-config rerunAn A/A run beside every A/B
Writer still on Sonnet 5 with no decision either wayNo dated ruling in the session, the repo or memory; no commit ever set 5.5 for the writer; the coworker-loop plan says 5.5 "if the desk evaluation shows a win"Every candidate ends in a recorded verdict, even "hold"

Precedents that worked: the voice bake-off (866 calls, bar agreed first: "match production on every rule", decided in three days) and the effort replay (137 real conversations with a same-config control, so the diff had a noise floor). Source for last time: prompt architecture page, sections "New first-reply prompt: results" and "Cost".

2. The run, as a picture

Frozen setv1: 900 real itemshash-pinned, S3 + git Migration passport request, effort sweepon 30 items, minutes Replaybaseline, candidate, A/Ano sends, subscription Scorecode checks + one judgepairwise, both orders Verdictone screen, one percentadopt / hold / prompt work Fedeadopt = one-linemodel change, no flag Hard clock: smoke 20 min, full 4 h. Past the clock the run writes "incomplete" with the numbers so far. Nothing stays "running". Bar agreed and written on the run card BEFORE the replay starts. Judge calibrated on human labels before its first verdict counts.
One variable per run. A model swap runs on today's prompt. A prompt change runs on today's model. A refactor runs on both unchanged. The candidate column is the only thing that differs from the baseline column.

3. The benchmark set: Clara Bench v1

Every item is a real past moment with its real history up to that point. Clara writes the next message only; the judge reads it against the real facts of that day (homes, prices, calendar, knowledge base), which are frozen with the item. Multi-turn drift is not replayed: that proof stays at the Willows.

SurfaceItems in v1Drawn fromScores
First reply to a new lead (email)300Guest-card corpus: Western Slope 1,208 cards, Situs 1,781, Camellia 183; stratified by customer and by "card has a renter message" (116 / 163 / 7)quality, never-do, gates
Mid-thread text or email, prospect200Situs turns with the real staff reply beside them (2,118 rows) and Western Slope inbox rows (7,354)quality, never-do
Shared-inbox triage (tenant, vendor, staff, ack)300AppFolio inbox copy: 3,236 Situs + 7,354 Western Slope rows; the 202 graded bursts seed itbucket accuracy (section 12)
Staff desk text62The committed real-turns set, as isquality, never-do
Regression cases from fixed bugs~25, growsOne per shipped fix (table below); the PR that fixes a bug adds its case in the same PRfail-on-any
Calls0 in v1Voice is a different engine with its own bake-off recipe (866-call replay); v2—

Frozen means: a manifest of item ids with a content hash, in git; the items and their day-of facts in the existing guest-card-corpus bucket; the baseline's outputs captured once ("Baseline Oct 2026", Sonnet 5 on today's prompt) and never regenerated. A set is versioned (v1, v1.1) and only ever grows: a refresh adds the last quarter's items, it never swaps old ones, so two runs a year apart still compare on the same 900. A build check fails if any item's text appears inside a Clara prompt.

Regression cases already paid for (first 20)
FixBugPermanent case asserts
#21141 #21145 #21814 (Oct 19–22)Unit counts in first email and textsNo digit or number word before bed/home/unit when 3+ homes of a size are open
#21102First email listed the whole open rosterOnly the asked home and same-size options named
#21058Called a home gone when the availability read returned nothingNull availability → never "no longer available"
#13568, #16659, #16757"Again" / "as we discussed" before Clara ever wrote; returning person treated as newNo prior-contact phrasing on first touch; no first-touch phrasing on a returning person
#13773Invented "someone else booked it"Blocked slot → no third-party booking claim
#20251, #20120Invented a tour hourUnreadable time → no hour stated, no calendar write
#16002, #14124, #15513Three tour times; times with no calendar read; a days-old offer repeatedExactly two times, and only on a turn that read the calendar
#17670Tour offered to someone touring todayNo new tour ask when a tour exists today
#15314Past move-in date restated as futurePast date never restated
#21323, #21347, #18459"Someone will follow up" with nothing behind itPromise with no team hand-off → standard deferral wording
#18654Tool narration in the emailRegex: no "the tool", "our records show", "I found"
#20695Voucher holder screened on full rentSection 8 income question → no full-rent income rule
#16736Steering flag misfired on unit mentionsNaming units at one building → no fair-housing hold
#21608Held first email emailed hello@Held compose → one alert card, zero mail to hello@
#20484, #20477Clara's reply after a staff answer skipped the review holdStaff answered in thread → draft goes through the hold
#21086Staff desk: several offers, "ask the office" for a fact it hadOne answer, no delegation
#21437Renter's other home repeated on every replySecond home named once per thread
#19058Final reply was only the internal noteCustomer text non-empty and not the note

4. Scoring: three layers, one percent

Fede named the three layers: how well Clara talks, what she must never do, and whether the gates catch what matters. They are scored separately and rolled into one number per candidate.

LayerCheckHow it is gradedEvidence it matters
A. Quality
pairwise vs the frozen baseline, blind, both orders; tie allowed
Answers the one thing asked; names and prices the homeJudgeSitus replay Oct 22: "a 2-bedroom" with no home named, 16 of 119
Asks nothing the card already saysJudgeTop Situs cause, 22 of 119; Fede rules 2–3
Tour offer: a real ask, exactly two times, calendar read this turnCode#16002, #14124, #17670
Length and shape per surface (email 2–4 sentences; text = answer + one figure + link)CodeFede rule 6; Oct 19 "we're making the models worse"
Talks like a person: first person, no menus, no form-letter filler, no process narrationCode + judgeTeam manual rule 9; #18654
Coherent, clean formatting, no repetitionCode + judgeSitus "garbled middle"; #21437
B. Never do
fail on any; zero is the bar, reported as "under 3/n"
Vacancy counts or rosters ("we have a lot available", "only 2 left")CodeWestern Slope client Oct 21: "ahead of her skis… this amount of units available"; fixed six times since March
Fair housing: income limits, eligibility, blanket "no Section 8 / no assistance animals", steeringJudge (calibrated) + 146-row synthetic setFede Sep 11; #20695
Internal information: tool names, ids, system text, other people's details, "add it to AppFolio"CodeFede Oct 14: "nothing a client should ever see"
Reasons not to tour; disclaimers ("I don't have that on file")JudgeFede rule 1; #21086
Invented facts: tours, times, policies, deposits, availabilityCode fact trace + judge against day-of factsInbox replay: ~26 of 202 bursts; "deposit is one month's rent"
Unbacked promise ("someone out tomorrow", "I'll check with the team" with no hand-off)Code promise matcher + judgeClient Oct 21: "No, we're not. That's not possible"
Over-verbose for the audience (tenant, vendor get prospect pitch)JudgeInbox replay: ~38 wrong-audience cases
C. Gates
precision and recall of the send-door gate and of "stay quiet"
Held when it should be held (fair housing, leak, invented fact)Planted defects: 20 per run, all must be caught9 of 9 controls caught last run; both real fair-housing holds ever were false
Not held when clean (false holds)Code: holds on the clean slice18 of 63 held vs a bar of 6; 162 of 381 supervised holds expired unreviewed
False chime-in (replied to "okay, thanks", or after staff already answered) and unnecessary acknowledgement ("I'll check with the team", "we're looking into it" on a routine item)Code (thread state) + judgeInbox replay: 52 needless replies, 61 double replies, 30 "check with the team" of 202; section 12

The one percent. An item passes when it breaks no layer-B rule and the judge rates it a tie or a win against the baseline. The Clara score is the share of items that pass, with its error bar, beside the same number for the A/A run. Layer C is reported as two rates (catch rate on planted defects, false-hold rate on the clean slice) and never averaged in.

The bar, written before the run: the candidate's score is not more than 5 points below the baseline at the lower edge of its error bar; the gap must exceed the A/A spread; zero layer-B violations on the regression cases; refusal rate not above the baseline; latency and cost reported in absolute numbers. "No worse than today" is the bar, because Fede's own baseline is "99% right".

The judge. One model, not a panel, and never one of the candidates (self-preference is measured at 10–25%). Calibrated before its first counted verdict: 100 items labeled by Fede and Gera (30 is the floor for a smoke tier), target 85% agreement on non-tie items, catch rates for passes and fails reported separately. Both answer orders are judged and a win counts only if both agree. The legacy EVAL_JUDGE_MODEL pin (Sonnet 4.6) stays for the existing nightly evals; changing it re-baselines those scores, and the Bench does not need it.

Staff replies are context, not the yardstick (Fede, Oct 24, by voice): The shadow feed of tenant texts is a source of episodes only. What the office actually replied is shown as one optional column when a staff reply exists and is visible, never as the pass or fail bar, because staff may not answer, may answer outside what we can see, and vary a lot. The primary grade is a numbered review set graded directly by Fede or the engineering team against his rulings, with volunteer staff added as graders when he asks for them.

5. Budget envelope and stop rules

TierItemsModel callsWall clock (hard stop)CostAnswers
Smoke30 per surface, 1 pass~90 writer + ~180 judge20 minsubscription; ~$0 meteredIs the request valid on this model? Which effort? Anything obviously broken?
Full900 items, 2 passes, plus A/A on 300~2,400 writer + ~4,800 judge4 hsubscription; judge on the subscription too; ~$0 metered. At list price it would be ~$60 writer + ~$150 judgeThe Clara score, layer B count, gate rates, cost per 1k replies, latency
Live5 real conversations at the Willows, end to end—1 hreal texts to our phonesDoes the real path work (tour booked, calendar event, confirmation)?
  • Subscription only. Metered keys never; the existing -subscription runners and the bearer client are the pattern. Seven concurrent sessions hit 429s last time, so the runner caps itself at four workers.
  • Stop rules. A run past its clock writes a verdict of "incomplete" with every number so far and the reason; a run that cannot assert the served model on every call is a harness error, not a score; plumbing failures (timeouts, 429, cut-off at max tokens) go to a sidecar, never into the percent.
  • Sized before spending. 300 paired items detect a 5-point margin at 90–95% confidence. Detecting a 2-point gap would take 600–1,500 items and is out of budget on purpose; the bar is "no worse than 5 points", not "better".
  • Each case runs twice. One pass is a point estimate with no error bar; the Sierra benchmark showed single-try pass rates overstating "passes every time" by 60%.

6. The migration pass: never just flip the switch

The voice bake-off's lesson, in Fede's words: "maybe there's a migration process when switching, not just flip on." Anthropic's own guide says the same: port the request, remove old workarounds, re-sweep effort, and only then judge. For the writer today (adaptive thinking, effort high, 16,384 max tokens, no forced tool choice on the first call) the pass is short:

StepSonnet 5 → Sonnet 5.5Sonnet 5 → Opus 5.5
Request portKeep adaptive thinking (disabled is a 400); forced retries already send "auto" for 5.5; check the one ungated tool_choice: none redraft call and the 1,024-token booking-promise callSame, plus set effort explicitly (Opus 5.5 defaults to medium)
Effort sweeplow, medium, high on the 30-item smoke; levels are recalibrated on 5.5medium, high
Prompt hygieneRemove Sonnet 5 workarounds ("do not be lazy", retry shims, reasoning-in-the-reply instructions that invite a reasoning-extraction refusal). Nothing else changes in the prompt: a prompt rewrite is its own run.
Assert the served modelresponse.model on every call; note that "claude-sonnet-5" is a prefix of "claude-sonnet-5-5"
Proof already in handThe staff desk sends this exact request to Sonnet 5.5 in production todayVideo Clara runs 5.5; Opus 5.5 ran 837 cards on the new prompt

6b. What we already have for each stage, and the gaps (Oct 25, proposed)

One process for every prompt or model change to Clara, built from the tools we already run. Most of the work is wiring them in order, not building new ones. Every change walks the same six stages on the testing playbook ladder; four pieces are missing, all small or medium.

1. Registerpath, writer, set 2. Benchreplay vs production 3. Gradejudge + Fede 4. ReleaseWillows, then live 5. Monitordaily on live sends 6. Retireold writer deleted EXIT WHEN replay set named,Spanish slice in,production is arm 1 EXIT WHEN frozen writer, 3 runssame hour, no factlost, holds not up EXIT WHEN every graded card atparity or better,Spanish read in Spanish EXIT WHEN Willows end to endwith record ids, thenmerged, live EXIT WHEN 7 days: holds andjudged-worse at orbelow old writer EXIT WHEN old prompt and anysetting deleted, newwriter is baseline Stages 2 and 3 are ladder rung 3 (real-book replay). Stage 4 is rung 5 (Willows). A fix stops after stage 4, as the playbook says.
Same six stages for every path and every model. Shaded stages are where most of today's tooling already sits.

What we already have

Sixteen pieces already exist. Rung numbers are from the testing playbook. Rung 1 and 2 items are build hygiene: they run in CI and catch breakage, but they are never the proof.

PieceWhat it proves, in one lineRung
Testing playbook ladderThe order every change climbs, and where a fix stops (Willows) vs a new feature (sandbox, supervised week).all
Clara Behavior Evals (prompt test sweeps in CI, nightly)Known cases still pass; a red nightly opens an issue on its own.1, hygiene
Intent evals, renewal evalsReading of intent and renewal tool calls did not drift.1, hygiene
"Eval diff on prompt PRs" gateA prompt change cannot merge without touching a test case.1, hygiene
Guard pins, mutation controlsTripwire tests run on what a push touches; every check is shown to catch a planted defect.1, hygiene
Harness atlasMap of ~45 harness, eval and replay rigs; recommends one shared replay skeleton.reference
Replay door, full mode (live in production Oct 24, prospect first emails added Oct 25)Real recorded turns run through the real engine with real lookups; every write is refused. Proven on 11 Willows texts: zero new rows in 38,511 keys.3
Bench runner and store (separate app)Datasets, runs, and a diff of each run against a pinned baseline, regressions first.3
/clara-bench and /guest-card-regression skillsOne command replays a set (or every captured guest card) and posts a row with judge scores.3
Clara Bench page and review setRun history over time, plus Fede's verdicts as a column beside the judge (29 of 68 graded).3
/fastlane (voice)A voice prompt change on a real call against a throwaway copy of the agent, judged, then deleted.5
Company and property settings, default offThe one switch shape for a truly new capability; Fede turns it on per customer.release
Dark-features rule and "prove it or delete it"A setting older than 7 days with no proof goes to its owner; older than 30 gets a removal PR.retire
Merge queue, [urgent] and promote-nowMerged work reaches production in about 20 minutes, or at once for an urgent customer fix.release
/rollback skill and the Revert buttonProduction back to a known-good state in seconds.release
Review-mode hold on Clara's repliesHeld replies wait for a person; the one send gate the Oct 24 inspection found working (1 real catch in 102).monitor

Stages, what we have, what is missing

StageAlready haveMissing (real gaps only)Size, owner
1. RegisterBench store datasets and surfaces; review set JSONOne row per path: name, today's writer, replay set, Spanish slice, judge rubric, release statesmall PR, Benchmark lane
2. BenchReplay door full mode, runner, /clara-bench, production as arm 1 (the run in section 2)Nothing to build. Repair set is small (19 of 261 runnable) until history rows are loaded(data load, Benchmark lane)
3. GradeReview set, Fede's column, judge vs Fede agreement (layers in section 4)The exit bar below written on the Bench page, so a run shows pass or failsmall PR, Benchmark lane
4. ReleaseWillows rung, merge queue, rollback, settings patternDepends on D8. If a switch: one generic "writer version" setting per pathnone, or small PR
5. MonitorReview-mode hold, nightly evals, bench historyDaily judged sample of live sends per path, alert when holds or judged-worse pass the old writer's ratemedium, Benchmark lane
6. RetireDark-features rule, prove-or-deleteRender the register (feature, days dark, proof, owner)small PR, docs

Exit bar, written once

Adds to the score bar in section 4; it does not replace it.

CheckBar
Facts vs productionNo fact production gave that the new writer drops
HoldsHold rate not above production's on the same set
Fede's gradesParity or better on every graded card, none worse
Size of the set (proposed)At least 60 episodes on a low-volume path, 200 on a high-volume one (today: 72 and 133 first emails, 261 repair episodes)
StabilityThe exact frozen writer, 3 runs in the same hour, all pass
SpanishSpanish slice present and judged in Spanish
End to endOne Willows run from inbound to outcome, with record ids

Worked example: the first email to a prospect

StageThis week, with existing pieces
RegisterPath "first email to a prospect"; today's writer on Sonnet 5 vs the four-piece split on Opus 5.5; 66 same-hour pairs, 12 of them in Spanish.
BenchReplay door full mode (both door PRs merged), run by /clara-bench. Run 4: skipped lookups 17 to 3, dropped answers 11 to 2, dashes 56 to 0.
GradeGraded cards #25 and #30 better, #26 and #27 same. Not passed yet: one draft read as a note about the prospect; frozen writer not yet run 3 times.
ReleaseWillows email from inquiry to booked tour with record ids, then one PR, merged, live (or one company first, per D8).
MonitorUntil the daily judged sample exists: review-mode hold plus a bench rerun on that week's real cards.
RetireOld first-email prompt deleted the same week; the split becomes the new arm 1.

The next model release is a rerun: the migration pass, then one new arm on the same replay set, judge, review set and exit bar, read on the verdict screen. If it passes, it walks stages 4 to 6 like any other change.

Sources: Clara lane page sections 0, 0c, 6, 12; testing playbook; always shipping (dark-features rule); feature flag audit. Folded in from the retired page "Clara changes: how we benchmark and release, with what we already have".

7. The verdict screen

Run 2026-11-02 · writer · Sonnet 5 (baseline, today's prompt) vs Sonnet 5.5 low · set v1 · bar: within 5 pts, 0 never-do Status: COMPLETE in 3 h 12 m · 900 items × 2 · A/A spread ±2.1 · judge agreement 87% on 100 labels CLARA SCORE96.1% ± 1.4baseline 96.8% ± 1.3 · gap −0.7, inside noise NEVER-DO0 of 925under 0.3% · 20/20 planted defects caught COST / 1K REPLIES$9.40baseline $11.20 · list price, today's prompt LATENCY p50 / p954.0 s / 9 sbaseline 7.1 s / 15 s Recommendation: ADOPT · passes the bar on every layer · one-line change in model-tiers.ts, no flag · Fede: adopt / hold Also on this screen: refusal rate (0 vs 0), gate false-hold rate (3.1% vs 3.4%), per-surface scores, the 12 items where the candidate lost, each with both texts side by side. Numbers above are a mock of the layout, not results.
One screen, three outcomes. ADOPT: passes every layer, Fede's one-line go. HOLD: fails a never-do rule or the score gap exceeds the bar. NEEDS PROMPT WORK: passes never-do but loses on quality in a pattern the losing items show (then a prompt run, same model, is the next card). A model switch is a change to live behavior: it ships with no flag and Fede decides adopt (dark-features rule).

8. The Bench app (Fede's ask: "like Gera's CI/CD app")

Every run is a row on a shared site, like the CI/CD and ingest apps Gera built, so a model upgrade and a refactor are read the same way: before and after, on the same set.

ScreenShowsWho sees it
Runs (home)One row per run: date, what changed (model / prompt / refactor PR), set version, tier, status (complete / incomplete / running with its clock), Clara score with error bar, never-do count, verdict, Fede's decisionTeam, read-only link for design partners if we choose
Run detailThe verdict screen above; per-surface and per-layer tables; the losing items with both texts; the planted-defect ledger; cost and latency; judge calibration for this run; the frozen set hashTeam
BaselineThe standing "where Clara is today" card: the latest adopted configuration's scores, per surface, dated. Every run compares to this; it moves only when Fede adoptsTeam
SetSet versions, item counts per surface, regression cases with their PR, refresh historyTeam
TrendClara score and never-do count over time, one line per surface, with the adopt points markedTeam, Sean, Gera

Build shape (not tonight): the runner writes one JSON per run to the training-data bucket; a static site reads the bucket, like the docs site reads artifacts. No database, no login beyond the shared link. The same runner serves refactor PRs: a PR that touches the writer path adds a "bench: smoke" label and the smoke tier posts its row.

9. Decisions for Fede

#QuestionOptionsRecommendation
D1Sample size vs cost(a) 300 per writer surface, 2 passes, A/A on 300: detects a 5-point margin, ~4 h (b) 100 per surface, 1 pass: ~1 h, detects only a 10-point gap (c) 900 per surface: detects 2 points, ~12 h, over budget(a). Fede's own bar is "don't regress", and 5 points is the smallest gap worth acting on; (b) would have called last run's 97.8 vs 99.2 noise either way.
D2 decidedJudge model(a) Fable 5.1 on the subscription, never a candidate (b) keep Sonnet 4.6, the pinned eval judge (c) a 3-judge panel as last time(a). (b) is two generations behind the writers it grades and re-baselines the nightly evals if touched; (c) tripled cost and produced no verdict. Calibrate (a) once on 100 labels; re-calibrate only when the rubric or judge changes. Fede, by phone Oct 23: yes, Fable 5.1 on the subscription is the sole judge, never a candidate.
D3Pairwise or absolute(a) pairwise for quality, pass/fail by code for never-do (b) absolute 1–5 rubric on everything (c) pairwise on everything(a). Pairwise is more accurate for tone and helpfulness; hard rules must be fail-on-any and mostly code, which a pairwise judge cannot express.
D4Who owns the run(a) a standing skill any attended session runs, verdict row posted to the Bench app (b) Gera's team owns it as part of the CI/CD app (c) nightly cron on the smoke tier, full tier on demand(a) now, (c) once the app exists. The run must be startable the hour a model ships; a cron smoke catches silent drift (GitHub runs theirs daily).
D5 decidedHuman labels for calibration(a) 100 items, Fede and Gera 50 each, ~2 h total, once (b) 30 items, Fede only, ~40 min (c) none, trust the judge(a); (b) is the smoke-tier floor. Without labels the percent is the judge's opinion, which is how last run's "99.2%" had no meaning. Fede, by phone Oct 23: only Fede labels, about 50 drafts, not Gera.
D6 decidedShadow mode first (section 0)(a) turn on the local shadow job tonight, drafts to the local review page, Slack channel with reactions from Monday (b) Slack channel from the start (c) wait for the full designFede, by phone Oct 23: hold until he has read the page; when live, drafts go to the property's Slack channel on the existing supervised-mode card, no local page, no new channel. Recommendation was (a); his ruling replaces it.
D7Make "bar and budget before the run" a standing rule(a) one line in the testing playbook rules section, from today (b) leave it on this page only(a). It is the only rule from the retro table that is not written anywhere yet.
D8 Oct 25How does a new writer go live on a path? (6b)(a) No switch: prove on replay and at the Willows, merge, live everywhere, rollback is the safety net (b) A per-company "writer version" setting, one company first, deleted the week the rollout ends(a). Your Sep 30 rule says an improvement to live behavior ships with no switch, and the exit bar already compares against production on real cards.
D9 Oct 25Which gap first? (6b)(a) Exit bar on the Bench page (b) Per-path register row (c) Daily judged sample of live sends(a), then (c). (a) makes every run read pass or fail today; (c) is the only real safety gap after release.
D10 Oct 25Who owns the daily monitor?(a) Benchmark lane (b) A separate monitoring lane(a): it reuses the same judge and rubric, so the bench and the monitor cannot drift apart.

10. Applied on paper: Sonnet 5 vs Sonnet 5.5 vs Opus 5.5 for the writer

What the framework needsSonnet 5 (today)Sonnet 5.5Opus 5.5
Baseline on today's prompt, frozenLive output only (held 6 of 78, 51 edited after writing); never captured as a set——
Same prompt as baselineyesno ran only on the new promptno ran only on the new prompt
Quality / never-do on the new prompt (837 cards)97.8% clean, 18 held, 6 unanswered, 3 inventedrows still "running"; 67-card Phase 1 finished with no numbers published99.2% clean, 7 held, 0 unanswered, 3 invented
Noise floor (A/A)none run; a 1.4-point gap on 837 single-pass items is inside the expected spread
Judge calibration3-judge panel, no human labels, 9 planted defects caught
Latency per turn7.1 s (75 s on today's prompt)4.0 s7.4 s
Cost at list, writer line per month~$298 today; ~$35–65 on the short promptsame price list as Sonnet 5~$65–125 on the short prompt
Request valid on the modelyesyes (staff desk proves it)yes

11. The outbound gates, inspected end to end (text and email)

Fede's ask: look at everything between the first inbound turn and the send, get rid of the prompt rewrites, keep one last gate that asks "are we about to say something stupid, illegal, or leak information". Read-only on main after the Oct 23 merge of #21992, which already deleted four dead rewrite steps.

22
steps between draft and send on a first email
8 of them ask a model to rewrite the reply
4
rewrites that never see the renter's message
draft checks, "name the home", unit count, booking promise
3×
fair-housing judge runs per first email
and since Oct 19 it can block none of them
162 / 381
supervised holds expired unreviewed at 24 h
since Sep 23; 53 of 61 Western Slope resident texts
TODAY: ONE WRITER, EIGHT REWRITERS, THREE SAFETY PASSES, TWO HOLD SURFACES Renter writestext / email / card WriterSonnet 5, sees all In-loop rewrites ×5weekday, tour time, booked claim,work order, unit count, redaction Blind first-email rewrites ×3draft checks, name the home,unit count again; fact trace strips Safety pass ×3loop, prep, send door;fair housing flags only Sendor supervised holds → leasing Slack channel or #alerts holds → #alerts card, no draft, no button (was hello@ until Oct 21) holds → review post, expires 24 h PROPOSED: ONE WRITER THAT FIXES ITS OWN REPLY ONCE, ONE GATE, ONE HOLD SURFACE Renter writes Writer, sees allcode checks name the failed rule;the writer retries once with it The last gate, at the send door, oncecode: counts, rosters, internal ids, personal info, fact traceone calibrated judge: fair housing, allowed to hold Sendunchanged words Holdsupervised post, draft+ reason, approve/reject The gate never rewrites. Pass = send the writer's words. Fail = hold with the draft and the named reason, on the one review surface, with an owner for the 24 h expiry. Gate precision and recall are layer C of the Bench, so every change to it is measured on the same 900 items.
Why it misfires today. Each rewrite is a model that cannot see the renter and may reintroduce what an earlier step removed (the unit-count check runs twice for that reason). The retry "changed another point of the email 65% of the time" on the Oct 22 replay. And the one gate Fede wants kept, fair housing, is advisory only: both production holds it ever made (Sep 3) were false, so on Oct 19 it was set to flag-and-send.
Step after the draftKindSees renter?Changes words?On failProposal
In-loop checks: weekday, unbacked tour time, "booked" claim, work-order claim, unit count, redaction (conversation-manager.ts ~14331–14811)code detects, Sonnet 5 redraftsyesyeshold to leasing channel / #alerts, or stripfold into one writer retry that names the failed rule
Promise backing, availability disclosure (policies)code—strips / rewrites in codenever holdskeep as code, in the gate
Booking-promise regenerate (booking-promise-regenerate.ts:85)Sonnet 5, 1,024 tokensnoyescode fallbackdelete; the code fallback already exists
Hallucination guard: money, tour times, claimed actionscode—replaces with canned hand-off textescalationkeep the check, change the fail: hold with the draft, never canned text
First-email draft checks, 8 kinds (guest-card-engine-turn.ts:708/723)code + blind redraftnoyesheld, #alerts carddelete the redraft; detect and hold
"Name the home" redraft (:753/874)blind redraftnoyeshelddelete
Fact trace (:670/780) and re-checkcode—strips untraced sentencesheldkeep the check, change the fail: hold with the draft
Unit count again (:831)blind redraft then stripnoyesnever holdsdelete; the disclosure policy's code removal covers it
Safety pass at prep and again at the send door (fair-housing judge, policies, hallucination guard)mixed, Haiku 4.5 judgecard words onlyyesheld, #alerts cardkeep one, at the send door, with the fair-housing judge allowed to hold once its false-hold rate is measured
"Check with the team" unbacked ask (prep)code—noheldkeep; becomes "send nothing" under the tenant design in section 12
Supervised hold (bake-gate.ts:489)rule + Haiku topic classifier—noreview post, approve/reject, expires 24 hkeep as the one hold surface for every hold above; owner for expiries

What a held message should be. One surface: the supervised post, with the draft, the named reason and approve/reject, in the property's channel. The mechanism exists (holdEscalationEmail); the gate-held first email just does not call it. The rule that "a blocked draft must never reach anyone" was written for fair-housing holds, which no longer hold. Open: why 53 of 61 Western Slope resident texts expired unreviewed; who owns the expiry.

12. Tenant comms: when Clara wakes up, how she sounds, what she tracks

Fede's frame (Oct 23): every message on a customer's shared AppFolio inbox lands in one of three buckets, and the buckets are the product. Design only: nothing here is built or turned on.

DecisionRecommendationFede decides
W1 How Clara decides to wakeCode pre-layer, then full Clara with an explicit "send nothing" answer recommendedTurn-on, per customer
P1 Voice by audienceOne shared voice plus a few tenant and vendor lines inside each job blockNothing new: follows the prompt-architecture plan
O1 Open itemsGera's existing morning digest, fed by bucket 2, at 24 hours24 hours or 2 days; its own switch or the tenant door's
H1 HandoffA teammate's message stops Clara, as today; shadow tags the cases where she could resumeThe resume rule
C1 When she cannot helpSilence and the digest; ping the named owner only above the urgency barThe bar's additions; N hours
LadderShadow, supervised, held when unsure, mostly autonomousEvery rung, per customer. Shadow: hold until Fede reads this page; drafts to the property's Slack channel (phone, Oct 23)

What tenants get today

Clara wakes on no tenant text on the AppFolio inbox unless the tenant door is on (wake-on-reply.ts:7-13). A tenant who reaches her gets this (main, 7e6bd5ecd3):

AudienceRules bodyVoicePromise and over-share limitsStay-quiet rule
Prospect, applicant, unresolved senderLeasing body with RULE 7.7 (clara-leasing.ts:1656-1680, rendered at :2288)Shared warm "friendly apartment concierge" (clara-personality.ts:178-227)Mandates "I'll check with the team and get back to you", character for character (:1665, :1674)Closer check fails open; a thread's first message is always answered; "ok" and "okay" never count as a closer (closer-skip.ts:46-57, :194-200). A teammate's live text holds the thread for good (auto-reply-hold.ts)
Tenant (resolved resident)Maintenance body plus RULE 7.8 (clara-maintenance.ts:58-79, added at :467)Same shared blockPromise no time; say the work-order number (:65-67); forbids "I'll check and get back to you" (:71); mandates "I'll let the property team know" (:75)Same
Renewal tenantMaintenance plus the renewal block (renewal.ts:105-111)SameStay in scope (:108); on a mismatch, "tell them you'll double-check with the office" (:110), another deferralSame
In-house handyman, unknown vendorProspect leasing body: no vendor workflow, so the unknown-sender fallback loads it (clara-unified.ts:66-77, :127-158)SameProspect pitch and tour rulesSame
Outside vendor on fileIts own vendor lane, before Clara's prompts (inbound-router.ts:609-622)Not reviewed here
StaffStaff desk (staff-desk-persona.ts)Its ownNever a stall like "let me check" (:141)"Speak only when someone asks YOU", with an explicit silent token (:135)
Who (raw transcripts in #transcripts; customer speakers unlabeled there)What they said
Western Slope customer, Oct 21"be very deliberate on the handoff between when Clara does something to when it gets handed off… it's very, um, delineated"
Same call"where we step in, where we don't, and what we need to do when we step in to let Clara know we've stepped in… So she doesn't say something like, awkward after."
Same call"[Clara] might get out ahead of her skis a little bit… this amount of units available"; "we're gonna have someone out there within the next day for you… No, we're not."
Same call"somebody's mad 6 months later that their garbage disposal doesn't work… And they're bringing it up in an eviction hearing."; "if an okay thanks didn't get a reply, it shouldn't trigger it. But if… the tenant says something that ends in a question mark…"
Same call"Probably the only person getting a notification about the response is me"; "3 days ago, and nobody's responded, who should grab it?"
Fede, debrief that evening"anything tenant communications. We really need to fine-tune it before we YOLO it"; "the supervised mode is great"
Same debrief"okay, leasing, we went YOLO"
Same debrief"people, you know, reporting issues there might be pissed… we just review the messages, like, it doesn't have to be instant"
Fede, voice note, Oct 23"with tenants we've got to be very cautious and careful about what we say, what we respond, what we promise, because these are people that could come after us"

The three buckets as the product

Gera's 90-day Western Slope maintenance audit (Oct 21) already sorted texts this way: some needed no reply ("just a simple, okay, thing"), 23 needed a person ("billing, deposits, rent timings"), 36 Clara could handle ("is the plumber coming?") (transcript).

Inbound text tenant, vendor, applicant, prospect Pre-layer: code, no model 0 · gas or CO words → page, always 1 · door or module off → no wake 2 · automated sender, or a bare reply to a mass text or notice → 1 3 · bare ok, thanks or tapback, and the office asked nothing → 1 4 · a teammate spoke last → 2 (theirs) else → full Clara Full Clara sees thread, record, tools may answer “send nothing” then code checks the draft: only a deferral → bucket 2 office replied since → drop 1 · No action nothing sent, nothing tracked, never a ping; one count for the bench 2 · Needs a human nothing sent to the renter tracked from the thread itself on the morning digest after 24 h urgent: ping the named owner (C1) 3 · Clara acts answers or does it from the record: work-order number, balance, booking never “I'll check” or “not on file” steps 2, 3 step 4 send nothing reply step 0 hit: today's page, 911 reply and on-call chain; never held, never silent
One pass per message. Gas and CO words skip the line, as today. Some case types are bucket 2 whatever her confidence: rent disputes, lease changes, legal matters (section 13).

The Oct 22 inbox replay (202 bursts, 7 days, nothing sent) against the buckets. The harness had the wake rule off and showed no earlier thread, so these are upper bounds, not production rates; the 52 and 61 may overlap.

Replay findingCountWhat the buckets doCaveat
Replied when nothing was needed ("ok", thanks, emoji on a notice)52Bucket 1, mostly in code (steps 2, 3)Production today wakes on none of these rows
Stayed quiet correctly46 (31 to tenants)Bucket 1None
Office or AppFolio's own AI also answered within minutes61Bucket 2 when a teammate owns it; re-check before sendCounts AppFolio's AI answering, or the grader judging the office's reply a duplicate; 31 of the 42 judge notes that give a time say within 3 minutes
"I'll check with the team"30 (24 to tenants), average grade 2.79Bucket 2: send nothingNone
"I don't have that on file"19Bucket 2, or 3 once the fact is in the knowledge baseNone
"I've noted that for the property team"29, average 3.76Bucket 2: send nothingPartly the harness: when a forward reaches nobody, this canned line replaces the draft's follow-up promise, or the whole draft if nothing else is left (templates.ts:802; conversation-manager.ts:3030-3060, :15947-15962), and in a dry run every forward reaches nobody
Tour talk33 (19 to tenants), average 1.74Wrong audience, not a bucketThe tour classifier runs on every non-staff text (inbound-router.ts:1440-1477)

Decision W1: how Clara decides to wake up

OptionWhat it checksCost per messageExpected false chime-inWhat it deletes
(a) Another Haiku "reply or not?" classifier, then full ClaraThe message and a few thread rows; not the record, tools or knowledge~$0.001-0.002 per Haiku call (classify-spam-ai.ts:11), plus a full turn when it says replyWiggins: an LLM priority classifier at about 82% accuracy, recall .55, so about 18 in 100 sorted wrong. Ours: not measuredNothing; one more Haiku layer beside the tour, topic and renewal classifiers
(b) Always wake full Clara; she decidesEverything, on every message, including an emoji on a noticeA full turn every time: ~41-46k prompt tokens for a tenant text today, ~7.4k on the short prompt being built for prospects (prompt-architecture page)Replay with no wake rule: 52 needless replies in 202 bursts. AbstentionBench (2025): models over-answer, a prompt helps only somewhat, and reasoning tuning cut abstention about 24% (section 13)The wake rule, which is what keeps her quiet today
(c) Code pre-layer, then full Clara with an explicit "send nothing" answer, then two code checks on the draft recommendedCode: sender kind, door, who spoke last, bare closers. Clara: the rest, with thread, record and tools; the silent answer has a precedent (VIDEO_SILENT_TOKEN, staff-desk-persona.ts:135). Code again: a draft that is only a deferral; an office reply filed sinceNo model for what code settles; a full turn for the restNot measured; shadow mode measures it against the 2% barThe deferral sentences on this door; two acknowledgement lists become one; the tour classifier on tenant and vendor texts
(d) Option (c) plus a Haiku bucket guess before ClaraAs (c), plus a Haiku guess at the bucket(c) plus ~$0.001-0.002Not measuredAs (c); adds a layer

Kept, not rebuilt: the wake rule's nine no-wake reasons (wake-on-reply.ts:24-33); the staff hold, already read at the send door (auto-reply-hold.ts; dispatch-envelope.ts:464); the automated-sender gate (automated-sender-gate.ts:95-124), its idea extended to texts via the inbox copy's bulk and notice labels.

Are today's Haiku layers a good idea? For a narrow question they can answer, yes: email triage calls automated notices no-reply 33 of 33 times at Western Slope (automated-sender-gate.ts:14-16). For "should Clara speak", no: Haiku cannot see the work order, the balance or who spoke last. Keep email triage, limit the tour classifier to prospects and applicants (inbound-router.ts:1440-1445), add none.

Decision P1: does Clara's personality change by audience?

OptionWhat it meansForAgainst
(a) One voice, rules differTodayNothing to writeThe tenant replies above; "ahead of her skis"
(b) Shared base voice plus a few audience lines inside each job block, picked where identity resolves (resolve.ts:206) and from capabilities recommendedThe prompt-architecture plan's shape: shared hard rules, a five-line shared voice, one job block per audienceRides a block being built anyway; no second copy to driftNeeds a vendor sender type
(c) Separate prompts per audienceA full prompt eachFull controlThe plan rejected it: it "multiplies copies", and the hard rules drift
Tenant voice lineWhy
Calm and plain: no exclamation runs, no emoji, no jokes"Ha, that emoji got me too" to a notice reply (replay, graded 2)
Say what the record says: the work-order number and what is on itKeeps RULE 7.8's best part (clara-maintenance.ts:65-67)
Never promise a time, a visit or an outcome the record does not show"someone out there within the next day… No, we're not"
Nothing useful to say: send nothing. Never "I'll check", "noted" or "not on file"Fede, Oct 23; the staff desk already bans stalls (staff-desk-persona.ts:141)
No unit counts, prices, vacancy or tour talk33 tour-talk replies, 19 to tenants (replay)
One plain clause for a problem; never "Ugh, that's no fun"; never match an angry tenant's energyToday's shared voice says both (clara-personality.ts:215-216)
Write it as if it will be read at an eviction hearingThe customer's own test
The fair-housing rule for every audience, in the shared hard rulesTenants get none today (prompt-architecture page)

Vendors. The in-house handyman and unknown vendors get prospect rules, as the code's own comment predicts (clara-unified.ts:69-72) and 9 of 9 handyman traces show (prompt-architecture page, bug fix 0). Fix: a vendor sender type beside tenant, prospect and unknown (resolve.ts:206), from the PMS adapter's neutral vendor record, plus a vendor job block.

Decision O1: the open-items layer (name TBD; not the promise ledger)

Concept. A bucket-2 message with no human reply for 24 hours goes on one morning list: a link to the thread, why it needs a person, a suggested next step (section 13). Default off per customer. No nudges to tenants. No urgency tiers in v1 ("first get the mechanism", Fede, Oct 23).

OptionWhat is storedForAgainst
(a) Thread state only recommendedNothing new: an item is "the renter's newest message needs a person and nobody has answered since"Already built by Gera (Oct 22, off everywhere): it counts AppFolio's own AI as an answer and Clara's "let me check" as no answer (unanswered-resident-questions.ts:13-27, :89-118)Misses a promise made only in words, which is fine: the bucket design stops making them
(b) Model-extracted open questionsRows a model writes from the conversationCatches asks without a question markThe promise ledger's shape: a model's guesses become a to-do list
(c) BothBothWidest netTwo sources for one list (Constitution II.3)
Promise ledger (dead)Open items
ReadsClara's words, with a model, looking for promisesThe thread's own state, with code
StoresIts own rowsNothing new
Who reads it"nothing in the product reads its output" (retro)A named person, every morning
Track recordCamellia: fired 36 times, reached a person 10, 8 of those wrongThe customer's own ask, Oct 21
How it endsRebuilt 46 times, deleted Oct 13; 22 files still under src/lib/domain/promises/Removed at a customer if listed threads get no human answer after the digest for 30 days

Decision H1: human ↔ Clara handoff

Clara to human. Bucket 2 is silent: the thread is the record, the digest the reminder, the ping for urgent items (C1). Staff never tell Clara anything; their message on the thread is the signal. That is the customer's "very deliberate… delineated" handoff with zero steps for staff.

Human to Clara. Today one live staff text ends Clara's part in the thread for good: a hold nothing clears (auto-reply-hold.ts:44-65; conversation.ts:2479, "sole writer"), plus the wake rule's own stop (wake-on-reply.ts:85), two mechanisms on one signal (II.3). Letting her answer again when the renter asks something new she can do would cut against Fede's "IF another human replies we stop" (Sep 3) and his Oct 16 ruling of no clock and no come-back (wake-on-reply.ts:13-15). OPEN, Fede. For v1 keep the stop; shadow tags the would-resume cases so the reactions decide.

SituationWho actsTenant seesStaff see
"ok", thanks, an emoji, a reply to a mass text with nothing to doNobodyNothingNothing new
A question the record answers, no teammate on the threadClaraThe answer, once, with the work-order numberClara's reply in the AppFolio thread
A judgment call (billing, deposit, an exception)StaffNothing from ClaraThe message, as today; on the morning list after 24 hours unanswered
Urgent, above the bar, nobody has answeredStaff, pinged at onceOne fixed line from code, only after N hours with no human reply (C1)A direct text or email to the named owner
Gas or CO wordsThe existing pageThe safety reply: get out, call 911Page and on-call chain, as today
A teammate repliedThe teammateNothing more from ClaraNothing changes
After a teammate, the renter asks something new Clara could answerOPEN (today: staff)OPENOPEN
Staff ask Clara to take a threadOut of scope for v1NoneNone

Decision C1: what Clara does when she cannot help (co-worker mode)

OptionWhat happensForAgainst
(A) Acknowledge, find the decision maker, come backClara says she is checking, texts or emails the named owner, relays the answer in the threadHow a person would do it; the relay loop exists (open-matter.ts; tell-staff.ts:31-33, "the one staff-exempt text send")For routine items it is the noise Fede named; routine asks go unanswered: Camellia's team answered 5 of 144, and 14 of 17 Western Slope asks waited 4+ days (retro)
(B) Send nothing; keep it in bucket 2; digestNothing to the tenant; on the morning list after 24 hoursNo noise; the team is on the inboxAn urgent item can wait until morning
(C) Hybrid recommended(B) for routine. Above the bar: ping the owner at once, and one fixed line from code only if no human replied within N hoursSilence for most traffic, speed where it mattersThe bar and N must be set
Above the bar: ping nowNever above the bar
Today's emergency list: gas, fire, smoke, flooding, an active leak, no heat in freezing weather, no water, sewage, a lockout (clara-maintenance.ts:61; tiers in life-safety-tiers.ts). Proposed, Fede's call: a legal notice; money due todayRepairs with no danger, scheduling, parking, billing questions, deposits, renewals, "running late"
Who is pingedDecision makerChannel
Any customerFrom the org record: the property-owner role, else the staff roster for that topic, set from the onboarding routing checklistTheir preferred one: text or email (calling later)
Western Slope, leasingKat, Leasing Manager (her signature in the replay)Not recorded yet
Western Slope, policyJay, who wrote their 26 knowledge answersNot recorded yet
Western Slope, emergenciesWe promised the chain Oct 7 and Oct 19; they asked again Oct 21. Still open. Their words: "get to safety and call 911… and then call me back" (transcript)Not recorded yet

Fede's caveat (the team "may not actually see the message"): both happen. 61 of 202 replay messages also drew an office or AppFolio AI reply, yet the customer said "Probably the only person getting a notification about the response is me". Silence covers the first case, the digest the second, the ping the urgent few. Fede's own test stands: a new hire whose every answer is "let me check" gets fired.

The confidence ladder

Tenant comms climb; they do not jump. Leasing was turned on and watched ("leasing, we went YOLO"); for tenants Fede wants review first, and so does the customer.

Per customer, default off. Each rung is Fede's call, with the Bench numbers on the run card. 1 · Shadow (section 0) nothing sent: the supervised card in the property's Slack channel, no approve button; four reactions: good, bad, should not have replied, wrong bucket 2 · Supervised every draft held (the existing hold) reviewer: Fede or the customer approve sends, reject drops 24 h unreviewed: nothing sent, the item goes on the digest 3 · Held when unsure sends when sure, holds when not unsure: low stated confidence, or two runs disagree on the bucket a band, set on the labels 4 · Mostly autonomous holds only for the outbound gate's named reasons (section 11) TO CLIMB FROM 1 100 labels; should not have replied under 5%; wrong bucket under 10%; 0 invented facts in the Good pile TO CLIMB FROM 2 the Bench bar on supervised decisions: false chime-in 2% or less, missed bucket 2 5% or less, no deferral in any reply TO CLIMB FROM 3 what the band lets through meets the Bench bar on live traffic at one property
One surface: the supervised Slack card (bake-gate.ts:489), with no approve button on rung 1 (section 0). Rung 2 is the customer's ask ("at this stage, I would want a human to review", Western Slope, Oct 14); section 0 skips it. Weak spot: 53 of 61 Western Slope resident texts held since Sep 23 expired unreviewed (section 11), so each rung names its reviewer, and an expired hold sends nothing and goes on the digest.

Benchmark cases: bucket accuracy

PartDesign
Set300 bursts from the inbox copy (Situs 3,236 rows, Western Slope 7,354), each with the thread before it, never after; the 202 replay bursts seed it (section 3)
MixAt least 150 no-reply items (buckets 1 and 2) and 60 bucket-2 items, because zero failures in n only shows a rate under 3/n
LabelsFede and Gera label 100 (shadow reactions count); the calibrated judge labels the rest (section 4)
ScorePrecision and recall per bucket; false chime-ins are the headline
Power300 paired items detect a 5-point gap between two candidates; a 2-point gap takes 600 to 1,500 (section 5)
Judge checkThe replay grader liked short acknowledgements ("noted for the property team" averaged 3.76); the buckets call them noise, so human labels settle it before the judge is trusted
ExamplesReal staff replies show how a teammate reasons; a few go into the prompt as examples, never from the 300 scored items. No fine-tuning
Scored failureWhat countsBar
False chime-inClara answered a bucket 1 or 2 message ("okay, thanks", or after staff already answered)2% or less
Unnecessary acknowledgement"I'll check with the team" or "we're looking into it" on a routine item (section 4)2% or less
Missed bucket 2A needs-a-human message sorted as no action5% or less
Deferral in a bucket-3 reply"I'll check", "noted for the team", "not on file"0
#CaseReal example (replay)ExpectedClara today
1Emoji or "ok" after a noticeSitus, Oct 20: emoji after a water shut-off notice; Clara pitched apartments (graded 2)1Where the tenant door is on, wakes: the rule skips notices when it looks for who spoke last (wake-on-reply.ts:119)
2"ok" after Clara's own messageNot in the replay (no earlier Clara turn). Camellia, Aug 28: four "Thank you"s, then "You will always sound like a bot" (closer-skip.ts:4-8)1, if her message asked nothingReplies: "ok" is never a closer (closer-skip.ts:194-196)
3Staff already answered, or answer while she draftsWestern Slope, Oct 17: trash question, Kat 3 minutes later (graded 1). Situs, Oct 22: vendor thanks after staff, Clara quiet (graded 5)2, the teammate'sStops only if the staff text is filed before her send
4Urgent wordsSitus, Oct 20: no water, no staff reply in the copy (graded 4). Western Slope, Oct 17: gas smell follow-up got "I'll check with the team" plus unsafe invented advice (graded 1)Gas: the page. Others above the bar: C1Gas and CO page on texts that reach the dispatcher; "no water" is not in the lexicon (life-safety-classify.ts:29-43)
5Vendor "Ok" or completion noteSitus, Oct 15: vendor "Ok" got a prospect greeting (graded 1)1Prospect rules: no vendor type
6Balance question the record answersNot measured: the replay's 6 rent rows were a portal glitch, NSF disputes and rent assistance (bucket 2)3, from the balance tool (get_tenant_balance, resident-services.ts:71)Not measured
7Running lateWestern Slope, Oct 16: "closer to 20 minutes" was a meetup with Kat; Clara invented a tour (graded 1)2, or 3 if the tour is on Clara's calendarTour talk
8Reply to a mass textSitus, Oct 20: answers to the parking-registration blast; Clara asked what it was about (graded 3)1: the blast's sender owns the replies; 2 if it asks somethingWhere the door is on, wakes, as in case 1

Challenges, answered or open

ChallengeAnswerStatus
Code will miss sarcasm or an emergency hidden in an "ok".The pre-layer drops a bare closer only when the office asked nothing; anything longer goes to full Clara. Gas and CO words are checked before any bucket.answered
A silent bucket 2 hides a gas smell at 11 pm.Today the gas and CO check reads one message in the inbound dispatcher (life-safety-classify.ts:4-8; inbound-dispatcher.ts:465-482), and an inbox row reaches the dispatcher only when it wakes Clara (pms-mirror-reply-wake.ts:1-10; our reading of the code). At turn-on it runs on every inbox row, with the thread; lockout, flooding and no heat still need the model's tier.OPEN who widens the lexicon (Gera's lane)
Per-audience voice multiplies prompts.It is a few lines inside a job block the prompt-architecture plan already has. Hard rules and the base voice stay shared.answered
Staff will not read a digest.It goes to the item's owner and comes out where listed threads get no human answer for 30 days. Team reminder emails were retired Sep 29; this digest is the one approved exception (run-resident-questions-digest.ts:4-7).answered
AppFolio's own AI answers in the same minute (Situs).The wake rule already treats it as a person (wake-on-reply.ts:98-106). The send-door check must too: today the staff hold is stamped only for staff and shared logins (file-message.ts:431).answered part of the re-check
Staff answer from personal phones, outside AppFolio.At Situs roughly half of tenant communication runs on two employees' personal cells (Situs onboarding atlas). Those answers are invisible, so "unanswered" can only mean unanswered in AppFolio.OPEN how the digest says so (Fede)
Staff answer 1 to 3 minutes after Clara sends.A re-check only sees what is already filed, and 31 of 42 timed judge notes say the office answered within 3 minutes. The buckets remove most of these by keeping Clara out of what staff own; a send delay would be a clock.OPEN send delay or not (Fede)
Supervised holds expire unread.An expired draft sends nothing and its item goes on the digest. One clock, 24 hours, not two.OPEN who reviews each customer's holds and owns expiries (Fede)
Haiku is cheaper.At about 30 messages a day the gap is small, and Haiku cannot see the record. Option (d) comes back if volume grows or shadow puts full Clara over the bar.answered
Clara should come back after a teammate.That re-opens threads against two dated rulings (Sep 3, Oct 16). Shadow tags the cases, so the call is made on data.OPEN Fede

What this deletes or folds

Constitution II.2. Changes apply to the shared inbox only; Clara's own line keeps its deferral sentences until that lane decides. Fixes ship with no switch; Clara on the tenant inbox is a new capability, default off per customer, Fede's turn-on.

WhatTodayProposalNeeded for shadow this weekend?
"I'll check with the team and get back to you", mandatedclara-leasing.ts:1665, :1674Shared inbox: send nothingyes the shadow prompt says "send nothing"
"I'll let the property team know", mandatedclara-maintenance.ts:75Sameyes
Canned "I've noted that for the property team." when a forward reaches nobodytemplates.ts:802; conversation-manager.ts:3030-3060, :15947-15962Shared inbox: send nothingyes every dry-run forward reaches nobody, so shadow would show the template, not Clara
Two acknowledgement lists that disagree on "ok"closer-skip.ts:194-200; unanswered-resident-questions.ts:163-164One predicate (closesTheThread, :167-172) plus "the office asked nothing"; each door sets its default: reply on Clara's own line, silence on the shared inboxyes in the pre-layer
Waking on a reply to a mass text or noticewake-on-reply.ts:119A bare reply to one is bucket 1yes
One warm voice for tenantsclara-personality.ts:178-227Tenant lines in the job blockyes about eight prompt lines; without them the Bad taps re-prove the known tone problem instead of testing the fix
farewell-loop: "the breaker never fires"closer-skip.ts:10-18Deletelater
"pass it to the team" in the shared voiceclara-personality.ts:209Out of the tenant lineslater
Gas page only on texts that wake Clarainbound-dispatcher.ts:469-482Run the check on every inbox rowlater it sends; shadow only tags it
Tour classifier on tenant and vendor textsinbound-router.ts:1440-1477Prospects and applicants onlylater
Vendors on prospect rulesclara-unified.ts:127-158Vendor sender type and job blocklater
Routine team emails from inbox threads: a second "needs a human" signal beside the inbox itself42 of 202 replay bursts would have emailed the teamBucket 2 is the one signallater shadow runs tools dry
Digest only for question marks, after 2 daysunanswered-resident-questions.ts:44, :144-150Add bucket-2 items; 24 hourslater built and off; turn-on is Fede's
Two stop mechanisms on one signalauto-reply-hold.ts; wake-on-reply.ts:85One "who spoke last" fact, read at wake and at sendlater after H1
Promise-ledger leftovers22 files under src/lib/domain/promises/Removal PRlater

Shadow is on hold until Fede has read this page (phone, Oct 23); "yes" means needed for its first run.

Shadow mode needsThis weekend?Why
Pre-layer steps 0 to 4 (step 0 as a tag)yesSettles most of bucket 1 in code; shows how many rows would page
Bucket decision with a "send nothing" answeryesThe thing being tested
Deferral-only check on the draftyesThe phrase list exists (handoff-claim-detector.ts:854-866); without it an "I'll check" draft looks like bucket 3
Office-replied-since check, as a tagyesMeasures the double-reply race on real timing
Shadow variant of the supervised Slack card (no approve button) and four reactionsyesFede's pick by phone, Oct 23 (section 0): one small dark PR after his go
"Would resume" tag after a teammateyesThe only way to settle H1 with data; one tag per draft
Morning digestlaterBuilt and off; turn-on is Fede's
Decision-maker pinglaterAn outbound
Ladder above shadowlaterEach rung is Fede's call
Vendor sender typelaterSection 0's picker gets a "the renter wrote this" check instead: 2 of its 10 picks were a vendor and a staff text

13. What others have already learned

Fede's ask (Oct 23): "there must be guidance, proven patterns out there… source beyond the big players." Seven research lanes ran in parallel on Haiku, about 130 pages, primary sources preferred. Honest coverage note: many pages were blocked (G2, Capterra, Reddit, Salesforce, several vendor docs), most vendor pages are marketing, and the field documents escalation far more than silence. Rows marked "snippet" come from search results, not a page we read. Raw citations with their verification level are saved beside the brief in sources-ai-employee-patterns.md.

PatternWho does itEvidenceWhere it lands in our design
Launch to staff first, customers later; draft mode, then one intent at a timeIntercom (Fin), Lorikeet, Pylon, Gradient LabsIntercom: "we decided to make our first release agent-facing and not user-facing" (Traynor). Lorikeet: "Going live on everything at once is the most common failure" (blog). Pylon: "asks before it acts" by default (docs). Gradient Labs waited 14 months before release (interview)Confirms section 0 and the ladder in section 12: shadow, then supervised, then one bucket or one customer at a time
Backtest a new agent configuration against past tickets before it touches a live onePylon; Parloa (simulations on every intent, tool call and handoff, A/B of two agent versions); Vapi (evals in CI, a failing eval blocks the build)Pylon, Parloa, VapiSection 3's frozen set and section 5's smoke tier; the regression-case-per-fix rule
Hand off by default when unsure; some ticket types are human-only regardless of confidenceLorikeet, Twig, Replicant, IntercomLorikeet: "if Lorikeet doesn't know how to answer… by default we'll hand it off to a human" (podcast, 26:46). Twig: billing disputes stay with a human even when the model is confident, "the business rule takes precedence" (blog). Intercom: escalation set by rules in advance, not a confidence score (Fin academy)Bucket 2 "needs a human" is a list of case types first (rent disputes, lease changes, legal, emergencies), confidence second. Section 12, W1 and C1
Confidence is banded, not one cutoffTwig (answer above 0.8, tentative 0.5 to 0.8, escalate below), Lorikeet (model self-rates, separate checks on each draft)Twig; Lorikeet podcast 54:49The "held when unsure" rung needs a band, not a threshold; the labels from section 0 set it
Handoff carries the full history plus a private note with reason and next step; a weekly sample of escalations is reviewed, target 85%+ correctIntercom, Microsoft Copilot Studio, Entrata, Gradient Labs (the customer keeps chatting while a human reviews one step)Intercom, Microsoft, Entrata, Gradient LabsH1 in section 12; the digest entry for a bucket-2 item is thread + reason + suggested next step. "Wrong bucket" taps are our weekly escalation sample
Binary labels from real traces beat scored rubrics; stop reading when you stop learning; keep the label set about half failuresHamel Husain, Anthropic"assigning scores… is more onerous than binary ratings"; labels in batches of 25 to 50 (Husain). Anthropic: "start with 20-50 simple tasks drawn from real failures" (evals guide)The four taps in section 0 are binary good/bad plus the two decision errors; D5's 100 labels and the 30-label floor match the field's 25 to 50 per batch
Judge agreement is measured with kappa, not raw agreement; pairwise is more stable than scores; position bias is realEugene Yan, MT-Bench, OpenAI evals guide"80% agreement but a kappa of only 0.62" (Yan); GPT-4 judge "over 80% agreement, the same level as between humans" (MT-Bench); calibrate to humans before scaling (OpenAI)Section 4: report kappa beside the 85% agreement bar; both-order pairwise stays
Offline scores are a weak signal; the real test is live, A/B, at scale; rare failures need many rerunsIntercom, Lorikeet, Anthropic (pass^k)"Don't fall in love with your offline stuff" (Reid); "run it 100 times and… it still happens 2 of the times" (Lorikeet, 60:34); pass^3 at 75% per trial is 42% (Anthropic)Why Bench ends at a Willows live run and shadow mode uses real traffic; never-do checks run as pass-all-of-k, not once
Reasoning-tuned models abstain lessAbstentionBench (2025)Reasoning fine-tuning cut abstention about 24% on average across 20 models (paper)A higher-effort model may chime in more; "should not have replied" must be scored per candidate in section 4
Residents want to know it is a bot and want a person on request; trust depends on the taskRently survey 2025 (800 US adults), Entrata survey 2019, NYT reporting74% less comfortable when AI is not disclosed; 71% contact a person first when a problem arises; 57% want a human available at any time (Rently). 62% would trust a bot to schedule, 36% to report a violation (Entrata)Never-do list: Clara never claims to be a person; a tenant asking for a person is bucket 2 at once; violations and disputes are human-only
What property managers hate about resident bots: stale facts, scheduling without telling staff, quoting wrong lease terms, residents thinking it is a personOn-site staff on EliseAI (Multifamily Insiders thread), SoftwareFinder reviews"she would give out the wrong info" unless updated; "schedules things for you without telling you"; "was telling people we offered 24 month leases" (thread); "the dashboard clearly flags leads needing team follow up" is the one consistent praise (reviews)Knowledge facts attached to every shadow draft (section 0 finding); bucket-2 flagging is the feature customers praise, so the digest is the product, not a side effect
Public failures: invented policy or price stated as the company's; no path to a human; fair-housing answersAir Canada (tribunal, 2024), Cursor (2025), Chevrolet dealer bot, Klarna's walk-back (2025), Harbor Group leasing bot (voucher holder told no; consent decree), HUD guidance (2024)Tribunal: Air Canada "did not take reasonable care to ensure its chatbot was accurate" (CTV); Harbor Group; HUDLayer B never-do (section 4): no policy, fee, price or term not in the knowledge base; no source-of-income or protected-class answers; the fair-housing check must be able to hold again (section 11)

Where the field disagrees, one line each side: Intercom and Twig escalate on written rules, Lorikeet and Gradient Labs on the model's own confidence plus checks; we take rules first, confidence second, because the labels will tell us where the band sits. Some ship LLM judges in production, Yan and Shankar say human grades are still needed; we calibrate the judge on Fede's taps before any verdict counts. Several vendors run offline simulations, Intercom says only live A/B counts; we do both, in that order.

What this changed on the page: bucket 2 is defined by case type before confidence (W1, C1); kappa is reported beside agreement in section 4; "should not have replied" is scored per candidate model; every shadow draft carries the property's knowledge facts; the never-do list gains "never claim to be a person" and "a request for a person is bucket 2 at once." Nothing we found argues against shadow first or against the four-tap feedback loop; the field's one consistent warning is to never go live on everything at once.

14. What this design session cost

1 h 33 m
wall time
13:07 to 14:41 UTC, Oct 23, one session, one compaction
~21
subagents
11 Opus 5.5 (research, gate inspection, tenant design at max effort, retro pass, prototype), 7 Haiku web researchers, 3 Haiku grep workers
0
PRs, CI runs, sends, model bake-offs
one local prototype branch, 10 drafts on the subscription, nothing pushed
1
page
plus one pointer line in the testing playbook and a sources file beside the brief

Main loop on Fable 5.1; all model calls on the subscription, no metered keys. Compare with the run this page replaces: 42 hours and 146 subagents for no verdict. The design cost about a twenty-fifth of the wall time and a seventh of the subagents, and the next step it proposes (shadow mode) costs about four seconds of model time per ten drafts.

PropFlow Docs