Clara, the new hire

This page shows how Clara works in production today, what we will rebuild and in what order. It then lays out the new-hire lifecycle that rebuild serves, the calls waiting on Fede, and the numbers behind it all.

Proposed, pending review

2026-10-25 · design only: no code, no PRs, nothing sent · ledgers, bench results and reviews live as working notes on the tracker page

A teammate's command is its own path (Nov 4, decided)

Decided, Nov 4 2026 (Fede, evening, session 005): "if a teammate is saying take this action take it" · "regardless of the human hold" · "its not clara autonomous. its a command from a teammate" · "we cant do a quick fix" · 18:06: "regardless of a human is in the thread. If it's supervised that still applies." Owner: 005. All five open sessions confirmed nobody else holds this area (Nov 4, 18:40 MT).

Path 1 · Clara autonomous Her replies, follow-ups, nudges, receipts Governed by, as today: human-replied hold · escalated takeover Off / Preview / Supervised · consent · quiet hours (unchanged by this decision) Path 2 · Teammate command A verified teammate tells Clara to act: text / email a person, send an application, book, move, cancel a tour, add a note Passes the one hold that means "a person is in the thread". Everything else still applies: Off, Preview, Supervised, consent. Only when the teammate is at the company that owns the line and the person
A person acting through Clara. It gets past the "a teammate is in this thread" hold and nothing else.
The design, the readers of the hold, the chain, the proof

What happened. Western Slope prospect Heather Wolff toured Oct 24 and applied. Nov 4, 10:31 AM she texted the office for a second showing so her co-applicant could see the house. Bev answered by hand and emailed Fede to schedule it. Fede texted Clara's Western Slope line: "Text Heather Wolff at Morningside: Kat can show the house any day next week between 2 and 4 PM, which day works best?" The staff desk found her and called the text tool. The outbound door refused it: the thread carries the human-replied hold, stamped Oct 27 when Kat answered Heather by hand from the AppFolio texting inbox (#20993). Nothing ever clears that hold. Clara told Fede "the message was blocked from going out to her." Heather is still waiting.

The signal names who asked. Every staff-desk write carries an origin on the message envelope: teammateCommand: { personId, channel, at }. Not a boolean. One field settles four things at once: the hold bypass at the outbound door; the "operator send with no trigger source" critical log (that is the missing source); the follow-through engine's "a human touched this thread" mark (001's constraint, no PMS literal); and the feed card label ("on Kat's ask", not a stale thread name).

Holds are read, never cleared. The autonomous path keeps autoReplyHold as its signal (cadence stop, follow-through brief, reply-clock silence). The command passes the hold on its own door and leaves the stamp in place.

What opens the path. The model's tool call on a verified staff turn: roles looked up at the company, any staff tier, as the desk does today. Never a phrase or punctuation (Nov 2 ruling). It is the same reasoned "did staff ask Clara to act" decision as the email-thread re-evaluation above, and its cases go in the staff-reaction harness, not a new one.

Shared with the autonomous path, not re-done: tour commands call the tour domain functions and the host rule (002's lane); staff recognition is roles; the sender rule (staff hear from Clara at Propflow, outside people from the customer's mailbox) is untouched.

Reader of the hold todayKindUnder the command
Outbound policy at the chokepoint (text, AppFolio texting door)sendpasses, logged "delivered on a held thread: teammate command"
PMS email lane refusal, bake gate "teammate took the thread" (#16608)sendpasses: both mean a person is in the thread
Supervised hold for approval, Off, Preview (Gera's four modes)modeunchanged. Supervised holds the command for approval like any message. Today's text tool skips that hold on a staff ask (the "staff-asked approval id"); under this ruling that skip comes out, Gera's chain
STOP / consent on file; a test property's fence; a conversation a teammate called "a test" (Gera, Nov 2: draft-only on every line)law / fenceunchanged, refused
Held-text set, AppFolio text-door drain re-checksendthe stored copy carries the origin, so a retry passes too
Cadence yield, follow-through brief, reply-clock silence, inbound escalated gatesignalunchanged; they keep reading the stamp

Chain, cut by proof (fix to live behavior, no switch). PR 1: the origin on the envelope, honored at the chokepoint; the two text tools and the application text leg carry it (the closed #25284 recut). PR 2: every other desk write carries it; the email leg and the bake gate honor it. PR 3: the AppFolio text-door drain honors the stored origin; the feed card and the trigger-source log read it. The command passes the hold only when the teammate works for the company that owns both the line and the person being texted. Each PR ships the same control: the command goes out on a held thread; Clara's own reply on that thread stays held.

Proof. Harness rows → a staff text to the Willows line commanding a text on a held test-prospect thread → the real re-send of Fede's Heather Wolff ask at Western Slope, end to end, with the message id. Text only; no voice minutes.

Decisions for Fede (yes / hold)

  1. Off and Preview: settled, option A (Fede 18:06: "if it's supervised that still applies"; Smith for Gera's chain: both A). Off refuses; Preview drafts and sends nothing; Supervised holds for approval.
  2. The permanent mute (separate from the command path). Today, once a teammate answers a prospect by hand, Clara is muted on that person for good. A: Clara steps back while a teammate is active and resumes when the prospect writes again and nobody on the team answers within a short window (recommended). B: the hold lifts when the teammate tells Clara "take it back". C: keep it permanent.

Out of this chain, named: Bev's original email to Fede is the case the ruling implies should also work by email. Staff email to Clara is not routed to a company today; the one-pipeline design (Nov 3) is the dependency.

Retiring the tour reply helper (Nov 3, decided: A, shipping)

Decided Nov 3 2026: option A, under Fede's "retire this helper" (the standing grant; A keeps what renters get today, an immediate cancel). Fede may override. Fede: "lets look at the history and put this in a test harness - test what happens if we remove it", then "retire this helper".

Four small PRs, no switch. After the first two, the replay shows tour changes better (worse 7 → 4), no tour booked that nobody picked (2 → 0), and every "I need to cancel" cancelled (84 of 84).

The chain and the replay numbers

The chain (no switch; improvement to live behavior)

PRWhatState
#24971Clara's tour tools carry the helper's rules: cancel text to email leads, the team-offered / phone / name checks on a yes, the offered day on a bare timemerged Nov 3
#24979Prompt: cancel at once, offer to rebook in the same reply; "reschedule" with no time takes the tour off; a yes that names no time is not a pickmerged Nov 3
#24997Two gaps the review found (checks skipped on a video switch; the name ask pointed at a field the tool lacks), plus tool-level testsmerged Nov 3
#25005Remove the helper from the router; the open-homes list loads on every tour turn instead; Fairhaven live runmerged Nov 3 23:12Z; live run passed (below)
#25029Fix found by the live run: the offered-day pin moved two Thursday bookings to Friday (it took the day from a Friday calendar read, not from Clara's sentence)merged Nov 4 00:38Z; live re-check passed; no customer tour was affected

Replay after the first two PRs (helper off, same real cases)

CasesBefore the chain: same / better / worseAfter: same / better / worse
Helper changed a tour (29)16 / 6 / 714 / 11 / 4
Helper only added advice (69)43 / 12 / 1342 / 11 / 15 (reply wording)
Clara booked a time nobody picked, or an extra tour20
The 5 JP&Co "I need to cancel" cases + 2 more, 12 runs eachtour left oncancelled, 84 of 84
"I added it to my calendar" after two offered times (Amy)booked 10 AM, 8 of 12asked which time, 12 of 12

The 4 still worse: one already worse before the chain; one asks for a phone under today's phone-first rule (the judge graded by the old date); one asks for a phone because the rebuilt prompt borrowed another lead's "no phone on file" line (books 3 of 6 runs). Reply-only gaps go to #24945. Planted mistakes: 4 of 4 caught on every run.

Live run at Fairhaven after the removal (Nov 3, 23:41Z)

StepResult
Book three homes3 tours, each carries its home (before: tours booked with no home)
"Cancel two, keep one"exactly two cancelled; no rebook offer (#25030)
"Sounds good" after two offered timesasked which time, booked nothing; booked once a time was named
"Friday at 3 instead?"same tour moved, no duplicate
"I need to cancel"cancelled at once, rebook offered

The old helper never ran (0 log lines). One defect: two Thursday tours first written on Friday, then corrected by Clara; fixed in #25029. Record ids are on #25005.

Diagram, results, options and plan

What the helper is: a step that runs before Clara reads a renter's reply. It confirms, cancels or moves a tour on its own, then tells Clara what it did. On Nov 3 it cancelled the one tour of three the renter wanted to keep. The goal is that Clara alone acts on tours, through her tour tools.

Renter replies Helper acts first (today) Clara writes, tools stripped After: Clara reads the reply and uses her tour tools herself

How it was tested

Every real renter message the helper acted on, at every customer, replayed twice on Opus 5.5: once as production ran it (helper on), once with the helper removed (helper off). A judge compared the two calendars and replies. Four planted mistakes were all caught. Nothing was written to production.

CasesSameBetter without itWorse without it
Helper changed a tour (30)1668
Helper only added advice (68)4312 (2 change the calendar)13 (3 change the calendar)

Where it is better and worse

Renter saidHelper onHelper off
Cancel two of my three tours, keep one (the Nov 3 case)Cancelled the one she keptRight: cancelled the two, moved the kept one to her new time
Picked a time; or answered on a stacked dayBooked a time she never picked, or added an extra tour (2 cases)Right: asked which one
"I need to cancel" (one tour; 5 cases, JP&Co)CancelledWrong: offered a new time, tour left on
"Reschedule" with no new timeTook the tour off and asked for a timeWrong: kept it
Picked a time, no phone on fileAsked for the phoneWrong: booked anyway (1 case)

Why the cancels go wrong: Clara's prompt says to offer a reschedule before cancelling, unless the renter insists. The helper never followed that line; it cancelled at once. Also lost by removing the helper: the text that goes to an email lead when a tour is cancelled (Fede, Oct 22). Clara's cancel tool sends no text.

Decision for Fede: what should "I need to cancel" do?

  1. A. Cancel at once and offer to rebook in the same reply. The prompt line changes. "Reschedule" with no time takes the tour off and asks for one. The cancel tool sends the cancel text. Then the helper goes. This is how renters are treated today. Recommended.
  2. B. Offer a reschedule first, cancel only when they insist. The prompt stays. The five cancel cases become intended behavior. The helper goes.
  3. C. Keep the helper for one-tour cancels only. Clara handles every other case. Two writers stay.

After the call: the retirement plan (2 to 4 PRs, no switch)

PRWhat
1Carry over what only the helper does: the available-homes list, the offered-times stamp, the cancel text, the phone check when moving a proposed tour
2Prompt line per the decision, proven on this replay (every protected case at least as good)
3Remove the helper and its tool stripping; live rung at Fairhaven

Replay code and ids-only results: evals/replay-harness/tour-journey/helper-off/ and results/before-2026-11-03-tour-helper-off.md on branch fede/amy-reid-tour-harness (pushed, no PR). Listed on the harness atlas, Tour journey row.

Re-evaluation: when Clara speaks on a staff thread (Nov 2, decided)

Decided, Nov 2 2026: Option A. Fede: "yes, this should always be our default." Building as a fix, no switch; the stay-quiet PR #24533 is closed after the inspection below; A ships as its own small chain.

Fede's premise: "we should be reasoning on whether they asked us a question or not, not having hardcoded characters." Every punctuation, name-position or regex rule on this path is debt and goes.

Diagram, cases, options and recommendation
Staff replies to aClara notice (reply-all) Lands on the thread(fixed, live today) Speak decision today:greeting + name + "?" regex Clara answers Clara stays quiet
Threading is no longer the problem. The last box is: it reads characters, not meaning.

Threading, as live today (006): a staff reply to any notice Clara sent lands on the conversation the notice came from, from any company staff member, reply-all included; from fix three, the same for every one-address staff email she sends. The one reader then sorts it: an answer is relayed to the renter (held under Supervised), "handled" closes the notice silently, a question or note runs her coworker turn there with Cc kept, unclear is held. None of the three options touches that; they only decide whether the question-or-note branch may speak.

Today's Situs casesWhat happenedShould be
Eileen: "Hi Deiby, How did this go?"Clara answered in a fresh threadQuiet. A question to a colleague.
"Team, This is a good example of someone messing with the ai agent…"Clara replied "Noted…"Quiet. A remark about her, not to her.
"Yeah this is PropFlow testing it themselves… Sent via Superhuman <link>"Clara answered; the "?" in the tracking link read as a questionQuiet. Staff talking to each other.
"Hi Clara, No, that is not possible." (Oct 31)HandledStill handled: an answer to her.
"Thanks! Can you resend it?"AnsweredStill answered: a request to her.

Options for the one question, "did the team ask Clara something?"

  1. A. The model reads the note and decides. One judgment call: is this addressed to Clara, or does it ask her for something? Yes → she acts or answers. No → she logs it on the thread and does nothing. No acknowledgements, ever ("Noted" is never a reply). All regex removed. Recommended.
  2. B. Addressed-only. Clara speaks only when the mail is to her alone or names her; a question to the group stays quiet even if only she can answer it. Simplest, but drops the real case "what did this caller ask for?" sent to the group.
  3. C. Never speak on notice threads. She only acts (relay an answer, close a notice) and the team talks among themselves. Loses the coworker loop Fede asked for by email.

What each option changes in that branch: A, the reader's question/note verdict gains one more judgment, "is it to Clara?", before the coworker turn; B, the same judgment made from the To line and her name, so a group question with a real ask ("what did this caller want?") goes unanswered; C, the branch is removed and a note or question is only recorded, so the Fairhaven proof case gets no reply unless staff mail her alone.

Inspection (007, read-only, production logs, Nov 2 afternoon): the regex was not even the cause. Main's model reader already labelled the "Team," note and the 18:26Z note as a note; since this morning's change every note starts a reply turn, and Clara's staff-email reply prompts have no way to stay silent (only the video prompt does). Eileen's email took a second door with no "should Clara answer" step at all. The stay-quiet PR added word lists at both doors and would still have answered the 18:26Z note, so it is closed, not merged. New chain (fixes, no switch): 1. a note, or a message for someone else, never starts a reply turn, and the email prompts get a silence outcome. 2. The reader sees To/Cc with roles, Clara's own message and the recent turns, gets a "for someone else" outcome, and is the one decision at both doors. 3. Threads are picked by what the reply answers, not by the sender, with no building required.

Proof before any merge: the overnight replay set (14 real Situs threads) plus today's three misfires and the two controls, the judgment run three times to show it is stable, no sends. Also running: Fede asked for a deep re-inspection of this architecture ("I don't trust it"); 007 owns it, with read access to the replay cases.

Morning decide list, Nov 2 (Situs ways of working)

Two independent studies of Situs's year of email and all guest-card messages (Fable, Opus), a harness of real VA-to-team exchanges, local POCs, and the landscape. Nothing below is on; each row is one yes/hold.

The ten rows
#What the team does todayHow oftenProposalSizeRecommend
1Renter names a time nobody has open; the VA emails the team "anyone available at X? I'll coordinate" and waits (median 3.6 h for a decision reply)31 of 91 time-naming texts; both studies' top email patternClara asks the hosts by email with a deadline and one nudge, books the first yes, tells the renter; falls back to the two nearest slots at the deadline. Harness: 0 of 10 real cases today, 9 of 10 on the branch; cover-for-me 1 of 3 → 3 of 3; hosts asked on their own channel.Feature, 2–3 PRs on the tour move/reassign designyes
2Staff move a tour; the prospect is told "confirmed", never asked. Reassigning a tour to another agent has no command6 of 77 tours moved in 60 days; 39 showings handed between agents this yearPropose-and-confirm + reassign; POC 23 of 23 cases on the branch (2 of 23 today), 0 sends4 PRs (state, ask+answers, timers, reassign)yes; plus 2 sub-asks: email reminder for email-only prospects (yes), still ask when the renter asked to move but the agent picked the time (yes)
3Clara and the VA desk answer the same prospect texts; the VA wins the racestaff first 36 of 47, Clara 1, nobody 10Decide who goes first at Situs; Clara claims the card visibly after her messageDecision + 1 PRClara first on new leads, staff keep threads they already own Fede, Nov 2: expected, we just launched. No action.
4Team email copied to leasing@ never reaches Clara or the renter's thread72 skipped in 8 days; 234 this yearLog teammates' replies on the thread (1 PR); the group-thread rule (speak / act / stay quiet) scores 6 of 14 real threads today, 14 of 14 as a decision rule, not wired yet (3 PRs)1 PR + designyes to the log; design for the rest
5Clara's notes go to leasing@ with no named owner; the VA names a personVA 95 of 105; Clara 0 of 20Address the host or the card owner by name, shared inbox in copy1 PRyes
6"I'm here" texts from the curb68 of 884 cardsClara stops saying "they'll be ready for you"; she names the host she told, repeats the property's meeting spot, and after an unconfirmed showing warns the agent may not be there and offers another time. Harness: 0 of 3 real cases today, 3 of 3 on the branch; planted defect red.1 PR (~100 lines), fix, no switchyes Fede, Nov 2: the host notification already exists (tour-day update email + host text). This row is only the renter-facing wording; fold it into row 7, not a PR of its own.
7Situs skips unconfirmed showings (they travel); confirm one hour out66 staff cancels, 53 prospect cancelsThe one-hour reminder asks the renter to reply to confirm (Fede's wording). Silent by 30 min out: the host gets one email that they haven't confirmed; the tour stays booked, nothing is cancelled or written to AppFolio. A confirmation sends the host nothing (today's "confirmed" note folds in); a late yes sends "confirmed after all". Row 6's "I'm here" words ride in the same PR. Harness: 9 of 23 today, 22 of 23 on the branch, 11 planted defects caught, 0 sends. Company setting tour.askToConfirm, default off. Design + POC3 PRs (~600 lines): new capability + fixesyes to build; turn on at Situs after a Willows run, with AppFolio's own confirmation text off for Clara's showings; hold auto-cancel Fede, Nov 2: no release or cancel at launch; email the host 30 min out instead.
8Staff email Clara delegations, loop-closers, status pings27 / 14 / 8 in the mailboxShipped tonight: verified staff email gets the desk (#24426), "Got it" back (#24428), after-tour ask by email (#24435). Owed: Willows end-to-end proof Mondaydoneprove Monday
9From the landscape: remember a correction; reply-all etiquette; never resend a follow-up a person already sentn/aFold ideas 1, 2 and 6 into the planned coworker workin existing itemsyes
10Back-office work (resident notices 16%, applications-to-move-in 15%) has no Clara tool~31% of the VA's dayDesign first; new capability, default offdesignhold until 1–7 are live
11Staff and the VA seats book showings by hand in AppFolio; Clara never hears about them, and misses AppFolio-side cancels and confirmations of the showings she booked507 showings Jan–Sep (383 staff, 124 VA seat)A 10-minute read of AppFolio’s showing calendar makes each one a Clara tour: intro, host note, reminders, after-tour asks, moves and cancels both ways. POC: main 3 of 19, branch 19 of 19, 8 of 8 planted bugs, 0 sends. Design4 PRs: a fix for her own showings (no switch) + the import (new capability, default off)yes; turn on at Situs with AppFolio’s renter showing messages off the same day

Curb-arrival and confirm-or-cancel POC: branch fede/poc-va-arrival-confirm (local only), 0 sends in every run; Clara's actual replies were not run, only what she is handed; today's "confirmed" note to the host is text-only, so Situs hosts (no phones on file) never get it; nothing was sent to anyone. Design and results: tour confirm-or-cancel.

00 · Where it stands

Root cause, Nov 3: Clara lost the reply to her own check-in

Proposed — pending review · read-only: nothing sent, nothing changed · built from production records, code on main, and the PR and session history (sources at the end)

What happened. Clara started both conversations. On Nov 2 she emailed Deiby, a Situs leasing agent with no phone on file: "How was the 3:00 PM tour with Stephany M. at Lampliter?" She sent the same about Patricia R.'s tour at Barcelona Apartments. On Nov 3 Deiby answered each email: a no-show, please follow up to reschedule. Both times Clara opened a new conversation under the wrong building and asked Deiby which of the two tours she meant. Both questions were blocked, so Deiby got nothing, and nobody has followed up with either prospect since. Miriam's reply to another check-in, at 3:22 PM, was filed and blocked the same way. Fede: "which one is concerning since we're the ones initiating the conversation".

Deiby's reply named the tour in its subject line. The reply step is built to match such a reply to its check-in by the email's headers, and for check-ins it drops that match on purpose. Four more links then broke in a row. Had the match been kept and used, both replies could have gone to Deiby's own thread at the tour's building, where sending was on, with Clara's question in view.

BEFORE  Nov 3, 4:53 PM MT. Deiby answers Clara's email "Stephany M.'s 3:00 PM tour at Lampliter":
        "She actually ended up not showing up. Can you check in with her to reschedule please?"

 1 Reply step       built to match the reply to Clara's check-in by its headers;
                    for a check-in it tells the next step "nothing matched"           MATCH DROPPED
 2 Clara's turn     gets Deiby's new lines only; subject and quoted question cut      "SHE" HAS NO NAME
 3 Filing           the company's first building by id, the no-building fallback:
                    Situs CFC One, a placeholder marked "not in PropFlow"
                    ──► Deiby's Lampliter thread skipped ──► a NEW conversation       WRONG PLACE
 4 Clara            lists Deiby's open check-ins: Stephany, Patricia
                    ──► "Which one didn't show: Stephany … or Patricia …?"            ASKS ABOUT HER OWN QUESTION
 5 Send gate        team notices are off at Situs CFC One ──► blocked;
                    the inbound-email log says only "suppressed"                      DEIBY GETS NOTHING

AFTER   with the fixes below
   Reply step       keeps the match ──► Deiby's Lampliter thread, Clara's question in view
   Clara's turn     sees the subject and the quoted question
   Clara            records Deiby's note on that tour and follows up with that prospect
   Send gate        Lampliter, sending on ──► the reply reaches Deiby
                    any block is logged with its reason

The five failures in the chain

#What brokeWhat it did on Nov 3Introduced
1The match was thrown away, on purposeThe reply step matches the reply to Clara's check-in by its headers, then reports "nothing matched" so tour notes never reach the prospect. A unit test asserts the drop.Nov 2 (#24435)
2Clara never saw the subject or her own questionShe read only Deiby's new lines ("She actually ended up not showing up…"). Her lookup listed both open check-ins with prospect and building; nothing said which one Deiby answered.Nov 2 (#24426); subject a row label only since Aug 3 (#5333)
3A fallback filed it under a switched-off placeholderFiled under the company's first building by id, the no-building fallback: Situs CFC One, a placeholder marked "not in PropFlow" on Oct 6. On email Clara keeps only threads at that building, so the threads holding her questions were skipped. Every module is off there, so even "which one?" was blocked. At the tour's building both would have sent.Nov 2 (#24426); line-based thread rule text-only (#20110)
4The Nov 2 fix for this class missed this senderThe Nov 2 fixes (Clara remembers her own notices, the reply tag on staff emails) land a reply on its notice's thread. The check-in uses a different sender, which gets no tag and no notice row.Nov 2 (#24489, #24494, #24534)
5No real staff reply was ever run through itThe two PRs that built this path were unit-only; their live proof was "owed". The replays graded "replied or stayed quiet", with sends switched off. The first end-to-end run was Deiby's.Nov 2 (#24426, #24435, #24543, #24565)

Why we keep missing basic functionality

"why does this keep happening on Clara as a coworker" … "do we not have previous context on what was sent? embarrassing"

Fede, Oct 16, on the same symptom by text: Kat wrote "She never showed", and Clara answered three times "I couldn't find that tour — who's this for?"
PatternEvidenceWhat it cost
1. We fix the door a bug came through, not the mechanism"Ask and reply on two threads" has hit four paths, each fixed alone: text check-ins (#14100, Sep 30), staff texts (#20110, Oct 15: "SMS only, on purpose"), plain staff emails (#24534, Nov 2), now the email check-in.It reached a customer the day after the last fix.
2. Each hand-off drops what the last step knewThe reply step drops the matched check-in; the turn drops the subject and the quote. Since Oct 17 Clara's lookup lists her open asks with ids (#20603), never which one a reply answers.Clara asks "which one?" about her own question.
3. A missing building changes behavior"First building by id" was added twice on Nov 2 (#24426, #24494), removed from one door on Nov 3 (#24746), and left on this one as "a separate change". Fede, Nov 2: "this should not matter if there's a property or not in the logic".Clara's only message was blocked without a word.
4. "Tested" stops short of the real pathTests pin the wrong behavior: the drop, and the fallback with the real building finder stubbed out. A replay graded Clara's "I'm missing who 'him' is" to Hugo a pass. The check-in's live proof sat "owed for Monday", blocked by the no-sends rule, while a sibling fix was proven at Fairhaven that day.The first end-to-end run was a Situs agent's real reply.
5. Simplifications and known gaps are never revisitedOct 4 simplification: "one open texted question per leasing agent and no reply matching". Oct 7, a review: "a staff reply can land on the wrong prospect when two asks are open" (#17333); deferred, owner unknown. The same fallback was filed twice on sibling doors (#24496; #24835, ten hours before Deiby's first reply); both open.Deiby had two open asks by email, the case flagged a month earlier; nobody revisited the premise (inference).
6. Speed on one seam, no sweep of siblingsThe email check-in was one PR after five weeks and 22 PRs on the text one, and skipped their thread and which-prospect fixes. The staff email turn changed 5 times and team notices 15+ in two days. Staff-reply work ran in six sessions, each on its own door (inference).Each fix closes its own door; the next sender reopens the hole.

Recommendations, ranked

All are fixes to live behavior: no switch, live everywhere on merge (Sep 30 rule). Each is proven by a real staff email reply at Fairhaven, from a staff test mailbox in the Microsoft tenant, with record ids (testing playbook; Willows is closed since Nov 2). Unit tests are build hygiene, not proof.

#ChangeOwnerSizeProof
1Keep the match. A reply to Clara's check-in runs on that check-in's thread and building, told which tour and prospect. Tour notes still never reach the prospect. Covers check-ins already open.Clara Refactor (001)1 PR, urgentReplay the three Nov 3 replies: right thread, right tour, send allowed. Fairhaven: a staff test mailbox with two open check-ins answers one "no-show"; Clara notes that tour, follows up with that test prospect, and her reply reaches the mailbox.
2No placeholder fallback. A staff email takes the building of the notice it answers; with none, it runs at the company (Nov 2 rule) and Clara works out the building from what she reads. Never a not-in-PropFlow building.Scope resolver1 PRReplay the Nov 3 three and Hugo's Nov 2 reply. Fairhaven: a staff email naming no building gets a delivered answer.
3One reply door for every notice (Fede, Nov 2: "any Clara communication like people should be able to reply to it…"). Register the check-in and the two virtual-tour emails to the host, then the rest. A build check, with a planted control, fails any staff email sender that skips it. A check-in answer becomes tour notes, never a relay.Clara Refactor (001)2 PRsFairhaven: a staff test mailbox answers one notice of each kind; each lands on its own thread.
4Context on every staff turn: the subject, the quoted question, and what the reply's headers matched. The model reads them and decides (Nov 2 rule: reasoning, never patterns).Clara Refactor (001)1 PRReplay, including a forward and a reply with no headers; Fairhaven live.
5Standing fixture set, "staff replies to Clara's own notices", from real records: the Nov 3 three, Hugo, Kat on Alicia J., and Eileen's note to Deiby (right move: silence), plus reply-all, forward and no-building variants. Graded on "right tour, right thread, reply left", never "replied or stayed quiet". Session-run on the subscription for every PR on this path; not in CI.Testing1 local harnessRed on today's main, green after 1 to 4; putting the drop back turns it red.
6Say why a reply was blocked: the inbound-email log names the gate and building, the reply step logs a set-aside match, the app marks an unsent reply "not delivered", and a blocked staff reply raises an alert in the alerts channel. Refusal rows stop saying "local".Clara Refactor (001)1 PRFairhaven: a reply blocked on purpose shows its reason in the log, the app and the alert.
7Sweep the about 271 "no building, do nothing" guards, starting with this path: staff email turn, reply step, notice door, send gate.Scope resolverChain, one concern eachRead-only replay of real records per PR; only the fixed cases change.

Today: recover what Clara should have done (pending Fede's go)

Decisions for Fede

  1. Send today's recovery messages (Patricia, Stephany, Deiby, then Miriam once read)? A. Yes. Recommended: recovering what Clara should have done is ours (Sep 30 rule); only the exact words need your OK. B. Hold.
  2. Keep the email check-in on while fix 1 ships? A. Keep it on; fix 1 ships as urgent. Recommended: Situs agents answered three check-ins today, so the ask works; the reply path is the bug. B. Revert the email check-in until fix 1 is proven at Fairhaven; phoneless hosts get no check-in meanwhile.
  3. One owner for every reply to anything Clara sent? A. Clara Refactor (001) owns it end to end: every door, every sender, the fixture set, and the seven open issues on this path. Recommended. B. One owner per door, as today.
  4. Known gaps on a path that is live at a customer? A. Each follow-up issue gets an owner lane the same day and stays on the nightly sweep until closed. Recommended. B. As today: filed with no owner.
For engineers: code path, the likely reason no building was found, record ids, where the inputs disagreed

Code path on main (e1d7fe14, read Nov 4 00:36Z)

LinkWhereWhat it does
1src/lib/domain/escalation/reply-release.ts:653-663; test __tests__/reply-release-message-id-routing.test.ts:165-189resolveMatterIdForReply matches In-Reply-To / References to the Message-ID stamped on the check-in's matter (minted at integrations/email/client.ts:314, stored by tour-checkin-ask.ts:575-591). For kind === 'tour_checkin' it returns not_a_matter_reply, the same value as "no match"; process-inbound-email.ts (~645) reads that value as "no open matter at all matched". RunStaffEmailTurnInput has no matter field. The step-aside logs nothing, and the one ingestion row checked (318bfa8c, Nov 2) stored no In-Reply-To, so production cannot show the match fired on Nov 3; this link is read from the code and its test.
2agents/clara/lib/email/staff-email-turn.ts:136-140, :222staffEmailTurnBody strips the quote; the subject is used only when the body is empty. Otherwise the subject feeds the building guess and the emailSubject row stamp, "never branched on by the writer" (#5333). thread_context returned both open check-ins with matter, tour and person ids and summaries; nothing says which one the reply answers.
3staff-email-turn.ts:107-128, :191; identity/find-property-in-text.ts; identity/resolve-by-ref.ts:245-283; agent/conversation-manager.ts:5040-5044; modules/building-module-chainThe anchor runs findPropertyInText on the subject and the RAW body (quote and signature included; Clara's turn gets the stripped one). Strict matching hits a building by name or by address; two or more hits return null, then the first company building by id. appfolio-situsgroup-property-101 sorts first of Situs's 53. On email the staff-thread filter keeps only threads at the anchor; the line-based rule is channel === 'sms' only. A building marked not in PropFlow resolves every module off (building_off).
4src/lib/integrations/email/client.ts:1029-1037; escalation/tour-checkin-email.ts; team-notify/inbound-email-reply.ts:186-205The #24534 tag applies only when record.mode === 'none'. The check-in declares outboundRecordOnTarget(...), so no rk_ key and no notice row; the door finds only notices in its store. leasing/tour/tour-room-made-notices.ts and tour-room-waiting-notice.ts (virtual-tour emails to the host) declare their record the same way. The door's "answer" branch relays to the person, so registering check-ins (fix 3) needs the tour-notes rule. The check-in file's header assumes "The subject names the home, so that turn files under the tour's building."
5agents/clara/lib/email/__tests__/staff-email-turn.test.ts:69-87The anchor test uses a substring stub, never the real matcher, always with an empty body, and pins "falls back to the company's first building by id".

Likely reason no single building was found (inference, to confirm)

The subject is built from the building's name, and Situs has one Lampliter, so the subject alone should match. Eight Situs buildings carry the Bannock office address (property-101, 113, 50, 61, 90, 91, 93, 96), and the company's front-door entry is named "Situs Group". If the signature or the quoted header in the raw body carries either, Lampliter plus that hit is a tie, and the fallback picks property-101. The PR history names a second possibility: the turn-home step moved the building. Hugo's Nov 2 reply, also through the staff email turn, was filed at Alton (property-112), so the fallback does not fire on every Situs email. Confirm from the raw stored bodies of ingestions fb23bc1d… and b1e9b65d… and the "staff email routed to the staff turn" log line; fix 2 removes the cause either way.

Records

WhatIds
Staff replies (ingestion log)fb23bc1d… (20:56:47Z, Barcelona); b1e9b65d… (23:53:21Z, Lampliter); Miriam 3c4a6d1e… (22:22:36Z, conversation 4abd32d7…)
New conversationsb46a96f8-786a-4287-9927-37ead4a47e5d, 8cc7c241-4138-4597-b5a6-f4bae62771ef; both filed at property-101, tag source backfill, confidence guessed
Blocked sendsdelivery log edl_78baca75… (20:56:57Z), edl_5fc2ff24… (23:53:33Z); refusals mref_f35106cd…, mref_674339aa… (Miriam, 22:22:46Z), mref_6681c2ca…: team.notices, module_off, env "local"
Clara's check-ins (both still open)matter_tourcheckin_64dfd201… (Lampliter, sent Nov 2 22:45Z, Deiby's thread 7e00314f…); matter_tourcheckin_ff5ef864… (Barcelona, 18:45Z, thread e0663b1f…)
ProspectsStephany pers_605fc468… (conversation e379ef3e…); Patricia pers_cbb66879… (d657e923…, conv_voice_21916806…)
BuildingsLampliter property-8 and Barcelona property-41, sending on (inherited); Situs CFC One property-101, on the company's hidden list, not in PropFlow since Oct 6 (Buildings settings page)

Where the inputs disagreed (the production record wins)

  • Which gate blocked: the PR history could not tell and raised a Supervised hold as possible; the refusal rows say team notices, module_off, at the placeholder building.
  • Why no single building: the code trace suspected a tie between same-company buildings; Situs has one Lampliter. See the inference above.
  • Miriam: a session note (filed as #25035) says Clara's answer to her went out as a new message; for her 3:22 PM check-in reply, mref_674339aa… shows the send blocked. The note may concern another email of hers; not checked.
  • Timing: the PR history puts the email check-in "18 hours before the incident"; it merged Nov 2 06:59Z, 38 hours before Deiby's first reply.
  • What Clara sees on email: the session notes say the Oct 16 "ids of her own check-in" fix was text-only; the Nov 3 records show her lookup listed both open check-ins with ids. What is missing is which one the reply answers.
  • "No-show": Deiby's word; Stephany's texts show a cancellation and a reschedule ask.

Side defects and open issues on this path

  • Production refusal rows are tagged env "local".
  • The reply is saved to the conversation before the send (staff-email-turn.ts:457-462), so the app shows a question that never left.
  • The ingestion row checked on Nov 2 (318bfa8c) stored no In-Reply-To or References (noted, not fixed).
  • Open, no fix yet: #24367 (its proof comment never posted), #24440, #24496, #24688, #24689, #24773, #24835.

Sources: prod-facts, code-trace, pr-mining, session-mining and prior-decisions notes (Nov 3, session 012 scratchpad); code read on main e1d7fe14; the Situs building list (53 rows), the ingestion log, the delivery log and module-refusal rows pulled Nov 3; PR bodies #24426, #24435, #24534, #24746, #20110; PR and issue dates from GitHub; the open issues above. No message was sent. Prospect names appear as Clara's own notices print them.

Staff replies to Clara: one pipeline instead of six doors (Nov 3)

Proposed — pending review · design only; nothing sent or changed · builds on the Nov 3 root cause

Scope: a human on the customer's own team (anyone with a PersonRole at the company) reacting to anything Clara sent them, on any channel. Prospects, renters, vendors are out.

"deep. not individual bug fixes. systematic refactor."

Fede, Nov 3
The answer. One in three staff reactions went wrong since Oct 5; 4 of 5 at Situs after both Nov 2 fixes. It is not one bug: a reaction comes in through one of six doors, and each decides alone what it answers, who wrote, which building and what it means. Each fix closed one door. Proposed: one pipeline for every channel; each old door is deleted in the PR that replaces it.
Went wrong
24/74
staff exchanges since Oct 5 (32%)
Situs, after both fixes
4/5
staff messages wrong, Nov 3
Reply doors
6
each deciding on its own
Duplicated
5·5·3
ways to match, to tell staff, to pick a building
TODAY     six doors; each one matches, decides who, picks a building and reads the words on its own

  email answering a tagged notice ──► 1 notice door      ─┐  5 ways to match the reply
  email answering a check-in      ──► 2 matter door       │  5 ways to decide "is this staff?"
  any other email to Clara        ──► 3 staff email turn  │  3 ways to pick the building
  email to the shared inbox       ──► 4 shared inbox      │  4+ ways to decide "is this for Clara?"
  a text                          ──► 5 text door         │  a refused reply is logged "suppressed",
  a call                          ──► 6 staff phone line ─┘  with no reason

PROPOSED  one pipeline, the same six steps on every channel

  email ─┐
  text  ─┼─► 1 WHO ─────► 2 MATCH ──────► 3 SCOPE ──────► 4 READ ───────► 5 ACT ────────► 6 DELIVER
  call  ─┘   roles, one   what Clara      the company,    one model      on the         from Clara at
             resolver     sent, from one  then the        read; may      matched        Propflow; every
                          register        record's        stay silent    thread         refusal keeps
                                          building                                      its reason

Recommended: option A. Five PRs, three lanes, no switch. Each goes live on merge, after a replay of all 74 exchanges and a real staff reply at Fairhaven.

Decisions for Fede

  1. Which shape? A. One pipeline; each old door deleted as it is replaced. Recommended B. A front door over the six; old code deleted later. C. Keep the six; pass the match along.
  2. Send today's recoveries (Somvang first, part 7)? A. Yes, words as previewed. Recommended B. Hold.
    Recovering is ours (Sep 30 rule); your OK covers the exact words and the two record fixes.
  3. Staff calls? A. Same "who" and "what Clara sent you" now; call actions later, as a new default-off setting you turn on. Recommended B. Build call actions now.
  4. Team notices off: does Clara still answer a teammate who writes to her? A. Yes; the switch stops notices, not answers. Recommended B. No, as today, reason logged.
    Your Sep 13 "dark" rule: whoever reaches Clara gets an answer. Tonight's shared-inbox fix keeps today's refusal; A lifts it in PR 5.
1. Where it breaks: the 74 exchanges, and today's six doors

An exchange is a staff reaction plus its follow-ups, graded by its worst moment. The eight "staff wrote first" exchanges enter the pipeline as "nothing matched".

NoticeChannelCustomerExch.RightWrongWhat went wrong
tour check-intextWestern Slope19163wrong thread, wrong action, silent
tour check-inemailSitus303wrong building (placeholder), all 3 blocked
escalation askemailWestern Slope10100
escalation asktextWestern Slope110
escalation askemailSitus202relayed Lee's note to an applicant; Somvang's answer never relayed
call summary / callbackemailSitus1064argued with Hugo's and Eileen's notes to their team, wrong thread (Hugo's David reply), silent
call summary / callbackemailWestern Slope413wrong thread (2, shared inbox taken for a test prospect), wrong building
emergency alertemailSitus770
emergency alertemailWestern Slope101wrong action (banter saved as a company note)
tour confirmed / updatetextWestern Slope431wrong action
tour confirmedemailSitus110
virtual-tours introemailSitus321answered Eileen's question to Deiby
welcome emailemailSitus110
staff wrote firsttextWestern Slope303wrong action (2), wrong building ("not set up under your access")
staff wrote firstemailWestern Slope101silent (Jason Fish's showing request)
staff wrote firstcallWestern Slope101wrong action (refused a lookup)
staff wrote firstcallSitus101wrong action (Hugo taken for a renter; techs paged)
staff wrote firstcallJP&Co220
Total745024wrong action 7, wrong building 5, wrong thread 4, spoke when quiet was right 4, silent when she should speak 4

Situs breaks on email: replies miss their thread, and Clara talks over staff-to-staff notes. Western Slope breaks on what Clara does next, and its shared inbox is taken for a test prospect.

CLARA SENT                    REPLY DOOR             MATCHES THE REPLY BY       LANDS ON
tagged notice email ────────► 1 NOTICE DOOR          its reply tag ───────────► the notice's thread
check-in or matter email ───► 2 MATTER DOOR          its message id ──────────► the matter's thread
                                                     check-in: match DROPPED ─┐
any other email to Clara ───► 3 STAFF EMAIL TURN ◄────────────────────────────┘
                                                     nothing ─────────────────► a NEW conversation
email to the shared inbox ──► 4 SHARED INBOX         nothing ─────────────────► whoever claims the address
                                                                                (leasing@ = a test prospect)
a text ─────────────────────► 5 TEXT DOOR            one open ask, 24 hours ──► the line's staff thread
a call ─────────────────────► 6 STAFF PHONE LINE     nothing ─────────────────► the call record
some staff email ───────────► none of the six (lead router, "data only") ─────► dropped, no reply

DECIDED AGAIN AT EVERY DOOR
         WHO IS STAFF                     WHICH BUILDING              FOR CLARA? WHAT IS IT?
door 1   role, else the mailbox domain    notice's; files 1st by id   model read; approvals by "?"
door 2   owner, @propflowai.co, role or   matter's                    model read
         domain, current owner
door 3   role                             named, else FIRST BY ID     read skipped if only to Clara
door 4   address claim; role OR domain    the mailbox's               none: handled like a prospect
door 5   the phone's person and role      the line's                  one-open-ask rule; "which tour?"
door 6   the phone's person (Hugo: none)  the line's                  model; lookups only
SEND     every door: the module switch at "its" building; a refusal is logged "suppressed", no reason

TOTAL    5 ways to match · 5 ways to decide "staff" · 3 building pickers · 4+ readers of the words
2. The target pipeline, and what gets deleted
A TEAMMATE REACTS: email, text or call; same steps on every channel
   │
 1 WHO      one resolver: the address decides the company, then the person, then their roles
   │        no role at the company ──► not this pipeline (prospect, renter and vendor paths)
 2 MATCH    the register of everything Clara sent a teammate: reply tag, message id, quoted text,
   │        the line's open asks ──► the notice, matter, tour, prospect and thread it answers,
   │        or the open asks it could answer; never a time window, never a guess
 3 SCOPE    the company, narrowed to the matched record's building, else a building the words name
   │        never a hidden or placeholder building, never "first building by id"
 4 READ     one model read: words, subject, quoted text, To/Cc with roles, thread, the match
   │        ──► answer · handled · question · note · for someone else · unclear
   │        staff talking to staff ──► silent
 5 ACT      Clara's turn on the matched thread, the match in her context:
   │        tour notes, relay to the prospect, close, look up, do what she was asked
 6 DELIVER  teammates hear from Clara at Propflow; one send gate at the scope from step 3
            every refusal stores its reason and scope; failures go to the alerts channel

Steps 1 to 3 are lookups with one right answer (the thin code layer, Oct 25); judgment is step 4.

#PrincipleFede's ruling
1Every Clara message to a teammate registers with the one reply door; a build check with a planted control fails any sender that skips it.Nov 2: "any Clara communication like people should be able to reply to it natural language"
2What the reply answers rides into Clara's turn as context; never dropped, never worked out again.Oct 16: "do we not have previous context on what was sent? embarrassing"; Nov 2: "it's pretty embarrassing to say 'what was this for?'"
3Scope starts at the company and narrows to the matched record's building when known; never a hidden, not-in-Propflow or placeholder building, never first by id.Nov 2: "this should not matter if theres a property or not in the logic"
4Who someone is comes from roles through one resolver (Gera's model); never a mailbox, domain or address shortcut.Nov 2: "always check roles"
5The model reads subject, quoted text, headers, thread and roles, decides what the message is and whether Clara speaks; staff talking to staff gets silence.Nov 2: "we should be reasoning on whether they asked us a question or not, not having hardcoded characters"
6Every refusal to send stores its reason and the scope it was judged at; a failed relay is told apart from one that ran.Oct 25: internal failures go to the alerts channel and the record
7Teammates hear from Clara at Propflow; outside people hear from the customer's mailbox.Nov 3: "It should be from Clara at Propflow for internal team notifications. And it should be leasing outside to prospects, not internally."
8Email, text and calls take the same steps.Oct 26: "channel should not matter"

What gets deleted

  • Five ways of matching a reply, including the check-in drop and the 24-hour rule on texts (Oct 25: "we should not be using time").
  • The texts-only rule that keeps a reply on the thread holding Clara's question.
  • Both "first building by id" pickers, and exits that do nothing without a building.
  • The mailbox, mail-domain, @propflowai.co and owner shortcuts for "is this staff".
  • Extra "for Clara?" deciders: the question-mark rule on approvals, the skipped read on mail to Clara alone, a prompt-only silence rule.
  • Saving a reply before it is sent; one result meaning both "relay ran" and "relay failed".
For engineers: deletions by file, and the no-building exits (main a4eef6ba)
DeletedWhereReplaced byPR
Check-in match droppedsrc/lib/domain/escalation/reply-release.ts:663; pinned by __tests__/reply-release-message-id-routing.test.ts:165-189the match carried into the turn1
Subject used only when the body is empty; quote stripped before the turnagents/clara/lib/email/staff-email-turn.ts:136-140subject and quoted ask in the turn's context1
Staff email turn takes no matchstaff-email-turn.ts:142-152 (RunStaffEmailTurnInput)the door's match1
Tag only when the send declares no record (check-ins get none)src/lib/integrations/email/client.ts:998-1060 (staffNoticeTagFor, record.mode === 'none'); src/lib/domain/escalation/tour-checkin-email.ts:95every staff send writes a notice row (the store from #notice-context)2
One open ask per teammate, 24-hour windowsrc/lib/team-notify/sms-reply-match.ts; sms-ask-gate.ts (SMS_ASK_OPEN_WINDOW_MS)the line's open asks from the register, read in step 42
"The server picks which tour" by person, then "which_tour"agents/clara/lib/agent/tools/staff-leasing-desk.ts:2040-2081 (findOpenTourCheckinsForStaff)the register's match2
Texts-only staff-thread ruleagents/clara/lib/agent/conversation-manager.ts:5041-5046the matched thread, every channel2
First building by id as the anchorstaff-email-turn.ts:107-128company scope, narrowed by the match or the words3
First building by id as the filing key for company-wide holdssrc/lib/team-notify/notice-thread-turn.ts:165 (companyFilingBuilding)holds filed at the company3
Same-mail-domain armagents/clara/lib/email/internal-recipient.ts:45-64; direct uses process-email-record.ts:642, 993, process-inbound-message.ts:1114, 1561, 2082; the Lambda caller lambda/inbound-processor/handler.ts:978 goes in the shared-inbox fix in flight tonightthe resolver's roles4
@propflowai.co, owner snapshot, current owner and building-mailbox checksreply-release.ts:561 (isStaffOnMatterThread) and ~700-745; src/lib/team-notify/inbound-email-reply.ts:93-119the resolver's roles4
"?" and word lists on approval repliessrc/lib/domain/staff-reply/door.ts:132 (reviewerIntent)the one read5
Read skipped when mail is to Clara alonestaff-email-turn.ts:346 (readStaffEmail)the one read, always5
Prompt-only silence ruleagents/clara/lib/agent/staff-desk-persona.ts:125 (STAFF_EMAIL_SILENCE_RULE)the read's silent outcome5
clara_turn returned when the relay failed and when it ransrc/lib/team-notify/ingest.ts ~215-300sent / refused / failed, each with a reason5
Reply saved before the sendstaff-email-turn.ts:457-462saved with its delivery state5

56 "no building, stop" exits found by pattern search (a floor) in the doors' code and Clara's staff tools. My read of each:

ExitWhat it does with no buildingVerdictPR
staff-email-turn.ts:194"not a staff turn"changes behavior3
notice-thread-turn.ts:250, 274reply not sent, hold not filedchanges behavior3
inbound-email-reply.ts:113mailbox check says "not staff"changes behavior4
reply-release.ts:3167relay email not sent, a warning onlychanges behavior (silent drop)5
staff-leasing-desk.ts:2044tour notes: "nothing to attach"changes behavior3
staff-leasing-desk-team-sms.ts:97held drafts not withdrawnchanges behavior3
conversation-manager.ts:7409the turn loads no building or company contextchanges behavior3
conversation-manager.ts:5076staff-thread filter offchanges behavior2
process-envelope.ts:1071, 1115, 1177, 1238, 1296; staff-line-thread.ts:54; open-matter.ts:1636, 2587; sms-recipients.ts:40; sms-sender.ts:33, 36; voice-handoff.ts:146staff holds, threads and team texts need a buildinglikely; checked in PR 33
inbound-dispatcher.ts ×6a line with no building is refusedline routing; check against Gera's address map—
29 others (conversation-manager.ts ×7, process-inbound-email.ts:1611, 1771, handler.ts:599, open-matter.ts:451, process-envelope.ts:219, tour-checkin-ask.ts:403, staff-tool lookups ×16)the record's own building was deleted, or the work is about one buildingfine under the Nov 2 rule—
3. Options
OptionWhat it isWhat it fixesWhat it leaves
A. One new pipeline (recommended)Five PRs; each moves doors onto the pipeline and deletes their old code in the same PR.All six doors, every channel.Nothing old running. Five PRs is the ceiling of the "cut by proof" rule.
B. One front door over the sixA single entry that hands each reply to its old door; old code deleted later.One place to log and test.Five matchers and five "staff" checks still run behind it; the front door becomes door seven.
C. Keep the six; pass the match alongEach door hands what it matched to Clara's turn."Which one?" on matched replies.Everything else; the next new sender reopens the hole.

Why A. The same failure hit four paths, each fixed alone; the fourth reached a customer the day after the third fix. Only deleting each door in the PR that replaces it stops the next sender routing around the fix; "delete later" is the root cause's pattern 5.

Risk. Live behavior changes at three customers; Western Slope's check-in texts (16 of 19 right) could regress when the text door moves. Every PR replays all 74 first and may change only the cases it names.

4. The PR chain: five PRs, three lanes, no switch
#What changesLaneProof: fixtures, then liveDeletes
1Keep the match and carry it (email, urgent). A matched reply runs on the matched record's thread and building, with the notice, matter, tour and prospect it answers, the subject and Clara's quoted question in her context. A check-in answer becomes tour notes on that tour, never a relay.Clara Refactor 001Deiby's two replies, Miriam's check-in reply, Hugo's David reply. Fairhaven: a test mailbox with two open check-ins answers one "no-show"; Clara notes that tour and her reply arrives. Record ids.the check-in drop and the test that pins it; subject and quote stripping; the match-less staff turn
2One register for everything Clara sends a teammate. Every staff send (notices, check-ins, matter emails, virtual-tour host emails, texts) records what it was about; replies on every channel look there first. A build check over the sender audit's inventory, with a planted direct send as its control, fails any sender that skips it.Clara Refactor 001 (inventory from 011)Kat's "She never showed" (three rounds), the other Western Slope check-in text cases, virtual-tour replies. Fairhaven: a test mailbox answers one notice of each kind, each lands on its own thread; one texted check-in answered.tag only when no record; one open ask in 24 hours; tour picked by person; texts-only thread rule
3Scope at the company. The company, narrowed to the matched record's building, else a building the words name; holds filed at the company; the turn loads company context when no building is known.Scope resolverThe Situs check-in replies with the match removed, Hugo's David reply, Kat's "not set up under your access". Fairhaven: a staff email naming no building gets a delivered answer.both first-by-id pickers; six no-building exits; the 12 likely ones once checked
4Who is writing, from roles, every channel. One resolver call: the address decides the company, then the person, then roles; no role means not this pipeline. Calls also get the caller's open asks from PR 2's register. Data: the shared-inbox address comes off the test prospect at Western Slope; Hugo's phone moves to his own person (both on your go).Sender identity (011), on Gera's resolverJay's shared-inbox email (taken for a test prospect), Hugo's test call as a simulated conversation (no call minutes), a same-domain address with no role. Fairhaven: that address is treated as outside; a teammate hears from Clara at Propflow.mail-domain arm (callers left after tonight's shared-inbox fix); @propflowai.co shortcut; owner and current-owner checks; building-mailbox check
5One read, one send record. Every reaction gets the one model read (step 4) and speaks or stays silent. Every refusal stores reason and scope; a blocked or failed reply alerts the alerts channel and shows "not delivered" in the app; refusal rows stop saying "local". With A on decision 4, Team notices off stops notices, not answers.Clara Refactor 001The five quiet cases stay quiet; the four "spoke when quiet was right" go quiet, including Lee's note that leaked to an applicant; Somvang's answer relays. Fairhaven: a staff-to-staff reply-all gets no answer; a reply blocked on purpose shows its reason in the log, the app and the alert.the "?" rule; read skipped when mail is to Clara alone; prompt-only silence rule; two-meaning relay result; save before send

Order. Now: PR 1, the shared-inbox fix in flight, the harness's first run. Then PRs 2, 3 and 4 in parallel (4 after the shared-inbox fix; its call part after 2). PR 5 last. Each: replay green, merge, Fairhaven run with record ids.

No switches: all five fix live behavior. Call actions and Jason Fish's showing notice would be new: outside this chain, default-off setting, your turn-on.

For engineers: files per PR
#Files (main a4eef6ba)
1src/lib/domain/escalation/reply-release.ts, agents/clara/lib/email/process-inbound-email.ts, agents/clara/lib/email/staff-email-turn.ts, Clara Refactor 001's turn-context loader
2src/lib/integrations/email/client.ts, src/lib/domain/escalation/tour-checkin-email.ts, src/lib/domain/leasing/tour/tour-room-made-notices.ts, tour-room-waiting-notice.ts, src/lib/domain/escalation/staff-line-thread.ts (the 13 text sends), src/lib/team-notify/sms-reply-match.ts, sms-ask-gate.ts, agents/clara/lib/agent/tools/staff-leasing-desk.ts, agents/clara/lib/agent/conversation-manager.ts; new build check plus its control under scripts/mutation-controls/, enumerating the 79 staff email and 13 text send sites in 011's inventory
3staff-email-turn.ts, src/lib/team-notify/notice-thread-turn.ts, staff-leasing-desk.ts, staff-leasing-desk-team-sms.ts, conversation-manager.ts, agents/clara/lib/messaging/process-envelope.ts, src/lib/domain/escalation/open-matter.ts, src/lib/team-notify/sms-recipients.ts, sms-sender.ts
4agents/clara/lib/email/internal-recipient.ts, reply-release.ts, src/lib/team-notify/inbound-email-reply.ts, agents/clara/lib/email/process-email-record.ts, process-inbound-message.ts, the call's caller lookup; uses src/lib/integrations/email/team-recipient.ts (the role read the sender fix added)
5src/lib/domain/staff-reply/door.ts, staff-email-turn.ts, agents/clara/lib/agent/staff-desk-persona.ts, src/lib/team-notify/ingest.ts, src/lib/domain/escalation/staff-loop/reply-meaning.ts, the refusal rows
5. Lane overlaps and conflicts
  • Gera's resolver (bridge post to Smith, not a tag) is step 1, as this page's architecture already says ("one resolver for every door"). His mail-domain fallback reads as access for Propflow's own staff, which "no domain shortcut" leaves alone. To confirm.
  • Gera, testers: the @propflowai.co shortcut contradicts "a tester is an ordinary admin inside the real company"; PR 4 deletes it.
  • Gera, access: roles do not gate reads inside a company, yet Kat (company-wide role) was refused "not set up under your access". Cause not traced.
  • Gera, one person per human: Hugo's phone is on a second, role-less person: a data fix.
  • Follow-through (#dropped-ball): its one read is step 4, not a second read; it owns "nobody followed up".
  • Sender audit (011): sender rule shipped Nov 3; PR 2 uses its inventory. Its shared-inbox fix, in flight tonight, refuses a teammate's reply when Team notices is off: today's rule, option B of decision 4. If you pick A, PR 5 lifts that refusal on every door.
  • Clara Refactor 001: the match rides its context loader.
  • Situs external-updates: whether a check-in goes out is theirs (Stephany's cancelled showing still got one).
6. The acceptance test

The fixture set: the 74 exchanges from real records, plus reply-all, a forward, no headers, no building named, and two open asks to one teammate (deferred Oct 7). A case passes only on the right record, thread, action and delivery, or on silence when silence is right; "replied or stayed quiet" never passes.

PRGreen meansPlanted defect that must turn it red
harness red run, Nov 3, main 8a0148fe: 22 pass / 19 fail / 2 skipped (43 fixtures: 13 from real incidents, 5 controls where Clara was right, 25 synthetic). A grader that only checks "replied or stayed quiet" passes 17 of the 19 failures. Failures on main: reply to a check-in lands on a new thread (9), handled at the hidden office building then blocked (6), "which one didn't show?" (3), the expected action never happens (4), an operator note relayed to a renter (1), self-contradiction about the building (1), silence after an owner's instruction (2, expectation pending Fede). Suite: scripts/coworker-harness/staff-reaction-regression/, branch fede/staff-reaction-regression-harness, run on the subscription, wire cut at the socket; calls skipped (voice minutes). Full table: results/before-2026-11-03.md.
1The three Situs check-in replies and Hugo's David reply land on the matched thread, right tour, reply delivered.Put the check-in drop back.
2Every send site in the inventory registers; Kat's three rounds resolve on the first; Western Slope's 16 right check-in texts stay right.A staff send that skips the register: the build check goes red.
3No case is filed under a hidden or placeholder building; no-building cases get a delivered answer at company scope.Put "first building by id" back.
4Shared-inbox and same-domain cases resolve by role; no outside person is taken for staff.Put the mail-domain arm back.
5The five quiet cases and the four staff-to-staff cases stay quiet; Somvang's answer relays; every refusal row has a reason and a scope.Put the "?" rule back; drop the refusal reason.

Standing rule. Every PR replays the whole set on the subscription, never in CI, posts the before/after grid, and may change only the cases it names (the Oct 25 gate, replay harness). Then a real staff reply at Fairhaven, from a corporate test mailbox, proves it with record ids. Calls: simulated; one real call at most.

For engineers: where the harness lives

scripts/coworker-harness/staff-reaction-regression/ (world, wiretap, local DynamoDB), built tonight on its own worktree: no PR, no CI. Input: staff-reaction-corpus.json. Separate from evals/replay-harness/ (day-0 byte diff); both run per PR.

7. Today's recoveries, pending your go
WhoWhat Clara should have doneRecoveryState
Somvang Keomanee, prospect, BarcelonaPass on Miriam's 4:33 PM answer on feesA text with her answer and an offer to book a tourpreview ready
Stephany M., prospect, LampliterFollow up on her cancel-and-reschedule text; Lee's offer is unansweredA text picking up the reschedule, including a late showingpreview ready
Patricia R., prospect, BarcelonaFollow up on a true no-showA text asking her to pick a new timepreview ready
Deiby, SitusAnswer her two check-in repliesShort email: both are being followed up; Stephany cancelled rather than missedintent only
Miriam, SitusPass on her fee answer (her 3:22 PM question was answered by hand at 5:28 PM)Short email once Somvang's text goes: her answer reached himintent only
Jay, Western Slope (Oct 18)Answer whether maintenance still goes to their call center; he got a reply in a test prospect's threadShort email with the current routingintent only; needs the routing fact
Jason Fish, Western Slope (Oct 31)Tell the 239 S Elm tenants about the Nov 2 showing; nothing happened and he got no replyThe showing has passed: tell Jason it was missed. Whether Clara can send that notice is unverified; if not, it is new, not a recoveryintent only
Kat, Western Slope (Oct 14)Save Scott Jacob's number; Clara refused itSave it on his record; no messagethree weeks old; check it is still wanted
Identity recordsWestern Slope's shared-inbox address sits on a test prospect; Hugo's phone on a person with no roleRemove the claim (our test record, in Western Slope's live data); move Hugo's phone (customer data)ready; both need your go

Previews are in the session, not on this page; nothing goes without your OK on the exact words.

Sources: staff-reaction corpus (88 message rows, 74 exchanges, Oct 5 to Nov 3, read-only from production), prod-facts, code-trace, pr-mining, session-mining and prior-decisions notes (Nov 3, session 012 scratchpad); code read on main a4eef6ba0e; the sender audit (011, Nov 3) and its merged fix #25042; the shared-inbox sender fix in flight (plan #25040); Gera's portfolio architecture page (model, wall, people, change); this page's #notice-context, #dropped-ball, #architecture, #core and #replay-harness sections. No message was sent.

Proof of concept result (Nov 4): 22 → 32 of 43, zero regressions; the chain starts

Local POC on branch fede/staff-reply-pipeline-poc, run on the subscription with the wire cut, both model columns complete runs on the same code; the overnight bar (net better, zero regressions) is met, so the fix chain (4 PRs, no switches) is being cut from it; the real Fairhaven staff reply is PR 1's proof.

A local proof of concept of the one-pipeline staff-reply design (who by roles, match from one register, company-first scope, one read, act on the matched thread), run against the 43-case staff-reaction harness on the local test world. One full run per column on the final POC code (branch fede/staff-reply-pipeline-poc, code at 484558bd1c). Nothing was sent; subscription only. Opus column via an env override used only for this run, proven by a control with a non-existent model name (8 not-found errors). The default model is unchanged.

Bottom line: 22 → 32 passing on today's models, 33 on Opus 5.5, zero regressions. The model gap (32 vs 33) is within run-to-run noise.

Totals

RunPASS / FAIL / SKIPMedian sec per fixtureTotal min
main (Nov 3)22 / 19 / 2––
POC, current models32 / 9 / 211.78.1
POC, Opus 5.533 / 8 / 216.711.1

Cost: the runner reports no token counts; seconds per fixture (whole fixture: world seed, notice, reaction, grade, judge) are in the grid. On the subscription there is no metered cost.

Grid: all 43 fixtures, before and after
FixtureBefore (main)POC, current modelsPOC, Opus 5.5sec current / Opus
control-01-recap-to-coworker-cc-claraPASSPASSPASS4 / 6
control-02-thanks-on-introPASSPASSPASS2 / 3
control-03-ive-got-this-onePASSPASSPASS3 / 5
control-04-praise-on-tour-confirmedPASSPASSPASS2 / 3
control-05-text-thanks-after-notePASSPASSPASS14 / 24
seed-01-checkin-noshow-followupFAIL (thread, action, scope, delivery)PASSPASS27 / 27
seed-02-checkin-two-open-asksFAIL (thread, subject, action, scope, delivery)PASSPASS30 / 32
seed-03-checkin-unrelated-questionFAIL (thread, scope, delivery)PASSPASS17 / 23
seed-04-escalation-answer-relayPASSPASSPASS16 / 17
seed-05-call-summary-complaint-office-claimFAIL (delivery)FAIL (delivery)FAIL (delivery)5 / 6
seed-06-call-summary-no-buildingFAIL (delivery)PASSPASS12 / 14
seed-07-text-checkin-never-showedPASSPASSPASS11 / 15
seed-08a-staff-to-team-remarkPASSPASSPASS3 / 4
seed-08b-owner-remark-about-test-callerPASSPASSPASS5 / 12
seed-09-coworker-question-on-clara-threadFAIL (scope)PASSPASS2 / 2
seed-10-owner-test-callSKIPSKIPSKIP0 / 0
seed-11-new-email-notify-tenantsPASSPASSPASS13 / 20
seed-12-text-contact-numberPASSPASSPASS14 / 17
syn-01-checkin-reply-plain-signatureFAIL (thread, action)PASSPASS15 / 26
syn-02-checkin-forwardFAIL (thread, action)FAIL (thread)FAIL (thread)14 / 21
syn-03-checkin-new-email-no-headersFAIL (action, scope, delivery)FAIL (scope)FAIL (scope)15 / 28
syn-04-checkin-reply-platform-staffPASSPASSPASS12 / 17
syn-05-checkin-reply-cc-renterFAIL (action)FAIL (action)FAIL (action)26 / 36
syn-06-checkin-staff-to-staff-cc-claraPASSPASSPASS10 / 12
syn-07-call-summary-reply-instructPASSPASSPASS17 / 21
syn-08-call-summary-forwardFAIL (thread, scope, delivery)FAIL (thread, scope)FAIL (thread, action, scope)20 / 25
syn-09-call-summary-no-building-questionFAIL (action)PASSPASS10 / 17
syn-10-call-summary-reply-platformFAIL (action)FAIL (action)FAIL (action)13 / 16
syn-11-escalation-answer-plainPASSPASSPASS19 / 18
syn-12-escalation-answer-owner-company-sigPASSPASSPASS19 / 35
syn-13-escalation-two-open-asksPASSPASSPASS16 / 19
syn-14-escalation-reply-cc-renterPASSPASSPASS5 / 8
syn-15-tour-confirmed-move-timeFAIL (action)FAIL (action)FAIL (action)9 / 15
syn-16-tour-rescheduled-ackPASSPASSPASS2 / 4
syn-17-tour-cancelled-rebookFAIL (action)PASSPASS11 / 20
syn-18-intro-questionFAIL (thread, action, scope, delivery)FAIL (action)FAIL (action)12 / 14
syn-19-application-invite-already-appliedFAIL (thread, action)FAIL (subject)PASS10 / 13
syn-20-digest-close-outFAIL (thread, action)PASSPASS11 / 20
syn-21-text-ask-renter-questionPASSPASSPASS16 / 20
syn-22-new-email-metricsFAIL (scope, delivery)PASSPASS10 / 14
syn-23-text-new-notePASSPASSPASS10 / 14
syn-24-platform-new-emailPASSPASSPASS3 / 3
syn-25-checkin-call-replySKIPSKIPSKIP0 / 0

What the POC fixes (10, current models)

seed-01, seed-02, seed-03 (check-in replies: run on the check-in's own thread at the tour's building, the tour and prospect carried, no "(by text)" on an email note, sent from clara@); seed-06 (call summary with no building: company scope, Clara texts Dale); seed-09 (coworker question on a company thread: quiet, company scope, never the hidden office); syn-01; syn-09 (no-building call question answered right this run; it flips, see variance); syn-17 (tour-cancelled notice now reaches the desk: rebook follow-up); syn-20 (digest reply finds its notice, Paula noted, Ben left alone); syn-22 (new email naming Birch: scoped to Birch, not the hidden office).

Breaks: none. Every fixture green on main is green on the POC, both models.

PR 1 green targets: 6 of 9 fully green (seed-01/02/03, seed-06, syn-01, syn-20). syn-18 now passes thread, scope and delivery (the PR 1 part: its reply finds the intro notice through the new register) and fails only the judge on wording (it passed in the earlier run). syn-02 and syn-19 stay red, below.

What stays red, and why

FixtureWhy (current models)
syn-02 checkin forwardA forward carries no In-Reply-To/References, so nothing matches; the turn runs at Birch (named in the words) and records the no-show, but on a new thread. Needs a match source for forwards (design delta 3).
syn-19 already appliedClara notes it on Paula's card with Paula's own tour id; the grader only allows tour ids that a notice names, and this notice names none. Likely a grader over-strictness (Opus passes by omitting the tour id). Raise with the harness owner.
seed-05 complaint, office claimThe read says "for someone else" ("Hey guys…", Clara in the third person). The fixture wants Clara to answer. Same on both models: a real judgment question for the design (should Clara answer a question the owner asks the team about her?).
syn-03 new email, no headers"at Birch" is not found by the building-in-text matcher, so it runs company-wide. PR 3's (allowed red).
syn-05 reply cc renterModel quality: with Paula copied, the reply exposes "marked a no-show". Both models.
syn-08 call summary forwardForward, no match (as syn-02); company scope. PR 3's building check (allowed red).
syn-18 intro questionMatched, scoped and delivered right; the judge fails the wording (offers to text the link to prospects, a capability the notice never named). Both models this run; current passed it in the earlier run. Model quality, not routing.
syn-10 platform replySender is a Propflow operator with no role: not staff, so the old notice door runs it, unchanged from main. Out of the POC's "who" step by design.
syn-15 move the tourThe harness world has no readable calendar, so reschedule_tour refuses (calendar_unavailable); Clara then asks staff instead of checking 4pm with Paula. Harness world gap plus model choice.

Opus vs current (this run): Opus also passes syn-19 (it leaves the tour id off the note) and fails nothing current passes: 33 vs 32, about 40% slower per fixture (median 16.7 s vs 11.7 s).

Run-to-run variance

Two full pairs were run (the earlier one before the last scope fix). Rows that changed verdict between them on the same model:

FixtureCurrent: run 1 → run 2Opus: run 1 → run 2Check that flips
syn-01PASS → PASSFAIL → PASSaction (follow-up to Paula started or not)
syn-09FAIL → PASSPASS → PASSaction (judge on the reply wording)
syn-18PASS → FAILFAIL → FAILaction (judge: invented capability)

So the honest read is: current 32 both times, Opus 32 then 33; the model gap is within the noise of one or two judge-graded rows. Routing checks (thread, scope, subject, delivery) did not flip on any row.

Design deltas (what did not survive contact with the code)

  1. Step 4, READ: the existing reader asks the wrong question. src/lib/domain/escalation/staff-loop/reply-meaning.ts classifies by "what should the renter hear" (answer / handled / question / note / unclear / for someone else). On a teammate's reply, "she no-showed, can you mark it", "close out Paula", "call him and explain" read as note or handled, and Clara went silent (POC run 1: 11 of 23 on the red set plus controls). The POC adds its own read, src/lib/domain/staff-reply/pipeline-read.ts: act / relay_to_person / remark / for_someone_else, with what Clara sent, the quote and everyone's roles. That flipped seed-06, syn-20, syn-22 and kept all controls quiet. The design's "one read" needs a new staff-reply taxonomy, not the renter-relay reader.
  2. Step 4: the relays keep their own read. A decision-request answer (src/lib/domain/escalation/reply-release.ts) and a renter-ask answer (src/lib/team-notify/ingest.ts) each read again. The POC enters them from the pipeline with the match made (two reads on those paths). Merging means the relay takes the pipeline's reading as input.
  3. Step 2, MATCH: forwards have no header to match. syn-02, syn-08. Needs the forwarded Message-ID from the body or a token in Clara's own footer; the design says header/SMS only.
  4. Step 2: record-carrying staff sends were never in a register. sendEmail (src/lib/integrations/email/client.ts) only tagged record-less staff sends. The POC tags and registers every single-address staff send whose record names a conversation (staffRecordRegisterTagFor). That is what made syn-18/syn-20 match. Side effect to check: the check-in's Message-ID is now an rk_ id; the matter stores the real one, so the matter match still works.
  5. Step 3, SCOPE: placeholders and "named in words". The company-line building is named after the company, so a signature "names" it. The POC drops a building whose name equals the company's from the words match, and stops narrowing by words once a record matched (syn-18). Production needs a real marker on the company-line building (role: 'company_line_umbrella' is not set in the fixture world). File: src/lib/domain/staff-reply/pipeline-match.ts.
  6. Step 5, ACT on a renter's thread. A call-summary or renter-ask notice lives on the renter's conversation. The POC files the teammate's words there as a team row and runs the desk turn in place (inboundOnThread), the pattern notice-thread-turn.ts already uses, instead of writing the staff words as the renter's inbound.
  7. Step 5: "(by text)" was hardcoded in every desk card-note label (staff-desk-writes.ts, staff-leasing-desk.ts); the POC labels by the channel the teammate used. The tool log still says actor=clara-sms on an email turn.
  8. Not wired: text and phone. Only the email door goes through the pipeline. All 5 text fixtures were green on main and are unchanged.

PR 1 merged and proven live (Nov 4, 12:16Z)

The first slice of the chain, #25097 (a teammate's reply carries its match into the turn), merged at 09:58Z and was in production by 11:59Z. Two review rounds: the org fence was skipped for matter matches, and a notice row registered on the same Message-ID let the notice door take an owner's reply before the matter's own release ran. The door now steps aside for a matter, in one place, on both lanes.

Harness (43 cases)PassFailSkipped (phone)
main before the chain22192
#250973382

Live proof at Fairhaven. A leasing-agent test mailbox replied to Clara's Nov 2 check-in on Tobias W.'s tour ("It went well… wants to apply this week. Please add that to his card."). The reply matched the check-in, stayed on its thread and building, the tour was marked attended with the note queued to the card, the check-in went from waiting on staff to resolved, and Clara's answer reached the mailbox from clara@propflowai.co 58 seconds later. Ids: PR comment. Two cosmetic follow-ups filed: the "Property:" line appears twice (#25137) and the sender name reads "Clara" instead of "Clara at Propflow" (#25138).

Next in the chain: PR 2 (#25120, armed) extends the read; PR 3 forwards, PR 4 the text lane, PR 5 the Message-ID claim across lanes, each opened only once its base is in main.

Baseline for "Clara as a coworker": 2 of 12 golden staff dialogues pass (Nov 4)

Twelve "staff wrote first" dialogues, built from the job map (morning queue, walk-in card plus showing, notes from the car, application chase, no-show then mark inactive, pest notice in two languages, resident ledger, open a work order, owner question, notify two units, driving catch-up, staff email cc'ing Clara) were added to the regression harness and run on main and on the proof-of-concept branch. Both pass 2 of 12. The failures are missing capabilities, not bad judgment:

GapDialogues it blocksWhere
No tool to set a follow-up on a card03staff desk tools
No tool to mark a card inactive05staff desk tools
Work orders blocked on staff turns08staff-write-gate
No application-status read04staff-portfolio
Thread history omits Clara's own earlier free-text answers, so a bare "Yes." points at nothing04, 11thread-context
Resident messaging only as a manager's text; the mass-text handler takes the building from the staff thread06, 10mass-comms, handle-send-mass-message
No owner role; the spam classifier drops the owner's email09 (allowed to fail)types, process-inbound-email
Showing booked at the card's building, not the one staff named02fixed in flight: PR #25150

This is the before-number for the superpowers work in the architecture re-pass above. Full 57-row grid: harness branch fede/staff-reaction-regression-harness, results/gold-2026-11-04.md. One run per side; single-row flips between main and the POC are noise until they repeat.

Group texts with the leasing team (Nov 4) — Proposed, pending review

What happened. Nov 4, 8:57 AM MT: Miriam Gallegos (Situs PM) started a group text with the leasing team and Clara's Situs line: "just want to test if we can have a group text with the leasing team. Any showings scheduled today?" The carrier delivered it to Clara's line as a plain one-to-one MMS (Twilio sid MMd6e95ed17c…, no other recipients exposed). Clara answered Miriam alone, correctly ("no showings today", confirmed by Fede), and told her replies come back on the same thread. Her teammates saw the question but never Clara's answer.

Why it cannot work today. Clara's lines run on Twilio Programmable Messaging: one number, one webhook, one recipient per reply. A group MMS has no "reply all" on that path, and the inbound webhook does not list the other members.

OptionHowWhat the team getsCost / riskVerdict
A. Twilio Conversations group texting on the existing linePut Clara's company line on a Conversations address configuration with autocreation on. An inbound group MMS creates a Conversation with every member as a participant; Clara replies into it and everyone sees the answer. The number's own webhook still fires, so one-to-one traffic keeps its current path; the new handler acts only on group conversations.A real group thread: any teammate can ask, everyone sees Clara's reply. Members identified by roles from their numbers, so Clara knows who is in the room.Only +1 long codes (Situs +1 720 740 4240 and Fairhaven +1 720 807 1724 qualify; toll-free lines do not). 10 participants max. Third-party prod config change on the number (Fede's go). Open mechanics to prove at Fairhaven first: that one-to-one messages do not double-fire once autocreation is on.Recommended
B. Second vendor (Telnyx or Bandwidth) for group threadsGroup MMS with explicit cc list on a new number.Same as A.New vendor, new number per customer, new A2P registration, split messaging stack.No
C. No group thread; Clara broadcastsEach teammate texts Clara directly (works today); Clara posts a morning showings summary to the team's phones.Answers reach everyone, but as separate texts; no shared conversation.None.Fallback while A is proven

Shape of A, if chosen. New capability, so it ships dark behind one company setting ("Clara joins team group texts", default off; Fede turns it on per customer). Three PRs: (1) a Conversations webhook door that recognizes a group conversation and maps its participants to people by their roles at the company (unknown numbers are named "someone on the team", never guessed); (2) the staff desk turn runs on the group as one conversation, with every member's role in context and one reply to all; (3) the per-line Twilio address configuration, written only on Fede's go, Fairhaven first, proven with one real group text from two test phones. Rules that carry: identity by roles, no regex on "did they ask Clara", staff hear from Clara's line (shared with prospects, per the Nov 3 ruling).

Who was in Miriam's group is being read from the team's email signatures (cells listed under each name); result lands here.

Channel inspection: Clara as a coworker today (Nov 3)

Read-only inspection, Opus 5.5, Nov 3 night; vision in Fede's words: Clara knows every teammate on every channel, sees everything they can see in AppFolio, and does what they ask, owners included.

Read-only. Code: origin/main 8e4f4d8227 (Nov 4 03:57 UTC). Data: propflow-prod, read-only. Nothing was sent or written. The vision: Clara knows every teammate on every channel, sees everything we can see, and does what they ask. Roles stay a thin layer for later.

TL;DR

(a) The grid

Verdicts: solid / partial / missing. Paths are under ~/code/PropFlow/propflowai.

ChannelIdentity (who is this?)Reach (what can she look up?)Act (what can she do?)Gates (what can silence her?)
Text to Clara's linesolid. Role at the line's company, looked up by phone (src/lib/domain/staff/inbound-resolution.ts:420-450). A fresh text gets a turn and a reply.partial. 23 company lookups including live AppFolio reports, plus people and thread lookups (agents/clara/lib/agent/capabilities/staff-portfolio.ts). Only for desk roles: maintenance, accounting and viewer get one metrics tool (inbound-resolution.ts:136, capabilities/index.ts:393-396).partial. Book, move, cancel, tour outcome, note, send application, new guest card, lockbox code, contact, text a prospect (capabilities/staff-leasing-desk.ts:34). All but texting reach AppFolio through the neutral PMS layer.partial. The Supervised hold is keyed on the thread's building (process-envelope.ts:583-611). A STOP on a staff phone blocks every reply (src/lib/integrations/twilio/client.ts:1166).
Email to clara@partial. Role by email, but only if the sender passes the strict mail check, Clara is on To/Cc, and the lead router doesn't claim the mail first (agents/clara/lib/email/staff-email-turn.ts:86-100, process-inbound-email.ts:1284-1378). Any miss means silence. The lookup isn't fenced to one company (staff-email-turn.ts:171).partial. Same as text when the mail check passes, otherwise nothing (staff-turn-options.ts:75).partial. Same as text, same mail-check condition.missing. The thread is filed under the company's first building by id (staff-email-turn.ts:117-128), and the send gate checks that building's modules. A "not in PropFlow" placeholder turns them all off: this blocked Deiby and Miriam today (company-live-gate.ts:369, building-module-chain.ts:410).
Email to the shared inbox (leasing@)partial. Recognised only when replying to a team notice or a held message (src/lib/team-notify/inbound-email-reply.ts:212, staff-reply/door.ts:218).closed on purpose for a fresh ask.closed on purpose.by design. Anything else is skipped silently as "coworker mail" (process-inbound-message.ts:1593-1636). Under Fede's Nov 3 ruling, staff mail landing in leasing@ is a symptom of an earlier wrong send, not a channel.
Callpartial. Role at the dialled line's company; any line that resolves to a company hands staff to the Coworker Line (src/app/api/voice/personalization/route.ts:2413). Its tools find the company only through the line's building, so a company-only line likely answers "not staff" (coworker-voice/call-binding.ts:61-65,145; inferred from code, not tested).partial. 12 lookups (agents/clara/lib/voice-agents/coworker.ts:75-87). No vendors, no live AppFolio reports, no knowledge base. Maintenance callers don't hear amounts. Model is Sonnet 4.6 (model-paths.ts:127).missing. Emergency page and a repair pin only; the work order is filed after the call (coworker.ts:151). No tour, card, application or note actions.partial. No switch since Nov 2. A caller's phone on a person with no role reads as a renter (Hugo, Oct 28).
In-app Ask Clarasolid. Signed-in user (src/app/api/dashboard/chat/route.ts:37).solid. The same 23 reads.missing. Read-only.n/a
Slackmissing. Only replies to held drafts (src/app/api/slack/events/route.ts:186). No mention or DM chat.missingmissingn/a

(b) Gaps, furthest from the vision first

  1. Most actions have no tool. Fede's list: "don't send one to X", "follow up with Y tomorrow", stop texting X, work-order create/note/status/assign vendor, renewal actions, vendor detail, contact changes into AppFolio. The robot already runs all of these (run-work-order, wo-action with 20 actions, run-renewal, run-mark-guest-card-inactive, run-guest-card-contact-set, get-vendor-detail). Work orders already go through the neutral writer (src/lib/integrations/appfolio/work-order-writer.ts). Renewal and tenant writes still call AppFolio directly (src/lib/tools/appfolio.ts, src/lib/tools/renewals.ts), so they need adapter work first.
  2. Calls can't act. A leasing agent driving home can't say "move Patricia to Thursday 2pm."
  3. Email to clara@ silently fails on hidden conditions: the strict mail check, Clara on To/Cc, and the lead router claiming it first. On top of that, the reply is gated on the wrong building (Deiby, Miriam). Fresh asks at leasing@ stay closed (Nov 3 ruling); reopening them would be Fede's call.
  4. Answers to staff are gated by the Team notices switch at the filing building and by a STOP record. Under the vision, arguably neither should stop a teammate's answer; Fede's Sep 13 rule says whoever reaches Clara gets an answer. The Supervised hold on staff replies is deliberate (hot rule 10). Whether it should stay is an open question, next to the design's decision 4.
  5. Situs staff can't use text or calls: 7 of 8 have no phone on file, and Hugo's phone sits on a person with no role (pers_ab61f830). This is data, not code.
  6. Maintenance, accounting and viewer roles get no lookups or actions by text or email, against the earlier coworker decision "the same Clara with the same brain everywhere". That affects 3 people today: 1 at Situs, 2 at Western Slope. Staff found only through an old phone or email get no role and no desk at all (agents/clara/lib/messaging/inbound-router.ts:867-906).
  7. Reach differs by channel. Calls lack vendors, live AppFolio reports and the knowledge base. Texts can't see application status: the prompt tells Clara to say she can't check it, though src/lib/domain/pms/application-status.ts exists. A company-wide live report covers at most 5 buildings (src/lib/domain/dashboard/chat/tools.ts:83); Situs has 53. Guest-card, application and owner reports aren't in the report list (tools.ts:94-110).
  8. Owners don't exist as people. There is no owner role in code (src/lib/data/types.ts:19635) or data. The AppFolio owner list is synced read-only (src/lib/integrations/appfolio/pms-adapter.ts:1165). Owners only receive a weekly report by email list. An owner who writes is a stranger.
  9. A voice note with a caption loses its audio. Voice notes texted in are transcribed (ElevenLabs Scribe), but body || audioText keeps only the typed words when both exist (src/app/api/twilio/webhook/route.ts:559).
  10. Model. Staff turns run on Sonnet 5.5 (model-tiers.ts:256), calls on Sonnet 4.6, not Opus.
  11. Latent: a role scoped to one building is not treated as staff on any channel (inbound-resolution.ts:434). It bites nobody today: every customer staff role is company-wide. It is the opposite of the Nov 2 rule.

Evidence from real "staff wrote first" cases:

Dream scenarios: what breaks first today

ScenarioFirst thing that breaks
Leasing agent texts all day. "What did the renter ask?", "tour went great, add a note", "move Patricia to Thu 2pm", "send Stephany the application".Works, with a desk role and a phone on file. It fails for 7 of 8 Situs staff (no phone).
Same agent: "don't send one to X", "follow up with Y tomorrow".No tool. Clara can only send one text now (text_prospect).
PM emails "what's open on work orders at Lampliter?"Works only if the mail check passes and Clara is on To. Naming the building saves the gate; a mail that names no building lands on the placeholder and is blocked. Sent to leasing@, it gets silence.
Owner: "how is leasing going at Barcelona?"Not recognised on any channel: no owner role.
Voice note to Clara's line: "the tour went really well, here's what you should know".Transcribed and run as a staff text. Breaks if typed words come with it (the audio is dropped). It's unproven in production: the database can't tell an audio message from a typed one.

(c) What the one-pipeline design already covers, and what the vision adds

Questions for Fede (yes / hold)

  1. Should Supervised still hold Clara's replies to teammates? Today it does, on purpose. Recommend: no for answers to lookups; yes for actions that reach a prospect.
    Fede, Nov 3 night, earlier in the session: "no I don't want supervised" for staff replies; recorded here, final yes/hold still his.
  2. Should a fresh ask in leasing@ get an answer? Your Nov 3 rule says no: it's a symptom of a wrong send. Recommend: keep it closed.

(d) Work items

Fixes (no switch, live on merge):

  1. One staff toolset on every channel, all roles. Text, email and calls compose the same lookups and the existing writes; the tier filter and building-only call binding are deleted. Proof: a maintenance user's text and a simulated call do a lookup and a tour move at Fairhaven.
  2. A teammate's answer is never gated on the first-by-id filing building, the Team notices switch at that building, or a STOP on a staff phone. Lands as the refactor's PR 3 and PR 5 if Fede picks A on decision 4. Proof: Deiby's two replies replayed, plus one real Fairhaven email naming no building.
  3. Voice note keeps both the words and the audio (route.ts:559). Proof: a captioned voice note to the Willows line, record id.
  4. Data: get the Situs staff phones from Situs (source per the onboarding playbook) and move Hugo's phone onto his person record. Both need Fede's go: it's customer data.

New capabilities (dark behind ONE company setting, "Clara acts for staff"; Fede turns on per customer):

  1. Leasing actions: stop or withhold an application, start or stop follow-up for a prospect, and push contact changes into AppFolio, through the guest-card outbox. 2 PRs.
  2. Work-order and vendor actions (create, note, status, assign vendor, vendor detail) through the neutral work-order writer, on every channel including calls. Renewal actions come after their writes move behind the renewal adapter. Owner recognition (a new owner role and a read-only "how is my building doing") is a separate later item.

The text-desk actions that are live today (book, move, cancel, note, send application, guest card, text a prospect) stay live with no switch. Fede ruled them in on Oct 26; the new setting covers only the new actions.

What the team does by hand: job map from Situs and Western Slope (45 days to Nov 3)

Read-only pull of the AppFolio activity we mirror, plus staff messages and calls; counts are minimums (texts and emails mirrored only since Sept 29 / Oct 2); names anonymised to roles.

This is a read-only pass over production. Nothing was written and nothing was sent. Names are replaced with role labels, and phone numbers would show only the last 4 digits (none are needed here).

How evidence is weighted (per Fede, Nov 3):

  1. What staff did by hand in AppFolio, counted from the copy we keep:
    • work orders
    • guest cards and their notes
    • applications
    • texts and emails staff sent from AppFolio
    • mass notices
  2. Staff messages inside renter and prospect threads, as the voice of each role.
  3. Renter questions that staff answered by hand.
  4. Industry-standard duties for jobs our data does not show yet. Each row is marked data (with a count) or domain (no count yet).

Staff messages to Clara are thin (74 exchanges in 30 days). They appear only in section (c).

Coverage and limits

(a) Roles present and how active they are

CustomerRolePeopleAppFolio texts / emails to renters (about 5 wks)Emails between staffMessages to Clara (30 d)Calls
SitusOwner/admin20 / 75615—
SitusProperty manager196 / 46325—
SitusLeasing agent4 with a role, plus a shared "leasing" login and 1 helper with no role534 / 171 (about 141 a week)11828 office-line calls recorded
SitusMaintenance1, plus a shared "maintenance coordinator" login66 / 040—
W. SlopeOwner/admin26 / 1229—
W. SlopeProperty manager11 / 000—
W. SlopeLeasing agent3, one of whom also uses a shared "assistant PM" login207 / 30 (about 52 a week)234377 calls Clara handed to staff
W. SlopeMaintenance22 / 000—

What the table shows:

(b) Jobs ranked by how often staff did them by hand

How much Clara already carries (before):

Rows 1 to 12 are ordered by count. The cross-cutting job below overlaps rows 2, 4, 6 and 8 to 12, so it is not added to them:

#JobWhoCount, 45 days (per week)ChannelReal example (anonymized)What Clara needsBasis
XAnswer what renters ask (the "answer this for me" job)Everyone who faces renters362 staff messages answered a renter question from the last 3 days: prospects 127, residents 114, applicants 85, vendors 35. Overlaps the rows belowText, emailQ: "Can't see the submit button to pay online" → "Scroll to the bottom and reduce your browser zoom."Read: units, ledger, work-order status, knowledge basedata
#JobWhoCount, 45 days (per week)ChannelReal example (anonymized)What Clara needsBasis
1Open, assign and close work ordersMaintenance coordinator, PM744 opened by hand (S 486, WS 258), about 116 a week; 704 closed; Clara opened only 11AppFolio"Move-out inspection and unit turn"; "Washer turns on but is not draining"Write in AppFolio: create, assign to vendor or in-house crew, close. Read statusdata
2Book, move and run showingsLeasing agents, PM at Situs353 actions (about 70 a week):
• 103 messages scheduling or moving
• 72 on day-of logistics
• 163 AppFolio showing notices (scheduled 43, confirm 67, confirmed 40, moved 6, cancelled 7)
• 15 notes
Text, AppFolio"No worries, I will schedule you for 3:00 PM today." / "[code] is the code for the lockbox on the stairs, message me when you're done."Write the showing in AppFolio and the agent's calendar, send access details, day-of confirm, a reminder to the agentdata
3Keep the guest-card list cleanLeasing agents285 actions:
• 129 guest cards typed in by hand (S 109: TurboTenant, affordable-housing lists, walk-ins, referrals, an agent's own social posts)
• 54 call attempts logged
• 50 cards marked inactive with a reason (WS 43, most often "no response")
• 52 follow-ups to quiet leads
AppFolio, text"I will mark your card as inactive so you stop getting messaged, but reply any time to see a home."Write: create a guest card, log the call, set status and reason. Run the follow-up scheduledata
4Run the application pipelineLeasing agents, shared leasing login280 actions:
• 100 application-link templates
• 36 helping someone apply
• 112 on processing (documents, references, approvals)
• 21 "application received"
• 11 notes
Results: 57 applications, 30 approved, 5 denied, 14 leases signed
Text, email, calls"I haven't heard back from your references yet. If you could give them a heads-up, that would speed up your application."Write: send the link. Reminder: chase missing documents and references. Read: screening status. The approve or deny decision stays humandata
5Send notices to residentsLeasing agents, shared logins118 distinct mass sends reaching 598 threads, plus 83 one-to-one notices. Many in English and SpanishAppFolio mass text"Pest Control Notice: treatment Tuesday 8:00 AM to 3:00 PM. Please remove food, open containers…"Write a mass message by property, building or unit list, in both languagesdata
6Keep residents and vendors posted on maintenanceMaintenance coordinator, leasing at WS119 messages:
• 62 to residents (intake, status, "was it fixed?")
• 57 to vendors (quotes, approvals, turn status, invoices)
Text"Just checking in: did the vendor fix your washer already?" / "We have the go signal, this is approved. When can you do the work?"Read work-order status, a reminder to vendors, write status updates. Invoices: nodata
7Owner and admin back office by emailOwners, PM, shared loginsAbout 100 threads between staff:
• 16 on application decisions
• 18 on vendor bills and laundry quarters
• 15 resident or legal issues
• 8 marketing
• 7 maintenance
• 4 move-outs
• 4 financials
EmailSubjects only: "Rental Application Report for [applicant]", "Outstanding invoices, action required", "Annual property assessment"Read and summarize, draft replies. The decision stays with the ownerdata (subjects only)
8Write notes after a showingLeasing agents62 notes (40 on how the showing went, 22 on the household: voucher, pets, move date), plus 19 answers to Clara's tour check-ins at WSAppFolio note, text"They liked it. She will talk to her daughter tonight. Didn't love that the washer/dryer hookups are upstairs."Take a dictated or texted note and write it to the carddata
9Renewals, move-outs, keys, depositsLeasing agents, PM47 messages (7 calls)Text, calls"How would you like your $1,000 renewal credit applied? Option 1…" / "Do you have a forwarding address for your deposit?"Read lease and ledger. Write the resident's choice. Reminder on move-out stepsdata
10Rent, ledger and payment questionsLeasing agents, PM35 (11 of them calls)Text, calls"Their ACH from 9/18 was not posted to your account; we've notified accounting."Read the ledger. A payment plan stays humandata
11Move-in coordinationLeasing agents, owner at WS28Text"Move-in instructions: lockbox on the front door, 3 keys inside…"Read move-in charges. Send keys and access, send the portal invitedata
12Complaints and disputesPM, leasing25Text"We have documented your complaints about smoking from the unit next door; management will address it."Log it and route it to the PM. The PM decidesdata
13Collections and late noticesPM———Read delinquency, write noticesdomain
14Renewal offers and pricingPM, owner— (WS gets Clara's "renewals coming up" list)——Read expirations, draft offersdomain
15Move-out inspection and deposit settlementPM, maintenance— (Situs has 132 inspection-type work orders)——A reminder on the deadline. Colorado has a hard deposit deadline (knowledge-base doc security-deposits-move-out-charges)domain + partial data
16Make-ready (unit turn) boardMaintenance, PM94 turn-type work orders (S 55, WS 39)——Read turn status, chase vendors (7-stage turn in knowledge-base doc turnover-make-ready-process)domain + partial data
17Owner report (occupancy, leasing, work orders)Owner———Weekly summary (knowledge-base doc owner-weekly-report-and-box-score-conventions)domain
18Housing-voucher paperworkLeasing, PM at SitusA handful in the dataEmail"RFTA means Request for Tenancy Approval… from Denver Housing" (an RFTA is the form a voucher holder's housing authority needs the landlord to fill in)Reminder and status trackingdomain + partial data

What Clara would need, across 765 of the 853 labelled messages and calls (acknowledgements and "other" left out)

Could Clara do them? The labels said:

(c) Asks Clara could not do or did not answer

Clara's notices to staff:

Of the 72 replies, 24 went wrong (33%):

Things staff asked Clara for first (5, all at WS):

Follow-ups that failed:

What staff did by hand that Clara has no path for today:

(d) Golden scenarios (acceptance cases for the staff agent)

Each one is built from the hand actions counted above. Numbers inside the dialogues are illustrative; the job counts they cite are real.

  1. Leasing agent, morning queue (job 2, 353 actions).
    • Agent (text): "What's on my plate today?"
    • Clara: "4 showings: 10:00, 11:30, 1:00, 4:30. The 1:00 hasn't confirmed. 2 applications are waiting on pay stubs. 3 leads went quiet 5+ days. Want me to chase the stubs and re-offer the 1:00?"
  2. Booking for a walk-in (jobs 2 and 3).
    • Agent: "Make a card for a prospect, phone ending 4417. I showed him a home at Ember Lane, and he wants to see the 3-bed at Northridge Tuesday at 10."
    • Clara creates the guest card with the source "walk-in", books the showing in AppFolio and the calendar, and texts the prospect. She replies with the card link.
  3. Notes from the car after a showing (job 8, 62 notes).
    • Agent (voice): "They liked it. They need a cosigner and want December 1. They didn't love the upstairs laundry."
    • Clara writes the note to that showing's card (she resolves which showing it was by herself), sets a follow-up for tomorrow, and says "Saved to [prospect]'s card."
  4. Application chase (job 4, 280 actions).
    • Agent: "Who's stuck in screening?"
    • Clara: "3: one is missing a co-applicant's date of birth, one has references with no reply in 4 days, one is missing pay stubs. Send the reminders?" → "Yes."
  5. No-show and lead clean-up (job 3, 50 marked inactive).
    • Agent: "She never showed."
    • Clara records the no-show on the showing she asked about earlier in the thread, and asks "Mark inactive, no response?" → "Yes." Clara sets that status and reason in AppFolio.
  6. PM, pest-control day (job 5, 118 mass sends).
    • PM: "Send the roach-treatment prep notice to these units for Tuesday, in English and Spanish."
    • Clara drafts both versions, shows how many units it will reach, and sends on "go".
  7. PM, a resident asks about their ledger (cross-cutting job X and job 10).
    • PM: "A resident says their payment wasn't posted. What do we see?"
    • Clara: "An ACH payment from the 18th is missing from the ledger. Their housing-authority payment is also pending. I'll tell the resident we're checking with accounting." The fix to the ledger stays with the PM.
  8. Maintenance coordinator, work orders (jobs 1 and 6, 744 opened).
    • Coordinator: "Open a work order: dryer at Lampliter needs a new filter, in-house crew, and ask the resident for a photo of the model plate."
    • Clara creates and assigns the work order and texts the resident. When the work order closes, she follows up with the resident.
  9. Owner's question (job 7).
    • Owner: "How did leasing go this week?"
    • Clara: "11 new guest cards, 9 showings, 3 applications (1 approved), 2 leases signed. 116 work orders opened, 98 closed, 12 older than 7 days."
  10. Owner asks for outreach (section c, the failure about notifying tenants).
    • Owner: "Notify the tenants of both units at the Elm St duplex that there's a showing Monday 3:30 to 4:30."
    • Clara finds both units and their residents, sends the 24-hour notice, and confirms who received it.
  11. Catch-up call while driving (all jobs, by voice).
    • Agent: "Anything urgent?"
    • Clara: "Two things. Your 3:00 is 10 minutes out and asking for the lockbox code; should I send it? And a resident at Zephyr says the scheduled pest visit didn't happen."
    • Agent: "Send the code, and tell the resident we'll reschedule this week."
    • Clara does both and logs them.
  12. A staff note Clara should not answer (control case).
    • A PM emails a coworker with Clara copied: "Hi [agent], how did this go?"
    • Clara stays silent and files nothing to a prospect.

Architecture re-pass: one staff agent behind one front door (Proposed, pending review)

Design pass, Opus 5.5 at max effort, Nov 3 night, on Fede's ask: "do we need to rethink the architecture, give Opus 5.5 broader powers, fewer rules, more domain guidance and examples?" Status: Proposed, pending Fede's review. The Opus-vs-Sonnet numbers quoted here are interim; the model-swap bench row supersedes them when it lands.

Proposed, pending review. Nov 3, night. Read-only: nothing was changed.

TL;DR

(a) Today, in one picture

 A teammate's message today. Every step exists in several copies.

 ENTRY    6 reply doors (text, email to Clara, shared inbox, notice replies,
          matter replies, the staff phone line), plus video, meetings, in-app chat
   |
 WHO      5 different "is this staff?" checks
   |
 MATCH    5 different ways to find what a reply answers
   |
 SCOPE    3 building pickers; email takes the company's first building by id
   |
 PROMPT   8 prompts. Text and email: the renter prompt with a staff hat
          (4,311 and 4,717 words). Calls: their own (1,790 words, older model)
   |
 TOOLS    5 tool lists: desk 38, maintenance 4, calls 14, video, in-app
          4 different ways to find a person
   |
 GATES    4 gate stacks. Email alone has 7 checks that can silence a teammate
   |
 SEND     each door sends its own way

The copies number: 8 prompts, 5 tool lists, 5 staff checks, 4 gate stacks.

Real use is still narrow. Kat sent 54 of the 55 staff texts in 30 days. Situs staff sent 5 emails and no texts. Clara's lines got 3 voice notes in 200 days.

(b) Seven gaps against the vision

 Work orders opened, 45 days
 by hand   ######################################## 744
 by Clara  # 11
#GapEvidence
1Most of the job has no tool: work orders, card status, follow-ups, withholding an application, vendors744 work orders by hand, 11 by Clara. 172 of 765 staff needs are writes. The AppFolio robot already does them all
2Every door is its own Clara24 of 74 staff replies went wrong since Oct 5. Situs: 4 of 5 after both Nov 2 fixes
3The staff prompt is the renter prompt with a hat118 rules, 0 examples. Kat was told "you'll need to send it yourself", though the tool existed
4Calls are a separate Clara that can't actOwn 12 lookups, older model. Jay was told "I only help prospective renters"
5Roles are uneven; property owners don't existMaintenance, accounting and viewers get 1 lookup. No owner role. 7 of 8 Situs staff have no phone on file
6Reach is capped and differs by channelLive reports stop at 5 buildings; Situs has 53. Calls have no vendors or knowledge base
7Building rules silence teammatesA placeholder building blocked Deiby's and Miriam's replies on Nov 3. 56 "no building, do nothing" exits in the staff code

(c) Rethink or not: the agent, not the door

The pipeline is the lever, not the model. Tonight's harness numbers, interim. The harness is our offline test rig: 43 real-shaped staff replies, nothing sent.

 passes of 41
 main, Sonnet        ######################            22
 main, Opus 5.5      #####################             21
 prototype, Sonnet   ################################  32
 prototype, Opus     ################################  32

Broad powers pay off only once the front door hands Opus the right person, thread and building. The Oct 30 second opinion agrees: Opus did worse than today's Clara on 5 of 7 live prospect cards, because it obeys wrong inputs. So judge Opus on multi-step work (the job map's 12 golden dialogues, model conversations for each role), not replies.

               TODAY                                 PROPOSED
 ENTRY    6 doors + video, meetings, in-app    one front door; channels stay thin
 WHO      5 "is this staff?" checks            1 lookup, roles only
 MATCH    5 ways to match a reply              1 record of what Clara sent
 SCOPE    3 building pickers                   company first, building when known
 READ     4+ readers, some word lists          1 model read, may stay quiet
 PROMPT   8 prompts, renter prompt + hat       1 prompt: goal, job guide, examples,
                                               8 rules, a few lines per channel
 TOOLS    5 lists (38 / 4 / 14 / video / app)  1 tool list, trimmed per channel
 GATES    4 stacks, 7 checks on email          identity and company only
 SEND     each door its own way                1 send point: Clara at Propflow to
                                               staff, the customer's mailbox to outsiders
 OPEN     not linked to staff turns            each staff turn tells follow-through,
 ITEMS                                         which keeps the only list

The prompt, before and after

Staff text promptToday (measured)Proposed (target)
Words4,311 (email 4,717)about 2,000, mostly examples
Rule bullets1188 hard rules, each with a reason
"never"53, 15 in capitalsabout 5
CRITICAL / IRON LAW40
Worked examples, start to finish012 to 15, from the job map
Renter-only sections carried overat least 60
Rules that contradict each other or the code40

The 8 hard rules

#RuleBecause
1Never delete or bulk-close anythingAppFolio deletes can't be undone
2Never message a renter, applicant, vendor or owner the teammate didn't ask you toThe teammate owns that relationship
3Never state a fact you didn't read from a tool or the threadWhat staff hear reaches renters
4Who someone is comes from the roles you are given, never from an address, a signature or a buildingA wrong guess exposes renter data
5Stay inside this teammate's companyAnother company's data is never theirs
6Approvals, denials, money and legal steps stay human: draft them, don't decide themStaff keep those calls (most of the job map's 236 "partly" answers)
7A note that isn't for you gets silence; if it is for you and unclear, ask one short question8 of the 24 bad replies were the wrong call to speak or stay quiet
8After an action, say what you did and name the recordStaff should trust it without opening AppFolio

Fewer rules is safe: the guards already live in the tools. About 42 of the desk tools' 55 outcomes are a refusal or a question back, with a reason. Outside research agrees that models miss more as rules pile up. Your earlier rulings add two cautions. Examples show a whole job, never a phrase to copy. A one-off incident becomes a test case, not a prompt patch.

Keep, change, delete

KeepChangeDelete
The refactor as the front door: who, match, company scope, one readOne staff prompt replaces the renter prompt with a hatThe renter sections, and the "pass this to the team" rule added to staff turns
The tool code and its guards, including "act only on records the thread names"One tool list; calls use the same toolsThe call line's 12 copied lookups
The shared store for worked examples (it exists)Every staff role gets the whole toolset ("open it up completely")The leasing-only tool gate
Follow-through as the only list of open itemsAnswers to staff are gated by identity and company onlyThe Supervised hold on staff replies; the word lists that read approvals
ElevenLabs running the callsOpus on text and email, once the bench says betterThe first-building-by-id pickers; the 56 no-building exits; the old video desk prompt

(d) Your calls

1. Calls

2. New actions (work orders, card status, follow-ups, withholding an application, vendors)

3. Property owners (the investors, not the company's owner, who is already an admin; the docs use "owner" three ways)

(e) Plan, cut by proof

WhenWhatFirst real proof
Tonight, in flight (fixes, no switch)The refactor chain, PR 1 first (keep the match)The 74 real exchanges, replayed
Opus on the staff turn, only if the bench says better. Tonight's interim run: a tie on repliesThe harness, both models, two runs each
A voice note keeps both the words and the audioA replay of real texts; then the first real captioned note after deploy
One staff toolset on every channel, for every roleA maintenance teammate's lookup and tour move by email at Fairhaven; one simulated call
Tonight, next (local, no CI)The harness gains the 12 golden dialogues as "staff wrote first" cases, plus maintenance and property-owner senders. Calls are simulated, so no call minutesRed on main first
Tomorrow, if you pick 2A (one dark slice: merged but off until you turn it on)Behind "Clara acts for staff", a teammate emails "open a work order for…". Clara opens and assigns it through the work-order adapter, then replies as Clara at PropflowLive at Fairhaven by email: the work-order id, the reply id, and the staff-turn event (the record follow-through reads). Text waits: Willows is closed, and Fairhaven's line takes no texts
This week, after your goOne staff prompt: goal, job guide, examples, 8 rulesThe harness, the 12 golden dialogues and the 74 real exchanges, with no regression
More actions behind the setting; calls get them tooA record id per action at Fairhaven; one real call at the end
Waits for youThe shape; the three calls above; the turn-on per customer; Situs staff phones and Hugo's record (customer data); property owners

Acceptance. Every step runs the 12 golden dialogues, the 43 harness cases and the 74 real exchanges through scripts/coworker-harness/staff-reaction-regression/. A case passes on the record written, or on the right silence. A grader that only checks "replied or stayed quiet" passes 17 of today's 19 failures, so it doesn't count. A few golden dialogues have near matches today (notify tenants, never showed, stay quiet); most are new.

(f) Risks

The big one: broad reach plus a false staff match. One wrong phone or email on a staff record would let a stranger read every renter's ledger and move tours across 53 buildings. Today's records are messy: Hugo's phone sits on a person with no role, and Western Slope's shared inbox is claimed by a test prospect.

Verified identity must mean all of this, on every turn:

These are your two Oct 9 hard rules made concrete: non-staff never reach it, and nothing crosses customers.

Other risks

RiskWhat we do
Opus obeys bad inputsBroad powers land only after the front door
Opus is slower: a median 16 seconds per case tonight vs 13Fine for text and email; calls stay on a fast model
A shorter prompt can regressShrink only with the full replay and a planted defect that must fail
Two lists of open itemsFollow-through keeps the only one; the staff agent reads it and sends it the staff-turn event
Gera's lane tonight: three open PRs make a building's Supervised mode hold or stop Clara's own texts to staff (his late-October rule, "Supervised holds every team message")Your Nov 3 "no supervised" covers replies. For her own notices, the hub records your Oct 16 "no" and still lists it as your yes/hold. This design assumes answers to teammates never wait on a building's mode. One line between you and Gera settles the notices

Where it stands, Nov 1 2026

Read-only audit of the staff side: staff asking Clara, Clara asking staff, and team notices. Code read on main 9e502ce48b; usage read from production, Oct 2 to Nov 1. The refactor's state is in the Oct 31 audit.

1. What staff can do, by channel

proven a real customer record · shipped, untested live code, no real use yet · missing · n/a

CapabilityTextEmailVoice
Staff ask Clara
Book or move a tourprovenWS: 3 of 5 worked; tour 4d116c70missingthe staff desk is granted on text onlymissingthe staff phone line only reads, by design
Cancel a tourshipped#20886; 0 real usesmissingmissing
Tour notesprovenWS: 24 of 26 saved; matter_tourcheckin_af61d484missingmissing
Look up recordsprovenWS: 1 of 1missinga staff email that matches no open ask never reaches Clara (gap 1)proven, WS only1 of 2 worked; conv_voice_5586a662; off at Situs and Camellia
Send application, text a prospectshippedswitch removed Oct 26 (#22532); the one real try (Oct 24) hit the old switchmissingmissing
Answer Clara's questionprovenWS lockbox asks 2 of 2provenSitus matter_41896f45; WS 7 repliesn/a
Clara tells or asks staff
Ask the team a questionprovenWS lockbox asksprovenWS 30 sent, 7 answered by replyn/a
"How did the tour go?"provenWS 23 of 27; Camellia 0 of 4; Situs since today (#24225), untestedmissingFede Nov 1: email by default; no PR yetn/a
Tour booked, moved, cancelledproven, opt-inWS 36 notices to 2 people; Situs 0 people opted ininbox onlytour host not emailed; Fede Nov 1, no PR yetn/a
Arrived, running lateproven, opt-inWS 6shippedto the tour host since today (#24230); proven live at Fairhaven Nov 1 (tn_770e05d7)n/a
Office note after a calln/aprovenWS 44, Situs 13, Camellia 10 delivered; 8 refused by the wording checksource
Welcome text to a new agentWillows only#22669; off at all three, Live mode onlyn/an/a
Hand a matter to a named personmissing on every channelhand-off framework not started (Oct 31 audit, row 13)
2. Usage, last 30 days
Staff to Clara (text / email / voice)Their requests that workedClara's asks answeredMedian answer
Western Slope55 / 17 / 231 of 38tour check-in 23 of 27; questions 7 of 30 by reply, 7 more closed in AppFolio, 14 open6.6 min (check-in) · 24 min (email)
Situs0 / 5 / 01 of 51 of 13 min
Camellia0 / 0 / 0none asked0 of 13 (4 check-ins, 9 questions)none

Kat sends 54 of the 55 texts. No customer staff member decided any held message; Fede, Gera or a session decided them all. PropFlow's own traffic is excluded (Fede: 39 calls at Western Slope).

3. Gaps, ranked

Situs marks the gaps that matter for Situs on Monday.

#GapEvidenceNext step
1Situs A staff email that matches no open ask falls through both inboxes silentlyMiriam's reply to a tour confirmation, Oct 29 (3ba9bea3); Eileen's reply to an office note, Oct 20 (e3bfdc15, before office notes carried a reply tag). The mailbox copy was skipped because "Clara's inbox handles it", and Clara's inbox skipped it as data only. Nobody was toldOne fix: route every staff email to Clara through the one staff reader; never skip it silently
2Situs Staff cannot book, move, cancel, note or look things up by emailDesk granted only on text (staff-turn-options.ts). The Sept 25 reason was spoofable senders; the email sender check now exists (#12334)One PR: open the desk to email when that check passes; prove it at Willows from the test mailbox
3Situs Tour host not emailed on booked, moved, cancelled; the "how did it go" ask exists only as a textSitus has 0 text opt-ins; Fede's Nov 1 ruling; no PR foundBuild PR 1 (host email) and PR 2 (notes ask by email), as already decided
4Clara's questions go unanswered, and Clara never checks whether a person already repliedWS: 14 of 30 still open; 7 closed only because staff wrote the renter in AppFolio (about 26 h). Camellia: 0 of 13 answeredBuild the wake, look, act slice (Oct 16): read the card for a staff reply before re-asking
5Situs Two of today's changes have no live proof#24225 check-in at Situs, #23188 text answer (#24230 host email proven at Fairhaven Nov 1)One Willows run each, with record ids
6Text desk misfires on harder requestsWS: 6 of 36 failed (note on the wrong card, wrong time, tour not found, card refused); 4 hand-sent corrections. Most predate the Oct 17 to 19 desk rewriteReplay those 6 against today's desk; fix only what still fails
7Supervised holds staff notices, which Fede ruled out on Oct 16Rule from Gera, Oct 29 (team-notify release.ts). Situs leasing is Live, so Situs is not affectedFede, yes or hold: do staff notices skip the Supervised hold?
8Staff phone line: lookups only, on at Western Slope only2 real staff calls in 30 daysLeave it; too little use to invest in now

Not verified: what Clara sent staff by email before about Oct 28 (bodies were not stored), so email notice counts are partial; who in Western Slope's shared inbox wrote each email; staff texting from numbers not on file; whether Lee's Oct 31 dog-limit reply ("duplicate") reached the renter; the content of the two dropped Situs emails, because the SES path keeps metadata only.

00b · Proposed

Teammate memory, proposed Nov 1 2026

Answer. In 30 days, one thing a teammate told Clara was a lasting habit she should have remembered. So build the smallest store there is: a few short "how I work" lines per teammate, read only when that teammate texts or emails Clara. Grow it only if use shows up.

1. What teammates actually told Clara

Kat (K.B., Western Slope) sent 54 texts. 46 were the task at hand (tour notes, bookings, "ok"). 8 said something more. Situs adds nothing: its 5 staff emails were either answers to Clara's questions or were dropped with no body kept (gap 1 above).

DateWhat K.B. saidWhere it belongs
Oct 2"I will show A.N. after B. It's the same location" (Clara had refused 3:45 over the 30-min gap, booked 4:00, then corrected)Memory: she stacks tours at one address
Oct 2"Duplicate" (second notes ask for one visit, two homes)Engine: one notes ask per visit
Oct 14"You said you already did"Engine: same
Oct 7"I made the guest card already"Engine: look up the card again
Oct 16"If you scroll up in this thread you can see you just asked me about her?"Engine: lost thread context
Oct 24"Good, please send an application" → "you'll need to send it yourself"Missing capability
Oct 15"Lockbox code is 6011 for 585-201"Already handled: the lockbox ask
Oct 14"L.J. is a current tenant switching properties"Prospect card note

Count: 1 truly needs memory, 1 already handled by a setting or flow, 1 is a card note, 4 are engine bugs, 1 is a missing capability. K.B.'s text-me choice is already a setting (tour alerts by text since Oct 1). The 4 engine bugs are follow-ups, not memory.

2. What exists today (for engineers)

Five per-person settings, none free-form, none read when a teammate writes to Clara.

SettingStoresCodeSet by
Text or emailtext / email per person; only the welcome text reads itsrc/lib/domain/staff/contact-preference.tsWhen the person is added
Welcome textOne intro text per personsrc/lib/domain/staff/staff-welcome-text.tsCompany switch, off
Tour alertsPer event: email or textsrc/lib/domain/portfolio/scope/staff-tour-alert-subscription.tsThe person, in settings
Who shows toursOrdered list + gap minutes (company)src/lib/domain/calendar/tour-showers-join.tsSettings
Working hoursNone per person; their calendar's free/busysrc/lib/domain/calendar/check-availability.tsCalendar connect
Language, timezoneBuilt for rentersPersonPreferences in src/lib/data/types.tsInferred
Answers saved from staff repliesProperty knowledge, live at oncesrc/lib/domain/escalation/teaching-capture.tsStaff reply

3. The design, one row per teammate

StoreOne row per teammate per company, beside the person: PERSON#<id> / MEMORY#<orgId>. Same pattern as the person-facts row (person-facts-item.ts): one write helper, carried on person merge. At most 10 short lines, each with the words, the date said and the message it came from. Not Person.preferences: that is shaped for renters.
CaptureClara notices when a teammate states a lasting habit about themselves during normal work and saves it with one tool call. No "should I remember this?" quiz (Fede, Oct 24). She confirms in one clause only when it changes what she does: "Booked 3:45, and I'll stack tours at the same address for you from now on."
UseSlice 1: added to Clara's staff-desk instructions when that teammate writes in (composeStaffDeskSystemPrompt() in agents/clara/lib/agent/staff-desk-persona.ts). Notices stay templated for now.
See / change"What do you remember about me?" lists it. "Forget that" or "stop doing X" removes it. No settings page, no approve button (autonomy rule).
ExpiryA line unused for 90 days drops. Over 10 lines, the oldest drops.
Not memoryProperty fact → knowledge base (teaching capture, incl. the "remember next time" email case). Company rule → company settings. Prospect fact → their card. Text vs email → the existing tour-alert setting.

4. One slice to add

RemembersCostProves
A. "How I work" lines (recommended)Habits a teammate states, e.g. stacking tours at one address1 PR: row, one tool, one prompt blockWillows test-line texts: teammate states a habit, a later booking follows it with no re-ask; record ids
B. "Text me / email me"Nothing new: saying it flips the existing tour-alert settingSmall, no new storeCapture wiring only; 0 real cases in 30 days
C. "Homes I cover"Which homes a teammate showsOverlaps the tour host field in the tour-move designBetter solved there
Oct 2, todayWith slice A
K.B. asks for 3:45 after B. Clara refuses (30-min gap), books 4:00, sends A.N. a 4:00 confirmation, then a correction to 3:45. 7 texts on the staff thread, 1 wrong confirmation to the prospect.Next time K.B. asks for a back-to-back slot at the same address, Clara books it first try. 1 text, no correction.

5. Decisions for Fede

  1. Build slice A as one PR, proven on the Willows test line? Recommend yes.
  2. Live everywhere on merge, no switch? It only changes how Clara treats what that teammate said to her. Recommend yes.
  3. Oct 2 case: K.B.'s memory, or a company rule ("no gap between tours at the same address")? Recommend memory: the gap is a company choice, and only K.B. said she skips it. If you pick the rule, there are zero memory cases in 30 days and we wait for one.

Related: staff tour moves and reassignment · client onboarding playbook (welcome text and team setup). Evidence: Kat's staff thread c9f809af and 4d116c70, Oct 2 to Nov 1.

00c · Proposed

Situs inbox study (Fable), Nov 1 2026

Answer. The shared box is a listening post, not a desk: of 5,238 messages this year, 13 left it, all Clara's. Staff answer from their own addresses and hand work around by reply-all (842 of 1,055 hand-offs, 80%). The VA seats do 42% of all human work on guest cards, first human on 56% of them; that work is 72% texting and 8% booking. Since Oct 20 Clara has been a bystander: in 47 prospect text conversations, staff or the VA answered first in 36 (median 9 min), Clara in 1, nobody in 10; Clara wrote 18 of 346 typed prospect messages (5%). Nothing in the mailbox stops Clara from doing the VA's prospect work; nobody has said who goes first.

1. What was read

JanFebMarAprMayJunJulAugSepOctNov 1
Received2162403853084494748407308657126
Sent from the box00000000012 (Clara)1 (Clara)
Who writes to the box (3,958 messages read)MessagesShare
Situs staff (president 328, PM 180, VP ops 136, leasing 191, others)1,29433%
Listing sites and website forms (Zillow, TurboTenant, Tenant Turner, Contact Us)1,12228%
System notices (AppFolio, vendor portals, forms)46712%
Residents3389%
Applicants, guarantors, housing connectors, unknown people3268%
VA seats (C.T. 24, PM Assistant 50, Assistant Lead 30, plus forwards)1313%
Vendors1253%
Prospects writing directly1203%
Clara and PropFlow351%

Internal reply speed by email: 546 replies, median 49 min, 52% within the hour, 1 in 10 over 22 hours. Staff answering a VA's team email: median 32 min (58 cases). VA answering a staff ask: median 69 min (101 cases).

2. What the VA does, what Clara can do, what Clara did

Three VA seats: C.T. (listings, cards, applications), A.L. (texting, calls, insurance) and P.A. (vendors, turns). Prospects are about 30% of their message volume.

VA work (share of 3,892 VA guest-card actions)Clara can do it todayClara did at Situs, Oct 20 to Nov 1
Text prospects, 71.6%Yes (AppFolio texting seat, live Oct 29)18 of 346 typed prospect messages; first to answer in 1 of 47 conversations
Book and move showings, 8.3% (VA booked 288: 164 C.T., 124 A.L., onto D.M. 142, L.M. 53, E.O. 32, M.G. 25)Yes for her own bookings; moves and cancels only when asked by textnot counted this pass
Card edits and notes, 8.4%Notes yesnot counted this pass
Phone calls to prospects, 4.9%Inbound onlynot in this study
Email prospects, 3.0%Yes12 first-touch emails (Oct 28 to Nov 1)
Move-in and application steps, 3.9%No (application link only)0
Resident texting and email (8,845 resident texts Jan to Sep, 338 resident emails in the box)No (tenant hand-off, Gera's lane)0
Team coordination by email: status answers, loop-closing, taking a delegated taskNo by email (#24367); yes by text. Nov 2: merged and live on deploy: a verified staff email to clara@ gets the desk (lookup, book, move, cancel, note) and a reply (#24426); staff who answer Clara's question by email get a "Got it" back (#24428). After-tour ask by email for hosts with no phone (#24435, merged 06:45Z). Willows end-to-end proof of all three owed Monday.0 emails to staff
Maintenance, vendor and turn mail (28 "GREEN, unit ready" mails, work orders)No0

Coverage. Clara can do about 80% of the VA's prospect-side actions and about 25% of all VA work. In the first 13 days she did about 5% of the prospect texting.

3. Gaps, ranked by what bites in the first two weeks by email

#GapEvidenceClara todayClara shouldSize
1Who goes first. Clara and the VA desk watch the same cards; the VA wins the race.VA or staff first in 36 of 47 text conversations, median 9 min; C.T. typed 101 prospect texts to Clara's 18. Aug 4: VA "I have spoken with him already", L.M. 15 min later "I believe D.M. did as well."Answers when she gets there; no visible claim on the cardOne explicit first-responder rule per customer: Clara first for N minutes, a human reply takes the card over, the claim visible in AppFolioDecision, then 1 PR
2The team-time ask (Fede's example): a prospect wants a time nobody has open.3 explicit asks all year; Oct 30 took 8 emails, 4 people and 3.5 h with a president nudge. The usual practice is booking straight onto an agent's calendar (288 times), which produced day-of cancels, an agent no-show and a prospect who could not find anyone (4 corpus cases).Says the time is not open and offers the two nearest slots (verified on the Oct 30 thread)Ask the agents with a deadline, tell the prospect "checking", book on the first yes and name who meets them, otherwise fall back to the offered slotsFeature, 2 to 4 PRs, on top of the staff move/reassign design
3"I'm here" texts from the curb.68 of 884 cards hold one (Jan to Sep 1), 8 more in October: "I was here at 350pm and no one is still here?????"; "I'm here. Where would the leasing office be?"; "I am here but not sure where to go"Not verified this passAnswer with the meeting spot and the host's ETA, text the host, note the card1 PR after verification
4Confirm-or-release. Situs skips showings the prospect did not confirm.D.M., Jul 28: "we do not reside at the property and we need to plan for travel"; CONFIRM/DENY texts one hour before; 66 staff cancels and 53 prospect cancels in 884 cards; a DENY the day after a VA booking (Jun 24)Reminders exist; whether an unconfirmed Situs showing is released is not verified this passMirror the house rule: ask the day before, cut off one hour out, release the slot, tell the host, re-offer timesFix or 1 PR after verification
5The email shapes #24367 has to handle (already filed; counts added here)Inbox-wide: status pings 8 ("did we get back to this applicant?", "have you followed up?"), delegations 27 ("can you call the new tenants?", "put this on the issues list"), loop-closers 14 ("I have already contacted the prospect"), decision asks by @mention 4, one never answered. The corpus holds 6/7/5/4 of them.Dropped unless it answers a question Clara askedAnswer from the record on the same thread, reply-all; take leasing-shaped delegations, decline the rest in one line; close her own loops#24367 plus the reply-all relay fix
·Residents and maintenance are most of the VA's day.8,845 resident texts vs about 3,900 prospect-side (Jan to Sep); in the box the VA's email tasks are maintenance 68 and residents 56 against showings 380%Nothing new for Situs this month; the counts go on the tenant hand-off listDesign first (Gera's lane)
·Website Contact Us forms53 this year, 18 from prospects, 29 residents or other, 6 vendor pitchesIgnored (no card is minted from listing mail)Decision: treat the prospect-shaped ones as leads, or leave them to the VADecision
·Cover requests ("can you take my showing?")0 asks in this mailbox; they travel by phone or personal text. AppFolio shows the footprint: 39 showings handed from one agent to another this year (35 cards), 14 of them for a slot the same or next day; plus an agent with car trouble (prospect rebooked next day) and a 3-property tour moved and reassigned within 68 minn/aHarness scenarios come from the reassignment events, not from mailCovered by the move/reassign design

4. Ten exchanges, initials only

  1. Oct 30, VA C.T. to the team: "Is anyone available to accommodate a showing today at 2:15 PM? If not, I'll reach out to the prospect to coordinate a different time." 3 h 18 min later, president H.W.: "Team - did we get back to C.T. on this?" VA: "I called [the prospect] and scheduled the tour for 3:30 PM today." Leasing D.M., a minute later: "for today I have opening at 3 or 3:15 pm." Clara had offered 1:30 or 1:45 and never saw the thread.
  2. Apr 9, leasing D.M. in a card note: "@C.T. @P.A. I am available between 9-10 am or 3-6 pm for this showing on Monday." Prospect, 15 h later: "Yes, I can do 3 if that works for you guys." Nobody booked; D.M. apologised four days later.
  3. Jun 24, VA A.L. note: "will schedule a showing for Saturday once D.M. confirms availability." Booked an hour later; the prospect answered DENY to the day-of confirmation.
  4. Jul 20, VA A.L.: "@D.M. - she is the housing connector who wants to tour 3 properties simultaneously on Wednesday." 68 min later all three showings were moved a day earlier and reassigned to L.M.; all three happened.
  5. Jul 28, after a prospect wrote "I showed up and walked round the building and there was no one there to show me around so I left", leasing D.M.: "the reason we didn't go to this one is because she never confirmed her appointment… remind the prospect that we do not reside at the property and we need to plan for travel." President: "makes sense to not go if they don't confirm."
  6. Jul 6, VA A.L. books 4:00 PM on L.M. after a phone confirmation; the prospect, confirmed by text, at 4:08 PM the next day: "I am here is anyone comming… I was here at 350pm and no one is still here?????"
  7. Sep 19, president H.W. forwarding an application notice: "Hey team - did we get back to this applicant?" Leasing D.M., 4 h later: "yes we received her application on Thursday. Hopefully we'll have her approved by Tuesday."
  8. Sep 3, VP E.O. on two website forms: "Are these being converted to guest cards?" D.M., 4 min later: "one was only asking for L.M.'s email, I just responded."
  9. Jul 21, VP E.O.: "C.T., can you call the new tenants and find out about the furniture?" VA C.T., 12 min later: "I just spoke with [the tenant]. He confirmed that the furniture belongs to them."
  10. Aug 13, VA A.L.: "@D.M., please advise about the waiving of the LLI fees." No reply in the thread.

5. Caveats, and the corpus for the harness

00d · Proposed

Situs inbox study (Opus), Nov 1 2026

Answer. The VA does two jobs: the AppFolio front desk (on the guest cards the VA seats booked 57% of showings, made 84% of logged calls, started 55% of move-ins) and an email back office the team hands out by name ("C.T., pre market it now"). Clara does about a third of the VA's typed work (30% fully, 11% partly). The first thing the team will hit is a closed door, not a missing skill: they work by copying leasing@, and Clara skips teammate email copied there unless it answers her.

1. How the team works with the VA

Habit (1,340 team and VA emails in the box)Number
leasing@ is only a copy (CC), not the addressee73%
Two or more colleagues on the email73%
A task handed to a person or "Team" by name (a floor)45 (E.O. 17, H.W. 11)
Team answers a VA questionmedian 40 min, 47% over an hour
VA answers a team askmedian 30 min

Totals match the Fable section (5,238 emails this year).

2. What the VA does, and what Clara covers today

Clara does it partly not at all unclassified

Lead replies, booking open slots555 Applications to move-in306 (29 are the link) Resident notices303 Maintenance, vendors, turns193 Follow-up calls189 (Clara texts instead) Collections, move-outs, listings167 Checks with the team, answers15 Other conversation207

1,935 typed VA work units (texts, emails, logged calls), Jan to Nov 1, not counting 454 AppFolio template sends; with those, 37% fully and 9% partly. The top five shapes make 80%.

3. Five gaps most likely to bite in the first two weeks

#GapEvidenceClara todayClara shouldSize
1Team mail copied to leasing@ never reaches ClaraClara's log, Oct 25 to Nov 1: 72 teammate emails skipped as staff-to-staff, e.g. H.W.: "Team can we please notice these units for Wednesday afternoon". This year 234 team emails to renters copied leasing@ (23 since Oct 15, mostly residents); none reaches the renter's thread.Skipped unless sent to Clara. Not the reply-all bug (replies to her notices).Log a teammate's reply in the renter's thread; treat asks to "Team", a VA or Clara as hers (#24367 decides what she does); otherwise stay quiet1 PR to log; design first for asks
2A renter names a time Clara doesn't haveOct 30, D.S. asks for 2:15. Clara: "2:15 PM … isn't open, but I do have 1:45 PM or 1:30 PM." VA C.T. asks the team; the president chases 3 h 18 min later; C.T. books 3:30 by phone. Clara saw the booking land; she couldn't ask. Guest cards, Jan to Aug: a third of renter texts naming a time ask for one nobody offered (31 of 91 sampled); 16 of the 31 got their time.Offers open slots onlyAsk the showing team with a deadline, tell the renter she is checking, book on a yes, else offer slotsFeature, 2–3 PRs (reuses the ask-the-team path and chaser)
3Clara's notes have no ownerThe VA names a person in 95 of 105 internal emails; all 20 Clara notes since Oct 19 went to leasing@ alone ("Can someone review…?"). E.O. on a callback note: "Did anyone call her?"Shared inbox, no addressee (tour notices to the showing agent are being built)Address each note to its owner by role, copy leasing@1 PR
4Back-office tasks have no Clara toolResident notices (16%). Listing edits ("VAs - for now can we turn off the leasing for all commercial units", done in 6 min). Outreach ("C.T. can you please contact the Alton team"). Notes and flags.Card notes only; #24367 opens the door, not these actionsNotes and listing availability first; decline the rest in one lineDesign first; new capabilities, default off
5Applications to move-in follow-through15% of typed VA work plus 140 template status sends. E.O.: "L., Have you followed up?"Sends the application linkChase each step (documents, deposit, lease, insurance, keys); flag stalls to the teamDesign first; new capability, default off

Checks, unverified: Oct 30, Clara's slots ended at 1:45 while D.M. had 3:00 free (check Situs rotation and hours); 42 showings staff booked in AppFolio since Oct 20 (do they reach the calendars Clara reads?). Agrees with Fable gap 1: Clara wrote in 10 of 150 staff-touched renter conversations since Oct 20.

4. Decisions for Fede

  1. Team mail copied to leasing@. A: log teammates' replies to renters. B: A, plus asks to "Team", a VA or Clara become hers (with #24367). C: leave it. Recommend B, A first.
  2. Off-calendar times. A: ask the showing team, tell the renter she is checking. B: open slots only. Recommend A.
  3. An owner on every note. A: address by role, copy leasing@. B: leasing@ only. Recommend A.
  4. First back-office design. A: application-to-move-in follow-through. B: resident notices. C: wait for the VA to step back. Recommend A.

5. Limits, and the corpus for the harness

Twelve exchanges, initials only
  1. Oct 30. Clara to renter D.S., 8:51: "2:15 PM on Friday, October 30 isn't open, but I do have 1:45 PM or 1:30 PM available that day." VA C.T. to the team, 9:30: "Is anyone available to accommodate a showing today at 2:15 PM? If not, I'll reach out to the prospect to coordinate a different time." President H.W., 12:48: "Team - did we get back to C.T. on this?" C.T., 12:56: "I called D.S. and scheduled the tour for 3:30 PM today." Asst PM D.M., 12:57: "for today I have opening at 3 or 3:15 pm."
  2. Oct 26. H.W., leasing@ copied: "Team can we please notice these units for Wednesday afternoon @ Carr Street. 103 104 303 304." PM M.G.: "Yes, will do." Clara's log: staff-to-staff, skipped.
  3. Oct 27. Renter N.M. emails her housing-voucher packet. Two minutes later Clara asks leasing@: "Can someone review the attached RFTA packet N.M. just emailed in?" Two minutes after that leasing L.M. tells the renter "I will complete this and send it over" and tells Clara "I just responded to N.M., thank you for following up." Clara closed her ask; L.M.'s note to the renter was skipped.
  4. Oct 31. L.M. answering a Clara question: "No, that is not possible. We cannot accommodate a $500 rent in exchange for exterior cleaning, nor can we allow 20 dogs in a single apartment."
  5. Oct 20. VP ops E.O., replying to Clara's first callback note (a test call Clara had already flagged as a test): "Hi Team, This is exciting! Did anyone call her?"
  6. Oct 28. M.G.: "C.T., can you please look into this?" then: "could you please post for us while C.T. works on getting Reddit set up?"
  7. Jul 17. E.O.: "Including the leasing team to make sure everyone is aware. L., can you please add this note and flag it for future reference?"
  8. Jul 21. E.O.: "D.M., can you get it scheduled for next week? C.T., pre market it now with last years photos and then add an updated version with digital furniture."
  9. Jul 24. C.T.: "For now, I've listed the availability date as 8/18 on all listings, but please let me know if we should update it. I have a prospect asking when the unit will be available."
  10. Aug 20. H.W.: "VAs - for now can we turn off the leasing for all commercial units so these go away for now until we get fixed?" C.T., 6 minutes later: "The commercial units have all been unlisted."
  11. Aug 31. D.M.: "C.T. can you please contact the Alton team and confirm they will be ready for this treatment. They said last week they would be but again it's been 3 weeks they haven't been."
  12. Jul 15. E.O., on an application thread: "L., Have you followed up?"

C.T., L. and B. are the three VA seats (C.T., Assistant Lead, PM Assistant). Staff: H.W. president, E.O. VP operations, M.G. property manager, D.M. assistant property manager, L.M. leasing.

Mailbox counts by month and sender
SenderJanFebMarAprMayJunJulAugSepOctNov 1Total
Listing sites3653369419715329126127820721,608
Situs team and VAs305473628910929124025627131,478
AppFolio9978243956674978481458
Personal addresses (renters, others)9918171331444153330268
Clara00000000021122
Other (vendors, utilities, banks, newsletters)13211518011111112514713920014401,404
All21624038530844947484073086572475,238

Gmail header counts by sender domain, sent and received, spam and trash excluded.

00e · Proposed

VA ways of working: POCs

POC results, Nov 2

Answer. Three of the VA's habits now work in code: asking the team to cover a time nobody has open, finding cover when a host is out, and knowing when to speak, act or stay quiet on a group email. The first two run on Clara's real booking and staff-reply code; the harness still drives the timer. The third is a decision rule, not wired in yet. Today Clara does not do the first two, and gets the third right in 6 of 14 cases.

TODAY Rosa asks for 2:15every calendar busy Clara offers 3:00 or 3:30the team never hears stops WITH THE POC Rosa asks for 2:15every calendar busy Offers 3:00 or 3:30, and emailsthe hosts: "can anyone take 2:15?I'll put it on your calendar" Noor: "I can"first yes wins Booked at 2:15Rosa told; a lateryes hears "Noor took it"
Fede's Oct 30 example took the VA 8 emails, 4 people and 3.5 hours. The ask stops at the first time Clara offered, after 2 hours, or 30 minutes before the asked time, whichever comes first. It never double-books a host and checks her drive between homes. Names are made up.
PatternCasesRight today → with the POCWhat changes for the teamProposed PRs (source lines, tests extra)
Ask the team for a time nobody has open10 + 5 controls
real: 4 of 12 tagged
0 of 10 → 9 of 10
controls 5 of 5 → 5 of 5
Clara offers the open times and asks each host directly if anyone can take the asked time, with one reminder halfway to hosts who have not answered. The first yes gets the tour on her calendar; Rosa gets one confirmation; a later yes gets one line back.3: the ask (~500); booking on a yes (~320); wiring into the booking flow plus the timer for the reminder and the close (~200)
Cover for me3
real: 2
1 of 3 → 3 of 3A host who is out tells Clara. Clara asks the other hosts first and moves the tour to the first yes; Rosa keeps her time and hears nothing. Only if nobody can does Clara ask Rosa for a new time. Today Clara moves the time straight away.1, on top of the first (~80)
Each host on their own channel10 of 1 → 1 of 1The ask goes by email by default and by text only to hosts who opted in. Situs has no one on text.Folded into the first PR (~10)
Group threads: speak, act or stay quiet14
real: 13 leasing, 138 all topics
6 of 14 → 14 of 14
decision only, not wired
Clara answers what she is asked, does what she is told (one line back to the sender), stays quiet when the team talks among themselves, and pulls her draft when a teammate already answered. She never repeats a teammate's words back. Also the Opus study's top gap: a teammate's email to a renter with leasing@ copied is skipped today (72 in 8 days).3: store who is on each thread (~100); teach the reader "instruction" and "question for Clara" (~80); wire the rule into the reply doors (~250)
"I'm here" from the curb; confirm or cancel23
real: 6 Situs cases behind 9
9 of 23 → 22 of 23
1 known gap; 11 planted defects caught
The one-hour reminder asks the renter to confirm. Silent at 30 minutes: the host gets one email and the tour stays booked. A confirmation sends the host nothing; a late yes sends "confirmed after all". At the curb Clara names the host she told and never promises anyone is ready. Design + POC3: setting and ask (~150); heads-up, fold and "I'm here" words (~300); weekend heads-up by email and an emailed yes counts, both fixes (~150)

Proof

What is not working yet

Decide

  1. Ask the team for a time nobody has open: build it as 3 PRs behind a company setting that starts off, then turn it on at Situs? Recommend yes.
  2. How long the ask stays open: 2 hours with one reminder (built), or, for a time on a later day, until the first time Clara offered? Recommend the later-day change; same-day asks keep 2 hours.
  3. Cover for me: same setting; ask the other hosts before moving the time? Recommend yes.
  4. Group threads: store thread members and teach the reader first, then wire the rule after a replay on real threads? Recommend yes. It improves staff email Clara already handles, so no setting.
  5. "Clara, leave maintenance to the team this weekend": add a pause staff can set by email? Recommend a separate decision; it is a new capability.
For engineers: branch, commands, evidence
  • Branch fede/poc-va-ways-of-working, pushed, no PR (head d9a6a6e2e0; 58 commits behind main at publish, not rebased; it carries the staff tour-move POC it was built on). Base for the red runs: ded901930b.
  • Cover ask (patterns 1, 2 and 4): npx vitest run --config scripts/coworker-harness/va-ways-of-working/vitest.config.ts scripts/coworker-harness/va-ways-of-working/__tests__/cover-ask.harness.ts
  • Group threads: same config, __tests__/group-thread.harness.ts. Plants: VA_POC_PLANT=ask_when_free | ignore_tour_then | silent_second_yes | drop_host_said_yes | nudge_everyone | relay_on_talk | ignore_cc.
  • Group threads, today's side: 7 cases ran through the real reply-to-notice code, 2 come from production records, 1 from reading the code; 4 have no evidence of today and say so.
  • Evidence: scripts/coworker-harness/va-ways-of-working/results/ (a run file per label, before and after notes, attestation.json, the 32-case coverage map).
01 · Production today

The Clara machine today (production)

Built from the code on main as of Oct 25. Read it left to right: who writes in, the entry points, the lanes before the model, what a turn gathers, the prompt layers, the model, the guards after it, the output gates, and what gets saved. It is wide on purpose; a big screen helps. Every box carries its plain name and, in grey, the code file or function that proves it.

What the map shows

The full list of facts, one line per box with its file, and the ten items marked unverified, are in the tracker's working notes.

The next message, or a staff answer to an ask or a held draft, starts the next turn1. Who writes inRenter or prospect textsTwilioRenter or prospectemailsour mailbox, Outlook, GmailPhone calltranscript only, after thecall endsProperty softwareAppFolio guest cards and PMSinboxStafftext, email or Slack2. Entry pointsText webhooktwilio/webhook/route.tsOur own mailboxses-email-forwarder/index.mjsOutlook push and mailboxpollerswebhook-processors.ts,company-mailbox-pollerCall-ended transcriptvoice/call-ended/route.tsGuest-card import andPMS reply wakeappfolio-sync/handler.ts,pms-mirror-reply-wake.tsNew lead first emailclara-first-email-consumer.tsApprove or answer a helddraftslack/events/route.ts,staff-reply/door.tsInbound queue, one at atime per sendersqs/client.tsQueue workerinbound-processor/handler.ts3. Lanes before themodelText laneprocess-envelope.tsEmail lanes: ourmailbox, Outlook, PMSprocess-email-record.tsSafety first: test menu,test data, gas or COinbound-dispatcher.tstryPreemptsScheduling laneinbound-dispatcher.tstrySchedulingLaneOpen repair answer, thenratingtryMaintenanceStateFirstLane,tryRatingLaneRepair intake createsthe work orderinbound-dispatcher.tstryIntakeLaneRouter: vendor, managerreplies, staff, toursinbound-router.tsrouteInboundMessageClara's turnconversation-manager.tshandleIncomingMessageTurn4. Inputs gatheredConversation history,newest 80k tokensapplyContextWindowKnowledge block, fulldump, no searchleasing-knowledge-block.tsWho is writing: person,tenant, unitidentity/resolve.tsProspect and guest cardgetProspectByPersonIdLease answersresolveLeaseAnswerContextRenewal and turnoverstatebuildRenewalPromptBlock,resolveTurnoverContextCompany and propertysettingscompany-voice.ts,buildTeamFactsOpen asks and held statematter-context.ts,deferred-reply-row.tsOpt-out and mutecheckSuppressionPMS messages, onlyinside historybuildClaudeMessagesTurn notes: doneactions, units, timeconversation-state.ts5. Prompt layers, inorderPersona: Claraclara-personality.tsToday, company voicepointercompany-voice-block.tsNo dead-end hand-offruleno-dead-end-handoff.tsProperty info andknowledgeclara-unified.tsResident scope, feesknowledgeproperty-knowledge-block.tsSpecials, lease facts,applicationbuildLeasingSpecialsBlockProspect, tour, tenant,renewal infoformatTenantInfo,buildRenewalPromptBlockModule workflow:repairs, leasing orturnoverclara-maintenance.ts,clara-leasing.tsChannel style rulesclara-delivery.tsLanguage and companyvoicerenderCompanyVoiceBlockDenied-applicant scope,always lastDENIED_APPLICANT_SCOPEAdded: lessons fromgradinggrading/injection.tsAdded: tool blocks permodulecapabilities/index.tsAdded: email overlay orstaff personaclara-email-core.ts,staff-desk-persona.tsAdded: thinking andwhy-line rulesdraft-thinking.ts,decision-why.tsTool definitions forthis personcomposeCapabilities,composeToolsNo examples file:examples sit insidemodule promptsclara-leasing.ts6. The modelText and email turnclaude-sonnet-5,model-tiers.tsStaff desk text turnclaude-sonnet-5-5Tool loop, up to 10roundsmodelCall, handleToolCallTools run: book tour,work order, renewal, askagent/tools/index.tsSide checks onclaude-haiku-4-5reply topic, email type,escalated topicAnthropic API, keyrotation, no fallbackmodel foundplatform/ai/client.tsVoice and otherchannels: envCLAUDE_MODELdefault claude-sonnet-4-67. Guards after themodel, no AIStrip leaked reasoning,markup, promptoutbound-safety-pipeline.tsEmpty draft rescueempty-final-fallbackWeekday dates, tourtimes from this turnweekday-date-redraftWork order andunit-count claimsgroundedturn-integrityFair housing and promisebackingrunOutboundSafetyChecksRemove private infostripOutboundPIINo dashesenforceNoDashesMade-up facts guardhallucination-guard.tsFinal re-checksendGateFindingAnomaly review, may holdanomaly-review-gateHand-off promise rewritestripAllHandoffPromiseClausesHold hook at the replyrowdeferred-reply-row.tsOpt-out withhold, textsopted-out-reply.tsWrite the reply rowsaveConversation8. Output gatesStay quietsuppressedBy reasonsHold for approvalreply-hold-decision.tsRouted backstop holdsupervised-reply-rule.tsApproval card: Slack,email, dashboardheld-text.tsPolicy skip: person tookover, test senderdispatch-envelope.tsText door: opt-out,Supervised, ceilingtwilio/client.tsEmail door: module,Supervised, company livecompany-live-gate.tsSend: Twilio, SendGrid,Outlook, PMSdispatcher.tsAsk for help: open anaskopen-matter.tsPage the managerpage-property-manager.tsAlert engineering:Sentry, #alertslogging.ts, notify.ts9. Saved and sideeffectsConversation andmessagesconversation-writer.tsHeld draftsescalation-hold.tsAsks (EscalationMatter)escalation-matter.tsTurn outcometext-outcome.tsTraces and snapshotsturn-snapshot.tsRefusals and touch countmodule-refusal-log/record.tsPMS outbox to AppFoliopms-write-intent-outbox.tsPromise ledger, checkedafter a quiet spellpromise-ledger.tsStuck ask posted toSlack alertsstuck-matter-surface.tsDark: team-notify engineteam-notify/setting.tsDark: emergency callchainemergency-alert-chain.tsDark: manager actionreminderspm-action-reminder-triggers.tsGas or CO words: canned leave-and-call-911 reply and a page to the manager, no model involvedstepmodel, tools, askhold, safety, pagemessage leavesoff by default or absentRead from origin/main edfd125bdc on 2026-10-25. Bold text is the plain name, grey text the code file or function.
The whole machine, left to right: who writes in, entry points, fixed rules, inputs, prompt layers in order, the model, guards, output gates, and what is saved. Dashed boxes are off by default or absent. Scroll sideways on small screens.

What a turn gathers

Everything Clara reads before she answersClara's turnone model loop onclaude-sonnet-5 (staff desk:claude-sonnet-5-5) with thetools for this personconversation-manager.tsConversation historynewest messages that fit 80,000 tokens; firstmessage always keptapplyContextWindow [shared]Knowledge blockcompany sections then property sections, all ofthem, no searchleasing-knowledge-block.ts [shared]Who is writingperson, tenant by phone, unit and occupancyidentity/resolve.ts, resolveTenantOccupancy[shared]Prospect and guest cardprospect record and the listing card for thereplygetProspectByPersonId [leasing]Lease answerslease terms for resident questionsresolveLeaseAnswerContext [tenant comms]Renewal stateopen renewal, notice days, paperworkbuildRenewalPromptBlock [renewals]Turnover contextmove-out and make-ready jobsresolveTurnoverContext [maintenance]Company and property settingsteam facts, office and tour hours, applicationlink modebuildTeamFacts, readOrgTourHours [shared]Company voicenever-say list and language onlycompany-voice.ts [shared]Personathe name Clara is fixed in code; no per-companypersona foundclara-personality.ts [shared]Open asks and held stateopen asks to staff, whether a reply is on holdmatter-context.ts, deferred-reply-row.ts [shared]Opt-out and muteread at the start of the turncheckSuppression [shared]PMS messagesonly as rows inside history; no separate PMSlookup foundbuildClaudeMessages [shared]Turn notesdone actions, open units, local time, scheduledwakeconversation-state.ts [shared]Outlined in colour: used by one module only. Grey outline: shared by every module.
What one turn reads. Knowledge is a full dump of the company and property sections, not a search. PMS messages arrive only as history rows. The persona name is fixed in code.

The output gates, in order

#Gate (text reply, in order)What makes it fireOutcomeWhere email differs1Stay quietconversation-manager.ts suppressedByThe turn returns no text: a person took over the thread, opted out,muted, conversation ended, farewell or runaway loop, a tapback,team-inbox silence.quietAlso: private notes, a leadclaimed by another lane, relay orlisting-site senders.2Turn failedhandleInboundTurnFailureRate limit or error. Nothing goes to the person; it is logged toSentry and the error is rethrown.quietSame.3Hold at the reply rowreply-hold-decision.tsshouldHoldClaraReplyHandyman texts are Supervised, or the hold rule below says thereply's topic, recipient or routed module is Supervised. Staff arenever held.holdSame rule, asked throughsupervised-reply-hold.ts.4Hold router answersprocess-envelope.tsRepair acknowledgements and the handyman divert, at a building whereMaintenance is Supervised.holdNot on email.5Routed backstopsupervised-reply-rule.tsroutedModuleSupervisedAtThe module the router chose is Supervised (residents, not urgentrepairs).holdOutlook lane checks company livefirst; PMS lane checks 'humanreplied' first.6Write the holdheld-text.ts holdTextDraft saved, card to the company's Slack channel, reviewers emailed,dashboard page. A resident gets one fixed 'we got it' text. A rolloutplan can release it at once.holdbake-gate.ts holds the email; the911 reply is never held.7Policy skipdispatch-envelope.tsapplyOutboundPolicyTest or stress sender, a person took over, a human already replied,texts switched off (not for replies).refuse'Human replied' found only in thePMS lane (unverified elsewhere).8Door: opt-out and safetytwilio/client.tsrunOutboundTextComplianceGateHarness off switch, canary, STOP opt-out, AppFolio code texts,stress, test recipient, flipped-line check.refuseEmail door: test recipient.9Door: module off or SupervisedshouldHoldClaraReply doorModule switched off refuses. Supervised with no approval refuses;urgent repairs pass.refuseSame check incompany-live-gate.ts.10Door: company liveoff-means-off.tsCompany not live yet. Text replies always pass this check.passEmail: refused and logged asBLOCKED, not held.11Door: contact ceilingcheckTouchBudgetToo many touches to this person.refuseEach email door has its own.12Senddispatcher.ts, adaptersTwilio text or the PMS text thread.sendSendGrid, Outlook, Gmail or thePMS thread.13After the sendfileStagedGuestCardTextNotesAfterSendRefused: row marked not sent. Sent: provider ids stamped, guest-cardnote filed to the PMS outbox.sendPMS 'email sent' entry (detailunverified).The hold rule (supervised-reply-rule.ts decideHold), first match winsR1The reply's topic (renewal or maintenance) belongs to a Supervised modulehold, except urgent repairs to a non-prospectR2A renewal tool action was recorded instead of run, and Renewals is SupervisedholdR3The module the router chose is Supervisedhold, same urgent-repair exceptionR4Renewal thread or open renewal, topic 'other', not staff, Renewals SupervisedholdR5The person is a prospect and Leasing is SupervisedholdR6The topic check gave no answer and anything is Supervisedhold, unless urgent or a known lane not SupervisedR7Anything elsesend; a held reply can be released at once by themodule's rollout percentThe topic check (claude-haiku-4-5) answers only renewal, maintenance or other; leasing is decided by the person being a prospect. 8 code paths ask shouldHoldClaraReply.
Output gates for a text reply, in the order the code checks them, with where email differs. Email lanes do not share one order: the Outlook lane checks company live before the hold.

Shared versus module-specific, from the code

ConceptOwn copies todayTargetShared coreLeasingMaintenanceRenewalsTenant commsInvented by the module
Hold decision for a reply00 · sharedsharedsharedsharedsharedsharedurgent-repair carve-out, handyman mode, deferred renewal actions
Review door for automated sends30 · sharedsharedown copyown copyown copynoneone review door per module
Held draft store00 · sharedsharedsharedsharedsharedsharedrenewal actions wait on the hold
Ask for help (hand-off)20 · sharedsharedown copysharedown copysharedtour update email, renewal manager email
Topic classification40 · sharedsharedown copyown copyown copyown copytour intent, repair triage, renewal decisions, lease questions
Knowledge00 · sharedsharedsharedsharedsharedsharedappliance manuals, listing search
Person lookup30 · sharedsharedown copyown copyown copysharedspoken address matching, renewal name match
PMS write30 · one adaptersharedown copyown copyown copynoneguest-card outbox, work orders, renewal offers
Reminders and follow-ups40 · sharedsharedown copyown copyown copyown copyoutreach cadence, repair check-ins, renewal ladder, morning digest
Quiet hours20 · sharednonenoneown copyown copynonetwo copies, one mirrors the other; kept as door parameters: the handyman's own window, each lane's wait walk, renewals refusing a building with no time zone
Tone and style00 · sharedsharedsharedsharedsharedsharedmodule rules layered on the shared voice
Prompt examples44 · one formatnoneown copyown copyown copyown copyno shared examples file
Tool set4shared + a few per modulesharedown copyown copyown copyown copyeach module brings its own tools
Intake question flow20 · sharednoneown copyown copynonenonelead intake, repair intake
Scheduling30 · sharedsharedown copysharedown copyown copytours, repair visits, key pickup
Staff notice sender30 · sharedsharedown copyown copyown copysharedtwo 'one doors' in core plus three module senders
Module-off refusal30 · sharedsharedown copyown copyown copynonesame refusal written three times
Module entitlement30 · sharedsharedown copyown copyown copynonesame check written three times
Offer saga and packet11 · keeps its ownnonenonenoneown copynoneRenewals: offer saga, auto-start scanner
Tour pipeline and guest card11 · keeps its ownnoneown copynonenonenoneLeasing: tours, guest-card write-back, application link
Work order triage and vendor dispatch11 · keeps its ownnonenoneown copynonenoneMaintenance: triage, vendor chase, on-call chain
Lease answers and key pickup11 · keeps its ownnonenonenonenoneown copyTenant comms: read-only resident answers
Shared core versus own copy, per concept. Hover a cell for the file. Tenant comms has no module folder; it is the resident-services tools, so its 'none' cells are expected, not gaps.

About 47 own copies today, 4 of them legitimate. Every other row collapses by the same move as the hold seam: one door, byte-identical on the frozen baseline's 5,515 cells, then delete the copies. One small PR per row, ordered by what breaks most today: first the hold (one door at all 8 callers, PR #22450 merged Oct 25 night; the six backstops stay as call points of that one function, each guards a path the earlier check never sees; PR #22473 folds the first-email check in and adds the first no-duplicates check). Then ask for help and staff notices together (the askTheTeam seam, being built now), then topic classification, then the rest. The 47 to 4 count is implementations, not call points. The tracker carries one row per concept so the own-copies count is visible falling.

Inventory · Oct 23 to 27

What is built since Friday (Oct 23 to 27)

Snapshot Oct 27 2026 ~03:00Z; live state stays on the phase tracker.

BucketItemsPRs
Done: live and proven end to end with record ids1047
Merged, not proven: needs a live run1248
Merged, not proven: no-change refactors (the frozen replay is their full proof)511
In progress138
Not started100
Decided by Fede18—
Open for Fede7—

Done: live and proven end to end

What it doesPRsProof
Tenants hear the work order number from the PMS, never our internal id#22174Willows, Oct 24: confirmation and follow-up texts delivered (SM1842cb13, SMfe3c9d3f): "Your work order number is 3319."
Clara's intro texts go out from the building line#22373Willows: three texts delivered to Fede's phone (SM6bfa46f5), conversation fcd0c46b Tracker: merged, unproven
A listing special is said beside the rent every time the home is named, and never copied into the knowledge base#22524, #22527Willows, Oct 26: draft says "$1,595 a month, and if you move in by November 30 you'll get your first month free"; inquiry 5af0eeb3, draft eschold_cb020a76. Drafts mode, nothing sent Tracker: proven
Checks only block; a held first email gets one writer retry before it is held#22249, #22500Willows, Oct 26 3:49 PM MT: first draft failed a check, the retry passed, email delivered; inquiry 2299df14, conversation 60ee2d3f Tracker: proven · merged, unproven
A reply Clara sent late no longer shows a false "draft held" card on the thread#22208Production screenshots of the real Western Slope thread, before and after. A truly held draft was not checked live (none existed)
Rating buttons on the Slack shadow cards save to our grading records#22411; bench #26; relay #1472, #14929 real presses Oct 25 to 26 (8 Fede, 1 Gera), each tied to a message id, on the bench's human-labels page Tracker: merged, unproven · part landed
The bench can replay a real recorded turn read-only, and never posts to Slack while it does#22151, #22152, #22173, #22179, #22201, #22238, #22351, #22386, #22324, #22327, #22329Used on production Oct 24 to 25: a recorded Willows turn (tsnap_aa2fa121), 20 repair episodes run through it; the rerun after the 97-card Slack incident posted 0 cards (session notes)
Clara Bench app, runner and the frozen baselinebench #1 to #21 (20 PRs)Baseline row adopted Oct 25: on tenant texts the office already answered, today's Clara would reply on 82 of 96 (85% noise) Tracker: proven (evidence)
Replay harness: every hold decision on the real book frozen and diffed after each change#224455,515 decisions frozen from production read-only Oct 26; used as the merge proof on 9 later PRs Tracker: part landed
Opus 5.5 shadow cards on Slack for Western Slope and Situs tenant texts, nothing sentbench #22, #23, #24, #25Real cards posting and being rated (row above); review set 3 built from 46 of them Tracker: part landed · part landed
Office-opened thread gets no Clara turn (#22509) and one topic classifier (#22519)#22509, #22519Willows live run Oct 26 night, thread 8ffa78e8 Tracker: part landed · merged, unproven

Merged, not proven: needs a live run

What it doesPRsWhat was checked, and what is missing
First email writing: opens like an agent, rent and size line, tour times kept, no dashes anywhere, asked size at another home, a lease phrase is not a tour promise#22061, #21992, #22175, #22178, #22185, #22236, #22292, #22317, #22485Replays of 23 to 95 real cards. No Willows first email on the deployed code for these paths Tracker: part landed
First email: a draft that is a note about the renter is held; a held draft goes to the review card#22314, #22336, #22542Willows run proved only "no regression" (the check did not fire); the review card ran at Willows from a laptop before merge, not on the deployed code Tracker: merged, unproven
Texts, follow-ups and call notes: checks only block, one retry, then hold#22296, #22306, #22321Replays: 117 text and email turns, 128 follow-ups, 310 calls. No live run
Tours and tour times (offered hours, drive gaps, staff blocks, cancel by email, "Saturday at 3", first open day)#21970, #21991, #22002, #22003, #22018, #22024, #22036, #22233, #22241Replays byte-identical. Willows: rescheduling passed, but the same-day case the fix was for was not run; the first-open-day run read the right times, yet the email sent was cut short by another check
When Clara stays out: shared numbers, unknown senders, staff notes, held replies, runaway stop, channel rules, no vacancy counts on calls#21861, #22058, #22218, #22515, #22077, #22080Replays of real threads. Every PR names a Willows run after deploy; none is recorded Tracker: part landed
Tenant repairs: photos reach the work order; a different problem gets its own order; one professional voice#22146, #22383, #22380Replays (17 real photos, 51 notes) and a voice eval. First proof is the next real tenant photo Tracker: proven · proven
Guest card notes written like a leasing agent#21985, #21986, #21997Replay of 24 real cards. The Willows run was promised; no record found (unknown)
Staff desk: Clara checks what was already done before acting; the two desk switches removed#22505, #22532, #22533Replay of the Oct 24 card. Live desk text tracked in issue #22514
Alerts: our failures go to #alerts only, never the customer's team; a held first touch counts as the reply; held card on the new card design#22417, #22482, #22486Unit tests and one record replay. The new held card was never posted (the Slack guard refused the sample) Tracker: proven · merged, unproven
Lead intake: no hold on a renter whose card already exists, new-lead card for email leads, held texts keep retrying#21930, #22239, #22240Replays of the last 7 days. Willows runs pending
Staff welcome: one text per role#22454Copy only; nothing sends it yet (what triggers it is Fede's call) Tracker: part landed
A "Why?" box after a rating press#22526; relay #1529Merged in the last hour; proof is the first real press Tracker: part landed

Merged, not proven: no-change refactors

What it doesPRsProof
One function decides whether Clara's reply is held#22334, #22450, #224730 of 5,515 frozen decisions differ Tracker: proven · proven
One list of which model each Clara step uses#22446Same models resolved everywhere; Opus not switched on anywhere Tracker: merged, unproven
One "ask the team" entry point over 23 callers#224550 of 5,515 differ Tracker: part landed
One review door for automated sends#225220 of 5,515 differ. Willows logs show the right call, but the text it cleared then did not send (cause unknown) Tracker: merged, unproven
Harness recorders and three real-case fixtures (held email with times, staff took the thread, office-opened thread)#22457, #22426, #22483, #22488, #22496Test-only; one real Willows turn recorded and replayed to the same reply Tracker: part landed · part landed · part landed
One ask-for-help door (#22592, 0 of 5,515 differ)#225920 of 5,515 differ Tracker: proven
One quiet-hours door (#22597, 0 differ)#225970 differ Tracker: proven (evidence)
One staff-notice sender for Leasing (#22595, 0 differ)#225950 differ Tracker: merged, unproven

In progress

What it doesPRsState
A thread the office opened gets no Clara turn at all#22509Merged and proven at Willows Oct 26 night Tracker: part landed
One topic classifier for every module#22519Merged and proven at Willows Oct 26 night Tracker: merged, unproven
"Try again" on a held first email; a 24-hour expiry leaves a clear expired state#22559Merged Tracker: merged, unproven
A held renter email never expires silently; the hold names its check#22538Open, not set to merge (tracker says it is) Tracker: merged, unproven
The follow-up writer gets the home's bedroom facts (Jessalyn)#22507Open, not set to merge (tracker says it is) Tracker: merged, unproven
One person lookup for leasing, maintenance and renewals#22506Set to merge, but has a merge conflict Tracker: proven
Rerun scripts write only to test properties#22504Set to merge, waiting on checks Tracker: merged, unproven
Staff desk: a queued application is "on its way", never "sent"#22574Merged
Shadow week—Running; the card does not yet update when the office replies later
Rating card polish (why it was held, record links)—A local change in the shadow runner, no PR
Renewals staff notices fold (building)—Being built; no PR
Module-off refusal and entitlement folds (building)—Being built; no PR
Robot phone format fix, appfolio-browser-agent#633 (merged, proven at Willows)appfolio-browser-agent#633Merged; Willows card 49 written as (404) 285-9387 by the deployed robot, read back, restored (Oct 27 02:12Z)
No-reply notification emails never become conversations, #22616 (armed, Willows proof after deploy)#22616Armed, Willows proof after deploy Tracker: part landed

Not started

What it doesDepends on
Situs Group onboarding package: Clara's intro to their team, what she does, who owns whatNeeds only the baseline, which is done
Hand-off fixes to live behavior, and a "did a person already reply" signal from AppFolioWaits on the ask-for-help fold
Tenant replies, dark: maintenance first, renewals secondWaits on the hand-off fixes and the full-context bench
PMS inbox behind one interface, then the review with numbersLast in the chain
The rest of the cleanup: 9 more one-door folds (PMS writes, reminders, quiet hours, intake questions, scheduling, module off, entitlement, tool set, prompt examples)Waits on the ask-for-help and topic folds
A text with two repair issues can lose oneNot started
Repeat messages on one guest card (7 sync bugs)Waits on Fede's pick of design A
Opus 5.5 as a bench row against the frozen baselineThe model list is ready
Smith's Slack cards on the one card designThe shadow card part is done
Replay harness gaps: the tour loop calls the model outside the recorder; phone and clock not pinnedFiled as #22458

What Fede decided

Open for Fede

Feedback audit · Oct 23 to 27

What Fede said, Oct 23 to 27

Snapshot Oct 27 2026 ~04:00Z. We read every message Fede typed to Clara lanes 001 to 006 from Oct 23 00:00 UTC to Oct 27 02:02 UTC. There were 1,438 messages, 57 of them status nudges. We found 136 distinct pieces of feedback. Live state for each item is on the phase tracker (rows 58 to 70).

Status of the 136 itemsCount
Done: a standing rule, decision or page41
Merged and proven7
Merged, not proven20
Designed or PR open16
Recorded only (memory or page line, nothing built)34
Not applied16
Built, but not reaching him2

Not applied, most important first

These 18 items have nothing in place yet. Two of them have code merged, but Fede's own words after the merge say it does not work for him. Items 9, 10, 14 and 16 to 18 are questions or grading work, not builds. All six sit on tracker row 70.

#StateWhat he said, and what existsTracker row
1Built, not reaching himWhat do we do with this data? How does it relate to Cerberus? Is the Slack feedback used? Will you use the examples I graded? Slack ratings became the bench's human column (clara-benchmark#26, merged 3:53 PM MT); per-text rows #22622 open. The label summary still reads 0 judged. Nothing shows his 52 voice verdicts from the review set loaded as truth. (first said 10-26 12:31)58
2Built, not reaching himAppFolio work: exponential backoff, a queue or circuit breaker, a dead-letter queue. Never give up; alert when it fails. Only the retry count changed: #22240 (retry to the age cap, not 10 tries) merged 10-24. No exponential backoff, dead-letter queue or failure alert in any PR or on the page. (first said 10-24 14:27)59
3Not applied#34: "the leasing agent will meet you at the home, what day works?" fails. Always offer real availability ("number one rule"). The production no-tour-times check exists, but nothing grades an answer with no times as a fail in the bench. The same check false-fired on Trang. (first said 10-23 19:42)60
4Not applied#33: too many "I'll check with the team" when the knowledge base already has the answer (pets). Verdict is in the review set. No check, fixture or bench column scores a "check with the team" deflection when the KB holds the fact. (first said 10-23 19:41)61
5Not appliedCard notes still in the old "Email Sent" format. "please dont tell me its off ina feature flag". Not behind a flag: the third piece (one line per exchange instead of full email copies) was never built. (first said 10-26 17:25) Oct 27: a builder is on it now (not merged).62
6Not appliedA nameless callback email went out. The rule: no basic info like a name, no callback. 004 memory nameless_callback_note: "if Fede reaffirms, the fix is one PR". He did reaffirm here. No PR. (first said 10-23 10:58) Oct 27: a builder is on it now (not merged).63
7Not appliedA mass text from the office is not a reply. Bench pairing still counts mass texts as staff replies. The baseline notes "tenant-other judge column invalid (pairing), v1.1 re-pairs"; v1.1 not done. (first said 10-23 19:01)64
8Not appliedDavid Jones: duplicate card. Why no reply? Go deep. Root cause recorded (AppFolio made both cards). The real bug, an Outlook 550 bounce not treated as a dead address, has no PR. (first said 10-26 17:24)65
9QuestionClara could have helped if she could read the lease. What would it take, and what share of questions need it? Plan only. Memory says "read the lease before no info on file". No plan or percentage on the master page. (first said 10-23 19:25)70
10Question"i was suppposed to review more". Three review sets are still ungraded: the 15-pair first-email review, review set 3 (25 tenant texts) and items 28, 31, 32, 35–40, 43, 54–58 and 64. (first said 10-26 19:59)70
11Not appliedSitus alert fires on every tenant text the team has not answered ("handed to the team" not skipped). "this needs to be fixsed". No tracker row or PR. The merged reply-late fix covers held prospect emails only. (first said 10-26 08:59)66
12Not applied#27: voucher question. Isn't accepting them Colorado law? Production deflected to the team. Verdict recorded. No knowledge or prompt fix found for source-of-income questions. (first said 10-23 20:55)67
13Not appliedDoes the bench include the emergency categories and policies? A water leak is usually urgent. No emergency policy in the bench context or prompt found. (first said 10-23 21:06)68
14Question#39 "McKinsey" comment: a prospect asked whether McKinsey is in Lakewood and similar in size. Not recorded. JSON #39 is a different (Spanish) card now, so this comment matches no item. (first said 10-23 20:57)70
15Not applied"it should not tag me and gera". No PR or row found. (first said 10-26 09:22)69
16QuestionWhere does shared code live? How do Gera and I avoid adding duplicates? Unanswered. The only related item is the "first no-duplicates check" inside the open shouldSpeak PR 2. (first said 10-25 22:08)70
17Question"we have a ton of wip nwith nothing done done". A WIP limit was proposed. No WIP limit on the page or tracker. (first said 10-26 15:43)70
18QuestionSales target: can we promise 50% fewer tenant messages for the office, short term? Question; no answer found on the page. (first said 10-23 21:30)70

Two updates from the session on Oct 27. First, the run order and the question of maintenance before the hand-off are answered. The order is: the pure split on the same Sonnet model with all folds first, then Opus, then tweaks. The gates fold first (tracker rows 52 to 56), then get attacked. The hand-off goes out when the last fold merges. Second, the rating "Why?" box went live at 21:53Z, and no one has pressed it since. PR #22622 fixes a bug where the same verdict on two texts collapsed into one record.

His grading verdicts, as acceptance tests

Fede graded the review set by voice on Oct 23, 7:00 to 9:25 PM Mountain time. 52 of its 68 examples have a recorded verdict. Every "wrong" or "should have" verdict is a test the next Clara must pass. Items 1 to 24 are tenant texts, 25 to 36 are prospect first emails, 37 to 40 are Spanish prospect emails and 41 to 68 are repair episodes. Not graded yet: #28, 31, 32, 35 to 40, 43, 54 to 58 and 64. His comment on "#39 McKinsey" matches a different card from the one now listed as #39, so it needs a regrade.

#KindRecordCustomerHis verdictHis notes (shortened)
1tenantsitusgroup:1162667257Situs Groupoffice reply unrelated"this is unrelated" — the office message shown is a mass pest-control notice, not an answer to this text; the Clara-vs-office comparison on this row is void.
2tenantsitusgroup:1156407909Situs Groupmissing contextv1 page showed no thread; "Hola buenos días" then an office reply about keys looked disconnected; re-grade on v2
3tenantsitusgroup:1156452641Situs Groupmissing context"I have a question" / "what is the question" with the real question missing from the page; re-grade on v2
4tenantsitusgroup:1157467044Situs Groupmissing context"is the office open tomorrow" answered with "did you leave the keys" looked disconnected; re-grade on v2
5tenantsitusgroup:1156660644Situs Groupdecent, missing full pictureoffice knew a pest-control rotation and added the unit; Clara started a work order and asked where the roaches are, "not terrible"; gap: no access to the pest-control…
6tenantsitusgroup:1157904179Situs Groupconcerningly badoffice had a payment plan in progress (DocuSign); Clara sent the generic portal link. Root cause: context gap, thread copy starts Sep 30, no balance / delinquency…
7tenantwesternslopepm:1227637967Western Slopetricky; reply is fine but do not announce closing the work orderthe tenant is answering Jay, so no reply to this text. The miss is upstream: once Bernie finished the smoke alarm replacement (Oct 7), the maintenance side of Clara…
8tenantwesternslopepm:1223901781Western SlopeClara greatthe office reply was not helpful ("put in a maintenance request"); Clara did great. Wants to see what happens after: would she have filed the work order, and correctly?
9tenantwesternslopepm:1233332378Western Slopewrongadding a note to the work order is wrong; expected an acknowledgement plus an FYI to whoever is assigned (handyman/vendor): "tenant wrote the garage is open, dog in…
10tenantwesternslopepm:1228104701Western Slopemuch better than the office, fact-check"much better than the office", asked to fact-check. Checked: balance snapshot the same day 3:06 PM shows $0.00, last payment $1,461.25 on 2026-10-08; Clara's amount,…
11tenantwesternslopepm:1228220222Western Slopefact-checkfact-check the LLC name. Checked: Cheryl had written earlier in the thread that the check must be made out to "1240 Elm Apts, LLC"; Clara took it from the thread.…
12tenantsitusgroup:1156656567Situs Groupnot terrible, not greattenant said "keys" plural with a photo; Clara asked whether both the door key and mail key arrived, an unnecessary extra question. Clara never saw the photo…
13tenantsitusgroup:1165765179Situs GroupimpressiveClara referred back to what a teammate had said earlier in the thread and did not invent a "you will not be charged" line; "this one is impressive".
14tenantsitusgroup:1157467286Situs Groupshould have stayed quiet"you can leave the keys in the apartment" is a human call; we cannot know that is OK or who would act on it. Stretching the limit.
15tenantsitusgroup:1167038035Situs Groupshould have stayed quieta person from the office already started this conversation; Clara chiming in with "thanks for letting us know" adds nothing and can confuse. Pattern: when the office…
16tenantsitusgroup:1156851472Situs Groupgoodthe office had sent a parking mass text and people reply "not my vehicle"; Clara saying "no worries, that went to everyone" saves the office time.
17tenantsitusgroup:1168357453Situs Groupgood"the reply is good" (Clara added the dryer details to the work order). Miriam's real reply next morning is a real reply, not a mass text; the mass text in the thread…
18tenantsitusgroup:1159276074Situs Groupgood"A+". A perfect reply for something that needs no human: we know the office address.
19tenantwesternslopepm:1223153146Western Slopewrongno team item at all in phase 1, the team already watches this inbox; "chime in when helpful, otherwise shut up". Unanswered items go to a daily digest after 24-48 h…
20tenantwesternslopepm:1223201287Western Slopeshould have stayed quieta nuanced one. The paperwork is the basic annual recertification (affordable housing, urgent) plus a lease amendment; Clara had no knowledge of either, so no reply…
21tenantwesternslopepm:1223646502Western Slopeshould have stayed quiet"again, noise. Terrible." Another team item on a thread staff can already see.
22tenantwesternslopepm:1223825094Western Slopeshould have stayed quietworse than 21: escalating what a human is already handling. In AppFolio the person on the conversation already gets an email per reply; a Clara item on top would be…
23tenantwesternslopepm:1232199367Western Slopegray areasilent is defensible, but the tenant is updating permission to enter (handyman may go in if nobody answers). The right logic: check the work order; if the permission…
24tenantwesternslopepm:1228227768Western Slopegoodsilent is right. Anything physical and immediate ("are you there?", "I'm on my way") is something the AI cannot know.
25prospect66b1eebcCamelliaproduction betterthe original production email is better, more human. Short prompt: "Camellia Apartments is open now" is wrong, that is a community, "open now" belongs to a specific…
26prospectcea1aec8Western Slopeproduction better (tone)the production email is great. The short prompt changes the tone too much ("Because it's open now, you can move in as soon as you're ready"); he wants the same Clara…
27prospect553d9000Western Slopeshort prompt better"Yes, we accept vouchers with the same screening as any other applicant" is right. Production deferring the Section 8 question to the property team at the tour is…
29prospect441766afWestern Slopeboth wrongneither offers a time range, so he does not trust either as current. Opus again says an agent will meet them (unnecessary) and dropped the 4-bed/2-bath, square feet…
30prospectd45b5be2Western Slopetoday betterproduction draft offers a time range, good, but uses an em dash ("an AI tell", new rule: never em dashes). Opus: "on the special you saw, I'll check with the team and…
33prospectc37d5234Western Slopeboth wrong"why so many check with the team? This is all in the knowledge base already." Verified: both arms had the identical knowledge (pet deposit $300, pet rent $35, cats…
34prospectae9e19cbWestern Slopeboth wrong"a leasing agent will meet you at the home" again, and "what day and time work for you" with no real availability. "We always need to offer real availability. That's…
41episodeG:dump:2550_5657:2026-08-03T10:35:00Situs Groupwrong work order: one work order, not threethe tenant listed three problems in one text; Clara filed three work orders, the office filed one. One work order makes more sense; do not split one tenant report…
42episodeG:dump:2072_4578:2026-04-15T14:08:00Situs Groupwrong: should have replied and actedmisspelled Spanish (ola, ban, abotar) from someone with little schooling, but the model can read it: the shower knobs do not work and may burst. Clearly a maintenance…
44episodeG:situsgroup:1156660644Situs Groupgoodgood (asks where the cockroaches are, permission to enter, photo).
45episodeG:dump:1767_3810:2025-08-09T06:51:00Situs Groupwrong: should have filedthe window seal fell off, a very clear work order. Silence plus no office reply for 3 days is bad; we could have filed the work order and asked for details.
46episodeG:westernslopepm:1226021456Western Slopewrong: should have triaged"was the AC turned off?" Clara should have asked clarifying questions, checked whether a work order already existed (there was one) and triaged it, instead of staying…
47episodeG:dump:1857_4048:2026-06-16T15:18:00Situs Groupwrongshe answered only the clogged sink and ignored the renewal request entirely, and the flooring (carpet is nasty, everyone else has hard floors). Bad.
48episodeG:dump:2199_4885:2025-08-31T11:12:00Situs Groupshould have filed3 keys for 5 tenants is a work order.
49episodeG:dump:2015_4422:2024-09-16T21:04:00Situs Groupshould have filed, emergencya leak in the laundry room is an emergency work order, high priority, not silence; it should match the emergency policy in context.
50episodeG:dump:2279_5101:2026-05-14T08:06:00Situs Groupcannot grade: our copy has no toilet work ordernot enough context; was there a work order, who was it assigned to, was it done? Maintenance needs much more context: outstanding work orders, assignment, closed…
51episodeG:situsgroup:1156192039Situs Groupcannot grade: thread context was missingincomplete context, something was said before. Thread rows added to every episode after this.
52episodeG:situsgroup:1156752809Situs Groupwrong: should have filedfilters are broken, a very clear work order; silent is bad. Why is it missing so many work orders?
53episodeG:dump:1245_2407:2025-12-30T13:31:00Situs Groupcannot grade: incomplete contextincomplete, hard to judge; but a maintenance issue. Maintenance needs a lot of dialing in.
59episodeG:situsgroup:1168357453Situs Groupgoodgood, adds the dryer details to the existing work order (assuming there was already one).
60episodeG:dump:1583_3348:2025-01-17T17:31:00Situs Groupgoodgood. Emergency, bucket or towels, photo. Asking permission to enter when not home is redundant on an emergency where someone is dispatched right away; not terrible.
61episodeG:dump:1813_3961:2024-04-22T22:02:00Situs Groupgood with a nuance: property-level vs unit-levelthe washer is in the basement, a shared area, so this is a building issue; Clara asked which room or wall in her unit and about entering her unit. Tricky: when does a…
62episodeG:dump:2141_4749:2026-04-01T16:08:00Situs Grouprepair filed ok; name update missed; commercial treated as residentialthe name correction was missed (edge case; maybe a tool). Chase Tower suite is a commercial building and Clara treated it as residential ("can they come in if you are…
63episodeG:dump:2191_4862:2026-01-26T09:18:00Situs Groupgood"A plus". Structural damage is maintenance; filing the work order and asking the few questions was right. Fede, later: Clara should also have acknowledged the renewal…
65episodeG:dump:2260_5065:2026-06-20T19:07:00Situs Groupgood, minorfunny one. Did the tenant send a picture? Clara did not ask for one and our copy has no attachments. Minor.
66episodeG:dump:2355_5245:2026-03-05T18:07:00Situs Groupgood, minor nitdishwasher not working; Clara asked for a picture, which does not help much for an appliance that does not run (a video might); minor nit, do not over-index on…
67episodeG:dump:2493_5543:2026-08-10T22:34:00Situs Groupduplicate of #64Same text, same tenant, second tenant record (new lease Jun 2026). Graded with #64.
68episodeG:dump:73_291:2026-08-31T15:41:00Situs Groupgoodshared laundry washer, filed as property-level, asked for a photo of the display. Noticed no work order number was sent: production always quotes the number; the…

Named cases he raised

CaseCustomerRecord idsWhat he saidTest to pass
Taylor (former tenant)Western Slopepers_794b2bc7-9b0d-4d6e-9a90-a48fbae4c104 · thread 470977e2-8c9b-4467-8d65-fea18677993310-23 09:25 "why did we reply here", "formet tenant needs to be foleded into the same tenant guardrails"A former tenant or unknown role gets no reply.
Lori RuizWestern Slope (Pomona Park)pers_06d179ba-d24c-4a49-967b-29522a3f6eab · thread bdaed90a-f0bf-41ba-a2ab-eff6ecfa5aef · card 304110-24 14:03 "whywould we say weekend tours need to be booked by friday"; 10-26 17:29 "why is it +970 and not +1 or no plus?"No made-up booking cutoffs. The card phone stays in a format AppFolio links to the text thread. Her reply reaches the conversation.
TrangWestern Slope (Ember Estates, card 3047)pers_08d5ec68-a7f1-4323-b4c3-d14831ea0905 · thread b26a5299-5901-4e9e-974f-9675d22f7255 · intent gc:schedule_showing 5e0d4682-1fad-5aa3-99f6-8056ae07d9fc10-26 09:10 "why didnt we offer is the open question"; 09:20 "doesnt ember estates have a promotion?"The first email offers real tour times and the listing special, is not held, and a building tour books on a best-guess unit.
Patrick OsborneWestern Slope (Northridge, card 3048)pers_2fdc2da9-1241-470d-9e1d-2b7e5fb63448 · thread bbc825d1-3571-48db-a51c-cc4e13b247c410-26 09:48 "so not here kat is talking to this person"; 11:33 "a test shoul dnever w[rite]"Clara stays out while staff are on the thread. Tests never write to his record.
AustinWestern Slope (2841 Morningside)pers_62402c98-2573-417b-90c6-e7b30557e563 · thread 9cc7dc8f-1786-4576-bf92-52dce34ebab010-26 11:04 "well this should not have been a hodl at all"Thread opened by staff: no draft, no hold, on any channel.
AnthonyWestern Slope (2841 Morningside)pers_8f205968-ad0a-479e-9f66-e926aa875c46relayed 10-25 14:20 "never email the customer when something on our side fails"An internal failure goes to #alerts only.
Luke BurriesciWestern Slopepers_ef28f50d-71a8-49d7-91f9-bee5100397e8 · thread 99e5e0f8-8b9c-4f8f-8384-a0e3d60cf57c10-26 17:22 "why is this email even makign it into our conversations?"An AppFolio notification email never becomes an inquiry.
David JonesWestern SlopeAppFolio prospect 09da9c79-d0ef-11f1-b01d-02a2910905a910-26 17:24 "why didnt we reply to david jones?", "go deep fidn out whey"An Outlook 550 bounce marks the address dead. Duplicate cards are AppFolio's.
HeatherWestern Slopepers_878b6e8d-b568-4df5-8ac5-16f4de47fd5e · thread c9f809af-2a67-47dc-8731-55dac75ee51a10-26 10:49 "what hte heck?", 11:09 "if we already send it we say i already send it"Never tell a renter "send it yourself". Read the card; if the application was already sent, say so.
Emelyn Castillo ValdezSitus (Dahlia)AppFolio prospect 0d176c30-d143-11f1-b01d-02a2910905a910-26 08:24 "we didnt anser the utiliyt question"A follow-up question on the same card gets answered.
Genesis Diaz (three cats)Camelliapers_779ddb81-1cde-4097-a2e3-b15a5d55569c · thread 3d62aa84-a6cb-4e32-acc9-5b26333807f010-24 08:50 "i didnt ask for any changes"No fixes he did not ask for.
MarissaWestern Slope (Pomona Park)unanswered since Sep 2410-26 14:05 "please dont this eery again, thi sis way too in the past"Never offer to recover stale leads.
Nameless callbackWestern Slopeconv_voice_f9e839a610-23 11:12 "i had said if they dont provide basic things like name we dont do a callback"No name means no callback email.

The leasing verdicts are now acceptance rows in the bench store, outside the locked v1 sets: #27 (vouchers), #33 (no "check with the team" when the knowledge base has the answer), #34 (offer real tour times), #39 (needs a regrade), Heather (read the card, never "send it yourself") and the nameless callback (no name, no callback email). File: ~/.clara-bench/sets/v1/fede-verdicts-leasing.acceptance.json. Fede also pressed the Slack rating buttons 8 times on Oct 26. None of the 8 presses carries a reason.

The scratch file holds his full words: every item by topic, all 1,438 messages in order, and his full verdict notes. Path on the Mac mini: /private/tmp/claude-501/-Users-federicochapa-agents-001/efdb403c-4197-4ea2-967a-9f1fd47f77cc/scratchpad/fede-feedback-oct23-27.md. Phones and emails are removed. One pasted credential is replaced by [credential omitted].

Open question (Oct 27): who decides the topic, and what does "unsure" do?

From Fede's call with Gera on Oct 27 (raw transcript, 13 thread chunks in #transcripts). Gera is looking into it; this is recorded as an open question, not a decision.

Gera on the callOur pages today (Fede's Oct 23 and 25 rulings)Idea on the table
Who decides the topicA separate classifier runs before the on/off check; it gives a best guess on the first message and corrects earlier messages as the thread goes on; add a confidence score and go quiet when unsure.The one model decides the topic inside the writing call; no stacks of small classifiers; the code layer stays thin.Keep one model deciding, and have it return topic plus confidence as part of its answer, so "unsure means quiet" exists without a second classifier. Caution: the two silences Fede rated Wrong today (Rachael, Elizabeth) would get more common under "quiet when unsure", not less.
Owner: Gera (looking into it). Related: tracker row 30 (topic door, #22797 merged Oct 27), row 82 (deep review of ratings and holds).

Second opinion on the approach (Oct 30)

Fede, Oct 30: "we need a second opinion on our approach, don't think this is working well." Two independent read-only reviews from one shared brief, Opus 5.5 and Fable 5.1 at max thinking.

Where they agree

FindingBoth say so
The first-email prompt was never actually split (65k to 68k tokens per first email, plan said 7k to 19k) and grew 14% this week.Yes
The facts block reads vacant units, not posted homes, and nothing checks it against the public listing.Yes
The bench sample has 0 Situs, 0 Spanish, 0 reply turns and its judge trusts our facts block, so it cannot see Fede's misses.Yes
Opus is worse than today's Clara on the live prospect cards Fede saw (5 of 7) because it obeys wrong inputs Sonnet ignored, better on tenant texts and on the frozen bench.Yes
Stop per-card prompt patches and stop using the Day 0 compare as proof for prompt changes.Yes
Fede's ratings become the bar.Yes

Where they differ

TopicOpus 5.5Fable 5.1
Swap bar size40 blind pairs, Wrong at most 4Last 25 paired cards, Wrong 1 or fewer, 8+ Situs
Tenant-text work in this laneStop (Gera's hand-off)Does not raise it
Extra checksNone addedPrompt coherence check with a planted-conflict control, plus a cost/latency line

Opus 5.5 review

Opus 5.5, independent, read-only.

Verdict. The direction is right, but the week did not carry it out: the leasing prompt got bigger, not smaller, and the bench that says PASS cannot see the customers, message types or mistakes you rated. On prospect messages Opus is worse than today's Clara (today better on 5 of 7, by your own notes on each pair) because it does exactly what our prompt and facts say, including the wrong parts; on tenant texts it does better.

1. Is the approach sound?
Plan pieceWhat happenedVerdict
Small job promptsNot done. A first email still gets one 273K-character prompt (about 68K tokens); the "decomposed" arm is that text re-filed plus an override block. Done-means says "decomposed"; roadmap step 2 says "no prompt split needed".Added, removed nothing
Hand the writer factsBuilt; nothing checks they are trueMissing truth check
Bench Opus vs todayBuilt with careWrong sample, judge trusts our facts
Fix inputs one at a time34 changes to the leasing prompt in 8 daysDoes not converge
Swap on your goUnchangedKeep

Structural problem: Opus obeys lines Sonnet ignored, so every wrong or contradictory line in a 68K-token prompt is a hidden Opus regression. One rated card at a time cannot find them all. None of the three done-means items is finished.

2. Why the bench passes while you reject 6 of 7
CauseEvidence
Wrong sampleRunnable items: Western Slope 39, Camellia 12, Situs 0, Spanish 0, replies 0. 4 of your 6 Wrong (Situs or replies) could never appear.
Judge trusts our recordsIts prompt: "a fact in those records or from its tools is sourced, not invented". A wrong facts block grades as correct.
No check for your complaintsMissing special, office hours as availability, "a leasing agent will meet you", unposted home: none checked.
Noisy judgeToday's Clara against itself, same 51: 19/18/14, 7/30/14, 16/25/10, 13/28/10 (better/same/worse).
Rewards over-sharingOct 30 PASS, Ember: Opus named a $2,300 home plus a second $2,550 home with the special; judged "better".
Different armsBench PASS used today's prompt; your first-email cards used the override arm.
3. Is it worse than today?
SurfaceCardsResultWhy
Prospect messages7Today better 5, both wrong 1, Opus fine 1Opus wrote what our inputs said: wrong home from the facts block (Lampliter), "say plainly when the office is open" (Barcelona), "leasing agent meeting them there" (Ember, twice), no special on the named home (Ember; owner traces it to the facts block). Sonnet ignored them or looked the home up live.
Tenant texts33Opus better26 right, 7 wrong, mostly correct silence; no paired ratings, but today's writer would reply on 85% of texts the office already answered
Bench first emails51Opus "better" 29 to 34, worse 3 to 5Not usable (section 2)

The prospect calls are mine: your note names a defect today's text lacks. Customers are not worse off: they still get Sonnet, and held first emails fell from 24 of 51 to between 12 and 16. The Opus shadow is what is worse.

4. Was the refactor cleaner?
MeasureOct 23Oct 30
Leasing prompt file, lines2,2982,618 (+14%)
Numbered RULE lines163179
NEVER / ALWAYS / MUST248270
Prompt a first email getsn/a273K chars; 144 NEVER, 36 "HARD FAIL"
Share that cannot apply to a first emailn/aabout 23%
Office-hours instructionsn/a2 orders to state hours, 4+ bans
Gatesabout 255, plus 60 rewrite layersMostly re-housed in named doors; a few deleted
Your PRs, all lanes338 in 8 days, +113K / -29K lines

Credit: real code merges (one hold function, one ask-for-help door, shared reminders). But Day 0 compares hold and send decisions, not words, yet for changes like #23482 it was the only proof above unit tests. Plumbing cleaner; prompt and checks not.

5. Next 7 days, ranked
  1. Settle split or not: I recommend yes, first email only, by deletion: voice verbatim, cut the 23% that cannot apply, each rule once. Track prompt size.
  1. Fix facts at the source (your Oct 29 rule): "open now" means what AppFolio posts, with its special. One check: facts match the public listing.
  1. Make your ratings the bar: add Situs, replies, Spanish; freeze each Wrong card with its day's inputs and your verdict; blind pairs.
  1. One Opus arm everywhere: Slack, app shadow and bench on the same prompt.
  1. Freeze the leasing prompt except customer bugs; at most 3 open items.

Stop: Day 0 as a proof rung for prompt changes; PASS from a set missing your surfaces; override blocks instead of deleting rules; tenant work here (it works; Gera's hand-off).

6. Swap readiness bar (my recommendation, countable on Slack)
LinePass mark
Blind live pairs you rate40: 20 first emails, 20 replies, 10+ Situs, 5+ Spanish
Your Wrong countOpus no more than today's on the same 40, and at most 4
Your 6 Wrong prospect cards, re-run on today's pipelineright on all 6, 3 runs each
Live never-do0: dash, made-up time or fact, needless "check with the team", unposted home, missing special, office hours as tour times
HeldOpus no more than today
End to endone Willows conversation: inquiry, first email, booked tour, confirmation text, record ids
Appendix: evidence

V = I read the code or data myself. O = owner's account, not re-checked.

  • A1 Prompt growth (V). clara-leasing.ts at ea32569650 (last main commit before Oct 23 UTC) vs origin/main aade7fb253: 2,298 vs 2,618 lines; 312,537 vs 345,117 bytes; lines naming "RULE n" 163 vs 179; NEVER/ALWAYS/MUST/DO NOT 248 vs 270; 34 commits since Oct 23. guest-card-home-facts.ts 1,449 vs 1,647 lines.
  • A2 Prompt sent (V). c2930/tsnap_3f21581bbd175c3e2253c265.json: 272,657 chars, 23 tools; NEVER 144, MUST 28, CRITICAL 24, HARD FAIL 36. Older snapshots (ctx/, Oct 24, mostly Camellia) run 232K to 249K, but size varies by property and turn, so growth rests on A1. Sections that cannot apply to a first email: existing-tenant rule 31,736; repeat-ask rule 19,846; reschedule and cancel 5,153; earlier-messages rule 2,468; work-order confirmations 1,304; renewals 1,007; post-call 469; total about 62K (23%).
  • A3 Arms (V). Opus shadow snapshot for the same turn: system prompt, tools and messages identical to production. App shadow run-arm.ts: only the model swapped. Bench upgrade.ts candidate argv is only --writer-model; run summary writer "claude-opus-5-5-production". "Decomposed" = prompts/first-email-decomposed.ts (re-file plus TEN FIXES) and repair-rulings.ts (rulings block, forward-to-team tool removed). Owner memory calls the PASS arm "decomposed" (O, contradicted by the code).
  • A4 Lampliter (V). Facts block: "Open now: a 2-bedroom, 1-bath with 832 sq ft, from $1,450/mo", no special. Production called get_available_units and wrote 1-bed $1,153 with 4 weeks free; "1,153" and "4 week" appear nowhere in the prompt. situs-listings.json: unit 203 offered true (1-bed $1,153); unit A offered false ($1,450, read Oct 16); unit 109 offered false. lamp-units.json: 5 vacant, 4 of them 2-beds. Owner's cause (vacant units, not posted homes) is consistent; exact code path not re-traced.
  • A5 Barcelona (V). alternatives-summary.ts buildAlternativesSummary: "say plainly when the office is open"; clara-leasing.ts line 2420 the same; bans at lines 523, 1026, 2428, 2547, 2549. Production omitted hours; Opus added "Our office is open 9 AM to 5 PM on Fridays". Owner's cause verified, and understated.
  • A6 Agent line (V). clara-email-core.ts:232: "Tours happen AT the home, with the leasing agent meeting them there". In every Western Slope and Situs snapshot checked, absent at Camellia.
  • A7 Seven pairs (V). ~/agents/001/shadow-leasing/pairs.jsonl. Today better: 39788e20 Bernadette, b8e2cb35 Micheal, 8e342bde Kerry, d8eb8bbf Deyci, 3f21581b Yaramin. Both wrong: ed8ab1e2 Tyler (the shadow blocked send_application, then Opus deferred; production offered no times). Opus fine: 8a818d6a Jane (pair records production silent; the audit says a draft existed). Kerry named 2858 C 1/2 Rd; both arms answered about 374 Ember Lane, while the app's Sonnet 5.5 shadow named the advertised home near that road, with its special. The Ember facts-block cause is the owner's reading (O); the pair records do not keep the block.
  • A8 Bench set (V). sets/v1/prospect-first-email.json: 73 items, 51 runnable (WS 39, Camellia 12, Spanish 0). prospect-reply-turn.json frozen empty.
  • A9 Judge and bar (V). judge.ts FE_SYSTEM_EN; criteria facts_kept, correct, answers, no_overshare, tone, brevity. NEVER_DO_CHECKS in upgrade-lib.ts (10 checks, none for the four complaints). The bar line labeled "Fede's graded cards" counts the judge's verdicts on 9 items you graded on Oct 24, not your verdicts.
  • A10 Ember on the PASS run (V). runner/out/upgrade-2026-10-30-post-23764: 8 Ember items, Opus "better" on 5; rs-2026-10-24-n30 and bench-a:37e9db7f name 374 Ember Lane $2,300 and a $2,550 home with the special.
  • A11 Bench rows (V, from the page). Oct 30 Opus 33/14/4, 29/17/5, 30/20/1 (FAIL), 34/14/3; today against itself as in section 2; held 13 to 16 of 51 vs baseline 24. Inputs read on the run day (bench issue 47, O).
  • A12 Day 0 limit (V). PR #23482 body: rungs climbed "unit (with planted defect), Day 0 replay compare", and "The compare measures the hold-or-send decision; this change only moves the home-facts text the writer reads, so 0 differing is the expected result". PR #23658 says the same and also ran the bench.
  • A13 Gates (O counts, V that rows say so). Oct 26 inventory: about 255 gates, 60 rewrite layers. Rows 52 to 56: "pass-through", "detectors unchanged". A few deletions since (for example #23013 removed a forced retry). Row 101: the rest after the swap.
  • A14 Volume (V). fede-propflow PRs created since Oct 23: 338 (317 merged); +113,543 / -28,871 merged; 49 fix(leasing), 32 fix(clara). Bench issue 61: prompt changes every 10 to 20 minutes (O).
  • A15 Ratings (V store, O press mapping). 53 rows, 42 cards. Tenant arm stored 24 good / 9 bad; ratings-audit.md maps 2 stored downs to "stayed quiet, right", giving 26 / 7. Tenant 85% noise baseline from the bench page (O).
  • A16 Not verified. Whether the Oct 28 to 29 listing fixes cleared the Opus misses live; no Willows driver for a guest-card first email (tracker row 113, O).

Fable 5.1 review

Independent read-only review by Fable 5.1. Evidence in the appendix.

Verdict

The plan is right but was run upside down: the week went into patching the prompt and chasing a bench score, while the two things the plan put first (true facts handed to the writer, one rule per topic) were never built, so a model that follows instructions better than Sonnet now follows our wrong instructions better too. On the cards you looked at, Opus was worse than today's Clara, and the bench could not see it: it grades against our own facts block and against production, never against what AppFolio posts or your verdicts.

1. Is the approach sound?
Part of the planSound?Where it is structurally wrong
Decompose the promptYesNot done. A first email still gets about 65k tokens of prompt (plan: 7k to 19k). The promised "no topic with two rules" check was never built.
Code gathers facts, model writesYes"Open now" comes from our vacancy roster, not from what AppFolio posts; nothing checks it against the listing page.
Bench Opus vs productionHalfEvery line is relative to production. "Correct" is judged against the block the writer was given, so a wrong block passes. "Fede's graded cards" is the judge's opinion, not yours. Situs: 0 items. No check covers 5 of your 6 misses.
Fix inputs one at a timeNot as practiced34 prompt and 12 facts commits in 7 days, one revert, each shaped like one card.
Swap on your goYesFine.
2. Why your ratings say Wrong while the bench says PASS

Six of six real Opus prospect cards were Wrong (the "Fine" one is a Willows test lead).

CardThe missCould the bench see it?
LampliterRoster 2-bed, no special; the only posted home is a 1-bed with 4 weeks freeNo: block treated as truth; 0 Situs items
BarcelonaOffice hours quoted as tour availabilityNo check; a prompt order told it to
Ember (Kerry)Special droppedPartly: on the frozen Ember cards production drops the special too, and the judge rewards Opus for naming a second home with it, against your one-home rule
Ember (two cards)"A leasing agent will meet you"No check, no rule; both Opus arms wrote it
Situs front doorApplication deferred to the teamPartly, via the team-told check

Wrong sample, wrong measure, and wrong inputs made load-bearing: all three.

3. Worse, equal, or better than today?
WhereOpus vs today's ClaraWhy
Frozen bench, 51 emails, judgeBetter: 29 to 34 wins, 1 to 5 losses over 4 runs (production vs itself swings up to 10)Cleaner, shorter, keeps block facts
Live cards with production's email known (3)Worse on all 3Lampliter: Sonnet ignored the block and looked units up; Opus obeyed it. Barcelona: Sonnet ignored the office-hours order; Opus obeyed it. Ember: Sonnet said the special, Opus omitted it (owner's read)
Tenant texts, 33 cardsRoughly 24 good, 8 to 9 bad by his pressesNo paired production rating; today's state is silence

Better on the frozen set, worse on the live cards you saw: Opus does what the inputs say, and the inputs were wrong. A swap today ships those defects where Sonnet papers over them by accident.

4. Was the refactor cleaner?
MeasureOct 23Oct 30
Leasing prompt file2,298 lines2,618 lines
"NEVER" in that file129142
First-email rule file741 lines850 lines
First-email draft checks8 kinds10 kinds
Outbound guard families33, plus one new guard file
Retry or redraft layers removed00

Plumbing got cleaner (one hold function, six collapses, five switch files deleted); what the writer reads got bigger on every count.

5. Next 7 days, ranked
  1. Fix the facts source, not the wording: "open now" and the special come from posted listings; roster vacancies are "opening later" at most. One blocking check: the home named is posted and its special quoted. Lampliter and Ember become fixtures.
  1. Delete the two "state the office hours" orders; build the promised coherence test with a planted-conflict control.
  1. Your cards are the bar: every Wrong card becomes a frozen item with your verdict; no PASS while any reproduces; shadow cards show production and Opus side by side.
  1. Put Situs and Spanish into the measured set (today 0 and 0).
  1. Ship one real job prompt, the first email, under 20k tokens with the same voice, or stop calling it decomposed.

Stop: per-card prompt patches; bench runs as the progress signal; reporting PASS while your Wrong cards stand.

6. Readiness bar for the swap (first email first, what you check before your go)
CheckNumber
Last 25 paired Opus prospect cards on Slack, at least 8 from SitusWrong 1 or fewer; "production better" 2 or fewer; 0 repeats of a fixed mechanism
Posted-home check, 7 days of live first emails100% name a posted home and quote its special
Prompt coherence check0 topics with two rules; control goes red
Bench3 full runs in one day PASS with your Wrong cards as never-do checks; Spanish at least 10 items
Willows end to end on Opus3 real conversations (email, text, call) to a booked tour, with record ids
Cost and speedAbout 2x cost per email, half the latency
Appendix: evidence
  • Prompt size and rule counts: agents/clara/lib/agent/clara-leasing.ts at ea32569650 (Oct 23) vs origin/main aade7fb253: 2298 to 2618 lines, 312,537 to 345,117 chars, NEVER 129 to 142, CRITICAL 19 to 21, HARD FAIL 38 to 40, incident dates 62 to 73; 32 commits since Oct 23 (+498/-178). evals/prompts/guest-card-first-touch-rules.ts 741 to 850 lines. Frozen first-email request systemChars 272,657 (c2930/tsnap_3f21581b...). Master page plan: "Total ~7 to 19k tokens", "Build-time coherence test".
  • Decomposition exists only on the bench: clara-bench/runner/prompts/first-email-decomposed.ts (production prompt split under four headers plus a "TEN FIXES" block). Bench PASS runs used prompt: "production as deployed (today's prompt, unchanged)" (runner/upgrade.ts lines 361, 379).
  • Facts source: src/lib/domain/leasing/guest-card-home-facts.ts line 426 openTruthUnits = rawUnits.filter(u => u.available). Lampliter frozen inputs: c2930/lamp-units.json 5 vacant units (203, 208, 209, 217, A); c2930/situs-listings.json only unit 203 offered: true (1-bed, $1,153, "4-week-free rent concession"); unit A listing offered: false, read Oct 16.
  • Card 42 head to head (c2930/tsnap_3f21581b... and tsnap_shadow_...opus): production tools save_prospect, get_available_units, check_availability, email names the 1-bed at $1,153 with the concession; Opus tools save_prospect, declare_deferred_asks, email names "a 2-bedroom, 1-bath with 832 sq ft at $1,450/mo". Facts block in both: "Open now: a 2-bedroom, 1-bath with 832 sq ft, from $1,450/mo". "No lookups" rule: PR #22932, tracker row 104.
  • Card 41 (c2930/tsnap_d8eb8bbf...): completed-actions text and src/lib/domain/leasing/tour/alternatives-summary.ts lines 50 to 53 plus clara-leasing.ts line 2420 order the writer to state when the office is open; lines 520, 523, 1026, 2426, 2547, 2549 forbid it. Production's frozen draft: "2:15 PM on Friday, October 30 isn't open, but I do have 1:30 PM or 1:45 PM that day."
  • Ember on the frozen set: run runner/out/upgrade-2026-10-30-post-23764-prospect-first-email-full, judge.jsonl, items at appfolio-399: Opus better 5, same 3, production better 0. Card rs-2026-10-24-n30: production omits the special; Opus adds "Our 3-bedroom at $2,550 a month comes with the Grand Opening Special" (a second home); judge worst: "edging into a roster", still picks Opus. Live card 37 (Kerry), owner analysis: Sonnet glued the special to the $2,300 home. Fede's rules: "one home named" (2026-10-22), "specials always mentioned" (2026-10-26).
  • Bench bar: runner/upgrade-lib.ts lines 66 to 75 (every line relative to production run 2); line 120 graded.production_better computed from judge rows, labelled "Fede's graded cards"; NEVER_DO_CHECKS line 31 (no check for special, posted home, office hours, unsourced promise). Judge criteria runner/judge.ts lines 104 to 119: "correct" against "the records the assistant had".
  • Set v1 composition: sets/v1/prospect-first-email.json: 73 items, 51 rebuildable; Western Slope 57, Camellia 12, Situs 4 (all Spanish, 0 rebuildable). Oct 30 full runs: Opus PASS 34/14/3, FAIL 30/20/1, PASS 29/17/5, PASS 33/14/4; production vs itself 19/18/14, 7/30/14, 16/25/10, 13/28/10 (bench page rows 2130 to 2137).
  • Fede's ratings: fede-cards.json arms: first-email-decomposed 3 cards, all wrong; production prompt on Opus 4 cards, 3 wrong, 1 fine (Willows test; Opus text not found per ratings-audit.md); repair-g3-v2 33 cards: up 12, fine 12, stayed_quiet_right 1, down 10, wrong 4 (cards 4 and 7 stored down but were "Stayed quiet, right"). Notes verbatim: "no mention of concession", "Confusing office hours with availability", "Missed specials", "No need to say a leasing agent will meet you at the property".
  • Checks and guards: guest-card-first-email-draft-checks.ts kinds 8 to 10 (582 to 540 lines); guest-card-fact-trace.ts FactTraceHoldReason 4 to 4 (933 to 1009 lines); outbound-safety-pipeline.ts the same three guard families on both dates (fair_housing_hold, first_email_body_guard, hallucination_guard; the fair-housing label is now a ternary at line 288), one label added (internal_text_hold), 316 to 340 lines; new card-notes/card-note-guard.ts 191 lines; deleted held-first-email-retry.ts, prior-thread-tour-rule.ts, preference-capture-flag.ts, staff-asked-*-switch.ts, availability-cache-gate.ts. Retry layers still live: retryWriterOnce in guest-card-engine-turn.ts line 897; forced-tool retry and first-turn violation retry in conversation-manager.ts (owner memory Oct 29); em-dash retry rewrote content (#23099).
  • Plumbing credit: tracker rows 3, 27, 31, 34, 36, 40, 52, 53, 54, 56 shipped; #23252/#23253 listing specials read per company.
  • Week's PR mix (prs-week.txt): 120 PRs, 108 merged; 37 writer-shaped leasing/clara fixes; 24 escalation/team-notify; 22 CI/deploy/perf/sync. Facts file: 12 commits incl. #23482 and its revert #23495.
  • Owner's own Oct 30 ruling (memory feedback_fede_ratings_are_the_bar): ratings read every tick, every Wrong card a frozen check, no PASS while one reproduces. Endorsed here as change 3.
  • Fede's Oct 25 ruling: no automatic readiness floors; he moves customers by hand. Section 6 is what he checks before his go, per job, not a gate.

Willows end-to-end proof of the Oct 30 fixes

Oct 30, 21:40Z, production deploy a4d7d3fc0. One real text conversation at The Willows (test property) between our prospect tester number and the Willows line. Three of the four live fixes behaved in a real reply. Nothing here is a replay.

FixWe textedClara replied (verbatim)ResultRecord ids
Office hours named only when they are the reason (#23811)"Hi, can I tour unit 201 tomorrow at 1 PM?" (inside hours, slot taken)"For your tour, 1:00 PM tomorrow isn't open, but I've got 12:30 PM or 1:30 PM for unit 201, a two-bedroom at $1,550/mo. Which works better?"Shipped: other times offered, no office hoursreply msg_fd5f558d, Twilio SMb6c5703a6c56e67544cf2873e4e7c33d
Same fix, time outside hours"Could I come tomorrow at 10 PM instead?"Held, never sent: "10 PM isn't going to work, tours run 10 AM to 4 PM on Saturday. I do have 3:00 PM or 3:30 PM open for unit 201..."Wording right; delivery failed (see finding 2)held msg_held_755415bd
No "a leasing agent will meet you" (#23800)"1:30 PM tomorrow works, please book it.""You're all set, your tour is confirmed for tomorrow, Saturday, October 31st at 1:30 PM at The Willows, 1601 Blake Street, to see unit 201. Looking forward to it!"Shipped: tour booked, calendar event created, no meet-you linereply msg_e357aa49, Twilio SM2ef6fc852fb7f00fa252d815a96037b0, tour d0c94d19
Goodbye without rule echo or hold (#23822)"Thanks, we decided to go with another place.""No worries at all, Door, thanks for considering us. Best of luck with the new place, and if anything changes, feel free to reach back out."Shipped: sent, not held, no rule wordingreply msg_6400f6ba, Twilio SMf36d340f5ef86267d3171f3958ffb144
Approve follows the held message's channel (#23795)nothing to approven/aNot exercisedn/a

Conversation 81e09472-535a-4a10-9531-521b926cf949. Before-number for the today/tomorrow fix (#23792, merged after this run): the confirmation said "tomorrow, Saturday, October 31st".

Production conversation page: the four test texts and Clara's replies, including the held 10 PM draft
The conversation in production after the run. The "Draft held, not sent" card is the 10 PM reply.

Two ways a renter got silence (found here, no fix started)

  1. Runaway limit mutes the thread with no trace. After 40 Clara replies in a row with no person on the thread, Clara stops answering. A renter's own texts do not reset the count. No card, no hold, nothing on the page; only a log line. It tripped on this thread Oct 28 and again Oct 30; the tester's fee-waiver question sat two days.
  2. A correct reply held with no exit. The check that confirms tour times were looked up could not read the reply ("AI fallback, unparseable") and held it. The hold never appeared on the review page and the approval script refuses it as a duplicate. Matches the Oct 26 rule that held messages need a recovery path.
Production escalation holds list with no Willows entry for the held 10 PM reply
The holds list after the run: the held 10 PM reply is not on it.

Also seen: a team "asked us something we could not answer" email went out on the plain tour request Clara answered fully.

Today/tomorrow wording (#23792), after deploy f13324ff1

We textedClara replied (verbatim)ResultRecord ids
"Hi again, could I actually see unit 201 tomorrow at 1 PM?" (slot taken)"Glad to hear you're interested again! 1:00 PM tomorrow isn't open, but I've got 12:30 PM or 1:30 PM for unit 201. Which works better for you?"Shipped for the declined-time reply: "tomorrow", no formal date. Before: "tomorrow, Saturday, October 31st"msg_9cad83f8, Twilio SM3c984d67e7eb193e594be6aa784247a6
"Thanks, no need, I'll pass for now.""No worries at all, Door. If anything changes, feel free to reach back out."Thread settled, nothing bookedmsg_c9126e8d, Twilio SM06f285532e4aaf7ba929cc6f0ff286fe

Not yet exercised after the deploy: the booking confirmation itself, where the formal date appeared earlier tonight. Next real Willows booking covers it.

Production conversation page showing the tomorrow wording reply
The two new turns at the bottom of the conversation, in production.
Hand-off · Oct 27

Tenant comms hand-off to Gera's swarm (Oct 27)

Tenant comms now belongs to Gera's swarm; leasing stays with session 001. Fede, Oct 27 ~03:10Z: "gera owns tenant comms now cause maintenance is the critical path", "so we could do some hand off there", "lets give a very comprehensive hand off". Everything needed to pick this up cold is below. Questions: #engineering-bridge via Smith.

In this section: what moves · tracker rows · where everything is · how to run it · shadow pipeline · bench numbers · open findings · Fede's rulings · merge gate · traps · the bar · first week · talking to 001

What moves, what stays

MOVES TO GERA'S SWARM Every tenant textrepairs (maintenance) and everything else: deposits, parking, lease questions Shadow week feed and its Slack cardsWestern Slope + Situs, what Clara said vs what New Clara would say Tenant bench sets, frozen records, decomposed tenant promptplus the Maintenance part of every one-door fold STAYS WITH SESSION 001 Leasing: the prospect pathfirst email, follow-ups, tours, calls ("what i own and is higher priority is leasing") The core folds (one door per concept)shouldSpeak, askTheTeam, notice engine, the shared doors themselves Day 0b baseline, Clara Bench app, Slack card designyou use them; 001 keeps them working and re-freezes the baseline
The split. Shared pieces (bench app, replay harness, card design) stay 001's; you use them freely, and changes to them go through the bridge.
ItemGera's swarm001
Tenant texts (repairs and everything else)owns
Prospect texts, emails, callsowns
Shadow week loop, pairs file, Slack shadow cards (content)ownscard design system
Tenant sets on the bench (repair, other, Spanish rows) and their frozen recordsownsprospect sets
Decomposed tenant prompt (repair-g3-v2 + emergency clause)ownsfirst-email decomposition
One-door folds: the Maintenance caller of each rowowns (re-point, delete the copy)the core door, Leasing and Renewals callers
Maintenance supervised holds on template textsalready yours (Gera, #22487)

Tracker rows that move

Rows on the phase tracker; change the owner field when you pick one up. Status stays derived.

RowSliceStatusPRsWhat it is
repair-pathHin buildnone yetRepair path on the decomposed prompt, writer on Opus 5.5, Willows end to end. Proof planned: shadow week first, then Willows with record ids.
tenant-replies-darkJnot startednoneTenant replies built dark behind the existing maintenance.pms_inbox_tenant_door setting (default off); maintenance first, renewals second.
opus-shadow-weeknonein build#22526, agent-harness #1529, clara-benchmark #25 (all merged)The shadow week; running since Oct 26 04:43Z.
two-issue-intakenoneopenissue #22381A two-issue text can lose one issue (nothing filed, nothing asked). Fix, no switch; proof 8 of 8 filed on the reproduced case, production note replay unchanged.
full-context-bench (tenant half)Hopenclara-benchmark #27, #28, #29 (merged)The tenant numbers below are yours; the first-email half stays 001's.
Maintenance part of each collapse-* rowC to Evariessee each rowMaintenance own copies: staff notice senders (after-hours-oncall-heads-up.ts, tech-sms-dispatch.ts), review doors (maintenance-text-review.ts, handyman-text-review.ts), intake classify, work-order writer, repair check-ins and rating asks, maintenance-off-refusal.ts, maintenance-entitlement.ts, tool set, prompt examples in clara-maintenance.ts. Table: shared versus module-specific.
Already merged and yours to build on: #22383 (a different problem gets its own work order; follow-up #22389), #22380 (one professional register; follow-up #22385), #22146 (photos reach the work order), #22411 (rating buttons).

Where everything is

Paths under ~/ are on Fede's Mac. Tenant text never goes in git or on a docs page; ids, counts and hashes only.

WhatWhereWhat it holds
Frozen tenant sets~/.clara-bench/sets/v1/tenant-repair-text.content.json, tenant-other-text.content.json, spanish.content.jsonThe v1 items, masked text: repair 261 (20 runnable), other 150 (99 with a known stay-quiet truth), Spanish slice 421. Ids and fingerprints in git at clara-benchmark/sets/v1/ with LOCK.json. Never re-freeze v1; add v1.1 beside it.
Frozen tenant context records~/.clara-bench/sets/v1/tenant-repair-text.context.json (20), tenant-other-text.context.json (150)What the writer saw, cut at the text: tenant, unit, lease terms, work orders open then, thread, knowledge; content hash per record. Built by ~/.clara-bench/tools/freeze_tenant.py from runs/slice-h-2026-10-26/freeze-raw.
Slice H runs~/.clara-bench/runs/slice-h-2026-10-26/h2-tenant-{repair,other}-text-{production,restrictive,full}/ (results.jsonl, summary.json, controls.json, proof.json), h2-score.json, h2-run.log. The h- folders are the replaced first pass.
Sonnet 5.5 arm (running now)~/code/PropFlow/clara-bench-wt-sonnet55/runner/out/h3-*-full/, log ~/.clara-bench/runs/slice-h-2026-10-26/h3-run.logSame runner and items, writer claude-sonnet-5-5, decomposed, full context. First email done; tenant repair and other in flight. The runner change is two lines in runner/writer.ts on local branch fede/sonnet-55-writer, not in a PR.
Bench tools~/.clara-bench/tools/run-h2.sh (three tenant arms), run-h3-sonnet.sh, score-h2.ts (row values from run folders), freeze_tenant.py, check-swap.ts, probe/ (read-only door probes).
Bench repoPropFlow-Technologies/clara-benchmark, local ~/code/PropFlow/clara-benchmarkRunner (runner/baseline.ts, writer.ts, checks.ts, door.ts, opus-shadow.ts, shadow.ts), decomposed tenant prompt (runner/prompts/repair-rulings.ts, arm repair-g3-v2), labels CLI (cli/labels.ts), web app. Own CI, never PropFlow's. Its CLAUDE.md says clara-bench; the checkout is clara-benchmark.
Clara Bench page/a/clara-bench; rows in artifacts/clara-bench/runs/*.json, rendered by bin/render-clara-bench.mjsTenant rows: 2026-10-23-bench-d, -d2, -d3, -f, -g, -g2, 2026-10-25-baseline-v1, 2026-10-26-slice-h-full-vs-restrictive; review set 3; human labels.
Shadow week (New Clara on Opus)~/agents/001/shadow-opus/loop.sh, loop.pid, loop.log, pairs.jsonl (155 pairs: production vs New Clara), state-*.json, build_review_set_3.py. Loop runs from worktree ~/code/PropFlow/clara-bench-wt-opus-shadow.
Shadow feed (turn records)~/agents/006/shadow/turns-westernslopepm.jsonl, loop ~/agents/006/shadow/loop.shSession 006's Western Slope per-turn records, the bench's episode source. Slack posting off since Oct 26 (SHADOW_NO_POST=1). Runs from worktree clara-bench-wt-shadow.
Slack channels for shadow cards#western-slope C0C283G9QDR, #situs-group C0BUB71T4NMOne card per new tenant text: New Clara's reply with the rating row under it, the office's reply below as context.
Label recordPropFlow GradeVerdict rows (table propflow-prod, index entityType-createdAt-index); bench export ~/.clara-bench/labels/labels-YYYY-MM-DD.jsonOne row per press: source (slack_card, app, fede_chat), rater, verdict, button, note (arm, PMS message id). Oct 25 to 26: 9 real presses (8 Fede, 1 Gera): Wrong 3, Fine 4, Stayed quiet right 2.
Replay snapshot~/agents/001/replay-snapshots/day0b-2026-10/cells.jsonl (5,515 hold decisions), snapshot.json, LEDGER.md, census-stock.json. No message text; never in git. The older day0-2026-10 was superseded after Gera's #22487.
G3 repair episodes, filing proofsession 001 scratchpad bench-g3/, filing-proof/, filing-proof/decomp/, g3-full-mode-report.md261 episodes; filing comparisons on the 20 runnable. Ask 001 for a copy (scratchpad is per session).
Four repair cases for Fedetracker #repair-review-casesSame order or new order: Beate (stove), Cornisha (washer and dryer onto the AC order), Marly (extractor onto the faucet order), Karin (indoor AC leak onto the outdoor spigot order).

How to run it

Every command runs on the Claude subscription, never a metered key, and reads production only through the bench door (writes, sends and notices blocked).

JobCommandNeeds
Baseline rerun, one surfacecd ~/code/PropFlow/clara-benchmark; export BENCH_DOOR_URL=https://propflowai.co HARNESS_SUPPRESS_OUTBOUND=1; unset ANTHROPIC_API_KEY; npx tsx runner/baseline.ts --surface tenant-other-text --tier full (or tenant-repair-text --tier smoke)Subscription token from Keychain Claude Code-credentials (or ANTHROPIC_AUTH_TOKEN); door token from Keychain benchmark-door-token, account propflow (or BENCH_DOOR_TOKEN).
A candidate armadd --run-id <id> --writer-model claude-opus-5-5 --writer-prompt decomposed [--context full]Same. --context full requires decomposed. Always run production in the same hour (Fede's apples-to-apples rule).
All three tenant arms~/.clara-bench/tools/run-h2.sh, then npx tsx ~/.clara-bench/tools/score-h2.ts (H_OUT, H_PREFIX override folder and prefix)Same.
Shadow week loopstart: nohup ~/agents/001/shadow-opus/loop.sh > ~/agents/001/shadow-opus/loop.nohup.log 2>&1 & echo $! > ~/agents/001/shadow-opus/loop.pid; stop: kill $(cat ~/agents/001/shadow-opus/loop.pid); posting off: change export OPUS_SHADOW_POST=1 to unset, restartRead access to AWS table propflow-prod (queries PMSMIRROR#appfolio#<account>), the door token, Keychain slack-bot-token, the subscription. It warns if a metered or AWS key sits in the environment.
Read the ratingscd ~/code/PropFlow/clara-benchmark; npm run bench -- labels --since 2026-10-25T00:00:00ZRead-only propflow-prod; writes the JSON to ~/.clara-bench/labels/.
Push a run to the bench storenpm run bench -- push <runner out dir> --kind tenant_textThe bench's own table propflow-clara-benchmark.
Replay compare (merge proof for code)in a propflowai worktree: HARNESS_SUPPRESS_OUTBOUND=1 npx tsx evals/replay-harness/run.ts --mode recorded --baseline day0b-2026-10The snapshot folder above. Exit 0 and 0 differing cells, or a known-bugs ledger entry for each diff.

The two shadow loops run from worktrees that are behind clara-benchmark main (#26 to #29 not in them). Start your copy from a fresh worktree off origin/main (the repo's CLAUDE.md has the command). 001's loop keeps running on Fede's Mac until you post on the bridge that your copy is up; then 001 stops it, so no text gets two cards.

The shadow pipeline, end to end

AppFolio mirrortenant text landsPMSMIRROR#appfolio#… Loop, every 5 minopus-shadow.ts, bothaccounts, new texts only Bench door, read-onlybuilds the real turn; runsproduction + New Clara pairs.jsonlboth arms, every textreview-set source Slack cardone per new textrating row Press → socket on the MacAgent Smith app, signed relay(agent-harness #1472, #1492) /api/slack/interactionswrites one GradeVerdict(#22411; "Why?" box #22526) bench labels (read-only)human column beside the judge(clara-benchmark #26) Nothing reaches a tenant. The only outbound is the internal Slack card. Backfills write the JSONL only, never Slack.
Buttons: Stayed quiet, right · Wrong · Fine · Better than staff; each sends shadow_rate:<verdict> with conversation id, message id, arm and PMS message ref. The relay signs with SLACK_RELAY_SIGNING_SECRET (readable copy in AWS SSM /propflow/prod/SLACK_RELAY_SIGNING_SECRET). Socket: launchd co.propflow.clara-slack-socket, restart with launchctl kickstart -k gui/$(id -u)/co.propflow.clara-slack-socket.
Door and card quirkState
Texts filed on voice or email threads were refused (judged by thread channel)Fixed, #22351 (Oct 25)
Door runs posted ops and Slack alerts (97 calendar cards in 47 s, Oct 24)Fixed, #22324 #22327 #22329; rerun posted 0 cards
Door skipped the work-order filing step, so filing could not be measured#22386 runs filing read-only; issue #22384 still open for the rest
Backfill burst: about 33 unstyled cards in one minute (Oct 26)Fixed: the runner refuses to post if the last tick is over an hour old or the state file is missing
Two cards per text (006 feed plus 001 card)Fixed: 006 feed no longer posts
8 of 15 refused texts refuse as "not an active tenant"Open. The mirror may file those texts under the wrong person (#22320 comment)
Card does not update when the office replies laterOpen
Rating polish: "Why held" line and record-id linksOpen: a local commit in the 006 runner, no PR

State of the week: the Oct 26 05:50Z backfill covered 96 texts (Western Slope 41, Situs 55). Both arms ran on 46; the door refused 50. Production would reply / hold / stay silent on 7 / 27 / 12; New Clara on 4 / 14 / 28; they differ on 19 of 46. Review set 3 (the 19 plus 6 controls) waits on Fede's verdicts by number. At the first live grading (Oct 26) Fede marked New Clara's silence Wrong on both texts (Alba, Maleah, Western Slope): a possible too-timid pattern.

Bench rows and numbers

Noise, the headline, counts replies where the office had already answered within 48 hours. Lower is better. Helpful counts replies that are not "I've told the team".

Slice H, Oct 26 (170 items)Today (Sonnet 5)New Clara (Opus 5.5)New Clara + full facts
Other texts: noise, of 99 the office had84 (85%)44 (44%)53 (54%)
Other texts: helpful replies76 of 122 (62%)30 of 56 (54%)37 of 66 (56%)
Other texts: "told the team" / invented facts46 / 826 / 729 / 8
Repair texts (20): noise, of 101067
Repair texts: replied / helpful19 / 1810 / 1011 / 11
Spanish (27): noise, of 13131011
Spanish: answered in Spanish23 of 2413 of 1315 of 15
Sonnet 5.5, decomposed, full factsRunning tonight (run-h3-sonnet.sh); no tenant numbers yet. They land in h3-tenant-*-full.
Row 2026-10-26-slice-h-full-vs-restrictive. Read: laying every fact out made Opus chattier, not "facts hurt". New Clara is less noisy but also less helpful, and Fede's live presses call some of its silences wrong; both have to move. Caveats: Opus arms got code checks only (no office-reply comparison); the comparison step caught 3 of 5 planted checks; production's prompt changed mid-run; 64 of 170 work orders show today's status, not the status on the day.
Earlier tenant rowsQuestionAnswer
baseline-v1 (Oct 25)What does production score on frozen set v1?Noise 82 of 96 (85%), helpful 72 of 119 (61%), 47 "told the team". Repair smoke: noise 10 of 10, filing matched the office 7 of 17. Zero writes; 120 write attempts refused.
G3 (Oct 24), 261 repair episodesToday vs today's prompt on Opus vs Fede's graded fixes on OpusFiled when the office filed 45% / 48% / 57%; "check with the team" 34% / 39% / 8%; invented facts 30% / 21% / 16%. Duplicates doubled (5% → 11%): nothing matches a text to an open order. Full mode reached only 20: judge 4.00 vs 2.85.
G3 filing, 20 full-mode texts (Oct 25)Does the decomposed classifier on Opus file like production?No. Add to open / new / ask first / reply only: 5 / 3 / 4 / 8 vs production 8 / 5 / 0 / 7. Production's thresholds are tuned for Sonnet; keep the classifier on Sonnet for the first step.
Willows recorded v1 (Oct 25), 11 textsDo two rule lines fix Opus habits?Full 8 → 9, light 6 → 8; "team has it" before a work order exists 0. Accepted version: repair-g3-v2 plus the emergency clause.
D3 (Oct 24)Model reads the staff thread vs a 24 h code gateAgrees with Fede on 22 of 23 (24 h gate: 20). In-sample.
D2, F, G, G2 (Oct 23)Earlier tenant and Spanish passesSuperseded; useful for method: D2 found only 958 of 1,523 "staff answered" pairs were real answers. F: 40 of 40 replies in Spanish.

Open findings, with evidence

FindingEvidenceNext step
11 texts where Opus with full facts spoke though the office had it, while restrictive Opus stayed quiet (reverse: 2)T:situsgroup:1168128252, T:westernslopepm:1235281725, T:situsgroup:1157661192, 1167583157, 1158507401, 1156656567, 1158696881, T:westernslopepm:1234150772, T:situsgroup:1167581991, 1167050418, 1166634742; text in h2-tenant-other-text-{full,restrictive}/results.jsonlMake a fixture; find what in the facts block pulls Opus in
Filing not at parity on OpusG3 filing row above; filing-proof/decomp/Re-set thresholds for Opus and clean the open-order list (8 to 43 stale open orders per Situs tenant) before moving the classifier
Match before filing missedPrompt rules 3c to 3e and code check 3f: filing fell 25 → 19 to 22 of 42; indoor AC leak still attaches to the spigot order; two wrong attaches in 3b (washer and dryer onto an AC order, kitchen extractor onto a faucet order) because the right order was not in the open list Clara sawA design for open-order matching plus Fede's calls on the four cases, not another prompt line
Two-issue text loses one issue#22381, 1 of 8 runsFix, no switch; proof 8 of 8
8 of 15 shadow refs refuse as not a tenant#22320 comment; door refusals in loop.logCheck how the mirror files them; never count a door refusal as Clara's silence
A failed wake on a PMS inbox reply raises no alert#22601; Willows Oct 26 23:09Z, thread 8ffa78e8, decision=wake_failed (cause fixed by #22590)One alert card through the notice door
A new work order tags earlier unrelated texts#22602; Willows WILL-003963 (kitchen sink) tagged 7 earlier deposit and guest-parking texts on 8ffa78e8Fix, no switch, Willows proof
Unknown-number text left unfiled#22612 (mirror MSG#1237846985, pending / no_match)Filed, not built; the same mirror rung affects tenant texts
Photos and multi-problem rules#22146 (photos reach the order) and #22383 (different problem, own order) merged; neither proven on a real tenant photo yet. Follow-up #22389: scheduling and access fields dropped when the note tool files a new orderFirst proof is the next real tenant photo; keep one order per report
Data gaps2,276 of 4,114 work orders have no status; every arm re-adds entry details already on the order because tools do not show themContext, not prompt

Fede's rulings that bind tenant work

DateRulingHis words
Oct 23Reply only to a known prospect, or a tenant where the switch is on; unknown sender = silent; former tenant = tenant"The default should be off."
Oct 23Office started or is running the thread = Clara silent; never acknowledge an arrangement only a person can approve"we're just chiming in like this, unnecessary"
Oct 23Phase 1 has two outcomes, reply or silent; no team items, no escalations; unanswered items tracked internally only; read the lease before saying "not on file""either we stay silent or we're helpful, or we keep track of things that are not answered, but not do anything with it yet"
Oct 23AppFolio already emails staff per tenant reply; a Clara note on top duplicates it"a disgrace"
Oct 23Spanish is first class in every bench; never Spanish knowledge entries, Clara rewrites the fact"we need to get really good at spanish"
Oct 23Every bench ships a numbered review set; his verdicts are the human column"i want to see and review a few dozen examples"
Oct 23Benchmarks replay episodes (next turns, the work order filed), not one turn"this atomic testing just of the one turn doesn't seem very useful"
Oct 24Decompose today's prompt, never rewrite; same tone; production is arm 1 in every bench"We're not trying to reinvent the wheel here."
Oct 24One work order per tenant report, all items in it"It makes more sense to have just one work order."
Oct 24Shared-area problems file on the property, no entry question; infer, don't ask"nobody has a laundry in their basement, it's probably shared"
Oct 24Acknowledge every item in a text (renewal interest, a call request)"we would love you guys to renew and to stay"
Oct 24After a work order is done, Clara checks in on her own"is everything done? How would you rate your experience?"
Oct 24Commercial work orders supported, research first"we should support work orders for commercial buildings"
Oct 25Noise is the primary score; "told the team" is a failure"the number one failure for Clara is adding noise"
Oct 25"Person on it" by topic, never a clock; thin code layer"we should not be using time. we need to reason about the ask and topic"
Oct 25No readiness floors; customers move only on his word"they live wherever they are today and what i decide manually"
Oct 25Prompt changes may merge, then run in shadow; nothing live to customers"its fine if we merge prompt changes but its gonna go supervised for a while, like shadow"
Oct 25Safety emergency: tell the team at once and ask the unit in the same reply (decided under the grant; Fede may override)recorded on this page
Oct 26Decide to speak before drafting, from the whole thread across every channel"channel should not matter"
Oct 26No partial sends; fewer gates, battle-tested"we need to keep it simple and reliable"
Oct 26Tests never write to production"a test should never write to production"
Oct 26Backfills never post to Slack; one card per new text"you're spamming the channels"
Oct 26Recovering a held message: drafted via Clara's path, sent only on his yes"do not send anything without my approval"
Oct 27Get tenant replies to a point where they can be turned on, then supervised for a while"its gonna be supervised for a while"

Replay harness and the merge gate

ChangeWhat merges itWhat makes it live
Pure move or fold (code)Day 0b compare byte-identical: 0 of 5,515 cells differLive on merge, no switch
Code fix that moves holds on purposeEvery differing cell matches a known-bugs ledger entry named in the PR (evals/replay-harness/ledger/known-bugs.json); 001 re-freezes with a ledger the same dayLive on merge, plus a Willows proof
Fix to what feeds the decision (data, context)The grid shows 0 diffs for these; prove it with a real-case fixtureLive on merge, plus a Willows proof
Prompt changeBench row (production in the same hour, Spanish slice) plus a non-regressing compareRuns in shadow first; Fede reviews examples and flips each customer by hand
New capability (tenant replies)Dark behind maintenance.pms_inbox_tenant_door, default offFede's word per customer, then supervised
The replay covers the hold decision over a fixed grid, not the full turn; taps 3 to 5 miss the tour-booking loop and do not pin the phone and clock yet (#22458). The module release sits at the send door (company-live-gate.ts holds on module_off); see tenant communications.

Known traps

TrapWhat to do
An apply rerun wrote six fake rows into a real Western Slope prospect's thread (Oct 26)Bench door only; rerun scripts refuse any non-test property (#22504)
Bench door side effects (97 cards, Oct 24)A door proof counts Slack posts and ops events, not only database keys
hello@propflowai.co is Fede's real inboxNo test, bench or replay mail to it or any hello+ alias, ever; no test call, text or email reaches anyone at Western Slope
Willows bench tenantFede is the tenant at The Willows: org_sandbox, property appfolio-45, unit TEST-102 (AppFolio occupancy 986), tenant tenant_c38824c0-7cac-401f-9488-9a2aa9bc3008; his phone is in memory reference_fede_test_renewal_targets.md. Last live tenant run: thread 8ffa78e8, work order WILL-003963. The /willows-persona skill switches what his phone is treated as.
Mirror filing quirksSitus history before Sep 29 2026 predates the mirror (215 of 261 G3 episodes unresolvable); texts filed under the wrong person (8 of 15); unknown number with no name stays no_match (#22612); the thread's "our side" label does not say whether Clara or staff wrote it
Judge pairingThe tenant-other judge column is not valid: the mirror's next office message is often about something else (controls 5 of 13, then 2 of 5). Re-pair in v1.1 before trusting a judge column
Production moves under youThe prompt sha changed twice during slice H; run production in the same hour as every candidate
Balance and work-order statusBalance is never frozen; a work order closed since the text shows today's status

The bar

Get the decomposed tenant prompt to where Fede can turn tenant replies on, then run them supervised (a person sees each reply before it goes) at the first customer he picks. Noise is the primary score, helpfulness second. The bar is "good enough to supervise", not full autonomy. Tenant texts are off at Western Slope, Situs and Camellia today, so this blocks nothing in leasing.

Suggested first week, in dependency order

StepWorkStarts when
1Read pairs.jsonl, review set 3 and the 9 presses; start your own shadow loop, 001 stops its copynow
2Study the 11 texts and the two Wrong silences (Alba, Maleah)now
3Read the Sonnet 5.5 tenant arm; pick the writer model for the tenant armh3-run.log says ALL DONE
4Prompt edit for "person on it by topic"; bench row with production in the same hour and the Spanish sliceafter 2 and 3
5No-switch fixes: #22601, #22602, #22381, each with a Willows proofany time, in parallel
6Open-order matching design and Opus thresholds; Fede's four repair callshis calls
7Mirror filing for the not-a-tenant refsin parallel
8Repair path (H) as a mergeable shadow arm, then Willows end to end with record idsafter 4 and 6
9Tenant replies dark (J) behind the tenant-door setting; Fede picks the first customer for supervisedafter 8

How to reach 001

One channel: #engineering-bridge, addressed to Smith in the bridge message shape; 001 answers there. No DMs, no tags on Fede for routine questions, no posts in customer channels. A change to a shared piece (bench runner core, card design, replay baseline, a core door) is a bridge message before the PR.

02 · Gate review, one gate at a time

Gate review: one report per gate, with an Opus 5.5 replay

Update Nov 2: the one retry-once kept for dash and no-tour-times on the first email is also gone. Every rewrite, retry-regenerate and redraft layer is deleted; checks hold into Supervised review only, and a misfiring check gets its wiring and context fixed. Tracked on rows 43 and 101.

Fede's decision, Nov 1 (voice notes via the Trinity DM), applied to the eight reports. His words, lightly cleaned: "I don't think there should be any rewrites. Opus 5.5 doesn't need another model to rewrite it; that's a hack we did a long time ago for Sonnet, not best practice. Gates that fact-check or catch hallucinations are fine, but they must be very well wired with all the right context or they misfire. If we need to roll out over time, hold them as supervised and put it on Slack. The rewrites have to be all eliminated." Three rules follow: every rewrite, retry and redraft layer is eliminated, none of it folds into a new rewrite path; the checks that remain can only hold, and a held reply goes to supervised review on Slack; a check that misfires is fixed by its wiring and context, never compensated by a rewrite. Code work belongs to the Clara Refactor session's PR chain; this block is the list it works from. Each row cites the report that graded it.

Rewrite layer (edits or re-runs Clara's reply after she writes it)What the data saidDo
Hand-off template swap (report 8)18 of 22 replies replaced; 1 real catch at a customer, 1 false "noted for the team" sent, 1 answer lostEliminate.
"Lock in" booking-promise regenerate and fixed-line rewrite (report 5)0 real catches in 9 customer fires; 4 rewrites made the reply worseEliminate.
Unit-availability forced retry (report 4)0 real catches in 10 customer fires; 7 misfires, 5 never checked the unitEliminate.
Tour-time forced retry (report 4)4 real catches in 9 customer fires, all Sonnet's "10 or 2" habit; 1 retry ignored by the modelEliminate the retry. The fact it guarded (every clock time offered came from this turn's calendar read) stays as a check, below.
Unit-count redraft (report 6)2 of 2 customer fires real; 2 of 5 redrafts dropped real contentEliminate the redraft. The rule (never a quantity of homes) stays as a check, below.
Time-stamp strip (report 7)6 of 6 real, 0 misfires, but 14 of 15 copies were of our own history noteEliminate the strip. Fix the wiring: the writer never sees the note (history rows enter the facts block without transport headers).
First-email redraft rules and the second-model rewrite era (report 3)9 rules; "no tour times" is 20 of 23 named fires; five rules never fired, three fired once; 34 of 35 Western Slope fires were rewritten by a second modelEliminate the redraft and the second-model rewrite. The two rules Fede asked for by name (no tour times, no dash) stay as checks, below.
First-email tools-off re-runNov 1, Situs Group: the re-run, with its tools switched off, typed 60 pieces of tool-call markup into the email; held (reported by the Clara Refactor session)Eliminate.
Never fired or plainly wrong (remove now)Evidence
Five first-email rules that never fired, plus the "no home named" and "implies prior contact" rules (report 3)0 fires in 30 days for five; the rest once each
The anomaly gate's five content signals (report 2)Never fired; the gate's only real fire was a timeout. The timeout and tool-failure alarm stays as an engineering alarm and a hold, never a blind re-run (a tool that already ran must not run twice, #11694).
The "lock in" phrase list and the unit-availability retry0 real catches each (rows above)

What stays, as checks that can only hold, with the held reply sent to supervised review on Slack: the supervised hold itself (report 1); the calendar rule (a clock time offered must come from this turn's calendar read); the unit-count rule; the first-email "no tour times" and dash checks, holding into the same review and team notice the supervised path uses instead of a silent row; the fair-housing judge (Fede: keep); the hallucination guard; the send door. Each one is wired with the full context it judges against (the facts block with ids, the calendar read, the actions taken) before it is allowed to hold, because a check with less context than the writer misfires, and a misfire is fixed in the wiring, never by a rewrite. A hold check that has not fired in 60 days comes up at the monthly review, per the registry rule in the synthesis below.

Sequence for the PR chain: the eight eliminations first, each proven by a byte-identical replay of the recorded turns where the layer did not fire; then the never-fired removals; then the remaining checks rewired to hold-to-supervised with the Slack review. Already merged before this note: the Oct 26 calendar-read fix (#22485).

Fede, Oct 26 voice note relayed through the Trinity DM: "review the gates we have: the hold gates, the rewrite gates, and all the outbound stuff that is blocking… what it is, why it was built, how many times it has misfired, has it actually caught any bugs, and then a decision… maybe we built that gate because we were using a weaker model, but if we were to use Opus 5.5, do we still need that gate?" This section answers that one gate at a time, biggest first. The full catalogue of gates and their 30-day fire counts is the inventory section below (001, gate inventory Oct 26); this section does not repeat it.

How each report is built. Production records first (every hold row since the table began, read-only), then the gate's origin PR, then the same cases replayed through the read-only bench door on two arms: the model production used that day, and Opus 5.5 with the same prompt. A Fable judge answers the reviewer's question on each draft: would a careful property manager stop this before it goes out, and is the problem material. The judge is compared with what the person actually did (approve, reject, let it expire), never with an office message. Counts and ids only; no tenant names or text on this page.

Words used in every report. Caught: a person rejected the draft for a defect in the draft. Misfire: the gate held something nobody changed (approved as drafted) or something nobody looked at (expired after 24 hours, never sent). Superseded: the person texted again before anyone decided, and a newer draft replaced the held one.

Report 1 · The supervised hold (the biggest gate: every Clara reply in a supervised module waits for a person)

What it is. When a company's module is set to supervised, Clara still drafts the reply, but instead of sending it the system stores it as a hold, posts a card to the company's Slack channel, and sends only on a person's approve. A draft nobody decides in 24 hours expires and is never sent. Staff cannot edit a held draft: the approve path takes approve or reject only, so every one of the 110 approvals all time went out as Clara wrote it (the records keep no edited version; the only other path is Clara redrafting on a reviewer's emailed instruction, which the records do not mark).

Why it was built. PR #16514 (2026-10-05) made the hold cover every module's email replies (the SES lane), closing two gaps from the supervised-mode audit under Gera's Oct 4 ruling; PR #16644 the same day held a text reply routed to a supervised module even when the topic check said general. Neither PR names an incident: both close gaps in the supervised-mode net. The eval catalog puts the drafting model at Sonnet 4.6 then and Sonnet 5 since Oct 10. The hold is a blanket: it does not detect anything, it holds everything in the module.

How often it has fired, all time (453 holds, 154 at real customers; 006 pull of every hold row, Oct 26).

WhereWhat was heldAllApproved as draftedExpired (24 h, never sent)SupersededRejected by a personEngineering or test
Western SlopeMaintenance notice to resident (template)73664010
Western SlopeMaintenance notice to vendor (template)101000
Western SlopeProspect email (first email or in-thread reply)31165028
Western SlopeLeasing outreach text100000
Situs GroupMaintenance notice to resident (template)45043000
Situs GroupProspect email (first email or in-thread reply)100000
JP&CoTeam notice email220000
Test orgs and rows with no org (299 holds: Willows, Fairhaven, the retired bake gate), same columns
WhereWhat was heldAllApproved as draftedExpiredSupersededRejected by a personEngineering or test
(no org)Maintenance notice to resident (template)210000
(no org)Decision request (bake gate, retired)811006
(no org)Leasing outreach text300000
Fairhaven (test)Clara reply text41314213
Fairhaven (test)Renewal outreach text1250600
Fairhaven (test)Renewal reminder text210000
Fairhaven (test)Team notice email110000
Fairhaven (test)Renewal monthly batch email110000
Willows (test)Maintenance notice to resident (template)1127001
Willows (test)Maintenance notice to vendor (template)82473004
Willows (test)Clara reply text351221406
Willows (test)Renewal outreach text5188506
Willows (test)Prospect email (first email or in-thread reply)1986104
Willows (test)Renewal reminder text25500317
Willows (test)Team notice email550000
Willows (test)Renewal monthly batch email110000

"Engineering or test" = holds closed by a proof run, a harness, or an engineering recompose during the Western Slope first-email launch week (Sep 22 to 24). Pending rows are omitted from the outcome columns.

Has it caught bugs? At a real customer, a person has rejected a Clara draft for a defect in the draft 1 times (one Western Slope maintenance template, Oct 11, a format request, not a wrong fact). The real catches came from engineering, not from the gate: 8 Western Slope first emails were recomposed during launch week because the held draft recited the listing back, narrated internal matching, or carried an unsupported claim; those are prompt fixes that shipped the same nights. One more catch happened at the Fairhaven test org (Oct 13: a draft pointed at a renewal link that does not exist at that building; Fede's reject). Two Western Slope rejects on Sep 23 were an incident (old inquiries re-surfaced as new), not draft defects.

How often it misfired. At real customers, 24 holds were approved exactly as drafted and 113 expired with nobody deciding. The expiries are almost all the maintenance notices (work order created, rate your repair): notice text built from a template, held because the maintenance module is supervised at Western Slope and Situs. Situs has never decided a single one. Approvals at Western Slope take a median 15 minutes and a 90th percentile of 49 minutes (22 approvals), so a prospect's first email waits that long on top of Clara's own time; 3 Western Slope first emails and 2 in-thread prospect replies expired unsent, which means the lead waited a day and then the team took the thread.

Opus 5.5 replay (68 held drafts replayed so far, Oct 26). Same records, same prompt, two models, one judge. "Would be stopped" is the judge saying a careful property manager would stop the draft; "material" means a wrong fact, link, date or promise, not style. Calibration against the people who decided: on the 40 text replies (test properties), the judge would stop 2 of the 7 drafts a person rejected and 6 of the 30 a person approved, on either model, so the judge is stricter than the team on style and misses most of what the team rejected (those rejects were format asks, not facts). On the 28 real first emails the judge is not usable: it cannot see the facts bundle the writer had (open homes, tour windows), so it calls real facts "invented" and stops 22 of 28 on production and 21 of 28 on Opus 5.5. The deterministic checks per arm are the reliable comparison there; they are in report 3.

Case setReplayedProduction model would be stoppedOpus 5.5 would be stoppedStaff actually rejectedProduction model served
In-thread prospect email replies0 of 4not replayable through the read-only door today (it rebuilds text turns and first emails only)
Fairhaven (test) reply texts408 (4 material)6 (4 material)2claude-sonnet-5
Western Slope first emails2822 (22 material)21 (19 material)10claude-sonnet-5

Judge calibration: the 8 engineering-recomposed first emails are labelled ground truth for "stop"; the production arm's stop count on those rows is the check that the judge is strict enough. The Fairhaven reply texts are a test org and say nothing about customers; they are here because they are the only held reply texts that exist. The one Fairhaven reject (the non-existent renewal link) reproduced on the production model and did not on Opus 5.5.

Decision. Fede has already ruled that supervised stays per customer and he sets it by hand (Oct 25, relayed by the Clara Refactor session in the A1 decision above: "situs stays supervised", "they live wherever they are today and what I decide manually"). So the question for this gate is narrower than keep or remove.

QuestionOptionsRecommendation
Template notices (work order created, rate your repair) inside the hold?(a) keep holding them; (b) send them without review and keep the hold for model-written replies only; (c) turn the notices off at Situs and Western Slope until maintenance goes live(b). A template cannot have the defects the hold exists to catch, and 108 of 119 at real customers died in the queue. No switch: this is a fix to live behavior.
What happens at the 24-hour expiry?(a) silent drop, as today; (b) drop and tell the team in the same Slack card that the person was never answered; (c) auto-send on expiry(b). Today a prospect waits a day and nobody is told. (c) is a turn-on by the back door and is not Fede's ruling.
Does the hold earn its delay on model-written replies once the module runs on Opus 5.5?(a) keep as is; (b) keep supervised but on Opus 5.5 so the reviewer sees the better draft; (c) drop the hold where the replay shows zero material stops(b) now, (c) per customer on Fede's word, after the replay above is complete and he has read the material rows.

Sources: hold rows read Oct 26 (006); origin PRs from git history (006); 30-day fire counts and the sampled verdicts (13 wrong, 4 right, 7 unclear of 24) in the inventory section (001); replay files in session 006's scratchpad. Report order: the anomaly review gate (below), then the first-email draft checks, then the strip and rewrite layers, one per hour.

Report 2 · The anomaly review gate (holds a turn when the machinery, not the text, looks wrong)

What it is. After Clara's reply is drafted, this gate looks at how the turn went, not at the words: a tool that crashed, a validation conflict, the output gate refusing, a say-do mismatch (the reply claims an action no tool took), a bare "yes" that overrode a question, a person asking for a human, or a turn that timed out. When one of those seven signals fires it parks the draft on the conversation, pages the on-call in #alerts, and on voice says "Let me check on that and get right back to you." The same cause on the same conversation is held once per hour without a second page.

Why it was built. PR #4061 (merged 2026-07-18), the third fix PR for the Camellia tour incident of 2026-07-17, where a renter asked to tour that day, Clara confirmed a tour three days later (his move-in date) and wrote the calendar event for it, then a second email contradicted the first and gave out the building buzz code. It was scoped to the leasing and scheduling tools first and shipped with kill switches defaulting on. The model drafting replies then was the mid-2026 Sonnet; the incident class it targets (a reply that asserts something the tools did not do) is exactly the class a stronger model makes rarer, which is the Opus question for this gate.

How often it has fired. Ten held turns in all retained production logs (Vercel runtime since Sep 23, inbound processor 30 days, renewal worker 90 days with zero; 006 CloudWatch count, Oct 26). One was a real customer: Western Slope, Oct 22, a prospect email turn that timed out. The other nine were test properties: five tour-booking tool errors on Fairhaven voice tours, two tour-booking tool failures at the Willows, two turn timeouts (Willows, Yale sandbox). Two more fires in the same hour were deduplicated. Every fire was a tool error or a timeout; the five content signals (validation conflict, output gate refusal, say-do mismatch, bare-affirmative override, human request) have never fired in retained history. The gate's own earlier history (Jul 17 to Sep 22) is not in CloudWatch.

Has it caught bugs, and how often did it misfire? The one real-customer fire held an empty draft from a timed-out turn, and 18 seconds later the first-email path answered the prospect anyway, with a text from the inbox mirror two minutes after that; nobody had to review anything and the prospect saw no gap. So since Sep 23 the gate has caught zero wrong replies at a customer and produced one on-call page, for a turn the first-email path answered on its own 18 seconds later (the message rows above). At test properties it held nine turns, seven on a failing tour-booking tool and two on timeouts, with no page (sandbox fires never page); that is an engineering alarm, not a reply gate.

Opus 5.5 replay. Not applicable, and that is the finding. The model is not the main variable: a tool crash is the tool's, and a timeout is the whole turn's clock (a faster model could cut timeouts, a slower one add them, and no replay can show it because these turns cannot be rebuilt). The content signals that a stronger model could change have never fired, so there is nothing to replay. Seven of the ten held turns were voice tours and one an in-thread email, which the read-only door cannot rebuild; the two other timeouts were test properties (one text at the Willows, one email from the email stress rig at the Yale sandbox).

Decision.

OptionsRecommendation
(a) keep as is, seven signals, hold plus page; (b) keep only what has ever fired, tool failure and timeout, as a retry first and a page only when the retry also fails, and delete the five content signals and the parked-draft review surface; (c) remove the gate and rely on the send gate and the hold(b). The gate is an infrastructure alarm wearing a review gate's clothes. Keep the alarm, drop the review. Under the rollout rule this is a change to behavior that is already live, so it ships with no switch. One caution from the gate's own source: a turn's tools may already have run before the crash, so a blind re-run could book or send twice (#11694); the retry has to be of the drafting step only, never of a tool that already ran. The five content signals come back only with a reproduced case, as a replay cell in the harness, not as a gate.

Report 3 · First-email draft checks (Clara's first email to a new renter; 9 rules plus 3 sibling checks; 53 fires since Sep 28, 40 at Western Slope)

What it is. Before Clara's first email to a new renter goes out, a set of fixed rules reads the draft. Nine of them live in one file (no tour times offered while times were on hand; one price quoted for every size; a unit label on a one-home address; a hedged money fact such as "usually"; wording that implies an earlier contact; a size question with no tour ask; a "that one is gone" claim with no availability read; a promised follow-up nothing backs; any dash). Three siblings run in the same step: no home named, a sentence nothing on file backs (the fact trace), and a unit count. None of them is a model call. Since Oct 24 a failing draft gets one retry by the writer with the findings, and if it still fails it is held and nothing is sent. Before Oct 24 a failing draft went to a second model that rewrote it, and the rewrite went out.

Why it was built. PR #13351 (merged Sep 29, "live bug fix, no switch") added the first two rules in Western Slope's launch week, when first emails closed with a size question while tour times were on hand and quoted one price across sizes. The other seven arrived one or two at a time through Oct 24 (#13471, #13568, #21058, #21085, #22178), each after a draft someone did not like. PR #22249 (Oct 24) turned the rewrite into check, retry once, hold, after the Oct 22 Ember Estates incident, where the rewrite step produced the unit counts and roster that went out.

How often it fires (CloudWatch, both log groups, Sep 28 to Oct 26).

EraWhereFiresWhat firedWhat happened to the draft
Rewrite era, Sep 28 to Oct 24Western Slope3517 draft rules, 15 no home named, 2 unit count, 1 draft rule still failing after the one retry34 rewritten by a second model and sent; 1 held (Oct 5), rerun into review Oct 7, expired unreviewed
JP&Co21 draft rule, 1 unit countrewritten and sent
Test properties86 draft rules, 2 unit countrewritten
Check era, Oct 24 22:19Z onWestern Slope54 no tour times, 1 no home named plus fact trace2 passed on the retry and went out; 3 held
Situs Group1no tour timespassed on the retry
Willows (test)2no tour times1 passed, 1 held

Which rule does the work. Of the 23 draft-rule fires that name a rule, 20 are "no tour times offered". Three rules fired once each (a promised follow-up nothing backs, a dash, wording implying prior contact). The other five rules have never fired. Every fire in the check era is "no tour times" except the last.

The retry works; the hold path does not. Where the writer's retry ran, it passed 4 of 4 times. In all 4 held cases the retry never ran at all (the log says retried: false; three from the inbound processor, one from the web runtime, so it is not one host's problem). The cause is not pinned down. One candidate, a writer round that ended in a tool call so nothing was captured, does not fit the data: the 4 held turns and the 4 passed turns all made tool calls, and in both groups some ended on a tool result. What is left is the capture not being reached on the inbound-processor path, which needs a code trace, not more logs. Either way the design "retry once, then hold for a person" has run as "hold at once" every time it held.

Has it caught a bug a renter would have felt? No. "No tour times" is a weaker email, not a wrong one, and in the rewrite era the fix was the rewrite step that PR #22249 removed on Oct 24 (checks now hold, never rewrite). The one sibling catch at a real customer in the check era was wrong: on Oct 26 at 15:35Z the fact trace held a draft for saying the application had been sent, and the application-send tool had finished about ten seconds earlier in the same turn (001 read the same logs the same way).

Misfires and what a hold costs. A check hold writes no review record and tells nobody: the row sits as "held" on the intent until an engineer finds it and reruns it with a script. Of the 4 real held first emails, 2 were rerun into review by hand (Oct 7 by a session, expired unreviewed; Oct 26 14:41Z by 001, approved by Fede at 15:28Z as written), and 2 had no review record as of this report. Neither of those two renters went unanswered: the Oct 25 renter had asked about two homes and got Clara's first email for the other home two minutes later; the Oct 26 15:35Z renter got Clara's text with the application link within a minute of the inquiry and a Western Slope team member texted them four minutes in, so the held email did no harm. A rerun of that second one at 17:16Z by this session (not needed, from a misread of the thread) produced no email and no review record; Clara's turn ended in a team hand-off and a turn-integrity hold on the thread, which this report owns and reported to Fede.

Opus 5.5 replay. The 28 real first emails from report 1 (27 Western Slope, 1 Situs Group) were rebuilt through the read-only door on both models with the same prompt, and the same deterministic checks were run on each draft. The judge is not used here (see the calibration note in report 1).

Checks on the fresh draftProduction model (Sonnet 5)Opus 5.5
Would be sent to the retry (any check fails)15 of 2811 of 28
Unit count stated ("a few other homes")97
Draft rules (no tour times, dash)64
No home named30
Of the 14 first emails staff approved as written9 would retry6 would retry

The fact trace and the send door did not run through the door (they need live property data), so these counts cover the nine rules, the home-named check and the unit-count check only.

Decision.

QuestionOptionsRecommendation
Keep the nine rules?(a) keep all nine; (b) keep the two that matter (no tour times; no dash) and delete the seven that fired once or never; (c) delete the step(b). Seven rules are dead weight with a maintenance cost and a false-hold risk each; the two that remain are the ones Fede asked for by name.
Still needed on Opus 5.5?(a) yes, as is; (b) yes, the check, with the retry fixed so it always runs; (c) no(b). Opus trips the rules less often (11 vs 15 of 28) but still trips them, mostly on the unit count. With the retry working, 4 of 4 retries passed, so holds should approach zero on either model; the check then costs one extra writer call now and then and never a hold.
What does a hold do?(a) as today, a silent row an engineer reruns by script; (b) the same review hold and team notice the supervised path uses; (c) send anyway(b), and until it ships, (a) is a dropped lead. A fix to live behavior, no switch, one PR.

Sources: CloudWatch log lines "First-email draft check fired", "First reply named no home fact", "unit_count_stated" and "First-email check fired", web runtime and inbound processor groups, Sep 28 to Oct 26 (006); first-email intent rows and message rows read Oct 26 (006); PR bodies #13351, #13471, #13568, #21058, #21085, #22178, #22249; replay files hold-replay-email-results (006, Oct 26); 001, gate inventory Oct 26, section 6B (3 wrong, 1 right, 2 unclear of 6 first-email holds).

Report 4 · The two "no claim without a lookup" retries (tour times and unit availability; 63 fires in 90 days, 19 at customers; Clara reads the calendar or the unit list and writes the reply again)

What it is. Two small fixed rules read every reply Clara drafts on a text or email turn. The tour-time rule fires when the draft names a clock time ("I have 10:00 AM or 2:00 PM", "1:00 PM isn't open") and no calendar tool ran in that turn. The unit rule fires when the draft, or the renter's own message, names a unit number tied to availability and no unit lookup ran. Neither one holds or rewrites. The draft is thrown away, Clara is told to read the calendar (or the unit list) first, the tool is forced on the next model call, and she writes the reply again. The second reply goes out whatever it says. Nobody sees that it happened except the log.

Why it was built. The unit rule came first: PR #10579 (merged Sep 21) after a Camellia email on Sep 19 where Clara wrote that two units were "set to be available by September 17" and both were occupied, with zero tool calls in the turn. The tour-time rule is PR #14124 (merged Sep 30), after a Western Slope email the same week where a renter proposed Friday at 1:00 PM and Clara answered "1:00 PM on Friday isn't open, but I do have 12:00 PM or 11:30 AM" without reading the calendar. Both PR bodies say live bug fix, no switch. Both are the exact kind of incident Fede's question is about: a wrong time or a wrong unit stated as fact.

How often it fires (agent traces, Sep 21 to Oct 26). Every fire leaves a retry step in the turn's trace, with the draft that was thrown away, the forced tool's answer and the reply that went out. That is what the table below is graded from, not the model's opinion.

WhereRuleFiresWhat the draft had doneDid the forced lookup change what Clara offered?
Western SlopeTour times55 offered times with no calendar read (6 email, 3 text across both customers)3 changed, 2 same
JP&Co (Camellia)Tour times43 offered times, 1 declined a time2 changed, 2 same
Western SlopeUnit availability55 named a unit1 changed, 4 same
JP&Co (Camellia)Unit availability53 named a unit, 2 had no unit in the draft (the renter's message named one)1 changed, 4 same
Situs Groupeither0
Test properties (Willows, Yale, Fairhaven)Tour times2615 offered, 11 declined10 changed, 15 same, 1 reply had no time
Test propertiesUnit availability1816 named a unit, 2 did not6 changed, 10 same

63 retry steps in traces; the CloudWatch warn lines count 62 (60 in the inbound-processor group, which keeps 30 days, and 2 in the web runtime group), so one trace fire has no warn line. Every fire was on Sonnet 5, the production model for the whole window. The forced tool ran every time. Each fire added a median 7 seconds to the reply (longest 28 s). No fire ever held a reply.

The 19 fires at customers, one by one, graded against the forced lookup. A "catch" means the thrown-away draft stated something the calendar or unit list then contradicted. "Moot" means the draft was right and the retry only cost time. "Misfire" means there was no claim to check, or the retry never checked it.

RuleGradeFiresWhat happened
Tour timesCatch4Two Camellia texts offered "10:00 AM or 2:00 PM" on days where the calendar only had a morning window; the sent reply offered 9:00 to 11:45. One Western Slope email on Oct 7 offered windows on Monday Oct 5, a day already past; the sent reply offered Wednesday. One Western Slope text re-offered four windows from an earlier read; two of them were gone and the sent reply dropped them.
Tour timesMoot4One decline ("12:00 PM isn't open, 11:45 or 11:30 are") was exactly what the calendar said. Two replies offered the same windows the calendar then returned. One restated the time the renter had asked for; the forced read found it open and Clara booked it in the same turn, which the draft had not done.
Tour timesUnresolved1Western Slope, Oct 14: the renter had asked for Saturday; the draft offered "10:00 AM or 2:00 PM"; the forced read said the asked-for time was open and to book it now; the sent reply still offered 10:00 or 2:00 and did not book. The retry read the calendar and the model ignored it.
Unit availabilityCatch0No fire at a customer found a unit stated as available that the lookup did not have.
Unit availabilityMoot3Camellia's one open one-bedroom, named twice, was in the lookup both times. A Western Slope text saying a unit was "not showing as available" was confirmed by the lookup.
Unit availabilityMisfire7In 5 the forced tool was the tour calendar, not the unit list, because the property's tool set has no unit lookup; the rule accepts either as grounding, so the retry satisfied the rule without ever checking the unit (one of these was "Unit 405 is the one you're touring", not an availability claim at all; two repeated a home list Clara had given minutes earlier). In 2 the draft named no unit; the rule fired on the unit number in the renter's own message.

Pattern worth naming: the pair "10:00 AM or 2:00 PM" appears in 4 of the 9 tour-time drafts at customers, and in 3 of them (three days, two customers) the calendar did not have those times. That is a Sonnet 5 habit, not a property fact, and it is most of what the tour-time rule caught.

Has it caught a bug a renter would have felt? Yes, the tour-time rule has, 4 times at customers in four weeks: a renter would have picked 2:00 PM on a day with no afternoon slot, or a Monday that had already passed. The unit rule has not caught one at a customer since the Camellia incident it was built for; its 10 customer fires were 3 confirmations and 7 retries that checked nothing. Neither rule has ever caused a wrong reply; the cost is 7 seconds a fire and, once, a retry the model ignored.

Does the new setup still need it? (Opus 5.5 replay.) This is the one gate so far whose fires cannot be replayed on another model: they are renter (prospect) text and email turns, the read-only bench door only rebuilds tenant texts and first emails, and the recorded-turn path (every model request saved as Clara saw it, since Oct 24) holds none of these turns because the rules have not fired at a customer since. So the honest cell is "unmeasured on the fire turns". The nearest evidence, from turns the door can serve:

Turns replayedArmRepliesNamed a time or unit with no lookup (the rule would fire)Called the calendar or unit list on its own
29 recorded customer turns since Oct 24 (JP&Co email 9, JP&Co sms 2, Situs Group email 1, Western Slope email 14, Western Slope sms 3), mostly tenant emails and texts, served by the door from the saved requestProduction (Sonnet 5, same prompt)2985
Opus 5.5, same prompt29114
40 held tenant texts from report 1 (Western Slope, Situs Group, Fairhaven test), rebuilt from the recordsProduction (Sonnet 5)4020
Opus 5.54000

Reading the 29 recorded turns: 8 production replies (Sonnet 5) named a tour time or a unit with no lookup in the turn, 6 of them times. Most were first replies to a new renter, where tour windows also come from the facts bundle, so not every one is invented; but Opus 5.5 on the same requests read the calendar or unit list itself on 14 turns against 5, and the tour-time rule flagged none of its replies (the rule excuses times a recent read already put on the table, so this is the rule's verdict, not a count of tool calls). The one Opus flag and one of production's are the same turn: a renter's application email, where the unit rule read the tax form "W-2" as a unit number. On the 40 held tenant texts neither model needed either rule.

The detector numbers above come from running the same two pure rules over each arm's reply text and tool names, with the same prior-turn context the live gate builds. Both production-arm flags in the 40 texts were a tenant's own unit named in a renewal-rate reply at the Fairhaven test org, which is a detector false positive, not an availability claim.

Decision.

GateBuilt forReal catches sinceDoes the new setup still do the thing?Verdict
Tour-time claim retryWestern Slope email, Sep 30: a time declined and two offered with no calendar read (#14124)4 of 9 customer fires were real (invented "10 or 2", a past Monday, stale windows); 0 wrong declines caught; 1 retry ignoredUnmeasured on the fire turns. 0 unbacked time claims from Opus 5.5 on the ordinary turns we could replay. Sonnet 5 invented the "10 or 2" default 3 times.Keep for now, as the one calendar rule inside the facts check: "every clock time Clara offers came from a calendar read this turn". Re-decide after one week on Opus 5.5: every turn is now recorded with its checks, so that week answers it from the index rows alone. If Opus never trips it, delete.
Unit-availability claim retryCamellia email, Sep 19: two occupied units called available with zero tool calls (#10579)0 of 10 customer fires were real; 7 were misfires, 5 of which never checked the unit because the forced tool was the calendar0 unbacked unit claims from Opus 5.5 on the replayed turns; the first-email path already forces the unit list on turn 1.Delete the retry. Keep the one-line log so the week on Opus still counts it. If a unit rule survives, it belongs in the facts check as "a unit called open must be in this turn's unit list", with the calendar no longer accepted as proof.

Sources: agent trace rows with a tourtimeclaim-retry or availabilityclaim-retry step, read Oct 26 (006); CloudWatch warn and info lines for both gates, both log groups, 90 days; PR bodies #10579 and #14124; snapshot index rows TurnSnapshot since Oct 24 and the two-arm replay through the read-only door (scratchpad gates/snapshot-replay-results.jsonl); report 1 replay rows for the 40 texts. No renter name, phone or message text appears here; the drafts were read from the traces and are described, not quoted beyond clock times.

Report 5 · The "lock in" booking-promise guard (40 fires in 90 days, 9 at customers; a phrase list that regenerated or rewrote Clara's tour replies, and since Oct 25 holds them)

What it is. A fixed list of phrases is run over every tour reply Clara drafts on a text or email turn where no tour is confirmed yet: "lock in", "locked in", "lock it in", "you're all set", "book it right away", "automatically booked", "consider it booked", "no extra steps". Until Oct 25 a match meant one regenerate (same model, told to drop the phrase); if the phrase survived, the sentence was replaced by a fixed line and the reply went out. Since Oct 25 (PR #22296) a match is a block: the writer gets one retry, and if the phrase is still there the reply is held for a person. The renter never sees any of this except the wording that results.

Why it was built. PR #9635 (merged Sep 19), after a strengthened eval case (#9572) showed the drafting model writing "I'll lock it in" as if the tour were booked, 2 of 2 runs, even with the prompt rule that forbids it. No customer incident is named in the PR. Two later changes narrowed it: #18657 (Oct 11, stands aside on a cancel or decline) and #22292 (Oct 25, "lock in a 12-month lease" is the lease special, not a tour, after a Willows email went out cut off, #22289).

How often it fires (CloudWatch, Sep 26 to Oct 26). The log group that carries these lines keeps 30 days, so this is one month, not the 90 days the other reports cover.

WhereFiresPhraseOutcome
Western Slope5lock in 2, lock it in 1, locked in 1, you're all set 15 regenerated
JP&Co (Camellia)4lock it in 1, lock in 1, locked in 1, you're all set 13 regenerated, 1 fixed-line rewrite
Situs Group0
Test properties (Willows 22, Fairhaven 5, Yale 3, pipeline lab 1)31lock in / locked in 28, lock it in 2, you're all set 130 regenerated, 1 fixed-line rewrite

All 40 fires were a "lock" phrase or "you're all set"; the other four phrases on the list never fired. 10 fires in late September (from the 26th), 30 in October. Last fire Oct 24 23:35Z at the Willows; no fire since the Oct 25 block-only change, and the hold path writes no log line of its own, so a hold since then would show only as a held reply, and none has. Every fire was on Sonnet 5. The regenerate added a median 1.9 seconds (longest 11 s). No fire ever held a reply before Oct 25.

The 9 fires at customers, one by one. Graded from the trace: the draft that was thrown away, and the reply that went out. A "catch" would be a draft telling a renter a tour was booked when it was not.

WhenWhat the draft saidWhat went outGrade
Western Slope, Sep 26, text"give me one day and time… and I'll lock in the virtual tour" (asking for a time)Same reply reworded, sent with a stray """ at the start (the regenerate echoed its own delimiter; fixed by #15250 on Oct 2)No claim. Made worse
Western Slope, Oct 2, email"could you confirm one date and time… once I have that, I'll get it locked in""…I'll check availability and send a confirmation"No claim. Harmless
Western Slope, Oct 2, emailRenter was on a tour at that moment: "you're already here touring… so you're all set, no need to book anything else" (true)"…is available for a tour this morning, let me know if that time works and I'll get it booked", wrapped in """True draft turned false. Made worse
JP&Co, Oct 3, email"we offer 6- and 12-month terms at the same rate, so you're all set either way" (lease terms, not a tour)Same answer plus a boilerplate "I'll send a confirmation once it's booked"No claim; the list still matches this today (the lease exemption in #22292 covers "lock in", not "all set"). Harmless
JP&Co, Oct 4, text"just to lock it in, you mean 10:00 AM on the 7th, right?" (a question)"Just to confirm, you mean 10:00 AM…"No claim. Harmless
JP&Co, Oct 6, text"I don't actually have a way to lock in a viewing… nothing is booked for the 13th" (the opposite of a promise)Regenerate kept the phrase, so the fixed line replaced the sentence: "I'll send a confirmation once it's booked. I'm sorry for any confusion there…"Honest draft mangled. Made worse
JP&Co, Oct 20, email"Let's get your tour locked in, what day and time works?""Let's get your tour set up… Once you pick one, I'll book it, and my reply will tell you whether it's confirmed"No claim. Harmless
Western Slope, Oct 23, text"1:30 isn't open, I've got 12:00 or 2:00… could I grab your full name to lock in the tour?"Dropped both open times: "let me check what's actually open… what day and time would work?"No claim. Made worse
Western Slope, Oct 23, text"I can do 2:00 or 2:30 on the 28th… can I get your full name to lock it in?"Same times, "lock it in" replaced by the booking boilerplateNo claim. Harmless

None of the nine drafts told a renter a tour was booked. "Lock in" is how Clara (and leasing staff) say "book it once you pick a time"; the list reads intent as a claim. The one "all set" that was about a tour was true: the renter was on it. Four of the nine regenerations made the sent reply worse than the draft, and two of those four went out with a stray """ on a renter's phone or inbox.

Has it caught a bug a renter would have felt? No, not once at a customer in 90 days. Its own rewrite layers were the hazard: the fixed-line replacement erased an honest sentence (JP&Co, Oct 6), and a regenerate turned "you're already on the tour" into an offer to book it. Those two layers were removed on Oct 25 (#22296); what remains is the phrase list plus a hold, which has not fired yet.

Does the new setup still need it? (Opus 5.5 replay.) Like report 4, the fire turns themselves are renter tour replies the read-only door cannot rebuild, so they are unmeasured on Opus. The same phrase list run over every reply from the turns the door can serve:

Turns replayedArmRepliesPhrase on the listWhat it was
29 recorded customer turns since Oct 24 (mostly tenant texts and emails)Production (Sonnet 5)261"You're all set, your tour is confirmed for Monday": a tour the records show as confirmed; Opus wrote the same confirmation without the phrase
Opus 5.5270
40 held tenant texts from report 1Production (Sonnet 5)401"you're all set" about a renewal, not a tour; the guard would not have run
Opus 5.5400
28 Western Slope first emails from report 1Production (Sonnet 5)283"You're all set for your tour on " to a guest card that arrived with a showing request. Both models do this at the same rate; the Opus three are three recomposes of one inquiry (same home, same Friday 3:00 PM). Whether that showing was already confirmed sits in the facts bundle the replay row did not keep, so these are not graded; the first-email composer does not run this guard anyway (its own checks are report 3).
Opus 5.5263

Replies counted where the arm produced text (a few turns ended in a hand-off or a tool call with no reply, so the counts differ by arm). The phrase list is the production regex run over each reply; it does not know whether a tour is booked, which the live guard does know.

Decision.

GateBuilt forReal catches sinceDoes the new setup still do the thing?Verdict
Booking-promise phrase guard (regenerate, fixed-line rewrite; hold since Oct 25)An eval case, Sep 19 (#9572): the model wrote "I'll lock it in" as if booked. No customer incident named.0 of 9 customer fires were a claim; 4 of 9 regenerations made the reply worse, 2 sent a stray """; 1 true sentence turned falseUnmeasured on the fire turns. 0 list phrases from Opus 5.5 on 67 replayable customer turns and texts; Sonnet 5 wrote 2, both true statements. On first emails both models say "all set for your tour" at the same rate, ungraded.Delete the phrase list. The thing it was meant to stop is a fact, not a phrase: "Clara says a tour is confirmed only when the records show a confirmed tour". That belongs in the one facts check, next to the calendar rule from report 4, where it reads the tour state instead of guessing from "lock in". With the Oct 25 hold in place, the nine customer fires above would now be nine holds on replies that had nothing wrong with them.

Sources: CloudWatch BookingPromiseGuard warn lines, both log groups, Jul 28 to Oct 26 (scratchpad gates/booking-fires.json); agent trace rows for the 40 conversations with the safety:booking-promise step, draft and sent text (gates/booking-cases.json); PR bodies #9635, #15250, #18657, #22289, #22296; the production phrase regex run over the report 1 and report 4 replay rows (gates/hold-replay*-results*.jsonl, gates/snapshot-replay-results.jsonl). Drafts are paraphrased or quoted only for the matched sentence; no renter name, phone or message text appears.

Report 6 · The "never say how many homes are open" check (built Oct 19 on Fede's ruling; 5 replies redrafted in its first week, 2 at customers)

What it is. Before an email or text goes out, a fixed rule reads the reply for a quantity of homes: a number in front of a home type ("two 3-bedrooms"), a vague count ("a few other homes"), a plural type said to be open, one type open now and opening later, or a list of homes the renter did not ask about. If it finds one, Clara is told to write the reply again without saying how many; if the second draft still counts, the count is cut by hand and the rest goes out. Email and text only; voice keeps its prompt rule. It never holds.

Why it was built. Western Slope staff wrote on Oct 19 about a Pomona Park email thread of Oct 18 in which Clara had counted the homes open now and opening Oct 20 (the planning note quotes her sentence: "two 3-bedrooms (Units 204 and 405) open now and four 3-bedrooms opening October 20"), and asked that she never give counts. Fede, Oct 19, per the same planning note: "No counts at all". A read-only pass over Clara's outbound since go-live found 16 messages that counted homes (13 Western Slope, 3 Camellia); 6 of them were the first email's own dictated first sentence, which the prompt had told Clara to write that way since Sep 25. PR #21141 (Oct 19) stopped the prompt from counting and #21145 (same day) added this check; #21806 (Oct 22) widened it to rosters and now-and-later after a Western Slope first email the count-only rule had passed. Both are fixes with no switch.

How often it fires (CloudWatch and traces, Oct 19 to Oct 26).

WhereReplies redraftedWhat the draft saidWhat went out
Western Slope (Oct 23, email)1The asked-for home is gone, then "a few other homes": three addresses with beds and pricesOne 4-bedroom at its price, "or would you like to see something else?". The other two homes, one of them the only 3-bedroom, were dropped.
JP&Co (Oct 24, email)1"studios and one-bedrooms available right now""a studio available right now… and a one-bedroom", everything else kept
Situs Group0
Willows test (Oct 23, two texts; Oct 24, one email)3"one-bedrooms open… a couple of two-bedrooms"; "units 105 or 106, both one-bedrooms, are open"; "one-bedrooms and two-bedrooms available" plus the special and the tour windows"a one-bedroom is open… a two-bedroom's available"; "unit 105, a one-bedroom"; the Oct 24 email went out without the tour windows and the special (the "lock in" guard of report 5 fired on the same draft; this is the Willows incident #22289)

6 log lines, 5 distinct replies: the Western Slope email was checked on both its doors (first-email and main loop) in the same minute. Every fire ended in the redraft; the hand cut never ran. Every fire was on Sonnet 5. Five of the six lines sit in the inbound-processor log group, one in the web runtime group.

Has it caught what it was built for? Yes, by Fede's rule: both customer fires were a quantity or a roster, 4 and 5 days after the ruling, with the prompt already fixed. The cost shows in the same two rows: the redraft is a free rewrite, and in 2 of 5 fires it dropped real content (a home type at Western Slope; the tour windows at the Willows, together with the other guard).

Does the new setup still need it? (Opus 5.5 replay.) The same rule, minus the roster kind (it needs to know which home the renter asked about, which the replay rows do not keep), run over every reply from the turns the door can serve:

Turns replayedArmRepliesSaid how many
29 recorded customer turns since Oct 24Production (Sonnet 5)260
Opus 5.5270
40 held tenant texts from report 1Production (Sonnet 5)400
Opus 5.5400
28 Western Slope first emails from report 1 (Sep 21 to 24, written with that week's prompt, which still told Clara to count)Production (Sonnet 5)289 (counts 2, "a few" 6, now-and-later 1, plural 1)
Opus 5.5264 (counts 2, "a few" 1, now-and-later 1)

Neither model counts on ordinary turns. On first emails under the old prompt both did, Opus less; the Oct 19 prompt fix is what changed that, and the two customer fires since show Sonnet 5 still slips.

Decision.

GateBuilt forReal catches sinceDoes the new setup still do the thing?Verdict
Unit-count check (redraft, then cut)Fede's Oct 19 ruling after the Pomona Park email; 16 counted messages at customers before it (#21145, #21806)2 of 2 customer fires were real under the rule (one week of data); 2 of 5 redrafts dropped real contentOpus 5.5: 0 counts on 67 ordinary turns, 4 of 26 on old-prompt first emails (Sonnet 9 of 28)Keep, as one rule inside the facts check ("never a quantity of homes; name one per type"). It has a standing ruling behind it. The redraft should keep every other sentence or not run; re-read after a week on Opus 5.5 from the recorded turns.

Sources: CloudWatch guard:unit_count_stated lines, both log groups (scratchpad gates/three-gates-lines.json); agent traces with the safety:unit-count-stated step, draft and sent text (gates/three-gates-cases.json); docs/planning/no-unit-counts-2026-10-19.md; PRs #21145, #21806; the production detector run over the replay rows (gates/unitcount-arms.mts). No renter name, phone or message text appears here; drafts are paraphrased or quoted only for the counted phrase.

Report 7 · The internal time-stamp strip (15 fires since Sep 26, 6 at customers; a one-line cleanup that never misfires)

What it is. Older Clara replies reach the model with a bracketed note in front of them saying when they were sent ("[Context note, never write this in a reply: sent Thursday, October 15…]"). Sometimes the model copies that line into its new reply. At the send step a fixed rule removes any line that is exactly one of those notes and sends the rest. Nothing else is touched; if nothing is left, nothing is sent and the team is told.

Why it was built. PR #14874 (Oct 1, urgent): a Western Slope renter texted "I'm here" and the reply went out starting with "[Sent Thursday, … not necessarily now.]". The same PR reworded the note so it tells the model not to copy it; this strip is the backstop in case it does anyway.

How often it fires (CloudWatch, Sep 26 to Oct 26; the log group keeps 30 days).

WhereFiresWho was being answered
Western Slope42 staff texts on the front-door line, 2 renter texts (in Spanish, Oct 13)
JP&Co (Camellia)21 renter email (Oct 4), 1 renter text (Oct 6)
Situs Group0
Test (Willows 5, Yale sandbox 4)9staff and renter texts

15 fires, 13 texts and 2 emails, between Oct 4 and Oct 22 (14 lines in the inbound-processor log group, 1 in the web runtime group). Each one removed exactly one line, and the rest of the reply went out as written. In 14 of 15 the copied line was the reworded note that says "never write this in a reply"; the model copied it anyway.

Has it caught a bug a renter would have felt? Yes, 4 times at customers (2 Western Slope renters, 2 JP&Co renters) and twice for Western Slope staff: an internal bracketed line would have opened the message. It has no misfires to count: the rule matches only the exact note lines, which never belong in a reply.

Does the new setup still need it? (Opus 5.5 replay.) Neither arm copied a note line on any of the replayed turns (0 of 94 Sonnet 5 replies, 0 of 93 Opus 5.5), which is a weak test: most replayed turns carried little stamped history. The 15 production fires are all Sonnet 5 on turns the door cannot rebuild, so the fire turns are unmeasured on Opus.

Decision.

GateBuilt forReal catches sinceDoes the new setup still do the thing?Verdict
History time-stamp stripWestern Slope text, Oct 1: reply opened with the internal sent-time line (#14874)6 of 6 customer fires were real; 0 misfiresUnmeasured on the fire turns; 0 copies from either model on 187 replayed repliesDelete the output strip; clean the input instead. The note is our own prefix on history rows, so the writer should never see it (the facts block carries message text without transport headers), and the leak itself becomes one row in the door 4 leak list (retry once, then hold). That keeps Fede's Oct 22 rule: nothing edits Clara's message after she writes it. The data supports it: 14 of 15 copies were of the note that already says "never write this in a reply", so the prompt line cannot cure what the input contains; removing the line from the input can.

Sources: CloudWatch "Internal history stamp copied into a reply" lines, both log groups (scratchpad gates/three-gates-lines.json); agent traces with the safety:history-stamp-strip step (gates/three-gates-cases.json); PR #14874; the stamp regex run over the report 1 and report 4 replay rows (gates/unitcount-arms.mts). No renter name, phone or message text appears here.

Report 8 · The hand-off template gate (22 fires in 30 days: 18 drafted replies replaced by a one-line template, 4 released; 3 at customers)

What it is. When Clara hands a question to the team in a turn (the forward tool), the reply she drafted in that same turn is thrown away and a fixed line goes out instead: "I'll check with the team on that.", "I've noted that for the property team.", or, when the team has already been asked, "Still on it. I'll get back to you the moment I hear from the team." (three variants, in English and Spanish, with a text and an email wording for the last one). The draft survives only if the model marked the forward as covering part of the ask ("scope: partial" on the tool call) and the reply still carries every answer the model recorded in that turn. One exception since Sep 24: on a brand-new renter's first email, only the promise clauses are cut and the rest ships.

Why it was built. Aug 4 (#5388): on a thread the team owns, Clara had invented an answer; the fix was "replace the whole reply, don't try to detect which sentences were substantive". Aug 10 (#5640): the replacement was also deleting real answers next to a forward, so a forward the model marks "partial" releases the reply. Aug 17 (#5826) and Aug 19 (#5915, a criminal-history question): Clara must never promise a follow-up nobody keeps. Aug 21: a "partial" reply that dropped a known answer added the known-answer check. All of it is one idea: on a turn where the team takes over, Clara's own words are not trusted.

How often it fires (CloudWatch, Sep 26 to Oct 26; the log group keeps 30 days).

WhereReplacedReleasedWhy replacedWas an ask actually opened for the team?
Western Slope (Sep 27, text)10no scope on the forwardyes, team notified
JP&Co (Oct 6 and Oct 13, texts, same resident)20no scope; scope "full"Oct 6: nothing opened (the tool answered "nobody was notified and nobody is going to be, answer the sender yourself"); Oct 13: team notified
Situs Group (Oct 14, a renewal sandbox thread)10no scopeteam notified
Test (Willows 12, Fairhaven 2, harness commons 2, Yale 2)144no scope 8, "full" 3, undelivered 2, invalid 1team notified 4, logged but not delivered 8, nothing opened 2; the 4 released were all Willows

22 lines on 19 conversations; every one on Sonnet 5. Of the 18 replacements, 11 happened because the model set no release scope at all, 4 because it said "full", 2 because the forward could not be delivered, 1 because the value was not one the gate knows. Asks opened across the 18: 7 team notified, 8 logged for pickup but not delivered, 3 nothing opened.

The 3 fires at customers.

WhenWhat the draft saidWhat went outGrade
Western Slope, Sep 27, textRenter could not open the video-tour link for a tour that morning. Draft: passed along so the team can email the link, and meanwhile try pasting the link into the browser."I'll check with the team on that."Promise was backed (team notified); the usable workaround was lost. Made worse
JP&Co, Oct 6, textA resident with a lease asked to see their unit again before move-in. Draft: office hours, the entrance code and who to ask for. The forward tool replied that this property answers these itself, nobody was notified, answer the sender."I've noted that for the property team."A correct answer replaced by a false statement. Made worse
JP&Co, Oct 13, textSame resident waiting at the leasing office for someone to meet them. Draft: flagged to the team, "they'll be with you shortly"."I'll check with the team on that.""Shortly" was unbacked; the team was notified. Catch, though the line sent to a person standing at the door is cold.

The 15 test replacements read the same way: the drafts answered a fee, offered a tour, said a home was no longer available, and ended with "they'll follow up with you"; the template erased the answer with the promise. That is the design ("no substantive content on an escalating turn"), and it is what the data shows it costs.

Has it caught what it was built for? Once at a customer in 30 days (an unbacked "shortly"). It also sent one false line (an ask that was never opened, reported as "noted for the team") and dropped one working answer. The gate cannot tell those apart because it does not read whether an ask was opened; it reads a release flag on the tool call that the tool's own description tells the model to "ALWAYS set", and the model left it out in 11 of 18.

Does the new setup still need it? (Opus 5.5 replay.) The three customer fire turns are renter texts the read-only door cannot rebuild (the Situs sandbox turn replayed: both models forwarded and wrote the same "I'll check with the team and get back to you"). On the turns the door can serve, how often each model hands off and, in the same reply, writes a promise clause (the pair that makes this gate fire):

Turns replayedArmRepliesHanded offHanded off and promised
29 recorded customer turns since Oct 24Production (Sonnet 5)2672
Opus 5.52754
40 held tenant texts from report 1Production (Sonnet 5)402816
Opus 5.5403410
28 Western Slope first emails from report 1Production (Sonnet 5)2866
Opus 5.52666

Both models write "I'll check with the team and get back to you" when they forward, because the prompt tells them to, in those words. The gate then replaces the reply for saying it unless the model also set the release flag to "partial"; the tool description demands that flag, and Sonnet 5 left it out on most fires. Opus 5.5 does not change that pair; it hands off about as often and promises less on texts. Caveat: in the door the forward tool runs nothing, so these counts say what each model writes, not whether an ask would have opened.

Decision.

GateBuilt forReal catches sinceDoes the new setup still do the thing?Verdict
Hand-off template gate (whole reply replaced on a forward unless "scope: partial")Aug 4 invented answer on a team-owned thread (#5388); Aug 19 promised follow-up nobody kept (#5915)1 of 3 customer fires (an unbacked "shortly"); 1 false "noted for the team" sent; 1 answer lost; 11 of 18 replacements were a release flag the model left out despite the tool telling it toOpus hands off as often and promises the same words; the pair that fires this gate is written by the prompt itselfDelete the template replacement. What it protects is "promises match actions", and that is a fact the open-ask record already holds: a "I'll check with the team" is allowed when an ask was opened (notified or logged) and blocked (retry once, then hold) when nothing was opened. The reply is never swapped for a template, and the answer next to the promise ships. The first-email clause cut goes the same way.

Sources: CloudWatch Agent:escalated-gate lines, reason=same_turn_escalation and same_turn_escalation_released, both log groups (scratchpad gates/handoff-lines.json, handoff-fires.json with each forward's input and result); agent traces for the 19 conversations (gates/handoff-traces.json); conversation-manager.ts, the same-turn escalation scope comment (Fede decision of Aug 10) the release-scope helper and the forward tool's scope schema in src/lib/tools/_constants.ts; PRs #5388, #5640, #5826, #5915; the door replay of the four customer turns (gates/handoff-replay-results.jsonl) and the promise detector run over the report 1 and report 4 replay rows (gates/handoff-arms.mts). No renter name, phone, code or message text appears here.

02b · Model upgrade runbook

How to move a Clara job to a new model (runbook)

Goal: a repeatable, safe upgrade. Each writer job names its model in code, in src/lib/platform/ai/model-paths.ts. A swap is one PR per job that changes that one line. Rollback is GitHub's Revert button. Never a per-company model setting (Fede, Oct 27: "this is a global rollout").

JobModel todayBench surfaceProof needed
First emailclaude-opus-5-5first_emailSteps 1 to 5
Prospect email replyclaude-opus-5-5prospect_replySteps 1 to 5
Prospect text replyclaude-opus-5-5prospect_replySteps 1 to 5
Text beside the first emailHaikuNone yetRecord its request first
Quiet-lead follow-up (and its re-engagement twin)HaikuNone yetRecord its turn first
Tour-reminder translationHaikuNone yetRecord its request first
Card notesclaude-opus-5Not named yetName a bench surface, then steps 1 to 5

The five steps

  1. Bench on the subscription, never metered keys. From the clara-bench repo, each run as env -u ANTHROPIC_API_KEY npm run -s bench -- <command>:
    upgrade --surface first_email --model <id> [--tier smoke|full]
    upgrade --surface prospect_reply --model <id> [--tier smoke|full] [--production-model <id>]
    upgrade --surface tenant_text --model <id> [--tier smoke|full]
    fede-cards control
    The last one is the planted-defect check on its own. Each run shows a "Fede cards" column: Fede's rated cards (17 Wrong, 1 Fine) are a frozen check, and an arm FAILS while any of his Wrong cards still reproduces. Any never-do finding fails the arm. The bar: better than production on the judge, Fede cards clean, never-do zero. Full tier decides; smoke is a first look. Limit: prospect_reply replays each turn's recorded prompt, so it judges a model swap only, never a prompt change.
  2. Day 0 replay must be byte-identical. The repo's frozen-cell harness, baseline day0l-2026-10 (6,487 cells). It cannot see prompt text, so it is not proof for prompt changes.
  3. Willows end to end on the real path. A real prospect conversation through Clara at the Willows test property: times asked, tour booked, calendar event, confirmation. Record ids go in the PR body. Unit tests are build hygiene, listed as "unit-covered", never as "tested".
  4. The swap PR. One line in model-paths.ts. The body names the bench run row on the Clara Bench page, the Day 0 result and the Willows ids. Merge is Fede's go for a swap; live everywhere on merge, no switch.
  5. After merge. Watch the first real sends at each customer. A regression is reverted with the Revert button, not patched forward.

Jobs the bench cannot judge yet (named debt)

The quiet-lead follow-up and its re-engagement twin (Haiku, no recorded turn); the text beside the first email (Haiku, no recorded request); the held-message redraft writer; the tour-reminder translation (Haiku). Each needs its request recorded before it can be swapped with proof.

What the other AI coworkers do, Nov 2

Full page: AI leasing assistant landscape (Viktor, OpenClaw, EliseAI, BetterBot, Zuma, Funnel and others). Ideas worth stealing, in order: (1) remember a correction after one note and undo it with one message; (2) on a reply-all thread read everything, answer only when named or when it is her item; (3) plain-words orders from staff within their own permissions ("move Maria's 3 PM to Thursday and give it to Ryan"); (4) standing orders by chat ("every evening send me tomorrow's tours"); (5) scheduled check-ins that stay quiet unless a person is needed (an agent out tomorrow with three tours, ask who covers); (6) never send a follow-up a person already sent. Complaints to design against: follow-ups before staff arrive, more tours but fewer leases, long replies to quick questions. Recommendation: fold 1, 2 and 6 into the coworker work already planned; the rest after those are proven at Willows.

Gate report, Oct 26: which checks the new Clara still needs

Three opinions, one recommendation (Oct 26 evening). Fede: "are you sure we need 29 gates?", "it seems like too many individual little pieces built once per incident", "look at anthropic / openai guidance or other frameworks / startups". Two independent reviewers at max effort (Opus 5.5 and a second Fable 5.1), each with the report and the published guidance (Anthropic, OpenAI Agents SDK, NeMo, Guardrails AI, Sierra, Decagon, Fin, Ada, Parloa), both attacked the first answer. Their full texts are below. What all three agree on, and the recommendation:

#DoorWhereWhat it doesCan it stop a reply?
1Should Clara speakbefore the writerPerson on it, nothing to answer, muted, unknown role, runaway, bare "thanks" (built: shouldSpeak)silent, with a reason
2Facts inbefore the writerCode hands the writer a facts block with ids: home, rent, size, open date, special, tour slots, policies, actions taken. The writer gets only this turn's tools.never; it removes the mistake
3Declarationat the writerStrict schema: the writer declares the ids it used (homes, slots, prices, facts, actions, asks, language)never; the API guarantees it
4Claims match the recordafter the writerOne code join: every declared fact is in the facts block, every promise has an action (booked, filed, team told via an open ask), plus a leak list (undeclared times or money, time stamps, tool markup). Replaces 30 prose-pattern lines.the only content hold: retry once, then one hold record with the check name, and an alert that re-fires at expiry
5Voiceafter the writerDashes, greeting, renter's language, staff-note shapenever: retry once, then send; the residue is a bench row
6Send doorat sendConsent, live, module on, test scope, ceiling, quiet hours; any error sends nothing and alertsrefuse with a reason
judgeFair housingafter the writerCheap word screen, then a separate model judge (Fede: keep)hold, as today

Where the first answer (five doors) was wrong, per both reviewers: it kept the fact trace as the base of the facts door (its one real fire was wrong; it judges where a fact came from, not whether it is true); it had no severity tier, so every fire held and a missing tour time cost a lead; it said nothing about the hold lifecycle (110 of 124 renter-facing holds expired unseen, the largest harm in the window); two of its seven deletes were unsafe (the typed tool-call strip and the work-order claim rule still do real work); and the 5,515-cell replay proves hold decisions, not content checks, which need recorded drafts with every fire labeled and about 300 clean cases to show under 1% false fires.

What stops one-line-per-incident: a closed registry of checks with a build check that fails any PR adding one without a row (id, join target, origin case, three controls in English and Spanish, false-fire rate, status hold / retry-only / observe / retired). An incident's first artifact is a replay ledger row and a bench row, filed by cause (fact missing, prompt ignored it, schema cannot say it, hold died, tool bug). Only "had the fact, declared it, still wrote something else" earns a column in door 4. A hold check that has not fired in 60 days or crosses the false-fire line is demoted at a monthly review.

Order of work (Fede: yes. He had approved it before Oct 31; the "awaiting his go" label here was wrong and the steps sat idle five days. Builders started Oct 31 under the grant): (1) hold lifecycle first: the retry that never ran on held first emails, and holds that re-alert at expiry; (2) facts in, with ids, on the decomposed prompt already in shadow; (3) declaration schema; (4) door 4 as one join, run in observe mode beside today's 56 lines for a week on recorded drafts, then the lines retire in one PR each as the compare and the bench show no new misses; (5) voice to retry-only; (6) registry and build check. Disagreement left open: fair housing as a hold (Opus) or alert-only (Fable); Fede said keep, so it stays a hold.

Where the six steps stand, Nov 2 (04:45Z)

StepDoneOpen
1 Hold lifecycleFede's ruling Nov 2 replaced "fix the retry" with "no retry": a first email holds on any finding (#24379). A check-held text is now a regular Supervised review with the 20-hour warning (#24378); a held draft wrong as written never reaches the card (#24400).Email half #24420 (opened 04:34Z, red: needs a rebase on #24400). Until it lands, a check-held email still expires silently at 24 h.
2 Facts in, with idsOpen homes = homes on the market (#24125); facts block carries ids, trace records it (#24142); thread facts with ids for later turns (#24247).Open-unit rent and size are not on the ids line yet (door 4 reads them observe-only).
3 DeclarationRecorded on the trace (#24151); writer fills it, an action is backed only by a call that succeeded (#24161).First email only; text turns get it in wave 2.
4 Door 4, one joinLive in observe mode since Nov 1 (#24193); replay of 357 real first emails: today's checks fired on 111, door 4 would hold 1. Wave 2 folds landed (#24258, #24288).Observe week runs to Nov 8; then the 56 lines retire one PR each as the compare and bench show no new misses. Live since Nov 1: 6 first emails through the join (2 Western Slope, 1 Situs, 3 sandbox), 0 would-hold, 0 findings. Too few to say anything about the hold rate yet. Both Western Slope emails (Sierra, Bre) were sent; Bre replied two minutes later. Emmanuel (Situs) was held by the send door for internal notes in the draft, approved by Fede at 04:11Z, and the email left at 04:11Z from the Situs company inbox (Gmail id 1a19a74784a6071e); the "delivery failed" flag on the hold was a false stamp from a text attempt and is being cleared. Text delivered 04:23Z.
5 Voice retry-onlyDash check retry-only on text and email (#24169); a dash never holds a first email or follow-up (#24196).none
6 Registry + build checkClosed registry of every check that can stop, hold, retry or rewrite (#24172); build check fails a PR adding one without a row (#24187). 307 live rows.Monthly demotion review not yet scheduled.

Gaps the report named that are still open: 110 of 124 renter-facing holds expired unseen in the window; #24420 closes that for email. Fair housing stays a hold (Fede: keep).

Opus 5.5 reviewer, full opinion (max effort, 18 sources)

No, Clara does not need 29 gates. 29 counts rule lines, mostly one idea coded again per incident. Clara needs four output gates: three code checks and one model judge. The rest belongs upstream, before the writer, at the send door or on the bench.

The four output gates (after the writer)

GateChecks the draft againstTypeIf it firesAbsorbs
1. Facts match our recordsThe turn's facts block (each home's price, special, open or gone, date, slots), the thread, the turn's actions. Never "which tool ran"CodeWrong or unlisted fact: block, retry, hold. Missing must-say fact: retry, sendFact trace, tour time this turn, weekday, price per size, gone claim, home counts, follow-up facts, hallucination guard, no tour times
2. Promises match actionsAction record and open asks (booked, filed, sent, team told), both waysCode; the writer lists its promisesUnbacked: block, retry, hold. Unsaid action: retry, sendHand-off rewrites, booking promise, promise copies, work-order claim and confirmation, say-do mismatch
3. Nothing internal leaksOne pattern list: stamps, tool-call markup, reasoning, prompt text, dashesCodeBlock, retry, hold; never stripStamp, tool-call, reasoning and prompt strips; dash checks
4. Fair housingModel judge behind a cheap word screenModelFlag, send, review same dayToday: holds first emails, flags replies
Not an output gateWhat
shouldSpeak (before the writer)Code only for one-answer lookups (opt-out, mute, unknown sender, Supervised, runaway, tapback). "A person is on it" is the model's call. Today nothing returns silent
Send doorConsent, quiet hours, live company, test recipient, duplicate, daily ceiling
Failure ruleCrash, timeout, empty reply: send nothing, alert
UpstreamOne home's facts handed in, replacing forced lookups; tools take only real slot or home ids [1]. Fixes "this is dumb"
Bench onlyGreeting, report shape, staff-note tone, size question, prior-contact wording, follow-up style

Why these four

Every real catch in 30 days is one of three:

  • A wrong fact: Will's "1 PM works" for a 4:45 tour, Jessalyn's "2-bedroom", home counts.
  • An empty promise: nobody told (3), tour not booked (7).
  • A leak: time stamps (6).

One gate per idea covers them. Only fair housing needs meaning no pattern can see, so it alone is a model judge.

Facts are checked by code. Anthropic calls a model judge "generally not a very robust method" [2]; NVIDIA's own model-run fact check is "strongly dependent on the capability of the LLM" [9]; Sierra's code guards "can't be talked out of doing their job" [10].

Gate 1 is the crux. It asks whether a fact is true, never where it came from. Asking where caused the false holds: Patrick's own application link, and Trang's and Anthony's correct times.

The facts block is also the list of what Clara may say. Hand in one home, and any count or extra home is unlisted, so over-sharing needs no separate gate. With a complete block, gate 1 rarely fires. Gates come down by fixing data, not by deleting checks.

Severity sets the action [14]:

SeverityAction
Harm: false fact, broken promise, leakRetry, then hold (refrain)
Omission: a must-say fact left outRetry, then send and log
StyleLog only

Never fix (rewrite). No tour times, the busiest check (20 of 23 named fires), should never hold.

Fair housing holds on one path and flags on another. Flag and send everywhere until labeled cases prove it precise enough to block. Its one sampled fire looked false, and expired holds risk ignoring the prospects it protects. A cheap screen in front keeps the judge to a small slice, the cascade behind Anthropic's 0.05% production refusal rate [6].

Voice cannot wait, and today voice checks edit words. On calls, gates 1 and 2 live in the data and tools: the booking tool refuses a closed slot. Even the call error line, "get right back to you", is a promise that needs an owner.

Stopping one line per incident

  1. Closed registry. Only these gates, shouldSpeak and the send door may stop, hold or silence a message. A build check fails any new site (about 255 today).
  2. Three questions per incident.
  • Fact missing from the writer's input? Fix the data.
  • Person already on it? shouldSpeak.
  • Writer had it and missed? Bench case and prompt fix.

Only a measured rate after that adds a row (fact type, action type, pattern) to an existing gate. Never a new code path.

  1. Incidents become bench cases [5][10]. OpenAI says to add guardrails from real failures [7]; that is how Clara got here.
  2. A fifth gate needs Fede's ruling and the evidence below.
  3. Delete on cost, not silence: when false fires outweigh catches, or the row asks where a fact came from.

Battle-testing

Fix the lifecycle first. It multiplies every false fire. On held first emails the retry never ran (3 of 3), and 110 of 124 renter-facing holds expired unseen. Every fire records its gate and finding (Managed Agents keeps a reason code per decision [4]). Every retry runs. Every hold ends in a send, a person or an alarm.

Then five tests:

  1. Right baseline. The 5,515 frozen cells are hold decisions: they prove shouldSpeak changes, not content precision. For content, replay recorded drafts log-only and label each fire. Records judge facts, the action record judges promises, Fede judges policy. Staff approval is a signal, not truth.
  2. Honest sizes. Zero fires in N clean cases only bounds false fires below about 3 in N. 0 of 28 still allows 11%; under 1% needs about 300.
  3. Recall on planted violations, with model-written paraphrases and a Spanish slice. "I can also do Thursday at 7:15" passed 0 of 10.
  4. Composition. Re-check every gate on every redraft, and give the retry all findings at once. Cheryl's redraft tripped the hand-off guard, Will's tripped fair housing, and Ibrahim's passed one check before the final send check held on another. Agent SDK rule: "the most restrictive result applies" [3].
  5. Not worse. Bench the gate on versus off, several runs per case [5][12], noise first. New gates run log-only for a shadow week, scored on precision and recall [8], before blocking.

Where the first opinion is wrong or shallow

Right: the five ideas, and style to the bench.

  • Miscounted. "On error" is a failure rule; shouldSpeak runs before the writer; voice is bench work except the dash ban.
  • Two deletions are wrong.
  • Typed tool call. The empty-reply rule only catches markup because the strip emptied the reply first. Delete the strip and the markup ships.
  • Work-order claim. The confirmation rule it cites covers the opposite case (filed, not mentioned), still rewrites words on calls, and reuses the claim detector.

The farewell loop and the shape checks can go.

  • Its report contradicts its doors. It keeps no tour times, report shape, forced lookups, greeting and follow-up style in production.
  • It folds 18 lines into the fact trace, the one gate whose only real fire was wrong.
  • Thin evidence. Opus samples of 28 and 72, while production runs Sonnet and follow-ups, voice and staff paths have no new writer.
  • Missing: failure actions, lifecycle, voice, anti-sprawl structure, test method, research.

Sources (read for this review)

  1. Anthropic, "Building effective agents" (Dec 2024). Make tools hard to misuse ("poka-yoke your tools"); add complexity "only when it demonstrably improves outcomes"; a separate screening model "tends to perform better". https://www.anthropic.com/engineering/building-effective-agents
  2. Anthropic, "Building agents with the Claude Agent SDK" (Sep 2025). "The best form of feedback is providing clearly defined rules for an output"; a model judge "is generally not a very robust method". https://claude.com/blog/building-agents-with-the-claude-agent-sdk
  3. Claude Agent SDK, hooks and permissions. Hooks "run in parallel. For permission decisions, the most restrictive result applies"; "deny takes priority". https://code.claude.com/docs/en/agent-sdk/hooks and https://code.claude.com/docs/en/agent-sdk/permissions
  4. Claude Managed Agents, permission policies. always_allow, always_ask, auto; each call carries an evaluated permission and a reason code "to keep in audit records". https://platform.claude.com/docs/en/managed-agents/permission-policies
  5. Anthropic, "Demystifying evals for AI agents" (Jan 2026). Code graders are "brittle to valid variations"; model graders need "calibration with human graders"; pass^k for customer-facing agents; turn failures into test cases. https://www.anthropic.com/engineering/demystifying-evals-for-ai-agents
  6. Anthropic, Constitutional Classifiers and the follow-up paper. "0.05% refusal rate on production traffic" with a cheap first-stage screen that escalates "only suspicious exchanges". https://arxiv.org/abs/2501.18837 and https://arxiv.org/abs/2601.04603
  7. OpenAI, "A practical guide to building agents" (PDF, pp. 24 to 31). Guardrails as "a layered defense"; "Add new guardrails based on real-world edge cases and failures you encounter". https://cdn.openai.com/business-guides-and-resources/a-practical-guide-to-building-agents.pdf
  8. OpenAI Agents SDK guardrails (input, output and tool guardrails; tripwires; parallel or blocking) and OpenAI Guardrails evals ("labeled datasets with precision, recall, F1"). https://openai.github.io/openai-agents-python/guardrails/ and https://openai.github.io/openai-guardrails-python/evals/
  9. NVIDIA NeMo Guardrails (input, dialog, retrieval, execution and output rails) and its fact-checking rail ("strongly dependent on the capability of the LLM to follow the instructions"). https://github.com/NVIDIA/NeMo-Guardrails and https://docs.nvidia.com/nemo/guardrails/configure-guardrails/guardrail-catalog/fact-checking.md
  10. Sierra, "Defense in depth in the age of agents" (Aug 2026): code guards that "can't be talked out of doing their job", supervisors "catch nuance that fixed rules can't". "Agent development life cycle" (Jun 2024): "Every annotated conversation ... can become a conversation test". https://sierra.ai/blog/defense-in-depth-in-the-age-of-agents and https://sierra.ai/blog/agent-development-life-cycle
  11. Sierra, "Simulations" (Aug 2025): "gate releases on specific simulations". https://sierra.ai/blog/simulations-the-secret-behind-every-great-agent
  12. tau-bench: grades the end state of the records, reports pass^k ("pass^8 <25% in retail"). https://arxiv.org/abs/2406.12045
  13. Intercom Fin AI Engine: checks whether the answer "is grounded in the knowledge of your knowledge resources", else escalates; Fin Procedures add "deterministic controls". https://www.intercom.com/help/en/articles/9929230-the-fin-ai-engine and https://www.intercom.com/help/en/articles/12495167-fin-procedures-explained
  14. Guardrails AI, on-fail actions: REASK, FIX, FILTER, REFRAIN, NOOP, EXCEPTION. https://guardrailsai.com/docs/concepts/validator_on_fail_actions
  15. LangChain guardrails: code rules are "fast, predictable, and cost-effective, but may miss nuanced violations"; model rules "catch subtle issues ... but are slower". https://docs.langchain.com/oss/python/langchain/guardrails
  16. Decagon: a supervisor model on live conversations, re-run tests on every change, "running tests multiple times is essential". https://decagon.ai/modules/agent-architecture and https://decagon.ai/modules/testing
  17. Ada: model checks for safe, relevant and accurate before each reply. https://docs.ada.cx/docs/generative/before-you-begin/understand-how-your-ai-agent-works/
  18. Parloa: rule checks on the conversation and tool trace are "precise and fast but limited to known patterns", plus a separate model as evaluator. https://www.parloa.com/labs/insights/how-parloa-stress-tests-production-deployments/

Fetched directly in this review: 1 to 8, 9 (fact-checking page), 10, 12, 13 (engine page), 14 and 15. Read through research subagents and quoted as their fetches rendered them: 9 (GitHub page), 11, 13 (Procedures), 16, 17 and 18.

Internal evidence: gate-report.json and gate-report.html, hold-gates-inventory.html, the gates and core sections of the Clara coworker loop v3 page. Code was read at repo HEAD 604b8ac278: followUpFinding, the first-email draft checks, no-dashes, shouldSpeak, the anomaly review gate and the work-order confirmation.

Fable 5.1 reviewer, full opinion (max effort, 16 sources)

Short answer: six doors, not 29 lines. Only one may hold a reply Clara wrote, for content. The leverage is before and at the writer, not after. Prose-pattern checks are why each incident adds a line.

The gates

#DoorWhereHow it decidesHold or silence?
1shouldSpeakbefore the writercode lookups (opt-out, mute, unknown role, Supervised, runaway, tapback); the model judges "person on it, anything to answer" in the writing call, reason loggedsilent with a reason; hold only where Fede set Supervised
2Facts in, choices outbefore the writercode builds the facts block with ids (home, rent, size, open date, special, slots, policies, date, actions taken); the writer gets only this turn's toolsnever: it removes the mistake
3Declarationat the writerstrict schema: the writer declares what it used, as facts-block ids (homes, slots, prices, facts, actions, asks, language)never: the API guarantees the schema
4Claims match the recordafter the writerONE code join: declared ids exist in the facts block, actions in this turn's ledger, "with the team" has an open ask (askState); a leak list for undeclared times, money, "the team will", internal markupthe only content hold: retry once, then one hold record, review door and alert
5Voiceafter the writercode: dash, greeting, renter's language, staff-note shapenever: retry once, then send; residual is a bench row
6Send doorat sendcode: consent, live, module on, test scope, ceiling, quiet hours; any error sends nothing and alerts; a Supervised hold re-alerts at expiryrefuse with a reason; hold with a record
judgeFair housingafter the writerseparate model instance, alert-only as todayFede's call

Today's 56 lines:

TodayLinesGoes to
Provenance (first-turn lookup, tour-time-this-turn, forced tour/availability retries, stale slot, "gone" claim, fact trace)7deleted by doors 2 and 3
Fact and promise shapes (fact rules, date, counts, tour times, home named, promises, work-order claim, follow-up facts, time stamp, markup)30door 4, as declaration columns and leak entries, not regexes
Style (dashes, greeting, staff-note, blast opener, size question, prior contact)12door 5, retry only
Silencers (runaway, mute, tapback, bare closer, farewell loop)5door 1; farewell loop deleted
Empty reply, anomaly gate2door 6; anomaly keeps crash and timeout only (retry once, else nothing); its five never-fired signals go to the bench

Why shape beats count

The strongest guard is a removed choice before the model: Sierra's deterministic guards "can't be talked out of doing their job" (its example: no account tools before authentication). Every wrong correctness hold in the sample was a provenance check (which tool ran this turn); of two tour-time parsers, one missed "I can also do Thursday at 7:15" 10 of 10 times and the other held a correct French reply (it reads only English and Spanish). Wording never fixes a parser; a join on ids has none, so it is language-agnostic by construction. Only block-and-retry fits Fede's no-rewrite rule; the frameworks' "fix" actions are what he ruled out.

In code today: twelve inline blocks in the main loop, four outcome types, one real looped registry, retry-then-hold built three ways, eight hold sites stamping the wrong check name. Door 4 is that registry, generalized.

Severity is a property of the check, set in code, identical at every company, never a setting. Only door 4 holds a written reply; voice retries then sends: Opus writes a dash 2 in 72, one retry clears nearly all, and a held first email is a lost lead (110 of 124 renter-facing holds expired unseen).

No new production judge: the 006 judge stopped 22 of 28 real first emails without seeing the facts bundle; judges live on the bench, calibrated to Fede's verdicts.

What stops "one line per incident"

An incident's first artifact is a reproduced case, never a check: a ledger row on the frozen replay plus a bench row, filed by cause (data missing, prompt ignored it, schema cannot express it, hold died, tool bug). Only "had the fact, declared it, still wrote something else" earns a change to door 4, as a column or leak entry with a registry row (id, join target, origin case, three controls, false-fire rate, status: hold, retry-only, observe, retired). A build check fails any PR adding a check without the row; a monthly review demotes a hold check whose false-fire rate crosses the line or that has not fired in 60 days (control green). This is Anthropic's evals guidance: failures become regression cases, graders deterministic where possible.

Battle-testing: no false fires, not worse

  1. Ground truth exists: holds staff approved as drafted are "fine"; rejects and engineering recomposes, "defect". Score each check on the recorded replay: right fires, false fires (on an approved draft), misses (known-defect ledger). On 28 replayed cards, home counts fired 9 times in production and 7 on Opus, 5 of each on staff-approved emails. A hold check needs one real right catch and a false-fire rate under about 10%, else retry-only or observe.
  2. Three controls per check, in English and Spanish: planted defect; correct draft passes (the positive control, missing today; it would have caught every wrong hold in the sample); same defect reworded. Build hygiene, not proof.
  3. Proof path: Day 0 book replayed byte-identical at the check tap; a week of observe mode in production (logged, sent anyway, fires on the rating cards); hold status only after those fires are reviewed; then one real Willows conversation per hard check: defect planted in data, hold, review door, release, record ids as evidence.
  4. "Not worse" is two numbers against Day 0: Fede's noise score and a silence score (held, expired, silent with no reason, per gate per customer). Run the writer k times on flaky records: a check that fires on some runs only measures writer variance; fix facts or prompt, not a gate.

Where the first opinion is wrong

  • It keeps fact trace as the base of the facts door; its one real fire was wrong (the application-send extractor is always untraced), it has zero right catches, and it judges provenance by construction.
  • "Keep the rest until the new writer proves it does not need them" inverts the burden of proof: 29 hold-capable lines stay, several mostly false fires.
  • Every fire holds; the missing severity tier turned correct replies into silence.
  • Voice as a hold door trades a lost lead for a punctuation mark.
  • Nothing on lifecycle (the largest harm in the window) or before the writer; its "pending" forced-retry row is settled on the master page ("goes away").
  • It counts doors by idea and leaves prose parsers as the mechanism, so the next incident still adds a line.

Sources (read Oct 26, 2026)

  • Anthropic, Building effective agents: https://www.anthropic.com/engineering/building-effective-agents ("simplest solution possible", "only when it demonstrably improves outcomes", guardrails as a separate model instance, sandboxed testing)
  • Anthropic, Demystifying evals for AI agents (Jan 9, 2026): https://www.anthropic.com/engineering/demystifying-evals-for-ai-agents (deterministic graders where possible, calibrate LLM graders to humans, regression suites, failures into test cases, pass^k)
  • Anthropic, Structured outputs and strict tool use: https://platform.claude.com/docs/en/build-with-claude/structured-outputs (constrained decoding; enum values compared case-insensitively; refusals and cut-offs break the schema; limits: 20 strict tools, 24 optional fields)
  • Claude Agent SDK permissions and hooks: https://code.claude.com/docs/en/agent-sdk/permissions and https://code.claude.com/docs/en/hooks (a disallowed tool is removed from the request; PreToolUse blocks with a reason fed back)
  • Anthropic, test and evaluate: https://platform.claude.com/docs/en/test-and-evaluate/develop-tests ("automate when possible", volume over hand grading)
  • OpenAI Agents SDK, Guardrails: https://openai.github.io/openai-agents-python/guardrails/ (input, output and tool guardrails; tripwires; blocking vs parallel; cheap model)
  • OpenAI, A practical guide to building agents (2025): https://cdn.openai.com/business-guides-and-resources/a-practical-guide-to-building-agents.pdf (layered defense, "add new guardrails based on real-world edge cases", high-risk actions get human oversight until reliable)
  • OpenAI Guardrails library: https://github.com/openai/openai-guardrails-python
  • Sierra, Defense in depth in the age of agents (Aug 13, 2026): https://sierra.ai/blog/defense-in-depth-in-the-age-of-agents (four layers, "half a dozen" checks per message, deterministic guards "only fire on what's been explicitly defined", supervisors' limits, Monitors, Simulations)
  • Sierra, tau-bench and tau2-bench: https://arxiv.org/abs/2406.12045 and https://arxiv.org/abs/2506.07982 (grade the end state of the record, pass^k, simulated users)
  • Intercom Fin, AI guardrails for customer service: https://fin.ai/learn/ai-guardrails-customer-service ("over-blocking is as dangerous as under-blocking", "firing on 40% is probably too aggressive", "never fires is probably misconfigured", deterministic controls where precision matters, regression testing)
  • Intercom Fin, How to test an AI agent before it talks to customers: https://fin.ai/learn/how-to-test-ai-agent-before-deployment (simulations, no writes to production in tests, judge scoring)
  • Decagon, Why we built AOPs (Apr 8, 2025): https://decagon.ai/blog/why-we-built-aop (conversational instructions merged with code-based logic; validation steps in code for sensitive actions)
  • NVIDIA NeMo Guardrails: https://docs.nvidia.com/nemo/guardrails/about-nemo-guardrails-library/rail-types and https://github.com/NVIDIA/NeMo-Guardrails (input, dialog, retrieval, execution, output rails; heuristic vs self-check)
  • Guardrails AI, on_fail actions: https://guardrailsai.com/docs/concepts/validator_on_fail_actions (reask, fix, filter, refrain, noop, exception)
  • LangChain middleware and LangGraph interrupts: https://docs.langchain.com/oss/python/langchain/middleware/custom and https://docs.langchain.com/oss/python/langgraph/interrupts; LangSmith online evaluation: https://docs.langchain.com/langsmith/evaluation
  • Code read at origin/main 604b8ac278 (clean worktree propflowai-desk-baseline): conversation-manager.ts 14550-16100, guest-card-engine-turn.ts, guest-card-fact-trace.ts, generate-followup-message.ts, should-speak.ts, outbound-safety.ts, anomaly-review-gate.ts.
  • Not verified (pages unreachable or teaser only): Sierra Agent OS page (404), Decagon Watchtower, Ada, Parloa simulation details, OpenAI guardrails pipeline stage names.

Does each check on Clara's messages still earn its place now that she writes with Opus 5.5, a split prompt, and the facts handed to her? Each row says what incident the check was built for, what it really caught in the last 30 days at Western Slope, Situs and JP&Co, and whether the new setup still makes that mistake. Samples: 72 bench first emails per arm, 55 tenant texts per arm, 12 Opus repair replies, and 006's 28-card first-email replay. Supervised holds, maintenance templates and fair housing are out of scope. Read only: nothing was changed or sent.

By check: keep 29, delete 7, fold 18, pending 2. By row: keep 15, delete 4, fold 5, pending 1.

GateBuilt forReal catches sinceDoes the new setup still do the thingVerdict
First email: no tour times offeredSep 28, a replay of 170 Camellia guest cards: emails ended on a size question and dropped the tour offer (#13351).The busiest first-email check: 20 of the 23 named rule fires in 30 days (006). No renter-felt bug found. On 28 replayed cards it fired 4 times on production, 2 of them on emails staff approved as is.Yes. Opus still trips it: 4 of 28, 1 on a staff-approved email (006).Keep
First email: says how many homes are openOct 22, a Western Slope first email listed three 3-bedrooms open now and one opening later; Fede: never say how many are open (#21806).Main loop redraft fired 3 times in 30 days (Western Slope 2, JP&Co 1). On 28 replayed cards: 9 production fires, 5 on staff-approved emails.Yes. Opus 7 of 28 (5 on staff-approved, 006). On 72 bench emails 1 of 72 on each arm; the Opus one (case 019) named a three-home roster, a right fire.Keep
No dashes (first email and main loop)Oct 23 to 24, Fede on the review set: never an em dash, it is an AI tell (#22178, #22236).Production first emails used dashes in 60 of 72 bench drafts. 006: 3 of 28 production fires, 2 on staff-approved.Mostly fixed by the writer: Opus 2 of 72 bench emails, 0 of 28 (006), 0 of 55 tenant texts, 0 of 12 repair replies. Production tenant texts: 2 of 55.Keep
First email: every fact traced to a sourceSep 25, Fede's goal for the Western Slope engine: zero invented fees, dates, specs or promises (#12074).1 real fire in 30 days (Western Slope, Patrick). It was WRONG: the check missed the application link Clara had sent herself.Not measurable today: it needs the live source bundle the door does not return.Keep
First email: fact-shaped rulesSep 23 to Oct 19, Camellia and Western Slope replays: one price for all sizes, 'Unit 313' on a house, 'typically one month', 'nothing open' with no answer, 2.5 bath from marketing text, an invented pet rule, a past tour time.0 fires in 30 days for every one of them (006 production list).Opus 0 of 28 on each (006). Each is a question of whether a sentence matches a fact the writer is now handed.Fold
First email: shape rules Opus never tripsSep 26 to 29, Western Slope replays: an email that named no home (#12744), a bare 'what size?' (#13568), 'just confirming' in a first message (#13568), 'I've noted that for the team' and nothing else (#12546).names_home 2 fires, bare hand-off 1 (Cheryl, a test applicant, unclear), prior contact 1 (unrated), size question 0. On 28 cards names_home fired 3 times on production, all 3 on staff-approved emails (misfires).No. Opus 0 of 28 on all four (006).Delete
First email: reads like a staff note, not an emailSep 23, 'I found the exact home the address matches' (#11252); Oct 25, a preventive check for the decomposed writer (#22314).Not counted in the 30-day logs.Yes. Opus wrote a staff report instead of an email once in 72 (case 023). Production prompt: 6 of 72 missing a greeting.Keep
Weekday and date matchSep 26, three real Western Slope sends said 'tomorrow, Friday September 19' with the date one day off (#12530, #12543).0 real fires in 30 days.No. 0 of 72 on both arms, 0 of 55 tenant texts, 0 of 12 repair replies. Planted control fired 10 of 10.Fold
Tour time named this turn must come from this turn's calendar readOct 16, the Willows test building, one text thread: Clara offered 12:00 or 2:30 after the calendar said not to list times, and a stale 4:30 (#20338; widened Oct 20, #21497; false holds fixed Oct 23, #22024 and #22036).0 real-customer fires in 30 days; 2 fires, both on the test property. Its own replay found one live-customer email (Oct 14) with an unbacked 2:00 PM. #22036 found 0 real prospects silenced (Western Slope 143 sent, Situs 1).No. 0 of 72 on both arms, though 62 and 65 drafts name a clock time. Planted control fired 10 of 10, but only after the wording changed: 'I can also do Thursday at 7:15' slipped past (0 of 10).Fold
Forced retries: tour-time claim and availability claimTour time: Sep 30, Western Slope email 7ddd98a6 (#14124). Availability: Sep 19, Camellia said units 420 and 524 were open, both occupied (#10579).Logged in 30 days: tour time Western Slope 10 (5 conversations), JP&Co 8 (4); availability Western Slope 10 (4), JP&Co 8 (2). Neither fired on either bench arm.006 report 4 (#gate-claim-gates): tour-time retry, 9 customer fires in 90 days, 4 real catches (invented "10 AM or 2 PM" twice at Camellia, a past Monday and stale windows at Western Slope), 4 moot; Opus read the calendar itself 14 of 29 turns vs Sonnet 5 of 29 and named no time without a read. Availability retry, 10 fires, 0 real catches, 7 misfires (5 where the forced tool was the calendar so the unit was never checked); Opus 0 unbacked unit claims. Every fire was Sonnet, forced tool ran 63 of 63, median 7 s added, never a hold.Keep tour-time as the one calendar rule inside the facts check, re-decide after a week of Opus snapshots; delete the availability retry, keep its log line
First turn must look things up before answeringApr 8, a bare Zillow lead: Clara skipped her tools and invented price ranges (no PR).0 real-customer fires in the pulled 30-day logs.Yes. Opus skipped the lookup 3 of 72 times; production prompt 17 of 72. The retry fixed every one.Keep
Typed tool-call text stripped from the replyAug 2, an eval bug where tool-call markup landed in a test tenant text (#5257). Not a customer incident.0 real fires in 30 days.No. 0 of 72 on both arms, 0 of 55, 0 of 12. Planted control 10 of 10.Delete
On error, send nothingOct 1, residents were texted engineering fallback text; Fede: if we error, we don't answer (#14348).Not counted as a fire; it is the failure path.Not model-dependent.Keep
Internal time stamp stripped from the replyOct 1, a Western Slope prospect texted 'I'm here' and the reply began with '[Sent Thursday, October 1...]' (#14874).6 real catches in 30 days (Western Slope 4, JP&Co 2), all right: the stamp would have reached the person.No. 0 of 72 on both arms, 0 of 55, 0 of 12. Planted control 10 of 10.Keep
Hand-off promise with nobody reachedSep 5 to Oct 20, Western Slope cards: 'the team will be in touch' when no one was told (#7119, #11980, #12370, #21395).3 real catches in 30 days (Western Slope 2, JP&Co 1), all looked right. 006 audit (report 8, Oct 26 eve): the template swap fired 22 times in 30 days (18 replaced, 4 released), 3 at customers: 1 real catch (JP&Co Oct 13), 1 false 'noted for the team' sent when nobody was notified (JP&Co Oct 6), 1 working answer thrown away (Western Slope Sep 27). Of the 18 replacements: team notified 7, logged but not delivered 8, nothing opened 3. The leasing prompt itself mandates the wording the gate punishes.No on 72 Opus emails (0), 55 Opus texts (0), 12 repair replies (0). Production tenant texts: 1 of 55. Planted control 7 of 10 (the 3 misses had a real hand-off tool call, so they were correct passes).Fold: delete the template swap; door 4 'promises match actions' allows the promise when the open-ask record shows an ask opened, retries once then holds when nothing opened; the answer beside the promise ships. Full audit: #gate-handoff-template.
Other unbacked-promise checksAug 19, a Willows bench prospect asked about a felony and heard 'the team will be in touch' (#5915); Oct 18 replay, 'I'll check with the team' on six cards (#21085); Oct 25 send gate (#22296).Send gate 1 (JP&Co, Ibrahim, unclear). First-email copy 1 (unrated).No. Opus 0 of 28 (006), 0 of 72, 0 of 55.Fold
Tour promised or confirmed but not bookedSep 18, 'I'll get it locked in for you' before booking (#9635); Sep 30, 'See you at 1' after nothing was booked (#14353).7 real catches in 30 days (Western Slope 3, JP&Co 4). The redraft cleared 6; 1 JP&Co reply was not cleared. 006 audit (report 5, Oct 26 eve): the phrase guard itself ('lock in' list, rewrite until Oct 25, block-only since #22296) had 0 real catches in 9 customer fires; 4 of its rewrites made the reply worse and 2 sent a stray quote mark. The 7 real catches above come from the say-do check (promise with no booking on record), not the phrase list.No. 0 of 72, 0 of 55. Planted control 10 of 10.Fold: keep 'tour confirmed only when the records show one' inside door 4 (promises match actions); delete the phrase list. Full audit: #gate-booking-promise.
Claims a work order was filed with none filedOct 1, a flaky renewal eval, not a customer (#14864).0 real fires in 30 days.No. 0 of 12 Opus repair replies with filed actions, 0 of 55, 0 of 72. Planted control 10 of 10.Delete
Says it did something no tool didApr 27, 'Done, I'll flag this for PM' with no escalation fired (#485).1 real catch in 30 days, right: JP&Co, Will, Sep 30, said '1 PM works' while the tour was at 4:45 PM.Not measurable today: needs the full live tool trace.Keep
Anomaly reviewJul 17, a Camellia tour incident (#4061).10 fires in all kept logs, 1 real and right (Ember, an empty reply). Its content signals never fired (006).Not replayable: voice turns and tool crashes cannot be rebuilt (006).Keep
Follow-up texts: fact-shaped checksJul 14, a follow-up invented 'our studios and two-bedrooms' and 'Tuesday at 10 AM' (#3762); Jul 16 pricing (#3936); Oct 22 availability (#21806).1 real catch in 30 days, right: Jessalyn at Pomona Park was told '2-bedroom' where every home is 3 or 4 bedrooms (unit-type).Not measurable today: follow-ups have no decomposed writer yet.Fold
Follow-up texts: dash and mass-text openerJun 19, no 'Hi there' mass-text opener (#2509); Oct 23 no-dashes rule (#22236).0 real fires in 30 days.Not measurable today: no decomposed follow-up writer.Keep
Silencers: runaway ceiling, muted person, tapback, bare closerJun 13, Willows and Camellia texted each other for hundreds of turns (#2341); Aug 28 to 30, Camellia replies to a thumbs-up and to 'Thank you' four times (#6519, #6552); Aug 28, Fede's per-person mute (#6526).Bare closer 6 in 30 days (Western Slope 2, Situs 2, JP&Co 2). Runaway 9, all sandbox. Muted and tapback 0 found.On all 5 inbound closers and tapbacks in the 55-text sample, both production and Opus chose to stay silent on their own. Runaway, mute and tapback run before the model.Keep
Silencer: farewell loopJul 30, a plumber's auto text and Clara traded 11 rounds of 'Take care!' (#5047).0 fires found in 30 days.Both models ended the conversation on their own on all 5 closers in the sample.Delete
Email greeting and footer added after writingMar 20, the first email reply feature (no incident). Sep 23, two greetings stacked in a held draft (#11371).Not logged.Opus left out the greeting once in 72 (the staff-report case).Keep

Why delete or fold

Fold: First email: fact-shaped rules. Each rule restates one fact that now sits in the facts block. One check that compares every sentence to that block covers all seven, and none has fired in 30 days.

Delete: First email: shape rules Opus never trips. These were built for the production prompt's habit of thin, odd first emails. The decomposed writer is handed the home and told it is a first message; it never produced these shapes, and the one with real fires misfired every time.

Fold: Weekday and date match. Today's date is a fact in the facts block. A date check belongs inside the one facts check, not as its own gate.

Fold: Tour time named this turn must come from this turn's calendar read. Fede's hunch holds. It was built from one test-line thread, has never fired on a real customer, and twice held correct replies on the test line. The real rule (a named time must be in the calendar read) is a fact match, so it moves into the one facts check.

Delete: Typed tool-call text stripped from the reply. Built for an eval-provider bug, never a customer, and a rewrite layer Fede ruled out. If the markup ever shows up, the empty-reply rule (do not answer) is the right response, not an edit.

Fold: Other unbacked-promise checks. Three copies of the hand-off promise check above, with no right catch between them. Fold them into that one check.

Delete: Claims a work order was filed with none filed. Built for an eval flake, never a customer, never fired. The work-order confirmation rule (#16358) covers the real case.

Fold: Follow-up texts: fact-shaped checks. Each one compares a sentence to a fact (price, policy, size, slot, count). They belong in the one facts check once follow-ups are written from the facts block.

Delete: Silencer: farewell loop. The model now ends these itself, and the runaway ceiling still stops any bot-to-bot loop.

Did not fit the master page

Sources: first-email replay and anomaly numbers from 006 (#gate-first-email-checks, #gate-anomaly-review, #gate-supervised-hold). Origins verified with git log and the PR bodies. 17:16Z manual rerun rows excluded. Case ids in gate-report.json.

Gate ledger, 30 days (baseline before any gate changes)

Read-only, built Oct 26 2026. Window Sep 26 to Oct 26 (UTC). Western Slope, Situs Group and JP&Co (Camellia) only. Every row is a time an output check stopped, held, silenced or forced a retry of a Clara message. Raw rows: gate-ledger-30d.json (scratchpad of session 001).

DoorFiresRightFalseUnresolved
Door 1, should Clara speak4312031
Door 4, claims match the record7841460
Door 5, voice0000
Door 6, send door (+123 Supervised holds, not judged)5005
Fair-housing judge1010
All doors127161596

What it says. Of 31 fires with readable words, 16 stopped a real mistake and 15 stopped a fine message. Door 4 is where the false ones live: 14 false against 4 right, and every false one judged where a fact came from, not whether it was true (fact trace, tour time from this turn, promise backing, the "lock in" phrase list). The right ones are plain record checks: wrong tour time, empty draft, a home size that does not exist, bare thank-yous left alone. 96 fires are unresolved because the log keeps only that the check fired, never the words it stopped; that gap is itself a finding for the hold record (one record, with the check name and the words).

Doors. 1: silencers before the writer (shouldSpeak said "reply" on all its lines, so 0 fires). 4: fact, provenance and claim checks, including forced-tool retries. 5: no fires recorded. 6: send-door refusals; Supervised holds are a setting, counted but not judged.

Door 4, claims match the record

DateCustomerChannelCheckWhat the message saidWhat happened nextFiresVerdict
2026-10-04Western Slopeemailfirst email: fact trace (fact_trace_untraced)Carmen, Pomona Park: draft said "I'm not able to pull up live tour times"held; later rerun and sent1RIGHT Slots were on hand; saying none could be pulled is a false claim.
2026-10-04JP&Coemailfirst email: implies-prior-contact (forced redraft)Will, Camellia: first draft not keptredrafted, then the fair-housing judge held the redraft (row below)1UNRESOLVED Pre-redraft text is not stored.
2026-10-05Western Slopeemailfirst email: draft check (first_email_check_failed)Robert, Northridge: held draft not keptheld; reruns then sent four different first emails in 21 minutes; Oct 7 review rerun expired unseen1UNRESOLVED Held words are not stored; only the Oct 7 rerun draft is.
2026-10-21Western Slopeemailfirst email: fact trace (fact_trace_untraced)Morgan, Pomona Park: "Unit 405 runs $2,495/mo, which is above the $1,800/mo budget you mentioned... 585 Redcliff Cir, #201 ... listed at $1,750/mo" plus tour timesrerun into review, expired unseen after 24 h; nothing sent1FALSE Every fact is on file: $1,800 budget on her card, #201 vacant and listed at $1,750. The trace judged where the fact came from.
2026-10-25Western Slopeemailtour time not from this turn's calendar readAnthony, 2841 Morningside Court: first draft offered the slots the first email was handedretry told "do not name any tour time"1FALSE The slots were real; the gate did not count the handed-in slot read (fixed by #22485, Oct 26).
2026-10-25Western Slopeemailfirst email: no tour times offered (on the retry)Anthony, 2841 Morningside Court: "Thanks for reaching out about 2841 Morningside Court, it's available now, a 4 bedroom, 2 bath with 1,518 sq ft at $2,300/mo. I'd love to get you in for a tour: what day and time work best for you?"held; staff got an "I couldn't get a clean reply out" email; nothing sent to him1FALSE Sendable email; the missing times were caused by the previous gate's own retry instruction.
2026-10-26Western Slopeemailtour time not from this turn's calendar readTrang, Ember Estates: first draft offered the slots the first email was handedretry told "do not name any tour time"1FALSE The slots were real; the gate did not count the handed-in slot read (fixed by #22485, Oct 26).
2026-10-26Western Slopeemailfirst email: no tour times offered (on the retry)Trang, Ember Estates: retry draft without timesheld; rerun into review, approved by hand, sent 15:28Z (about 47 min late)1FALSE Sendable email; the missing times were caused by the previous gate's own retry instruction.
2026-10-26Western Slopeemailfirst email: fact trace + names-home (draft check)Patrick, Northridge: "I've sent the application for Northridge Apartments, it'll come from AppFolio in the next few minutes."held; Kat replied to him by text at 15:38Z1FALSE True: the application went out at 15:35:30Z; the trace did not count its own turn's tool.
2026-09-30JP&Cotexthallucination guard (parked)Will, Camellia: "1 PM works" when the tour on file was 4:45 PMparked, nothing sent1RIGHT Wrong tour time against the tour record.
2026-10-22Western Slopeemailanomaly gate (agent turn timed out)Ronald, Ember Estates: empty draftheld; a retry 18 s later sent a reply listing units 361, 363, 364 and a Nov 2 opening (the Ember overshare incident)1RIGHT An empty draft should never send. The harm came from the retry path, not the gate.
2026-10-26JP&Coemailsend gate: unbacked_promise_in_retryIbrahim, Camellia: "Signing the lease before you arrive in the US isn't something I have on file, so that's one the property team can go over with you directly... would a virtual tour work in the meantime? I'm happy to set one up"parked, nothing sent; no Slack page1UNRESOLVED Depends on whether Camellia offers virtual tours and whether a team ask was filed; not checked.
2026-10-26Western Slopeemailsend gate: promise-backingAustin (applicant, Beverly reviewing): "I've passed along the references for Terry Dwayne and Stacey Farney, along with the 2019 to 2020 rental history..."parked; the team notice with the same facts was posted in the same second1FALSE The pass-along really happened (team notice 17:01:42.9Z). Separate issue: the office was running this thread (door 1).
2026-10-26Western Slopetextcadence unit-type check (held after retry)Jessalyn, Pomona Park: "...a tour of our 2-bedroom homes still interests you"held, still pending1RIGHT Every Pomona Park home is 3 or 4 bedrooms.
2026-10-24JP&Coemailunit count stated (forced redraft)(pre-redraft text not kept)redrafted, then sent1UNRESOLVED Log line only.
09-26..10-26Western Slopeemailunit count stated (forced redraft)(not kept)redrafted, then sent1UNRESOLVED WS 2 lines in the Oct 26 pull; one is the Cheryl test lead (excluded).
09-26..10-26Western Slopetext/emailbooking-promise phrase ("lock in")(pre-rewrite text not kept)regenerated and sent (3)3FALSE 006 audit, Oct 26: 0 real catches in 9 customer fires; 4 rewrites made the reply worse.
09-26..10-26JP&Cotext/emailbooking-promise phrase ("lock in")(pre-rewrite text not kept)regenerated and sent (3), 1 not cleared and blocked4FALSE Same audit as above.
09-26..10-23Western Slopeemailfirst email draft checks (redraft era, before Oct 24)(pre-redraft text not kept)redrafted, then sent17UNRESOLVED Pre-redraft words are not stored.
09-26..10-23Western Slopeemailfirst reply named no home (redraft)(not kept)redrafted, then sent15UNRESOLVED Same.
09-26..10-23Western Slopeemailfact-trace sentence strip(not kept)sentence cut, then sent5UNRESOLVED Same.
10-24..10-26Western Slope + Situs Groupemailfirst email check, retry passed(not kept)sent after one retry3UNRESOLVED WS 2, Situs 1; first draft not stored.
09-26..10-26Western Slope + JP&Cotext/emailtour-time claim with no calendar read (forced tool retry)(not kept)redrafted with a forced lookup, then sent9UNRESOLVED WS 5 turns, JP&Co 4; the draft before the forced lookup is not stored.
09-26..10-26Western Slope + JP&Cotext/emailavailability claim with no lookup (forced tool retry)(not kept)redrafted with a forced lookup, then sent6UNRESOLVED WS 4 turns, JP&Co 2.
Door 1, should Clara speak (43 fires)
DateCustomerChannelCheckWhat the message saidWhat happened nextFiresVerdict
2026-09-27Western Slopesmsbare closer skipInbound: "Thank you."nothing sent1RIGHT Bare thanks or goodbye; a reply would be noise.
2026-09-29Western Slopesmsbare closer skipInbound: "Thank you!"nothing sent1RIGHT Bare thanks or goodbye; a reply would be noise.
2026-10-01Western Slopesmsbare closer skipInbound: "See you then!"nothing sent1RIGHT Bare thanks or goodbye; a reply would be noise.
2026-10-03Western Slopesmsbare closer skipInbound: "Okay thank you"nothing sent1RIGHT Bare thanks or goodbye; a reply would be noise.
2026-10-13JP&Cosmsbare closer skipInbound: "Okay, thank you. See you soon!"nothing sent1RIGHT Bare thanks or goodbye; a reply would be noise.
2026-10-16Western Slopesmsbare closer skipInbound: "Thank you so much!"nothing sent1RIGHT Bare thanks or goodbye; a reply would be noise.
2026-10-19JP&Cosmsbare closer skipInbound: "Thank you!"nothing sent1RIGHT Bare thanks or goodbye; a reply would be noise.
2026-10-19Situs Groupsmsbare closer skipInbound: "Thank you"nothing sent1RIGHT Bare thanks or goodbye; a reply would be noise.
2026-10-20Western Slopesmsbare closer skipInbound: "thank you so much"nothing sent1RIGHT Bare thanks or goodbye; a reply would be noise.
2026-10-20JP&Cosmsbare closer skipInbound: "Thanks!"nothing sent1RIGHT Bare thanks or goodbye; a reply would be noise.
2026-10-21Situs Groupsmsbare closer skipInbound: "👍"nothing sent1RIGHT Bare thanks or goodbye; a reply would be noise.
2026-10-24JP&Coemailend_conversation (model chose silence)Inbound: "Gracias ! Yoira E. El 23 oct 2026, a la(" after her tour was confirmednothing sent; tour reminder still went out next day1RIGHT Bare thanks after a confirmed tour; nothing to answer.
09-26..10-26Western Slopetext/emailend_conversation (model chose silence)(not kept: log line only)nothing sent5UNRESOLVED Counted in the Oct 26 pull; lines carry no inbound text and were not re-found by id.
09-26..10-26Western Slope + JP&Cotext/emailconversation already ended(not kept)nothing sent6UNRESOLVED WS 3, JP&Co 3; log line only.
09-26..10-26Western Slopetextstaff sender (a staff member texted the line)(not kept)nothing sent14UNRESOLVED 14 lines, all one conversation; likely right but not read.
09-26..10-26JP&Coemailresident scope (resident wrote the prospect inbox)(not kept)skipped, parked3UNRESOLVED Log line only.
09-26..10-26Western Slopetextfollow-up cadence stop(not kept)touch skipped3UNRESOLVED Temporal log only.
Door 6, send door, and the Supervised holds (5 fires + 123 policy holds)
DateCustomerChannelCheckWhat the message saidWhat happened nextFiresVerdict
09-26..10-26Western Slopetext/emailcompany not live(not kept)held, not sent5UNRESOLVED Western Slope is live, so these 5 lines need reading; not re-found by id.

Supervised holds, one JSON row each: maintenance_resident_sms expired unreviewed: 106; maintenance_resident_sms approved and sent: 5; maintenance_resident_sms still pending: 5; team_notice_email approved and sent: 2; maintenance_resident_sms rejected: 1; maintenance_vendor_sms expired unreviewed: 1; clara_prospect_email expired unreviewed: 1; maintenance_resident_sms approved, delivery failed: 1; clara_prospect_email still pending: 1. Maintenance holds are Gera's lane (Fede, Oct 26).

Fair-housing judge

DateCustomerChannelCheckWhat the message saidWhat happened nextFiresVerdict
2026-10-04JP&Coemailfair-housing judge (fair_housing_hold, "familial status")Will, Camellia: redrafted first email for a one-bedroom, west-facing, floor 3+ askheld; rerun sent 34 min later (22:41Z) with tour times and unit 2201FALSE Nothing about family in his ask or the draft (Oct 26 inventory read the held text as fine).

Left out (listed in the JSON): test companies, the Cheryl test lead, manual reruns, alert-only fair-housing flags, cadence lines with no company, rewrites that forced no retry. Unresolved: the held words of Robert and of Will's first draft are not stored; Ibrahim needs Camellia's virtual-tour policy; count-only rows need text the log never kept. Sources: hold, intent, message and unit rows read by key; CloudWatch; Slack held cards; the Oct 26 gate report.

Clara remembers her own notices (Fede, Nov 2: "it's pretty embarrassing to say 'what was this for?'")

The case. Nov 1, 4:04 PM MT: Clara's call summary about a resident's cleanup call went to the Situs Group leasing inbox. Nov 2, 7:43 AM MT: a Situs org admin replied to it, To Clara, Cc the leasing inbox: "let's call and explain to him that we have the city inspection and need it cleaned up today." Clara answered him alone 16 seconds later: she could not place calls and did not know who "him" was. Fede: the team will reply-all on these notices to add teammates and tell Clara what to do; Clara must keep the context of her own message and answer basic questions about it, through the one coworker loop, no separate path.

Root cause, from the raw records (session 006, read-only).

StepWhat happenedWhy
1. The reply matched the noticeThe team-notice reply door found Clara's notice by its message id (In-Reply-To) within a secondWorking as built (ADR-0146 §2)
2. The door refused the sender"neither a recipient nor staff", so the reply fell to ordinary triageThe staff check reads the notice's property mailbox, and a call-summary notice carries no property (company, person and the call only), so the check answered "not staff" before looking at his role. He is an active org admin on the company record.
3. A second door took itThe new staff email turn (merged that morning, #24426) recognized him as staff and ran a coworker turnWorking as built, but it minted a brand-new conversation ("no canonical thread matched"), so Clara saw one line and none of her own notice, the call or the caller.
4. It sentNo hold rule fired (Situs staff notices are Live); the reply went to him alone, dropping the leasing inbox from the threadThe staff turn replies to the sender only and does not keep Cc.

Second gap, from the code: when the door does accept a staff reply, it reads the words with the one staff-input reader; an answer is relayed to the person on the notice's own conversation (under Supervised, held for Slack review) and "handled" closes the notice, but a question or a note returns "not an answer" and nothing happens. So a teammate asking Clara "what was this call about?" gets silence today.

BEFORE  staff reply ──► notice door: "not staff" (no property on the notice) ──► triage ──► staff email turn, NEW conversation ──► blind reply to sender only
AFTER   staff reply ──► notice door: staff by the company's role record ──► the notice's own conversation (call + Clara's notice in history)
                         ├─ answer   ──► Clara relays to the person (Supervised: held, Slack review)      (exists)
                         ├─ handled  ──► notice closed, nothing sent                                      (exists)
                         └─ question / note ──► the coworker turn on that conversation, reply-all on the thread, Cc kept   (new)
                         └─ unclear  ──► held, Supervised review card on Slack, no guess                 (new)

Proven live, Nov 2, 11:10 AM MT, Fairhaven test company (Willows testing is closed by Gera today). Same shape as the Alton case: a hand-off notice with no property, a staff test mailbox that was not on the notice replies with a question, reply-all to the original recipient.

Before (Nov 2, 7:43 AM, Situs Group)After (Nov 2, 11:10 AM, Fairhaven)
Staff check"neither a recipient nor staff; left to triage"recognized by company role, "team reply routed to the engine"
Where Clara thoughta brand-new conversation, nothing of the call in viewthe call's own conversation (10 messages before, 12 after: the staff reply and Clara's answer)
What she saidcould not place calls, did not know who "him" waswhat the caller asked for, the two matches offered, and that nothing was promised
Who got itthe sender alone, team droppedthe sender, with the original recipient still on Cc, threaded on the notice
Time16 s34 s from send to delivered reply
Fix 3, plain staff email (Nov 2, 6:54 PM MT, Fairhaven)Situs, 5:40 PM: a staff reply to Clara's virtual-tours intro (random message id, no notice row) matched nothing; a fresh conversation, Clara wrote that nothing had been sentA tour-confirmed email to the team went out tagged (notice tn_38a9212b, kind fyi, source staff_email); a staff test mailbox not on the email replied with a question; the reply found the email's own thread (conv-staff-mail-db97f4e9…) and Clara answered there with the tour, the time and its cancellation in view; 43 s, nothing held. Two side findings filed as issues: Clara's own answer is tagged again, so a second reply lands on a split thread; the first turn logged the sender as identity unknown and opened a matter.

Evidence: inbound-processor log 18:10:19 to 18:10:43Z (reader outcome "question", notice-thread "answered on the thread (sent=true, held=false, cc=1)", action coworker_turn; no "minting a new conversation" line); conversation conv_voice_c59a5d61… rows at 18:10:10 (team reply) and 18:10:31 (Clara, staff-only); the reply in both test inboxes at 18:10:46Z with In-Reply-To and References chaining to the notice's reply key. One side finding filed as #24536: the reply opened with a "Property:" line printed twice, taken from the conversation's property although the notice had none.

The one mechanism. No new path. A staff reply to any notice Clara sent lands on the conversation the notice came from, where Clara's notice is already recorded as her own message. The one reader says what the words are; answer and handled do what they do today; a question or a note runs the ordinary coworker turn on that conversation, so Clara answers from the call, the person and her own notice, and replies on the thread with everyone who was copied. A reply-all that adds a teammate works the same way: the thread id matches the notice, and the sender is checked against the company's staff roles.

PRChange (each a fix to live behavior, no switch)Proof
1 (#24489, merged Nov 2)The notice door checks the sender against the company's staff roles (the same lookup the staff email turn uses), with the property-mailbox check kept as the second chance. Fixes step 2 and the reply-all case.Read-only replay of the Nov 2 reply shape (notice without a property, org-admin sender); Willows live: a real hand-off notice to a tenant test mailbox, a staff test mailbox replies, the reply lands on the call's conversation. Test mail from the Microsoft tenant only.
2 (#24494, merged Nov 2)A reply read as a question or a note runs the coworker turn on the notice's conversation and answers on the thread, Cc kept, hello@ copied. A reply the reader cannot place (unclear) is held into the Supervised review card, never answered with a guess (Clara Refactor, Nov 2: gates hold, never compensate). Fixes steps 3 and 4 and the "what was this about?" gap.Willows live: a staff test mailbox asks "what did he call about?" on a notice thread; Clara answers from the call with the team still on the thread.
3 (#24534, merged Nov 2)Every staff-facing email Clara sends becomes a notice a reply can find: the send is stamped with a reply key and a notice row (kind fyi) points at the staff conversation that already holds Clara's email. Needed by a second real case the same afternoon (Nov 2, 17:40 MT, Situs Group): a staff member replied to Clara's virtual-tours intro, which had a random message id and no notice row, so the reply fell to the staff email turn, which started a fresh conversation and Clara wrote that nothing had been sent on the thread. The other half of that case, staying quiet when a staff member addresses a named colleague on a thread Clara is only copied on, ships from the Situs Onboarding session inside the one speaking decision.Read-only replay of the Nov 2 intro send and reply shape; Fairhaven live (Willows testing is off): a staff test mailbox replies to a Clara staff email that is not a hand-off, and the reply lands on the conversation holding Clara's email. Proven Nov 2, 6:54 PM MT, row below.

Owners: 006 builds PR 1 and 2 under Fede's Nov 2 go; the Clara Refactor session holds the staff loop and the one reader (staff-loop-v2 §12) and reviews the cut. Sources: inbound-processor log group Nov 2 14:43Z, the stored notice row (kind handoff, no property), the S3 copy of the reply's headers, team-notify/inbound-email-reply.ts, team-notify/ingest.ts, agents/clara/lib/email/staff-email-turn.ts. No renter name or number appears here.

Clara re-engages when a human drops the ball (Proposed, Nov 2; Fede, relayed by the orchestrator session: "we could be proactive and follow up with the person again and continue our regular follow-up cadence")

This design grew into one framework for every ball in the air, and it now has its own page: Follow-through (Proposed, pending Fede's review). Every signal goes through one read that decides what Clara says now and who owes what: Clara does her own balls, a teammate's ball closes on evidence of what people did, and everything else lands by itself. The first build is the next-morning re-engage after a missed tour, behind a company setting that is off by default, and the seven decisions are on that page.

Ownership. The follow-through page owns the ball record, the read's ball output and what goes on the list. Clara Refactor (001) owns the shared "load the turn's context" step, and the read is a caller of it, not a second loader. Situs external-updates owns the PMS inputs the read needs (current assignee, showing status, staff-booked tours). The scope resolver owns who someone is, by roles at the company, with or without a building.

Proof. A read-only replay of real Situs and Western Slope records first, with the read's verdict per thread logged and nothing sent; then a Fairhaven live run with record ids; then a supervised week at one customer, on Fede's word. Willows testing is off. Fixtures: the five Situs cases from the first pass, each with a control where the read must stay quiet.

The core loop today

Today one large prompt, picked by who is writing, drafts every reply, and code the model never sees patches it afterwards.

Gas or CO: canned 911 reply, skips the modeltool results go back in, up to 10 roundsnext message or a staff answerOne turn per inbound messageSendHold for approvalStay quietAsk for helpthe four ways a turn can end, decided in step 81. Someone writes intext, email, PMS, calltranscript2. Queue, one at a timeper sendersqs/client.ts3. Fixed rules firstsafety, scheduling, repairs:inbound-dispatcher.ts4. Gather inputshistory, knowledge, person,settings5. Build the promptclara-unified.ts6. Model thinks and callstoolsclaude-sonnet-5, modelCall7. Guards clean and checkconversation-manager.ts8. Gate: send, hold orstay quietreply-hold-decision.ts9. Save and follow upconversation-writer.ts,open-matter.ts
The core loop. Every inbound message runs one turn; the model may call tools up to ten rounds. Gas or CO words skip the model entirely. A staff answer to an ask or a held draft re-enters the loop.
DOORS IN Email Text AppFoliotext door Calls(voice) one shared builder Who is the sender?Picks the body by sender, never by turn. Prospectleasing body, ~63k tokens, ~60 sections;the same for a first reply and a tenthemail Tenantmaintenance body Staffsmall body Unknownfalls back to the leasing body: thein-house handyman reads the whole leasingrulebook (9 of 9 traces) One giant prompt Shared top · 3.7k Property and knowledge First-email rules (first reply only) Leasing body · ~63k, ~60 sections Tail Email core Tools · 16k Total ~104–110k tokens for a prospect first email 8 topics with contradicting rules, e.g. 6 different length rules Model (Sonnet 5)~75 s per turn Code rewrite layers the model never sees51 of 78 emails rewritten after writing Fair-housingjudge Send OUTSIDE THIS PIPELINE 12 ElevenLabs voice agentsRules copied by hand: 19 of 66 rule cellsmissing; security block absent on 6 inboundvoice agents 18 other model writersAlso send customer words; 17 import none of theshared rules, 12 check nothing
Today. Rules are chosen by who is writing, never by what this turn is. Everything shares one body that only ever grew (404 prompt commits since March, none shrinking it).

Fede, Oct 25: the foundation was written on early models, with a weaker model in production. It grew a prompt of negative examples (“don't do this, don't do that”), a new rule after every incident, and contradictions. Objective: clean it up and shrink it.

03 · Proposed architecture

Proposed architecture

We rebuild it as one shared engine under every module, so each decision (reply or not, who to ask, what is already in hand) is made in one place.

MODULES: THIN, SPECIALIZED Leasinginquiry, tour, guest card Renewalsrecipe, offer, Send gate Maintenanceintake, work orders Collectionsaging, dunning CORE ENGINE: ONE, USED BY EVERY MODULE Turnassemblyfull context(hypothesis) shouldSpeakreply, holdor silent,with a reason Notice engineaskTheTeam,askState; every hold,hand-off, fallback;failures to #alerts The recordask, work order,offer, ledgerstep Proof railfrozen sets,three arms,judge PmsInboxadapter;AppFolio is oneimplementation Channelstexts · email · the customer's AppFolio inbox · phone later (out of scope for now)
Figure 7. Proposed, pending review. One core, thin modules on top, channels below. Into the core: 5 supervised-hold sites, 9 live checks, the opt-out withhold and the "human replied" skip become shouldSpeak; about 13 paging paths, two owner lookups and every module's own fallback become the one notice engine (askTheTeam; internal failures go to #alerts, never to the customer or their staff); the unchecked "it's with the team" sentence becomes askState; AppFolio literals become the PmsInbox adapter; each module's own hand-off becomes one record and one state. Labels from the modules table.

The six boxes, in plain English

One example runs through every row: a tenant texts "the kitchen sink is leaking, unit 4B".

BoxWhat it isOn the example
Turn assemblyGather everything Clara needs before she thinks: who this is, their home, their lease, open work orders, what staff already said in this thread.Finds Maria in 4B, sees no open plumbing order, sees nobody from the office has replied yet.
shouldSpeakThe one question: reply, hold, or stay silent, and why.Reply: a tenant, nothing open, nobody on it.
Notice engineThe one place Clara asks for a person: a question to staff, a hand-off, a hold card; failures to the alerts channel.If the leak were a flood at night, this is what pages the emergency line.
The recordWhat Clara writes down: the work order, the ask she made, the offer, and a step-by-step ledger of what she did.Files one work order for 4B, logs "replied, filed WO 1234".
Proof railHow we know she behaves: the frozen sets (the 5,515 decisions), three arms compared (production, production on a new model, decomposed prompt), and the judge.Tonight's replay and the shadow cards.
PmsInboxThe door to the customer's property software, written once as a neutral interface; AppFolio is one plug-in behind it, Yardi could be another.Reads Maria's text from the mirror and writes the work order back.

"Full context (hypothesis)" means we believe giving the model the full record instead of a slice fixes many bad replies, and it is being tested, not assumed.

Today these six exist as scattered copies (the duplication table above). The lane makes each exist once, in src/lib/domain/core/, one file per box. Modules import from core and core never imports from a module. Nothing outside the PMS folder names a PMS.

How Fede and Gera avoid adding duplicates:

Proposed, pending review Refactor the base first (Fede, Oct 25): reusable interfaces, common things in one place, no module with its own hand-off or escalation. Lesson: renewals and leasing were built separately.

The turn, rebuilt

Code decides what each turn is and gathers the facts; the model only writes, and checks only block.

DOORS IN Email Text AppFoliotext door Calls(voice) Code picks the turn type Prospect, first reply Prospect, later turn Tenant Vendor or handyman Staff Unknown sender Thin prompt, fixed parts first so it caches 1 · Hard rulesOne constant, verbatim in every channel incl.voice: security, fair housing, the one handoffsentence, emergencies, language 2 · VoiceWho Clara is, 5 lines 3 · The job for this turn(one small job prompt per task: first reply,tour booking, later turn, repair intake,renewal; each owns its rules once; see'Clara the new hire' below) 4 · Customer rulesFrom company settings, never in the sharedbody 5 · Facts, resolved by code before the modelrunsRecord, availability shaped to one home withno counts, tour windows, thread summary,knowledge 6 · ToolsOne fixed set per role Total ~7–19k tokens Build-time coherence testThe build fails if a topic has two rules or ahard rule is missing Model: Opus 5.5 proposedSonnet 5.5 is the cheaper close second · ~7 sper turn Six doors, checks that only block:1 should Clara speak · 2 facts in ·3 declaration · 4 claims match the record(the only content hold) · 5 voice ·6 send door, plus the fair-housing judge.No silent rewrites. See 'Gate review' below. pass fail Send Retry once, thenhold for a person EVERY OTHER DOOR Voice agentsImport the same hard-rules constant and jobblocks Every other send doorImports the short shared rule block, plus codechecks by recipient
Proposed. Code decides what this turn is and gathers the facts; the model only writes. One rule per topic, one owner per job, one hard-rules constant everywhere.
Updated Oct 26 night: boxes 3 and the checks box follow the newer sections (new-hire job prompts, Oct 24 to 25; gate review, Oct 26).

Prompt note (006, report 8, Oct 26). Today's leasing prompt orders the writer to say "I'll check with the leasing team and get back to you" on every forward, and the hand-off template gate then punishes that very line unless a flag is set. In the thin prompt, part 1 (hard rules) carries one hand-off sentence, and it should be written from the facts block: say what you did ("I asked the team about X") only when the ask actually opened (the action list in part 5 shows it as notified or logged); when nothing opened, say nothing about the team. The open-ask record then checks the sentence at door 4. Audit: #gate-handoff-template.

One place decides who hears about a problem

One central ask-for-help and notice engine (Fede, Oct 25, after a Western Slope first email failed its draft check and the fallback emailed the customer's staff asking them to reply): every hand-off, hold, alert and fallback in every module goes through one piece of the core. No module invents its own. An internal failure (a draft check, a tool error, a send that could not go out) never reaches the customer or their staff; it goes to #alerts and to the record, and Clara stays quiet. The Escalations session's full audit of today's paths (who each one reaches) lands as its own section on this page. A turn that does not send never raises a team notice on its own (Austin, Oct 26: a held draft still emailed the team; that path closes with the office-thread fixes).

Recipient by cause, one rule (Fede, Oct 25: "deep inspection of all spread out logic of holds or engineering alerts that notify the customer vs engineering, folded into the overall Clara re-architecture"):

CauseWho hears about itWhat the renter or staff see
Engineering error: a draft check failed, a tool or send errored, a record could not be written, a timeout#alerts and the record onlyNothing. No reply, no staff email, no hold card. Clara stays quiet and the ask stays open on her side.
Clara cannot help: the fact is not on file, the policy is missing, the request needs a personThe hand-off framework: one tracked ask to the owner, through askTheTeamThe renter gets a reply only if it helps; staff get one notice, never a second for the same thing.
A person is already on it (reasoned from the ask and topic against the staff thread, never a time cutoff)NobodyNothing. shouldSpeak returns silent.
Critical emergency (fire, flood, no heat, lockout)The emergency path the customer set up, plus #alertsThe renter gets the emergency line; staff get the page.
Proposed, pending review. Every hold, draft check, hand-off, fallback and engineering-error path in every module resolves to one of these four rows. A module never picks its own recipient.

Input: the inspection of today's paths

Inspected Oct 25 Every place in the code where a hold, a draft check, a hand-off, a fallback or an engineering error decides who hears about it. Twenty-two paths, read from the code on Oct 25, 2026 (Escalations session, after the Western Slope 2841 Morningside Court case). "Rule row" is the row of the table above each path should resolve to. "Fixed" means PR #22417, merging Oct 25, no switch, live everywhere.

The short version: one shared engine already exists for staff notices (the team-notify engine, one recipient per company, one row per event) and the voice path already sends engineering failures to #alerts only. The holes were all in the text and email paths and in one leasing caller: an engineering failure was spelled as "hand-off, unhandled", and "unhandled" is what emails the customer's staff. Four paths did that. Thirteen more decide their own recipient without going through the engine.

#Path (plain words)TriggerWho heard about it, Oct 25 morningRule rowThrough the engine?Now
1Held first email: ask the property owners to reply (leasing prep)A draft check held Clara's first email to a new leadCustomer staff inbox, by email ("I couldn't get a clean reply out. Can you reply to them directly?") one second after the #alerts cardEngineering errorYes (engine, its own family)Fixed: deleted. The #alerts card is the only signal.
2Text turn threwClara's text reply crashed on the last retryCustomer staff inbox, by email, as an ordinary hand-off; #alerts also pagedEngineering errorYes (turn outcome, unhandled)Fixed: alert outcome, no staff email.
3Email turn crashed mid-reply (fail open)The email agent threw after changing somethingCustomer staff inbox, by email; #alerts also pagedEngineering errorYes (turn outcome, unhandled)Fixed: alert outcome, no staff email.
4Text turn crashed mid-reply (fail open)Same crash, text channel; the text outcome never saw the crash reason and read it as "no reply"Customer staff inbox, by emailEngineering errorYes (turn outcome, unhandled)Fixed: crash reason carried; alert outcome.
5Agent-loop draft checks held the reply (fair housing, weekday or date, a tour time the calendar did not return, a tour confirmed that nothing booked, the anomaly review gate)A check held the reply and blanked it, with no reason recordedCustomer staff inbox, by email, as a hand-off (each hold also pages Slack)Engineering errorYes (turn outcome, unhandled)Fixed: holds are stamped "draft check held"; alert outcome; the 15-minute no-reply page still fires to #alerts.
6Held first email, PropFlow's own noticeSame hold as row 1#alerts card (was the hello@ mailbox until PR #21608 on Oct 21)Engineering errorNo (direct Slack post)Correct recipient, own path.
7Voice: a call-end door failedClara could not file the call's outcome#alerts onlyEngineering errorYes (alert outcome)Correct. The model the text and email paths now copy.
8Voice: a promise not keptA tool errored on a call and Clara told the caller "the team will follow up"Customer staff inbox (the caller is owed the callback)Clara cannot help (the callback) plus engineering error (the tool)YesOpen: keep the callback ask, add the #alerts page; one prompt still allows the promise another forbids.
9Text to a company line with no buildingOnboarding left a line unmappedCustomer staff inbox, by email; no engineering alertProbably engineering error (our config)Yes (unhandled)Open question for Fede: treat as ours (#alerts) or theirs (hand-off)?
10No reply and no reasonClara wrote nothing and no guard claimed the silenceCustomer staff inbox, by email (Gera's Decision 13)Clara cannot helpYesAs designed. Left alone.
11Emergency on-call chain stopped on a store errorOur store failed partway through the chainOffice inbox: "the on-call chain stopped early on a system error, please call the rest of the list"Critical emergency (plus engineering error)No (its own note path)Keep the page (life safety); add #alerts; move onto the engine.
12Gas or unknown-caller page when both lookups failedIdentity lookups failed on an emergency callCustomer PM inbox: "looking up the number failed on our side"Critical emergencyNoKeep (an emergency always pages); add #alerts; move onto the engine.
13Renewal stuck in "prepare failed" for 24 hoursAny cause, including our runner errorsPM email plus a text to the renewal contact: "hit a problem AppFolio hasn't told us the reason for"Split: PMS refusal is theirs, runner error is oursNo (renewal copy of its own)Open: split the cause; ours goes to #alerts only.
14Key pickup calendar write failedTool failure during move-inClara forwards to the PM (a person must book it)Clara cannot help, after an engineering errorNo (forward tool)Open: page #alerts too; keep the ask.
15Work order filing refused by the PMSThe PMS was down or refusedPM paged: "Clara couldn't file a work order"Clara cannot help (the PM can act)No (promise alarm)As ruled Aug 30. Move onto the engine.
16Mass-text or staff-desk send failedA send failed in a flow a staff member startedText back to that staff memberClara cannot help (direct feedback to the actor)NoFine: the staff member asked for the action. Move onto the engine.
17First-email ops feed cardCompose failed, no reply, or heldThe per-customer Slack channel the customer can see: "Clara could not draft a reply, nothing sent"Engineering errorNo (ops feed)Open: the customer can see our failure wording; route to #alerts or soften.
18Undelivered reply, tour confirmation with no booking, guard-rejected forwards, dead letters, stuck sagas, engine send failuresVarious internal failures#alerts onlyEngineering errorMixedCorrect recipient; several own paths to fold in.
19Lease not drafted emailLease draft failedNobody (no live caller)n/aNoDead code; delete.
20Promise alarm "we tried to send it and it did not go through"A send failed on a promised messageNobody (the human-notification lane refuses it)Engineering errorNoEffectively dead; delete or route to #alerts.
21Message taken, tour expected, gated inbound, tour slot refused, handyman stand-down, vendor notices, renewal holdsReal business outcomesCustomer staff, as intendedClara cannot helpMostly yesCorrect. Remaining own paths fold into the engine.
22Leasing-team auto-fire blanks the reply without a reasonA hand-off already told the teamCan produce a second "unhandled" staff notice for the same askA person is already on itYesOpen: stamp the silence so the engine stays quiet.
Rows 1 to 5 are the Oct 25 fix (PR #22417). Rows 8, 9, 11 to 14, 17 and 22 are the open items; none of them emails a customer about our error except 13 and 17. Rows 6, 7, 18 and 21 already reach the right people.

Proved at Willows, Oct 25, 22:43Z (PR #22417 merged 22:04Z, live 22:35Z). A Zillow-style inquiry to the Willows mailbox ran the real path: webhook, lead parser, first-email draft. The draft was held by a check (no tour times, no home named). What happened next, before and after:

Before: Western Slope, Oct 25 20:18Z (real customer)After: Willows, Oct 25 22:43Z
Held first emailYes, intent e65ca74bYes, intent 6784aef9, guest card 347
Engineering told#alerts card at 20:18:48ZInternal notice logged (a test property never posts to #alerts)
Customer staff emailedYes: "Can you reply to them directly?", delivered 20:18:49ZNo. Zero staff-notice rows, zero sends, SendGrid empty
Draft kept on the recordYesYes, status held
Second of three allowed attempts (the first draft passed on its one redraft). Covers the first-email path only; the reply-path arm of the fix (agent-loop holds, mid-reply crashes) is unit-covered by the harness and not yet run live. Side finding: the held French draft did offer tour times; the tour-times check reads only English and Spanish, so a correct French reply gets held (issue filed). The harness that keeps this closed is PR #22426: red on the old main (18 of 29 checks), green on the fix, two planted defects caught.

Why the hole stayed open for a month (history dig, Oct 25, from PR bodies, git history and four session transcripts): six earlier leaks since Sept 28, and every fix closed one sender, never the decision of where a Clara failure goes.

DateWhat reached the customer or staffWhat got fixedWhat stayed open, and why
Sept 28Western Slope leasing inbox: "Clara's first email could not be composed. Please reply to them directly."#13343: notice kinds labelled ours or theirs; a held first email is ours and goes to our inbox onlyAnything sent to staff by another route. Fixed at the one file that sent it.
Sept 25 to 30Western Slope staff got "Guest card not created" error emails, one for Fede's own test call#14252, #15547: failed guest cards go to the engineering channelOther staff notices were judged by reading their wording; gaps logged as follow-ups and not done.
Sept 30Prospects got "I wasn't able to generate a response, please call our office"; a crash leaked Clara's instructions to residents; the client got a "tour-day update" error email#14337, #14348: on a failure send nothing and page Fede ("If we error, we don't answer. I get pinged.")A single gate on all outbound was proposed and Fede rejected it; the session wrote "fix each leak at its source". Email staff notices never got the text rule.
Oct 7New: "I couldn't get a clean reply out. Can you reply to them directly?" to the property's people on a held first email (#17408); "please add it in AppFolio" (#17509)Nothing; both were built as features in an overnight autonomous runNot Fede's ruling. Because they went through the team-notify engine they counted as normal team notices and passed the Sept 28 check.
Oct 14Western Slope inbox: "AppFolio showing not recorded, please add it in AppFolio"#19579 deleted it; a failed AppFolio write holds, retries, alerts engineeringScoped to AppFolio writes; nobody searched for other "please do it yourself" asks.
Oct 21Held first email at Pomona Park emailed to hello@#21608: the ours branch posts one #alerts cardThe builder prompt and PR body said the team email path is "untouched".
Oct 24(set-up) #22249 removed the rewrite steps on first emails: a failed check now means one retry, then holdFewer bad drafts shippedKept the Oct 7 ask on purpose ("the team sees the existing held-email copy"); more holds meant the Oct 7 path fired more, which is why it showed up Oct 25.
The pattern: each fix patched one sender; the label "team notice" was the loophole; sessions kept reading "hold for a person" as "ask the client's staff"; text got "send nothing, page us" on Sept 30 and email never did. PR #22417 fixes it at the decider, and the harness shipping with it keeps every failure fact out of the staff path.

The one-path refactor, in four moves (plan only, not for today): (1) one decider vocabulary for every channel: every turn, tool and job ends as exactly one of handled, ask, hand-off, alert; the deciders for text, email and voice already agree, so the job is making every own-path caller in rows 6 to 20 produce one of those four instead of picking a recipient. (2) One sender: the team-notify engine becomes the only code allowed to address customer staff; a build check fails any other file that names an owner email, a PM inbox or a staff phone. (3) Alerts are a sink, not a recipient: "alert" writes the record and posts #alerts through one function; nothing else posts to Slack about a failure. (4) A table, not code, maps cause to recipient (the four rows above), and the harness shipping with the fix keeps every engineering-failure fact out of the staff path for good.

Four interfaces, each replacing a spread.

Proposed, not decided. Each is one small PR chain, no behavior change first (byte-identical replay), then the one-line behavior change. None adds a switch.

InterfaceReplacesOne question it answers
shouldSpeak(turn) → reply · hold · silent, with reason5 supervised-hold sites, 9 live checks, the opt-out withhold, the "human replied" policy skip"Should Clara say anything here, and if so does a person see it first?" One place, one log line per decision. The shadow feed's overlay is the first draft of it.
askTheTeam(matter) → one notice13 paging paths and the two owner lookups"Who owns this, and how do they want to hear it?" Writes the EscalationMatter, picks the owner once, sends one notice through the team-notify engine (then delete the engine switch). It is also the only path for a fallback: an internal failure writes the record and posts to #alerts, never a message to the customer or their staff (Fede, Oct 25).
readStaffInput(words) → answer · handled · question · note · unclear, with facts (ids) and a reasonThe phrase-list reader (classifyStaffReply), the rewrite step and the verbatim fallback on every place staff words come in (email reply, team note, held-card thread, a teammate in the thread)"What did staff just tell me, and is any of it for the person?" Only answer can reach the person, as fact rows with ids for door 4; every doubt is unclear (one line back to staff). Never sends. Built Oct 27, nothing calls it yet; the callers move in the next PR. Benchmark: 0 wrong sends in 144 cases, the phrase list on main 38. Design.
askState(thread) → asked · reached · acted · staleNothing today; the prompt says "it's with the team" unchecked"Before I say it's with the team, is it?" Read of the matter record; the design's state rule; verifier blocks the sentence when the record disagrees.
PmsInbox adapter (read texts, read staff replies, post a text)AppFolio literals in core, mirror-specific ids downstream"What did the tenant and the staff say in the customer's system?" Neutral rows; AppFolio one implementation (Fede's Oct 15 rule).
Figure 8. Proposed. The order is the order of the order of work. Each interface is first wired as a pass-through over today's code, proven by replay, and only then simplified.

Decided, Fede, Oct 25 evening (Clara Refactor session). Two rulings on shouldSpeak:

The riskiest layer: who is writing, and what turn is this.

A wrong pick loads the wrong rules, tools and facts. Design: one resolver for every door, in code: dated records, then the PMS label, then the door default. A role only moves toward silence. Unknown senders stay silent on the AppFolio copy and the mailbox. Proof: Benchmark E, not started.

Full context, trusted: a hypothesis, no proof yet.

Fede: give the model all the correct context (for a tenant: knowledge base, conversation, lease, work orders, staff messages) and trust it. No proof yet that it does not invent facts; it is the top bench row, run before any prompt is rebuilt around it.

Cerebrus: kill, merge or fold.

Cerebrus grades sent replies; nobody reviews its flags, and it cannot judge whether Clara should have spoken. Decided: D, fold (Fede, Oct 30) Keep its checks as plain app code, delete the engine and its CI check, throw the 362 existing flags away (Fede, Oct 30 evening: "we have more data now"), and, pending his answer, post each new text or email flag as a Slack card with the same rating buttons; checks nobody rates by Nov 25 are deleted. Numbers; full inventory and options.

04 · Baseline replay harness

Should each job prompt open with a goal? (research, Oct 28)

Answer: yes, a short one. Proposed, pending the bench. Every major vendor guide tells you to state the goal and explain the why. No study tests a 2 to 4 sentence goal block on its own, so our bench settles it. A long mission essay is the one thing the evidence argues against.

Three kinds of "goal" text, three verdicts

(a) Short goal at the top, 2 to 4 sentences  ->  DO IT      (all three vendors recommend it)
(b) A "because" on each key rule             ->  DO IT      (Claude generalizes from the reason)
(c) Long mission or vision preamble          ->  DON'T      (more words, more missed rules)
SourceFindingApplies to Clara?
Anthropic best practicesContext or motivation behind an instruction helps; "Claude can generalize from the explanation." One role sentence makes a difference.Yes: (a) and (b)
Anthropic context engineeringAim for the "right altitude": not brittle if-else rules, not vague guidance.Yes: keep the goal concrete
OpenAI GPT-4.1 guideTemplate opens with "Role and Objective". Instructions at the top beat the bottom if stated once.Yes: (a), placement
OpenAI GPT-5 guideContradictory instructions cost the model reasoning effort.Yes: never restate rules in the goal
Google Gemini guideState the goal clearly and concisely; context first, the ask last.Yes: (a)
Persona study (EMNLP 2024)A persona did not help on 2,410 factual questions.Partly: Clara writes, not quizzes
IFScale (NeurIPS 2025)More instructions, more misses; models favor earlier ones.Yes: against (c), goal goes first
When Instructions MultiplySuccess falls steadily as rule count rises.Yes: against (c)
Explanations in context (EMNLP 2022)Explanations help, but only large models.Yes: Opus 5.5 is large
Goal drift (2025)A goal stated in the system prompt drifts as context grows; firmer wording drifts less.Partly: our turns are short
Underspecified prompts (ACL 2026)Unstated needs are guessed right 41% of the time; listing every rule does not fix it.Yes: goal covers unwritten cases

What the block should look like

Three sentences, at the very top, before rules and inputs:

<objective>
This email answers the prospect's question using only the facts below and offers
two tour times from the tour windows. Success: they reply to pick a time, and every
fact we state is in the inputs. Never invent a fact, a price or a time; if a fact is
missing, say we will confirm it.
</objective>
<rules> ... each key rule with a short "because" ... </rules>
<inputs> home facts, tour windows, knowledge base </inputs>

If a job's inputs run long, add one line at the end restating the ask.

Not in the block: the company vision ("the PMS stays the system of record" is true but does not change this email), copies of rules already in the rules section, or any line with no effect on the message.

Bench to settle it (Clara Bench, smoke tier)

What we will do

  1. Write one objective block per job (first email, prospect text reply, repair intake, renewals), 2 to 4 sentences each.
  2. Add a short "because" to the rules that most often go wrong.
  3. Run the smoke bench above on first emails; one run, one decision.
  4. If it wins, the block ships in the decomposed prompts, no switch. If not, it is deleted.

Sources

Gap: no source tests a short objective block alone on a writing task. Quotes above are from the Anthropic page read in full; other rows are paraphrased from fetched abstracts and guides.

The replay harness: freeze today, diff every step

Proposed, pending review

First we replay every live customer's real records through today's code and save the exact output at every gate. After each refactor step we replay them and compare byte for byte; any change is named, unless it is a known bug we meant to fix.

Design only. Codes like F3 point at the map above.

Oct 27: the plan to make this the one harness, folding the others into it, is on the Harness Atlas, October 27 plan.

Day 0 · today's code on the frozen inputs Doors intext, email, PMS Lanes, routerlane and rung Prompt builtsystem text, tools Modellive, recorded once Guards afterdraft after each Gatesquiet, hold, door Records savedrows, would-send capture taps Frozen baselineinput snapshot + recorded model answers + one fingerprint per tap per record; scrubbed bytes kept outside git Refactor step N · same inputs, same recorded answers Doors in Lanes, router Prompt built Recordedno model call Guards after Gates Records saved compare Diff, one cell per record × tapsame bytes: green · different: red, naming the gate, module, channel, record id, before and after Exit 0: every cell identical Exit 1: any unexpected diff Known-bugs ledgerexpected-wrong cells skipped, not compared
Capture then replay. Every layer of today's machine is tapped once on Day 0. After each refactor step the same records run again with the same recorded model answers, so any change in bytes is the code's doing. Cells on the known-bugs ledger are skipped.

What this extends

No new rig. This is a new leg of evals/replay-harness, the atlas's recommended replay engine: it enters at the real door (runPipeline → dispatchInbound), proves its sandbox before turn one and already records gates. The capture record is its TurnMeasure with new fields.

The second engine is the hold replay behind #22334 (1.57M decisions over 203 buildings, byte-identical). It was a local script; here it becomes permanent.

PieceReused fromPath
Real door, sandbox proof, parity alignmentReplay harnessevals/replay-harness/run.ts, lib/sandbox.ts, lib/diff.ts
Read-only snapshot outside the repo, manifest with sha256Gold mine extractorevals/replay-harness/goldmine/
Bench target, Temporal fail-closedShared BenchConfigscripts/harness/types.ts, defaults.ts, temporal-guard.ts
ScrubberPromise harnessscripts/promise-harness/scrub.ts
Subscription billing, never API keysEval runnerscripts/lib/subscription-eval-runner.ts
Mutation control registryPre-push gatescripts/mutation-controls/

Bench scores quality; this checks equality. Clara Bench (frozen set v1, clara-benchmark#21) has judges score replies. This harness asks only: did any byte change at any gate?

Corpus and safety. Real records from Western Slope, Situs, JP&Co/Camellia and Willows, read only, snapshotted once, scrubbed with a stable map per record, stored outside the repo. Git holds ids and hashes only. Replays write to the bench at the test property with HARNESS_SUPPRESS_OUTBOUND=1.

What is captured

TapMapBytes capturedModulesChannels
1 Door and laneA1 to A7, S5Entry point fired; fixed-rule lane picked; any canned replyAllText, 3 email lanes, PMS inbox, guest card, voice transcript
2 Router rungS6The rung that claimed it (vendor, PM confirm, staff, tour, pass to Clara)All; tour is leasingAll
3 Turn inputsB1 to B13Trimmed history, knowledge block, every <system_context> messageAllAll
4 Assembled promptC1 to C24Full system prompt text, tool list, cache breakpointsWorkflow per module (C11)Email overlay (C18) separate
5 Model and side checksD5, D6Every tool round's raw output; every topic verdict. Recorded, then replayedAllAll
6 Guards after the modelE1 to E19Draft text after each guard, and which guard changed itLeasing E4, maintenance E5, rest sharedAll
7 Stay quietF1, F-e1Reason codeAllText, email
8 Hold decisionF3, F5, F-e2{hold, reason} at each of the 8 callers, plus the rule R1 to R7 that firedAllText, 3 email lanes, both doors
9 Door gatesF7 to F9, F-e3Each step reached and its verdict, in orderAllText door, email door
10 Would-sendF10, F-e5Adapter, synthetic recipient, final body bytes, caught by the kill switchAllAll
11 Asks, pages, PMS, remindersF12, F13, F17, F18Ask opened and its owner; page; PMS write intents; promisesAll; page is maintenance; PMS writes leasing firstAll, incl. voice transcript
12 Records savedG1 to G8Rows written, with generated ids and times replaced by placeholdersAllAll

Two pins keep it deterministic: the clock is set to each record's original time (C2, B13), and every read comes from the snapshot.

Two modes

ModeModelPasses whenUsed for
RecordedNone called. Each round's answer is played back by record, turn and round, not by prompt matchEvery tap identical, except cells on the ledgerEvery refactor step. A prompt change shows at tap 4 alone; the gates still get the same answer, so the report can say "prompt changed, gates identical"
LiveCalled on the subscriptionAt or above baseline on Clara Bench judges. Words always differ, so never equality. Bench v1 has no renewals or prospect reply turns; those steps stay recorded-only until it doesSteps that change the prompt on purpose

Known-bugs ledger

Bugs are not carried forward. Each known defect is one row; its cells (record × tap) are skipped, so its fix is not a regression, and the row becomes that fix's acceptance test.

Row: id · ref · tap and gate · module, channel · record selector (ids kept locally) · today · right · status.

IdRefTap, gateModule, channelToday (expected wrong)Right looks like
KB-01Machine map, 8 callers; #22334 unified the function, not the order8, F3/F5/F-e2All, every laneThe hold is asked from 8 places; PMS email checks "a person replied" before the hold, text holds at the row line and again at the doorOne decision, one order, same outcome on every lane
KB-02Machine map F-e48 and 9, F-e2 then F-e3All, SES emailAt a company not yet live, SES makes a held draft and approval card; Graph refuses the same input and logs itLive check first: refused and logged, no card
KB-03Fede's anti-pattern (Clara new hire); bench no_team_told check, clara-benchmark#216 and 10, E15/E17Tenant comms, leasing; text, email"I don't have that on file, I'll let the team know" goes outAnswer, or stay quiet and open one tracked ask
KB-04Hand-off audit (appendix): one in three hand-offs never reaches a person10 and 11, E17/F12All; text, emailReply says it is with the team; no ask is openedClaim a hand-off only when the ask opens in the same turn

Run and report

One local command on the subscription, never in CI:

HARNESS_SUPPRESS_OUTBOUND=1 npx tsx evals/replay-harness/run.ts --mode recorded --baseline day0-2026-10

On the testing ladder this is rung 3: every live customer's real book, read only, byte-identical. Atlas row: Clara byte replay, extends evals/replay-harness, recorded model, byte equality per tap, rung 3.

Build order

  1. First deliverable: tap 8 at all 8 hold callers on today's main, Day 0 frozen, mutation control registered. PR #22450 merged Oct 25 night.
  2. Snapshot, clock pin, recorded answers (taps 3 to 5). Being built, Oct 25 night.
  3. Remaining taps and channels.
  4. Ledger, atlas row, nightly run.
  5. Live mode on Clara Bench.

Decisions for Fede

1. How much of the book goes in? Decided

Fede, Oct 25 evening: every real record since each customer went live, census re-run first (August's count covered Camellia and Yale only). Decision 2 stays open; decision 3 was decided later the same night; no Day 1 go yet.

2. Voice in v1?

  1. Recommended: the transcript entry only (what the call-end door saves and opens)
  2. Also replay live calls through ElevenLabs
  3. Leave voice for v2

3. What gates a merge? Decided

Fede, Oct 25 night (Clara Refactor session): a pure move must be byte-identical on the Day 0 compare. A refactor that also fixes a bug on purpose passes only if every differing cell matches a known-bugs ledger entry named in the PR. Prompt changes are judged by the bench. On strictness Fede said "maybe fine".

Prompt changes, same night, Fede's words: "its fine if we merge prompt changes but its gonna go supervised for a while, like shadow" and "nothing live to customers". A prompt change may merge on its bench row, but it runs in shadow: drafts on cards beside what Clara sent, nothing reaches a tenant. He reviews examples over days ("as the judges have gotten it wrong") and flips shadow to sending per customer by hand, the same rule as A1.

05 · Clara the new hire

Clara the new hire

Clara joins the office like a new employee, and the first thing she learns is when not to speak.

#QuestionIf yes
1Should I be quiet here? (a thanks, a reaction, an unknown sender, a mass-text answer)Stay quiet
2Should a person take this? (a floor, a money call, an exception)Stay quiet to the tenant; track it for the owner
3Is a person already on it?Stay quiet
4Is my reply actually helpful?Reply. If not helpful, do not reply.
Before every reply Clara asks these four questions, in this order. This is what shouldSpeak is for.
Week 1 · Setup, onceConnect, read into the brain, identity of buildings and residents, who owns what per building, meet the team
Lost here: Situs live at 33% coverage; no owner on any of its 52 properties; a ring list dialing an old number; Rossi's 11 notes, 9 saying "property not identified"
Month 1 · Learn & feedbackRecipe from past records; asks in batch; readiness is a number
Lost here: Western Slope went live at 35–70% replay accuracy; the notice-to-vacate period was never asked
Month 1–3 · SupervisedShadow the person who does the job; in-system gate where one exists; no queue
Lost here: 95 of 142 held drafts expired silently at 24 h, a rule nobody decided; Spencer's moved tour never reached him
Month 3–6 · Live, next layer learningA ask & remember · B hand off · C morning list · D check first · E take work
Lost here: three cats ("with the team", no ask ever sent); 122 silent drops; the roofing caller asked 4 times for a person; 16 Western Slope asks waiting
Setup, once: connect the systems, read what the office has into a company brain, learn who owns what, meet each person.
The loop, per layer of work: learn the office's recipe from its records, get corrected by answering questions, work supervised, go live when a readiness number says so.
Supervised: the customer's own Send button or an approval card is the design (Fede: “I never said I didn't want an approval queue”).
Live, five habits: ask and remember, hand off as a kept state, remind next morning, check before speaking, take work the team sends.
Clara does itYour team does itWhere a new hire without this gets lost
Week 1 · Setup
Learn & feedback
Supervised
Live
Clarathe new hire
Reads the PMS, inbox, notes and drives into the company brain; works out who's who
Introduces herself; asks how each person likes to work
Drafts each job's recipe from past records
Asks what she cannot read, in your words, once
Drafts next to the person who already does the job; agreement is measured on real work
Answers, books, chases inside policy
Asks and remembers · hands off as a kept state · morning list · checks before speaking · takes work from the team
Your teamthe senior
Connects the sources; answers the who-owns-what questions
Answers questions; decides per customer when a module moves
Keeps working as before; corrections are graded; Clara sorts a standing answer from a one-off herself and saves the standing ones
Decides the 20%: legal, money, exceptions; reads one morning list
Without thiswhat we measured
Goes live knowing a third of the answers; nobody told her who owns what
Readiness is a date, not a number
Drafts sit in a queue and expire unseen
Says "it's with the team" when nobody was asked; one in three hand-offs never reaches a person
Figure A. The lifecycle at 10,000 feet. Setup happens once; the four-step loop repeats for every deeper layer of work in every module; the five coworker habits run from the supervised stage on. The gap lane is what our own hand-off audit found at offices where an AI already answered renters (see the appendix).

She replies only when it helps. Otherwise she stays quiet and tracks the work, asks one owner for help, or stays out because a person is already on it. The anti-pattern: “I don't have that on file, I'll let the team know,” plus one more email to the team. Two dials per customer: scope (which jobs she holds) and autonomy (a person approves first, or she sends by written policy). Fair housing, legal and emergencies are never hers. Long term she carries most routine work (Fede's aspiration); phone is out of scope.

06 · Tenants

Tenant communications: maintenance first, renewals second.

Next, Clara starts answering tenants: maintenance first, renewals second. Proposed, pending review

TODAY AppFolio inbox copycopy switch, default off Code gate (no model)role · teammate last · tenant door off → silent Intake classifierSonnet 4.6 · files work order Reply writerSonnet 5 · 53k prompt Haiku topic → hold?maintenance → PMS door Can't answer: "I'll check with the team" to the tenant · escalation row only if the property names an owner email · morning digest of unanswered questions. Non-maintenance replies leave from Clara's own line, not the AppFolio door. Email never wakes her here. PROPOSED Any doorAppFolio copy · line · mailbox Code gate (same, free)+ notices, staff-typed, unknown → silent One Opus 5.5 call, full contextlease · unit · work orders · thread · KB · settings Checks blockfacts · promises · no "check w/ team" Hold cardproperty Slack The one call outputs: reply or silent, the reply, and the facts it used with their source. Silent = tracked internally, nothing sent to anyone. Every tenant reply leaves by the same door the tenant used (AppFolio door for AppFolio texts), not only maintenance. Work-order creation becomes a tool of the one call; the separate intake classifier and the Haiku topic step retire. Supervised = every reply stops at the hold card until a person approves; the model's own decision replaces the Haiku topic for routing the card.
Today, no model runs before the wake; the tenant door is a switch (default off) and only maintenance replies take the AppFolio door. Proposed: one call decides and writes, checks only block, the hold card is the supervised step.

Fixes to what is already live ship with no switch and go live everywhere on merge. New outbound, such as tenant replies, the morning list or staff texts, ships dark: off by default until Fede turns it on per customer.

Tenant replies are released one module at a time (Gera, Oct 26). If maintenance is released at a company, replies the one call declares as maintenance can go out; a reply on any topic whose module is not released stays silent or held, never sent. The gate already exists at the send door (door 6): company-live-gate.ts takes the module the writer declares (door 3) and holds on module_off. The module's own mode is the release: off = silent or held, supervised = hold card, on = sends. So the one company setting above sits behind that per-module gate, not in place of it, and today's maintenance.pms_inbox_tenant_door is the first of those gates and stays.

StepWhatSwitch?
1Read-only replay of every customer's real book through the state rule and ownership routing; byte-identical where behavior is unchanged; hand-off correctness becomes a standing numbernone
2Fixes to live behavior: no "with the team" without a tracked ask; no held drafts on Clara's own channels (covered topics answered live, the rest an ask); routing by the ownership map; delivery confirmed before a hand-off counts; a staff answer passed to the renter and recorded on its ask; today’s standing-vs-one-off sort keeps saving standing answers until the question in step 4 replaces it; identity checked before a policy answernone, live everywhere on merge
3Willows live run with Fede's own number as staff: a prospect conversation to an ask, the chaser, the intro, a piece of work sent to Clara by text—
4New outbound: the morning list to staff; transfer confirmed by text to the caller; Clara introduces herself; Clara texts staff questions; Clara chimes in inside their shared inbox; Clara proposes PMS settings; after an answer Clara saves the standing ones as policy herself (the vision's "your answer becomes policy"; no “remember this?” question, Fede Oct 24)company setting, default off, Fede turns on per customer
5Sandbox company in the customer's shape, then a supervised week at the customer—
Figure 9. The ladder from the testing playbook; unit tests and planted defects are build hygiene, never a proof step. Nothing is "tested" until a real conversation ran end to end on a live rung with record ids. Where the three live customers enter the lifecycle is question 1 in decisions for Fede.
07 · Order of work

Order of work: the base first, then Fede's three priorities.

After the foundation (Fede, Oct 26 night): attack the false holds and false passes that (1) hold leasing emails for no reason, (2) let wrong facts out, and (3) cause accidental escalations to customers, "so this never happens again". Door 4 for holds, doors 2 and 4 for facts, door 4 promises plus the ask-for-help door for escalations. The 30-day gate ledger below is the before-number; the same 30 days and the 5,515 frozen decisions give the after-number. Nothing is attacked before every fold and the pure-split baseline are merged.

How nothing gets lost (Fede, Oct 27 night: 'i keep reminding you of things we forgot'): every piece of feedback Fede gives, in any session, becomes a tracker row with an owner the same day (136 items from Oct 23 to 27 are rows 58 to 71 and the 'What Fede said' section). The tracker derives a 'Said, not acted on' list: every row that came from his feedback and has no PR after two days. That list renders here and on the morning page; a row stays on it until a PR exists or Fede closes it.

Said, not acted on

Rows from Fede's feedback with no PR after 2 days, oldest first, derived from the tracker by bin/derive-master (UTC date 2026-11-02).

RowWhat he saidFirst saidOwnerDays with no PR
7Maintenance intake: a two-issue text can lose one issue (nothing filed, nothing asked)2026-10-25fede8
10Situs Group onboarding package: Clara's intro texts, what she does, the who-owns-what map, the hello per role2026-10-25fede8
13Hand-off fixes to live behavior on the shared interface: the one-in-three hand-offs that needed a person and never reached one2026-10-25fede8
14'Did a human already reply' signal from AppFolio, so Clara stays out when a person is on it2026-10-25fede8
17Tenant replies path dark: maintenance first, renewals second, behind the existing tenant-door setting2026-10-25fede8
20Decision 3 (decided): the morning list is a per-company setting, off everywhere for now2026-10-25fede8
66Unanswered-tenant alert skips threads already handed to the team (Situs)2026-10-270016
68Emergency categories and policy in Clara's context and the bench (a water leak is usually urgent)2026-10-270016
69Alerts never tag Fede and Gera2026-10-270016
70Open questions from Fede's feedback (Oct 23 to 27)2026-10-270016
82Deep review, one case at a time: every shadow-card rating and every supervised hold since launch (context, category, previous messages, should-reply logic)2026-10-270016
88Follow-up writer stops echoing a bedroom count from the card notes (Jessalyn: "2-bedroom" at an all-3-and-4-bedroom property)2026-10-270016
90"I can't add anything here" is a recognized outcome with no outbound at all (one-door design)2026-10-270016
97Tenant-text judge fixed so candidate rows are scored, not shown unjudged (control failed Oct 25)2026-10-270016
98Post-release watch: the week after a swap, the same shadow cards plus a daily count of sends, holds and Wrong ratings for that job2026-10-270016
113Willows guest-card first email has no live driver (rows 93, 104, 47 cannot be proven live)2026-10-270016
122A Zillow relay lead for a building we hold is filed on the company front door because the building-name match is exact (door 2 intake adapter)2026-10-270016
125Ember Estates lead: we couldn't locate the property (design + harness first)2026-10-28Situs Leasing session (handed off by Fede, Oct 28)5
129A neighbor's complaint (drugs, noise, a person) is never answered as a repair follow-up; Clara stays quiet and it goes to the office2026-10-290014
135A short acknowledgement beats silence when a tenant explains themselves or asks when the tech comes2026-10-300013
143First-email prompt split (real, by deletion) - parked2026-10-300013
144Lampliter third-party inquiry (Michael Neuhalfen), tour already on the card2026-10-30Situs Leasing session3

The base is refactored first; Fede's three priorities sit on top of it, in his order. Proposed, pending review

Fede's three priorities, in his words and his order:

  1. Situs Group onboarding done well: Clara's introduction to their team, what Clara does, working better with their people.
  2. Make the hand-offs clear, and a hand-off framework built from customer feedback.
  3. Upgrade to Opus 5.5 and get ready to start replying to tenant communications.

The full advice on the order (why the base is refactored before any module) is in the tracker's working notes.

The order of work, as a chain of what depends on what

Not a calendar. Each slice starts when the slices it depends on are done, and its state is what the tracker shows today.

Left to right: a slice starts when every slice its arrow comes from is done. Green = done, amber = in build or merged, not proven, grey = not started.A. Frozen baselinein buildB. Hold: one doordoneD. Topic: one classifiermerged, unprovenF. Model plumbingmerged, unprovenG. Situs onboardingin buildC. Ask for help + noticesin buildH. Bench: full vs restrictivein buildI. Hand-off fixes, livein buildE. The rest: 47 to 4in buildJ. Tenant replies, darknot startedK. PMS inbox + reviewin build
Slices B through E are the same move repeated: one door, byte-identical on the frozen baseline, delete the copies. G runs beside the refactor; it only needs the baseline.

States derived from the phase tracker by bin/derive-master (tracker refreshed 2026-11-02 05:58Z), never typed by hand.

SliceWorkDepends onState
A Frozen baselineA fixed corpus per surface (prospect first email, prospect reply, tenant repair text, tenant other text, Spanish slice across all), smoke and full tiers, content-hash locked, production's run recorded as the baseline row on the Clara Bench page. Renewals and voice get their first frozen set later. Owner: Benchmark lane.

Status: see the derived state in this row. Clara Bench set v1 is frozen and locked (clara-benchmark PR #21 merged; a drift test with four planted changes went red on all four; the text stays off git, masked, on this Mac). Production's baseline is adopted on the Clara Bench page as row 2026-10-25-baseline-v1. Headline, tenant texts the office had already answered within 48 h: today's writer would reply on 82 of 96 (85% noise), and only 72 of its 119 replies help, the rest are "I've told the team". Repair texts, smoke of 20: noise 10 of 10, filing matched the office 7 of 17. Prospect first emails, 51: 24 held by send checks, 50 of 51 helpful. Live tenant noise is 0 today only because the tenant switch is off at both customers; the bench bypasses the switch. Zero writes, zero notices during the run. Caveat: the Clara-vs-office judge column on tenant-other texts is not valid yet (the mirror pairs the wrong office reply in 8 of 13 controls); v1.1 re-pairs. Earlier that day the answer to "do we have a frozen baseline?" was no; renewals and voice still get their first frozen set later in the week.

nothingin build · 1 proven, 1 part landed, 1 not started · from the tracker
B Hold: one doorshouldSpeak seam at all 8 hold callers, no behavior change, byte-identical replay (PR #22450, merged Oct 25 night). The six hold backstops stay: each guards a path the earlier check never sees (final module after routing versus provisional; router replies with no Clara turn; door sends with no turn), and all six now call the one shouldSpeak function. That is the collapse: one implementation, several call points. Next, same slice (PR #22473, armed, Day 0 byte-identical): the first-email check folded in, isLeasingSupervisedAt deleted, one log line per decision, and the first no-duplicates check (scripts/check-should-speak-duplicates.ts, zero-entry allowlist, mutation control).Adone · 2 proven · from the tracker
D Topic: one classifierThe four module classifiers (tour intent, repair triage, renewal decisions, lease questions) behind one shared classification, byte-identical replay.Amerged, unproven · 1 merged, unproven · from the tracker
F Model plumbingOne registry of model paths for every Clara call site, pass-through, byte-identical replay (PR #22446, merged Oct 25 night).Amerged, unproven · 1 merged, unproven · from the tracker
G Situs onboarding packageClara's introduction to the Situs Group team and the working agreement, built and proven at the Willows first.Ain build · 2 merged, unproven, 1 not started · from the tracker
C Ask for help + staff noticesaskTheTeam(turn, ask) pass-through seam over 23 callers on the three existing paths (page the team 12, held text 7, turn outcome 4), Day 0 byte-identical (PR #22455, open). askState(thread) maps to asked, reached, acted, stale; no caller yet. Still outside the seam, each its own next slice: tellStaff (16 callers), sendOrHoldTeamNotice (13, business notices not asks), sendStaffAskSms (6), pagePropertyManager, two direct notice-engine callers. Then every fallback routed through the one notice engine, the staff-facing fallbacks removed (the first-email draft-check fallback found Oct 25, and whatever the Escalations audit lists), failures to #alerts only.Bin build · 2 proven, 1 merged, unproven, 1 part landed, 2 not started · from the tracker
H Bench: full context vs restrictiveFull-context versus restrictive row on the frozen set. Repair path on the decomposed prompt, writer on Opus 5.5, Willows end to end.A, Fin build · 1 proven, 3 merged, unproven, 3 in flight, 3 part landed, 1 not started · from the tracker
I Hand-off fixes, liveHand-off fixes to live behavior on the shared interfaces, plus a Willows run.Cin build · 6 proven, 18 merged, unproven, 3 in flight, 2 part landed, 15 not started · from the tracker
E The rest of the 47 → 4One small PR per table row above, same move each time: one door, byte-identical, delete the copies. PMS write becomes one adapter.C, Din build · 14 proven, 11 merged, unproven, 5 part landed, 6 not started, 1 canceled · from the tracker
J Tenant replies, darkMaintenance first, then renewals, dark. Held drafts that expire in silence become an approval that stays open.I, Hnot started · 3 not started · from the tracker
K PMS inbox adapter + reviewPmsInbox adapter pass-through; the core-and-modules diagram checked against the code; review with the numbers. Found Oct 26 (Lori Ruiz, Western Slope): PMS notification emails get drafted to and refused; a text-door refusal (party not in thread) is read as "no phone"; an inbound on an unlinked PMS text thread never reaches the person. Belongs here, not a new item.E, Jin build · 1 part landed · from the tracker

Phase tracker

Status of each phase, derived from PR and decision state and refreshed on a schedule.

Separate URL on purpose: the tracker is rebuilt by a script on a schedule (status derived from each row's PRs, decisions and production evidence), so it cannot live inside hand-written HTML. Open it on its own at /a/clara-new-hire-phase-tracker.

Working notes (ledgers, bench results, model inventory, both final-pass reviews, the chapter list) live on the tracker page under Working notes.

07b · Rollout plan

Rollout plan: order of execution and dependencies

Order of execution and dependencies live on the tracker: clara-new-hire-phase-tracker#roadmap

11 · Battle test

Battle test: five real cases from Oct 26 against this design

Proposed, pending review Design only: no fixes, no PRs, nothing sent. Fede, Oct 26: "before we go into quick fixes i want a deep dive into each area, see how the new architecture would have covered it or not covered", and "these are exactly the kind of weird bugs and edge cases we want to roll into the new architecture". Each case is read against the sentences on this page as they stand, then turned into a test the refactor must pass.

Verdicts: COVERED a sentence on this page prevents it · PARTLY the page points the right way but leaves the failing part open · NOT COVERED the page says something that would still let it happen · NOT ADDRESSED the page is silent.

A · Held first emails (Trang at Ember Estates, Patrick at Northridge)

Two Western Slope first emails were held on the same check. Trang got nothing until a session sent the draft by hand at 15:28Z. Patrick got his application link but no answer to his lease question and no tour offer. The drafts were written correctly once; code around the writer broke them.

1. What happened2. Owner on this page3. Covered? The sentence4. What the design must say5. Battle-test case
Tour times stripped by provenance. Trang's first draft offered two real slots from the facts block. The "tour times from this turn" guard only counts a calendar call made this turn, so it ordered a retry with no times; the first-email check then held it for having no times. Intent 5e0d4682, snapshot tsnap_4faebf4f, 14:41Z.Turn rebuilt, layer 5 (facts resolved by code: "tour windows") and "Checks that only block".PARTLY "Checks that only block: a count, a closed time" checks a fact, and layer 5 hands the slots in as facts, so the new turn should not have this gate. But the machine map still lists "tour times from this turn" as a guard and the page never says it is deleted or rewritten.A check compares the draft against our own records (the slot list, the calendar, the listing rows), never against which tool ran this turn. Every provenance guard is listed and converted or deleted.Fixture #22483 (offline replay of the real held draft, XFAIL today, strict mode red). Assert: draft names one given slot. Positive control: the writer's own first draft passes. Joins Day 0 as ledger row on tap 6 (which guard changed the draft) and tap 8.
The one retry never ran. The writer-call capture skips any round with a tool call; every first email ends with the declare tool, so there was nothing to retry (retried: false). Same shape Oct 25 20:18Z.Turn rebuilt: "Retry once, then hold for a person".PARTLY The sentence promises a retry; nothing on the page proves the retry exists on each path.The retry is part of the core turn, not each module's capture code, and the harness records "retry attempted: yes / no" as its own cell.New tap: retry attempted, per held turn. Assert yes on Trang and on the Oct 25 hold. Mutation control: replant the skip, cell turns red.
Half a turn. Patrick: the application went out through AppFolio at 15:35Z, then the reply was held on the same check. He got the link and silence. Intent ff83442c, card 3048.The record ("a step-by-step ledger of what she did"); four ways a turn ends.NOT ADDRESSED The page treats a turn as one outcome (send, hold, quiet, ask). It never says what happens when an action already ran and the words did not.A turn's actions and its words are two outcomes on the record. A held reply carries the actions already taken, the retry is told they are done, and the person seeing the hold sees them. Words are never edited after writing (Fede's no-rewrite rule; the send-layer split was refused Sep 30); the fix is the writer passing, not a partial send.Patrick fixture (not in any harness today): tap 11 shows the application intent, tap 8 the hold. Assert: hold record lists "application sent"; retry draft does not resend it. Control: same input without the application ask holds nothing.
Silent holds. Trang's hold had no review record, so the conversation page showed nothing and no one could approve from Slack or the app; four turn snapshots marked held (Oct 25 to 26) have no hold row, though what that flag means is not yet proven; the records that exist store a reason, not the check name.Notice engine; "Recipient by cause"; Supervised ("an approval card is the design").NOT COVERED The cause table puts "a draft check failed" under engineering error: "Nothing. No reply, no staff email, no hold card. Clara stays quiet." Read literally, that is Trang's silence. It also contradicts "Retry once, then hold for a person".A blocked reply to a renter is never silent: it is one hold record (draft, check name, finding, renter's latest words, actions taken) plus the #alerts line, recoverable everywhere. Staff are still never emailed about our failure.Census cell: every held turn has exactly one hold record with a check name. Today red: since Oct 25 noon only one Western Slope first-email hold row exists against at least four held turns.

Judged against the hub's held-messages design (option B: one hold record, the draft inline on the conversation page, approve, edit and send, retry and dismiss on every surface, automatic retry on a new renter message): it fits this page's rules. It adds no routine queue, holds exist only where Fede chose supervision or Clara could not write a sendable reply, and it merges the two hold paths (the intent row and the review queue) into one record, which this page needs and never states. The page should adopt it as the review door's design.

B · The listing special and the price ranges (Trang, Ember Estates)

Ember advertises six free weeks on its listings. Trang never heard about it, and the email she did get quoted a price range that mixed in a home not open until Nov 2.

1. What happened2. Owner on this page3. Covered? The sentence4. What the design must say5. Battle-test case
Special dropped. "6 weeks free" was on the listing rows for 363 and 364 Ember Ln and came back in the unit lookup. A prompt line says "Tool results never carry concessions; if the block is absent, no specials are running", so Clara left it out on purpose (her own reasoning says so). Asked "any specials?", she would have said no.Layer 5 facts; layer 3 job prompt; "Build-time coherence test".NOT ADDRESSED The word special appears once, as today's prompt block. Nothing says where a special lives or when it is shown. The coherence test catches two rules on one topic, not a rule that contradicts the data.A listing special is a field on the home with an end date, shown on the same line as that home's rent wherever the home is named, and never copied into the knowledge base. Past its end date it is gone.Bench episode on Trang's frozen turn (prompt change, so live mode plus shadow, per decision 3). Assert: special mentioned; "any specials?" answers yes. Control: a home with no special, none mentioned. Mutation: put the prompt line back, red.
Specials in the knowledge base. The concession watcher writes temporary listing specials into the knowledge base; four stores, five render paths, none with an expiry.Knowledge block ("full dump, no search"); the modules table, Knowledge row.NOT ADDRESSED The page fixes where the knowledge base is read, not what may be written into it.Where facts live: each fact has one home (listing facts on the listing, standing policy in the knowledge base). The knowledge base holds no temporary fact.Replay cell on tap 3 (turn inputs): the knowledge block contains no listing special for any property in the corpus.
Ranges, and one wrong. The sent email said "$2,775 to $2,795, 1,289 to 1,435 sq ft, open right now". $2,775 and 1,435 belong to 2863 Florida St, which opens Nov 2. Two prompt rules disagree (quote a range; name by size), so the model picked differently at 14:40 and 15:15.Layer 5: "availability shaped to one home with no counts"; layer 3: each job "owns its homes-to-name rule exactly once".PARTLY "One home, no counts" is on the page; "no ranges" and "open now means open today" are not.The facts block names one home with its own price, size, open date and special; never a range; a home that opens later is never "open now".Same episode. Assert: one price, one size, no "to"; no figure from a home not yet open. Control: a single open home quotes its own numbers.

C · A renter writes again on the same guest card (seven sync bugs)

1. What happened2. Owner on this page3. Covered? The sentence4. What the design must say5. Battle-test case
Later messages lost. AppFolio folds repeat messages into one inquiry; we keep one, so Clara answers the first and never sees the rest. Situs card 8995 (photos, utilities), WS card 3047 (tour ask). A 60-day sweep found 5 cards with this shape (3 Situs, 2 Western Slope).PmsInbox adapter ("read texts, read staff replies"); turn assembly.PARTLY "Neutral rows; AppFolio one implementation" puts it in the right box, but the page says nothing about one row per message, or that a new message is a new turn.PmsInbox returns messages, each keyed by the provider's own message id; every new message is a turn; prospects and tenants follow the one rule (the dark tenant copy already does).003's local harness: 7 cases, 18 checks, 7 red today, 18 red with a planted defect, all green on design A. Today it is rung 1 on the testing ladder (fixtures with a planted defect: build hygiene, not proof). To join the gate, its real cards enter the Day 0 corpus and its 7 red cells become ledger rows on taps 1 and 12.
Rerun duplicates the message. Re-running Trang's first email wrote "I'm interested..." a second time (14:40 and 15:15), because each run mints a fresh id. The lead card and first bubble also show the same words.The record; replay harness "Records saved".NOT ADDRESSED Idempotent writes are not mentioned.Every write is idempotent on a stable key (provider id, or the guest card's own key); a rerun or retry never adds a row.Replay twice on the same record; assert tap 12 identical row count. Control: a genuinely new message adds one row.
Half-done hold (Patrick, bug 7), and an empty thread for 30 to 60 s before the first save.As case A, row 3; the record.NOT ADDRESSEDAs case A. The renter's message is saved when it arrives, before the model runs.Tap 12 order: message row written before the first model round.

Customer-side, listed only (not ours to code): Situs staff reconnecting Google with the calendar box ticked; the Situs AppFolio auto-responder, which sends three canned emails per renter beside Clara's.

D · Staff took the thread inside AppFolio (Patrick and Kat)

1. What happened2. Owner on this page3. Covered? The sentence4. What the design must say5. Battle-test case
Kat replied to Patrick inside AppFolio; the reply was mirrored; Clara stayed silent. The approve path closed the held draft, and no follow-up cadence started. Conversation bbc825d1. This worked.shouldSpeak ruling; Recipient by cause, row 3; PmsInbox ("read staff replies").COVERED "'Is a person already on it' is reasoned, never timed", and "A person is already on it: Nobody. shouldSpeak returns silent." PARTLY on the aftermath: the page never says what happens to a held draft or the cadence once a person takes the thread.When a person takes the thread, Clara's held draft closes with that reason on the record and her own follow-ups stand down until the thread is handed back.The staff-took-thread fixture being built separately. Assert: shouldSpeak silent with reason "person on it", held draft closed, no cadence row. Control: same thread with no staff reply, Clara replies.

E · The held-item Slack card

The card that announced Trang's hold tagged Fede and Gera, looked like the old cards and offered nothing to press, so the only way out was a session running a script.

1. What happened2. Owner on this page3. Covered? The sentence4. What the design must say5. Battle-test case
The card for a held item tagged Fede and Gera (a fixed list in code, whose comment says it is deliberately not a setting), used the old renderer and had no actions. Fede: "it should not tag me and gera", "why is it not using the new design".Notice engine ("A module never picks its own recipient"); modules table, "Review door for automated sends"; tenants: "Hold card, property Slack".NOT ADDRESSED Who is tagged, which renderer, and what a person can do on the card are absent. The review door is a row in the modules table, not one of the four interfaces.The review door is named as a core interface: one renderer, the four actions, recipients from the cause table, nobody tagged by default; the mention list is a per-customer setting Fede picks.Render tap on would-send (tap 10) for every hold in the corpus: zero mentions by default; the same card shape and actions on every surface; then a production screenshot of a real card.

What the five cases say about the design

The page decides well who speaks and who hears; it is thin on what is true and what is left behind. Three of five cases are gates that judge by where a fact came from (a calendar call this turn, a "no specials" block) instead of by the fact in our own records, and the new turn removes their reason without naming them for deletion. Two hold paths exist, and one leaves no record, so a blocked reply becomes silence; the page's own cause table, read literally, keeps that silence. Facts live in several places at once (specials in four stores, messages overwritten into one row), so the facts block cannot be trusted until each fact has one home and one key. A turn is drawn as one outcome, but real turns act and then speak, and half a turn is the worst shape. PMS literals sit in core leasing code on every path we read: the listings syncs and listing details import the AppFolio scraper directly, core reads AppFolio-shaped inquiry fields, the special is extracted inside the scraper, and the first-email send, consumer, prep and inbound-message files name AppFolio (debt, not fixed here). None of these were caught by the Day 0 harness, because it freezes today's behavior; each one needs a ledger row so the refactor does not lock it in.

Design changes to this page, ranked

  1. Checks compare the draft against facts in our own records, never against which tool ran this turn; every provenance guard on the machine map is listed for conversion or deletion.
  2. A blocked reply to a renter is never silent: one hold record with draft, check name, finding and actions taken, plus the #alerts line; rewrite the "draft check failed: no hold card" row to say so.
  3. One hold record and one review door for every hold kind, named as a core interface, adopting the hub's option B (four actions on every surface, automatic retry on a new renter message).
  4. A turn's actions and words are separate outcomes on the record; a held reply names what already ran, and the retry is proven to run.
  5. PmsInbox returns messages keyed by the provider's message id; every new message is a turn; every write is idempotent on a stable key.
  6. Each fact has one home: a listing special is a field on the home with an end date, shown wherever the home is named, never in the knowledge base.
  7. The facts block names one home with its own price, size, open date and special; no ranges; "open now" means open today.
  8. Hold cards tag nobody by default; recipients come from the cause table; one renderer.
  9. When a person takes a thread, Clara's held draft closes with a reason and her follow-ups stand down.
  10. Each case above becomes a known-bugs ledger row (proposed KB-05 to KB-12), and none is called fixed until a real conversation runs end to end at the Willows.
08 · Owner calls

Real-life ledger: every hold, issue and incident, and whether it is closed

Proposed, pending review. Read-only sweep of production holds, Slack cards, GitHub issues and incident pages, Oct 26 2026. Nothing was changed or sent.

318 real-life cases. 28 fixed and tested, 76 fixed but untested, 63 open, 5 regressed, 142 by design, 4 unknown. Of the 176 that are not by design, only 28 are fixed and tested.

Each case is read against the master design on this page with the battle-test words: COVERED, PARTLY, NOT COVERED, NOT ADDRESSED. Each case not fixed and tested gets one line on how it joins the Day 0 replay harness (evals/replay-harness, #22445) as a fixture or the bench as an episode. No new harness folder. The pattern is #22483 (held first email with tour slots) and #22488 (staff took the thread).

Counts

SourceFIXED+TESTEDFIXED, UNTESTEDOPENREGRESSEDBY DESIGNUNKNOWNTotal
Holds (rows and cards)113431414166
Incident pages712520026
GitHub issues205154010126
All28766351424318

By root cause, cases that are not by design:

Root causeCasesFIXED+TESTEDFIXED, UNTESTEDOPENREGRESSEDUNKNOWN
hold handling (review door)366151500
sync dropped a message30220701
identity/matching291151201
other code bug25911410
provenance gate stripped real facts22341230
missing fact in prompt12111000
tours and staff-desk logic1052300
writer quality (prompt rules)808000
unknown200002
review mode by design110000
wrong fact in KB100010

Against the design, holds and incidents that are not by design (graded by reading each against the page; issue rows carry a keyword guess and are not counted here): COVERED 5, PARTLY 32, NOT COVERED 2, NOT ADDRESSED 12. Most NOT ADDRESSED cases sit in three places the page is thin on: the hold record and review door, idempotent writes in PmsInbox, and what is left behind after a turn acts.

Holds

453 hold rows in production since Aug 31: 158 at Western Slope, Situs Group and Camellia, 295 at test companies (Willows, Yale, Fairhaven; left out). Plus 6 first-email holds that exist only as a Slack card, with no hold row. Maintenance texts are Supervised by design, but 107 of 119 expired after 24 hours with nobody pressing anything, so the resident never got the "work order created" or "rate the repair" text. That is the largest real-life gap in this ledger; #22487 (open) touches the same Supervised path.

Date (UTC)CustomerPropertyKindGateHeld text, first lineOutcomeRoot causeVerdictDesignHarness view
Oct 11 to 26Situs Groupmanymaintenance texts (42)SupervisedWork order ... created / rate the repairexpired unreviewedreview mode by designBY DESIGNshouldSpeak Supervised + bt-e review door: PARTLYAlready frozen: Day 0 tap 8 records the Supervised hold at the maintenance caller. Add a bench episode only for the expiry outcome: assert an expired resident text raises one owner notice. Control: an approved card raises none.
Oct 11 to 26Situs Groupmanymaintenance texts (3)SupervisedWork order ... created / rate the repairstill pendingreview mode by designBY DESIGNshouldSpeak Supervised + bt-e review door: PARTLYAlready frozen: Day 0 tap 8 records the Supervised hold at the maintenance caller. Add a bench episode only for the expiry outcome: assert an expired resident text raises one owner notice. Control: an approved card raises none.
Oct 11 to 26Western Slopemanymaintenance texts (5)SupervisedWork order ... created / rate the repairapproved and sentreview mode by designBY DESIGNshouldSpeak Supervised + bt-e review door: PARTLYAlready frozen: Day 0 tap 8 records the Supervised hold at the maintenance caller. Add a bench episode only for the expiry outcome: assert an expired resident text raises one owner notice. Control: an approved card raises none.
Oct 11 to 26Western Slopemanymaintenance texts (1)SupervisedWork order ... created / rate the repairapproved, delivery failedreview mode by designBY DESIGNshouldSpeak Supervised + bt-e review door: PARTLYAlready frozen: Day 0 tap 8 records the Supervised hold at the maintenance caller. Add a bench episode only for the expiry outcome: assert an expired resident text raises one owner notice. Control: an approved card raises none.
Oct 11 to 26Western Slopemanymaintenance texts (65)SupervisedWork order ... created / rate the repairexpired unreviewedreview mode by designBY DESIGNshouldSpeak Supervised + bt-e review door: PARTLYAlready frozen: Day 0 tap 8 records the Supervised hold at the maintenance caller. Add a bench episode only for the expiry outcome: assert an expired resident text raises one owner notice. Control: an approved card raises none.
Oct 11 to 26Western Slopemanymaintenance texts (1)SupervisedWork order ... created / rate the repairrejectedreview mode by designBY DESIGNshouldSpeak Supervised + bt-e review door: PARTLYAlready frozen: Day 0 tap 8 records the Supervised hold at the maintenance caller. Add a bench episode only for the expiry outcome: assert an expired resident text raises one owner notice. Control: an approved card raises none.
Oct 11 to 26Western Slopemanymaintenance texts (2)SupervisedWork order ... created / rate the repairstill pendingreview mode by designBY DESIGNshouldSpeak Supervised + bt-e review door: PARTLYAlready frozen: Day 0 tap 8 records the Supervised hold at the maintenance caller. Add a bench episode only for the expiry outcome: assert an expired resident text raises one owner notice. Control: an approved card raises none.
2026-09-01 01:51ZCamellia (JP&Co)Camellia Apartmentsdecision_requestsupervised reviewKurt Schmittgen got in touch. You're all set , tour confirmed for Monday, August 31 at 2:00 PM at Camellia Apartments, 1235 Grant Street.rejectedidentity/matchingFIXED, UNTESTEDaskState verifier + askTheTeam: PARTLYDay 0 fixture: the June call re-graded in Sept; assert no hold when the tour row exists. Control: a real missing tour holds.
2026-09-03 14:16ZCamellia (JP&Co)Camellia Apartmentsdecision_requestsupervised reviewRodulf Parra Fuentes got in touch. ¡Listo, Rodolfo! Le agendo el recorrido para hoy a las cuatro y quince de la tarde.rejectedidentity/matchingFIXED, UNTESTEDaskState verifier + askTheTeam: PARTLYDay 0 fixture: the June call re-graded in Sept; assert no hold when the tour row exists. Control: a real missing tour holds.
2026-09-03 23:24ZCamellia (JP&Co)Camellia Apartmentsdecision_requestsupervised reviewJordan Miller got in touch. You're all set, Jordan! Tour confirmed for tomorrow, Wednesday August 12 at 9:00 AM at Camellia Apartments, 1235 Grant Street, Denverejectedidentity/matchingFIXED, UNTESTEDaskState verifier + askTheTeam: PARTLYDay 0 fixture: the June call re-graded in Sept; assert no hold when the tour row exists. Control: a real missing tour holds.
2026-09-03 23:24ZCamellia (JP&Co)Camellia Apartmentsdecision_requestsupervised reviewJordan Miller got in touch. As for the co-signer/guarantor question, the leasing team will be in touch to confirm that for you.rejectedreview mode by designBY DESIGNaskTheTeam: COVEREDAlready frozen by Day 0 tap 8. No fixture needed.
2026-09-20 23:02ZWestern SlopeNorthridge Apartmentsclara_prospect_emailfirst-email reviewThanks for reaching out about a 2 bed, 2 bath home for you, your girlfriend, and your friend , we have two-bedroom, two-bath units here at Northridge, with rentapproved and sentreview mode by designBY DESIGNshouldSpeak (module Supervised lookup): COVEREDAlready frozen by Day 0 tap 8 (Supervised lookup). No fixture needed.
2026-09-21 16:44ZWestern Slopeappfolio-194clara_prospect_emailfirst-email reviewThe home at 486 32 1/8 Road is a 2 bed, 1 bath, 890 sq ft place renting for $1,250/mo , great fit if you're eyeing an October 1 move-in.approved and sentreview mode by designBY DESIGNshouldSpeak (module Supervised lookup): COVEREDAlready frozen by Day 0 tap 8 (Supervised lookup). No fixture needed.
2026-09-21 17:17ZWestern Slopeappfolio-208clara_prospect_emailfirst-email reviewThe home at 566 Placer Street is no longer available.approved and sentreview mode by designBY DESIGNshouldSpeak (module Supervised lookup): COVEREDAlready frozen by Day 0 tap 8 (Supervised lookup). No fixture needed.
2026-09-22 18:34ZWestern SlopeEmber Estatesclara_prospect_emailfirst-email review2863 Florida Street is open now , a 3 bed, 2 bath home at 1435 sqft, $2,775/mo, and it doesn't take any pets so that's an easy fit for you.rejected, superseded by a recomposed draftwriter quality (prompt rules)FIXED, UNTESTEDTurn rebuilt layer 3/5 + bt-b facts block: PARTLYBench episode (prompt change, shadow per decision 3) on the frozen turn: assert no listing recital, no unbacked claim, one home. Control: a clean prior draft passes.
2026-09-22 18:55ZWestern Slope2841 Morningside Courtclara_prospect_emailfirst-email reviewThanks for your interest in 2841 Morningside Court , it's a spacious 4-bedroom, 2.5-bath single-family home in Orchard Mesa with 1,518 sq. ft., a 2-car garage, rejected, superseded by a recomposed draftwriter quality (prompt rules)FIXED, UNTESTEDTurn rebuilt layer 3/5 + bt-b facts block: PARTLYBench episode (prompt change, shadow per decision 3) on the frozen turn: assert no listing recital, no unbacked claim, one home. Control: a clean prior draft passes.
2026-09-22 19:50ZWestern SlopeEmber Estatesclara_prospect_emailfirst-email reviewThanks so much for reaching out to Ember Estates HZ! We've got a nice range of 3-bedroom, 2-bath homes available right now, generally running $2,300-$2,850/mo aapproved and sentreview mode by designBY DESIGNshouldSpeak (module Supervised lookup): COVEREDAlready frozen by Day 0 tap 8 (Supervised lookup). No fixture needed.
2026-09-22 22:28ZWestern Slopeappfolio-208first emailnone (dropped before hold)Sara (card 2951) and Nathan (card 2952) hit a timing race and Clara quietly dropped both first emailsno reply, no holdsync dropped a messageUNKNOWNbt-c "renter's message is saved when it arrives": NOT ADDRESSEDDay 0 corpus: both cards; tap 12 order: message row written before the first model round; assert one outcome per card (reply or hold, never neither).
2026-09-22 22:53ZWestern Slopeappfolio-208clara_prospect_emailfirst-email reviewThanks for reaching out! The home at 566 Placer Street is no longer available.approved and sentreview mode by designBY DESIGNshouldSpeak (module Supervised lookup): COVEREDAlready frozen by Day 0 tap 8 (Supervised lookup). No fixture needed.
2026-09-22 22:53ZWestern Slopeappfolio-208clara_prospect_emailfirst-email reviewThanks for reaching out! The home at 566 Placer Street is no longer available.approved and sentreview mode by designBY DESIGNshouldSpeak (module Supervised lookup): COVEREDAlready frozen by Day 0 tap 8 (Supervised lookup). No fixture needed.
2026-09-23 17:28ZWestern Slope2841 Morningside Courtclara_prospect_emailfirst-email reviewI found the exact home the address matches: 2841 Morningside Court, Grand Junction, is a 4-bedroom, 2.5-bath single-family home in Orchard Mesa with 1,518 squarrejected, superseded by a recomposed draftwriter quality (prompt rules)FIXED, UNTESTEDTurn rebuilt layer 3/5 + bt-b facts block: PARTLYBench episode (prompt change, shadow per decision 3) on the frozen turn: assert no listing recital, no unbacked claim, one home. Control: a clean prior draft passes.
2026-09-23 18:17ZWestern Slopeappfolio-208clara_prospect_emailfirst-email reviewThanks for reaching out about a tour! The home at 566 Placer Street is no longer available, but we do have a couple of other homes open right now , 2863 Floridarejectedsync dropped a messageFIXED, UNTESTEDbt-c PmsInbox, idempotent writes: NOT ADDRESSEDDay 0 fixture: replay the historical inquiry twice; assert tap 12 adds no new first email for an inquiry older than go-live. Control: a fresh inquiry gets one.
2026-09-23 18:18ZWestern Slopeappfolio-171clara_prospect_emailfirst-email reviewThe home at 2978 Krista Street is no longer available. A couple of options I do have open right now are 2863 Florida Street (3 bed, 2 bath, 1,435 sq ft, $2,775/rejectedsync dropped a messageFIXED, UNTESTEDbt-c PmsInbox, idempotent writes: NOT ADDRESSEDDay 0 fixture: replay the historical inquiry twice; assert tap 12 adds no new first email for an inquiry older than go-live. Control: a fresh inquiry gets one.
2026-09-23 18:36ZWestern Slope2841 Morningside Courtclara_prospect_emailfirst-email reviewThe home at 2841 Morningside Court is a 4 bedroom, 2.5 bath single-family house in Orchard Mesa, 1,518 sq ft, with a 2-car garage and a fenced-in backyard, avairejected, superseded by a recomposed draftwriter quality (prompt rules)FIXED, UNTESTEDTurn rebuilt layer 3/5 + bt-b facts block: PARTLYBench episode (prompt change, shadow per decision 3) on the frozen turn: assert no listing recital, no unbacked claim, one home. Control: a clean prior draft passes.
2026-09-23 18:39ZWestern Slope2841 Morningside Courtclara_prospect_emailfirst-email reviewThanks for reaching out about 2841 Morningside Court , happy to help you and your husband learn more.approved and sentreview mode by designBY DESIGNshouldSpeak (module Supervised lookup): COVEREDAlready frozen by Day 0 tap 8 (Supervised lookup). No fixture needed.
2026-09-23 23:37ZWestern Slope2841 Morningside Courtclara_prospect_emailfirst-email reviewThe home at 2841 Morningside Court is open now.rejected, superseded by a recomposed draftwriter quality (prompt rules)FIXED, UNTESTEDTurn rebuilt layer 3/5 + bt-b facts block: PARTLYBench episode (prompt change, shadow per decision 3) on the frozen turn: assert no listing recital, no unbacked claim, one home. Control: a clean prior draft passes.
2026-09-24 00:57ZWestern Slopeappfolio-406clara_prospect_emailfirst-email reviewI can get you a look at the home at 2863 Florida Street , I have Thursday at 9:00 AM or Friday at 8:00 AM open, which works better for you?approved and sentreview mode by designBY DESIGNshouldSpeak (module Supervised lookup): COVEREDAlready frozen by Day 0 tap 8 (Supervised lookup). No fixture needed.
2026-09-24 01:05ZWestern Slope2841 Morningside Courtclara_prospect_emailfirst-email reviewThe home at 2841 Morningside Court is available now, and it's a great fit for anyone wanting extra space and privacy. I have Thursday at 9:00 AM or Friday at 8:rejected, superseded by a recomposed draftwriter quality (prompt rules)FIXED, UNTESTEDTurn rebuilt layer 3/5 + bt-b facts block: PARTLYBench episode (prompt change, shadow per decision 3) on the frozen turn: assert no listing recital, no unbacked claim, one home. Control: a clean prior draft passes.
2026-09-24 01:05ZWestern SlopeEmber Estatesclara_prospect_emailfirst-email reviewThanks for your interest in 2863 Florida Street , it's a 3 bed, 2 bath home at 1,435 sqft, listed at $2,775/mo.rejected, superseded by a recomposed draftwriter quality (prompt rules)FIXED, UNTESTEDTurn rebuilt layer 3/5 + bt-b facts block: PARTLYBench episode (prompt change, shadow per decision 3) on the frozen turn: assert no listing recital, no unbacked claim, one home. Control: a clean prior draft passes.
2026-09-24 01:05ZWestern Slope2841 Morningside Courtclara_prospect_emailfirst-email reviewThe home at 2841 Morningside Court is open now, and having all four of you along for the tour is no problem , the application works the same whether it's one apapproved and sentreview mode by designBY DESIGNshouldSpeak (module Supervised lookup): COVEREDAlready frozen by Day 0 tap 8 (Supervised lookup). No fixture needed.
2026-09-24 01:13ZWestern SlopeEmber Estatesclara_prospect_emailfirst-email reviewThe home at 2863 Florida Street is a 3 bed, 2 bath, 1435 sqft home listed at $2,775/mo. A 1-month lease term would be a leasing-team decision.rejected, superseded by a recomposed draftwriter quality (prompt rules)FIXED, UNTESTEDTurn rebuilt layer 3/5 + bt-b facts block: PARTLYBench episode (prompt change, shadow per decision 3) on the frozen turn: assert no listing recital, no unbacked claim, one home. Control: a clean prior draft passes.
2026-09-24 01:17ZWestern Slope2841 Morningside Courtclara_prospect_emailfirst-email reviewThe home at 2841 Morningside Court is a 4 bedroom, 2.5 bath single-family home in Orchard Mesa with 1,518 square feet, a 2-car garage, and a fenced-in backyard,approved and sentreview mode by designBY DESIGNshouldSpeak (module Supervised lookup): COVEREDAlready frozen by Day 0 tap 8 (Supervised lookup). No fixture needed.
2026-09-24 01:21ZWestern SlopeEmber Estatesclara_prospect_emailfirst-email reviewThanks for reaching out about 2863 Florida Street , a 1-month lease term would be a leasing-team decision, but I'd love to get you in to see the place.approved and sentreview mode by designBY DESIGNshouldSpeak (module Supervised lookup): COVEREDAlready frozen by Day 0 tap 8 (Supervised lookup). No fixture needed.
2026-09-24 01:47ZWestern SlopePomona Park Townhomesclara_prospect_emailfirst-email reviewUnit 300 at Pomona Park Townhomes is open now, and I'd love to help you find the right fit here. I have Thursday at 9:00 AM or Friday at 8:00 AM for a tour , whexpired unreviewedreview mode by designBY DESIGNshouldSpeak (module Supervised lookup): COVEREDAlready frozen by Day 0 tap 8 (Supervised lookup). No fixture needed.
2026-09-24 14:52ZWestern Slopeappfolio-194clara_prospect_emailsupervised reviewI'll check with the team on that.expired unreviewedreview mode by designBY DESIGNshouldSpeak (module Supervised lookup): COVEREDAlready frozen by Day 0 tap 8 (Supervised lookup). No fixture needed.
2026-09-25 01:29ZWestern Slopeappfolio-400clara_prospect_emailfirst-email reviewThanks for reaching out about Flats on Elm , happy to help you find the right home here. Let me know what size or layout you're looking for, and I can point youapproved and sentreview mode by designBY DESIGNshouldSpeak (module Supervised lookup): COVEREDAlready frozen by Day 0 tap 8 (Supervised lookup). No fixture needed.
2026-09-25 15:12ZWestern Slope2841 Morningside Courtclara_prospect_emailsupervised reviewGood morning, Barbara , sorry to hear your husband isn't feeling well, hope he's back on his feet soon.approved and sentreview mode by designBY DESIGNshouldSpeak (module Supervised lookup): COVEREDAlready frozen by Day 0 tap 8 (Supervised lookup). No fixture needed.
2026-09-25 15:45ZWestern Slope2841 Morningside Courtclara_prospect_emailsupervised reviewYou're all set , your tour is now confirmed for Monday, September 28 at 11:00 AM at 2841 Morningside Court. Glad he'll get some rest today, and we'll see yapproved and sentreview mode by designBY DESIGNshouldSpeak (module Supervised lookup): COVEREDAlready frozen by Day 0 tap 8 (Supervised lookup). No fixture needed.
2026-09-25 20:14ZWestern SlopeNorthridge Apartmentsclara_prospect_emailfirst-email reviewThanks for reaching out about 565 Redcliff Cir , it's currently available for lease, and I'd love to help you find the right fit for an October 9th move-in. Wanapproved and sentreview mode by designBY DESIGNshouldSpeak (module Supervised lookup): COVEREDAlready frozen by Day 0 tap 8 (Supervised lookup). No fixture needed.
2026-10-04 18:07ZWestern SlopePomona Park Townhomesfirst emailfact_trace_untracedCarmen, guest card 2980: first email held by the fact traceno record (card only)provenance gate stripped real factsOPENbt-a "Silent holds" + bt-a row 1: NOT COVEREDDay 0 tap 8 census: every held turn has one hold record with a check name; assert hold row exists. Control: a clean first email writes none.
2026-10-04 22:05ZCamellia (JP&Co)Camellia Apartmentsfirst emailguard-blockedWill, guest card 196: first email held by an outbound safety guardno record (card only)unknownUNKNOWNbt-a "Silent holds": NOT COVEREDPull the Oct 4 turn snapshot into the Day 0 corpus; tap 6 names the guard. Assert one hold record with the guard name.
2026-10-05 07:39ZWestern SlopeNorthridge Apartmentsfirst emailfirst_email_check_failedRobert, guest card 2983: held, then four different first emails went out 10:38 to 10:59Z, each naming another homererun sent four emails in 21 minutesidentity/matchingUNKNOWNbt-c "Rerun duplicates the message" (idempotent writes): NOT ADDRESSEDDay 0 fixture: replay the rerun twice on conversation 0d714ce0; assert tap 12 one outbound first email. Control: a genuinely new renter message adds one.
2026-10-06 19:30ZCamellia (JP&Co)Camellia Apartmentsteam_notice_emailsupervised reviewLorraine Lago in Unit 410 at Camellia Apartments has completed their lease renewal. Their new rent is $1,150/mo on a 12-month term.approved and sentreview mode by designBY DESIGNshouldSpeak (module Supervised lookup): COVEREDAlready frozen by Day 0 tap 8 (Supervised lookup). No fixture needed.
2026-10-06 19:30ZCamellia (JP&Co)Camellia Apartmentsteam_notice_emailsupervised reviewDeb Self in Unit 505 at Camellia Apartments has completed their lease renewal. Their new rent is $1,150/mo on a 12-month term.approved and sentreview mode by designBY DESIGNshouldSpeak (module Supervised lookup): COVEREDAlready frozen by Day 0 tap 8 (Supervised lookup). No fixture needed.
2026-10-07 04:39ZWestern SlopeNorthridge Apartmentsclara_prospect_emailfirst-email review (rerun after first_email_check_failed)Good to hear from you again! The home at 565 Redcliff Cir, unit 585-202 is still available, and it lines up well with your November 1st move-in.expired unreviewedprovenance gate stripped real factsOPENbt-a row 1: checks compare against our records; Turn rebuilt layer 5: PARTLYDay 0 fixture on the #22483 envelope: frozen held draft, assert the draft names the real fact (slot, rent) and passes the check. Positive control: the writer's own first draft passes. XFAIL until #22485.
2026-10-11 23:45ZWestern SlopePomona Park Townhomesmaintenance_resident_smssupervised reviewA plain thread reply on the POMO-6061 card was read as a rejection, so the work-order text never wentrejected by mistakereview mode by designFIXED+TESTEDbt-e review door: PARTLY
2026-10-20 15:00ZWestern Slope2841 Morningside Courtclara_prospect_emailsupervised reviewHey Spencer, I wasn't able to lock in 9:30 on my end , our system needs a bit more notice for same-day changes, so the earliest I could officially book is 10:00expired unreviewedreview mode by designBY DESIGNshouldSpeak (module Supervised lookup): COVEREDAlready frozen by Day 0 tap 8 (Supervised lookup). No fixture needed.
2026-10-21 16:49ZWestern SlopePomona Park Townhomesclara_prospect_emailfirst-email review (rerun after fact_trace_untraced)Thanks for your interest in the 3-bedroom townhome! Just want to flag that Unit 405 runs $2,495/mo, which is above the $1,800/mo budget you mentioned.expired unreviewedprovenance gate stripped real factsOPENbt-a row 1: checks compare against our records; Turn rebuilt layer 5: PARTLYDay 0 fixture on the #22483 envelope: frozen held draft, assert the draft names the real fact (slot, rent) and passes the check. Positive control: the writer's own first draft passes. XFAIL until #22485.
2026-10-23 16:33ZWestern Slope (test lead)Lincoln Apartmentsfirst emailguard-blockedCheryl (TEST APPLICANT): first email held by an outbound safety checktest lead, nothing owedreview mode by designBY DESIGNshouldSpeak: COVERED
2026-10-25 20:18ZWestern Slope2841 Morningside Courtfirst emailfirst_email_check_failedThanks for reaching out about 2841 Morningside Court, it's available now, a 4 bedroom, 2 bath at $2,300/mo.held; staff were emailed 'I couldn't get a clean reply out'; Clara answered his next message 2 min later naming a different home (2980 Emerald Circle)provenance gate stripped real factsREGRESSEDbt-a rows 1-2 (gate, retry never ran) + Recipient-by-cause row 1: PARTLYDay 0 fixture beside first-email-slots (#22483): new tap 'retry attempted', assert yes. Mutation: replant the skip, red. Bench episode for the home switch on the next turn.
2026-10-26 13:44ZSitus GroupDahlia Apartmentsclara_prospect_emailfirst-email reviewThanks for reaching out about Dahlia Apartments. We have a one bedroom, one bath home open now at 731 square feet, running $1,049 per month, and it's pet friendstill pendingreview mode by designBY DESIGNshouldSpeak (module Supervised lookup): COVEREDAlready frozen by Day 0 tap 8 (Supervised lookup). No fixture needed.
2026-10-26 15:17ZWestern SlopeEmber Estatesclara_prospect_emailfirst-email review (rerun after first_email_check_failed)Thanks for reaching out about Ember Estates. We have a 3-bedroom open right now, running $2,775 to $2,795 a month, around 1,289 to 1,435 square feet. I'd love tapproved and sentprovenance gate stripped real factsREGRESSEDbt-a row 1: checks compare against our records; Turn rebuilt layer 5: PARTLYDay 0 fixture on the #22483 envelope: frozen held draft, assert the draft names the real fact (slot, rent) and passes the check. Positive control: the writer's own first draft passes. XFAIL until #22485.
2026-10-26 15:35ZWestern SlopeNorthridge Apartmentsfirst emailfirst_email_check_failedI've sent the application for Northridge Apartments, it'll come from AppFolio in the next few minutes.human replied (Kat by text, 15:38Z); application link had gone outprovenance gate stripped real factsREGRESSEDbt-a "Half a turn" + bt-d staff took thread: NOT ADDRESSEDFixture #22488 is the pattern; add the half-turn assert: hold record lists 'application sent', retry does not resend. Control: no application ask, no hold.
2026-10-26 15:36ZWestern SlopePomona Park Townhomesleasing_outreach_smssupervised reviewHi Jessalyn, it's Clara with Pomona Park Townhomes. I've reached out a few times and want to make sure a tour of our 2-bedroom homes still interests you. If it still pendingmissing fact in promptOPENTurn rebuilt layer 3/5 + bt-b facts block: PARTLYBench episode on the frozen touch-4 text: assert it names only the size the renter asked for (or none). Control: a renter who asked for 2 bedrooms gets 2 bedrooms.

Issues and incidents

26 incidents from the docs pages and memory notes since Sep 1, and 126 GitHub issues (open, plus closed since Sep 1) that touch a customer path. CI and harness issues were dropped. Customer and root cause on issues come from keyword rules on the title; treat them as rough. "Unit-only" means a merged fix with unit tests and no replay, harness or bench case.

KindIdDateCustomerWhat brokeFix PRsCaseRoot causeVerdictDesignHarness view
incidentcamellia-shared-routing-revert-2026-09-072026-09-07Camellia (JP&Co)A shared prompt change took call routing from 39/40 to 0/20 on the bench; reverted in 13 minutes, no real callers hit.#7260 merged, #7263 mergedunit-test-onlyother code bugFIXED, UNTESTEDoutside the turn (phone routing): NOT ADDRESSEDNot a turn case: keep as an ops runbook check, not a fixture.
incidentappfolio-robot-login-lockout-2026-09-102026-09-10internal (all three AppFolio accounts)The browser robot that writes into AppFolio could not sign in at JP&Co, Situs and Western Slope for about a day; no customer-facing write was lost.#7794 merged, #7796 merged, #7797 mergedunit-test-onlyother code bugFIXED, UNTESTEDPmsInbox adapter: NOT ADDRESSEDDay 0 fixture: replay the same record twice; assert tap 12 row count unchanged. Control: a new record adds one.
incidentaws-config-cost-2026-09-132026-09-13internalTurning on self-hosted CI runners made AWS Config write ~120,000 billable records a day, and every spend alarm was blind to it; a DynamoDB write storm from the AppFolio sync was found in the same swee#9063 merged, #9134 merged, #9144 merged, #9145 merged, #9146 merged, #9479 merged, #9480 merged, #9482 mergedunit-test-onlyother code bugFIXED, UNTESTEDoutside the design (infra): NOT ADDRESSEDNot a turn case: keep as an ops runbook check, not a fixture.
incidentvoice-outage-2026-09-162026-09-16internal (all customers on the shared line; Camellia and Western Slope callers hit)A maintenance call-center forwarding change sent an empty value the voice platform rejects, killing every inbound call on the shared line and Willows; 19 failed calls.#8882 merged, #8923 merged, #8934 mergedunit-test-onlyother code bugFIXED, UNTESTEDoutside the turn (voice infra): NOT ADDRESSEDNot a turn case: keep as an ops runbook check, not a fixture.
incidentws-reminder-email-flood-2026-09-162026-09-16Western SlopeSetting Western Slope's leasing inbox as the team-notice address also armed an hourly reminder nobody meant to turn on, sending about 100 emails.#8926 closed, #8962 merged, #9264 mergedunit-test-onlyother code bugFIXED, UNTESTEDRecipient by cause (who hears): PARTLYDay 0 tap 8 census: assert the failure reaches #alerts and the record only, never staff. Control: a real hand-off notifies once.
incidentethan-ws-three-day-misses-2026-09-212026-09-19Western SlopeEthan's email reply was never answered, the follow-up texts kept running and invited him to tour a home Clara had said was rented, his text opened a new unlinked thread, and Clara quoted a comput#10535 merged, #10538 merged, #10544 merged, #10545 mergedreplay/harnessidentity/matchingOPENidentity layer + bt-c every message is a turn: PARTLYDay 0 fixture from the real conversation: assert tap 1 resolves the right person and home. Control: an unambiguous sender resolves as today.
incidentwillows-test-mailbox-locked-2026-09-212026-09-21internalNightly stress tests drove one consumer Outlook mailbox hard enough that Microsoft locked it for suspected abuse.#13827 merged, #13882 merged, #15602 mergednoneother code bugFIXED, UNTESTEDoutside the design (test infra): NOT ADDRESSEDNot a turn case: keep as an ops runbook check, not a fixture.
incidentws-transfer-loop-2026-09-222026-09-22Western SlopeClara transferred callers to Western Slope's main line, which forwards to Clara, so callers looped and were dropped.#10795 mergedreplay/harnessother code bugREGRESSEDaskTheTeam (hand-off to people, not numbers): PARTLYBench episode (voice, Day 0 has no voice in v1): assert no transfer goes to a number that rings Clara. Control: a person transfer connects.
incidentws-lead-outbox-claim-race-2026-09-232026-09-23Western SlopeLosing a concurrent-delivery claim counted as a failed attempt, so card 2840's lead parked after 5 tries and never got a first email.#13411 mergedunit-test-onlysync dropped a messageFIXED, UNTESTEDbt-c idempotent writes: NOT ADDRESSEDDay 0 fixture: replay the same record twice; assert tap 12 row count unchanged. Control: a new record adds one.
incidentcamellia-joanna-screening-2026-09-242026-09-24Camellia (JP&Co)The Sep 23-24 caller-ID passthrough made Clara's hand-offs ring Joanna's cell as an unknown number, which her phone screened; 8 transfers screened over ~14 days with no alert.#11075 merged, #11100 merged, #18008 merged, #18016 merged, #21668 mergedreplay/harnessother code bugFIXED+TESTEDaskTheTeam: PARTLY
incidentws-home-match-from-calls-2026-09-252026-09-25Western SlopeThe home matcher found several candidate homes and by design picked none, the card writer only reads a single picked home, so no card was filed and the alert for it had been removed.#10755 merged, #10903 merged, #11361 mergednoneidentity/matchingOPENidentity layer: PARTLYDay 0 fixture from the real conversation: assert tap 1 resolves the right person and home. Control: an unambiguous sender resolves as today.
incidentws-cancel-tour-cross-property-2026-09-282026-09-28Western SlopeThe text thread sat under Ember Estates and the tour under the same house's own property id, so cancel_tour found "no upcoming tour" and the tour and a follow-up text sequence stayed ar#13286 merged, #13288 mergedunit-test-onlyidentity/matchingFIXED, UNTESTEDidentity layer (what turn is this): PARTLYDay 0 fixture from the real conversation: assert tap 1 resolves the right person and home. Control: an unambiguous sender resolves as today.
incidentws-first-email-compose-timeout-2026-09-282026-09-28Western SlopeClara's first-email compose ran inside a 60 s cron, was killed mid-compose, and the stale claim was then finished as "held, reply by hand" with no retry (card 2968).#13333 merged, #13625 mergedunit-test-onlyother code bugFIXED, UNTESTEDRecipient by cause, engineering-error row: COVEREDDay 0 tap 8 census: assert the failure reaches #alerts and the record only, never staff. Control: a real hand-off notifies once.
incidentws-error-email-to-client-2026-09-282026-09-28Western SlopeThe held-first-email notice sent Clara's own failures to the customer's team inbox ("nothing sent, please reply directly").#13343 mergedunit-test-onlyother code bugFIXED, UNTESTEDRecipient by cause, engineering-error row: COVEREDDay 0 tap 8 census: assert the failure reaches #alerts and the record only, never staff. Control: a real hand-off notifies once.
incidentguest-card-created-by-unknown-2026-09-282026-09-28Western Slope + Camellia (JP&Co)A failed or skipped "who created this card" read was stored once and every retry trusted it, so cards 2955/2966/2968 (WS) and 152/158 (JP&Co) were never assigned to Clara.#13314 merged, #13598 mergedreplay/harnesssync dropped a messageFIXED+TESTEDPmsInbox adapter: PARTLY
incidentws-promise-misattributed-2026-09-282026-09-28Western SlopeAfter Clara transferred a resident to the maintenance call center, the promise scanner read the human agent's words as Clara's and emailed Western Slope a first-person note signed Clara.#13422 merged, #13801 mergedunit-test-onlyother code bugFIXED, UNTESTEDaskState (is it with the team?): PARTLYDay 0 fixture on the real turn; assert the shown failure is gone. Positive control from the same corpus.
incidentmac-mini-disk-2026-09-282026-09-28internalAbout 175 repo checkouts (mostly open-PR worktrees no reaper touches) filled the 460 GB drive despite five cleanup rounds.noneother code bugOPENoutside the design (infra): NOT ADDRESSEDNot a turn case: keep as an ops runbook check, not a fixture.
incidentember-two-lists-2026-09-292026-09-29Western SlopeAppFolio keeps a clean listings list and a messy unit list; Clara read one or the other depending on how the question was phrased (4 homes vs 26 "vacant"), and filed tours under the communit#13837 mergedbenchwrong fact in KBREGRESSEDbt-b facts block, one home per fact: PARTLYBench episode on the frozen first reply: assert one home, its own numbers, no counts. Control: single open home quotes its own numbers.
incidentcamellia-nobody-to-connect-2026-09-292026-09-29Camellia (JP&Co)The Western Slope routing chain that went live Sep 25 removed Camellia's person destination, so 7 of 11 person-asks got "nobody can pick up" for ~7.5 days.#21671 mergedreplay/harnessother code bugFIXED+TESTEDaskTheTeam: PARTLY
incidentsame-day-tour-offers-2026-10-092026-10-09Western Slope + Camellia (JP&Co)Code and prompt both started the slot search at tomorrow when no day was named, so 48 of 48 first replies skipped today (two WS prospects offered Saturday only on a wide-open Friday).#18279 merged, #18280 merged, #18268 merged, #18270 merged, #18275 merged, #18297 merged, #18285 merged, #18290 mergedreplay/harnessmissing fact in promptFIXED+TESTEDTurn rebuilt layer 5 (tour windows as facts): COVERED
incidentcamellia-transfer-loop-2026-10-132026-10-13Camellia (JP&Co)With caller-ID passthrough, a transfer to Camellia's main line looked like an outside call and JP&Co's forward sent it straight back to Clara; applicant Victoria asked for a person four #21636 merged, #21668 merged, #21670 merged, #21671 merged, #21682 merged, #21705 mergedreplay/harnessother code bugFIXED+TESTEDaskTheTeam: PARTLY
incidentlincoln-leak-call-2026-10-182026-10-18Western SlopeThe phone lookup never read a unit's own street address so a leaking-disposal call got no emergency page, and Jay's reply from the shared leasing mailbox matched a placeholder "JOHN M. #20946 merged, #20949 mergedunit-test-onlyidentity/matchingFIXED, UNTESTEDidentity layer: PARTLYDay 0 fixture from the real conversation: assert tap 1 resolves the right person and home. Control: an unambiguous sender resolves as today.
incidentember-first-reply-overshare-2026-10-222026-10-22Western SlopeAfter a 120 s engine timeout, a rewrite step blind to the main rules emailed Ronald units 361/363/364 plus "opening Nov 2"; earlier emails said "27 3-bedrooms open now" from a roll#21806 merged, #21814 merged, #21815 merged, #21808 merged, #21830 merged, #21885 merged, #21930 merged, #21886 mergedreplay/harnessother code bugFIXED+TESTEDTurn rebuilt layer 5 ("one home, no counts"): COVERED
incidentsitus-first-reply-findings-2026-10-222026-10-22Situs GroupOn 119 real Situs inquiries Clara re-asked a size the lead had given (13/30) and handled "asked home is gone" wrong (5/8), and 6 leads were told "no 1-bedrooms open" with five on t#22061 merged, #22071 closedreplay/harnessmissing fact in promptOPENbt-b facts block: PARTLYBench episode on the frozen first reply: assert one home, its own numbers, no counts. Control: single open home quotes its own numbers.
incidentws-former-tenant-reply-2026-10-232026-10-23Western SlopeA Pomona Park former tenant's text woke Clara because one unrelated prospect on the same number made the thread a "prospect" thread; Clara replied from her Twilio line, emailed the team#22058 mergedunit-test-onlyidentity/matchingOPENshouldSpeak (unknown sender lookup) + identity: PARTLYDay 0 fixture from the real conversation: assert tap 1 resolves the right person and home. Control: an unambiguous sender resolves as today.
incidentbench-door-tour-alert-flood-2026-10-242026-10-24Western Slope (internal cause)A Clara Bench ids-only loop against the production bench door read tour availability; the read-only guard refused the alert dedupe write, the dedupe read that as an outage and failed open, and every c#22324 merged, #22327 merged, #22329 mergedreplay/harnessother code bugFIXED+TESTEDRecipient by cause (who hears): COVERED
issue#123992026-09-25unknownLeasing desk: staff-booking SMS confirmation fans out to household parties without their own consent#13313 merged, #13535 mergedreplay/harnessidentity/matchingFIXED+TESTEDbt-e review door (one hold record, option B) (keyword, not read): NOT ADDRESSED
issue#134132026-09-28Western SlopePromise scanner attributes a transferred-to human agent's promise to Clara and emails the client a first-person 'Clara told the caller…' notice (WS, Kayla Masukawa, 2026-09-28)#13422 merged, #13801 mergedreplay/harnessother code bugFIXED+TESTEDpage silent (keyword, not read): NOT ADDRESSED
livetour 9dc6f8eb2026-10-26Western SlopeLori Ruiz, Pomona Park tour 4:30 PM: hour-before text refused by the AppFolio text door (party not in thread; AppFolio shows her as Unknown Number), fallback email asked for a phone we hold, her 4:14 PM "where do we meet you?" reached only the no-reply notification mailbox; showing never written (tour has no unit, 49 tries)conv 99e5e0f8 / bdaed90aRoot cause (Oct 26 night): our robot created the card with the phone stored as "(970) ***-****" (machine format, sent verbatim); staff corrected it to "(970) ***-****" Mon 2:58 PM, AppFolio read that as a foreign code and unlinked the texting thread 32 min before the reminder. Her text then arrived as an unknown number; our mirror received it with the right phone but left it pending (no_match: the matching rule needs a name to agree). Fixes: write phones to AppFolio in its own display format at create and fill; file an unknown-number text whose phone belongs to one person; stop ingesting AppFolio no-reply notification emails as conversations Oct 27: Fede: one root cause, one fix; robot PR appfolio-browser-agent#633 (display format at create and fill) merged and proven at Willows (card 49 written as (404) 285-9387, read back, restored, Oct 27 02:12Z); no-reply notifications fix #22616 open and armed (30-day replay: 5 records would be dropped, all notifications, 0 real people); Willows proof after deploy; unknown-number filing #22612 and Outlook bounce #22613 filed, not built.ROOT CAUSE FOUNDslice KFede corrected the phone on the card Oct 26 night
issue#133632026-09-28Western SlopeEngine first email: AppFolio unit label ("Unit 313") leaks into prose for a single-family home, and deposit is hedged "typically one month's rent"#13471 merged, #13568 merged, #17375 mergedreplay/harnesssync dropped a messageFIXED+TESTEDPmsInbox adapter, bt-c idempotent writes (keyword, not read): NOT ADDRESSED
issue#130092026-09-28unknownRenewals review: Clara's text replies to residents are not held while the company review switch is on#13629 merged, #13682 merged, #13690 merged, #13704 mergedreplay/harnesshold handling (review door)FIXED+TESTEDbt-e review door (one hold record, option B) (keyword, not read): NOT ADDRESSED
issue#135412026-09-29test/internalRetire clara-guest-card-first-email-compose.ts (the composer) for guest-card first email#13519 mergedreplay/harnessother code bugFIXED+TESTEDpage silent (keyword, not read): NOT ADDRESSED
issue#139002026-09-29Camellia (JP&Co)First-email reply held by the content check: draft named no home and asked for no tour while homes were open (Willows proof 2026-09-29 21:42Z)#13908 mergedreplay/harnessprovenance gate stripped real factsFIXED+TESTEDbt-a row 1 (checks compare against our records) (keyword, not read): PARTLY
issue#139892026-09-30Western Sloperecord_tour_notes can't save a reply to the check-in Clara just sent (matter saved without inquiryId)#14004 merged, #14005 merged, #14063 mergedreplay/harnessprovenance gate stripped real factsFIXED+TESTEDbt-a row 1 (checks compare against our records) (keyword, not read): PARTLY
issue#139912026-09-30Western SlopeStaff desk: confirmation texts read the whole note back and add an 'or is that already set up outside this system?' re-ask#14004 merged, #14005 merged, #14063 mergedreplay/harnesstours and staff-desk logicFIXED+TESTEDpage silent (keyword, not read): NOT ADDRESSED
issue#139902026-09-30Western Slopebook_showing_for re-asks staff for what the data knows: single-unit home rejected, second address not resolved#14005 merged, #14020 merged, #14031 mergedreplay/harnesshold handling (review door)FIXED+TESTEDpage silent (keyword, not read): NOT ADDRESSED
issue#184652026-10-10test/internalvoice maintenance: water dripping through the ceiling near a light fixture was filed without escalate_to_human (the post-call sweep paged anyway)#19137 merged, #19368 mergedreplay/harnessother code bugFIXED+TESTEDpage silent (keyword, not read): NOT ADDRESSED
issue#190772026-10-12Camellia (JP&Co)Available-units list shows past vacancy dates as future hold dates#19122 merged, #19109 merged, #19111 merged, #19138 mergedreplay/harnesshold handling (review door)FIXED+TESTEDbt-e review door (one hold record, option B) (keyword, not read): NOT ADDRESSED
issue#193142026-10-13unknownTour hold: a failed calendar read is reported as 'slot no longer open'#19309 mergedreplay/harnesshold handling (review door)FIXED+TESTEDbt-e review door (one hold record, option B) (keyword, not read): NOT ADDRESSED
issue#193152026-10-13Western SlopeNo-tour-without-a-name: SMS real-path E2E right after deploy (hold → name → confirm)#19309 mergedreplay/harnesshold handling (review door)FIXED+TESTEDbt-e review door (one hold record, option B) (keyword, not read): NOT ADDRESSED
issue#209662026-10-19unknownstaff desk: a first name matches a stranger whose display name is an email, and the booking goes on that person#21008 merged, #20978 merged, #21012 mergedreplay/harnesstours and staff-desk logicFIXED+TESTEDbt-b facts block (keyword, not read): PARTLY
issue#209802026-10-19Western Slopeeval(real-turns): scripted desk world cannot reproduce 4 adversary defects (unit-needed refusal, reschedule confirm, list_units, homes/knowledge keys)#21012 mergedreplay/harnessother code bugFIXED+TESTEDpage silent (keyword, not read): NOT ADDRESSED
issue#209672026-10-19unknownstaff desk: a card note for a named home lands on another home's open check-in tour#21041 merged, #20978 merged, #21012 merged, #21051 mergedreplay/harnessprovenance gate stripped real factsFIXED+TESTEDbt-a row 1 (checks compare against our records) (keyword, not read): PARTLY
issue#209682026-10-19unknownstaff desk: lockbox texts with no code (a question, a moved lockbox) are sent to the code tool and Clara asks staff for a code#21020 merged, #20978 merged, #21012 mergedreplay/harnesstours and staff-desk logicFIXED+TESTEDpage silent (keyword, not read): NOT ADDRESSED
issue#209692026-10-19unknownstaff desk: a multi-unit home with no unit given loops on 'which unit', or Clara picks a unit herself and books it as taken#21047 merged, #20978 merged, #21012 merged, #21060 mergedreplay/harnesstours and staff-desk logicFIXED+TESTEDpage silent (keyword, not read): NOT ADDRESSED
issue#209702026-10-19unknownstaff desk: 'put her back to the original time' is refused once for missing time words, though Clara read the original time#21059 merged, #20978 merged, #21012 merged, #20798 mergedreplay/harnesstours and staff-desk logicFIXED+TESTEDpage silent (keyword, not read): NOT ADDRESSED
issue#216252026-10-21unknownSupervised hold bypassed when the topic classifier labels a renewal-tool turn "other"#21646 merged, #22334 mergedreplay/harnesshold handling (review door)FIXED+TESTEDbt-e review door (one hold record, option B) (keyword, not read): NOT ADDRESSED
issue#121772026-09-25unknownTwo inactive guest cards of one person still trade the pointer every tick (#12141 review)#12182 mergedunit-test-onlyidentity/matchingFIXED, UNTESTEDbt-e review door (one hold record, option B) (keyword, not read): NOT ADDRESSEDDay 0 tap 10 render cell on the hold: assert one card shape, four actions, no default mentions. Then a production screenshot.
issue#124502026-09-26unknownFirst email: a stuck-prep takeover should cancel the tour the dead engine turn booked#13625 merged, #17318 mergedunit-test-onlytours and staff-desk logicFIXED, UNTESTEDpage silent (keyword, not read): NOT ADDRESSEDDay 0 fixture on the real record; assert the reported failure is gone. Positive control from the same corpus.
issue#133952026-09-28Western SlopeLead outbox: a consumer that loses the concurrent-delivery claim parks the lead after 5 attempts instead of re-queueing (WS 2840 Jolynn never got a first email)#13411 merged, #13448 closed, #18757 merged, #21057 mergedunit-test-onlyother code bugFIXED, UNTESTEDpage silent (keyword, not read): NOT ADDRESSEDDay 0 fixture on the real record; assert the reported failure is gone. Positive control from the same corpus.
issue#136592026-09-29unknownEmail-lead engine reply (#13658) sends via sendClaraProspectEmail, not the held first-email pipeline#13658 merged, #13711 merged, #13714 mergedunit-test-onlyhold handling (review door)FIXED, UNTESTEDbt-e review door (one hold record, option B) (keyword, not read): NOT ADDRESSEDDay 0 tap 10 render cell on the hold: assert one card shape, four actions, no default mentions. Then a production screenshot.
issue#146812026-10-01unknownMerge hold: claude.yml's @claude re-review posts review=success without the hold gate (must land before deleting auto-merge-all)#14688 merged, #14689 closed, #14700 mergedunit-test-onlyhold handling (review door)FIXED, UNTESTEDbt-e review door (one hold record, option B) (keyword, not read): NOT ADDRESSEDDay 0 tap 10 render cell on the hold: assert one card shape, four actions, no default mentions. Then a production screenshot.
issue#146422026-10-01unknownheavy lane: closed culprit issues are not matched, so a reopened red files a duplicate#17447 merged, #17446 mergedunit-test-onlyidentity/matchingFIXED, UNTESTEDpage silent (keyword, not read): NOT ADDRESSEDDay 0 fixture on the real record; assert the reported failure is gone. Positive control from the same corpus.
issue#152472026-10-02unknownRobot/fastlane/rig test callers unrecognized by isTestSender , real AppFolio guest card created (card 2963, 2939/2940)#15248 mergedunit-test-onlyidentity/matchingFIXED, UNTESTEDidentity layer / PmsInbox (keyword, not read): PARTLYDay 0 fixture from the real card: assert tap 1 resolves the right person and card. Control: a clean sender resolves as today.
issue#155612026-10-02test/internalFlaky test: src/__tests__/sync-renewal-voice-prompt.test.ts#17595 mergedunit-test-onlysync dropped a messageFIXED, UNTESTEDPmsInbox adapter, bt-c idempotent writes (keyword, not read): NOT ADDRESSEDDay 0 fixture: replay the record twice and after a parked write; assert tap 12 rows and one retry. Control: a new record adds one.
issue#159622026-10-03unknownHeld-text approve re-run drops the staffAsked flag, so the staff-requested application text never goes#16054 merged, #15983 mergedunit-test-onlyhold handling (review door)FIXED, UNTESTEDbt-e review door (one hold record, option B) (keyword, not read): NOT ADDRESSEDDay 0 tap 10 render cell on the hold: assert one card shape, four actions, no default mentions. Then a production screenshot.
issue#163372026-10-04unknownteam-notify SMS quote: focusClause drops a statement that holds the antecedent#16343 merged, #16329 mergedunit-test-onlyhold handling (review door)FIXED, UNTESTEDbt-e review door (one hold record, option B) (keyword, not read): NOT ADDRESSEDDay 0 tap 10 render cell on the hold: assert one card shape, four actions, no default mentions. Then a production screenshot.
issue#169122026-10-06unknowntours: booking pick falls back to any-free-agent when the tour grid read fails (#16891 follow-up)#16923 mergedunit-test-onlytours and staff-desk logicFIXED, UNTESTEDpage silent (keyword, not read): NOT ADDRESSEDDay 0 fixture on the real record; assert the reported failure is gone. Positive control from the same corpus.
issue#169272026-10-06unknownvideo Clara: a silent turn is saved as a visible '<silent>' Clara message (from #16901 review)#16948 merged, #17016 mergedunit-test-onlyhold handling (review door)FIXED, UNTESTEDRecipient by cause + bt-a "Silent holds" (keyword, not read): NOT COVEREDDay 0 tap 8 census cell: every held or failed turn has exactly one hold record with a check name plus an #alerts line. Mutation: drop the record write, red.
issue#173512026-10-07Western SlopeA first reply held by a draft check is never re-drafted and only our own inbox is told#17408 merged, #22060 mergedunit-test-onlyprovenance gate stripped real factsFIXED, UNTESTEDbt-a row 1 (checks compare against our records) (keyword, not read): PARTLYDay 0 fixture on the #22483 envelope: frozen draft, assert the check passes the real fact. Control: the writer's first draft passes.
issue#177482026-10-08Western SlopeA main-line booking's guest card never gets created: the create still names the front-door placeholder#17753 mergednoneidentity/matchingFIXED, UNTESTEDbt-e review door (one hold record, option B) (keyword, not read): NOT ADDRESSEDDay 0 tap 10 render cell on the hold: assert one card shape, four actions, no default mentions. Then a production screenshot.
issue#177492026-10-08Western SlopeA note waiting on a guest card never sends after the card is created#17753 mergednoneidentity/matchingFIXED, UNTESTEDidentity layer / PmsInbox (keyword, not read): PARTLYDay 0 fixture from the real card: assert tap 1 resolves the right person and card. Control: a clean sender resolves as today.
issue#183352026-10-09Western SlopeTenant calls and texts bump their old, converted guest card to the top of Prospects#18343 merged, #18384 merged, #21631 mergedunit-test-onlyidentity/matchingFIXED, UNTESTEDidentity layer / PmsInbox (keyword, not read): PARTLYDay 0 fixture from the real card: assert tap 1 resolves the right person and card. Control: a clean sender resolves as today.
issue#185262026-10-10unknownOffice-notice hold: fallback timer stops on in_flight and gives up after 30 s (lease is 3 min)#19112 mergedunit-test-onlyidentity/matchingFIXED, UNTESTEDbt-e review door (one hold record, option B) (keyword, not read): NOT ADDRESSEDDay 0 tap 10 render cell on the hold: assert one card shape, four actions, no default mentions. Then a production screenshot.
issue#185732026-10-10unknownRenewal text with no outbound line fails silently as dispatched_failed#19304 merged, #19080 merged, #19300 mergedunit-test-onlyother code bugFIXED, UNTESTEDRecipient by cause + bt-a "Silent holds" (keyword, not read): NOT COVEREDDay 0 tap 8 census cell: every held or failed turn has exactly one hold record with a check name plus an #alerts line. Mutation: drop the record write, red.
issue#191012026-10-12test/internalHeld-item follow-up posts for test/sandbox companies still reach #alerts (withdraw/expire paths)#19142 mergednonehold handling (review door)FIXED, UNTESTEDbt-e review door (one hold record, option B) (keyword, not read): NOT ADDRESSEDDay 0 tap 10 render cell on the hold: assert one card shape, four actions, no default mentions. Then a production screenshot.
issue#192112026-10-13unknownpms-mirror: handler-level controls for the mirrored wake/hold/unreadable wiring (#19161 follow-up)#19222 mergedunit-test-onlysync dropped a messageFIXED, UNTESTEDbt-e review door (one hold record, option B) (keyword, not read): NOT ADDRESSEDDay 0 tap 10 render cell on the hold: assert one card shape, four actions, no default mentions. Then a production screenshot.
issue#193242026-10-13Western SlopeText and email tour bookings never request an AppFolio guest card and stay filed on the company main line#19325 mergednoneidentity/matchingFIXED, UNTESTEDidentity layer / PmsInbox (keyword, not read): PARTLYDay 0 fixture from the real card: assert tap 1 resolves the right person and card. Control: a clean sender resolves as today.
issue#193262026-10-13test/internalPMS mirror: hold, don't drop, an inbox thread whose party has no property#19338 merged, #19349 closed, #19374 mergedunit-test-onlysync dropped a messageFIXED, UNTESTEDbt-e review door (one hold record, option B) (keyword, not read): NOT ADDRESSEDDay 0 tap 10 render cell on the hold: assert one card shape, four actions, no default mentions. Then a production screenshot.
issue#194052026-10-14unknownpms-mirror: a cold AppFolio session pauses the inbox watch silently (no alert)#19410 merged, #19485 merged, #19668 merged, #20072 mergedunit-test-onlysync dropped a messageFIXED, UNTESTEDRecipient by cause + bt-a "Silent holds" (keyword, not read): NOT COVEREDDay 0 tap 8 census cell: every held or failed turn has exactly one hold record with a check name plus an #alerts line. Mutation: drop the record write, red.
issue#194942026-10-14unknownRenewals Supervised: guard blocks a correct reply that repeats the tenant's own rent/term ask; held draft becomes "I've noted your request on your renewal." (X-35)#19498 mergedunit-test-onlyprovenance gate stripped real factsFIXED, UNTESTEDbt-a row 1 (checks compare against our records) (keyword, not read): PARTLYDay 0 fixture on the #22483 envelope: frozen draft, assert the check passes the real fact. Control: the writer's first draft passes.
issue#195732026-10-14unknownShowing write with no home: delete the 'please add it in AppFolio' staff email, hold-and-retry instead of parking#19579 merged, #19645 merged, #19750 merged, #19794 mergedunit-test-onlysync dropped a messageFIXED, UNTESTEDbt-e review door (one hold record, option B) (keyword, not read): NOT ADDRESSEDDay 0 tap 10 render cell on the hold: assert one card shape, four actions, no default mentions. Then a production screenshot.
issue#195952026-10-14unknownpms-mirror: on a one-company AppFolio database, a row with no property is held instead of going to that company's front door#19602 merged, #19605 mergedunit-test-onlysync dropped a messageFIXED, UNTESTEDbt-e review door (one hold record, option B) (keyword, not read): NOT ADDRESSEDDay 0 tap 10 render cell on the hold: assert one card shape, four actions, no default mentions. Then a production screenshot.
issue#195962026-10-14unknownPMS mirror: AppFolio inbox adapter drops the main party, holding tenant texts as no_property#19605 mergedunit-test-onlysync dropped a messageFIXED, UNTESTEDbt-e review door (one hold record, option B) (keyword, not read): NOT ADDRESSEDDay 0 tap 10 render cell on the hold: assert one card shape, four actions, no default mentions. Then a production screenshot.
issue#196352026-10-14test/internalPMS mirror: a guest-card prospect's text is held no_property on a two-company database#19662 merged, #19668 mergedunit-test-onlysync dropped a messageFIXED, UNTESTEDbt-e review door (one hold record, option B) (keyword, not read): NOT ADDRESSEDDay 0 tap 10 render cell on the hold: assert one card shape, four actions, no default mentions. Then a production screenshot.
issue#196362026-10-14test/internalPMS mirror: unresolvable holds are silent (no engineering alert)#19668 mergedunit-test-onlysync dropped a messageFIXED, UNTESTEDRecipient by cause + bt-a "Silent holds" (keyword, not read): NOT COVEREDDay 0 tap 8 census cell: every held or failed turn has exactly one hold record with a check name plus an #alerts line. Mutation: drop the record write, red.
issue#196102026-10-14unknownpms-mirror: #19602 and #19605 disagree on unknown_phone_number, so unknown-number texts stay held on a one-company database#19900 mergedunit-test-onlysync dropped a messageFIXED, UNTESTEDbt-e review door (one hold record, option B) (keyword, not read): NOT ADDRESSEDDay 0 tap 10 render cell on the hold: assert one card shape, four actions, no default mentions. Then a production screenshot.
issue#197132026-10-14test/internalguest-card sync: an INACTIVE card still rewrites the linked person's name (Willows battle test, card 216)#19901 mergedunit-test-onlysync dropped a messageFIXED, UNTESTEDPmsInbox adapter, bt-c idempotent writes (keyword, not read): NOT ADDRESSEDDay 0 fixture: replay the record twice and after a parked write; assert tap 12 rows and one retry. Control: a new record adds one.
issue#198472026-10-15unknownApproved list row joins a still-running offer job and sends nothing, silently#19861 mergedunit-test-onlyhold handling (review door)FIXED, UNTESTEDRecipient by cause + bt-a "Silent holds" (keyword, not read): NOT COVEREDDay 0 tap 8 census cell: every held or failed turn has exactly one hold record with a check name plus an #alerts line. Mutation: drop the record write, red.
issue#202022026-10-16Western Slopepms-mirror: unmatched prospect email filed into a new conversation on the placeholder property#20210 mergedunit-test-onlyidentity/matchingFIXED, UNTESTEDbt-e review door (one hold record, option B) (keyword, not read): NOT ADDRESSEDDay 0 tap 10 render cell on the hold: assert one card shape, four actions, no default mentions. Then a production screenshot.
issue#203712026-10-16test/internaltext door: staff and vendor texts are held with no_pms_thread when the AppFolio door is on , they must always use Clara's line#20384 merged, #20982 mergedunit-test-onlysync dropped a messageFIXED, UNTESTEDbt-e review door (one hold record, option B) (keyword, not read): NOT ADDRESSEDDay 0 tap 10 render cell on the hold: assert one card shape, four actions, no default mentions. Then a production screenshot.
issue#203852026-10-16test/internaltext door: two manager replies (confirmation-review and mass-message confirm) are not marked as going to staff, so they would be held when the AppFolio door is on#20410 mergedunit-test-onlysync dropped a messageFIXED, UNTESTEDbt-e review door (one hold record, option B) (keyword, not read): NOT ADDRESSEDDay 0 tap 10 render cell on the hold: assert one card shape, four actions, no default mentions. Then a production screenshot.
issue#206872026-10-17unknownFair-housing gate passes voucher-holder screening on full rent and credit score#20695 mergedunit-test-onlyhold handling (review door)FIXED, UNTESTEDbt-e review door (one hold record, option B) (keyword, not read): NOT ADDRESSEDDay 0 tap 10 render cell on the hold: assert one card shape, four actions, no default mentions. Then a production screenshot.
issue#213372026-10-20unknownA company list reviewer can approve a per-offer Supervised renewal hold from the admin page#21341 merged, #21430 mergedunit-test-onlyhold handling (review door)FIXED, UNTESTEDbt-e review door (one hold record, option B) (keyword, not read): NOT ADDRESSEDDay 0 tap 10 render cell on the hold: assert one card shape, four actions, no default mentions. Then a production screenshot.
issue#213662026-10-20test/internallead.received terminalState says 'replied' when the first email was held compose-failed#21371 merged, #21614 mergedunit-test-onlymissing fact in promptFIXED, UNTESTEDbt-e review door (one hold record, option B) (keyword, not read): NOT ADDRESSEDDay 0 tap 10 render cell on the hold: assert one card shape, four actions, no default mentions. Then a production screenshot.
issue#213622026-10-20unknownOffice 'not renewing' email is held under Supervised and never composed after a 24h expiry; a staff note should always go out#21426 mergedunit-test-onlyhold handling (review door)FIXED, UNTESTEDbt-e review door (one hold record, option B) (keyword, not read): NOT ADDRESSEDDay 0 tap 10 render cell on the hold: assert one card shape, four actions, no default mentions. Then a production screenshot.
issue#213602026-10-20unknownPer-offer renewal hold: can a customer company admin approve on the admin page, or only the Slack card / PropFlow admin?#21430 mergedunit-test-onlyhold handling (review door)FIXED, UNTESTEDbt-e review door (one hold record, option B) (keyword, not read): NOT ADDRESSEDDay 0 tap 10 render cell on the hold: assert one card shape, four actions, no default mentions. Then a production screenshot.
issue#213652026-10-20test/internalA new lead whose first email fails to compose 3 times is held for good: no later retry, no draft to release, lead stays silent#21446 mergedunit-test-onlyhold handling (review door)FIXED, UNTESTEDRecipient by cause + bt-a "Silent holds" (keyword, not read): NOT COVEREDDay 0 tap 8 census cell: every held or failed turn has exactly one hold record with a check name plus an #alerts line. Mutation: drop the record write, red.
issue#215042026-10-20test/internalApproved held reply that fails to send is dead and its recorded tenant intent is lost#21507 merged, #21522 closedunit-test-onlysync dropped a messageFIXED, UNTESTEDbt-e review door (one hold record, option B) (keyword, not read): NOT ADDRESSEDDay 0 tap 10 render cell on the hold: assert one card shape, four actions, no default mentions. Then a production screenshot.
issue#215352026-10-20Situs GroupProspects list shows "No source recorded" for guest cards with a real AppFolio source (Situs 28 of 68)#21536 mergednoneidentity/matchingFIXED, UNTESTEDidentity layer / PmsInbox (keyword, not read): PARTLYDay 0 fixture from the real card: assert tap 1 resolves the right person and card. Control: a clean sender resolves as today.
issue#219262026-10-22unknownText door holds a booked-tour text as no_pms_record when Clara's create_card resolved to an existing card (no af.propertyId written back)#21930 mergedunit-test-onlysync dropped a messageFIXED, UNTESTEDbt-e review door (one hold record, option B) (keyword, not read): NOT ADDRESSEDDay 0 tap 10 render cell on the hold: assert one card shape, four actions, no default mentions. Then a production screenshot.
issue#219382026-10-22Western Sloperenewals: outreach-started renewals save no 'respond by' day, so a Western Slope packet holds on it#21981 merged, #22051 mergedunit-test-onlyhold handling (review door)FIXED, UNTESTEDbt-e review door (one hold record, option B) (keyword, not read): NOT ADDRESSEDDay 0 tap 10 render cell on the hold: assert one card shape, four actions, no default mentions. Then a production screenshot.
issue#219442026-10-23unknownnew-lease prepare rung: tell the office when a packet is parked or held (#21941 follow-up)#21977 merged, #22187 mergedunit-test-onlyhold handling (review door)FIXED, UNTESTEDbt-e review door (one hold record, option B) (keyword, not read): NOT ADDRESSEDDay 0 tap 10 render cell on the hold: assert one card shape, four actions, no default mentions. Then a production screenshot.
issue#220142026-10-23test/internalNew-lease packet: a second application on the same prospect is silently dropped (workflow id is per prospect, not per application)#22017 merged, #22444 mergedunit-test-onlysync dropped a messageFIXED, UNTESTEDRecipient by cause + bt-a "Silent holds" (keyword, not read): NOT COVEREDDay 0 tap 8 census cell: every held or failed turn has exactly one hold record with a check name plus an #alerts line. Mutation: drop the record write, red.
issue#220202026-10-23unknownTour-time guard holds a correct refusal that states the tour hours ("tours run 9:00 AM to 6:00 PM")#22024 merged, #22018 merged, #22036 mergedunit-test-onlyprovenance gate stripped real factsFIXED, UNTESTEDbt-a row 1 (checks compare against our records) (keyword, not read): PARTLYDay 0 fixture on the #22483 envelope: frozen draft, assert the check passes the real fact. Control: the writer's first draft passes.
issue#220342026-10-23unknownTour-time guard holds a correct reply when the incoming-text tour check (not a Clara tool) found the alternatives#22036 merged, #22485 openunit-test-onlyprovenance gate stripped real factsFIXED, UNTESTEDbt-a row 1 (checks compare against our records) (keyword, not read): PARTLYDay 0 fixture on the #22483 envelope: frozen draft, assert the check passes the real fact. Control: the writer's first draft passes.
issue#219872026-10-23unknownRenewal packet: hold when the respond-by day falls on or after the new term's start#22051 mergedunit-test-onlyhold handling (review door)FIXED, UNTESTEDbt-e review door (one hold record, option B) (keyword, not read): NOT ADDRESSEDDay 0 tap 10 render cell on the hold: assert one card shape, four actions, no default mentions. Then a production screenshot.
issue#220542026-10-23Camellia (JP&Co)Application sync: our copy shows Camellia application 119 as approved, AppFolio says Decision Pending#22133 merged, #22134 merged, #22118 mergedunit-test-onlysync dropped a messageFIXED, UNTESTEDPmsInbox adapter, bt-c idempotent writes (keyword, not read): NOT ADDRESSEDDay 0 fixture: replay the record twice and after a parked write; assert tap 12 rows and one retry. Control: a new record adds one.
issue#198662026-10-15unknownList email reply: a term change with no model instruction is silently dropped on approvenonesync dropped a messageOPENRecipient by cause + bt-a "Silent holds" (keyword, not read): NOT COVEREDDay 0 tap 8 census cell: every held or failed turn has exactly one hold record with a check name plus an #alerts line. Mutation: drop the record write, red.
issue#211142026-10-19test/internalAppFolio sync: every desk-booked showing at The Willows unit 102 fails (showing picker unit search returns nothing), runs 7-11nonesync dropped a messageOPENPmsInbox adapter, bt-c idempotent writes (keyword, not read): NOT ADDRESSEDDay 0 fixture: replay the record twice and after a parked write; assert tap 12 rows and one retry. Control: a new record adds one.
issue#211132026-10-19test/internalstaff desk: duplicate-card question uses the full name and runs over 120 chars with long namesnonetours and staff-desk logicOPENpage silent (keyword, not read): NOT ADDRESSEDDay 0 fixture on the real record; assert the reported failure is gone. Positive control from the same corpus.
issue#215422026-10-20unknownTours: probe the host once and delete the old 'confirmed, no calendar to sync' arm (follow-up to #21540)#21540 mergednonesync dropped a messageOPENPmsInbox adapter, bt-c idempotent writes (keyword, not read): NOT ADDRESSEDDay 0 fixture: replay the record twice and after a parked write; assert tap 12 rows and one retry. Control: a new record adds one.
issue#215372026-10-20test/internalTour yes by email is never recorded: no host confirm text, staff line shows no confirmationnonetours and staff-desk logicOPENpage silent (keyword, not read): NOT ADDRESSEDDay 0 fixture on the real record; assert the reported failure is gone. Positive control from the same corpus.
issue#215142026-10-20unknownHeld text: Twilio line gets a real send-once marker so a throw with unknown carrier outcome can be retried safelynonehold handling (review door)OPENbt-e review door (one hold record, option B) (keyword, not read): NOT ADDRESSEDDay 0 tap 10 render cell on the hold: assert one card shape, four actions, no default mentions. Then a production screenshot.
issue#215122026-10-20unknownHeld reply supersede: a sent-then-bounced email hold must not be relabelled 'replaced, not sent'nonehold handling (review door)OPENbt-e review door (one hold record, option B) (keyword, not read): NOT ADDRESSEDDay 0 tap 10 render cell on the hold: assert one card shape, four actions, no default mentions. Then a production screenshot.
issue#215062026-10-20unknownApproved held EMAIL reply whose send fails has no retry and no action floor#21507 mergedunit-test-onlyhold handling (review door)OPENbt-e review door (one hold record, option B) (keyword, not read): NOT ADDRESSEDDay 0 tap 10 render cell on the hold: assert one card shape, four actions, no default mentions. Then a production screenshot.
issue#214722026-10-20unknownA long AI outage on first-email compose is silent for up to 24 h (no ops card while deferring)noneother code bugOPENRecipient by cause + bt-a "Silent holds" (keyword, not read): NOT COVEREDDay 0 tap 8 census cell: every held or failed turn has exactly one hold record with a check name plus an #alerts line. Mutation: drop the record write, red.
issue#214702026-10-20unknown/review feed still shows Approve/Reject on per-offer renewal holds to company admins; every click 403snonehold handling (review door)OPENbt-e review door (one hold record, option B) (keyword, not read): NOT ADDRESSEDDay 0 tap 10 render cell on the hold: assert one card shape, four actions, no default mentions. Then a production screenshot.
issue#214552026-10-20test/internalParked PMS write-backs (assign card to Clara, record 'Email Sent') are never retriednonesync dropped a messageOPENPmsInbox adapter, bt-c idempotent writes (keyword, not read): NOT ADDRESSEDDay 0 fixture: replay the record twice and after a parked write; assert tap 12 rows and one retry. Control: a new record adds one.
issue#214542026-10-20test/internalReleasing a prep-held first email writes a fake inbound message on the conversationnonehold handling (review door)OPENbt-e review door (one hold record, option B) (keyword, not read): NOT ADDRESSEDDay 0 tap 10 render cell on the hold: assert one card shape, four actions, no default mentions. Then a production screenshot.
issue#214532026-10-20test/internalA refused first text in the follow-up cadence is never retried and raises no alertnonesync dropped a messageOPENRecipient by cause + bt-a "Silent holds" (keyword, not read): NOT COVEREDDay 0 tap 8 census cell: every held or failed turn has exactly one hold record with a check name plus an #alerts line. Mutation: drop the record write, red.
issue#214502026-10-20unknownA tenant who is also a vendor contact still loses a renewal reply sent to Clara's own line (door off)noneidentity/matchingOPENidentity layer / PmsInbox (keyword, not read): PARTLYDay 0 fixture from the real card: assert tap 1 resolves the right person and card. Control: a clean sender resolves as today.
issue#214422026-10-20unknownA failed Temporal signal leaves a permanent 'delivery failed' flag on an offer hold even after the text is deliverednonehold handling (review door)OPENbt-e review door (one hold record, option B) (keyword, not read): NOT ADDRESSEDDay 0 tap 10 render cell on the hold: assert one card shape, four actions, no default mentions. Then a production screenshot.
issue#214402026-10-20test/internalRenewal offer text renders 'coming up on your lease end date' when the lease end is blanknoneother code bugOPENpage silent (keyword, not read): NOT ADDRESSEDDay 0 fixture on the real record; assert the reported failure is gone. Positive control from the same corpus.
issue#213642026-10-20test/internalRenewal reader asks 'hold or send as listed?' when a hold is followed by 'leave it as is for now'#21370 mergedunit-test-onlyhold handling (review door)OPENbt-e review door (one hold record, option B) (keyword, not read): NOT ADDRESSEDDay 0 tap 10 render cell on the hold: assert one card shape, four actions, no default mentions. Then a production screenshot.
issue#216272026-10-21test/internalSupervised hold card for a tenant's "no" omits "and tells the office"nonehold handling (review door)OPENbt-e review door (one hold record, option B) (keyword, not read): NOT ADDRESSEDDay 0 tap 10 render cell on the hold: assert one card shape, four actions, no default mentions. Then a production screenshot.
issue#216182026-10-21unknownGuest-card notes policy (a): every Clara contact and every outcome lands on the AppFolio guest card, the same way at every customer, no setting#21622 merged, #21630 merged, #21637 merged, #21656 mergedreplay/harnessidentity/matchingOPENidentity layer / PmsInbox (keyword, not read): PARTLYDay 0 fixture from the real card: assert tap 1 resolves the right person and card. Control: a clean sender resolves as today.
issue#216042026-10-21unknownReasoning-preamble guard runs before the history-stamp strip and leaves no trace on the redraft pathnoneprovenance gate stripped real factsOPENbt-a row 1 (checks compare against our records) (keyword, not read): PARTLYDay 0 fixture on the #22483 envelope: frozen draft, assert the check passes the real fact. Control: the writer's first draft passes.
issue#216032026-10-21unknownReasoning-preamble guard: narrow the tools and third-person markers; fix the tú boundarynoneprovenance gate stripped real factsOPENbt-a row 1 (checks compare against our records) (keyword, not read): PARTLYDay 0 fixture on the #22483 envelope: frozen draft, assert the check passes the real fact. Control: the writer's first draft passes.
issue#215972026-10-21unknownTour reminders: a failed reminder email raises no engineering alert (never-silent rule, follow-up to #21595)nonetours and staff-desk logicOPENRecipient by cause + bt-a "Silent holds" (keyword, not read): NOT COVEREDDay 0 tap 8 census cell: every held or failed turn has exactly one hold record with a check name plus an #alerts line. Mutation: drop the record write, red.
issue#215962026-10-21unknownSelf-guided tours: Clara still says "text me when you get there, I'll send the code" after the code goes out one hour before (#21589)nonemissing fact in promptOPENpage silent (keyword, not read): NOT ADDRESSEDDay 0 fixture on the real record; assert the reported failure is gone. Positive control from the same corpus.
issue#215772026-10-21Camellia (JP&Co)Lead marked not_interested and guest card set inactive from a STOP that a later START reversednoneidentity/matchingOPENidentity layer / PmsInbox (keyword, not read): PARTLYDay 0 fixture from the real card: assert tap 1 resolves the right person and card. Control: a clean sender resolves as today.
issue#218482026-10-22Western SlopeCadence close-out text garbles two Emerald Circle addresses ("2980 Emerald Circle -2978 Emerald Circle is no longer available")nonemissing fact in promptOPENbt-b facts block (keyword, not read): PARTLYBench episode on the frozen reply: assert only facts on our records, one home. Control: a clean home quotes its own numbers.
issue#218132026-10-22unknownTour held for the renter's name and confirmed by update_prospect is not texted to an email lead's number#21815 mergedunit-test-onlyhold handling (review door)OPENbt-e review door (one hold record, option B) (keyword, not read): NOT ADDRESSEDDay 0 tap 10 render cell on the hold: assert one card shape, four actions, no default mentions. Then a production screenshot.
issue#218122026-10-22test/internalEmail-reply tour booking attached to another person's guest card that still holds the shared number in AppFolio#21815 merged, #21886 merged, #21930 mergedunit-test-onlyidentity/matchingOPENbt-e review door (one hold record, option B) (keyword, not read): NOT ADDRESSEDDay 0 tap 10 render cell on the hold: assert one card shape, four actions, no default mentions. Then a production screenshot.
issue#217982026-10-22unknownFollow-up #21784: approved email hold can be dropped on re-run (self-guided delay note / leave check-in)noneprovenance gate stripped real factsOPENbt-a row 1 (checks compare against our records) (keyword, not read): PARTLYDay 0 fixture on the #22483 envelope: frozen draft, assert the check passes the real fact. Control: the writer's first draft passes.
issue#217452026-10-22unknownFirst AppFolio-door text to an email lead is held forever when the guest card does not yet carry the number; never retried, nobody toldnoneidentity/matchingOPENbt-e review door (one hold record, option B) (keyword, not read): NOT ADDRESSEDDay 0 tap 10 render cell on the hold: assert one card shape, four actions, no default mentions. Then a production screenshot.
issue#217442026-10-22unknownTour reminders text any number we hold with no consent check, including numbers found in an email signature (Oct 19 decision says found numbers get no texts)noneprovenance gate stripped real factsOPENbt-a row 1 (checks compare against our records) (keyword, not read): PARTLYDay 0 fixture on the #22483 envelope: frozen draft, assert the check passes the real fact. Control: the writer's first draft passes.
issue#217422026-10-22Western SlopeContacts before the guest card exists never reach the card (WS card 3035: Clara's phone-number ask and the renter's three replies missing)noneidentity/matchingOPENidentity layer / PmsInbox (keyword, not read): PARTLYDay 0 fixture from the real card: assert tap 1 resolves the right person and card. Control: a clean sender resolves as today.
issue#217352026-10-22test/internalClara invents a reason ("occupied") when a unit is held by an approved application; her two availability tools disagree about a held unitnonemissing fact in promptOPENbt-e review door (one hold record, option B) (keyword, not read): NOT ADDRESSEDDay 0 tap 10 render cell on the hold: assert one card shape, four actions, no default mentions. Then a production screenshot.
issue#217282026-10-22test/internalLead card can hold a listing-level placeholder as its apartment (appfolio-45-2-bedroom), which then becomes a booked tour's unitnoneidentity/matchingOPENbt-e review door (one hold record, option B) (keyword, not read): NOT ADDRESSEDDay 0 tap 10 render cell on the hold: assert one card shape, four actions, no default mentions. Then a production screenshot.
issue#217262026-10-22test/internalShowing write retries without end when the unit has no AppFolio id; should park like the no-home holdnonesync dropped a messageOPENbt-e review door (one hold record, option B) (keyword, not read): NOT ADDRESSEDDay 0 tap 10 render cell on the hold: assert one card shape, four actions, no default mentions. Then a production screenshot.
issue#217242026-10-22test/internalText booking does not carry the unit the renter chose (tour saved without a unit, or with a listing placeholder)noneidentity/matchingOPENbt-e review door (one hold record, option B) (keyword, not read): NOT ADDRESSEDDay 0 tap 10 render cell on the hold: assert one card shape, four actions, no default mentions. Then a production screenshot.
issue#216732026-10-22unknownRenewal packet at 'prepare': page wording, held-vs-failed colour, version skew, park-by-ref tests (follow-up to #21672)#21672 mergedunit-test-onlymissing fact in promptOPENbt-e review door (one hold record, option B) (keyword, not read): NOT ADDRESSEDDay 0 tap 10 render cell on the hold: assert one card shape, four actions, no default mentions. Then a production screenshot.
issue#221222026-10-23unknownLearner: same.last_document scores the household's last FILLED value but the fact is named fact.lastDocument.*; pick one meaning before the park supplies it (score.ts:128, from #22117 review)noneidentity/matchingOPENbt-e review door (one hold record, option B) (keyword, not read): NOT ADDRESSEDDay 0 tap 10 render cell on the hold: assert one card shape, four actions, no default mentions. Then a production screenshot.
issue#221032026-10-23unknownBooking confirmation names two homes and calls a held unit 'occupied'nonemissing fact in promptOPENbt-e review door (one hold record, option B) (keyword, not read): NOT ADDRESSEDDay 0 tap 10 render cell on the hold: assert one card shape, four actions, no default mentions. Then a production screenshot.
issue#220452026-10-23Western SlopeA held first reply (guard block) at a live customer should raise an alert, not sit silentnoneprovenance gate stripped real factsOPENRecipient by cause + bt-a "Silent holds" (keyword, not read): NOT COVEREDDay 0 tap 8 census cell: every held or failed turn has exactly one hold record with a check name plus an #alerts line. Mutation: drop the record write, red.
issue#220212026-10-23unknownnew-lease packet: pin the run to the approved application from the writer, and hold-path card per run (follow-up to #22017)nonehold handling (review door)OPENbt-e review door (one hold record, option B) (keyword, not read): NOT ADDRESSEDDay 0 tap 10 render cell on the hold: assert one card shape, four actions, no default mentions. Then a production screenshot.
issue#219612026-10-23unknownClara-sends: a company with two or more renewal recipes in use holds every packetnonehold handling (review door)OPENbt-e review door (one hold record, option B) (keyword, not read): NOT ADDRESSEDDay 0 tap 10 render cell on the hold: assert one card shape, four actions, no default mentions. Then a production screenshot.
issue#222482026-10-24unknownPMS text door: an unreadable guest-card list is treated as 'no card yet' and waits silently up to 6 hnonesync dropped a messageOPENRecipient by cause + bt-a "Silent holds" (keyword, not read): NOT COVEREDDay 0 tap 8 census cell: every held or failed turn has exactly one hold record with a check name plus an #alerts line. Mutation: drop the record write, red.
issue#222302026-10-24test/internalTour day check: hold a Clara reply whose tour day disagrees with the booked record#22233 mergednoneprovenance gate stripped real factsOPENbt-a row 1 (checks compare against our records) (keyword, not read): PARTLYDay 0 fixture on the #22483 envelope: frozen draft, assert the check passes the real fact. Control: the writer's first draft passes.
issue#224322026-10-25test/internalFirst-email tour-times check reads only English and Spanish, so a correct French reply is held; and the writer's one redraft did not run#22483 open, #22485 open, #22488 opennoneprovenance gate stripped real factsOPENbt-a row 1 (checks compare against our records) (keyword, not read): PARTLYDay 0 fixture on the #22483 envelope: frozen draft, assert the check passes the real fact. Control: the writer's first draft passes.
issue#224202026-10-25unknownFour unstamped engineering-failure exits in the agent loop still end in the team hand-off email#22417 mergedunit-test-onlyother code bugOPENpage silent (keyword, not read): NOT ADDRESSEDDay 0 fixture on the real record; assert the reported failure is gone. Positive control from the same corpus.
issue#224192026-10-25unknownReply clock exits on guardSilencedBy before reading turnOutcome, so a draft_check_held hold never pages#22417 mergedunit-test-onlyprovenance gate stripped real factsOPENbt-a row 1 (checks compare against our records) (keyword, not read): PARTLYDay 0 fixture on the #22483 envelope: frozen draft, assert the check passes the real fact. Control: the writer's first draft passes.
issue#223762026-10-25unknownRejecting a stale first-email hold cancels a tour the email already bookednonehold handling (review door)OPENbt-e review door (one hold record, option B) (keyword, not read): NOT ADDRESSEDDay 0 tap 10 render cell on the hold: assert one card shape, four actions, no default mentions. Then a production screenshot.
issue#223752026-10-25unknownStale held-draft copy points reviewers to Reject, which pauses the building's rolloutnonehold handling (review door)OPENbt-e review door (one hold record, option B) (keyword, not read): NOT ADDRESSEDDay 0 tap 10 render cell on the hold: assert one card shape, four actions, no default mentions. Then a production screenshot.
issue#223602026-10-25Western SlopeConversation turnOutcome.why says replied_not_sent after a first email was sentnonemissing fact in promptOPENpage silent (keyword, not read): NOT ADDRESSEDDay 0 fixture on the real record; assert the reported failure is gone. Positive control from the same corpus.
issue#223262026-10-25test/internalHeld-reply review page calls a prospect's reply "Text to a resident"nonemissing fact in promptOPENbt-e review door (one hold record, option B) (keyword, not read): NOT ADDRESSEDDay 0 tap 10 render cell on the hold: assert one card shape, four actions, no default mentions. Then a production screenshot.
issue#223252026-10-25unknownConversation page shows no held marker for a Supervised holdnonehold handling (review door)OPENbt-e review door (one hold record, option B) (keyword, not read): NOT ADDRESSEDDay 0 tap 10 render cell on the hold: assert one card shape, four actions, no default mentions. Then a production screenshot.
issue#223102026-10-25unknownOutage page still says customers got the holding note (text and email now get nothing)nonemissing fact in promptOPENRecipient by cause + bt-a "Silent holds" (keyword, not read): NOT COVEREDDay 0 tap 8 census cell: every held or failed turn has exactly one hold record with a check name plus an #alerts line. Mutation: drop the record write, red.
issue#223012026-10-25unknownAvailability check: on a held reply, say it was held, not that words were removed#22296 mergedreplay/harnessprovenance gate stripped real factsOPENbt-a row 1 (checks compare against our records) (keyword, not read): PARTLYDay 0 fixture on the #22483 envelope: frozen draft, assert the check passes the real fact. Control: the writer's first draft passes.
issue#224812026-10-26Situs GroupHeld first-touch email hold should carry the conversation id when one exists#22482 mergednonehold handling (review door)OPENbt-e review door (one hold record, option B) (keyword, not read): NOT ADDRESSEDDay 0 tap 10 render cell on the hold: assert one card shape, four actions, no default mentions. Then a production screenshot.
issue#133962026-09-28Western SlopeFirst email home facts: unit number leaks into the street number ("1240 Elm" → "1250 Elm", "565 Redcliff" → "575 Redcliff"; WS 2738/1365)noneother code bugBY DESIGNpage silent (keyword, not read): NOT ADDRESSED

Harness view

Every case that is not fixed and tested carries its own line in the tables above. They fall into six fixture shapes, all inside the Day 0 harness or the bench:

  1. Held draft replay (#22483 envelope): frozen draft, assert the real fact passes the check; positive control is the writer's own first draft. Covers the provenance-gate holds (Trang, Anthony, Robert, Morgan, Carmen, Patrick).
  2. Hold census cell on tap 8: every held turn has exactly one hold record with a check name and one #alerts line. Covers the card-only holds and the silent-hold issues. Mutation: drop the record write, red.
  3. Staff took the thread (#22488): shouldSpeak silent with reason, held draft closed, no cadence row; add the half-turn assert that a held reply lists the actions already taken.
  4. Replay twice on tap 12: row counts unchanged for the same record, one added for a new one. Covers the Sep 23 lead flood, Robert's four emails, the outbox race and the sync issues.
  5. Identity on tap 1: the real card or call resolves to the right person and home. Covers Ethan, Lincoln, the former tenant, the Ember callers and the shared-number booking.
  6. Bench episode in shadow for prompt-side cases: one home, its own numbers, the special, no unbacked claim. Covers the Ember lists, Situs first replies and the touch-4 outreach text.

How this was built

Holds: every EscalationHold row in production (453, one query on the entity index, no sampling), the first-email intent rows each hold points to, and 598 Slack messages matching "Held for review" or "FIRST EMAIL HELD". Issues: open issues and those closed since Sep 1, filtered by label and title words, with the PR that closed or referenced each. Incidents: pages under docs with incident, RCA or root cause in the title, and the memory incident notes. Test case: a merged fix counts as tested only when a replay, harness or bench case names it. Verdict REGRESSED means the same signature came back after a merged fix. The root cause list adds one bucket, "writer quality (prompt rules)", for the Sep 23 recomposes, "hold handling (review door)" for bugs in the hold path itself, "tours and staff-desk logic", and "other code bug" for issues that fit none. The same event can appear as a hold, an issue and an incident (Trang is in all three), so totals across the tables overlap. First-email intents have no index, so a held intent with neither a hold row nor a Slack card is not in this ledger; the battle test found held turns with no hold row, so there are likely more. Open issues that a merged PR only references stay OPEN. Raw ledger: real-life-ledger.json, one object per case.

Hold and rewrite gates: full inventory, Oct 26

Proposed, pending review. Read-only: no edits, no sends, no production writes. Code read at origin/main 137f883e7f (Oct 26 15:41Z). Merged after that snapshot and folded in below: #22485 (16:11Z, the first email's tour slots count as this turn's calendar read), #22483 (its fixture), #22482 (a held first touch is an alert, not an outage), #22425 (the maintenance relay records when it did not send). Open and relevant: #22487 (Supervised holds every resident message, emergencies included). Window for counts: Sep 26 to Oct 26. "The three customers" are Western Slope, Situs Group and JP&Co (Camellia); test companies (Willows, Fairhaven, Yale) are left out of every count. Long dashes in quoted log strings are shown as hyphens.

Totals

Gates that can stop, hold or silence a messageabout 255 distinct (284 rows, about 25 repeat across sections), in 15 families
Rewrite layers still on mainabout 60 that change words (24 in the main loop: voice and video, internal-text strips, staff-facing swaps, hand-off rewrites and salvage; 26 side writers; 10 at the send doors), plus 5 cosmetic transport steps. 11 more were removed Oct 13 to 25.
Left evidence of firing at the three customers, 30 daysabout 22 gates and 7 rewrite layers (several of those layers have since been removed)
Fired only at test companies, or not at all where we can seemost of the rest; about 30 gate types and about 17 rewrite layers leave no record or log at all, so their count is unknown, not zero
Holds at the three customers127 hold rows (124 to a renter), 110 of them expired with nobody looking; 5 first emails still held on the intent row; 3 parked replies; 103 held-item cards in customer channels
Sampled right / wrong, all gatesSAMPLE of 24 across 6 reason families, not 10 per gate: 13 wrong (the message was fine), 4 right, 7 unclear
Sampled, policy holds only (Supervised)SAMPLE of 12: 10 wrong, 0 right, 2 unclear. "Wrong" here means fine words held by a setting that did what it says; the harm is the expiry.
Sampled, correctness gates only (fact and provenance)SAMPLE of 12: 3 wrong, 4 right, 5 unclear. All 3 wrong are provenance gates on a first email.

Data gaps that carry into every count: the shouldSpeak decision line exists only since Oct 26 04:52 (2 lines); turn snapshots only since Oct 24 (10 Western Slope turns marked held, only about 4 match a record); the first-email intent row keeps only its current state and never the check name, so a hold later sent shows only on its Slack card; no record was found for draft salvage or the bounced-email text fallback; 3,353 agent traces could not be tied to a company; the inbound-processor logs start Sep 26 16:37Z. Labels are one reader's judgment.

1. Hold gates, by family

Each row is a family; its values apply to every gate listed in it. The appendix has every gate on its own row with its file:line, release path and the literal log string to count it by. Decides by: FACT checks our own records; PROVENANCE checks how the writer learned it; POLICY is a company setting, the clock, or a role. Master page verdicts use the page's own words (COVERED, PARTLY, NOT COVERED, NOT ADDRESSED) and point to clara-coworker-loop-v3-2026-10.

#Family and gatesWhere (origin/main)What it checksDecides byWhen it firesWho releases, from whereAdded, and why30-day fires at the three customers (source)Sampled right / wrong(a) Master page section(b) Fact protected, verdict(c) Fixtures: true fire / no false fire
H1Supervised reply holds: rules R1 to R7, the text and email row lines, the email 'hook never asked' fallback, the four routed backstops, router answers with no turn (maintenance acks), team-answer hold, first email (R5), unthreaded prospect emailsupervised-reply-rule.ts:130-147; should-speak.ts:100, :152; process-envelope.ts:621, :828, :926; supervised-reply-hold.ts:111, :199; process-inbound-email.ts:2033; process-pms-email.ts:461; inbound-processor handler.ts:1011; send-clara-prospect-email.ts:397The module this reply belongs to (by topic, by recipient being a prospect, or by the router's final module) is set to Supervised at the building. R2: a renewal action was deferred this turn. R6: the topic check gave no answer, so it fails closed.POLICY (module mode); R2 PROVENANCE; R6 fail-closedSilent hold WITH record: EscalationHold (clara_reply_sms or clara_prospect_email), card in the company channel, reviewer email. A tenant gets one fixed 'we got it' text.App /review, /admin/escalation-holds, /held-messages; Slack THREAD reply 'approve N' (relayed by Agent Smith; the Slack buttons only rate); reviewer email reply; rollout auto-release. Auto-closed by expiry, supersede, teammate replied.#13906 Sep 30 (drafts mode); #16514 Oct 5 (Supervised email replies went out with nobody approving); #16644 Oct 5 (routed maintenance reply refused at the door and lost); #22450, #22473 Oct 26 (all eight callers behind shouldSpeak)Clara-written reply holds at the three customers: 5 prospect emails (Western Slope 4, Situs 1). Source: EscalationHold. The shouldSpeak log line exists only since Oct 26 04:52 (2 lines, both reply). The 72 Western Slope 'reply row withheld' log lines are a normal step before the first-email decision, not holds.2 sampled: 1 wrong (Emelyn, Situs: fine draft with tour times, still pending), 1 unclear (Spencer: 'I'll let the team know' with nothing behind it). Policy holds: a 'wrong' here means the words were fine, the hold did what the setting says.#inv-interfaces shouldSpeak: COVERED (one place, one log line; 'module Supervised' is one of the four thin lookups). #machine-gates-h rows 3 to 6 and 9.Protects no fact; it is Fede's choice to see messages first. Verdict: KEEP AS A CHECK (thin layer).True fire: Day 0 tap 8, hold decision at all 8 callers, 5,515 frozen cells (exists). No false fire: the same tap's Live-building and urgent-repair cells return reply (exists).
H2Automatic maintenance and renewal texts held (work-order-created notice, rate-your-repair ask, vendor relay, handyman texts, renewal offer, reminder, change-term, lease-ending warning, monthly batch park)maintenance-text-review.ts:63, :161; maintenance/rating.ts:854; handyman-text-review.ts:24; renewal-text-review.ts:73; renewal-email-review.ts:57; renewal-reply-review.ts:58, :95; renewal-auto-start.ts:2690; renewal-batch/batch-gate.tsThe module is Supervised and the repair is not emergency or urgent (renewals: or the month's list is not approved).POLICYSilent hold WITH record: EscalationHold (maintenance_resident_sms, maintenance_vendor_sms, renewal_*), Slack card. Approve re-runs every check.Same doors as H1; renewal list approval releases parked renewal texts.#12977 Sep 28 (renewals); #16508 Oct 5, #16855, #16919 Oct 6 (maintenance); #20060 Oct 16 (handyman, Gera's Oct 15 ask)118 renter-facing maintenance holds (Western Slope 73, Situs 45): 106 expired unreviewed, 6 approved, 5 pending, 1 discarded. 1 vendor text. Renewals: 0 at real customers in the window. Source: EscalationHold; 86 Slack cards (some holds got no card or a grouped card).10 sampled: 9 wrong (fixed template notices for work orders that exist, rating asks on completed jobs), 0 right, 1 unclear (rating ask on a job still dispatched).#rll-holds: 'the largest real-life gap in this ledger'. #bt-e review door: PARTLY. #tenants: hold card in the property's Slack.Protects no fact: the words are a fixed template and the facts behind them (work order exists, job completed) are in our records. Verdict: KEEP only as Fede's Supervised choice; the open widening to emergencies (#22487) goes the other way.True fire: Day 0 tap 8 maintenance caller (exists). No false fire / expiry: none today; the ledger names 'an expired resident text raises one owner notice; control: an approved card raises none'.
H3Hold lifecycle closers: 24h expiry, newer draft supersedes, teammate took the thread, stale draft (4h or a past slot), approved but not sent (no time zone, renewal gone), approved waits for quiet hours, one held-reply ackheld-message-rule.ts:64, :95; held-message-max-age.ts:17; held-text.ts:1007, :1375; bake-gate.ts:464, :1938, :2662; held-reply-ack.tsHow old the hold is; whether a newer reply, a staff reply or a past tour slot makes the words stale; whether the building has a clock.POLICY (time) for expiry; FACT for supersede, teammate, past slotHold closed unsent WITH record (resolvedBy system:draft-expired, system:draft-superseded, system:human-replied); thread note 'Expired, not sent'. The renter hears nothing.Nobody after it closes; a person writes by hand.#11417 Sep 24 (Western Slope stale drafts Sep 22 to 23); #14241 Sep 30 (supersede); #16608 Oct 5 (teammate); #17249 Oct 7 (no time zone)110 of 124 renter-facing holds at the three customers expired with nobody looking (106 maintenance texts, 3 prospect emails: Robert, Spencer, Morgan; 1 vendor). Source: EscalationHold resolvedBy.Not sampled on its own; the expired set includes the 9 wrong maintenance texts above and Robert and Morgan (unclear).#rll-holds; #bt-d (held draft closes when a person takes the thread): PARTLY; #bt-e review door: NOT ADDRESSED for expiry.Supersede, teammate and past slot protect a fact (are these words still true) and stay. Expiry protects nothing about the words. Verdict: KEEP the fact closers; expiry DEFER TO NEW ENGINE (review door).True fire for teammate closer: staff-took-thread fixture (open PR, #22488). Expiry: none today.
H4First-email draft checks (one writer retry, then hold): no tour times offered, one price for all sizes, unit label on a house, hedged money, implies prior contact, size question with no tour ask, dash, 'gone' claim on an unknown home, unbacked promise, names no home, fact trace, how-much-is-open, PII, bare hand-off body, deferred ask not backedguest-card-first-email-draft-checks.ts:462 to :483; guest-card-engine-turn.ts (firstEmailDeterministicFindings, detectNoHomeFactBody, fact trace, findAvailabilityDisclosures); clara-guest-card-engagement-prep.ts (deferred ask)Text of the draft against what the turn was handed: did it offer the slots it had, name a home, quote the right rent, trace every fact to the listing or the knowledge base.FACT for most; no-tour-times reads requireTourTimes (set from the turn's slot read); fact trace is PROVENANCE (did the sentence come from a known source)Silent hold WITH record on the intent row only (CLARA_FIRST_EMAIL_INTENT heldReason first_email_check_failed, no_home_named, fact_trace_untraced; the check name is not stored), card in the company channel, #alerts line. No EscalationHold row unless rerun into review.Rerun script only (scripts/guest-card-rerun-one.ts); a rerun at a Supervised building lands in review (H1).#12074 Sep 25 (fact trace); #13351 Sep 28 (170-card replay: no tour times); #21085 Oct 19; #22178 Oct 24 (dash); #22249 Oct 24 (block only, one retry)Western Slope: 4 'held after retry' log lines, 7 first-email held cards (Anthony, Trang, Patrick, Carmen, Morgan, Robert, Cheryl); 5 intent rows still held. Before Oct 24 the same checks redrafted: 17 draft-check redrafts, 15 no-home redrafts, 5 fact-trace strips. Sources: CloudWatch, intent rows, Slack.6 sampled: 3 wrong (Anthony Oct 25, Trang Oct 26: fine drafts, retry never ran; Patrick Oct 26: 'I've sent the application' was true), 1 right (Carmen: 'I'm not able to pull up live tour times'), 2 unclear (Robert, Morgan).#bt-a rows 1, 2, 4: PARTLY / PARTLY / NOT COVERED (silent holds); #bt-changes items 1 to 4; 'Turn rebuilt' layer 5 hands in the facts.Protects: a real slot, the home's own rent and size, an action that really ran. Verdict: KEEP the text checks as block-only; fact trace and the tour-times requirement DELETE WHEN DATA LANDS (compare to our records, not to the source).True fire and no false fire for tour times: first-email-slots fixture (#22483, merged today; a time not in the list still fires). Patrick: none today (ledger: tap 11 shows the application intent, tap 8 the hold). Retry ran: none today (ledger: new tap 'retry attempted'; mutation: replant the skip).
H5Tour time not from this turn's calendar read (main loop and first email)agents/clara/lib/agent/tour-time-this-turn-gate.ts:249, :316; conversation-manager.ts:14820, hold :14866Every tour time in the reply must appear in a calendar read made this turn (tool rows, times offered in the last half hour, the tour pipeline's openings, and since 16:11Z today the first email's handed-in slots).PROVENANCERetry with 'do not name any tour time', then park (main loop: msg_held row, subReason tour_time:not_in_this_turn_read, no Slack page). On a first email the retry's draft then fails no-tour-times (H4).Main loop: nobody. First email: rerun script.#20338 Oct 16; widened #21497 Oct 20 (stale times); #22036 Oct 23 (pipeline slots, issue #22034); #22485 Oct 26 16:11Z (first email slots)Direct log: 0 at real customers (1 Fairhaven, 1 test property), visible only through DecisionFallback lines. Through H4: 2 Western Slope first emails (Anthony, Trang). Source: CloudWatch, intent snapshots.2 of 2 wrong (both drafts offered real slots).#bt-a row 1: PARTLY ('the machine map still lists it and the page never says it is deleted').Protects: a real open slot. Verdict: DELETE WHEN DATA LANDS (check the time against the slot list in our records).First-email-slots fixture (#22483): true fire on a time outside the list, no false fire on the handed-in windows (exists).
H6Main-loop post-draft checks (one writer retry, then park): weekday/date, unbooked tour confirmation, work-order claim, unit count, outbound policies (promise backing, booking promise, availability disclosure), work-order confirmation missing, PII, no dashes, hallucination guard, final send gate, anomaly gate (tool failure or timeout)conversation-manager.ts:14744 to :16085 (weekday :14744, unbooked :14899, WO claim :14960, unit count :15029, policies :15088, WO confirmation :15254, PII :15336, dashes :15409, hallucination :15461, send gate :15933, anomaly :15967); guards/hallucination-guard.ts:861; turn-integrity/anomaly-review-gate.ts:296The final text against our records (weekday, counts, offer figures, tour on file) or against what the turn did (a booking, a filing, a backed promise).FACT (weekday, unit count, PII, dash, hallucination vs the offer); PROVENANCE (unbooked tour, WO claim, WO confirmation, promise backing)Retry once, then park WITH record (message row blockedByGuard, msg_held or msg_blocked); Slack page for some; hallucination opens an automatic hand-off. The renter hears nothing.Only three park kinds can be released (fair_housing_hold, weekday_date_guard, dash_in_reply) through a Slack thread reply that runs a script (texts only). Every other park: nobody; a person writes by hand.#4061 Jul 17 (anomaly gate, after a Camellia tour incident that day: 006, git archaeology Oct 26); #14348 Oct 1 (empty reply sends nothing, Fede Sep 30: 006); #485 Apr 27 (hallucination); #12543 Sep 26 (wrong weekday to a Western Slope prospect); #14353 Sep 30 (Camellia 'See you at 1' after both bookings failed); #21145 Oct 19 (no counts); #22236 Oct 24 (dashes); #22296 Oct 25 (block only)Parked at the three customers: 3 (Western Slope 1 anomaly, JP&Co 1 send gate 'unbacked promise in retry', JP&Co 1 hallucination). Trace blocks: booking promise 7 (6 cleared by the regenerate, 1 not), anomaly 1. Turn snapshots since Oct 24: 10 Western Slope turns marked held, only about 4 match a record. Sources: message rows, AgentTrace, TurnSnapshot.3 sampled: 2 right (Will Sep 30: '1 PM works' when the tour was 4:45 PM; Ember Oct 22: empty draft after a timeout), 1 unclear (Ibrahim Oct 26).#turn-rebuilt: 'Checks that only block' COVERED in principle; #bt-a row 4 silent holds NOT COVERED (no release path); askState replaces the 'it's with the team' promise check.Protects: the date, the tour on file, the offer, a filing. Verdict: fact checks KEEP AS A CHECK; provenance ones DELETE WHEN DATA LANDS (askState and the turn's action ledger answer them from records).Promise without backing: goldmine repro 04 (exists). Others: none today.
H7In-loop forced-tool retries: first-turn leasing tool gate, availability claim, tour-time claim, typed tool callconversation-manager.ts ~12547, :12717 to :12860, ~12870; availability-claim-gate.ts:294; tour-time-claim-gate.ts:328The reply names availability or tour times, or ends turn 1, without the matching lookup tool this turn.PROVENANCERedraft with a forced tool call; if that fails the degraded reply is SENT anyway (never holds).None needed.Apr 8 (first-turn gate); #10579 Sep 21 (Camellia: units named with no lookup); #14132 Sep 30 (Western Slope tour times with no read)Tour-time claim: Western Slope 5 turns, JP&Co 4. Availability claim: Western Slope 4, JP&Co 2. Source: CloudWatch.Spot-read, not tallied (the pre-retry text is not kept): mostly right or unclear.#turn-rebuilt: 'Goes away: the forced call-3-lookup-tools-first gate'. COVERED.Protects: the facts named come from a lookup. Verdict: DELETE WHEN DATA LANDS (facts block hands them in).None today.
H8Turn silencers before or around the model: runaway ceiling, muted person, tapback, farewell loop, bare closer, escalated thread (human takeover), team-answer takeover, model chooses end_conversation, video abandoned, opted-out person, team-inbox silence, conversation ended, staff sender, resident scopeguards/runaway-ceiling.ts:170; guards/tapback-reaction.ts:222; guards/farewell-loop.ts:138; guards/closer-skip.ts:426; conversation-manager.ts:1665 (escalated gate), :7618 (mute), :16641 (team inbox), :17106 (opted out); tools/end-conversation.tsThe shape of the inbound (reaction, goodbye, bare thanks), who owns the thread, consent, or the model's own choice to stay quiet.FACT (text shape, consent); PROVENANCE (who owns the thread); POLICY (mute)Nothing sent, nothing said. Escalated and runaway write a status change; mute writes one ops card; the rest log only (opted-out: a trace step only).Staff unmute, release the thread, or the person texts START; otherwise none needed.#5047 Jul 30 (Clara traded goodbyes with another machine); #6519 Aug 30 (closers); #6526 Aug 28 (mute); #5985 Aug 20 (team inbox); #21302 Oct 20 (opted out)end_conversation Western Slope 5, JP&Co 1; bare closer 2 / 2 / 2 (WS / Situs / JP&Co); conversation ended WS 3, JP&Co 3; staff sender WS 14 lines in 1 conversation; resident scope JP&Co 3; escalated 13 lines with no company id. Source: CloudWatch.Not sampled.#inv-interfaces rulings: opt-out is a thin lookup; 'is a person already on it' is reasoned by the model, never timed (COVERED). Tapback, farewell, closer: NOT ADDRESSED.Opt-out, mute, tapback protect consent and sense. Verdict: KEEP AS A CHECK; the escalated-thread gate DEFER TO NEW ENGINE (the model reads the staff thread).Silence after hand-off: goldmine class1 and its green control (exists). Staff took the thread: #22488 (open).
H9Send-door refusals: module off, Supervised with no approval (text and email doors), company not live, STOP / consent, test or stress recipient, canary, AppFolio code numbers, flipped line, contact ceiling, AppFolio text door (media, over 910 characters), dispatch policy skips (thread escalated, human replied)twilio/client.ts:904, :1111 to :1249; company-live-gate.ts:~400 to :495; off-means-off.ts; dispatch-envelope.ts:247, ~570; appfolio-inbox-text.tsLast line before the carrier: is this module on, approved, the company live, the person consenting, the recipient real.POLICY (module, live, test scope); FACT (consent)Nothing sent. Module refusals write a MODULE_REFUSAL row and page Sentry ('an upstream lane missed its hold'); email writes an EMAIL_LOG BLOCKED row; text-door test-scope, not-live and dispatch skips log only.Nobody (turn the module on, go live, the person texts START). The AppFolio text door re-drives itself.#1100 May 17 (dispatch policy); #6831 Sep 3 (text door routing; compliance origin unconfirmed: 006, git archaeology Oct 26); #9177 Sep 17 (company-live email hold, one seam: 006); #9988 Sep 19 (38 lanes, zero readers of the module flag); #12142 Sep 25; #14235 Sep 30; #16495 Oct 5; #19463 Oct 14MODULE_REFUSAL at real customers: 0 (17 rows, all local). Company-not-live: Western Slope 5 lines. Test/stress: test companies only. Sources: DynamoDB, CloudWatch.Not sampled (no customer fires to sample).#machine-gates-h rows 7 to 11; #inv-interfaces: shouldSpeak replaces 'the human replied policy skip' (COVERED).Consent, test scope and live state are one-right-answer lookups. Verdict: KEEP AS A CHECK.Day 0 tap 8 door callers (text.door, email.door) exist for the Supervised branch. Others: none today.
H10Lead intake and first-email consumer skips: company not live, leasing off, Clara's own card or home, backfill import, seen before the source was on, arrived before go-live, already applied, source not in scope (Situs list), already engaged, no email, staff person, folded card, historical lead, mailbox lane made first touch, Zillow relay never answered by email, relay with no renter addressguest-card-reply-intake.ts; lead-scope.ts; leads/consumers/clara-first-email-consumer.ts; clara-guest-card-reply-composer.ts; clara-guest-card-engagement-prep.ts:445; email/decide-email-send-mode.ts:150, :170Whether this card is one Clara should answer at all.POLICY (live, scope); PROVENANCE (who made the card, when it was seen); FACT (applied, no email)Nothing sent, nothing said; log line only (company not live at prep writes heldReason org-not-live with no alert). Going live does not re-drive skipped cards.Nobody.#9633 Sep 18; #14504 Sep 30; #16461 Oct 5 ('He already applied. Leave it alone.'); #19004 Oct 12; #20019 Oct 15 (Situs list); #8896 Sep 16 (Zillow relay)JP&Co: 13 first touches made by the mailbox lane (a routing decision). Other skips not separately counted. Source: intent rows, CloudWatch.Not sampled.#bt-c (PmsInbox, one row per message, idempotent writes): NOT ADDRESSED for the skips; #rll 'sync dropped a message' 30 cases.Protects: answering only real, in-scope, new leads. Verdict: KEEP AS A CHECK; the staff-created-card rule Fede gave on Oct 23 is not in code (see below).None today; the ledger names a Day 0 replay of a historical inquiry twice (control: a fresh inquiry gets one).
H11Prospect cadence and reminder gates: follow-up stop, company not live, identical text already sent, unit-type check, quiet hours, reminder freshnesstemporal/activities/prospect-outreach.ts:1809; leasing follow-up gate; leasing_outreach hold (unit-type)Whether the next follow-up still fits (a reply came, the company is live, the text is new, the home type matches the property).FACT (unit type, duplicate); POLICY (live, quiet hours)Touch skipped, log only; the unit-type check writes an EscalationHold (leasing_outreach_sms).Unit-type hold: review doors as H1. Others: nobody.#2470 Jun 18 (quiet hours); 62dbb95391 Oct 1, Supervised holds the cadence text (006, git archaeology Oct 26)Follow-up stop: Western Slope 3. 'Cadence touch held: company not live': 34 (company not split). Identical text: 5. Unit-type hold: 1 (Jessalyn, pending). Source: renewal worker / Temporal logs, EscalationHold.1 sampled: right (Jessalyn: '2-bedroom homes' at Pomona Park, where every home is 3 or 4 bedrooms).NOT ADDRESSED by the page beyond 'checks that only block'.Protects: the home type on file. Verdict: KEEP AS A CHECK.None today.
H12Fair housingcompliance/outbound-safety.ts:344 (ALERT_ONLY_POLICY_IDS); first-email safety pipeline (outbound-safety-pipeline.ts)A model judge reads the reply for fair-housing risk.POLICY (model judge)Reply loop: flags and SENDS, Slack flag (since Oct 19). First email: holds (guard fair_housing_hold) on the intent row.First email: rerun script, or a Slack thread reply on the review card.#21159 Oct 19 (reply loop stopped holding)1 first-email hold at JP&Co (Will, Oct 4, later sent). Source: intent row, Slack card.1 sampled: unclear (text reads fine; the 'familial status' trigger looks like a false positive).'Stays: the fair-housing judge.' COVERED.Protects a legal line, not a fact. Verdict: KEEP AS A CHECK; the reply loop and the first email disagree on what it does.False block: goldmine repro 03 fair-housing-false-block (exists). True fire: none today.
H13Hold could not be written (text and prospect email)renewal-reply-review.ts:351; send-clara-prospect-email.ts:415The hold write threw, or there is no building, conversation or person to key it.FACTNothing sent; #alerts post WITH the words; critical log. If the post fails too, the words are lost.Nobody; a person replies by hand.#13906 Sep 30 (driver ruling: never sent live, never dropped silently); #11269 Sep 23Not counted in this pull.Not sampled.#notice-engine-rule: an engineering error goes to #alerts and the record only. COVERED.Verdict: KEEP (it is the alarm for a broken hold).None today.
H14Quiet hours (renewal outreach, prospect cadence, maintenance pages, collections, application sends, voice callbacks, month-to-month warning)quiet-hours.ts:226; renewal.ts:897, :1377, :2202, :2609; prospect-outreach.ts:1809; maintenance-comms.ts:1440; voice-callback.ts:1628:00 to 21:00 at the property (per handyman for pages).POLICY (time)Waits and retries, except renewal outreach, which returns 'dispatched' without sending (the touch may be lost; not traced).Automatic at window end.#1001 May 16 (Camellia tenant voice-called at 10:21 PM, May 15); #11366 Sep 23 (time zone fix)Not counted (renewal outreach did not run at real customers in the window).Not sampled.NOT ADDRESSED.Verdict: KEEP AS A CHECK; the renewal no-op needs a look before anyone relies on it.None today.
H15Voice gates: outbound call door, never transfer to a number that rings Clara, settings refuse a looping catch-all, muted caller with no destination, missed-call note gatevoice/initiate-outbound-call.ts:278; properties/clara-line-loop.ts:156, :175; api/settings/call-routing/route.ts:221; voice/personalization/route.ts:4246; promises/guards/missed-call-note-gate.ts:196Consent, test scope, module, Supervised and contact budget for calls; whether a transfer destination loops back to Clara.FACT + POLICYCall not placed or destination dropped; a looping catch-all is refused in settings. The outbound call door has no quiet-hours or not-live branch (each caller owns it).Fix the destination or the setting.#6526 Aug 28; #13381 Sep 28 (Western Slope forwarded main line looped, Sep 22); #14995 Oct 1; #21636 Oct 21 (bounce alert)Not counted in this pull.Not sampled.#rh-d2 'Voice in v1?' is an open decision. NOT ADDRESSED.Verdict: KEEP AS A CHECK.None today.

Rules that are not in code.

  • Staff-created guest cards excluded (Fede, Oct 23): the 'created by System' gate was removed on Sep 30; the only origin skip left is Clara's own card.
  • Unknown role stays silent (Fede, Oct 23): shouldSpeak has a 'silent' answer, but nothing returns it yet.
  • Fair housing holds a reply: true only for the first email; the reply loop flags and sends since Oct 19.
  • Slack buttons approve a hold: the buttons only rate shadow cards; approval is a thread reply relayed by Agent Smith, the app pages, or a reviewer's email reply.

1b. Rewrite layers, by family

Fede, Oct 22: "nothing edits Clara's message after she writes it; checks only block; fix the writer instead." Text and email replies in the main loop now retry the writer once and then hold; the rest below still edits words. "Still on main" is stated in the When-it-fires column.

#Family and gatesWhere (origin/main)What it checksDecides byWhen it firesWho releases, from whereAdded, and why30-day fires at the three customers (source)Sampled right / wrong(a) Master page section(b) Fact protected, verdict(c) Fixtures: true fire / no false fire
W1Internal-text strips: decision-why marker, reasoning preamble, history sent-time stamp, typed tool-call markup, internal-prompt leak (can replace the whole reply with 'Hey there! I'm Clara. What can I help you with?'), first-email prompt-leak strip at sendconversation-manager.ts:14313, :14338, :14373, :14407, :14459; safety/internal-prompt-strip.ts:37, :70; outbound-safety-pipeline.ts:227Removes text the model wrote that is not for the renter.FACT (a pattern in the text)Strip; substitute a canned line when nothing is left. Still on main (left for 'PR D', not started).Trace step on most; the first-email strip at send logs nothing.#629 May 5 (prompt leak); #5257 Aug 2 (typed tool calls); #6159 Aug 23; #14874 Oct 1 (Western Slope reply opened with the stamp); #21599 Oct 21 (SMS opened with the model's plan)History-stamp strip: Western Slope 4, JP&Co 2. Prompt-leak strip: 0 at customers. Source: AgentTrace.Not tallied (pre-strip text not kept).NOT ADDRESSED by name; 'checks that only block' implies block and retry.Protects: no internal text reaches a renter. Verdict: KEEP AS A CHECK (block and retry), delete the strip part.None today.
W2Draft salvage and empty-final fallbackconversation-manager.ts:14214 (intermediate-draft-drop-guard.ts:261), :14256 (empty-final-fallback.ts:62)Merges a link or price from the pre-lookup draft back into the reply; replaces an empty final reply with earlier text.FACTAppend / substitute. Still on main.Trace step (salvage); log only (fallback).#6278 Aug 25 (Camellia: the application link sat in the undelivered draft); #18626 Oct 10No record found at customers: unmeasured, not zero.Not sampled.NOT ADDRESSED.Protects: a promised link or price is not dropped. Verdict: DEFER TO NEW ENGINE (one writer call per turn removes the second draft).None today.
W3Same-turn hand-off rewrites: unreached-forward promise line, first-touch promise-clause strip, template replacementconversation-manager.ts:16661 (:3064), :16726 (:2693), :16757 (:2600, :1453)When Clara forwarded to the team this turn, her 'the team will follow up' sentence is swapped, cut, or the whole reply replaced by a template.PROVENANCE (did the forward reach anyone) + POLICYRewrite / strip / substitute. Still on main (named as left out by the main-loop no-rewrite change).Log only; template replies carry kind escalated_thread_ack.#5640 Aug 10; #7119 Sep 5; #11980 Sep 24 (hand-off leak); #21395 Oct 20Hand-off promise rewrites: Western Slope 2, JP&Co 1. Source: AgentTrace (promise_backing).2 read: both right (unbacked 'I've flagged this to the property team right away' became the standard line).askState(thread): 'before I say it's with the team, is it?' COVERED as a check.Protects: a promise is backed by a real ask. Verdict: DEFER TO NEW ENGINE (askState blocks instead of rewriting).Promise without backing: goldmine repro 04 (exists).
W4Voice and video rewrite mode: redraft shown its draft, video WO-claim cut, video WO-confirmation append, PII redact and redraft, hallucination canned line, anomaly holding line, outbound-policy rewrites (promise, booking, availability), blank-replacement fallback with an em dash and an unbacked promise, spoken releaserconversation-manager.ts:14568, :15010, :15318, :15385, :15584, :16021, :14193; compliance/outbound-safety.ts:82, :523; policies/promise-backing-policy.ts:316; booking-promise-policy.ts:85; availability-disclosure-policy.ts:51On calls and video a failed check edits the words instead of holding (a call cannot wait).FACT and POLICYRedraft / strip / substitute / append. Kept on purpose.Trace steps; booking-promise logs.#9635 Sep 18; #14348 Oct 1 (zoom.us/j/[REDACTED] reached a prospect); #14353 Sep 30; #15679 Oct 2; #5921 Aug 19 (blank fallback)Booking-promise regenerate: Western Slope 3, JP&Co 3 (not split by channel). Source: CloudWatch.Spot-read: mostly right.#rh-d2 'Voice in v1?' open. NOT ADDRESSED.Verdict: DEFER TO NEW ENGINE; the blank fallback's own copy breaks two of Fede's rules today.None today.
W5Staff-facing rewrites: turnover fabrication, turnover async honesty, turnover edit honesty, staff-desk ref echo and write-claim rewriteconversation-manager.ts:16219, :16253, :16401, :16412, :16425; turnover-edit-honesty-guard.ts:466Replaces a reply to a property manager that claims work no tool did.PROVENANCESubstitute a fixed line. Still on main. Staff, not renters.Record on the row; critical log.#2254 Jun 11 (Clara told a PM '5 work orders created' that never existed); #2331, #2431 Jun; #20602 Oct 17Not counted (staff only).Not sampled.NOT ADDRESSED.Verdict: DEFER TO NEW ENGINE.None today.
W6Email template: greeting prepend, HTML greeting, internal staff wrapper, greeting moved to the top, English or Spanish shell, footer, signature and preheader, markdown stripagents/clara/lib/email/clara-reply-template.ts:56, :142, :223 to :238, :298 to :372, :414; strip-markdown.ts:28Wraps Clara's email in a fixed shell and adds or moves the greeting.FACT + POLICYAppend / reorder / strip. Still on main; the greeting move into the writer is an open issue (#22299).Nothing logged; the saved row is the writer's text, so the row and the sent email differ.Mar 20 (threaded HTML email); #393 Apr 24 ('Hi Sydneylavigne727,'); #5057 Jul 30 (markdown reached prospects); #11371 Sep 23 ('Hi Alexis... Hi Alexis'); #17500 Oct 7 ('Hi' on top of 'Hola')Runs on every Clara email; no log, so no count.Not sampled.NOT ADDRESSED.Verdict: greeting moves to the writer as already planned; footer and signature are the company's fixed words and can stay.None today.
W7Email-bounce text fallbackndr-bounce.ts:337 to :347, :533A bounced email is cut to about 500 characters and re-sent by text inside fixed wording, with 'Reply STOP to opt out.'PROVENANCE + FACT + POLICYStrip / truncate / append. Still on main.Message kind bounce_fallback_sms.#6010 Aug 20 (a Zillow lead's full Gmail inbox)No record found at customers: unmeasured, not zero.Not sampled.NOT ADDRESSED.Verdict: DEFER TO NEW ENGINE.None today.
W8Side writers to renters: maintenance relay dash redraft then template, staff-answer rephrase then verbatim, staff-answer scrub, cadence writer failure template, cadence Subject and sign-off cuts, renewal held-text re-render, reviewer Slack feedback redraft, tour-arrival translation, crash fallback linestemporal/activities/maintenance-comms.ts:440; escalation/reply-release.ts:2563; escalation/decision-request.ts:1382, :1541; leasing/generate-followup-message.ts:411, :741; renewal-batch/release-render.ts:155; escalation/review-redraft.ts:98; i18n/translate.ts:92; messaging/fail-open-fallback-reply.ts:134A second writer, a template or a scrub between Clara's words (or staff's) and the renter.POLICY / PROVENANCERedraft / substitute / strip. Still on main. The maintenance relay dash redraft was ADDED on Oct 24, two days after the no-rewrite rule.Mostly nothing; a few log lines.#2106 Jun 10; #5841 Aug 18 (staff sign-offs reached residents); #6193 Aug 24; #9948; #10419 Sep 24; #22236 Oct 24Not counted (most have no log).Not sampled.NOT ADDRESSED.Verdict: DEFER TO NEW ENGINE (each becomes a check on its own send door).None today.
W9Side writers to the PMS and staff: work-order judge rewrite, dispatch summary, call-note narration swap, note-shape fallback, card-note fallback, message-taking strips, missed-call note trims, two-sentence tour note, knowledge scrub, neighborhood notes, team-notice subject fallbackmaintenance/work-orders/judge.ts:452; maintenance/dispatch-summary.ts:268; voice/postcall-call-note.ts:95; pms/guest-card-note-shape.ts:156; card-notes/compose-card-note-live.ts:90; handle-capture-unknown-caller-note.ts:253; promises/missed-call-note.ts:820; prospects/guest-card-core-facts.ts:122; escalation/teaching-capture.ts:927; leasing/neighborhood-notes.ts:223; team-notify/summarize.ts:442Rewrites what Clara files in AppFolio or tells staff and vendors.POLICYRewrite / truncate / substitute. Still on main. Not renter-facing.Some record fields (adjustments, dispatchSummary); most nothing.#1230 May 21 (WO judge); #6792 (a tenant's apology paragraph paged to a tech); #10892 Sep 22 (narration, fires on 301 of 310 summaries)Not counted.Not sampled.NOT ADDRESSED.Verdict: DEFER TO NEW ENGINE.None today.
W10Transport cosmetics: HTML escaping, splitting long texts, 'Re:' subject, phone links, Graph or SendGrid body choiceclara-reply-template.ts:39, :270; twilio/sms-segments.ts:71; decision-request.ts:1297Encodes the same words for the channel.FACTEncode / split (words kept). Still on main.Status callbacks per part.#19424 Oct 14 (a 701-character Spanish reply refused by the carrier)Every send.n/an/aCosmetic, not a rewrite. Verdict: KEEP.n/a

Removed already: bare hand-off recovery, after-trace redraft, held-email redraft and greeting restore (#21992, Oct 23); name-the-home redraft and every first-email redraft and cut (#22249, Oct 24); main-loop text and email redrafts, cuts and canned lines (#22296, Oct 25); cadence template swaps (#22306); call-note failure cuts and stale held recomposes (#22321); the observe-only output gate (Oct 22); the policy-gate repair (Oct 13).

2. Gate interactions seen in the records

Gate AGate BWhat happenedSeen (30 days)Status
Tour time from this turn (H5)First-email no-tour-times (H4)The retry was told 'do not name any tour time'; its draft then failed for having no times and was held.2 (Anthony Oct 25 20:18Z, Trang Oct 26 14:41Z)Closed at 16:11Z today (first email's slots count as read); unit-covered and byte-identical on Day 0, no live run yet
Writer-call capture (the one retry)Every first-email check (H4)The capture skips any round with a tool call and every first email ends with one, so the retry never ran and the first finding became a hold.3 of 3 real draft-check holds (retried=false)Open
Send-application toolFact trace (H4)The application really went out at 15:35:30Z; the fact trace did not count its own turn's tool and held 'I've sent the application'. Half a turn: link sent, words held.1 (Patrick Oct 26)Open
Unit-count redraftBare hand-off body guard (H4)The redraft that removed the count left a body the next guard read as a bare hand-off.1 (Cheryl Oct 23)Open
Implies-prior-contact redraftFair-housing hold (H12)The redraft passed its own check, then the fair-housing judge held it.1 (Will, JP&Co Oct 4; later sent)Open
Fact-trace stripNo-tour-times redraftTwo layers rewrote the same first email on the same turn (before Oct 24, when both still edited).2 (Western Slope Oct 11, Oct 18)Both now block only
First-email hold, rerunSupervised review (H1), then 24h expiry (H3)A held first email was rerun into review, nobody looked, and it expired unsent.2 expired (Robert, Morgan); 1 rescued by hand (Trang)Open
Hold record writeIntent consumerThe consumer read the intent while it was still 'preparing' and logged an error.2 (Trang, Patrick)Open
Maintenance Supervised hold (H2)24h expiry (H3)Template notices held for review expired with nobody looking.106 of 118Open
Shared retry (H6)Final send gate (H6)The retry fixed one finding, the send gate re-checked with no retry left and held on a second one, so the record names the second check.1 (Ibrahim, JP&Co Oct 26, unbacked_promise_in_retry)Open

3. Silent gates: no record and no release

  • Agent loop: tapback, farewell loop, bare closer, video abandoned, a silent reply on video or a scheduled wake, opted-out person (trace step only), a deduplicated anomaly hold and 'the anomaly gate itself failed', dispatch policy skips (test or stress sender, thread escalated, human replied), the consent drop.
  • Leasing: every guest-card intake skip and most first-email consumer skips; 'no email on file' at the send door; cadence touch skips and reminder freshness skips; company not live at intake and prep (prep writes a reason on the intent row, but nobody is told and going live does not re-drive).
  • Doors: text-door test scope and company not live (the email door writes a blocked row for the same decisions, the text door does not); the AppFolio-mirror no-wake decision; inbound dedupe (it lets messages through if its lookup fails); harness kill switch and canary; contact ceiling.
  • Email: Zillow relay leads never answered by email, and relay leads with no renter address (only an error on the send result).
  • Quiet hours on renewal outreach: returns 'dispatched' without sending.

Almost silent (a record exists but nobody can release it from the app):

  • First-email draft-check holds (H4) write only the intent row, which keeps the current state and not the check name; 5 of 8 first-email holds this month are visible today only on their Slack card. Release is a script.
  • Main-loop parks (H6): a message row exists, but only three kinds can be released, through a Slack thread reply that runs a script. Every other park has no release path.
  • The email 'hook never asked' fallback (H1) writes a hold row but no shouldSpeak line, so it cannot be counted on its own.

Rewrite layers with no log line or record: the email template's greeting, shell, footer and markdown steps; the first-email prompt-leak strip at send; the maintenance relay dash redraft and template fallback; the staff-answer scrub; the call-note narration swap; the message-taking and missed-call trims; the two-sentence tour note; the cadence Subject and sign-off cuts.

4. What has already been done

Inspection or changeDateWhat it removed or addedWhat it missed, as shown by today's cases
Rewrite-layers measurementOct 22Replayed 78 real first emails. Found 4 dead layers to delete; kept the count check; moved tour times and name-the-home into the writer's turn. Meaning changed from the draft on 29 of 78 with every layer on.First email only. Did not count the main loop, voice, the email template or side writers; the fact trace was not isolated, and it is the gate that held Patrick today.
Prompt architecture auditOct 22 to 23Census of 138 model call sites; listed 9 rewriters after the writer. Rule: rewrite layers go once replays show they are not needed; checks that only block stay.Missed the internal-text strips, salvage, empty-final fallback, same-turn hand-off rewrites, the template, the bounce fallback, the work-order judge and the note fallbacks.
Stale tour times (#21497)Oct 20The tour-time-this-turn check also covers turns with no calendar read.Added a redraft (later a retry); widened the provenance gate that held Anthony and Trang.
Pipeline slots (#22034 / #22036)Oct 23The tour pipeline's own calendar read counts as this turn's read, so a correct reply is not held.Did not count the first email's handed-in slots; closed today at 16:11Z (#22485).
Dead first-email layers (#21992)Oct 23Deleted 4 dead layers: bare hand-off recovery, after-trace redraft, held-email redraft, greeting restore.Kept name-the-home and tour-time redrafts, removed next day.
First email block only (#22249)Oct 24Every first-email check blocks; one writer retry, then hold.The retry never ran on first emails (writer-call capture skips tool rounds): 3 of 3 real holds had retried=false. The prompt-leak strip at send stayed silent.
Main loop block only (#22296)Oct 25Text and email: every check retries once, then holds; one final send gate.Left same-turn hand-off rewrites, salvage, empty-final fallback, forced-tool retries, staff turnover guards and internal strips; voice and video keep rewrite mode. Parks still have no release path.
Cadence and call notes (#22306, #22321)Oct 25Cadence copy and post-call notes block instead of rewriting.Kept the cadence failure template and format cuts, the narration swap; wrongly called the voice PII redraft dead (its deletion issue is still open).
No dashes (#22236)Oct 24Writer rule plus a blocking check everywhere.Added a new redraft-then-template layer on maintenance relays.
Hold consolidation (#22334, #22450, #22473)Oct 25 to 26One hold function, then shouldSpeak at all 8 callers, byte-identical on 5,515 Day 0 cells; the six backstops were checked and kept; the first email asks shouldSpeak too.Covers only 'is this module Supervised'. Not the missing hold record on first-email checks, not the retry that never ran, not the 24h expiry that ate 110 holds, not the parks with no release. 'Silent' is in the type and returned by nothing.
Real-life ledger and battle testOct 26453 hold rows since Aug 31, 318 cases graded against the design; five Oct 26 cases turned into design changes and fixtures.Graded cases, not gates: no per-gate fire counts, no rewrite layers outside the first email.

5. Fix now in the current engine, or wait for the new one

One row per gate or layer with a wrong fire in the sample or a known defect. No new mechanisms: each smallest change uses a record or alert that exists today. Nothing here is built.

DefectRenter harm if left (30-day count)Smallest change in the current engineDoes the new engine make it unnecessary?RecommendationWhy
Supervised maintenance notices expire unreviewed (H2, H3)106 of 118 residents in 30 days never got 'work order created' or 'rate your repair'; sample 9 of 10 were fine template texts.Fixed-template maintenance notices skip review (or someone reviews them daily); a setting change at the customer, so it is Fede's call.No: the new engine keeps Supervised as a thin lookup and adds a review door, not a reviewer.Delete the gate (for fixed templates)The words are a fixed template over facts we hold; the hold protects nothing and loses the message. The open emergency widening goes the other way.
Tour-time provenance gate empties first emails (H5 into H4)2 first emails held in 30 days (Anthony, Trang).Already merged at 16:11Z today: the first email's slots count as this turn's read.Yes: facts block plus 'checks compare to our records' (#bt-a row 1).Fix now (done today; prove it)Unit-covered and byte-identical only; needs a real first email at the Willows end to end.
The one retry never runs on first emails (H4)Every first-email finding becomes a hold: 3 of 3 real holds this month.Writer-call capture keeps the round that ends with the declare tool, so the retry exists.Partly: the design promises 'retry once, then hold' but the page does not prove it on each path (#bt-a row 2).Fix nowWithout it every false fire is renter silence; one-line change in the capture.
Fact trace ignores its own turn's actions (H4)1 hold (Patrick, half a turn); 2 more fact-trace holds and 5 strips this month.Count this turn's tool results (application sent, tour booked) as a traced source.Yes: checks compare against our records and the turn's action ledger.Fix nowSmallest change that stops holding true statements; delete the gate when the facts block lands.
First-email holds leave no hold record (H4)5 of 8 first-email holds this month visible only on a Slack card; release is a script.Write the existing EscalationHold row for every intent hold (same record the review path already uses).Yes: #bt-changes items 2 and 3 (one hold record, one review door).Fix nowUses a record that already exists; no new state.
Held first emails expire with no alarm (H3)2 prospects (Robert, Morgan) never answered.The existing 'held first touch' alert also fires when the hold expires.Partly: review door design (#bt-e) does not name expiry.Fix nowFede: 'I don't think we should leave this unresponded to for a long time.'
Main-loop parks have no release path (H6)3 parked replies at customers this month; the renter is silent until a person writes by hand.None small; the hold record and review door are the new engine's job.Yes: #bt-changes item 3.WaitLow count, and every sampled park was right or unclear.
Forced-tool retries (H7)About 15 customer turns; the degraded reply still sends.None needed now.Yes: 'goes away' in Turn rebuilt.WaitNo renter silence; it disappears with the facts block.
Fair housing: reply loop sends, first email holds (H12)1 first email held (Will), likely a false positive.None; it is a deliberate judge.No: the judge stays.WaitOne fire, later sent; a goldmine fixture already covers the false block.
Same-turn hand-off rewrites (W3)3 rewrites at customers, both read were right.None now.Yes: askState blocks the sentence instead.WaitBreaks the no-rewrite rule, but the samples were right and the replacement is designed.
Internal-prompt strip can replace a whole reply (W1)0 fires at customers this month.Block and retry like every other check (the planned 'PR D').Implied, not named.WaitNo renter harm seen in 30 days.
Voice and video blank fallback (W4)Unknown count (no customer fire found).Its fixed copy has an em dash and an unbacked promise; change the copy.No: voice is an open decision (#rh-d2).Fix now (copy only)The line itself breaks two standing rules; one constant.
Email template adds the greeting (W6)Every Clara email; no log.Already planned: the writer writes the greeting, then the template stops adding it.No: not on the page.Fix now (already planned)The saved row and the sent email differ today.
Issue to delete the voice PII redraft is wrong (W4)If done, voice and video lose their PII handling.Correct or close the issue.n/aFix now (the issue, not code)The function is still called.
Renewal quiet-hours skip returns 'dispatched' (H14)No renewal outreach at customers this month, so none yet.Trace it before anything relies on it.No.WaitNo current harm; unverified.

6. Design observations

  • Most false fires this month came from gates that judge where a fact came from (a calendar call this turn, a sentence traced to a source) rather than the fact in our records: every sampled wrong first-email hold was one of these.
  • The biggest renter harm is not a check at all but a lifecycle: 110 of 124 holds at the three customers expired with nobody looking, so a Supervised hold behaved like a silent drop.
  • Holds live in three places (the hold row, the first-email intent row, and parked message rows) with three different release stories, and only the first can be approved from the app.
  • A first-email gate that fires produces neither a send nor a loud hand-off today: a card that tags people, a script to release, and an intent row that forgets which check fired.
  • Rewrites are mostly gone from text and email replies, but about 60 layers still change words elsewhere, and at least 17 of them leave no trace in production.
Appendix: every gate and every layer, one row each (about 315 rows, open to read)
Hold gates, about 255 (sections A to D, origin/main 137f883e7f)

Line numbers in the leasing section (C) are approximate; grep the quoted log string to land on the exact line.

A. Supervised hold (shouldSpeak) and the send doors

#Gate (plain words)file:line (origin/main 137f883e7f)What it checksDecides byWhen it fires + recordWho releases, from whereAdded (sha, date, PR) + incidentCount by (literal)
A1Supervised rule R1: reply's topic module is Supervisedsrc/lib/domain/modules/supervised-reply-rule.ts:130Topic classifier (renewal / maintenance / other) on the FINISHED reply; module stored drafts at the buildingPOLICY (module mode) + model topic verdictSilent hold with record. Text: EscalationHold source: 'clara_reply_sms', resume.kind: 'conversation_reply', reply row withheld. Email: EscalationHold source: 'clara_prospect_email'Review page, admin hold page, Slack thread reply, reviewer email reply, rollout auto-release, 24h expiry321174e9a4 2026-10-05 #16514 (Maintenance/Renewals/Collections email replies went out with nobody approving)shouldSpeak rule: "R1", holdReason: "topic"; hold reason "Clara's maintenance reply (Maintenance is Supervised at this building)" / "Clara's reply about a renewal (Renewals is Supervised at this building)"
A2R2: a renewal tool call was deferred this turnsupervised-reply-rule.ts:134Renewal action recorded instead of run (noteDeferredRenewalAction) and Renewals SupervisedPROVENANCE (what the turn did) + POLICYSilent hold with record; hold carries resume.deferredActions, run on approve (deferredActionsRanAt)Same as A173b633ec85 2026-10-21 #21646 (Willows: general-topic reply sent and renewal action ran unapproved, #21625)rule: "R2", holdReason: "topic"; hold reason suffix " - Approving also: …"
A3R3: the router sent the turn down a Supervised modulesupervised-reply-rule.ts:136Provisional routed module is SupervisedFACT (router state) + POLICYSilent hold with record (same rows)Same as A1779d00abb1 2026-10-05 #16644 (routed maintenance reply called "general" reached the door and was refused, lost and paged)rule: "R3", holdReason: "routed"
A4R4: general reply on a renewal thread / open renewal cyclesupervised-reply-rule.ts:137Thread is conv-renewal-* or tenant has an open cycle, topic other, Renewals SupervisedFACT + POLICYSilent hold with recordSame as A17f60b7dc84 2026-10-13 #19302 (Fairhaven: "looping in your property manager" line read as general, sent unapproved)rule: "R4", holdReason: "topic"
A5R5: reply to a prospect while Leasing is Supervisedsupervised-reply-rule.ts:138Recipient resolved as prospectFACT (role) + POLICYSilent hold with recordSame as A1321174e9a4 2026-10-05 #16514rule: "R5", holdReason: "prospect"; hold reason "Clara's reply to a prospect - Leasing is Supervised at this building"
A6R6: topic check gave no verdictsupervised-reply-rule.ts:139-147Classifier failed; if thread lane unknown and anything Supervised, holdPOLICY (fail closed)Silent hold with record, unclearTopicSame as A1a2979107ec 2026-10-05 #16612; refined after Western Slope 2026-10-20 (timed-out check held a prospect tour reply that never went out)rule: "R6", holdReason: "no-verdict", topic: null; hold reason "Clara's reply - we couldn't tell what it is about, and this building is Supervised, so it waits for approval"
A7Urgent / emergency work-order carve-out (anti-gate)src/lib/domain/maintenance/approval-carve-out.ts (skipsSupervisedHold), used at supervised-reply-rule.ts:127, reply-hold-decision.ts:196Work order priority emergency/urgent, recipient not prospectFACTReleases the hold: sendsn/aUPDATE 10 (Sentry 7779239068, 2026-10-07)shouldSpeak verdict: "reply", holdReason: "urgent-carve-out" (door) or rule: "R1"/"R6" with verdict: "reply"
A8Text row line (asks A1-A6)agents/clara/lib/messaging/process-envelope.ts:621 (hook at 571-646, hold write at 979-1013)Above, at the deferred-row slot of the agent loop; requireLive: false (holds at a pre-launch company too); staff never heldPOLICYSilent hold with record: EscalationHold clara_reply_sms (holdDraftReplyText, renewal-reply-review.ts:176). Resident hears nothing (D13 ack excepted)Same as A101cb1b523e 2026-09-30 #13906 (gk-drafts-mode 11.1)shouldSpeak callerId: "text.row-line"; <source> Envelope "<module> drafts mode: held Clara's reply for envelope <id> (hold eschold_…) - nothing sent yet."
A9Email row line, all three email lanes + team answersrc/lib/domain/modules/supervised-reply-hold.ts:111 (scope 157); call sites process-inbound-email.ts:1892 (ses), process-pms-email.ts:423 (pms), lambda/inbound-processor/handler.ts:740 (outlook), team-answer-supervised-hold.ts:79Same rule; only at a claraLive company (else org-not-live owns it)POLICYSilent hold with record: EscalationHold clara_prospect_email, resume.kind: 'conversation_reply' (or prospect_email_unthreaded when no conversation, A16)Same as A1321174e9a4 2026-10-05 #16514callerId: "email.row-line", lane: ses/pms/outlook/team-answer; Email Ingest "Held Clara's reply for review (hold <id>, conversation <id>)"
A10Email "hook never asked" fallbacksupervised-reply-hold.ts:199If the loop never asked the row-line hook (pre-empt or router answer), hold whenever ANY module is SupervisedPOLICY (fail closed)Silent hold with record (A9 row); no shouldSpeak line for itSame as A1321174e9a4 2026-10-05 #16514No shouldSpeak line; only the Email Ingest "Held Clara's reply for review" line. Gap: not separately countable
A11Text routed backstop (after the loop)process-envelope.ts:926 (909-972)FINAL routed module Supervised, residents only, not urgentFACT + POLICYSilent hold with record; loop already wrote the row, so row is marked heldForApproval first (markReplyRowHeld); hold replyRowWritten: trueSame as A1779d00abb1 2026-10-05 #16644callerId: "text.routed-backstop", rule: "routed"; "<module> drafts mode: held Clara's reply routed to <module> for envelope …"; warn "Routed hold for envelope <id>: the loop named no reply row, so none is marked held."
A12SES / PMS / Outlook routed backstopsprocess-inbound-email.ts:2033; process-pms-email.ts:461; lambda/inbound-processor/handler.ts:1011Same as A11 for emailFACT + POLICYSilent hold with record (clara_prospect_email); PMS lane first refuses (not holds) if a teammate replied (humanRepliedRefusal, process-pms-email.ts:110)Same as A1779d00abb1 / #16644 family (supervised email net 5b, 2026-10-05)callerId: "email.ses.routed" / "email.pms.routed" / "email.outlook.routed", rule: "routed"
A13Maintenance acks answered without a Clara turnprocess-envelope.ts:828-866dispatchReason state_first_rating / state_first_resident_answer at a Maintenance-Supervised buildingFACT + POLICYSilent hold with record (clara_reply_sms, module maintenance). No shouldSpeak line (reads module state directly)Same as A1a2979107ec 2026-10-05 #16612 ("maintenance acks held not lost")"maintenance drafts mode: held the state_first_rating acknowledgement for envelope <id> (hold <id>) - nothing sent yet." (also state_first_resident_answer)
A14Handyman texts Supervised (reply to in-house handyman)src/lib/domain/maintenance/handyman-reply-hold.ts:41; used process-envelope.ts:592 and :872 (divert)Company "Handyman texts" mode = supervised and recipient is the crew/tech phone; any priorityPOLICY + FACTSilent hold with record (clara_reply_sms, module maintenance). Vendor-facing, not renterSame as A1b420c00ab3 2026-10-16 #20238 (Gera 2026-10-15: hold every handyman text)"handyman texts Supervised: held the in-house comms reply for envelope <id> (hold <id>) - nothing sent yet."; warn HandymanReplyHold "building <id> tech phone unreadable; the module's own rule decides"
A15Hold could not be written (text)renewal-reply-review.ts:351 escalateUnholdableDraftReply; called from process-envelope.ts:858, 900, 961, 1006Hold write threw, or no building/conversation/person to key itFACTNothing sent to renter. Alert to Slack #alerts WITH the words; logCritical without them. Row marked not sent if it had been marked held (markReplyRowNotSent(..., 'send_refused'))Nobody can release; a person must reply by hand01cb1b523e 2026-09-30 #13906 (Driver ruling 2026-09-29: never sent live, never dropped silently)logCritical('DraftReply', 'A Supervised <Maintenance/Renewals/Leasing/Collections> message could not be held and was NOT sent'); Slack title "Supervised reply could not be held - not sent"; if the post fails: "The #alerts post for a drafts reply that was not sent also FAILED; the reply's words are lost, open the conversation"
A16Prospect email with no conversation (unthreaded)src/lib/domain/messaging/send-clara-prospect-email.ts:397-414Review mode on, no conversationIdFACTSilent hold with record: EscalationHold resume.kind: 'prospect_email_unthreaded' keyed (org, recipient, subjectHash)Same as A12eed66375d 2026-09-23 #11269 (#11211: unthreadable draft fell through the gate and went out unheld)hold reason "… - no conversation could be resolved for it"; Email Ingest "Held Clara's reply for review (hold <id>, no conversation)"
A17Prospect email hold could not be writtensend-clara-prospect-email.ts:415-431Hold write threwFACTNothing sent; Slack alert (alertUnheldableProspectEmail) with recipientNobody; person replies by hand2eed66375d 2026-09-23 #11269logError('Email Ingest', 'Review mode is on and this reply could NOT be held (…) - dropping it unsent (property <id>, subject <hash>).'); result error "review hold could not be created - not sent"
A18Newer draft replaces older held draftsrc/lib/domain/escalation/held-text.ts:1007 (called renewal-reply-review.ts:225)Another pending clara_reply_sms hold on the same conversationFACTOlder hold rejected (nothing sent for it), held row marked not sentNobody (by design)a837f94f8f 2026-09-30 #14241 (gk-drafts-mode 11.3)resolvedBy: "system:draft-superseded"; HeldText "Held text <id> withdrawn: a newer draft on this conversation replaced it."
A19Text door: module OFFsrc/lib/integrations/twilio/client.ts:1111-1196Module declared by the send is stored OFF (or no company named)POLICYNothing sent nothing said to renter. MODULE_REFUSAL# row; page to Sentry for maintenance or repliesNobody (turn module on)3c9968d5db 2026-09-25 #12142 (refusal row); page a839379b5c 2026-10-07 #17560Twilio "Outbound SMS to <masked> held - module <m> is not enabled for this company (<m>_module_off)"; logCritical OFF_REFUSED_PAGE "Outbound text refused: <Module> is Off at this building"; module-refusal "channel=sms module=<m> reason=module_off …"; MODULE_REFUSAL reason: module_off / module_unresolved
A20Text door: Supervised drafts backstoptwilio/client.ts:1198-1249Send at a Supervised building carries no draftApprovalId (a lane missed its hold); waived for the exact held-reply ack text (isHeldReplyAckText) and urgent carve-outPOLICYNothing sent nothing said. MODULE_REFUSAL# row, Sentry pageNobody2bad0cc8ef 2026-09-30 #14235callerId: "text.door", rule: "door", holdReason: "module_drafts"; logCritical Twilio "Outbound text refused: <Module> is in drafts at this building and the send carried no approval - an upstream lane missed its hold"; MODULE_REFUSAL reason: module_drafts
A21Email seam step 2: module OFFsrc/lib/integrations/email/company-live-gate.ts:~400-453Declared module not enabledPOLICYNothing sent. EMAIL_LOG# BLOCKED row + MODULE_REFUSAL# rowNobody0b596ceb7f 2026-09-19 #9988 (audit: 38 lanes, zero readers of the module flag)"Held: module <m> is not enabled (<reason>) for org <id> …"; MODULE_REFUSAL channel: email, reason: module_off / module_unresolved
A22Email seam step 2b: Supervised drafts backstopcompany-live-gate.ts:455-495draftApprovalId === null at a Supervised buildingPOLICYNothing sent. EMAIL_LOG BLOCKED, Sentry page, MODULE_REFUSALNobody9924d6ba50 2026-10-05 #16495callerId: "email.door"; EMAIL_LOG errorMessage: "<module>_module_supervised"; logCritical "Outbound email refused: <Module> is Supervised at this building and the send carried no approval - an upstream lane missed its hold"; gate result reason: "module_supervised"
A23First email Supervised holdshould-speak.ts:152 (caller clara-guest-card-first-email-send.ts:758)Leasing drafts at a claraLive company (R5)POLICYSilent hold with record (see leasing table row A65)Review page, admin hold page, Slack thread reply961cf34d93 2026-10-26 #22473 (moved into shouldSpeak)callerId: "email.first-touch", rule: "R5"
A24Proactive renewal texts held (offer, reminder)src/lib/domain/leasing/renewal-orchestration/renewal-text-review.ts:73; callers src/lib/temporal/activities/renewal.ts:988, 1519, 2297Renewals drafts at the building, or the lease's monthly batch not approvedPOLICYSilent hold with record: EscalationHold renewal_outreach_sms / renewal_reminder_sms, workflow_signal resume; may be parkedForBatchSame as A1; batch list approval1b66316ad2 2026-09-28 #12977hold reason "The renewal offer text (Renewals is Supervised at this building)" / "(waiting for next month's renewal list)" / "(on this month's renewal list)"; refused kinds "approved hold not found", "hold is <state>, not approved", "approved hold is for a different send"
A25Renewal no-phone email heldrenewal-email-review.ts:57Same, emailPOLICYSilent hold with record renewal_outreach_emailSame3272c60b88 2026-10-02 #15085reason "The renewal offer email, with the renewal letter (…)"; warn RenewalEmailReview
A26Renewal change-term text, offer/portal text, after-call recaprenewal-reply-review.ts:58, 95Renewals SupervisedPOLICYSilent hold with record renewal_change_term_sms / renewal_offer_text_smsSame8a3c61885a 2026-10-02 #15077; ffd8ede127 2026-10-05 #16501reason "Confirms the renewal term the resident changed to (Renewals is Supervised at this building)"
A27Lease-ending / month-to-month warning textsrc/lib/domain/leasing/renewal-auto-start.ts:2690Renewals SupervisedPOLICYSilent hold with record renewal_expiry_warning_smsSame; next renewal scan sends after quiet hours533f4dbd8f 2026-10-02 #15083source: renewal_expiry_warning_sms
A28Automatic maintenance texts/emails held (rating ask, WO notices, vendor relay, forward/stand-down)src/lib/domain/maintenance/maintenance-text-review.ts:63, 161; rating.ts:854Maintenance Supervised and not emergency/urgentPOLICY + FACTSilent hold with record maintenance_resident_sms / maintenance_vendor_sms / maintenance_resident_email / maintenance_vendor_email, maintenance_rerun resume (approve re-runs every check). Hold write failure: refused HOLD_UNWRITABLESame as A179a0d35abf 2026-10-05 #16508; 3719bbe139 2026-10-06 #16855; fa0a2a56ac 2026-10-06 #16919source values above; refused reasons "approved hold is for a different address", "no company to hold the handyman text against"
A29Handyman automatic textssrc/lib/domain/maintenance/handyman-text-review.ts:24Handyman texts mode supervisedPOLICYSilent hold with record (maintenance_vendor_sms)Same45252d9726 2026-10-16 #20060source: maintenance_vendor_sms
A30Zillow relay lead never answered by emailagents/clara/lib/email/decide-email-send-mode.ts:150 (used process-inbound-email.ts:1997)Sender is Zillow-family relay and the listing-site email setting is offFACT (sender) + POLICYNothing sent nothing said (inbound recorded)Nobody17a47ee2e7 2026-09-16 #8896 (Fede 2026-09-15)send result error: "zillow_relay_never_answered_by_email"
A31Relay lead with no renter addressdecide-email-send-mode.ts:170Relay notification has no renter email to compose toFACTNothing sent nothing saidNobodydcbe07af7f 2026-08-09 #5578error: "relay lead with no renter address - refusing to email the relay mailbox"
A32Always-on reply override (anti-gate)process-envelope.ts:974-977; supervised-reply-hold.ts:224 replyNeverHeldA hold landed on emergency / team_alert / staff_replyFACTSends anywayn/a01cb1b523e #13906; email 7912f1bde9 2026-10-11 #18736logCritical <source> Envelope "Drafts hook withheld an always-on (<kind>) reply for envelope <id> - sending it anyway; its conversation row was not written."

B. Agent loop gates

B · How to read the action words

B · The gates

BA. Before the model runs (turn suppressors, SuppressingGuard union at CM:5941)

#Gate (plain words)file:lineWhat it checksDecides byWhen it firesWho can release, from whereAddedLiteral tag to count fires
1Runaway ceilingguards/runaway-ceiling.ts:170 (MAX_CONSECUTIVE_AUTO_REPLIES = 40, line 59); CM:7457, set 755340 auto-replies in a row on one threadFACT (count)The inbound is saved. Status becomes escalated with escalatedBy:'clara'. An activity log entry is written (id prefix log_runaway, type escalated). Silent hold with a record.Staff set status active with PATCH /api/conversations/[id]583fccb86b 2026-06-13 #2341. Origin: runaway conversation loops with machine senders.logCritical('Agent:runaway-ceiling', 'Runaway auto-reply ceiling reached - stopping outbound on this thread', {guard:'runaway_ceiling', consecutiveAutoReplies, ceiling}). suppressedBy:'runaway_ceiling'
2Muted personCM:7618 (checkSuppression muted===true), set 7628The person is muted. PM senders are exempt.POLICY (staff mute)The inbound is saved. One ops card per mute episode (type muted_inbound, qualifier NO REPLY SENT). Nothing sent.Staff unmute the personb6ad311807 2026-08-28 #6526. Origin: person-level mute v1.logInfo('Agent:person-mute', "Muted person on conversation ${id} - inbound persisted, no reply to them, no PM escalation email; the team gets one ops-feed card per mute episode."). suppressedBy:'person_muted'
3Tapback / reactionguards/tapback-reaction.ts:222 (recognizeReaction), 347 (findReactionTarget); CM:7727, set 7746The inbound is a phone reaction and the message it reacts to is foundFACT (text shape)The reaction is attached to (or removed from) the quoted message. No reply row. Nothing sent, nothing said.None needed. If the target is not found, the text is treated as an ordinary message.d088b46994 2026-08-29 #6552. Origin: Clara replied to tapbacks.logInfo('Agent:tapback', "Reaction ${emoji} attached to message ${msgId} on conversation ${id} - no reply turn.") (also a "REMOVED from" form). suppressedBy:'tapback_reaction'. Not-found case: "Reaction-shaped inbound ... handling as an ordinary message."
4Farewell loopguards/farewell-loop.ts:138 (FAREWELL_PRIOR_CLOSINGS_REQUIRED = 2); CM:7793, set ~7824A closing message after 2 or more closing repliesFACT (text shape + history)The inbound is saved. Nothing sent, no escalation.None. The next real inbound is answered.b1d0b958ee 2026-07-30 #5047. Origin: Clara traded goodbyes with another machine.logInfo('Agent:farewell-loop', "Farewell exchange complete on conversation ${id} - inbound closing after ${n} closing replies; suppressing (no escalation)."). suppressedBy:'farewell_loop'
5Bare closer skipguards/closer-skip.ts:426; CM:7809, set ~7824A bare "thanks" / "ok" / "bye" / glyphFACT (lexicon)The inbound is saved. Nothing sent.Nonee153c55541 2026-08-30 #6519. Origin: replying to bare thank-yous.logInfo('Agent:closer-skip', "Bare closer on conversation ${id} (rule=${rule}) - ${reason}; suppressing (no escalation)."). suppressedBy:'closer_skip'
6Escalated-thread gate (human takeover)CM:1665 (decideEscalatedGate); CM:7959 (gateCouldHold), verdict 8078, set 8248 / 8533The thread is human-owned (escalatedBy is not clara, or manuallyEscalatedAt is set) and the inbound is not a separate topic. A Haiku topic classifier can release a separate-topic inbound.PROVENANCE (who owns the thread) + POLICYThe inbound is saved. A matter is opened (openMatterRecordOnly). The team is told by email plus an ops card (notifyTeamOfGatedInbound, writerId escalated-gate.held-inbound-notice), except for a team-monitored inbox. A tour confirmation can still go out (runEscalatedTourBookingOnlyTurn). Hand-off to a person.Staff PATCH status active; a matter resolving (unmuteConversationIfResolved); a staff reply9f687a9529 2026-08-04 #5388 (team notice 9b6f71603b 2026-08-19 #5874). Origin: Clara went silent on human-owned threads.logInfo('Agent:escalated-gate', "Conversation ${id} is escalated (human-owned) - reason=${reason}; no agent loop, no tools, no reply to the tenant. Capturing inbound and notifying the team.") and the variant "...held-inbound notice suppressed (team-monitored inbox, Decision 9)." Reasons: not_taken_over, pm_sender, not_escalated, nothing_open, separate_topic, ambiguous_low_risk, held. suppressedBy:'escalated_thread'
7Takeover hold on a team-answer relayCM:8550, set 8561A human holds the thread when Clara would relay the team's answerPROVENANCENothing sent. Log only.Staff release the takeover076dae30bd 2026-10-03 #15597. Origin: the team-answer relay seam.logInfo('Agent:team-answer-turn', "Team-answer relay held on conversation ${id}: a human (${escalatedBy}) holds this thread - the relay does not talk over a takeover."). suppressedBy:'escalated_thread'

BB. Inside the loop (forced-tool retries and tool blocks)

#Gatefile:lineWhat it checksDecides byWhen it firesReleaseAddedTag to count
8First-turn leasing tool gateCM ~12547 (isFirstTurnLeasingViolation)Leasing turn 1 ended with no tool callsPROVENANCE (no lookup)Redraft with a reminder. If the retry still has no tool calls, the degraded reply is sent.Nonece3a18093d 2026-04-08 (no PR #). Origin: Mike Tappan turn 1 with no lookup.[FirstTurnViolation] Leasing turn 1 ended without tool calls ... - retrying with reminder. Then [FirstTurnViolation] Retry succeeded or [FirstTurnViolation] Retry STILL produced no tool calls - proceeding with degraded reply
9Availability-claim gateavailability-claim-gate.ts:294; CM:12717-12860The reply names unit availability with no get_available_units call this turn (reply turns too)PROVENANCERedraft with forced tool_choice. If the retry fails, the degraded reply is sent.Noneae6f8bd76e 2026-09-21 #10579 (widened #10564). Origin: Camellia conv 749affaa.[AvailabilityClaimGate] Turn N named unit availability with no lookup (units=...) ... - retrying with forced tool_choice, then forcedToolRan=, then Retry STILL called no grounding tool - proceeding with degraded reply or Retry call failed (...) - keeping the original response; proceeding with degraded reply. Trace name claude-${channel}-availabilityclaim-retry
10Tour-time claim gate (first response)tour-time-claim-gate.ts:328; same CM blockThe reply declines or offers tour times with no calendar read (get_tour_slots / check_availability)PROVENANCERedraft with forced tool_choice. The unit gate wins when both fire. If the retry fails, the degraded reply is sent.None75056437c3 2026-09-30 #14132 (first symbol commit). Origin: Western Slope conv 7ddd98a6.TourTimeClaimGate. stepName tourtimeclaim. Detail ${kind} with no calendar read (kind declined_time or offered_times)
11Typed tool call in textCM ~12870The model typed tool-call markup as textFACT (text shape)Redraft with forced tool_choice. If that fails, the markup is stripped (see #19).None245dfabf15 2026-10-01 #14348[TypedToolCall] ... retrying with forced tool_choice
12Duplicate work order (tool block)CM, trace safety:duplicate-woA matching work order is already openFACTBlocks the tool, not the message. The model replies without a new work order.Nonede5c191cb1 2026-04-04 (no PR #)checkName duplicate_wo, blockedBy safety:duplicate-wo
13Emergency guard (tool block)CM, trace safety:emergency-guardA safety emergency was detectedFACT / POLICYBlocks the toolNonede5c191cb1 2026-04-04checkName emergency_guard. Blocking ${tool} - safety emergency detected
14Staff write gatecapabilities/staff-write-gate.ts:183 (stripStaffTurnWriteTools)Staff-desk turnPOLICYWrite tools are removed. The reply can only claim what landed (see #33).None (code)b633d3a419 2026-08-19 #5900No log. The tool is absent.
15Video read-only gatecapabilities/video-read-only-gate.ts:129 (strip), 153 (refuseOnVideoReadOnlyTurn), 141 (isVideoReadOnlyRefusal)Video turn calls a write toolPOLICYThe tool is refused with error not_available_on_video (VIDEO_READ_ONLY_REFUSAL_ERROR, line 134)None73c6f92750 2026-10-02 #15342 (#15255)Tool result error not_available_on_video
16end_conversation (model chooses silence)tools/end-conversation.ts; set CM:13517/13521The model asks to end. It is refused while a duty is undischarged.POLICY (model)Approved: nothing sent, conversation resolved. Refused: the loop continues. The self-serve check (gateAllowsSelfServe, end-conversation.ts:432, CM:17298) only sets a dashboard flag, so it is NOT a message gate.Nonec434ac9c29 2026-06-24 #2625 (ADR-0070)logInfo('EndConversation', "REFUSED silence on ${id} - duty undischarged: ...") and "Silence approved on ${id}... Marking resolved.". suppressedBy:'conversation_ended'
17Video turn abandonedCM ~14029, 17279Nobody will hear the video turnFACTNothing sent, nothing recordedNone2a80fc95a6 2026-10-03 #15884 (#15487)logInfo('VideoClaraTurn', 'abandoned turn stopped; nothing recorded'). suppressedBy:'video_abandoned'

BC. After the draft (CM 14150-17125, in chain order)

#Gatefile:lineWhat it checksDecides byWhen it firesReleaseAddedTag to count
18Empty replyCM:14287-14289The model returned no textFACTNothing sent. Alert through alertNoReplySent. Video and scheduled-wake <silent> replies send nothing and raise NO alert.None245dfabf15 2026-10-01 #14348noReplyAlert('empty_reply', 'the model returned no text')
19Strip steps that can empty the reply (strip)CM:14362 (reasoning preamble), 14393 (history stamp), 14443 (typed tool call), internal-prompt strip, DecisionWhyLeakInternal text in the replyFACTStrip. When nothing is left: nothing sent plus an alert. The internal-prompt strip falls back to a fixed line.None245dfabf15 2026-10-01 #14348noReplyAlert('empty_reply','the reply was only the model\'s own reasoning'), ...'only an internal sent-time stamp', noReplyAlert('typed_tool_call_only', ...). Trace safety:reasoning-preamble-strip, safety:history-stamp-strip, safety:typed-tool-call-strip, safety:internal-prompt-strip. logCritical context ReasoningPreamble, TypedToolCall
20Intermediate-draft salvageintermediate-draft-drop-guard.ts; CM:14214The final reply dropped facts an earlier draft in the turn hadFACTAdditive only (blocked:false). It never holds. draftLeftBehind feeds #36.n/aa63c716246 2026-10-10 #18626 (fallback log)[IntermediateDraftDrop] final reply dropped N mechanical fact(s).... Trace safety:intermediate-draft-drop. empty_final_fallback
21Weekday / date mismatchCM:14744, hold 14783-14804The weekday named does not match the dateFACTRedraft (weekday-redraft). If still wrong: hold with record, guard weekday_date_guard, audit head WEEKDAY-DATE-HELD wrong weekday, Slack page (checkLabel date check).No in-app release9c5b35feee 2026-09-26 #12543logCritical('Agent','Weekday/date guard held a reply for human review - nothing was sent'). Trace safety:weekday-date-guard / weekday_date_guard
22Tour time not from this turn's calendar readtour-time-this-turn-gate.ts:249 (detectOffTurnTourTimes), 316 (correction); CM:14820, hold 14866-14884Offered times that this turn's calendar read did not returnPROVENANCERedraft (tour-time-this-turn-redraft). If still wrong: hold with record, guard anomaly_review_gate, subReason tour_time:not_in_this_turn_read. NO Slack hold page; reportFallback goes to #alerts.No in-app releasece62f94a74 2026-10-16 #20338 (hardened #22020, #22034). Origin: Willows 2026-10-16 and 10-20.Trace safety:tour-time-this-turn / tour_time_this_turn. Detail redrafted: offered X, ... or held: offered X, ..., and the redraft did not fix it. reportFallback surface clara-tour-time-this-turn. Content prefix [HELD-FOR-REVIEW anomaly:tour_time:not_in_this_turn_read]
23Unbooked tour confirmationCM:14899, hold 14931-14949 (unbackedTourConfirmation)The reply confirms a tour no booking tool bookedPROVENANCERedraft (unbooked-tour-rerun). If still wrong: hold with record (anomaly_review_gate, subReason tour_booking:unbacked_confirmation) plus alertUnbackedTourConfirmation.No in-app releasead65443706 2026-09-30 #14353. Origin: JP&Co Camellia 2026-09-30.Trace safety:tour-booking-outcome / tour_booking_outcome. Detail held: "<phrase>" confirmed a tour nothing booked, and the re-run did too. logWarn Unbooked-tour re-run failed - holding the reply
24Work-order claim (renewal threads)CM:14960, hold 14987The reply claims a work order was filed with no tool filing itPROVENANCERedraft (work-order-claim-redraft). Then hold (subReason work_order_claim:unbacked, checkLabel work order check). Voice gets the claim stripped.No in-app release2a9c46ed1b 2026-10-01 #14864'Work-order claim check held a reply for human review - nothing was sent'. Trace safety:work-order-claim
25Unit count statedCM:15029, hold 15054The reply states how many units are openFACT / POLICYRedraft (unit-count-redraft). Then hold (subReason availability:how_much_is_open).No in-app release4545dd190f 2026-10-19 #21145. Origin: WS bc17f805. [guard:${UNIT_COUNT_GUARD_ID}] held a reply for human review - nothing was sent . Trace safety:unit-count-stated
26Outbound policy: promise backingoutbound-safety.ts:307; CM:15088, hold 15186A promise with no backing actionPROVENANCERedraft (outbound-policy-promise-backing, correction "The send check stopped your reply: ${reviewReason}."). Then hold (subReason outbound_policy:promise-backing). blockOnly: textOrEmailTurn turns a rewrite verdict into a hold.No in-app releasebc642b99fc 2026-10-25 #22296 (hold semantics)'Outbound-safety policy held a reply for human review - nothing was sent'. Trace safety:promise-backing / promise_backing
27Outbound policy: booking promisesameA booking promised but not donePROVENANCESame as #26 (outbound_policy:booking-promise)samesameTrace safety:booking-promise / booking_promise
28Outbound policy: availability disclosuresameOver-sharing availabilityPOLICYSame as #26 (outbound_policy:availability-disclosure)samesameTrace safety:availability-disclosure / availability_disclosure
29Fair-housing checksame; ALERT_ONLY_POLICY_IDS = {'fair-housing'} (outbound-safety.ts:344)Fair-housing riskPOLICYAlert only: recorded, SENT, flag posted to Slack (postFairHousingFlagBounded). It never holds on main.n/ac2558720f9 2026-10-19 #21159 (dropped the hold)logWarn('Fair-housing check flagged a reply - recorded, the reply was sent, and the flag was posted to Slack', {guard:'fair_housing_flag', mode:'alert'}). Trace safety:fair-housing / fair_housing. Audit head FAIR-HOUSING-HELD for review survives only on old rows and the first-email path (#40).
30Work-order confirmation missingCM:15254, hold 15298A repair the intake filed is not confirmed in the replyPROVENANCERedraft (work-order-confirmation). Then hold (subReason work_order_confirmation:missing).No in-app releaseb6c304783c 2026-10-04 #16358'Work-order confirmation check held a reply for human review - nothing was sent'. Trace safety:work-order-confirmation
31Sensitive number (PII)CM:15336, hold 15370A sensitive number in the replyFACTRedraft (pii). Then hold (subReason pii:sensitive_number). Voice and video: redacted-redraft; if still withheld, nothing is said plus an alert.No in-app releasebc642b99fc 2026-10-25 #22296 (hold form)'PII check held a reply for human review - nothing was sent'. Trace safety:pii-strip (type pii_strip). noReplyAlert('redacted_after_redraft', ...)
32No dashesCM:15409, hold 15429An em or en dash in the replyFACTRedraft (no-dashes). Then hold (guard dash_in_reply, audit head DASH-HELD dash in reply).No in-app release995c9f204d 2026-10-24 #22236'No-dashes check held a reply for human review - nothing was sent'. Trace safety:no-dashes / dash_in_reply
33Hallucination guardguards/hallucination-guard.ts:861; CM:15461, held 15568. Runs only with an offer or tour snapshot.Renewal offer figures or tour-time follow-through not backed by data or toolsFACT / PROVENANCERedraft (hallucination-guard). Then block with record (prefix msg_blocked, head GUARD-BLOCKED hallucination) and an automatic hand-off: renewal_escalate, else notify_leasing_team, else escalate_to_human. Text and email: empty and silenced. Voice: canned line or GUARD_NO_HANDOFF_REPLY.The person the hand-off reaches; no in-app resenda786a23caf 2026-04-27 #485. Origin: legal risk on live renewal outreach.logCritical('Agent','Hallucination guard blocked an outbound message'). Not reached: 'Hallucination guard auto-fire did not reach a human - blocked thread may have no owner' with reason tool_reported_failure / no_recipient_configured / no_recipient_reached. Trace safety:hallucination-guard / hallucination_guard
34Send gate (final re-check)CM:15933, hold 15947Re-runs every deterministic check on the final text, plus unbacked_promise_in_retryFACT / PROVENANCENo retry. Hold (subReason send_gate:<finding>). Findings: weekday_date, tour_time_this_turn, unbooked_tour, work_order_claim, unit_count, outbound_policy:<id>, work_order_confirmation, pii, dash, hallucination_guard, unbacked_promise_in_retry.No in-app releasebc642b99fc 2026-10-25 #22296'The send gate held a reply - nothing was sent'. Trace safety:send-gate / send_gate. Content [HELD-FOR-REVIEW anomaly:send_gate:...]
35Anomaly Review Gatesrc/lib/agent/turn-integrity/anomaly-review-gate.ts:296; CM:15967, set 16027/16085A fatal tool failure or a turn timeoutFACTHold with record (anomaly_review_gate plus root-cause signature). Text and email: no holding line. guardAction edited / withheld. On timeout: alert. If the gate itself fails: silence. Repeats are deduped.No in-app releasee1017d39d6 2026-07-17 #4061 (ADR-0101)logCritical(..., 'Anomaly review gate held an outbound message', {cause, deduped, outageMode}). Trace safety:anomaly-review-gate. noReplyAlert('turn_timeout', ...) and ...; the review gate itself failed
36Turnover fabrication guardCM:16114 (detectsTurnoverWorkClaim)A turnover reply claims dispatch work no tool didPROVENANCEBlock with record (TURNOVER-GUARD-BLOCKED fabrication), replaced by a canned honest linen/a373867f6fd 2026-06-11 #2254 (fixed a4b2baa110 #4883)'Turnover fabrication guard blocked an outbound message'. Trace safety:turnover-fabrication-guard
37Turnover async-honesty guardCM:16245The reply says async work orders are completePROVENANCERecord (TURNOVER-ASYNC-HONESTY-GUARD-REWROTE completion framing) and a rewrite. Counts as a block plus replacement.n/a2cad9b301f 2026-06-12 #2331'Turnover async-honesty guard rewrote an outbound message'
38Turnover edit-honesty guardturnover-edit-honesty-guard.ts:466; CM:16353A claimed edit with no edit toolPROVENANCEBlock with record (TURNOVER-EDIT-GUARD-BLOCKED hallucinated edit) plus a canned linen/ad633e43e2e 2026-06-16 #2431'Turnover edit-honesty guard blocked an outbound message'. Trace safety:turnover-edit-honesty-guard
39Same-turn escalation outcomeCM:2836 (decideSameTurnEscalationOutbound); CM:16549An escalation fired this turn. What the reply becomes.POLICYTeam-monitored inbox: silenced with record (TEAM-INBOX-SILENCED bare handoff, silenceTeamInboxDraft). First touch: strip promise clauses. Others: template replacement or release.n/ae0c4e6ff40 2026-08-10 #5640; silence daf0e67de5 2026-08-20 #5985logInfo('Agent:escalated-gate', ... "reason=same_turn_escalation_team_inbox_silence"). Trace safety:team-inbox-silence (guardAction withheld). Other reasons: same_turn_escalation_substantive_release, same_turn_escalation_undelivered_promise, same_turn_escalation_first_touch_strip, same_turn_escalation, same_turn_escalation_released. suppressedBy:'team_inbox_silence' (17873)
40Supervised reply hold hookCM:16874 (replyRowHoldIf, heldBySupervisedHook)A Supervised module or the reply-topic classifier says holdPOLICYSupervised hold (see top). Decided before #41. If the hook throws, the reply is released.Approve on /review or /admin/escalation-holds/[id]82ab514237 2026-09-29 #13629 (#13009)logWarn Review-mode hold decision failed ... - releasing
41Autonomous team-note backstopCM:17003n/a (side effect only) - Not a gate. Skipped when the reply was held. - ac928e64e4 2026-09-05 #7119 (approx.)AutonomousTeamNoteBackstop
42Opted-out personopted-out-reply.ts:27; CM:17106The person opted out of everythingFACT (consent)The turn runs and the reply is withheld. Trace step only, NO row.The person texts STARTa300105ff5 2026-10-20 #21302 (#21279)logInfo('Agent:person-opted-out', "Opted-out person (scope=all) on conversation ${id} - inbound filed, turn ran, reply withheld, nothing sent."). Trace safety:person-opted-out / person_opted_out. suppressedBy:'person_opted_out'

BD. Messaging layer (after the loop, before the carrier)

#Gatefile:lineWhat it checksDecides byWhen it firesReleaseAddedTag to count
43Supervised maintenance acksPE:828First rating or first resident-answer ackPOLICYSupervised hold (state_first_rating, state_first_resident_answer)/review approve01cb1b523e 2026-09-30 #13906PE log ${module} drafts mode: held Clara's reply for envelope ... (hold ${id}) - nothing sent yet.
44Handyman texts divertPE:872; src/lib/domain/maintenance/handyman-reply-hold.ts:41A reply to the in-house handyman with the "Handyman texts" settingPOLICYSupervised hold/review approveb420c00ab3 2026-10-16 #20238holdsHandymanReply (same drafts log)
45Routed-module backstop (shouldSpeak)PE:921; src/lib/domain/modules/should-speak.ts:100The module verdict is holdPOLICYThe row is marked held (markReplyRowHeld, hold id prefix eschold) plus a Supervised hold/review approve6eafef0c9e 2026-10-08 #17564eschold hold ids
46Drafts module hookPE:979; renewal-reply-review.ts:176The module is in Supervised (drafts) modePOLICYSupervised hold. If the reply cannot be held: NOT sent plus a critical page. Module off: not sent. Always-on module: SENT anyway./review approve; rollout release01cb1b523e 2026-09-30 #13906"${module} drafts mode: held Clara's reply ...". logCritical('DraftReply','A Supervised Maintenance message could not be held and was NOT sent'). "Clara's reply not sent: Maintenance is Off at the resident's building". "Drafts hook withheld an always-on (...) reply ... - sending it anyway". "Rollout released hold ..."
47applyOutboundPolicyDE:247Stress or test sender; thread escalated; a human replied; SMS disabled (non-replies only)PROVENANCE / POLICYSkipped. Log only, no row. Throws ThreadOwnershipUnreadableError when status cannot be read.Staff release the thread6ae64094ee 2026-05-17 #1100reasons policy:stress_sender, policy:test_sender, policy:thread_escalated (logWarn 'applyOutboundPolicy' "Skipped outbound on escalated conversation ... - thread is human-owned."), policy:human_replied, policy:sms_disabled
48SMS consent (dispatcher)DE ~570 (non-replies)STOP on fileFACTDropped. Log only.START6ae64094ee 2026-05-17 #1100logWarn('SMS Consent', "Outbound to ... blocked - recipient opted out (STOP). Reason: ... Message dropped."). Trace envelope:consent_check
49Text door compliance gateTW:904 (runOutboundTextComplianceGate)Canary string; STOP / consent; AppFolio OTP number; stress sender; test-scope recipient; flipped line; module off or unresolved; Supervised backstop shouldSpeak holdFACT / POLICYBlocked. Module refusals write a record (recordModuleRefusal, reasons module_off / module_unresolved / module_drafts). Some page Slack. An unresolved module read SENDS anyway.Fix the setting or consentaad072c182 2026-09-03 #6831 (OFF page a839379b5c #17560; backstop page 7ac239ef5e #14900)logError('CANARY', 'System prompt canary detected in outbound ... - BLOCKING SEND'). logWarn('Twilio', "Outbound SMS to ... blocked - ${reason}") (refusal opted_out). '... AppFolio OTP gateway ... - BLOCKING SEND (reply-loop regression)' plus alert kind appfolio-otp-reply-loop. '... refused - ${reason}: a test building or sandbox company may text only a number listed in config/phone-registry.json'. '... held - module ${module} is not enabled for this company'. OFF_REFUSED_PAGE[module], DRAFTS_BACKSTOP_PAGE[module]. '... SENT despite an unresolved module read'
50AppFolio inbox text doorsrc/.../adapters/appfolio-inbox-text.tsThe PMS text door is on; media is attachedFACTHeld on the outbox (carrier:pms_text_held, refused:attachments_unsupported). Re-driven by drainPmsTextDoors.Automatic re-drive3615858879 2026-10-14 #19463logCritical PMS text door got a text with media: held whole, nothing sent. logWarn text held at the AppFolio door: ${reason}
51Guest-card first email pipelineoutbound-safety-pipeline.tsFirst email body: fair housing, policy, hallucinationFACT / POLICYReturns {ok:false, guard, reason}. Not sent. - (not looked up)guards first_email_body_guard, fair_housing_hold, outbound_policy_hold, hallucination_guard

B · Gate interactions

B · Fully silent gates (no reply row and no release path)

C. Leasing / prospect path gates

C · A. First email (guest card) - intake, consumer, prep, engine-turn checks, send door

#Gate (plain words)file:line (origin/main)What it checksDecides byWhen it fires + recordWho can release, from whereAddedLiteral log tag / record field / reason string
1Company not live (intake)L/guest-card-reply-intake.ts (mode skip)firstEmailMode = off because claraLive falsePOLICYEvery card at a dark company. LOG onlyNobody. Turning the company live does not re-run skipped cardsbcaec8cd66 2026-09-18 #9633guest_card_company_not_live (logInfo 'guest-card-reply-intake')
2Leasing module off (intake)L/guest-card-reply-intake.tsmodule = offPOLICYLOG onlyNobody (no re-drive)1c842aedf1 2026-10-19 #20994guest_card_leasing_off
3Card made by ClaraL/guest-card-reply-intake.tscard creator is Clara's own writePROVENANCELOG onlyNone (by design)75d4871430 2026-09-25 #12201guest_card_created_by_clara
4Home added by ClaraL/guest-card-reply-intake.tsinterested-home row was Clara's writePROVENANCELOG onlyNonefa14f54c54 2026-10-03 #15832guest_card_home_added_by_clara
5Imported as backfillL/guest-card-reply-intake.tscard came from a history importPROVENANCELOG onlyNone#9633guest_card_imported_as_backfill
6Seen before lead source was turned onL/guest-card-reply-intake.tsfirst-seen < source enabled-atPROVENANCELOG onlyNone#9633guest_card_first_seen_before_lead_source_enabled
7Arrived before go-liveL/guest-card-reply-intake.tscard time < company go-livePROVENANCELOG onlyNoned954ad91e4 2026-10-12 #19004guest_card_arrived_before_go_live
8Prospect already appliedL/guest-card-reply-intake.tsperson has an application ("He already applied. Leave it alone.")FACTLOG onlyNoneef3ea6f1bc 2026-10-05 #16461guest_card_prospect_already_applied
9Lead source not in scopeL/guest-card-reply-intake.ts via leadScopeSkip (L/lead-scope.ts)settings.leadScope {mode:'listed',sources} excludes the source (Situs list)POLICYLOG onlyEdit company leadScope; no re-drive of skipped cards8edfcc5cb7 2026-10-15 #20019guest_card_source_not_in_scope
10Already engaged (message-less card)L/guest-card-reply-intake.tscard has no inquiry text and the person is already in a conversationFACTLOG onlyNone#16461guest_card_prospect_already_engaged
11Consumer: no email on the leadsrc/lib/domain/leads/consumers/clara-first-email-consumer.tslead has no emailFACTLOG onlyNone (a later email update re-emits lead.received)7aed0e1092 2026-09-20 #10317clara_first_email_consumer_verdict {outcome:'skipped', reason:'no_email'}
12Consumer: unsupported record / bad refsamerecord kind or ref shape not recognizedFACTLOG onlyNone#10317unsupported_record_kind, unrecognized_record_ref_shape
13Consumer: person is staffsameresolved person is a staff memberPROVENANCELOG onlyNonee7574007d9 2026-10-15 #19819staff_person
14Consumer: identity settle misssameperson identity not settledFACTLOG + ALERTEngineer(consumer)person_identity_settled_miss
15Consumer: application member never mintedsamegroup member row missingFACTLOG onlyNone(consumer)application_group_member_never_minted
16Consumer: card folded into anothersamecard was folded into an existing leadPROVENANCELOG onlyNone18aff74472 #20090GUEST_CARD_FOLDED_REASON constant
17Consumer: historical lead, no inquiry rowsameold lead with no inquiry rowPROVENANCELOG + OPSNone9c2ede05f8 #12212historical_lead_without_inquiry_row; ops cause first_email_stale_skip
18Consumer: answered elsewhere / no homesameper-inquiry event without a home, or already answered on another laneFACTLOG onlyNone59d8d52ebb #11585per_inquiry_event_without_home, answeredElsewhere
19Consumer: already handled / claimedsameintent row exists or claim heldFACT (idempotency)LOG onlyn/a(consumer)already_handled, already_claimed, stale_*_claim_reported
20Consumer: vendor id on the leadsamelead id resolves to a vendorPROVENANCELOG + ALERTEngineer(consumer)alertOnSilentSkip cause lead_received_terminal_skip
21Consumer: compose kept failing for 24hsametransient compose failure past the 24h retry windowFACTINTENT heldReason compose-failed + notice + OPSscripts/guest-card-rerun-one.ts only89e43e6e66 2026-10-20 #21446compose_failed_expired
22Mailbox lane already made first touchL/clara-guest-card-reply-composer.ts (claimLeadFirstTouch)the mailbox lane holds the first-touch claimFACTINTENT heldReasonNone (by design, a reply already went)e80a5485af 2026-09-30 #14504'First touch already made by the mailbox lane - recorded, nothing sent'; heldReason first-touch-claimed-by-mailbox
23No intent row after prepare/sendL/clara-guest-card-reply-composer.ts (outcomeFor)prep wrote nothingFACT (bug)LOGNone(composer)'No ClaraFirstEmailIntent row after prepare/send - holding'
24Org lookup failed at prep (fail closed)L/clara-guest-card-engagement-prep.ts ~L440org read threwFACTINTENT heldReason org-not-liveRerun script#20994'Organization lookup failed for the first-email intent hold check - holding (fail-closed)'
25Company not live at prepL/clara-guest-card-engagement-prep.ts L445mode === 'off' (orgNotLive)POLICYINTENT heldReason org-not-live; NO alert, NO ops cardNobody is told. Rerun script only; going live does not resend#20994heldReason org-not-live
26Engine turn failedL/guest-card-engine-turn.tsroutedTo 'failed' → GuestCardEngineTurnFailedErrorFACTINTENT compose-failed / compose-rate-limited; OPS first_email_compose_failed (not for rate-limited)Consumer retry within 24h, then rerun scriptf887f80f00 2026-10-24 #22249'Compose failed while preparing the first-email intent - holding without a draft'
27Engine turn produced no replyL/guest-card-engine-turn.tsengine routed elsewhere, no textFACTINTENT no-reply; OPS first_email_no_reply; ALERTRerun script#22249'Engine turn produced no reply for this guest card - recording no-reply'; noReply.reason engine turn produced no reply (routedTo: X)
28Bare hand-off body (redraft)L/guest-card-engine-turn.ts firstEmailDeterministicFindingsbody is only "the team will reach out"FACTredraft once, then INTENT first_email_check_failed; OPS first_email_held; ALERTRerun scriptaa1807eaef 2026-09-26 #12546 (moved 50b15daf70 #21003)check bare_handoff
29Draft checks (redraft) - containerL/guest-card-engine-turn.tsruns detectFirstEmailDraftDefects (rows 30-38)FACTredraft once, then INTENT first_email_check_failedRerun script#22249check draft_checks, detail = kinds joined
30No tour times offered (redraft)L/guest-card-first-email-draft-checks.ts L462requireTourTimes && !draftOffersSlot (open home, slots on hand; off for self-guided "any time" and returning-unbooked)FACTas row 29Rerun script4944552756 2026-09-28 #13351 (170-card replay: unsized cards got no times)kind no-tour-times; snippet 'open home with tour times on hand, none offered'
31One price for all sizes (redraft)same L466draft quotes one rent while distinctRents >= 2FACTas row 29Rerun script#13351one-price-for-all-sizes
32Unit label on a single home (redraft)same L469"Unit 313" on a single-family houseFACTas row 29Rerun scriptb96313e12f 2026-09-28 #13471unit-label-on-one-home
33Hedged money fact (redraft)same L471"around/about $X" for a known rent/depositFACTas row 29Rerun script#13471hedged-money-fact
34Implies prior contact (redraft)same L473"following up / as we discussed" with no prior contactFACTas row 29Rerun scriptdaae46baf7 2026-09-29 #13568implies-prior-contact
35Size question with no tour ask (redraft)same L476open home, no slots, draft asks size but not for a tourFACTas row 29Rerun script#13568 (Camellia card 108)size-question-no-tour-ask
36Dash in draft (redraft)same L479 (findDash)em/en dash in bodyPOLICY (style)as row 29Rerun scriptffc2a036a8 2026-10-24 #22178 (Fede review set #30)dash-in-draft
37"Gone" claim on a home of unknown status (redraft)same L481says leased/unavailable while availabilityUnknownFACTas row 29Rerun scriptdb55121563 2026-10-19 #21058gone-claim-on-unknown-home
38Unbacked promise (redraft)same L483"keep you posted", "on file", "keep an eye out"; on-opening + contact-later; team-follow-up unless backed; confirm-availability unless backedFACTas row 29Rerun script083582f478 2026-10-19 #21085 (#13520 replay)unbacked-promise
39Names no home (redraft)L/guest-card-engine-turn.ts (detectNoHomeFactBody)no home fact in bodyFACTredraft, then INTENT no_home_named (when only check)Rerun script#21003check names_home; heldReason no_home_named
40Fact trace (redraft)L/guest-card-engine-turn.tsevery stated fact traces to KB/listingFACTredraft, then INTENT fact_trace_untraced / fact_trace_kb_unavailable (when only check); OPS; ALERTRerun script432715be12 2026-09-25 #12074check fact_trace, detail ${action} ${heldReason}: items
41"How much is open" disclosure (redraft)L/guest-card-engine-turn.ts (findAvailabilityDisclosures)vacancy counts / unit rosterPOLICYredraft, then INTENT first_email_check_failedRerun script4aacf771d1 2026-10-22 #21806check how_much_is_open
42PII (redraft)L/guest-card-engine-turn.ts (redactSensitivePatterns)SSN/card-like numbers or redaction markerPOLICYredraft, then INTENT first_email_check_failedRerun script#22249check pii, detail hits or 'redacted_marker'
43Send-door check pre-run (redraft)L/guest-card-engine-turn.tsruns the send-door finding at compose timeFACTas row 42Rerun script#22249sendDoorCheck finding
44Writer retry outcome (log)L/guest-card-engine-turn.tsone retry after any finding - LOG - #22249'First-email check fired - the writer\'s one retry passed' / 'First-email check fired - held after the writer\'s one retry, nothing sent' / 'First-email check retry failed - held, nothing sent'
45Deferred ask not backedL/clara-guest-card-engagement-prep.tsdraft defers a question to the team with no forward; auto-backed via backUncoveredDeferredAsks when it is the only problemFACTINTENT deferred_ask_unbacked; ALERT; NO ops cardRerun scriptcbd78a61de 2026-09-25 #12360; backing 532c33424b #12409heldReason deferred_ask_unbacked
46Safety pipeline at prepL/clara-guest-card-engagement-prep.ts → agents/clara/lib/agent/outbound-safety-pipeline.tsbody guard + policies + hallucination guard (rows 47-58)FACT/POLICYINTENT guard-blocked, no draft stamped; OPS first_email_held; ALERTRerun script9dced10129 2026-09-19 #9721'Outbound safety pipeline blocked the composed draft at prep - held, no draft stamped'
47Body guard: process narrationL/first-email-body-guard.ts L141 BLOCKING_DEFECT_KINDS"I checked our system…"POLICYguard-blocked (prep or send)Rerun script45af5487db 2026-09-23 #11252guard first_email_body_guard, reason process-narration: <snippet>
48Body guard: listing fact contradictionsamebed/bath/rent contradicts listingFACTguard-blockedRerun scriptff8e3b434c 2026-09-24 #11409 (WS 2954, 2.5 bath)listing-fact-contradiction: …
49Body guard: stale tour slotsameoffered slot no longer open/pastFACTguard-blockedRerun scriptda234858ed 2026-09-23 #11399stale-tour-slot: …
50Body guard: weekday/date mismatchsame"Tuesday Oct 28" wrong weekdayFACTguard-blockedRerun script50099278b1 2026-09-26 #12530weekday-date-mismatch: …
51Body guard: unsupported policy claimsamepet/deposit/etc. claim not in KBFACTguard-blockedRerun script#11399unsupported-policy-claim: …
52Body guard: bare hand-offsameas row 28, second line of defenseFACTguard-blockedRerun scriptaa1807eaef #12546bare-handoff: …
53Body guard: note about the prospectsameinternal note text leaked into bodyPROVENANCEguard-blockedRerun script726cdd2fd3 2026-10-25 #22314note-about-prospect: …
54Body guard: no greeting / text before greetingsamelog only, ships (and marks review holds, row 61) - LOG - 7b9d7b408b #11410no-greeting, pre-greeting-text
55Policy: promise backing (blockOnly)src/lib/domain/compliance/outbound-safety.ts (blockOnly branch)unbacked follow-up promise; "rewrite" verdict becomes a holdFACTguard-blockedRerun script9869235253 2026-08-19 #5915; blockOnly #22249guard outbound_policy_hold, reason promise-backing: Unbacked follow-up promise, held (block only)
56Policy: booking promisesame"you're booked" with no booking (tour replies)FACTguard-blockedRerun script7bf664079a 2026-09-18 #9635outbound_policy_hold, booking-promise: …
57Policy: availability disclosuresamecounts/roster of open unitsPOLICYguard-blockedRerun script#21806outbound_policy_hold, [guard:availability-disclosure] reply disclosed how much is open - removed (logWarn 'outbound-safety')
58Hallucination guard: tour time with no tooloutbound-safety-pipeline.tstour time stated not in tourSnapshotFACTguard-blockedRerun scripte2925564b7 2026-09-24 #11936guard hallucination_guard, tour_time_no_tool
59Fair housing (alert only, does NOT hold)outbound-safety.ts ALERT_ONLY_POLICY_IDSFH classifierPOLICYsends + flagged-sent cardn/a#21159event clara_flagged_sent
60Send door: no email on fileL/clara-guest-card-first-email-send.ts L382no addressFACTLOG only, no recordNone07fde39148 2026-09-18 #9425'Guest card has no email on file - nothing to send yet'
61Send door: lost claimsame L510another run owns the sendFACTLOGn/a(send door)'Another run owns this first-email send - not sending twice'
62Send door: stale tour plansame L519draft from old composer carries a tour planPROVENANCEINTENT compose-failed; ALERTRerun script40dbd0fd86 2026-10-19 #21005'First email carries a stale tour plan from the old composer - held, nothing sent'
63Send door: no stamped draftsame L536pending intent has no draftFACT (bug)INTENT compose-failed / no-reply / send-failedRerun script(send door)'Pending intent has no stamped draft - this is an upstream bug, not a reason to recompose'
64Send door: safety re-runsame L685 runOutboundEmailSafetyChecksrows 47-58 again at send (composedAt differs, can fail after a prep pass)FACT/POLICYINTENT guard-blocked; booked tour cancelled; ALERTRerun script#9721'Outbound safety pipeline blocked the stamped draft - held, not sent' {guard, reason}
65Supervised review holdsame L758 (forcedReview or shouldSpeakFirstEmail → hold; src/lib/domain/modules/should-speak.ts)company claraLive AND Leasing module = 'drafts'POLICYESC source clara_prospect_email, resume first_email_intent; INTENT heldReason review + reviewHoldIdStaff: /review or /admin/escalation-holds/[id] (ApproveRejectButtons), or Slack330cc0d61c 2026-09-19 #9948; shouldSpeak 961cf34d93 2026-10-26 #22473"Clara's first email touch held for review"; logInfo 'shouldSpeak' Clara ${verdict}: ${reason}
66Review hold marked defectivesame (gradeHeldFirstEmail)held draft has no greeting / double greetingFACTESC needsAttentionsame as 657b9d7b408b 2026-09-23 #11410'Held a first email that is defective as the reviewer will read it - the hold is marked for attention'
67Approve door refusalsL/clara-guest-card-first-email-send.ts (approve path)tour gone / approved text changed / approved text off the booked tourFACTINTENT tour-gone-at-approval / approved-text-changed / approved-text-off-booked-tourRe-review(approve path)those heldReason strings
68Review hold could not be writtensame (parkForcedReviewRun)forced-review rerun failed before the holdFACTINTENT review-hold-failedRerun script07b081cb62 2026-10-07 #17267'Review-only first-email rerun stopped before its review hold (...) - parked, nothing sent'
69Lost stamp before transportsame L966claim reclaimed by a later runFACTLOGn/a(send door)'This run lost its first-email send claim before the transport was called (reclaimed by a later run) - not sending'
70Transport: company not livesrc/lib/integrations/email/property-graph-sender.ts + src/lib/domain/organizations/clara-live.tsorg_not_live / org_unresolvedPOLICYINTENT org-not-live; NO alertNone (no resend on go-live)(clara-live)Held: company is not live yet (org_not_live) for org X (to=...) / Held: company could not be resolved for the company-live gate (org_unresolved); "Clara's first email touch held (company not live)"
71Transport: refusedproperty-graph-sender.tsopt-out, contact ceiling, budget unreadable, PMS has no card, hard bounce, module off/unresolved, test-scope recipient, module supervisedFACT/POLICYINTENT send-refused + refusalCode; ALERTRerun script after the cause is fixed9f6efc10c2 2026-09-19 #9941; test scope 9422e08273 #15863; supervised 9924d6ba50 #16495"Clara's first email touch was refused - held, and the company-live gate is not why"; refusalCode opted_out / contact_limit_reached / contact_budget_unreadable / pms_no_guest_card / hard_bounce / module_off / module_unresolved / test_scope_recipient / module_supervised; Suppressed: <to> is opted out (...) - PMS leg, nothing sent; Held: <to> is at their contact ceiling (...)
72Transport: unknown outcomesametransport threw / ambiguousFACTINTENT send-unknown; ALERTManual check, rerun script#9941"Clara's first email touch ended with an unknown outcome - held as send-unknown (nobody knows whether it delivered)"

C · B. Follow-up cadence (enrollment, touch, generator, supervised)

#Gate (plain words)file:line (origin/main)What it checksDecides byWhen it fires + recordWho can release, from whereAddedLiteral log tag / record field / reason string
73Enrollment: identity blockedL/outreach-trigger.tslead is vendor/staff/resident etc.PROVENANCELOG (record kept)None160b427906 #4332 Enrollment blocked - lead is a ${reason} (cadence not started; record kept for PM visibility)
74Enrollment: cadence turned offsameaccount follow-up sequence offPOLICYLOGSetting(trigger)'Follow-up sequence is turned off for this account - cadence not started'
75Enrollment: exhausted / joined person tracksamecadence already ran / person-level track existsFACTLOGNone(trigger)cadence-exhausted, joined-person-track
76Enrollment: portfolio lead at a dark companysameorg_not_livePOLICYLOGNone (no enroll on go-live)f8d173d799 2026-09-14 #8375'Portfolio-arrived lead - cadence not started, company not yet live (org_not_live)'
77Touch: send claim pendingPOprior touch claim in flightFACTTOUCHn/a9fc424f0dc #4321send-claim-pending
78Touch: prospect deleted / mergedPOrecord gone or mergedFACTTOUCH, stopNone(PO)prospect-deleted, prospect-merged
79Touch: lead convertedPO + outreach-stop-conditionsreplied, applied, closed, tour_booked, mergedFACTstopNoneca341b6883 2026-06-19 #2520'Outreach cadence stopping - lead converted (${stopReason})'
80Touch: vendor/solicitor threadPOperson is vendorPROVENANCEstopNonede09e23a5c #17371'Outreach cadence stopping - the person on this thread is a vendor/solicitor, not a prospect'
81Touch: person clockPOpersonStop toured_here / applied / other; foldIntoFACTstopNone3e069fd867 #18305personStop toured_here / applied / other
82Follow-up gate (model look)PO checkFollowUpGate; L/follow-up-gate.tscurrent resident, asked to stop, card closed lost/leased, tour happened staff on it, staff promise pending (wait), teammate answered and no renter reply since; fails OPEN after 8sFACTTOUCH skip/waitNone8493d49a31 2026-10-10 #18625'Outreach follow-up gate: ${decision} (${reason})'; reasons current_resident, asked_to_stop, card_closed_lost_or_leased, tour_happened_staff_on_it, staff_promise_pending, teammate_answered_no_renter_reply_since; follow_up_wake_look
83Touch: first email not sent / unconfirmedPOintent not sentFACTTOUCHNone (follows first email)f56bd3912a #17261first-email-not-sent, first-email-unconfirmed
84Touch: no property / home truth or roster unavailable / home gonePOdata reads fail or home left marketFACTTOUCH (stop on home gone)None93e033fe85 #12502; 7f7fd77f26 #10558no-property, home-truth-unavailable, roster-unavailable, home-gone
85Touch: no contact / no consent / no phonePOmissing channel or SMS consentFACTTOUCHNone63e7329220 #2825no-contact, no-consent, no-phone
86Touch: asked not to be contactedPOsuppression listFACTTOUCHNone771483ffa3 #3854'Prospect asked not to be contacted - skipping touch'
87Touch: Leasing switched offPOmodule offPOLICYTOUCHSetting (next touch)52058d95b7 #10420 Cadence ${channel} touch held - the company has Leasing switched off , reason module_off
88Touch: SMS company not livePOorg_not_livePOLICYTOUCHGo-live (next touch)8cc10fcc67 #10132'Cadence SMS touch held - company is not live'
89Touch: identical text already sentPOrepeat body on threadFACTTOUCHNone(PO)'Cadence SMS not sent - identical text already sent on this thread' (+ email twin)
90Generator check (redraft)L/generate-followup-message.ts followUpFindingdash, blast opener, pricing, policy claim, unit type, tour slot, availability:<kind>, emptyFACT/POLICYone retry, then held {check,reason} → row 91 or 92see 91/92934cc05acf 2026-10-25 #22306'Generated copy still failed a check after one retry, holding it for a person'; labels dash, blast-opener, pricing, policy-claim, unit-type, tour-slot, availability:<kind>, empty-retry
91Generator held, no workflow to wait onPOheld copy outside a Temporal wait - dispatch-skipped, NO hold recordNone#22306dispatch-skipped
92Held for a person / SupervisedPO + L/leasing-prospect-text-review.tscheck held after retry, or Leasing = SupervisedPOLICY/FACTSMSH eschold_lt_…, 24h expiryStaff: /review, /admin/escalation-holds/[id], Slack. Expiry = never sent62dbb95391 2026-10-01'Cadence SMS touch held for a person - the copy failed a check after one retry' / 'Cadence SMS touch held for approval - Leasing is Supervised at this building' / 'Cadence email touch held for approval - Leasing is Supervised at this building'
93Approved text refused at sendL/leasing-prospect-text-review.tshold not found / other property / not approved / other workflowFACTTOUCHRe-hold62dbb95391'Approved cadence text not sent - the hold did not check out'; 'approved hold not found', 'approved hold is for another property', hold is ${state}, not approved, 'approved hold belongs to a different workflow'
94Email: company not live (MISLABELED)POtransport 'suppressed' (now only company-not-live)POLICYTOUCHGo-live(PO)'Cadence email skipped - prospect opted out (suppressed)' - wrong words, see note
95Email: no mailboxPOproperty has no mailboxFACTTOUCHConnect mailbox(PO)no-mailbox

C · C. Tour reminders (prospect texts)

#Gatefile:lineWhat it checksDecides byWhen + recordReleaseAddedLiteral
96Tour not foundsrc/lib/temporal/activities/tour.tstour row goneFACTALERT (alertTourActivityFailureSkip)None(tour)tour-not-found
97Already sent this versionsameidempotencyFACTLOGn/a(tour)tour X already sent T-24h for schedule version - no-op
98Premise failedsamecancelled / declined / stale anchor versionFACTLOGNone720b1c384b #4274tour X premise failed (${premiseSkip}) - skipping reminder
99Slot lost / weekend check-in replaces / same-day or past / stale anchorsametime freshnessFACTLOGNone1feb4d012c #13749; f7f4d54d7d #13975; 87ca56d9c9 2026-06-05 #1969; 2079a753c9 #4235slot-lost, weekend-checkin-replaces, same-day-or-past, tour X stale timer anchor - skipping T-24h reminder (...)
100No prospect / test property / no phone / no outbound linesamedataFACT/PROVENANCELOGNone(tour)prospect-not-found, no-phone, no-outbound-line
101Supervised remindersameLeasing = SupervisedPOLICYSMSH/review, admin, Slackc22eff5f59 #15161reminder for tour X held for approval - Leasing is Supervised (hold ...)
102Reminder SMS skipped / module offsamesend gatePOLICYLOGSetting(tour)SMS skipped for tour X - ..., held_module_off

C · D. Prospect replies (main reply turn, CM)

#Gatefile:lineWhat it checksDecides byWhen + recordReleaseAddedLiteral
103Tour time not read this turn (redraft)CM ~L14835reply states a time not in this turn's slot readFACTretry, then PARKNonece62f94a74 2026-10-16 #20338subReason tour_time:not_in_this_turn_read; reportFallback surface clara-tour-time-this-turn; trace safety:tour-time-this-turn
104Unbacked tour confirmation (redraft)CM"you're booked" with no bookingFACTretry, then PARK + alertUnbackedTourConfirmationNonead65443706 #14353tour_booking:unbacked_confirmation
105Unbacked tour-time claim on first responseCM (detectUnbackedTourTimeClaim)times claimed with no tool callFACTretry/holdNone6fe5795759 2026-09-30 #14124detectUnbackedTourTimeClaim
106Work-order claimCM"filed a work order" without oneFACTPARKNone(CM)'Work-order claim check held a reply for human review - nothing was sent'
107Unit count statedCMhow many units are openPOLICYPARKNone#21806[guard:unit-count-stated?] held a reply for human review - nothing was sent; subReason availability:how_much_is_open
108Outbound policyCMpromise-backing / booking-promise / availability policies (blockOnly)FACT/POLICYPARKNone#22249'Outbound-safety policy held a reply for human review - nothing was sent'; outbound_policy:<policyId>
109PIICMsensitive numbersPOLICYPARKNone(CM)'PII check held a reply for human review - nothing was sent'; pii:sensitive_number
110DashCMem/en dashPOLICYPARK [DASH-HELD dash in reply]Slack card thread (dash_in_reply is releasable)995c9f204d 2026-10-24 #22236'No-dashes check held a reply for human review - nothing was sent', guard dash_in_reply
111Send gate (every text/email reply)CM ~L15948 sendGateFindingweekday_date, tour_time_this_turn, unbooked_tour, work_order_claim, unit_count, outbound_policy:<id>, work_order_confirmation, pii, dash, hallucination_guard, unbacked_promise_in_retryFACT/POLICYPARKweekday_date and dash only via Slack thread; others nonebc642b99fc 2026-10-25 #22296'The send gate held a reply - nothing was sent'; subReason send_gate:<finding>; trace safety:send-gate

C · Gate interactions

C · Gates that fire with NO record and NO release path

C · Not found on origin/main / mislabels

D. Send doors, compliance, lifecycle

D · A. Text door - runOutboundTextComplianceGate (src/lib/integrations/twilio/client.ts)

#Gatefile:lineWhat it checksByFires / record writtenReleaseAddedCount it by (literal)
1Harness kill switchtwilio/client.ts:928-930Test harness has suppressed all real sendsPOLICYAny send while harness flag on. Fake sid returned, recordSend to harness log onlyTurn harness off (env)b1f2bb5c3f 2026-06-18 #2462 (CRUCIBLE turnover voice harness)HARNESS_SUPPRESSED_SID in result sids
2Prompt canarytwilio/client.ts:940-943Body contains system-prompt canary PF-8X2M9K (prompt leak)FACT (body)Leak. No row; error logNone (message dropped)≤9edb2c2359 2026-05-04 #600CANARY / System prompt canary detected in outbound ${CHANNEL} to ${to} - BLOCKING SEND; alarm:'canary_detected'
3SMS consent / suppression (STOP)twilio/client.ts:953-989 → checkSmsSendAllowed sms-consent-gate.ts:106-131 → checkSuppression suppression-gate.ts:200Revoked consent row or suppression row for the number; lookup failure fails closed for outreachFACTOpted-out recipient. No new row (reads existing)Person texts START (webhook:338), or staff clears do-not-contact2a7745073b 2026-07-08 #3295 (consent gate + reactive opt-out); suppression f648ce4796 2026-07-15 #3859 (ADR-0092)Outbound ${CHANNEL} to ${maskPhone(to)} blocked - ${gate.reason}; reasons SMS consent revoked at ..., Communication suppressed (opted out X, scope=Y), Legacy consent lookup failed - blocked (fail-closed for outreach), Suppression lookup failed - blocked (fail-closed for outreach); refusal:'opted_out'
4AppFolio OTP gatewaytwilio/client.ts:999-1024Recipient is AppFolio's OTP short code (reply loop)FACT (number)Loop regression. Alert emittedNoned26b9e10f2 2026-06-03 #1893 (OTP reply loop on Test-Property line)... to AppFolio OTP gateway ... - BLOCKING SEND (reply-loop regression); alert kind appfolio-otp-reply-loop; alarm:'appfolio_otp_gateway_blocked'
5Stress-harness numbertwilio/client.ts:1026-1027, 484-505Recipient is a stress-test numberPROVENANCE (synthetic)Stress runs. No rowNone needed5046b0bd99 2026-07-26 #4597 (direct sends bypassed the guard)stress-guard / ... was intentionally not sent ...; field suppressedSid
6Test-scope recipienttwilio/client.ts:1055-1074 → test-scope-recipient-guard.ts:78Test building or sandbox company may text only numbers in config/phone-registry.json (login_code exempt)POLICYTest property texting a real number. No rowAdd number to registry (PR)8d9148f003 2026-10-02 #15782Outbound ... refused - ${testScope.reason}: a test building or sandbox company may text only a number listed in config/phone-registry.json; reasons test_building, sandbox_company; refusal:'blocked'
7Flipped line refusedtwilio/client.ts:1086-1087, 867-902Sending line no longer authorized (portfolio flip, address revoked)FACTText from a revoked line. Sentry warning + bake alert, deduped 24hRe-authorize the line8d41e5fa8e 2026-10-08 #17819; page 07662167fc 2026-10-22 #21870Outbound text refused: the sending line is no longer authorized to send; fingerprint flipped_head_refused; alert kind flipped_line_send_refused; reason address_revoked
8Module offtwilio/client.ts:1104-1196Company's module for this send (leasing/renewals/maintenance...) is off or unreadablePOLICYModule off. Row: recordModuleRefusal({channel, module, reason}); critical pageTurn module on (company settings)3c9968d5db 2026-09-25 #12142 (record); gate olderOutbound ${CHANNEL} to ... held - module ${module} is not enabled for this company (${entitlement.reason}) for org ...; reasons like leasing.renewals_module_off; unresolved: Outbound ... SENT despite an unresolved module read - module ...; result heldByModule
9Supervised drafts backstop (record only; rule excluded)twilio/client.ts:1197-1250Excluded R-rule refusal at the doorPOLICYrecordModuleRefusal reason:'module_drafts', DRAFTS_BACKSTOP_PAGEReview queue - module_drafts; waiver isHeldReplyAckText (1216, 1a66d97cbe 2026-10-10 #18564)
10Off means off (company not live)twilio/client.ts:1260-1274 → organizations/off-means-off.tsNot-live company sends no *notifications*; replies and on-the-line people allowed; login_code exemptPOLICYNot-live org. No rowCompany go-live4c61370c45 2026-10-20 #21381 [urgent] (Fede 10/19 "off means off")Outbound ... refused - org not live: notification suppressed (${reason}); reasons org_not_live, org_unresolved
11Contact ceilingtwilio/client.ts:1313-1317 → checkTouchBudgetTouch ledger over per-person ceiling; unreadable = refuseFACT (ledger) + POLICY (ceiling)Over budget. No row (ledger write happens only on send)Time passes (window rolls)6b3a2a712f 2026-08-03 #5232Outbound ... held - ${budget.reason}; refusal:'contact_limit_reached' or 'blocked'
12Carrier 21610 (reactive opt-out)twilio/client.ts:1366-1384; status/route.ts:109Twilio says the number is STOPped at carrierFACT (carrier)Send rejected by Twilio. Writes consent revocation (source:'twilio_21610_blocked_send' / 'twilio_21610_status_callback')Person texts START2a7745073b 2026-07-08 #3295...rejected send ... as opted-out (21610) - recorded consent revocation; refusal:'opted_out'
13Outbound call creation refusedtwilio/client.ts:321-345Twilio refuses the callFACT (carrier)No rowNone≤#600createOutboundCall to ... refused (Twilio code X)

D · B. Email seam - evaluateCompanyLiveGate + sendEmail + Graph/PMS legs

#Gatefile:lineWhat it checksByFires / recordReleaseAddedCount it by
14Test-scope recipient (email)company-live-gate.ts:358-377; guard :144Test building/sandbox may email only our own inboxes; hello@ / hello+ shared inbox refused (#20911/#20912)POLICYBLOCKED rowNot releasable (by design)9422e08273 2026-10-03 #15863 [urgent]; hello@ d13d361820 2026-10-18 #20912errorMessage 'test_scope_recipient'; log Refused: ${reason} may email only our own inboxes (test_scope_recipient) ...
15Module off (email)company-live-gate.ts:391-453Module off/unreadablePOLICYBLOCKED row + recordModuleRefusal channel:'email'Turn module on98599a1e36 2026-09-17 #9177errorMessage = entitlement reason e.g. leasing.prospects_module_off; Held: module ${module} is not enabled (${reason}) for org ...
16Supervised (email, record only)company-live-gate.ts:464-495excluded rulePOLICYBLOCKED rowReview queue - errorMessage ${module}_module_supervised; reason module_supervised; EMAIL_DRAFTS_BACKSTOP_PAGE
17Company not live (email)company-live-gate.ts:509-559; staff branch :331 sendWhenUnreadableOrg not live / unresolvablePOLICYBLOCKED rowGo-live98599a1e36 2026-09-17 #9177; staff unreadable 4c61370c45 2026-10-20 #21381errorMessage org_not_live / org_unresolved; Held: company not yet live (org_not_live) for org ...; Held: company could not be resolved for the company-live gate (org_unresolved)
18Email harness kill switchemail/client.ts:992Harness flagPOLICYstatus:'suppressed'envd94ad7200d 2026-07-29 #4898harness_kill_switch; Suppressed by harness kill switch (no send)
19Email canaryemail/client.ts:1043Canary token in contentFACTdelivery rowNoned94ad7200d #4898 (reason string); canary oldercanary_block; System prompt canary token detected in outbound content - blocked
20Reserved fake domainemail/client.ts:1064, 1110; Graph inbox-client.ts:1672; PMS property-graph-sender.ts:1240-1275@example.test / @example.invalid with no MailpitPROVENANCE (synthetic)suppressedNoned94ad7200d #4898test_recipient_no_mailpit; Graph sendReply refused - test-domain recipient is never deliverable
21Undeliverable recipientemail/client.ts:1210Address known undeliverableFACTsuppressedFix addressd94ad7200d #4898undeliverable_recipients; Blocked send to undeliverable recipient
22Prior bounceemail/client.ts:1246; inbox-client.ts:1691Address bounced beforeFACT (bounce row)suppressedClear bounce (SendGrid)d94ad7200d #4898bounce_suppressed; Suppressed: ${bounceType} bounce on ...; Graph send skipped - ${to} bounced before as not existing; mapped bounce-suppressed
23Email opt-out / muteemail/client.ts:1295; inbox-client.ts:1685; property-graph-sender.ts:458checkSuppressionFACTsuppressedPerson opts back in / stafff648ce4796 2026-07-15 #3859; Graph c82955e82e 2026-07-15 #3860opted_out; Recipient opted out of communications (...); Graph sendReply skipped - recipient opted out (${category}).
24Email contact ceilingemail/client.ts:~1396; inbox-client.ts:1700-1708Touch budgetFACT+POLICYsuppressedTime6b3a2a712f 2026-08-03 #5232contact_limit_reached, contact_budget_unreadable; Graph sendReply held - recipient at their contact ceiling. / sendReply refused fail-closed - contact budget unreadable → budget-held
25emailsEnabled kill switchemail/client.ts:1554Property/company emailsEnabled=falsePOLICYsuppressedSettingd94ad7200d #4898emails_disabled; Blocked: emailsEnabled is false
26Company-live verdict applied in sendEmailemail/client.ts:1599Result of row 14-17POLICYsuppressedas above - companyLiveDecision.reason
27Hard bounce on sendemail/client.ts:~1690Provider rejectsFACTfailedNoned94ad7200d #4898hard_bounce
28Observer BCC dropped on test scope (not a block - hello@ never copied)email/client.ts:1513Test scopePOLICY - - d13d361820 2026-10-18 #20912Send on isTest scope: observer BCC not added
29Graph-leg harnessinbox-client.ts:1661harnessPOLICY - env - harness-suppressed

D · C. Dispatch envelope and PMS doors

#Gatefile:lineWhat it checksByFires / recordReleaseAddedCount it by
30Stress / test senderagents/clara/lib/messaging/dispatch-envelope.ts:289, 292Recipient is stress/test senderPROVENANCETrace step only - 6ae64094ee 2026-05-17 #1100policy:stress_sender, policy:test_sender
31Thread escalated (human takeover)dispatch-envelope.ts:429-433; escalated-gate.ts:122Conversation is human-ownedFACT (escalation row)Trace step onlyClose escalationeac606c1ae 2026-08-04 #5400; takeover at autonomous props c9064d2042 2026-10-05 #16448Skipped outbound on escalated conversation X ... - thread is human-owned.; policy:thread_escalated
32Teammate replied (autoReplyHold)dispatch-envelope.ts:464-469; auto-reply-hold.ts; process-pms-email.ts:141A human replied on thread → autoReplyHold='human_replied' (Fede 09-03 "IF another human replies we stop")FACTHold stamped on conversation; outbound traceClear the hold on conversation (no UI found)2db2e02f0d 2026-09-03 #6870; email d18bb43283 2026-09-03 #6974Conversation X is now human-held - a teammate replied on it, so Clara will keep filing and processing but will not send.; ... a human teammate has replied on this thread (autoReplyHold=…), so Clara is not auto-replying on it.; policy:human_replied
33smsEnabled kill switchdispatch-envelope.ts:475-477smsEnabled=false (not applied to replies)POLICYtracesetting6ae64094ee #1100policy:sms_disabled
34Synthetic / shadow origindispatch-envelope.ts:520-537Envelope origin is synthetic or shadowPROVENANCEtrace - 064e8a7224 2026-05-10 #818origin:synthetic, origin:shadow
35Envelope consent (STOP)dispatch-envelope.ts:595-604 (pre-compose read :182 fails OPEN)Opt-out (skipped for replies)FACTtraceSTART6ae64094ee #1100SMS Consent / Outbound to X blocked - recipient opted out (STOP). Reason: …. Message dropped.
36Recordless lane (anti-gate: sends unheld)dispatch-envelope.ts:386No record to hold on - logCritical, sends - - logCritical at :386
37AppFolio text door holdagents/clara/lib/messaging/adapters/appfolio-inbox-text.ts:212+Door refusals: media, daily ceiling, cold session, in-flight, duplicate; plus row A gateFACT+POLICYcarrier:pms_text_held trace; alert when holdingDoor recovers / retry3615858879 2026-10-14 #19463; media b4bb2b404f 2026-10-19 #20982carrier:pms_text_held; refused:attachments_unsupported; PMS text door got a text with media: held whole, nothing sent; text held at the AppFolio door: ${reason} (daily_ceiling, session_cold, in_flight, duplicate); ALERT AppFolio text door is holding Clara texts - nothing was sent by another door
38PMS mirror wake-on-replysrc/lib/domain/pms-mirror/wake-on-reply.ts (89, 92); file-message.tsWhether a mirrored AppFolio row wakes Clara at allFACT + POLICY (role)Watch log onlyNonetenant 60ddb9fbf8 2026-10-21 #21563; teammate 55cedddedc 2026-10-19 #20992; role ea7b98fedd 2026-10-23 #22058reasons history, not_inbound, not_renter, not_text, tenant_thread, role_unknown, door_off, teammate_after_clara, clara_not_on_thread; file-message adds no_phone, wake_failed, coalesced, keyword
39Inbound escalated gate (turn)agents/clara/lib/agent/escalated-gate.ts escalatedGateSuppresses; conversation-manager.ts:7960Inbound turn on escalated thread (PM sender exempt)FACTNo reply composedClose escalation87f7f14db6 2026-08-04 #5387escalatedGateSuppresses (gate-registry escalated-gate 2026-08-04)

D · D. Opt-out sources (writers; enforcement is row 3/23/35/68)

#Gatefile:lineWhat it recordsByFires / recordReleaseAddedCount it by
40Inbound STOP on Clara's linesrc/app/api/twilio/webhook/route.ts:207-210, 333; START :338revokeSmsConsent + recordSuppression (suppression-gate.ts:483) + ops-feed cardFACTconsent + suppression rowsSTART text≤#600; card 3cbb5017ca 2026-08-29 #6570STOP keyword from ... - opt-out (Twilio handles + app DB revocation); unannounced Opt-out from ... not announced - destination number maps to no property.
41STOP on AppFolio texting linesrc/lib/domain/compliance/pms-line-opt-out.ts; pms-mirror/opt-out-keyword.tsrecordPmsLineKeyword, idempotent messageSid pms:<id>, sourceChannel PMS_TEXT_LINEFACTsuppression row; sends nothingSTART on that line17f3aa52da 2026-10-19 #20995; unplaced numbers 96a0282da0 2026-10-19 #21031sourceChannel PMS_TEXT_LINE, messageSid pms:
42Voice opt-out (tool + post-call sweep)handle-opt-out-of-communications.ts; voice-postcall-opt-out-sweep.ts:140, 384Caller asked to stopFACTopt-out event; bake alert on possibleStaff4c53c1a673 2026-07-15 #3861; flag c4f9f2b444 2026-10-17 #19767Recorded opt-out ${event.id} on ...; Opt-out already on file (scope=all ...) - no second event; opt-out captured by sweep, tool was missed - conversation X; alert voice_possible_opt_out
43Person mutesrc/lib/domain/compliance/person-mute.ts; suppression-gate.tsStaff muted the person: no automated reply; deliberate human send allowedPOLICY (staff decision)mute rowStaff unmutesb6ad311807 2026-08-28 #6526muted ${identifierType} by ${actor}; Person is muted (since X) - no automated reply; Muted - deliberate human send allowed; mute stays on
44Suppression exemptions (allow with audit)suppression-gate.tsExempt category / transactional reply to own inboundPOLICYaudit log, sends - f09851247a 2026-07-15 #3849Exempt category ... - override logged; Transactional response to the person’s own inbound - audit-logged

D · E. Quiet hours (8:00-21:00 property local; origin: Camellia tenant voice-called 10:21 PM, 2026-05-15)

#Gatefile:lineWhat it checksByFires / recordReleaseAddedCount it by
45Renewal outreach quiet hourssrc/lib/temporal/activities/renewal.ts:897, 1377, 2202, 2609; quiet-hours.ts:226Outside window (property tz) unless bypassQuietHoursPOLICY (time)NOOP that returns 'dispatched' - workflow believes it sentNext workflow ticka892561346 2026-05-16 #1001; tz fix c261d04d97 2026-09-23 #11366sendOutreachSms: quiet hours - NOOPing
46Prospect cadence quiet hoursprospect-outreach.ts:1809windowPOLICYworkflow sleeps holdMsauto5a33c8acdf 2026-06-18 #2470holdMs
47Maintenance comms / handyman pagemaintenance-comms.ts:1440-1457; tech-sms-dispatch.ts:677; maintenance/quiet-hours.tsPer-handyman window default 21:00-07:00 ('none' = opt out); emergency always sends; test property → 0POLICYheld via signal dispatch-page:${wo.id}auto at window end2f417de900 2026-06-10 #2106; c2e517dc98 2026-06-11 #2249eventId dispatch-page:${wo.id}
48Collections dun windowcollections/approved-dun-send-ops.ts:119; recipient-clock.tsProperty clock; refuses with no zonePOLICYrefusedsweep retriesd17dcc5808 2026-08-25 #6268timezone_unusable
49PMS-generated application sendpms-generated-application-send.ts:400windowPOLICY{ok:false, reason:'quiet-hours'}outbox retry27fd5d3229 2026-09-19 #9783send_application_deferred_quiet_hours
50Voice callbackescalation/voice-callback.ts:162window etc.POLICYnot placed - 315d9f1991 2026-08-19 #5904Voice callback not placed for matter X: ${decision.reason}
51MtM warning deferralrenewal-auto-start.ts:2546windowPOLICYdeferrednext scan48957836ab 2026-06-09 #2114MtM warning deferred for X: quiet hours (...) - next scan retries

D · F. Held-message lifecycle (EscalationHold / HeldMessage)

#Gatefile:lineWhat it checksByFires / recordReleaseAddedCount it by
5224h expiryheld-message-rule.ts:64; held-message-max-age.ts:17; held-text.ts:1375 expireStaleHolds; cron escalation-hold-sweepPending > 24h (unreadable createdAt = expired; parkedForBatch with unapproved batch never expires; workflow_signal holds skipped)POLICY (time)hold → rejected by system:draft-expired; email row markHeldEmailRowNotSent 'expired' (bake-gate.ts:2839); thread noteNone after expiry4480301497 2026-10-05 #16510; sweep 4c296f2c33 2026-10-05 #16590HELD_MESSAGE_EXPIRED_BY='system:draft-expired'; Expired - not sent; Expired: a held message waits 24 hours for approval.; This waited more than 24 hours for approval, so it was not sent.; prospect Expired: a draft waits 24 hours, then the team takes the thread.; sweep line considered=… expired=…; Could not expire stale hold X
53Approved, waits for send windowheld-message-rule.ts:95 heldSendTiming; held-text.ts:836Approval during quiet hours → deferPOLICYawaitingSendWindow, sendAfter; sweep sends laterauto4480301497 #16510send_now/defer/no_clock/unreadable; deferredSent= in sweep line
54Approved but no time zoneheld-text.ts (approve path); held-message-rule.tsBuilding has no tzFACTapprovedNotSent → deliveryFailed:trueFix tz, re-send manually097f55d118 2026-10-07 #17249Held text X approved by Y - NOT sent: the building has no resolvable time zone; Property X has no time zone - an approved message is timed on the default zone ...
55Approved but renewal gone / other approvedNotSentheld-text.tsRenewal workflow no longer running; handyman quiet hoursFACTdeliveryFailed:trueNone26e8fa649f 2026-09-28 #12956the renewal it belongs to is no longer running
56Superseded by newer draftheld-text.ts:1040; held-reply-supersede.ts newerReplyVerdict; bake-gate.ts:3033Newer reply on same conversationFACTwithdrawn by system:draft-supersededNonea837f94f8f 2026-09-30 #14241Not sent: a newer draft on this conversation replaced it.; Approved email X closed unsent - a newer reply replaced it
57Teammate took the threadbake-gate.ts:464 (only clara_prospect_email + conversation_reply)Staff replied since draftFACTrejected by system:human-repliedNone39dad5e50a 2026-10-05 #16608A teammate has replied on this thread since the draft was written, so it was not sent.; Hold X approve by Y did NOT send - a teammate has replied on the thread; deferred Deferred approved email X closed unsent - a teammate has replied on the thread
58Stale draft (4h / past slot)bake-gate.ts:1938, 1955, 2185Draft older than 4h or offers past tour slot (clara_prospect_email; anchor draftComposedAt ?? createdAt) - origin WS 09-22/23FACT+POLICYstays held as written (approve refused)Reject / recompose26b430bb83 2026-09-24 #11417older-than-4h, offers-a-past-slot; Hold X approve by Y did NOT send - draft is stale (reason); it stays held as written; deferred Deferred approved email X went stale (reason) - closed unsent, not rewritten
59Approved hold later dropped/bouncedbake-gate.ts:2662Provider drop after acceptanceFACTflagged not-delivered - 706d482d9f 2026-10-05 #16761Approved hold X was dropped/bounced (via) after acceptance - …
60Renewal batch gaterenewal-batch/batch-gate.tsMonthly list not approved → parkedPOLICYparkedForBatch; release reason:'list approved'Approve the monthly list917fee9d11 2026-10-09 #18320states none/approved/parked/unreadable; RenewalBatchGate / pointer read failed for lease X
61Held-reply ack (one per thread)held-reply-ack.ts decideHeldReplyAckResident texts again while reply held → one fixed ack, else silent (Gera D13)FACT - - 1a66d97cbe 2026-10-10 #18564Held list unreadable for conversation X; no ack this turn
62Team-answer under Supervised holdteam-answer-supervised-hold.tsClara reply after staff answer goes through holdPOLICYhold rowReview queue5f2ad13888 2026-10-16 #20477${heldModule} Supervised: held Clara's reply for X (hold id) - nothing sent yet.
63Handyman reply holdmaintenance/handyman-reply-hold.ts"Handyman texts" setting (Gera 10-15)POLICY - settingb420c00ab3 2026-10-16 #20238building X tech phone unreadable; the module's own rule decides
64Slack stale bump (not a block)bake-gate.ts:2971 bumpStaleHoldsPending 1h / 3hPOLICYSlack bump - 2c51916ffa 2026-08-30 #6654bumped= in sweep line

D · G. Agent-loop guards (draft parked before any door)

#Gatefile:lineWhat it checksByFires / recordReleaseAddedCount it by
65Outbound-safety policies (block)src/lib/domain/compliance/outbound-safety.ts; policies/*; conversation-manager.tspromise-backing, booking-promise, availability-disclosure (counts/rosters, 10/22)FACT (claim vs records)parked draftscripts/approve-held-draft.ts (SMS only)be0b2268d6 2026-08-02 #5285 (ADR-0123); availability 4aacf771d1 2026-10-22 #21806guard anomaly_review_gate subReason outbound_policy:<id>; Outbound-safety policy held a reply for human review - nothing was sent; [guard:...] reply disclosed how much is open - removed
66Fair housing (alert only now)outbound-safety.ts ALERT_ONLY_POLICY_IDS; fair-housing.ts:1002 (classifier error fails closed)FH classifierFACT (content)sends, records, Slack - c2558720f9 2026-10-19 #21159guard fair_housing_flag; Fair-housing check flagged a reply - recorded, the reply was sent, and the flag was posted to Slack
67ONE send gate findingsconversation-manager.ts sendGateFindingweekday_date, tour_time_this_turn, unbooked_tour, work_order_claim, unit_count, work_order_confirmation, hallucination_guard, unbacked_promise_in_retryFACTparked draftapprove-held-draft scriptbc642b99fc 2026-10-25 #22296send_gate:<finding>; The send gate held a reply - nothing was sent; Work-order claim check held …; Work-order confirmation check held …
68PII checkconversation-manager.ts (stripOutboundPII)Sensitive number in replyFACTparkedscriptbc642b99fc #22296pii:sensitive_number; PII check held a reply for human review - nothing was sent
69No dashesconversation-manager.tsEm dash in replyPOLICY (style)parkedscript995c9f204d 2026-10-24 #22236guard dash_in_reply; No-dashes check held a reply for human review - nothing was sent
70Runaway ceilingconversation-manager.ts:7468Per-conversation turn ceiling (machine loops)FACTparkedscript583fccb86b 2026-06-13 #2341 (guard); string 96e9da7df3 2026-07-26 #4606guard runaway_ceiling
71Voice/video redacted replyconversation-manager.tsReply redacted after redraftFACTno reply - - noReplyAlert('redacted_after_redraft')

D · H. First email and lead intake

#Gatefile:lineWhat it checksByFires / recordReleaseAddedCount it by
72Guest-card intake gatessrc/lib/domain/leasing/guest-card-reply-intake.tscompany not live, leasing off, created/home-added by Clara, before go-live, already applied, source not in list, already engagedPOLICY + FACTverdict logsettings / nonebcaec8cd66 2026-09-18 #9633; sources 8edfcc5cb7 2026-10-15 #20019guest_card_company_not_live, guest_card_leasing_off, guest_card_created_by_clara, guest_card_home_added_by_clara, guest_card_arrived_before_go_live, guest_card_prospect_already_applied, guest_card_source_not_in_scope, guest_card_prospect_already_engaged
73Guest-card eligibility (provenance)guest-card-reply-eligibility.tsbackfill import, first seen before source enabled, stale at first sight, assigned to a person (staff-typed cards)PROVENANCEverdict lognone42f127ee35 2026-09-18 #9671guest_card_imported_as_backfill, guest_card_first_seen_before_lead_source_enabled, guest_card_stale_at_first_sight, guest_card_assigned_to_person
74First-email consumer skipssrc/lib/domain/leads/consumers/clara-first-email-consumer.tsalready claimed/handled, compose expired, no home, identity miss, staff personFACTverdict lognone7aed0e1092 2026-09-20 #10317clara_first_email_consumer_verdict {outcome, reason}: already_claimed, already_handled, compose_failed_expired, per_inquiry_event_without_home, person_identity_settled_miss, staff_person
75First-email send door holdsclara-guest-card-first-email-send.ts:510, 519, 685, 841stale tour plan from old composer; safety pipeline blocked; another run owns sendPROVENANCE / FACTholdReview queue9dced10129 2026-09-19 #9721; claim 68dc2ca093 2026-10-01 #14711; stale plan 40dbd0fd86 2026-10-19 #21005First email carries a stale tour plan from the old composer - held, nothing sent; Outbound safety pipeline blocked the stamped draft - held, not sent; Another run owns this first-email send - not sending twice; Clara's first email touch held for review
76Lead outbox parksrc/lib/domain/leads/lead-outbox-park-alert.tsattempts >= MAX_ATTEMPTSFACTparked row + one page per org per reasonmanual re-drive89013248a4 2026-09-24 #11660alertOnParkedOutboxRows
77Resident scope (email)agents/clara/lib/email/process-inbound-message.ts; process-email-record.tsSender already lives here → no prospect reply / parkedFACT (role)status SKIPPEDnone47d5c0eec4 2026-08-08 #5573; open conv ca91896107 2026-10-05 #16478RESIDENT_SCOPE_DEMOTION_REASON (This is from someone who already lives here…); Parked for review at property X; logEmailReplyScopeSkip({gate:'queue', reason:'resident_sender'})
78Prospect cadence skipsprospect-outreach.ts:199; post-tour-chase.ts:1318; tour-workflow.ts:699, 730cooldown, claim pending, held-for-review, approval-refused, opted out; chase park 1h recheck / 14d budgetFACT+POLICYskipped unionauto5a33c8acdf #2470; 09080563f0 2026-07-23 #4413cooldown, send-claim-pending, held-for-review, approval-refused; Email chase skipped - lead opted out (suppressed); CHASE_PARK_RECHECK_MS, CHASE_PARK_BUDGET_MS

D · I. Renewals and collections

#Gatefile:lineWhat it checksByFires / recordReleaseAddedCount it by
79Renewal fully suppressed / spine gatesrenewal-auto-start.ts:329, 1031; renewal-decision-spine.ts:297; renewal-restart-gate.ts:107All channels suppressed; holdover lookup failure = suppressed; notice-to-vacate on fileFACTskipClear suppression771483ffa3 2026-07-15 #3854; spine 91fad602f8 2026-07-22 #4374; ntv 8b7f5ba028 2026-07-14 #3796suppressed_all_channels; HOLDOVER suppression lookup failed … - treating as suppressed; HOLDOVER skip X: gate G blocked (reason); ntv_on_file
80Supervised no per-tenant pagerenewal-notify.ts:241Supervised renewals never page staff per tenantPOLICY - - e6c4083d7b 2026-10-10 #18552supervised: no per-tenant page
81MtM warning suppressedrenewal-orchestration/mtm-warning-send.ts:158suppressionFACTskip - 533f4dbd8f 2026-10-02 #15083skipReason:'suppressed'
82Collections chase suppressionsrc/lib/temporal/activities/collections-chase.tsSuppressed / lookup failed (fail-closed transient)FACTchase receipt - 54f0269d2c 2026-07-29 #4848stopReason:'suppressed'; skipped:'suppression-unavailable'; Suppression lookup failed - skipping this dun touch (fail-closed, transient)

D · J. Dedupe / idempotency

#Gatefile:lineWhat it checksByFires / recordReleaseAddedCount it by
83Inbound webhook dedupe + filterssrc/app/api/twilio/webhook/route.ts:113, 138, 179, ~413, ~655; src/lib/platform/security/idempotency.ts:53 (fails OPEN)Duplicate MessageSid; AppFolio OTP inbound; machine/robot/test sender; rate limit 30/60s → 429; unmapped numberFACT/PROVENANCEno reply, no person mintednonededupe da50ad4955 2026-02-25; OTP d26b9e10f2 #1893; machine 583fccb86b 2026-06-13 #2341; rate b1c2a87386 2026-02-21Duplicate MessageSid ${messageSid}, skipping; Suppressed AppFolio OTP from ... - no envelope, no person mint; Suppressed machine/robot/test sender ... - no envelope, no person mint, no reply (runaway-loop guard); Unmapped destination Twilio number ...; DynamoDB error checking key …, allowing request through
84Cadence send claimsrc/lib/domain/leasing/outreach-send-claim.ts:104At-most-once per touchFACTclaim row - 9fc424f0dc 2026-07-22 #4321outcomes claimed, already-sent, in-flight, claim-error

D · K. Voice

#Gatefile:lineWhat it checksByFires / recordReleaseAddedCount it by
85Outbound call doorsrc/lib/integrations/voice/initiate-outbound-call.ts:278+suppression/mute, test scope, module, Supervised, contact budget. No quiet-hours or not-live branch here (callers own quiet hours)FACT+POLICYresult flagsas text doormute 018161ebdf 2026-08-29 #6558; test 7ee23bc5f6 2026-10-03 #15849; supervised ebd05d4258 2026-10-01 #14995${logLabel}: call refused - ${reason}; heldByTestScope, test_scope_${reason}; call held - module X is not enabled for this company (reason), heldByModule; call held - X is Supervised here, and Supervised places no outbound call (module_drafts); call refused fail-closed (no ceiling verdict), heldByContactBudget
86Never transfer to a number that rings Clarasrc/lib/domain/properties/clara-line-loop.ts:156, 175; handle-escalate-to-human.ts:424; escalation/human-handoff-route.ts:355; escalation/ring-list-route.ts:271; voice/personalization/route.ts:766-771Destination is a Clara line, prototype, or customer-forwarded number (WS 09-22)FACTcandidate droppedConfigure a person destinatione5aef53e84 2026-09-11 #7921; a5ff64361f 2026-09-16 #8912; 67cb204665 2026-09-20 #10209transferredTo candidate skipped - X reaches Clara (source), so it would loop the caller back; kinds property-line, prototype, customer-forwarded; dropLoop
87Settings refuse a looping catch-allsrc/app/api/settings/call-routing/route.ts:221, 230Staff types a number that rings ClaraFACT400Enter another number06bebcb042 2026-09-28 #13381LOOPS_TO_CLARA
88Muted caller, no destinationvoice/personalization/route.ts:4246Muted person, no transfer targetPOLICYcall refusedConfigure destinationb6ad311807 2026-08-28 #6526Muted caller reached a property with NO transfer destination - call refused…
89Hand-off bounce detector (alert, not a block)src/lib/domain/voice/handoff-bounce.tsTransfer came back / forwarded back / Clara called itselfFACTbake alert - 14f8458a48 2026-10-21 #21636kinds forwarded_back, came_back, clara_called_itself; problem 'handoff_bounced'; alert voice_handoff_broken
90Missed-call note gatesrc/lib/domain/promises/guards/missed-call-note-gate.ts:196Hang-up notice lacks topic or identityFACTno note - f645c55bd9 2026-09-23 #11114missing_topic_or_identity

D · Release paths

PathWhereReleases
PATCH /api/admin/escalation-holds/[id]src/app/api/admin/escalation-holds/[id]/route.ts; reviewer gate reviewerDecisionBlockedReason / isChosenReviewerOfHold (1371464485 2026-10-20 #21341)approveHeldText, rejectHeldText, approveEscalationHold, rejectEscalationHold (rows 52-60, 62, 75)
Hold pages/admin/escalation-holds/[id] (ApproveRejectButtons); /held-messages/[id] (customer reviewer); /review operations page lists via GET /api/held-emails and links to the admin detail route (HeldEmails.tsx:12)same PATCH
Slack thread reply"approve N" / "reject N: why", relayed by Agent Smith to /api/slack/events → findHoldForSlackReply (c27b2e338f 2026-10-11 #18732)escalation holds. Non-command replies go back to Smith. Slack reply in X thread Y names no hold - acting on nothing. /api/slack/interactions handles only shadow_rate: buttons, not approvals
scripts/approve-held-draft.tsoperator scriptagent-loop parked drafts (rows 65-70); SMS only, refuses this conversation has no recipient on file
Monthly renewal list approvalrenewal batchrow 60 (reason:'list approved')
Gatekeeper rolloutreleaseEscalationHoldByRollout bake-gate.ts:2304 (12ce383c1b 2026-10-23 #21900)a fixed % of Supervised replies auto-released
Opt back inSTART text (webhook:338) or staffrows 3, 12, 23, 35, 40-42
Settingscompany/property settingsmodule (8, 15), go-live (10, 17), emailsEnabled (25), smsEnabled (33), lead sources (72), handyman texts (63)
Automaticsweep cron escalation-hold-sweep (bumpStaleHolds → expireStaleHolds → sendDeferredApprovedHolds → sendDeferredCollectionsDuns); workflow sleepsrows 45-53, 64

D · Gate interactions

D · Fully silent gates (no record row, no release path)

D · Not found

Rewrite layers (sections A to C)

A. Main conversation loop (text, email, staff desk, video, voice-through-loop)

#Layerfile:lineWhat it changes (plain words)TriggerEffectWho can see / undoAdded (commit, PR, why)Still on main?Log tag / record field that shows it fired
A1In-loop re-prompts (first-turn tool gate, availability-claim and tour-time-claim gates, typed-tool-call gate)cm:12566 (FIRST_TURN_VIOLATION_REMINDER), cm:12758/12765 (AVAILABILITY_CLAIM_ / TOUR_TIME_CLAIM_VIOLATION_REMINDER), cm:12913 (TYPED_TOOL_CALL_REMINDER)Throws away a draft written before a required lookup and asks the model again with a reminder and a forced tool call. The person never sees the first draft.Pol + Fredraft (pre-final, new tool round)trace; logsce3a18093d Apr 8 (turn-1 tool gate); ae6f8bd76e #10579 Sep 21 (Clara named units without a lookup); b8c55f166f #5257 Aug 2 (Clara typed her tool calls)yes (named as left out by #22296)logWarn [AvailabilityClaimGate] / [TourTimeClaimGate] / [TypedToolCall] ... retrying with forced tool_choice; step names availabilityclaim, tourtimeclaim
A2Intermediate-draft salvagecm:14214 → decideIntermediateDraftSalvage agents/clara/lib/agent/intermediate-draft-drop-guard.ts:261When the final reply drops a URL or $ amount the pre-tool draft had, the old draft segments are merged back INTO the reply. Never on video.F (dropped fact tokens)append (merge)trace (blocked:false, detail "merged N dropped fact(s)")ce121fd357 #6278 Aug 25 (Camellia: prospect asked for the application, link sat in the undelivered draft)yes (left out by #22296)logWarn [IntermediateDraftDrop] ... merged the draft back in; step safety:intermediate-draft-drop
A3Empty-final fallbackcm:14256 → fallBackToEarlierTurnText agents/clara/lib/agent/empty-final-fallback.ts:62An empty final reply is replaced by text the model wrote earlier in the turn (before a tool call). Never on video.F (empty final)substitutelog onlya63c716246 #18626 Oct 10 (made it countable; behaviour older)yes (left out by #22296)logWarn event empty_final_fallback
A4Decision-why marker extractioncm:14313 → agents/clara/lib/agent/safety/decision-why.ts:207Removes Clara's internal [[WHY: ...]] reason line from the reply.F (marker present)stripreason stored on trace row; logCritical on malformed markerb948f520a9 #6159 Aug 23 (Clara states her real reason)yeslogCritical DecisionWhyLeak (only for malformed/mid-message)
A5Reasoning-preamble stripcm:14338 → agents/clara/lib/agent/safety/reasoning-preamble.ts:102Drops leading paragraphs where the model talks about the turn in third person ("This is a walkaway signal..."). Customer channels only, not staff desk. Empty → nothing sent.Fstriptrace (blocked:true)4320ccc0fb #21599 Oct 21 (WS SMS opened with the model's plan)yes (internal-text strip, "PR D" not done)logCritical ReasoningPreamble; step safety:reasoning-preamble-strip
A6History sent-time stamp stripcm:14373 → src/lib/agent/turn-integrity/history-stamp-strip.ts:23Removes a copied "[Sent Thursday ...]" internal header line.Fstriptrace51d0636693 #14874 Oct 1 (WS reply opened with the stamp)yes (PR D)logWarn Internal history stamp copied into a reply; step safety:history-stamp-strip
A7Typed-tool-call markup stripcm:14407 → agents/clara/lib/agent/safety/tool-call-markup.ts:143Removes tool-call markup the model typed as text, keeps the sentence around it. Empty → nothing sent.Fstriptraceb8c55f166f #5257 Aug 2yes (PR D)logCritical TypedToolCall; step safety:typed-tool-call-strip
A8Internal-prompt leak stripcm:14459 → agents/clara/lib/agent/safety/internal-prompt-strip.ts (paragraph filter :70-75)Drops any whole PARAGRAPH that quotes system context or names an internal tool. If every paragraph goes, SUBSTITUTES a canned line: "Hey there! I'm Clara. What can I help you with?" (SAFE_FALLBACK :37) or on video "Sorry, I lost my train of thought..." (:44).F (denylist phrase)strip; substitute when all droppedtrace; Sentry fatal0355aaf7cf #629 May 5 (internal prompt leak sentinel)yes (PR D). Also runs on every writer retry (cm:14630) and redraft (cm:14593)logCritical ContextLeak "Internal-prompt verbiage detected ... stripped before delivery"; step safety:internal-prompt-strip
A9Voice/video redraft (redraftReply)cm:14568A text-only rewrite where the model IS SHOWN its own draft plus a correction. Since #22296 used only on voice and video (text/email go to A10).Pol (each check)redraft (draft shown)trace "redrafted:"ad65443706 #14353 Sep 30 (Clara confirmed an unbooked tour)yes, voice/video onlytrace detail prefix redrafted:; model trace name clara-<channel>-<label>
A10ONE writer retry per turn (sanctioned)cm:14611 retryWriterThisTurn; note agents/clara/lib/agent/writer-call-capture.ts:97/108Not an edit: the writer's own call is re-sent with the finding appended; it does not see its draft. Every check below spends this one retry, then holds.Polretry (allowed by Fede's Oct 23 decision 5)trace "retried:" / held rowbc642b99fc #22296 Oct 25yesmodel trace name clara-<channel>-<label>-check-retry; step details retried:
A11Weekday/date checkcm:14748 (enforceWeekdayDates)Text/email: retry then hold. Voice/video: redraft via A9.Fretry→hold (text/email); redraft (voice/video)trace, held row weekday_date_guard9c5b35feee #12543 Sep 26 (wrong weekday reached a WS prospect)yes; block-only on text/email since #22296step safety:weekday-date-guard; logCritical Weekday/date guard held a reply
A12Tour time not in this turn's readcm:14835 (detectOffTurnTourTimes, gate agents/clara/lib/agent/tour-time-this-turn-gate.ts)Text/email only; retry then hold.Fretry→holdtrace; held row sub-reason tour_time:not_in_this_turn_readce62f94a74 #20338 Oct 16; widened #21497 Oct 20; pipeline slots #22036 (issue #22034) Oct 23yes, block-onlystep safety:tour-time-this-turn; reportFallback surface clara-tour-time-this-turn
A13Unbooked tour confirmationcm:14900Text/email/video (not voice): retry then hold.F (booking tool failed)retry→holdtrace; held row tour_booking:unbacked_confirmationad65443706 #14353 Sep 30 (Camellia "See you at 1" after both bookings failed)yes, block-onlystep safety:tour-booking-outcome
A14Work-order claim grounding (renewal threads)cm:14966 → src/lib/agent/turn-integrity/work-order-claim.ts:145Text/email: retry then hold. VIDEO (channel != voice but not text/email): the claim sentences are still CUT and the rest ships (responseText = woClaim.text, cm:15010).Ftext/email: retry→hold; video: striptrace blocked:false "stripped" on video2a9c46ed1b #14864 Oct 1 (renewal scoping eval: "A work order has been submitted" with no tool)yes; strip branch survives for videostep safety:work-order-claim; logWarn Work-order claim with no filing this turn - stripped
A15Unit count / how-much-is-opencm:15035 → src/lib/agent/turn-integrity/unit-count-stated.ts:218Text/email only (guard applies to those); retry then hold.Fretry→holdtrace; held row availability:how_much_is_open4545dd190f #21145 Oct 19 (Fede "No counts at all"); extended #21806 Oct 22yes, block-onlystep safety:unit-count-stated; log [guard:<UNIT_COUNT_GUARD_ID>]
A16Outbound safety policies (promise-backing, booking-promise, availability-disclosure; fair housing alert-only)cm:15159; responseText = safety.replyText cm:15243; framework src/lib/domain/compliance/outbound-safety.ts (blockOnly :146, apply :461/:494)Text/email: blockOnly: true → retry then hold. VOICE and VIDEO: blockOnly false, so a policy 'rewrite' verdict ships its replacement text (promise swapped for a deferral line, availability sentence removed, booking promise rewritten).Poltext/email: retry→hold; voice/video: rewrite/substitutetrace steps from the framework; MessageSafetyCheck[] stamped on the shipped row (outboundSafetyChecks)ADR-0123 framework; promise-backing / booking-promise / availability-disclosure policies (rewrite verdicts at policies/promise-backing-policy.ts:312, booking-promise-policy.ts:98/113, availability-disclosure-policy.ts:63)yes; rewrite mode survives on voice/video and on any caller that omits blockOnlyrow field safetyChecks (verdict rewrite); logMessage Outbound-safety policy held a reply
A17Work-order confirmation sentencecm:15260 → src/lib/agent/turn-integrity/work-order-confirmation.ts:127Text/email: retry then hold. VIDEO: a sentence "your repair request is in" is still APPENDED (cm:15318).F (WO filed, reply silent on it)text/email: retry→hold; video: appendtrace added "<sentence>"b6c304783c #16358 Oct 4 (real-path email E2E: repair filed, reply never said so)yes; append survives on videostep safety:work-order-confirmation detail added "..."
A18PII redactioncm:15336 (stripOutboundPII, defined cm:1289); voice/video branch cm:15385 → src/lib/domain/messaging/redacted-reply.ts:42Text/email: retry then hold (parked copy redacted). Voice/video: number replaced by [REDACTED], then a redraft, else withheld.Ftext/email: retry→hold; voice/video: redact + redrafttrace pii_strip6d3a69060c Mar 19 ("Audit AI Core" hardening); resolveRedactedReply 245dfabf15 #14348 Oct 1yes; voice/video path live (so issue #22319 "no caller left" is wrong: cm:15385 still calls it)step checkName pii_strip detail PII found and stripped; noReply cause redacted_after_redraft
A19No dashescm:15410 (enforceNoDashes, src/lib/agent/turn-integrity/no-dashes.ts)Text/email only: retry then hold.Fretry→holdtrace; held row dash_in_reply995c9f204d #22236 Oct 24 (Fede: em dash is an AI tell)yes, block-onlystep safety:no-dashes
A20Hallucination guard canned linecm:15584 safeEscalateMessage; GUARD_NO_HANDOFF_REPLY cm:6616 used at cm:15643/15656/15772/15879Text/email: retry, then hold (nothing sent, cm:15917-15920). VOICE/VIDEO: reply REPLACED by "Thanks, I'm looping in your property manager..." or "I'm not able to help with this one here, please contact your property management office...".F (unbacked $/tour time/action)text/email: retry→hold; voice/video: substituteheld row hallucination_guard (msg_blocked)a786a23caf #485 Apr 27 (renewal legal-risk guard); GUARD_NO_HANDOFF_REPLY 604d7d973f #13649 Sep 29yes; substitution survives on voice/videologCritical HALLUCINATION_GUARD_BLOCKED_MESSAGE; step safety:hallucination-guard
A21Send gatecm:15935 sendGateFinding (cm:14682)Block only: re-runs every check on the final text, holds on any finding. Not a rewrite.F/Polblocktracebc642b99fc #22296yesstep safety:send-gate, sub-reason send_gate:<finding>
A22Anomaly review gate holding linecm:16021 → src/lib/agent/turn-integrity/anomaly-review-gate.ts:296 (holding line only when channel === 'voice', :308)Text/email: true hold, nothing sent. Voice/video: reply REPLACED by a fact-free holding line ("let me check on that").F (fatal tool failure / timeout)substitute (voice/video) / block (text/email)trace guardAction: edited vs withhelde1017d39d6 #4061 Jul 17 (ADR-0101 turn integrity)yes; substitution on voice/videologCritical ANOMALY_REVIEW_GATE_HELD_MESSAGE; step safety:anomaly-review-gate guardAction
A23Turnover fabrication guard (staff/PM)cm:16219 (detectsTurnoverWorkClaim)Replaces Clara's whole reply to a property manager with one of three fixed honest lines ("I wasn't able to confirm the work plan... Reply yes").F (claims work, tool did not run)substituteheld row turnover_fabrication_guard; Sentryd633e43e2e era; claim detector a4b2baa110 #4883 Jul 29 (2026-06-11: Clara told the PM "5 work orders created" that never existed)yes (left out by #22296: "staff-facing turnover guard")logCritical TURNOVER_FABRICATION_GUARD_BLOCKED_MESSAGE; step safety:turnover-fabrication-guard
A24Turnover async-WO honesty guard (staff/PM)cm:16253Replaces the reply with "On it, lining up the work now. You'll see the work orders in AppFolio shortly."F (completion framing)substituteheld row turnover_async_honesty_guard263bb4e76d #4947 Jul 30 (Gate Run 1: "5 work orders created" while still minting)yeslogCritical TURNOVER_ASYNC_HONESTY_GUARD_REWROTE_MESSAGE; step safety:turnover-async-honesty-guard
A25Turnover edit-honesty guard (staff/PM)cm:16401 → agents/clara/lib/agent/turnover-edit-honesty-guard.ts:466Replaces a reply that claims a charge/plan edit with a fixed decline message.Fsubstituteheld row turnover_edit_honesty_guardd633e43e2e #2431 Jun 16yeslogCritical TURNOVER_EDIT_HONESTY_GUARD_BLOCKED_MESSAGE; step safety:turnover-edit-honesty-guard
A26Staff-desk ref echo strip + write-claim rewrite (staff)cm:16412 stripDeskRefEcho (agents/clara/lib/agent/desk-history-refs.ts:52); cm:16425 evaluateDeskWriteClaims (desk-write-claims.ts:182)Removes echoed internal record ids from a staff-desk text; rewrites a claim of a write that did not land.Fstrip; rewritetrace; logWarn3320d4a655 #20602 Oct 17yeslogWarn DESK_WRITE_CLAIM_UNBACKED_LOG
A27Same-turn escalation: unreached-forward promisecm:16661 → rewriteUnreachedForwardPromise cm:3064When a forward to the team reached nobody, each "the team will follow up" sentence is replaced by a fixed "unconfirmed" line; rest ships.P (forward undelivered) + Frewrite (sentence substitute)log only163c60cc3f #21395 Oct 20 (issue #21386: escalating-turn protections stop depending on the template path)yes (left out by #22296: "same-turn escalation strips")logInfo Agent:escalated-gate reason=same_turn_escalation_undelivered_promise
A28Same-turn escalation: first-touch promise-clause stripcm:16726 → stripAllHandoffPromiseClauses cm:2693On a guest-card first touch where a forward fired, every hand-off promise clause is cut and the rest ships.P + Fstriplog onlyb72611e4f6 #11980 Sep 24 (2026-09-24 leak fix, #11694 part 2)yeslogInfo reason=same_turn_escalation_first_touch_strip
A29Same-turn escalation: template replacementcm:16757 → buildBlockedDraftReplacement cm:2600 / buildEscalatedAckText cm:1453When a forward fired and the draft has no releasable substance, the whole reply is REPLACED by a templated acknowledgment (RULE 7.7 deferral or escalated_thread_ack).P (forward fired) + PolsubstituteoutboundKind = ESCALATED_ACK_KIND on the rowac928e64e4 #7119 Sep 5 (autonomous hand-off mode); verdict logic e0c4e6ff40 #5640 Aug 10yeslogInfo reason=same_turn_escalation; ... replaced by the templated acknowledgment; row kind escalated_thread_ack
A30Team-inbox silencecm:16641 / 16829 (silenceTeamInboxDraft)Withholds a bare hand-off ack on a mailbox the team reads (Decision 9). Block, not edit.P + Fblockheld row team_inbox_silencedaf0e67de5 #5985 Aug 20yesstep safety:team-inbox-silence, guardAction: withheld
A31Opt-out withholdcm:17106 (withholdsReplyAfterOptOut, ./opted-out-reply)Sends nothing to a number that opted out. Block.Polblockloga300105ff5 #21302 Oct 20yes(block)
A32Video spoken releasercm:14193 (spokenReleaser.sayFinal, SpokenReleaser per-sentence judges)On live video, the same strips (A4, A6, A7) then per-sentence judges decide what is said; what was spoken replaces the reply text.P (video) + Fstrip / drop sentencesspoken events logf2f23574e9 #15679 Oct 2yeslogSpokenEvents()

B. Side writers outside the main loop (still live)

#Layerfile:lineReceivesWhat changes (plain words)TriggerEffectRedraft/retryWho can seeAdded (commit, PR, why)Touched by a no-rewrite PR?Signal in production
B1Maintenance relay composeViaHaiku dash fix, then templatesrc/lib/temporal/activities/maintenance-comms.ts:440 (branch 462-467; fallbacks :600, :764, :945)Resident (tech's question/status), tech (resident's answer)A dash gets one redraft. Still a dash, empty or an error → a fixed template goes instead ("Quick question from the maintenance team about your work order: ...", "Resident says: ...")Polredraft → substituteredraft (draft shown)nobody (bare catch, no log)2f417de900 #2106 Jun 10. Dash redraft added by 995c9f204d #22236 Oct 24#22236 ADDED itnone
B2Staff-answer relay rephrase, then verbatim relaysrc/lib/domain/escalation/reply-release.ts:2563 (fallback :2581-2588; deterministic body :2524)Resident / prospectA model re-says a staff answer in Clara's voice. A failed fair-housing or number check, or a timeout → swapped for the scrubbed verbatim relayPol + Psubstitutefresh writerlogWarn escalation:reply-release "Own-words rephrase failed ... falling back"fa02a692ba #6193 Aug 24; only path since #16349nothat log
B3Staff-answer scrub cleanStaffAnswer / stripStaffSignOff / stripMailClientTrailersrc/lib/domain/escalation/decision-request.ts:1541, :1382, :1554 (frames :1529, :1654)ResidentCuts the staff member's sign-off, mail trailer and "tell them..." lead-in, then wraps the rest in a fixed frame. Staff words, not Clara'sPolstrip + framen/anobodya6624d7d8f #5841 Aug 18 (staff sign-offs reached residents)nonone
B4Booking-promise regenerate, then sentence rewritesrc/lib/domain/compliance/policies/booking-promise-policy.ts:85, :106; booking-promise-regenerate.ts:75Prospect, voice/video onlyRewrites a sentence claiming a tour is booked before it isPolredraft → rewriteredraftlogWarn BookingPromiseGuard; trace safety:booking-promise guardAction:edited7bf664079a #9635 Sep 18#22296 kept it for voice/videolog + trace
B5Promise-backing rewriteAutonomousPromisepromise-backing-policy.ts:316 (fn :480)voice/video onlySwaps an unbacked "someone will follow up" for the approved deferral linePolrewritenonetrace safety:promise-backing edited7d46c03e1b #12370 Sep 25#22296 kept it for voice/videotrace
B6Availability-disclosure stripavailability-disclosure-policy.ts:51-66voice/video onlyRemoves counts and rosters of open homesPolstripnonelogWarn outbound-safety [guard:availability-disclosure] ... removed4aacf771d1 #21806 Oct 22holds instead when blockOnlythat log
B7Policy runner blank-replacement fallbacksrc/lib/domain/compliance/outbound-safety.ts:523, constant :82voice/video onlyA blank replacement becomes "Thanks for reaching out - let me check on that and get back to you shortly." (has an em dash and an unbacked promise)Polsubstituten/alogError OutboundSafety "returned a blank replacementText"ab33619614 #5921 Aug 19blockOnly added by #22249that log
B8resolveRedactedReply (= A18 voice/video)cm:15385; src/lib/domain/messaging/redacted-reply.ts:42voice/videoPII → [REDACTED] → one redraft, else withheldFstrip + redraftredraftnoReplyAlert('redacted_after_redraft') only when withheld245dfabf15 #14348 Oct 1 (prospect got zoom.us/j/[REDACTED])#22321 wrongly called it dead; issue #22319 openwithheld only
B9Crash fallback buildFailOpenFallbackReplyagents/clara/lib/messaging/inbound-router.ts:1967; src/lib/domain/messaging/fail-open-fallback-reply.ts:134 (line :39)Tenant/prospect after a mid-reply crashFixed lines per completed action ("Got it, your repair request is in. Someone will follow up on timing.")F (crash)substitute (no draft)n/alogError inbound-router + alertNoReplySent cause crash_mid_reply9edc671900 #10419 Sep 24nothat alert
B10Cadence minimalFallbacksrc/lib/domain/leasing/generate-followup-message.ts:411 (used :747, :779)Prospect (follow-ups, re-engagement)A writer exception or empty first write → a fixed templateF (failure)substituteno retry on these pathslogWarn GenerateFollowUpMessage "... using template" (exception only; empty write is silent)2ccd10d347 #2509 Jun 19#22306 kept itthat log
B11Cadence email format cuts: Subject: line, stripEmailSignoffgenerate-followup-message.ts:741, :432/:742Prospect (email)Cuts a leading "Subject:" line and a trailing Clara sign-off and closerFstripn/anobody#2509; 78f2ea7a7f #2515#22306 kept them on purpose ("structure, not words; PR D decides")none
B12Dispatch summary mintsrc/lib/domain/maintenance/dispatch-summary.ts:268; hard cut clean() :135Vendor/handyman page, PMS-created WO tenant noticeA model rewrites the work-order description into dispatch prose, hard-cut at 240 charsPolrewrite + truncatefresh writerfields dispatchSummary, dispatchSummarizedAt, dispatchTitle; logInfo DispatchSummary462ea30d13 #6792 (CAM-2592: a tenant's apology paragraph paged to a tech)nofields + log
B13Work-order judge ("Agent Smith") applyAdjustmentsToWOsrc/lib/maintenance/work-orders/judge.ts:452 (write :471)AppFolio work order → vendors, staffA model polishes the title, description, priority and category Clara committedPolrewritereviewer modelWorkOrderJudgment record adjustments (judgment-record.ts:124)30fa124f01 #1230 May 21noadjustments
B14Post-call note narration swap stripNarration / NARRATION_REWRITESsrc/lib/integrations/voice/postcall-call-note.ts:95, :162, applied :183AppFolio guest-card note"The agent, Clara, informed the user" → "Clara informed the caller", etc. Fires on 301 of 310 summaries (#22321)Polsubstitute wordsnonenobodye3e921453f #10892 Sep 22#22321 kept it; "Decision for Fede"none
B15enforceGuestCardNoteShapesrc/lib/domain/pms/guest-card-note-shape.ts:156 (stamp cut :188; fallback :182/:193/:214)AppFolio noteAn empty or out-of-shape note → "Clara touched this lead; no outcome recorded for this contact."; legacy "M/D - " stamps cutPolsubstitute + stripn/afallback: logWarn GuestCardNoteShape; stamp cut: nobody3586d8c6d1 #10668nothat log
B16Card-note writer rejected → record sentencesrc/lib/domain/leasing/card-notes/compose-card-note-live.ts:90/:99AppFolio noteA model note that fails the check becomes the row's fixed sentencePsubstitutenonelogWarn CardNoteWriter "posting the record sentence instead of a model note"9422f0f080 #21985 Oct 23post-rulethat log
B17cleanCapturedReason (stripSummaryFiller + stripRestatedCallback)src/lib/tools/handlers/handle-capture-unknown-caller-note.ts:253 (callers 369, 905, 1135, 1364); autonomous-backstop-staff-sms.ts:77Staff email/SMS "Message taken from..."Cuts filler and "call me back" sentences from Clara's tool argument, and the repeated phone clausePolstripnonenobody68de93c276 #10752 Sep 22#22321 named it out of scopenone
B18Missed-call note stripRestatedCallback + tidyIssue/trimToClausesrc/lib/domain/promises/missed-call-note.ts:820, :654, :626Staff emailThe number clause is cut; the subject reason is cut to 8 words with an ellipsisPolstrip + truncatenonenobody6542417b38 #6813nonone
B19truncateToTwoSentencessrc/lib/domain/prospects/guest-card-core-facts.ts:122 (via calendar/sync-tour.ts:197)Staff tour calendar inviteClara's aiNotes are cut to 2 sentencesF (length)truncatenonenobody08802d5bd2 #8120nonone
B20Renewal held-text re-rendersrc/lib/domain/leasing/renewal-batch/release-render.ts:155 (:178); held-text.ts:965Resident (held renewal text/email)A template re-render with the reviewer's numbers is saved over the held words (template words, not model words)Fre-rendern/alogInfo RenewalBatch "re-rendered from the decided offer"; Slack thread "It now reads"; hold.sms.body overwrittenc433c061dd #18423; d6baa3d77b #22064 Oct 23n/alog + thread
B21Knowledge writer scrubDraftForKnowledgesrc/lib/domain/escalation/teaching-capture.ts:927Knowledge base → later repliesDrops sentences with private contacts from a distilled factPolstripnoneleftOutPrivate: trued5cc0b263a #17645noleftOutPrivate
B22Neighborhood notes fenceNeighborhoodLines/tidysrc/lib/domain/leasing/neighborhood-notes.ts:223, :208Listing card, spoken on callsStrips citations and bullets, drops long or steering lines, caps at 5Polstrip + capone thin-note retryFenceResult.droppeddeebad1ec9 #8091nodropped[]
B23Reviewer Slack feedback redraftsrc/lib/domain/escalation/review-redraft.ts:98 → held-draft-redraft.ts:59Prospect (held email)A person's Slack feedback → a true redraft ("CURRENT DRAFT" shown). Overwrites the hold in place, so the prior version is not keptP (human-asked)redraftredraftlogs escalation:review-redraft; Slack330cc0d61c #9948#22321 kept it ("a person asking, not a check")log
B24Team-notice subject fallbacksrc/lib/team-notify/summarize.ts:442Customer staffAfter 3 failed tries on the subject phrase, the engine's fixed subject is usedFsubstitute (subject)3 fresh retriessummaryCheck:'retried'd2c8d2f627 #16229nothat field
B25Tour-arrival translationsrc/lib/i18n/translate.ts:92 (tour.ts:1277, :1327; weekend-tour-checkin.ts:306)ProspectTranslates staff-written arrival text; on failure sends the EnglishPsubstituten/a#alerts surface translatedc6c65d642 #4273noalert
B26stripTtsDirectivesagents/clara/lib/messaging/adapters/elevenlabs.ts:249/:498Stored call transcript (record only)Cuts [laughs]-style tagsFstripn/anobody(record only, not delivery)nonone

C. Send doors and transports (after the text is final)

#Layerfile:lineWhat changesTriggerEffectCosmetic or contentWho can see / stored rowAdded (PR, why)Still on main?Signal
C1Template greeting prepend (plain text) - issue #22299 item 9agents/clara/lib/email/clara-reply-template.ts:223-238 (prepend :238)Adds "Hi {first}," / "Hola {first}," above a body with no greetingF + PolappendCONTENTnothing loggedd7a899f66b Mar 20 (threaded HTML email); name guard #12196yes (#22299 OPEN)none (renderedTemplate='leasing' only)
C2renderGreetingParagraphHtml (HTML twin)clara-reply-template.ts:326-336, called :346The same greeting as its own <p>F + PolappendCONTENTnothingoriginal; made conditional #393 Apr 24 ("Hi Sydneylavigne727,")yesnone
C3buildClaraInternalReplyTextclara-reply-template.ts:414-421Staff emails: "Hi {first}," + "Property: {name}" + "Clara" sign-offP (staff recipient)appendCONTENTnothing#6003 Aug 20; property line #10677yesrenderedTemplate='internal_plain'
C4normalizeGreetingPlacementclara-reply-template.ts:142-157 (limit :91)Moves a greeting found in paragraph 2 or 3 to the topFreorderCONTENT (order)nothing#11371 Sep 23 (WS "Hi Alexis... Hi Alexis")yesnone
C5Shell language pick resolveShellLanguage/SHELL_COPYclara-reply-template.ts:56, :72-80Picks EN/ES for the template's greeting and footer from the body's first wordFsubstitute (shell)CONTENT (shell only)nothing#17500 Oct 7 ("Hi" on top of "Hola")yesnone
C6Footer, signature block, preheaderbuildClaraReplyHtml footer :372, claraSignatureFooter :298-323, preheader :352"Have more questions? Just reply to this email...", a Clara/company/address/phone block, a hidden "Reply from {property}" line. HTML leg onlyPolappendCONTENT (fixed words)nothingd7a899f66b Mar 20; 0a19aef94c Apr 14; branding #10480yesrenderedTemplate='leasing'
C7stripMarkdownagents/clara/lib/email/strip-markdown.ts:28 (called template :230, :415)Removes **, #, code fences, backticks, ---; squeezes blank linesFstripcontent-lite (marks only)nothing#5057 Jul 30 (closes #4976: markdown reached prospects)yesnone
C8renderBodyHtmlclara-reply-template.ts:270-295HTML-escape, \n→<br>, paragraphs, bold → <strong>FencodeCOSMETICnothing#5057yesnone
C9splitSmsBodysrc/lib/integrations/twilio/sms-segments.ts:71-87 (sendSms client.ts:1356)Splits a long text into several texts (5 segments each, 1600 cap); cuts at sentence, then word, then mid-word; trims spaces at cutsFsplitCOSMETIC (words kept)row = full text, providerId = sids[0]#19424 Oct 14 (a 701-char Spanish reply refused, Twilio 30019)yesstatus callback ?op=&part=N (client.ts:122)
C10Email-bounce text fallback flattenForSmssrc/lib/.../ndr-bounce.ts:337-347, body :533-537Clara's bounced email: HTML removed, cut to about 500 chars at a sentence, wrapped "Hi {first}, it's Clara with {property}. I replied by email but it couldn't be delivered (...), so I'm texting instead." + " Reply STOP to opt out." on the first textP + F + Polstrip + truncate + appendCONTENTrow is post-transform, kind bounce_fallback_sms#6010 Aug 20 (a Zillow lead's full Gmail inbox)yesMessage.kind='bounce_fallback_sms', log email-ndr-bounce
C11stripInternalPrompt at first-email prep and sendagents/clara/lib/agent/outbound-safety-pipeline.ts:227-230; taken at clara-guest-card-engagement-prep.ts:681 and clara-guest-card-first-email-send.ts:693Removes a leaked prompt or tool paragraph from the first email. At prep a difference first triggers a writer retry (prep.ts:622); at send it is a silent stripFstripCONTENTnothing logged at this site (matches discarded); row draftBody is post-strip#9721 Sep 19yesnone
C12emailChannelWording + reminder email fallbackemail-channel-wording.ts:27; tour-reminder.ts:446-448; tour.ts:504; staff-booking-confirm-prospect.ts:229, :389"text me here" → "reply to this email" on template text reused in email; adds a "best phone number" linePsubstitute + appendCONTENT (template text, not the writer's)row post-substitution#21591 Oct 21yesnone
C13buildReplySubjectclara-reply-template.ts:39-42Subject → "Re: {original}"Polrewrite (subject)COSMETICon rowd7a899f66byesnone
C14Staff escalation HTML linkifyPhonesdecision-request.ts:1297-1319Escaping, <br>, phones become tel: linksFencodeCOSMETICnothing#10933 Sep 22yesnone
C15Graph/SendGrid body choiceinbox-client.ts:1795, :2068, :2194; sendgrid client.ts:349-352Graph sends HTML if present, else text; SendGrid sends bothn/aencodeCOSMETICn/an/ayesn/a

Decisions for Fede

Two calls are open (A2, A3); A1 was decided out on Oct 25. Proposed, pending review

A1 · Readiness floors, and where the three live customers enter Decided: out

Fede, Oct 25 night (Clara Refactor session): no readiness floors yet. Each customer stays exactly where it is today; a module moves at a customer only on Fede's explicit per-customer word; Situs stays supervised; no automatic promotion logic. Floors may be proposed again once the bench has enough runs to know the right percent, and Fede sets the number. His words: "this is dumb, i dont want this yet until we significantly fine tune it", "they live wherever they are today and what i decide manually", "floors can be determined later we are nowhere close enough to even know what the right percent is".

A2 · May Clara text staff a question, not only a tour event?

  1. Text first for anyone who gave a cell and met Clara, email otherwise; ships dark recommended
  2. Email for questions, text for tour events only (today)
  3. Text everyone on the map, no intro first

A3 · Do asks and the morning list run at Camellia too?

  1. Yes: strike Constitution I.1; the morning list ships dark recommended
  2. Keep I.1: Camellia stays hands-off
  3. Strike I.1 for asks only; the morning list waits
09 · Appendix

Appendix: numbers and results

Cost per inquiry, estimate (Oct 27 night; measured numbers come from the baseline runner): official prices, Opus 5.5 = $4 in / $20 out / $0.20 cached read per million tokens; Sonnet 5.5 = exactly half on every line. Today's prompt is about 105k tokens per turn; the decomposed one about 7 to 19k; an inquiry is about 5 turns. Per inquiry: today on Sonnet about 30 cents; decomposed on Sonnet 5.5 about 8 cents; decomposed on Opus 5.5 about 16 cents. The decomposition saves more than the model choice costs.

The measurements behind the sections above, in one place.

Where it stands today

Doors in
11
text, 4 email paths, 2 voice, guest cards, mirror wake, Slack, video
Supervised hold
5places
same decision, five code paths
"Is Clara live"
8+ sites
three functions, eight named callers, plus raw flag reads
Ways to page a person
~13
an Aug 24 estimate the code comment in human-notification-lane.ts still carries

Read from the code on main at commit 47c1188a19: almost every piece exists; one decision (should Clara speak here?) is made in many places.

One in three hand-offs that needed a person never reached one

Camellia (JP&Co)Western SlopeSitus
Conversations graded4482182
Needed a person326172—
Failed: never asked for help (incl. failed to transfer or answer) + silent drop121 of 326, 37% (36 + 85)51 (14 + 37)—
Asked for help when she should not have42—
Held drafts expired unsent—6035 of 35
Transfers with no human leg7061—
Main-line loop21 legs in 12 calls, Oct 13–19guarded: Clara never transfers to the forwarded line; since Oct 22 a bounce alerts and counts as no answer—
Figure 3. Aug 1 to Oct 20: 668 graded conversations plus 142 held drafts. "Failed" is the audit's category (never asked for help, which includes failing to transfer or to answer, plus silent drops); silent drops alone are 26% at Camellia. "No human leg" and "silent drop" are two definitions and are not added. Staff replies made in Outlook or AppFolio are invisible to us, so silent drops may be overstated.

The first-reply prompt, today vs proposed

Measure (first reply)TodayNew prompt
Prompt tokens109,658 (Oct 22 trace)~7,440 median
Topics with contradicting rules8 (length alone has 6 rules)build fails on any second rule
Held, 67 recent cards60 (Opus 5.5)
Emails rewritten after writing51 of 780
Time per turn75 s7.4 s (Opus 5.5)
Cost per card, list price$0.29$0.016 Opus · $0.008 Sonnet 5.5
Writer bill, 30 days~$298 (Sonnet 5)~$65–125 Opus 5.5 (estimate)

Cerebrus

MeasureValueSource
Turns graded after the fact3,509Sep 8 to Oct 25, 702 conversations, 87% voice
Flagged red362174 from the vendored engine, 188 from two app checks; precision unmeasured
Human labels on any flag0none of 85 thumbs since Aug 21 froze a per-turn row
CI catches in 60 days00 failures in 400 runs of the required gate

Tenant messages, Sep 30 to Oct 23

Western Slope and Situs GroupCount
Tenant texts and emails475
Answered by nobody274
Answered by staff189
Answered by Clara1

Tenant benches (rules prompts, not production)

BenchResult
D3: office-conversation rule, reply or silent22 of 23 of Fede's graded examples (in-sample); 0 replies on staff-run threads, 0 invented facts; routine replies 12 of 50
G2: 261 repair episodes, two outcomesInvented a fact in 1 of 261 (was 13); filed 8 of 42 where the office filed, all right
Triage: 1,994 real texts45% need no reply; of the rest 23% Clara today, 44% need a person, 33% need more tools

Oct 30 night: Opus first-email final replay, two silence fixes, Situs approve path

Opus 5.5 beat today's Sonnet 5 on the first prospect email, on a replay of every real guest card we could rebuild. On Fede's go (Oct 31, 00:25 MDT: first email on Opus, autonomous, all customers) the swap PR #24036 merged and went live for every customer at 05:11 UTC. Texts and every later turn stay on Sonnet.

Live in production: Willows first email written by Opus (Oct 31, 05:20 UTC)

BeforeAfter
Model on the first prospect emailSonnet 5 (trace step "claude-email-initial": claude-sonnet-5)Opus 5.5 (trace_aa2fc390-19f5-4621-b31b-c80622334432, step "claude-email-initial": model claude-opus-5-5, model path firstEmail)
Time from inquiry to reply in the renter's inbox75 seconds (inquiry 05:19:25, reply delivered 05:20:40)
First-email barNo em dashes, tour times offered from the calendar, listing facts match unit 201, special quoted, rent question answered, no "check with the team"

A Zillow-style inquiry for a made-up renter (test mailbox, no real person) went through the real intake at The Willows: guest card 365, conversation 35a617cb-d10a-42d4-8669-a8d1b777ae45, reply msg_c98cc919-1122-409e-8449-f66b2187ca97. Small things, not blocking: the opening sentence joins two thoughts with a comma; the delivered subject carries "Re:" while the record stores the plain subject.

Production Willows conversation: the Zillow inquiry and Clara's first email written by Opus 5.5
Production, Willows: the inquiry and the first email written by Opus 5.5

Follow-up turns stay on Sonnet. 53 real follow-up turns since the recorder started: Opus better 26, tie 8, worse 19 after the shared tour-reply rule (PR #24064, merged: who meets the renter only if asked, tour times never from office hours). Both of Fede's "Wrong" turns are clean on both models. A narrow win on a thin set; the swap waits for Fede's go.

356 real cards, same input for both models

Sonnet 5 (today)Opus 5.5
Head to head, same cardOpus better 161 (45%), tie 139 (39%), worse 56 (16%)
Cards with any never-do4032
Cards tripping one of Fede's checks4631
Em dashes90
Home named without its special1713
Formal date instead of today/tomorrow1810
Unprompted vacancy count or list of homes51
"Check with the team"31
Tour time not on the calendar86

Per customer

CustomerOpus betterTieOpus worseCards
Western Slope582420102
Situs8810936233
Camellia156021

Where the renter wrote something themselves (182 cards): Opus better 105, tie 45, worse 32.

Where Opus is worse. Two real misses, both at Situs. On a home that is gone, Opus says it will get it confirmed the home is still open. On a renter who offered a double deposit, Opus carried it to the tour though the records say one deposit per home. Two more hits were false alarms: a correctly worked out effective rent, and passing on what a staffer had already told an applicant.

What the judges are worth. The comparison judge matches Fede on 5 of his 7 rated cards. The code checks reproduce his 6 of 6 "Wrong" calls and caught 8 of 8 planted defects with 0 false hits. The corpus judge's "do not send" rate (about two thirds on both models) is not used, because it never sees the writer's input.

How many cards made it in. 856 real lead records; 430 rebuildable; 72 dropped with no email on file, 1 with no time anchor; 1 to the bad-data bucket; 356 compared. Not possible: 426 records with no time anchor, and about 2,640 historical report rows with no PropFlow record (Situs 1,572, Western Slope about 1,068). Tour slots come from today's calendar for both models. Lampliter input still names the unposted Unit A for both.

Samantha C. (Western Slope, Oct 30 evening). Rebuilt after the population was pulled; Opus better. The pet fees ($300 deposit, $35 a month per pet) are in Western Slope's knowledge base, not invented. The sentence "the property team will follow up with you about the eviction" is ordered word for word by the current prompt for eviction asks, and both models write it; keeping it is a prompt decision. Neither model mentions her $2,000 budget or 2-bed interest.

Review list of 104 cards for Fede, most important first (the first 25 matter), held in the run folder ~/.claude/guest-card-corpus/runs/2026-10-30-opus-swap-qa/.

Silence fix A (PR #23927, merged)

The 40-reply runaway limit muted a thread for good with no card. Now only a fast unbroken run counts, a 30-minute pause ends it, a new text 30 minutes after her last reply restarts her, held drafts never count, and the first stop posts a card through the shared #alerts helper as its own alert type (test properties get it too).

Before. On Oct 28 and Oct 30 the Willows tester thread hit the 40-reply limit and Clara went silent for good with no card. Replaying that real thread through the old rule trips both times; the new rule counts 1 and does not trip.

Willows proof, Oct 30 night (tester number to the Willows line only, our own numbers):

StepWhat happenedProof
1A real fast run: 40 texts about one a minute, 40 replies delivered (02:07 to 02:41 UTC)Twilio ids in the PR comment on #23927
2The 41st text got no reply, so real loops still triptext SM44bfb24e
3One internal card posted to #alerts for the WillowsSlack card
4A new text 32 minutes later was answered, with no resetTwilio SMaa31364179b2ec3b8392c027a349287d, row msg_a6fa4a3d-2b68-4fd7-8375-dc51c8b26793
Production Willows conversation showing the stopped text and the answered one after the pause
Production, Willows: the stopped text and the answered one after the pause

Follow-up suggestions: issue #23940.

Silence fix B (PRs #23932 and #23954, merged)

A correct tour reply ("tours run 10 AM to 4 PM") was held by the tour-time check because the pipeline path did not pass the tour window, with no way out.

Part 1. The check gets the window the reply used. Willows proof: the tester texted "Could I come tomorrow at 10 PM?" and Clara's reply arrived (Twilio SMc9150f7f96d6b5374ee267b9004ab8a8). Caveat: that reply came through Clara's own calendar lookup, not the changed pipeline path.

Part 2. Every held reply draft gets one internal review row with Approve and Reject, admin only; client staff never see it. Production proof at Willows: the row exists, one draft makes one row, and the detail page shows the draft with both buttons. Approve on a stale draft was refused with a 409 because a later reply had already reached the tester (nothing sent). Reject worked.

Production Willows hold detail page showing the held tour reply with Approve and Reject buttons
Production, Willows: the held tour reply with Approve and Reject

Follow-ups: #24031 (test context), #24032 (holds list shows only newest 200, search within them), #23992, #23933, #23942.

Situs approved texts reported as never sent (PR #24021, merged, live 03:00 UTC)

WhoWhat staff were toldWhat really happened
Deyci S."Not sent"Sent 14 s after approval (inbox busy, queued, then sent; lane already fixed by #23554)
Yaramin R."Not sent"Sent 13 min later (AppFolio login was cold, treated as final, a second try sent it anyway; issue #24022)
"Michael" (staff test)"Not sent"Correctly stopped, a teammate had texted the lead 4 minutes earlier
Estrella P."send failed, retrying, nothing has gone out yet" twice, then "Sent" at 10:45Sent 22 s after approval, one copy; only the status was 39 minutes late

No renter was left without a text. The bug is a false "Not sent" to staff when the AppFolio inbox queued the text. The fix counts a queued reply as on its way and posts "Sent" when it goes. Issue #24033 for the one suggestion.

Willows proof in production (Oct 31). A held Clara reply to our tester was approved at 9:03 PM the night before, parked by quiet hours, and sent by the 8:00 AM sweep with no false failure line.

StepWhat happenedProof
1Held reply approved at 9:03 PM MT, correctly parked for quiet hourshold eschold_adeefa26-4bac-4c22-9102-a6425d0f95a8, approved, awaiting the send window
2Sent at 8:00:50 AM MT, one text, deliveredTwilio SMf9aee1b81dffe5801f04e7f4e14085b0
3One matching row in the conversation, hold marked approved with no failure or retry fieldsrow msg_0eed8dcd-68a3-4101-a391-3f0d83a4df03, conversation 81e09472-535a-4a10-9531-521b926cf949
Production Willows hold detail page after the 8:00 AM send
Production, Willows: the hold after the 8:00 AM send. The page still reads "Approved, will send" after the quiet-hours sweep sent it; the text went, the status line is a follow-up (issue filed).

The busy-inbox case itself (the AppFolio door queuing a Situs text) is proven the next time it happens at Situs; the Situs Leasing session's watch reports it.

Gate ledger on Opus: first 10 hours (Oct 31, 05:11 to 15:00 UTC)

Too small to delete anything. Since the swap, Opus wrote 5 first emails, all at Willows (our test property). Western Slope, Situs and Camellia got no new guest cards in the window: the last customer card synced at 01:08 UTC, and an overnight gap like this is normal (about 6 customer first emails a day on Oct 30). On the 5 Opus emails no check fired, nothing was held or retried, and the words Opus wrote are the words that were sent. Zero out of 5 is still consistent with a true rate as high as about 60 per 100, so it proves nothing yet.

DoorOct 26 ledger: Western Slope first emails, 30 days (fires: right / false / unresolved)Same, per 100 sentOpus, 5 Willows emailsOpus, customer emails
Door 1, should Clara speak (the turn chose no reply)000none sent yet
Door 4, claims match the record (first-email checks, fact trace, writer retry)47: 1 / 6 / 4063: 1 / 8 / 530none sent yet
Door 5, voice00not on this pathnot on this path
Door 6, send door and Supervised holds0 judged00none sent yet
Fair-housing judge0 (the one false fire was at Camellia)00 (5 of 5 "Compliant")none sent yet
All doors47: 1 / 6 / 406300 emails

How the per-100 is built: the 47 Western Slope first-email rows of the Oct 26 ledger (the fact trace, draft checks, no home named, sentence strip, tour-time retries, retry passed), over the 75 Western Slope first emails sent in the same 30 days (one "lead replied" event each). An estimate: held emails are not in the 75, so the rate per email attempted is a little lower. Camellia (2 first-email fires) and Situs (1) are left out because their sent count for that window was not recorded.

Zero fires on Opus (5 emails)

KindCountWhich
Checks in the reply loop (trace steps)8draft-drop, internal-prompt strip, fair-housing, promise backing, booking promise (recorded on 4 of 5 turns), how-much-is-open, PII, send gate
First-email checks (block, retry once, then hold)7bare hand-off, draft checks (tour times, rent per size, dashes, hedged money, unbacked promise), no home named, fact trace, how much is open, PII, send-door check
Send door and holds2first-email send door, Supervised hold
Rewrite layers on this path that changed no word105 internal-text strips (reasoning preamble, sent-time stamp, tool-call markup, prompt leak, first-email leak at send), draft salvage, empty-reply fallback, 3 hand-off rewrites

Rewrite layers not settled by this run. The why-line strip changed 5 of 5 emails, by design: the writer is asked for a one-line reason and it is cut before sending. The email template (greeting, shell, footer, signature, markdown strip; 8 layers) wraps every email at send and leaves no record, so the saved draft cannot show it. The other families (voice and video, staff replies, bounce texts, side writers, transport) never touch a first email, so this ledger says nothing about them. That is 19 of the about 60 layers on this path, 10 at zero.

False fires on Opus: none. No fire, so no Fable judge was run.

Also seen. One Willows email from a sender with no guest card ran on Sonnet at 14:00 UTC and was held by the Supervised setting at Willows: that is the general inbound email lane, which the first-email swap does not cover.

Next run: after the first 50 customer first emails on Opus (about a week at today's pace). A check that fires rarely, like the fair-housing judge (once in 30 days), needs about a month of mail before "never fires" means anything.

Sources, read only: agent traces since 05:11 (45, of which 5 on claude-opus-5-5: trace_aa2fc390, trace_6a429fbc, trace_aaa674d1, trace_9b5c2c9a, trace_fcff1596); the draft stop record since 05:11 (45 rows, 0 first-email rows); first-email intent rows by key (5 of 5 sent, no held checks); conversation rows (sent words equal the saved draft, 5 of 5); new-lead events and the prospect list per company; CloudWatch (5 first-email turns logged, all at Willows; 0 customer guest cards created after 01:08). Raw rows: gate-ledger-opus-2026-10-31.json (scratchpad of session 001).

10 · Video and podcast

Video and podcast

The narrated explainer, the whole-vision podcast in two cuts, and the five chapter episodes.

Explainer, 4:43, narrated, animated, on the PropFlow brand. The lifecycle end to end, in the page's own order: what this is (an AI coworker who does the work, not automation, not a chatbot), week one (the company brain, who owns what, meeting the team, one form once), learning the job (the recipe from past records, corrected by answering questions, readiness as a number), supervised (shadow the work, compare, no queue), live (the five habits, each with a sample exchange), two dials (scope, and autonomy: approve first, or by policy, per job, acting always the baseline), fully autonomous (routine with Clara, judgment with people). Seventh cut, 2026-10-24 night, after Fede's notes: the sales intro and the brand-book vignettes are gone, no "remember this?" beat, "company brain" throughout, and the two-dials scene now carries the two approval levels of section 12 instead of talk, act, commit. Sample lines are illustrative. Shareable copy for the team on Google Drive: drive.google.com (anyone with the link); docs copy at /a/clara-new-hire-demo. Music by Eleven Music, ElevenLabs narration (Matilda), slides recorded headless, ffmpeg.

Listen: the whole vision in 22 minutes. The medium cut Fede asked for; two hosts, generated from this page on Oct 24 night with the facts pinned and claim-checked line by line. Episode page with read-along transcript, brief and outline.

The 63-minute deep dive (the Oct 24 night redo, 148 of 157 claims confirmed on the page):

Figure 1b. Two cuts of the same brief. The medium cut (22 minutes) is the one Fede asked for: its first pass misstated one design point and was never published; this pass was regenerated with the facts pinned and checked again: 58 claims checked, 54 confirmed on the page, 2 overstated (Western Slope ownership called clear where the page shows gaps; which reviewer caught a misquote) and 2 host embellishments the page does not say (a renter-versus-vendor example, and a left-over default in code as the cause of the 24-hour draft expiry, which the page only calls a rule nobody decided). The deep dive (63 minutes) is the Oct 24 night redo after the first 50-minute episode was pulled for 5 invented details. The five chapter episodes (about 5 minutes each) sit at the start of their chapters as they finish; chapters 1 to 4 are in place, chapter 5 is still rate-limited at NotebookLM.

Listen: chapter 1, the new hire and the spine, 5 minutes.

Listen: chapter 2, week one, 4 minutes. Two hosts, generated from this section with the facts pinned and claim-checked (nothing invented).

Listen: chapter 3, learn, get feedback, then supervised, 5 minutes. Two hosts, generated from this section with the facts pinned and claim-checked (nothing invented).

Listen: chapter 4, live as a coworker, the five habits, 7 minutes. Two hosts, generated from this section with the facts pinned and claim-checked (nothing invented).

Listen: chapter 5, the two dials, scope and autonomy, 4 minutes. Two hosts, generated from this section with the facts pinned. Claim-checked: 24 of 26 confirmed; two slips to ignore: the senders are live today, not merged-but-off, and "ships dark" means default off until Fede turns it on, not running silently.

11 · Audit

Where the initiative actually stands (Oct 31 audit)

Read-only audit, Oct 31, against main 2014531244. Fede: "seems like we left it half baked." Mostly true: the plumbing landed; the three goal items did not.

A. Every promise, and where it is

Promise (Fede's words)What shippedWhat is missingState
"specialized smaller prompts" (Oct 24)A split option in the bench only (bench #31)Nothing split live; leasing prompt grew 2,298 to 2,616 lines. Row 143 parkedNot started in production
"a higher frontier model"First email on Opus (#24036, live Oct 31, Willows proven)Every other job still SonnetPartial: 1 job of about 6
"a repeatable way to upgrade it safely"Bench upgrade command (bench #40 to #62)Bench: 0 Situs, 0 Spanish, 0 replies; his Wrong cards not frozenHalf-baked
A. Frozen baselineBench #21; Day 0 #22445, #22457Hold decisions only, not wordsDone for holds only
B. Hold: one door#22334, #22450, #22473 (0 of 5,515 differ)Nothing; row 4's text is #22473Merged with Day 0 proof
C. Ask for helpSeam #22455; folds #22592, #22595, #22617, #22646Staff senders still in 38 filesSeam only, callers not collapsed
D. One classifier#22519, #22797Live runMerged with Day 0 proof
E. 47 copies to 410 row folds (#22506 to #22877), 5 door foldsEvery detector keptMoved, not reduced
F. Model plumbing#22446, used by #24036NothingDone (tracker says canceled)
G. Situs onboarding#22373, #22411 at WillowsThe Situs package itselfWillows only
H. Full context benchBench #27, #28; tenant shadow weekRepair prompt on Opus stuck locally (row 16)Half-baked
I. Hand-off fixesAbout 40 single-case fixesThe framework (row 13); "did a person already reply" (row 14)Patches only, framework not started
J. Tenant replies, darkNoneAll three rowsNot started
K. PMS inbox adapterRead interface only (#19263, Oct 13)The pass-throughNot started (in motion today)

A2. The gate report's six steps

No go from Fede was ever recorded; the page still says "awaits his go". His Oct 26 yes covered folding only.

Step or verdictWhat shippedState
1. Hold lifecycle#22538, #22559, #22542, #23954. Re-alert covers leasing only; 106 of 110 unseen holds were maintenance textsPartial
2. Facts in, with idsFacts block (#22932, #24015). No ids; vacant units, not posted homesPartial
3. Declaration schemaNoneNot started
4. Door 4 as one join, observe week, retire lines#22649, #22691 moved checks, unchanged. No join; fact trace grew (#23347)Fold only
5. Voice to retry-only#22643 moved them; the dash check still holdsNot started
6. Check registry plus build checkNoneNot started
Delete: farewell loopStill on mainNot done
Delete: shape rules Opus never tripsStill in the first-email draft checksNot done
Delete: availability forced retryStill on mainNot done
Delete: typed tool-call strip#23013: retry gone, cut became a holdChanged, not deleted
Delete: work-order claimKept (delete judged unsafe)Correctly kept
Fold: 5 rows (facts, date, tour time, promises, follow-up facts)Behind door 4, detectors intactMoved, not merged

B. Fede's three attack targets

TargetBefore (30-day ledger)Today
Leasing emails held for no reasonDoor 4: 14 false, 4 right, 60 unreadable; 110 of 124 holds expired unseenNo live number. Bench only: held first emails 24 to 12-16 of 51
Wrong data sentNever counted: the ledger logs holds, not what got outNo live number. 356-card replay: Fede's checks tripped 46 Sonnet, 31 Opus
Accidental escalationsOne in three hand-offs never reached a person; 3 hand-off-promise catchesNo live number. Replay: "check with the team" 3 to 1. Row 147 open

C. What should be next (by dependency)

  1. In motion. Gate ledger on Opus: table B's after-number ("really question each one").
  2. In motion, already merged. Row 4 shipped as #22473 (Oct 26); rescope or stop today's copy.
  3. In motion. Row 5, askTheTeam callers: the last collapse gates the Gera hand-off.
  4. In motion. Row 6, PmsInbox pass-through: slice K, last in the chain.
  5. Freeze every Wrong card; add Situs, Spanish, replies (rows 133, 136). Everything after is judged by it ("ratings are the bar").
  6. Facts at the source with ids: "open now" means what AppFolio posts (gate step 2; Oct 29: "fix the data").
  7. Split the first-email prompt by deletion (row 143): Opus obeys every wrong line ("decompose the model into smaller pieces").
  8. One-line yes or hold to Fede on the six steps, then delete the layers Opus never trips (row 101): "less checks but only if safe."

D. Decided, then dropped or contradicted

E. Weekend queue (no decision needed)

Fix-shaped, already decided, no switch, nothing turned on at a customer. Size: S under 200 lines, M under 600.

ItemSizeProofBefore-number it moves
Delete the farewell-loop silencer (Oct 27 rule: never fires on Opus, delete)SDay 00 fires in 30 days; check count about 255
Delete the availability forced retry (gate report verdict)SDay 0 + replayForced retries on first emails
Delete the first-email shape rules Opus never trips, now that the first email is on OpusS356-card replay0 of 72 Opus trips; held first emails
Row 101: delete the first email's rewrite and retry layers Opus never tripsM356-card replay + WillowsAbout 60 rewrite layers
Row 147: no "could not answer" team email when Clara answered fullySWillowsAccidental escalations
Row 107: tool results stop prescribing "I've alerted the property manager"SReplay + WillowsUnbacked hand-off promises
Row 142: reword the other rule headings Clara can echo (same fix as #23822)SWillowsFalse holds
Row 140: availability and reminder texts say today or tomorrow (extends #23792)SWillowsFormal date on 10 of 356 Opus cards
Row 88: follow-up writer stops echoing a bedroom count from card notesSReplay + WillowsWrong data (Jessalyn)
Row 65: an Outlook 550 bounce marks the address deadSReplayRepeat sends to dead addresses (David Jones, 2)
Row 112: Day 0 compare pairs by question, not positionSPlanted grid changeProof rail reliability
Tracker: fix the 10 rows whose status disagrees with their PRsSbin/refresh-tracker18 "said, not acted on"

Needs Fede

12 · Week in review and plan of attack

Week of Oct 24 to 31: two max-effort reviews, your Gera commitments, and the plan

Fede, Oct 31: "review what was done this week, what we did well, where we missed, and the roadmap for what's next", "grounded in reality of the operations and what we learned in Western and Situs from real production interactions", "check my transcripts with Gera too", "plan of attack: autonomous weekend prep and hands on Monday". Two reviewers (Fable 5.1 and Opus 5.5, max effort) worked the same brief independently on this week's production records; a third agent read the 14 raw Fede and Gera transcripts. Full texts are at the bottom.

Where the two reviewers agree

QuestionFableOpus
Smaller promptsNot started. Leasing prompt grew 2,298 to 2,616 linesSame. One real email ran on a 47,000-word system prompt
Opus 5.5First email only; no real renter had one yet (no new lead at any customer since 05:00Z)Same, re-checked 16:06Z
Fewer checksNot started: 255 sites, 60 rewrite layers unchangedRe-housed, not reduced; 1 measured deletion; 3 of 10 judged fires false
One enginePartial, pass-through onlySame
"Finish, no WIP"Missed: 21 tracker rows disagreed with PRsMissed: cap 3 merged-unproven rows, actual 42
What nextGates and hold lifecycle before any further swapSame; honest that it slows the Oct 30 funnel order

Production this week, the numbers both built on

Western Slope (autonomous)Situs (supervised)
New leads answered23 of 269 of 38
Median time to first reply2.0 min11.5 min
Leads with no first-email attempt at all030 of 38 (skip reason logged, never stored)
Renters with no personal reply from anyone014
Held messages decided byour team 24, client staff 0, timed out 52 (of 110 at both customers)

Other misses with ids in the full texts: one renter got two first emails 63 seconds apart naming different homes; an approved email opened with the wrong first name; two callers never got their follow-up text (waited 74 times for an AppFolio record, then expired); one booked tour never reached AppFolio after 50 tries; "lock in the tour" held 5 replies as a false booking promise; hand tests from our side on Situs's live line paged real staff twice.

What you told Gera (14 raw transcripts, Oct 20 to 31)

34 commitments: 7 done, 15 partial, 10 not started, 1 contradicted. No trace of work: track every inbound as an open item; Spanish bench slice; plan to exit supervised tenant replies; lead-source report to Situs; "get renewals ready"; the green check on unsent drafts; remove old-model rules once on Opus; Western Slope staff guidance. Contradicted: "no new features" (Oct 28) then two tour features merged Oct 30 on Fede's own go. Gera owns maintenance, the classifier and its gates, tenant AppFolio messaging.

Decided today

Plan of attack

Method: one ledger of every check and rewrite layer; each row lands in one of four buckets by rule (keep: one-right-answer send rules and fair housing; context: hand the fact in with ids, then delete; fold: into one of four doors; delete: zero or only false fires, or a Sonnet-era habit); every rewrite layer becomes retry-once-then-send or is deleted; one PR per family proven on the Day 0 replay plus that family's historic fires; the count only goes down (registry with a build check); one weekly scoreboard: checks, rewrite layers, false-fire rate, holds expired unseen.

WhenWorkWho decides
Running now (Oct 31)Triage ledger of all 315 rows; step 1 hold lifecycle (leasing); step 2 facts with ids, "open now" from what AppFolio advertises; funnel inspection by both reviewers (job map, turn 1 vs turn N inputs, one-writer verdict). Merged today: hold records name the check (#24119), PMS inbox behind one interface (#24118); ask-for-help collapse (#24120) in the queue.Grant
Weekend, autonomousDelete and fold waves per family from the ledger; the merged weekend queue below; bench gaps (Fede's 8 Wrong cards frozen, Situs and Spanish slices); steps 3 to 6 in order (declaration schema, one claims check in watch mode, voice retry-only, registry).Grant; each PR dark, proven, armed
Monday, hands on with FedeRead the Opus ledger after the Monday lead wave (first real Opus mail); read the one-writer verdict and decide; walk the Situs autonomy settings with Gera (his Oct 30 ask); the two remaining asks below; the funnel order for the next swaps.Fede

Weekend queue, merged from the three lists (fix-shaped, no switch, nothing turned on, nothing outbound)

  1. Fact fixes at the cause: this turn's tool results count (Patrick); the listing special is a traced source (Yaramin); "4-week-free" matches "4 week free"; "lock in the tour" and "won't quite work" stop reading as promises. Before: 3 of 10 judged fires false.
  2. Hold lifecycle for texts too: alarm and re-alert for held renter texts; the 24-hour timer fires on later-turn holds (Tyler, 63 hours open). Before: 6 renter texts expired unseen this week.
  3. Hold status tells the truth: "Sent" after the quiet-hours sweep (#24114); session-cold resend (#24022); one inquiry answered twice through two doors.
  4. Stop records name the model and keep the text finally sent. Before: 0 of 43 first-email stop rows name the model.
  5. Slack card replies "approve", "approved", "reject" are commands, never feedback for a rewrite. Before: 2 approvals and 1 rejection answered "Draft unchanged".
  6. Deletes with ledger evidence: availability forced retry (10 fires, 0 catches), farewell loop, first-email shape rules Opus never trips; then the first email's rewrite and retry layers (row 101). Zero-fire checks wait for the Opus ledger, prepared locally.
  7. No "could not answer" team email when Clara already answered; tool results stop scripting "I've alerted the property manager".
  8. Outlook 550 bounce marks the address dead (David Jones). Alerts stop tagging Fede and Gera (13 of 198).
  9. Bench: Fede's 8 Wrong cards as frozen checks; Situs and Spanish and reply-turn slices.
  10. Proof sweep: 42 merged-unproven rows get a production record or reopen; the fifth Willows Opus email with no send recorded explained; the Oct 27 staff welcome setting proven before it ages out Monday.
  11. Hygiene: Day 0 compare matches by question not position and the stale baselines re-recorded; 96 "calendar unreachable" cards deleted from #western-slope (count printed first); closed-PR branches and worktrees (list first); AppFolio literals out of core, one small PR per file (41 left in leasing).
  12. Situs intake: why 30 of 38 cards got no first-email attempt, read-only first; a bug is fixed under the grant, a designed gate goes to Fede. Owned by the Situs session.

Needs Fede (two left; the gate order is answered)

Biggest risk next week, both reviewers

Monday's lead wave is the first real Opus traffic, through checks and rewrite layers tuned for Sonnet, with no production number yet for how often they fire on Opus. The two failure shapes are both on record: a check fires and the retry sends a trimmed email (Yaramin lost her terms), or nothing goes out and nothing alarms (Jeanine, four days). The Opus ledger re-runs after about 50 customer emails.

Full texts

Fable 5.1 review

Full text
# Clara refactor lane, week review, Oct 24 to Oct 31, 2026

Independent, read-only review (Fable 5.1). Sources: Western Slope and Situs production records pulled Oct 31 about 15:05Z by key and query (conversations, holds, the check-fire ledger, ratings, Slack cards), the docs and tracker, the bench, PR bodies. Maintenance holds are Gera's lane and stay out of this lane's misses.

## A. Scoreboard

| Fede's goal, his words (date) | State | Proof |
|---|---|---|
| "decomposed job prompts" (Oct 24) | Not started | Leasing prompt grew 2,298 to 2,616 lines and 163 to 179 RULE lines in 39 commits since Oct 23; first-email rules file 741 to 850 lines. The split (row 143) is parked, no PR. |
| "Opus 5.5" (Oct 24); "entire leasing funnel email+text on Opus" (Oct 30) | Partial | First email on Opus for every customer since Oct 31 05:11Z (#24036), proven on Willows (trace aa2fc390). Email and text replies still on Sonnet. By 15:05Z no Western Slope or Situs turn had run on Opus: no new guest card has arrived at either customer since the switch (last first email: Western Slope bb81adac, 01:09Z, Sonnet by the time, the model is not stored per email). Willows since the swap: 5 Opus first emails, 0 checks fired, 4 sent within a minute, 1 with no send recorded (unexplained). |
| "a repeatable safe upgrade path" (Oct 24) | Partial | Model named per job in code, swap = one PR, rollback = revert; 356-card replay, bench, Willows before the swap. Gaps: bench has 0 Situs and 0 Spanish items; Day 0 compares hold decisions, not words. |
| "fewer, reliable gates" (Oct 24); "fix all the gates and rewrites" (Oct 31) | Not started | About 255 check sites and 60 rewrite layers (Oct 26 inventory), unchanged; 38 retry and rewrite call sites on main. The six-door order has read "awaiting Fede's go" since Oct 26 and was never put to him as one yes/hold line. |
| "one core engine every module uses" (Oct 24) | Partial | Hold rule behind one seam (#22334, #22450, #22473), 0 differing cells on 5,907; askTheTeam callers collapsing; PmsInbox door open (#24118). Pass-through only. |
| "count fires on the Opus arm, never fires means delete" (Oct 27) | In motion, 0 deletions | Fire ledger exists since Oct 27 03:06Z, Sonnet only; 10 checks fired zero times in 5 days. Opus-arm ledger starts today. |
| "finish decided work, verified end to end; nothing new without a decision" (Oct 30); "no new features" (Oct 28) | Missed on "finish"; "nothing new" held | The decomposed prompt, decided Oct 24, never started; rows 4 and 6 "said, not acted" 6 days; 21 tracker rows disagree with their PRs; 337 PRs merged in 8 days. The Oct 30 tour features (#23858, #23938, #23869) carry Fede's own go in their PR bodies ("yes build it"), so they are a course change he did not pass to Gera, not sessions inventing scope. |
| Situs leasing "all by itself" by end of week (to Gera, Oct 27) | Partial | First email autonomous at Situs since 05:11Z; replies and texts stay Supervised. The week's measured gap between the two stages: Western Slope, autonomous, Clara answered 23 of 26 new leads, median 2.0 minutes; Situs, Supervised, 9 of 38, median 11.5 minutes, 30 of 38 with no first-email attempt at all (reason only logged, never stored), 14 renters with no personally written reply from anyone, AppFolio's auto-reply reaching 25 of them first. 4 renter-facing Situs holds expired unseen. |

### Docs say vs production shows

| Docs or tracker say | Production shows |
|---|---|
| Hold lifecycle: 4 PRs merged, "every hold ends in a send, a person or an alarm" | Held emails re-alert; held renter texts expire with no alarm (3 Situs, 3 Western Slope this week) |
| Specials "RESOLVED Oct 29, Situs 20/20, WS 4/4" | A send check stripped "4 week free" from Yaramin's Lampliter email Oct 30 (it kept "after a rent concession"), so the renter got vaguer terms than the listing |
| "Retry never ran on held first emails" (Oct 26) | Fixed by #22500: 13 drafts went out as sent_after_retry at the two customers this week |
| Bench "PASS, never-do 0" (Oct 30) | Fede's own ticks, all properties: 27 Wrong of 64, 53 unread when PASS was declared. Of 59 customer ratings by anyone, 57 judge Opus shadow drafts never sent (his two specials Wrongs judged drafts whose facts block had no special) and 2 judge a reply a renter received (Pomona Park, Oct 26, both Wrong) |
| Tracker: hold lifecycle, ask-the-team, rewrite audit all "open" | Their PRs are merged (4, 1 and 8) |
| Opus "live, all customers, 05:11Z" | True in code; zero customer turns on it by 15:05Z, because no new lead has arrived since |
| Situs sources on the approved list get a first email | 8 TurboTenant cards from 7 renters (Oct 26 on) had an approved source and an email and got no first-email attempt, no draft, no card; 3 of the 7 never got a staff message either |

## B. What went well

1. **The plumbing refactor touched no renter.** Four seam PRs (#22334, #22450, #22473, #22592) merged with 0 differing cells on the 5,907-cell Day 0 replay; renters got exactly the messages they would have gotten before.
2. **Situs Supervised first emails got out fast.** 13 of 24 prospect-facing Situs holds were approved within 0 to 41 minutes: 12 by Fede (11 in the app, where the approver id resolves by key to his account: eschold_4e1984ca, first email, 31 seconds; eschold_539542e7, reply text, 27 seconds; and Deyci's held text eschold_5fb65729 from the Slack card in 13 minutes, the first approve-from-Slack, #24079) and 1 by another PropFlow admin; none was edited before sending; no customer staff member closed a hold at either customer. Those renters heard back inside the hour.
3. **The checks that fire catch real mistakes, and the retry now runs.** Amy, Western Slope (3edfcfc7): the draft said "Tuesday November 5" (a Thursday) and that "a few 3-bedroom homes" were empty; two redrafts fixed both and she got a correct reply. Anthony (3aad8363): "lock in" before any booking, redrafted, sent. Before #22500 the retry never ran on a held first email; this week 9 Western Slope and 4 Situs drafts went out as sent_after_retry (the same path is the suspect in Micheal's double first email, C row 3).
4. **A false "Not sent" was chased to the record.** Three Situs approved texts showed "Not sent" Oct 30; the conversation rows showed the two real ones went (quiet hours delayed them) and the third belonged to a test lead at Zephyr. Fix #24021 live, proven on Willows Oct 31 08:00 MT.
5. **Two rulings became code the same week.** Specials read by a model with exact quotes, no word list (#23252, #23253; Situs 20 of 20, Western Slope 4 of 4 matched the listing). The Anthony hole, our own check emailing Western Slope staff to reply by hand (Oct 27), closed by #22417 the same day.

## C. Where we missed

| Miss | Dropped rule (date) | What production shows | Cost |
|---|---|---|---|
| 1. Opus shipped on top of unconsolidated gates | Gate report order "hold lifecycle first, then fold and delete" awaiting go since Oct 26; Fede Oct 31: "how did we roll out opus without consolidating and fixing all the gates and rewrites?" | Three Situs renters were dropped silently between Oct 27 20:16Z and Oct 28 00:00Z. Jeanine (card c08dd8c5, thread 2fb269b4): three checks fired in a row (booking promise, no tool call, tour-time redraft), nothing sent, no hold row, no card; four days later nobody has replied to her. Tyler (cards 2c3aa774 and 1f058cd7, thread 71fa5b88): his first draft was stopped by a unit-count check with no card; four later drafts were held Oct 28 to 29, one rejected by Fede (eschold_c008df66); his first reply was an email a PropFlow person sent by hand 44.9 hours later; his follow-up text card is still pending after 63 hours. Chataca (card d181a905, thread fb2adfc2): two replies stopped with no check named, nothing sent; 4 minutes later AppFolio sent her a showing notice under a staff member's name. | Opus now runs behind the same checks with zero production measurement. #23954 (Oct 31) gives Jeanine's shape a hold row from now on; Jeanine is still unanswered. |
| 2. Renter-facing holds and queued texts still die unseen | "Every hold ends in a send, a person or an alarm" (#22486, Oct 26) | Emelyn (Situs, card 4b10dedd): first email eschold_83a5fa65 expired after 24 hours; the first staff-written message reached her 25.5 hours after she inquired. A Situs renter called Oct 28; the tour confirmation text (eschold_lr_3c63930d) and the cancellation text (eschold_lr_2b421ee2) both expired unseen, so her receipt for the call never arrived. Follow-up texts: eschold_lt_ecccba5a expired, Tyler's eschold_lt_ab532d59 still pending after 63 hours. Western Slope reply texts: 3 expired, 2 pending; 9 Clara texts sit stuck in the AppFolio text queue. Two Western Slope phone callers (Dora dc885796, and 97db06a3) got nothing after their calls: each follow-up text waited 74 times for an AppFolio record, then expired as stale. Lori's tour (7d9fe683, tour 9dc6f8eb) was booked but never written to AppFolio after 50 tries, and her 1-hour reminder was held as the wrong thread. | #22538 re-alerts emails only (its body: "Leasing only for the re-alert (clara_prospect_email)"); held texts have no alarm. And when a person did act on a Slack card, the card bot sometimes did not: Fede's two "Approve" replies on Deyci card 1793339299 got "Draft unchanged"; his "approve" on card 1793371126 got "Revised per your feedback" quoting words he never wrote, and a session sent the text by hand 11 minutes later; his "Rejected. Do not send" on Lampliter card 1793387032 got "Draft unchanged"; Gera's two questions and Fede's "im on this already" on the Nicole card each produced a rewritten draft. |
| 3. Fact bugs reported resolved reached real renters | "Specials always mentioned"; "no partial sends" (Oct 26); row 127 "Situs 20/20, WS 4/4" (Oct 29) | Yaramin (Situs, Lampliter, 7b77f97b, Oct 30): a send check stripped "4 week free" from a true sentence (ledger: "fact_trace: stripped"); her email kept "after a rent concession" but lost the terms. Her Opus shadow card was handed a different home with no special (Fede: "no mention of concession"); Kerry's (Western Slope, b9274556) was handed the $2,300 home with no special (Fede: "Missed specials") while production named it. Micheal (Western Slope, 8ee909cf) got two first emails 63 seconds apart from one card, naming different Ember homes and prices: 1,228 sq ft "from $2,300/mo" at 14:09:53Z, then 1,289 sq ft at "$2,550 or $2,795 a month depending on lease length" at 14:10:56Z. The ledger ties only the second to the first-touch path (check fired 14:10:49Z, sent after retry), which leaves the first unexplained; inferred: the same inquiry answered through a second door. David got two 48 seconds apart from duplicate cards. Deyci's approved Situs first email (card c9a96584, msg_7ceae9e6) opens "Hi Pedro"; the hand approval did not catch it. | One renter got vaguer terms than the listing; both specials Wrongs trace to the facts handed to the shadow writer, not the model; the fact-trace fix (Patrick, Oct 26: "I've sent the application" held on Clara's own turn) sat under "fix now" since Oct 26. |
| 4. Fede's feedback loop closed late | "Fede ratings are the bar" (Oct 30); "Spanish first-class" (Oct 23); 8 commitments made to Gera | 64 ratings from Fede (27 Wrong, 37 Right); 53 sat unread while the bench said PASS. His Oct 28 to 30 Wrong notes ("No need to say a leasing agent will meet you", Micheal 8ee909cf; "Confusing office hours with availability", Deyci 9278d6a6) got their fix Oct 31 (#24064). No delivered trace for 8 commitments he made to Gera (listed in D row 8); and the Oct 30 tour features (#23858, #23938, #23869) carry his own go in their PR bodies two days after he told Gera "no new features", a course change Gera was not told about. An agency writing for a client at Lampliter (Michael N., b09b8690, eschold_abe02cc4) got a full priced draft from both arms, rejected by hand on Fede's "stay quiet" ruling, which is in neither prompt. | Fede re-asked decisions he had made and called the work "half baked". |
| 5. Statuses lag the work; hygiene debt | "Keep the roadmap current" (Oct 26); "No WIP tomorrow" (Oct 28); "No Slack bursts"; "Tests never write to production" (Oct 26) | 21 tracker rows disagree with their PRs (hold lifecycle "open" with #22538, #22500, #22542, #22559 merged; 6 "wip" rows with no PR). 11 branches of closed PRs on origin, 14 worktrees. Issues #24114 ("Approved, will send" on texts that went) and #24022 (false "Not sent", duplicate text) open. 96 "calendar unreachable" cards from the Oct 25 bench door still in #western-slope. Fake rows written into Patrick's real thread Oct 26. Day 0 (hold decisions) cited as proof for changes to Clara's words. Gera's lane, but a production lesson from the Situs channel: Fede on Oct 28, "Stop the work order created texts. Appfolio already does it", yet such texts kept being drafted and held at Western Slope (eschold_mr_0b1aa8c6, Oct 28 21:09Z, expired), and on Oct 29 Hugo asked that Clara "not do anything with maintenance" through the weekend. | The page Fede reads to know what is untested was wrong on 21 rows; staff saw a wrong status twice. |
| 6. Most Situs leads got no first-email attempt | "track every inbound as an open item" (Oct 26, no trace); the lead-source report promised to Situs (Oct 27, no trace); "if we can do it, we do it" (Sept 30) | 30 of 38 new Situs leads this week had no first-email attempt (measured); the skip reason is logged but never stored, so the cause is inferred from source labels. 8 TurboTenant cards from 7 renters (a9bcb78a, 02ac1d6a, 5c6ed19b, cc393d6c, b16b132b, e6ef77b9, 6e334420, 88f056e0) had an approved source and an email, were each seen within a minute of their AppFolio inquiry time (spread Oct 26 to 30, so real-time leads, not a backfill), and got no draft, no card, no Clara activity; 3 of the 7 never got a staff message either. AppFolio's auto-reply reached 25 of 38 renters first; 14 never got a personally written reply from anyone; Clara answered 9 of 38, median 11.5 minutes. Western Slope, autonomous, same week: 23 of 26, median 2.0 minutes. | The Situs week measured approval speed on 8 leads while 30 went unmeasured and mostly unanswered; whether this is a bug or a gate working as designed cannot be told from the data, which is the miss. |

## D. Roadmap (dependency order)

| # | Piece | Why (Fede's words) | Status |
|---|---|---|---|
| 1 | Gate fire ledger on the Opus arm: every check and rewrite counts fires per model for one week | "count fires on the Opus arm, never fires means delete" (Oct 27) | In motion today |
| 2 | Hold lifecycle for renter texts: alarm and re-alert for held reply and outreach texts; confirm #23954 covers the Jeanine shape on Willows | "every hold ends in a send, a person or an alarm" (Oct 26) | Not started |
| 3 | Seams: row 4 one shouldSpeak log line, no duplicates; row 5 askTheTeam caller collapse; row 6 PmsInbox pass-through (#24118) | "one core engine every module uses" (Oct 24) | In motion today |
| 4 | Fact-trace fixes from the real cases: this turn's tool results count (Patrick); the listing special is a traced source (Yaramin) | "no partial sends"; "specials always mentioned" (Oct 26) | Not started |
| 5 | Fold and delete from the ledger: zero-fire checks on the Opus arm deleted, doors folded per the gate report | "fewer, reliable gates" (Oct 24); "fix all the gates and rewrites" (Oct 31) | Needs the go below, after 1 |
| 6 | Decomposed first-email prompt (row 143) on Opus: bench and shadow, Fede reviews, swap by hand | "decompose, never rewrite" (Oct 24) | Parked |
| 7 | Next swaps: email reply and text reply on Opus, bench and shadow first, Situs and Spanish bench items added | "entire leasing funnel email+text on Opus 5.5" (Oct 30); "Spanish first-class" (Oct 23) | After 5 |
| 8 | Gap audit: the 8 commitments with no trace (Spanish bench slice, 0 items; "get renewals ready", no PR since; supervised-tenant exit plan; lead-source report to Situs; green check on an unsent draft; Western Slope hand-off guidance; "track every inbound", owned by this lane's reply framework and still open; remove old-model rules once on Opus), tracker reconciled to PRs, Fede's ratings read every morning | "never trust a recap" (Oct 27); "Fede ratings are the bar" (Oct 30) | Not started |

**The one decision (yes/hold):** run the gate report's order, hold lifecycle first, then fold and delete from the Opus ledger, before the email-reply and text-reply swaps. Recommend **yes**: each swap is one PR and loses nothing by waiting a week; the gates decide whether a renter hears back at all.

## E. Biggest risk next week

Monday's lead wave is the first real Opus traffic, through checks and rewrite layers tuned for Sonnet, with no production number for how often they fire on Opus. The Sonnet ledger shows both failure shapes: a check fires and the retry sends a trimmed email (Yaramin lost her terms), or nothing goes out and nothing alarms (Jeanine, four days). The bench saw Opus write longer and correct itself in line, so it may trip the checks more often; the visible symptom is more held cards on a weekend when only Fede approves, the invisible one is a renter who hears nothing, which at Situs was already most new leads this week (C row 6). Day one may already have one: of 5 Willows first emails on Opus since the swap, 1 (snapshot c5d5d07c, 14:17Z) has no send recorded, no check fired and no hold; Willows suppresses outbound by design, so it may be nothing, and F item 1 asks. The Opus-arm ledger and the text alarm turn that guess into a number by Tuesday.

## F. Weekend queue (no decision needed), by value per hour

Each item is fix-shaped, no switch, turns nothing on at a customer, sends nothing outbound. S under 200 lines, M under 600.

1. **Find out why the fifth Willows Opus first email has no send recorded** (snapshot c5d5d07c, Oct 31 14:17Z; 0 checks fired, no hold). Read-only, S. Before: 1 unexplained silent first email on the live Opus path, day one.
2. **Situs intake: find why 8 TurboTenant cards with an approved source and an email got no first-email attempt, then store the skip reason on the intent row** (read-only first; a bug is fixed under the grant, a gate working as designed goes to the needs-Fede list). S. Before: 30 of 38 Situs leads with no attempt and no stored reason.
3. **Slack card replies "approve", "approved" and "reject" are commands, never feedback for a rewrite, and a question from a person never produces a new draft.** S to M. Before: 2 approvals and 1 rejection by Fede answered "Draft unchanged" or "Revised per your feedback", 3 questions turned into rewrites. Proof: replay of the four cards, one Willows card.
4. **Alarm and re-alert for held renter texts**, the shape #22538 gave emails. S. Before: 3 Situs and 3 Western Slope renter texts expired unseen this week. Proof: Day 0 byte-identical, Willows held text left to expire.
5. **Fact trace counts this turn's tool results**, so "I've sent the application" is not held when the send ran this turn (Patrick, Oct 26). S. Before: 1 true sentence held. Proof: replay of the card, Willows.
6. **Fact trace treats the listing special as a traced source** (Yaramin: "stripped: 4 week free"). S. Before: 1 email lost its concession, rated Wrong by Fede. Proof: replay of the Lampliter cards, byte-identical elsewhere.
7. **Hold page shows "Sent" after the quiet-hours sweep** (#24114). S. Before: staff see "Approved, will send" on texts that went. Proof: Willows, production screenshot.
8. **Duplicate sends: the session-cold hold marked final yet the text re-sent (#24022), and one inquiry answered twice through two doors (Micheal, C row 3).** S to M. Before: 1 duplicate text with a false "Not sent", 1 renter with two first emails naming different homes. Proof: reproduced-case replay of both, Willows.
9. **Outlook 550 bounce marks the address dead and stops the cadence** (David Jones, Oct 26). S to M. Before: 2 dead addresses treated as live. Proof: replay of the bounce record.
10. **Tracker rows reconciled to their PRs** (status derived, never typed). S. Before: 21 wrong rows. Proof: the refresh output.
11. **Delete the 96 "calendar unreachable" cards** the Oct 25 bench door posted in #western-slope (Fede under the burst: "wtf"; our own bot, internal channel, print the count first). S. Before: 96 junk cards above real alerts.
12. **Branch and worktree cleanup**: print the list first; anything with unpushed work stays Fede's. S. Before: 11 closed-PR branches, 14 worktrees.
13. **Voice and video blank-reply fallback copy**: one constant with an em dash and an unbacked promise. S. Before: 1 string. Proof: unit-covered, one Willows call.
14. **Dark setting proof before it ages out**: the Oct 27 staff welcome text setting (#22648, #22669) crosses 7 days Monday; run its Willows proof and link it on the register. S. Before: 1 setting about to render "prove it or delete it".
15. **AppFolio literals out of core**: 41 in the leasing domain and agent files, one small byte-identical PR per file (Fede, Oct 15). M total. Before: 41.

Not this weekend: deleting the 10 zero-fire checks. Fede's rule is "never fires on the Opus arm"; the ledger holds 4 days of Sonnet. Prepare locally if idle; merge only on the Opus ledger.

**Needs Fede (3 lines):**
- Six-door order go (hold lifecycle first, then fold and delete from the Opus ledger) before the reply-model swaps. Recommend yes.
- Situs under Supervised answered far fewer leads than Western Slope autonomous (A row 8), Fede approved by hand 12 times and customer staff never, and tour confirmation, cancellation and follow-up texts expired unseen: flip those three text kinds to autonomous now, or accept the gap. Recommend flipping confirmation and cancellation; they are the renter's receipt for a call she already made.
- Fixed-template maintenance notices skip review (Western Slope: 46 supervised maintenance holds this week, most expiring). Gera's lane, Fede's call.

Opus 5.5 review (the test-call wording in miss 6 was corrected by its author after ids were pulled)

Full text
# Clara refactor lane: week review, Sat Oct 24 to Sat Oct 31 (Opus 5.5 reviewer)

**In short:** the plumbing is built and proven (the doors, the replay harness, a record of every stopped draft), but Fede's Oct 24 goal is about a third done in production. Opus writes the first email inside the old prompt and checks, and no real renter has had one yet. What hurt renters this week was wrong listing facts (5 of 21 first emails) and checks or holds that silenced them (Jeanine, Tyler). A model swap fixes neither.

## A. Scoreboard

| Goal, Fede's words | What the docs say | What production shows | Verdict |
|---|---|---|---|
| "specialized smaller prompts" (Oct 24) | Split on the bench only; the real split parked Oct 30. | The leasing prompt grew 14% (2,298 to 2,616 lines); Yaramin's email ran on a 47,000-word system prompt. | Not started in production |
| "a higher frontier model" (Oct 24) | Shipped. | First email only, all customers since 05:11Z Oct 31 (#24036), proven at Willows after it went live. No real renter has had one by 16:06Z. Everything else: Sonnet. | Partial, 1 of about 7 prospect jobs |
| "a repeatable way to upgrade it safely" (Oct 24) | Model registry (#22446); the bench upgrade command is in pieces. | Cleared by a hand-run 356-card replay, not the bench, which has no Situs, no Spanish, none of his 8 Wrong cards. | Partial |
| "we need to really question each one" (Oct 26, on checks) | Four of six checkpoints folded, 0 of 5,515 replay cells differing; report: keep 29, delete 7, fold 18. | Re-housed, not reduced: one measured deletion (#23013). Of 10 real fires judged, 3 were false: Jeanine lost her answer, Yaramin her special. | Partial |
| "let me get everything to one central place" (Oct 26) | One door each for speaking, asking the team (23 callers), person lookup, review, tools. | Callers not collapsed. Jeanine's and Patrick's held drafts never got a card. | Partial |
| "a more autonomous opus 5.5 with less checks but only if safe" (Oct 27) | Count Opus fires, delete never-fires: 0 PRs. | First-email stop records carry no model (0 of 43), and no real Opus email has gone out: nothing to count. | Not started |
| "we have too much on our plates", "done done" (Oct 30) | His Oct 27 cap: 3 merged-but-unproven rows. | 42 today. | Missed |

## B. What went well

1. **Fold first, then change.** 31 pass-through PRs put every check behind named doors with no behavior change on real traffic (promise checks: 0 of 1,816,185 differ on 24,543 real texts, #22691); a replay of every real record now guards core PRs (#22872). Western Slope never felt it: all 17 renters got a first reply, 16 within 15 minutes.
2. **Nothing edits Clara's words after she writes them** (#22249, #22296): checks block, one retry, then hold, so the Oct 22 Ember Estates rewrite that put invented unit counts in front of a renter cannot recur.
3. **Every stopped draft leaves a record** (#22659), so checks can now be judged: 7 of 10 fires were right, catching a wrong weekday ("Tuesday November 5", Amy) and an unbacked "I've sent the application".
4. **False "Not sent" labels fixed (#24021).** All 3 approved Situs texts marked unsent had gone out; a Willows text approved at 03:03Z went out at the 8 AM sweep (Twilio SMf9aee1b8).
5. **Specials fixed at the source.** Jose C. (Lampliter) got no special. The cause, a shared sync budget, was proven from 30 days of logs and fixed (#23253, #23252): stored specials Situs 20 of 20, Western Slope 4 of 4.

## C. Where we missed

1. **Opus went in before the cleanup it was meant to follow.** His Oct 26 order was split, fold, Opus in shadow, then his flip; on Oct 27, count Opus fires and delete what never fires. He pulled Opus forward on Oct 30 to 31 ("ok lets pencil in start with first email", then "Well not just situs all customers") on a bar that measured the writer, never the checks. A check re-drafts about a third of first emails in both the replay (114 of 356) and production (5 of 17 since Oct 27), and nobody knows how many were right; one cut Yaramin's special.
2. **False checks and invisible holds silenced renters.** Jeanine (Situs, conversation 2fb269b4, Oct 27) asked for a Friday tour. Checks read "get your full name to lock in the tour" as a booking promise and "5:20 won't quite work" as offering 5:20; the reply was held with no card, and she has no answer on record. Tyler (Situs, 71fa5b88) asked for an application; a check stopped the reply with no card, and Fede answered by hand 45 hours later. Austin (Western Slope) sent references Oct 26; a check held the reply, and staff answered four days later. Yaramin (Lampliter, 7b77f97b) lost her "4 week free" because the fact check could not match it to the listing's "4-week-free"; Fede rated her Opus card Wrong: "no mention of concession".
3. **Wrong facts reached renters; fixes came card by card.** 5 of 21 real first emails named a wrong home or price. Micheal, Bernadette and Kerry (Western Slope) were quoted "374 Ember Lane, 1,228 sq ft, $2,300": the property's own address with a delisted home's size and price (fixed Oct 29). Estrella (Situs) got a delisted home's rent and another home's special in an email Fede approved, as was Deyci's "Hi Pedro". After Kat's "no clear read" tour notes, Micheal and Trang got applications for a home neither had picked. Tour-time handling was patched 8 times in 7 days (#22178 through #24064).
4. **His ratings were not the bar until he caught it.** 53 ratings sat unread Oct 26 to 30 while the bench said PASS on 3 of 4 runs (Fede: "its frustrating its been a whole weeek"). All 8 of his Wrong cards were Opus versions; none is a frozen bench check or re-proven fixed, and Yaramin's still reproduces.
5. **Merged is not done; said is not built.** His cap is 3 merged-but-unproven rows; today 42. Said, not built: every inbound tracked as an open item (Oct 26), Outlook's "550" bounce read as a dead address, no alerts tagging Fede and Gera, the Spanish slice (Oct 23), a supervised tenant-reply exit ("not a month", Oct 21), the green check on unsent supervised drafts (Oct 29). A relay hole known since Oct 16 stayed open until it texted Nicole (Situs, Oct 27, under Supervised) "I've already reviewed the RFTA packet", which nobody had said (fixed that day, #22865). Promises to Gera show no work: renewals, the Situs lead-source report, Western Slope staff guidance. "No new features" (Oct 28, to Gera) changed on his own go two days later (#23858, #23869), without a word to Gera.
6. **Supervision and tests landed on real people.** Supervised mode is a queue only we see: of 110 held messages at the two customers, our team decided 24, client staff none, and 52 timed out. Emelyn's held first email (Situs) expired unseen; a person reached her 25 hours later. Fede's "Approve" on Deyci's reply was misread twice, and a version "revised per your feedback" with words he never wrote went out 9 hours after the card. Test calls from phones registered to our own test residents set off two evening emergency alerts to Situs staff (a third was Situs's own test), and "Michael" left 9 notes on real guest card 9010; today a Situs staffer answered his "$500 rent, 20 dogs" request (conversation f2978476). All after the Oct 26 rule that tests never touch production (#22504).

## D. Roadmap, dependency order

| # | Piece | Why (Fede) | State |
|---|---|---|---|
| 1 | Check ledger: each fire labeled right or false; first-email stop records name the model | "how many times do we rely on re writes?" (Oct 27) | In motion today |
| 2 | Fix false fires at the mechanism, one PR per check, Yaramin's and Jeanine's first | "the core turn needs to add the times not rely on another re write" (Oct 27) | Not started |
| 3 | Row 4: one hold path: every held draft gets a row, a working timer, one log line (#23954 started it) | "let me get everything to one central place" (Oct 26) | In motion today |
| 4 | Row 5: the 23 ask-the-team callers on one interface; none leans on client staff or relays their words unreviewed | "this should have never happened" (Oct 27) | In motion today |
| 5 | Row 6: property-software inbox behind the adapter, pass-through | "this is a big miss" (Oct 15) | In motion today |
| 6 | Delete never-fires, one PR per check, with ledger numbers | "start fresh not just copy paste the issues" (Oct 26) | Waits on 1 |
| 7 | His Wrong cards, Situs and Spanish in the bench | "did u check my ratings" (Oct 29) | Not started |
| 8 | Follow-ups to Opus after the gap audit; proposal: repair on Opus to Gera's lane (his Oct 30 order parks it) | "ok lets pencil in start with first email" (Oct 30) | Gap audit in motion today |

**Decision for Fede (slows his own Oct 30 order):** follow-ups move to Opus only after items 1, 2, 3 and 6, not job by job now? Recommend yes.

## E. Biggest risk next week

The first real Opus emails meet the checks and holds that hurt renters this week, and nobody can tell an Opus fire from a Sonnet fire. Opus cannot fix facts either: the 5 wrong homes or prices came from listing data. If follow-ups move on the narrow bench pass (better on 26 of 53 turns, worse on 19) before the ledger exists, every Wrong card becomes another patch on a 47,000-word prompt. The guard is the order in D.

## F. Weekend queue (no decision needed)

Fixes or proofs under the standing grant (no switch, no turn-on, nothing to real people), by value per hour.

| # | Item | Size | Proof | Before-number |
|---|---|---|---|---|
| 1 | Move our test calls and the "Michael" test lead off Situs's real line and AppFolio to Willows | S | Next test run lands only at Willows | 2 evening alerts to Situs staff; 9 notes on card 9010; staff answered one today |
| 2 | The 24-hour timer fires on later-turn holds | S to M | Tyler's hold replayed at Willows expires | Tyler's hold open 63 hours |
| 3 | Three false fires: "4-week-free" matches "4 week free"; "lock in the tour" and "won't quite work" stop reading as promises | S each | Each real turn replayed keeps its words | 3 of 10 judged fires false |
| 4 | First-email stop records name the model and keep the text finally sent | S | A Willows first email that trips a check | 0 of 43 rows name the model; 2 "held" rows sent anyway |
| 5 | Proof sweep: each unproven row gets a production record or is reopened, #23954 first; misstated rows corrected | S per row | Read-only records, Willows | 42 unproven rows (cap 3); 5 misstated |
| 6 | Delete the availability forced retry (report's delete list) | S | Replay compare | 10 fires in 30 days, 0 real catches |
| 7 | Outlook "550 5.5.0" counts as a dead address | S | Replay of David Jones's bounces | Follow-ups to 2 dead addresses |
| 8 | Hold status tells the truth (#24114, #24033, #24022) | S each | Willows approve; replay of Oct 30 | Wrong status on Willows and Situs holds |
| 9 | Alerts stop tagging Fede and Gera ("it should not tag me and gera") | S | One Willows alert | 13 of 198 alerts this week |
| 10 | His 8 Wrong cards as frozen bench checks | S to M | Each fails on its old input | 0 of 8 |
| 11 | Green check on unsent supervised drafts: tell Smith (Gera's screen) | Message | n/a | "Clara engaged" shown when nothing went out |

**Needs Fede:**
- Spanish bench slice, judged in Spanish with his spot check on 10? Recommend yes.
- Supervised tenant replies ("not a month", Oct 21): exit bar and first customer? Recommend Western Slope after his shadow-card verdicts.
- Situs replies after the first email go live (its open decision 4)? Supervision kept Deyci waiting 9 hours and left Fede answering Tyler by hand, while approved emails still carried a wrong price and name. Recommend yes once weekend items 2 and 3 are proven.

Fede and Gera commitments

Full text
# What Fede told Gera we would do, Oct 20 to 31, and what happened

Every internal Fede and Gera meeting had a raw per-speaker transcript in #transcripts. All quotes come from those transcripts, so no item is recap-only. Not covered: the Oct 20 client leasing meeting. Fede missed the Oct 30 sync, so it is used only for what Gera owns.
Link pattern: `https://propflowai-workspace.slack.com/archives/C0BE1NFTA0K/p<ts without the dot>`. Extractions: `scratchpad/fg/out/*.md`.

## Oct 20, 12:32 and 15:18 (ts 1792517625.060189, 1792527765.013419; raw)
| Fede said | Topic | Promised / by when | What happened | Status |
|---|---|---|---|---|
| "I want to flip maintenance to be through a folio... Like, this week, that should happen." | Maintenance over AppFolio | This week | Handed to Gera on Oct 21. Gera's resident maintenance text now wakes Clara on the AppFolio thread (#21946, #21942). | Done (by Gera) |
| "Hopefully by today or tomorrow. I'll turn it on. We need it for Cytos Group." | AppFolio messaging, Situs first | Oct 20-21 | Western Slope leasing went on Oct 20, before Situs. Situs leasing is in supervised mode. | Partial |

## Oct 20, 17:20 (ts 1792534991.156149; raw)
| Fede said | Topic | Promised / by when | What happened | Status |
|---|---|---|---|---|
| "there's no source recorded, so I'll fix that. Fixing that right now" | Situs lead source | Now | #21536 merged Oct 20 | Done |
| "I'll supervise it for a week" | Situs leasing | A week | Still supervised on Oct 29. Opus first email autonomous Oct 31. | Partial |
| "start with very simple one doc... save the draft... have them do the final review" | WS renewals | Next meeting | Renewal packet built (#21876, #21956). WS deep-dive still pending. | Partial |

## Oct 21, 13:31 and 18:25 debrief (ts 1792607607.941179, 1792625319.521779; raw)
| Fede said | Topic | Promised / by when | What happened | Status |
|---|---|---|---|---|
| "turn it on supervised so that at least we know what would have happened" | Tenant inbox | Not stated | Shadow cards on every WS and Situs tenant text (opus-shadow-week) | Partial (shadow only) |
| "I don't think we should leave supervised mode for, like, a month" | Exit plan | Under a month | Tenant replies are still off everywhere, with no exit date | Not started |

## Oct 22, 18:29 (ts 1792712041.671219; raw)
| Fede said | Topic | Promised / by when | What happened | Status |
|---|---|---|---|---|
| "I'm gonna basically copy this for leasing for the next meeting" | Leasing who-owns-what for WS | Next meeting | Map drafted on the master page, not delivered (row situs-intro open) | Partial |
| "Put on some clear guidance for them... put the notes on the guest card" | Staff hand-off | Next meeting | No guidance document found | Not started |

## Oct 23, 13:02 (ts 1792778693.072789; raw)
| Fede said | Topic | Promised / by when | What happened | Status |
|---|---|---|---|---|
| "I want to clean up the prompt... a benchmark tool... upgrade models easily" | Baseline, Fede owns | Weeks to months | Gates folded into six checks. shouldSpeak PR2 in progress. | Partial |
| "my strategy of, like, haiku classifiers is kind of stupid" | Gates | Direction | Checks merged into fewer checkpoints, but the rewrite and retry layers still exist (tracker row open) | Partial |
| "upgrade to Opus 5.5. As a main model everywhere" | Model | Direction | Opus live only on the first email (#24036, Oct 31). Tenant texts, repair and voice wait. | Partial |

## Oct 23, 17:11 (ts 1792793634.155599; raw)
| Fede said | Topic | Promised / by when | What happened | Status |
|---|---|---|---|---|
| "running all the tenant communications through Opus 5.5... I'm gonna work on it all weekend" | Tenant comms on Opus | Weekend | Shadow ran. Repair on Opus in progress. Tenant replies off. | Partial |
| "once we have high confidence, we'll flip it. So it might take, like, a week" | Flip | About Oct 30 | Not flipped. On Oct 27 Fede made leasing the priority. | Not started |
| "I'm gonna be working on our benchmark in Spanish" | Spanish slice | Not stated | The Spanish benchmark slice has 0 items. Bench item #52 waits on Fede. | Not started |

## Oct 26, 15:05 and 18:18 (ts 1793045326.934169, 1793056944.308289; raw)
| Fede said | Topic | Promised / by when | What happened | Status |
|---|---|---|---|---|
| "let me get everything to one central place... just refactor" | Turn-decision framework | In progress | #22450, #22473, #22522, and about 20 merge PRs that combine duplicated code | Done (pass-through refactor) |
| "Cutting it down into pieces" (core prompt) | Prompt split | Since Friday | The leasing pure split merged. The real split by deletion is parked. The core prompt is not split. | Partial |
| "I think that should be our focus right now" (tenant inbox replies) | Priority | A couple of weeks | Fede moved the focus to Situs leasing in front of Gera on Oct 27 | Not started (superseded Oct 27) |
| "every single thing that comes in. We're tracking it somewhere" | Open items | Not stated | No open-item tracker. The rows "quiet-signal" and "hold-lifecycle" are open. | Not started |
| "the readiness gate is... replay the last 30 days... graduate" | Readiness | Not stated | Floors dropped Oct 25. The Opus swap went live after a bench PASS, his ratings and a Willows end-to-end run, with no 30-day replay score. | Partial |

## Oct 27, 11:37 (ts 1793119142.587719; raw)
| Fede said | Topic | Promised / by when | What happened | Status |
|---|---|---|---|---|
| "Opus 5 doesn't need that" (remove old rules) | Prompt rules | Not stated | Rewrite and retry audit open. "Delete layers after swap" open. | Not started |

## Oct 27, 17:58 (ts 1793142132.987359; raw)
| Fede said | Topic | Promised / by when | What happened | Status |
|---|---|---|---|---|
| "Our goal should be to be live... By end of week. With leasing" | Situs leasing | Oct 31 | Phones live Oct 28. First email autonomous. Other leasing paths supervised. | Partial |
| "Claire can read their email and then create the guest card" | Situs lead intake | Not stated | #23047, #24013, #24038 (TurboTenant, AffordableHousing) | Done (merged) |
| "I'm going to send [contact] a little report" | Situs lead sources | Not stated | Not found | Not started |
| "get renewals ready" | Renewals | This weekend | No renewals PRs merged Oct 28 to 31 | Not started |

## Oct 28, 19:04 Situs go-live debrief (ts 1793238193.424549; raw)
| Fede said | Topic | Promised / by when | What happened | Status |
|---|---|---|---|---|
| "by the end of this week, I wanna... Just let it... All by itself" | Situs leasing autonomous | Oct 31 | Only the first email is autonomous. Gera says the Situs leasing paths are still supervised. | Partial |
| "It's a bug. I'll own that." (backup calendar) | Tours | Not stated | #23587 (the offered slot carries its host) | Done (likely) |
| "address matching, alias... tomorrow morning" | Property match | Oct 29 | #23382 merged. Ember Estates design handed to the Situs Leasing session. | Partial |
| "No new features. Let's just fix this." | Priority | Now | Zoom tour recaps (#23858, #23938) and trip-aware tours (#23869), on Fede's later go | Contradicted |

## Oct 29, 18:49 (ts 1793317995.367689; raw)
| Fede said | Topic | Promised / by when | What happened | Status |
|---|---|---|---|---|
| "I want to keep it a few more days... Supervised, and then... Turn it on" | Situs leasing | A few days | First email went autonomous Oct 31 05:11Z | Partial |
| "if it's supervised, do not do the green checkmark" | Supervised UI bug | Not stated | No PR found (#21371 on Oct 20 is a different screen) | Not started |
| "I might just do it on the weekend... ready by Monday" (Orca) | Orca integration | Nov 2 | #23702, #23667, #23740 merged Oct 30 | Done |

## Commitments with no trace of work
1. Track every inbound message as an open item (Oct 26).
2. A Spanish slice in the benchmark (Oct 23). It has 0 items.
3. An exit plan for tenant replies in supervised mode, "not a month" (Oct 21).
4. The lead-source report to Situs (Oct 27).
5. "Get renewals ready" (Oct 27). No renewals PRs have merged since.
6. The fix for the green checkmark on unsent supervised drafts (Oct 29).
7. Remove the rules older models needed once Clara is on Opus (Oct 27).
8. Staff hand-off guidance for Western Slope (Oct 22). The who-owns-what map is drafted but was never delivered.

## Where what we built contradicts what he told Gera
- **No new features.** He said this on Oct 28. On Oct 30 Zoom tour transcripts and recaps and trip-aware tour offers merged. Both were built on Fede's own go in other sessions ("yes build it"), so this is Fede changing his mind without telling Gera, not a session acting alone. The Orca work doesn't count, because he told Gera about it on Oct 29.
- **Maintenance is Gera's lane.** On Oct 26 he said "I'm not gonna fix anything maintenance-related." Our lane still runs the repair path on Opus (tracker row repair-path, in progress). Check this with Gera.
- **Not contradictions, but changed in front of Gera.** "Tenant inbox is our focus" (Oct 26) became "I'll focus on getting leasing on" (Oct 27). "Opus everywhere, fewer gates" is unfinished, not reversed.

## What Gera owns (not our misses)
Maintenance end to end. Also: the topic classifier and gatekeeper (Paths tab, path modes), tenant-side PMS messaging (from Oct 21), Situs phones (Crescendo, MCC routing, on-call sync, the Monday maintenance turn-on), Yardi and ConAm, CI/CD speed and the break-glass lane, alert noise, ingest and the questionnaires, the meeting note-taker, Bitwarden, the admin shadow view, and the resident-questions digest (#24103). On Oct 30 Gera said the Situs leasing path modes are Fede's to set, and he wants to review every path with Fede.

12 · Gates

Gate triage: the fate of every check (Oct 31)

Fede: "theres too many gates and too many layers where we re write the ai output sometimes with not enough context or false fires. that was designed for an older sonnet model. now that we are on more intelligent models, we want to rely on the model reasoning giving it all the right context, so 100 gates need to be inspected and refactored or removed." He said yes to the six-step order. Below, every check and rewrite layer gets one fate. Read only, main 9c971af59b.

Rules, applied in order

The count

KeepContextFoldDeleteRetry onlyTotal
Checks that hold or block1871016333249
Layers that rewrite the words1100223972

So 123 of 321 distinct rows change or go. Most keeps are send rules and intake skips that never judge Clara's words.

What the fires say

Per family

FamilyRowsKeepCtxFoldDelRetryFires right / false (30d)Proof for its PRSizeWave
H1 Supervised reply holds191800100 / 0Day 0 onlyS1
H2 Maintenance and renewal template holds8800000 / 0no PR, all keep
H3 Hold lifecycle121100100 / 0Step 1 Willows expiry re-alertS1
H4 First-email draft checks304241827 / 14Day 0; 356-card replay; 6 judged draftsM, 2 PRs1
H5 Tour time from this turn1010000 / 1Day 0; 3 false holds replayed with slot idsS2
H6 Main-loop draft checks182186120 / 14Day 0; 22 judged drafts replayedM, 3 PRs1
H7 Forced lookup retries8330203 / 7Day 0; 10 judged retries with slots and units inS2
H8 Turn silencers1311101012 / 0Day 0; 12 right closers still silentS1
H9 Send-door refusals595710100 / 0Day 0 onlyS3
H10 Lead intake skips292900000 / 0no PR, all keep
H11 Cadence and reminder gates252410003 / 0Day 0; 2 cadence drafts with unit facts inS2
H12 Fair housing2200000 / 1no PR, all keep
H13 Hold could not be written3300000 / 0no PR, all keep
H14 Quiet hours7600100 / 0ledger only (already gone)S1
H15 Voice call gates7700000 / 0no PR, all keep
W1 Internal-text strips71013212 / 0Day 0; 6 stamp catches retried, never cutS1
W2 Draft salvage3000120 / 0Day 0; drafts that lost a link or priceS4
W3 Hand-off rewrites7301215 / 3Day 0; 3 hand-off fires vs the open-ask recordS1
W4 Voice and video rewrites2120031641 / 38 (shared counts)Day 0; recorder first, then call replays; 33 text draftsL, per check4
W5 Staff-facing rewrites7002140 / 0Day 0; add the stop record firstS4
W6 Email template words7100600 / 0Day 0; 356-card greeting check; Fede rules on footerS4
W7 Bounce fallback1000100 / 0bounce fixturesS4
W8 Side writers to renters10000370 / 0Willows run per writer; add the stop record firstM4
W9 Side writers to PMS and staff12100470 / 0Willows run per writer; add the stop record firstM4
W10 Transport cosmetics5500000 / 0no PR, all keep

"Day 0" means the replay grid stays byte-identical outside the cells the PR names. Fires before Oct 27 left no stored draft, so each PR says how many of its fires it could replay. S is under 200 lines, M under 600.

Waves

  1. Wave 1, no dependency (34 rows plus 5 already gone). 18 first-email checks with zero or only false fires; the booking-promise phrase list everywhere (16 false, 0 right) and its twins; the sensitive-number check (judgement call); the farewell loop; two dead flags; five strips and rewrites with no catch, plus the templated hand-off reply (1 right, 1 false; judgement call). The emergency guard is held back.
  2. Wave 2, after step 2 (facts with ids plus the open-ask record). The ten context rows: forced lookups, tour time, "no tour times", the fact trace, promise backing, cadence units, the takeover record.

    Correction, Nov 1: wave 2 deferred. Seven of the ten context rows need facts with ids in the main loop (later turns), which steps 2 and 3 built only for the first email; that input is being built first. C30 (no tour times offered) stays: on 357 first emails replayed on Opus it fires 34 times, about 6 of them real misses (all Situs), so it is not foldable until a prompt fix plus a bench run. C40 (fact trace) waits for door 4 to leave observe mode (wave 3).

  3. Wave 3, after step 4 runs a week in observe mode. The 16 folds: unit count, weekday, money, work-order claim, final send check.
  4. Wave 4, with step 5. Rewrites become retry once then send, voice first. Dash checks go retry-only (step 5 came after the Oct 23 blocking rule). Template greeting and footer wait on Fede.

Flags

Every row, with file, origin, fires and reason, is in gate-triage-ledger-2026-10-31.json (001 session).

13 · Funnel inspection

Why a separate multi-turn prompt? There is none. One writer per channel, with the turn as context

Fede, Oct 31: "did we inspect what needs to happen to also bring the model to multi turn and cover all leasing funnel", "why we even have a separate multi turn prompt is an open item", "i want both agents to inspect that". Fable 5.1 and Opus 5.5 inspected independently (code on main, production turn snapshots, the draft-stop log, 15 real Western Slope and Situs threads with 47 later turns, read-only). They reached the same verdict.

Answer

Decision (by the evidence Fede asked for)

Option A, one writer per channel, the turn as context. Keep the one prompt. The first-touch block renders whenever Clara has not written yet, cold email included. Every turn gets facts with ids, a calendar read, declared asks and one claims check. Then one model per channel, one PR per job. The Oct 30 first-email split is NOT merged as a second prompt (on today's inputs every arm, split or not, avoided all 6 of Fede's misses: the inputs were the cause); its other-job and duplicate cuts (about 15K characters) become the first trim of the one prompt, proven on the replay after the inputs land. Rejected: B, two prompts (23% fewer first-email tokens, two of everything to keep from drifting); C, swap later turns to Opus as they are (marginal bench 26/8/19, no Spanish, no booking turns, Opus without the facts it used well on turn 1).

The jobs

JobModel todayWhat turn N lacks vs turn 1BenchBefore its Opus swap
First email to a guest cardOpus 5.5 (all customers since Oct 31 05:11Z)n/a73 items + 356-card replayDone
Cold prospect email, no cardDoor decides: listing-site email from a new sender gets the Opus first-email path; anything else the Sonnet loop with no factsfacts, ids, calendar, declarationnoneFirst-touch block on every first touch
Later email repliesSonnet 5, path shared with tenant emailsfacts block (0 of 44 had it), code calendar read (9 of 44), declaration, ids, open asks53 real turns (WS 42, Situs 11, Spanish 0)Prospect-only model path; facts on turn N; bench with Spanish and Situs slices
Later text repliesSonnet 5, path shared with tenant textssame0 gradedas email replies, plus the tenant/prospect split
First reply text (60 s after the email)Haiku 4.5 by direct import, no model-path rowcondenses the email44-item prototypeModel-path row; lowest risk
Tour times, booking, reschedule, cancelthe turn's model; Haiku reads firstcode calendar read35 of 53 bench follow-ups could not bookCode calendar read on turn N; a bench that books
Confirmations, reminders, nudge to confirmtemplatesn/anonenothing to swap
Quiet-lead texts and emailsHaiku 4.5, own prompt, no thread, no ids, bans specialseverythingtiming only, no delivered textRecord its input (0 recorded today); fold into the channel writer
Application questions and linkthe turn's modelas replies18 casesas replies; Fede's Oct 31 Situs ruling (applicants get no reply) not yet on main
Reviewer-asked redraft of a held messageSonnet 5, even for a held first emailoutside the loop, unrecordednonesame writer as the channel

Shared pieces, in the six-step order

PieceTodayMissingStep
One prompt builderyes, every turnnothingdone
One model path per prospect jobreplies share a setting with tenant replies; two side writers read a tier alias, invisible to the swap mechanismprospect-only reply paths; rows for the first-reply text and the quiet-lead writernow (hygiene, no behavior change)
Facts with ids, every turnfirst email only (#24125 fixed "open now")every turn, cold email and quiet-lead too; ids on each fact line2
This turn's calendar readfirst email onlyany turn that talks times; count a dispatcher read as this turn's read2
Actions taken, as records with idsa completed-actions block, no ids; automated texts reach the writer as Clara's own repliesids; label automated texts; never the card-time instruction2
Declarationdeclared-asks tool, first email onlyevery prospect turn, email and text, with the ids used3
One claims checkregistry exists; fact trace on the first email only; three checks run twice on turn 1fact trace on every turn; special-to-home match (Situs fe4f838f: the offer landed on the wrong home through two human approvals)4
Lookups by code, not forcingclaim-gate retries force a tool call; rejected on Opuscode-run reads4
One model per channelOpus first email; Sonnet replies and redraft; Haiku shortener and nudgeone setting per channel writer; swaps one PR per job, Fede's ratings as the bar, then the Willows end-to-end pathafter 4

Outside the prompt question

Full texts

Fable 5.1 inspection

Full text
# Leasing funnel on Opus: every writer, why two prompts, what moves as one

Fable reviewer, Oct 31 2026. Read-only: code on main (9c971af59b), production turn records by key (propflow-prod, Oct 24 to 31), prompts rendered offline.

## 0. Answer first

Every reply turn comes from one function (`getUnifiedSystemPrompt`); the FIRST email is the special case, the same prompt plus a first-turn pack (facts block, about 20 rules, code calendar read, declaration tool, second check stack, Opus 5.5). The one separate multi-turn writer is the quiet-lead nudge (row 7, Haiku, own 2,907-char prompt). Verdict: one writer per channel with the turn as context; close turn N's gap and fold the nudge in (2e, 3).

## 1. Map: every prospect-facing writer job

CM = `agents/clara/lib/agent/conversation-manager.ts`; CU = `clara-unified.ts`; MP = `platform/ai/model-paths.ts`; GFM = `leasing/generate-followup-message.ts`. Bench = items / Situs / Spanish. Loop checks = post-draft checks at CM:15243-16671, one retry then a hold.

| # | Job and where | Model | Writer gets | Checks and rewrites | Bench | Willows proof | Before Opus swap |
|---|---|---|---|---|---|---|---|
| 1 | First email to a guest card: `guest-card-engine-turn.ts:668` → CM loop, `inboundSource.kind = pms_guest_card` | Opus 5.5 (MP:44, live since Oct 31 05:11Z) | Card text; facts block (homes, verdict, alternatives, rent, special, slots), no record ids; slots read by code (CM:10103); ~20 overriding rules (CU:1181-1411); `declare_deferred_asks` | Loop checks, then fact trace plus 14 named checks; up to two retries | 73 / not stated / 0 | `guest-card-harness/real-send.ts` | Done |
| 2 | Direct prospect email, no card: `inbound-processor/handler.ts:1441`, `email-lead-engine-reply.ts:202` | All three customers carry `leadSource = listing_site_email` (production ORG rows): a new sender's listing-site email takes row 1 on Opus; a known person or plain email takes the Sonnet 5 loop, no pack | Row 1, or row 3 on an empty thread | Row 1, or row 3 | 0 | email the Willows mailbox as a sandbox persona | Moves with row 3 |
| 3 | Email follow-up reply: CM loop, CU:1449 plus the email overlay | Sonnet 5 (`emailReply`, shared with tenant emails, CM:3637) | Full thread; blocks for actions this turn, available units, open matter, cadence events, conversation and tour state. Missing vs turn 1: facts, ids, code calendar read, declaration tool, first-email rules, open asks | Claim gates with a forced-tool retry (CM:13063; `auto` on Opus 5.5); loop checks; escalation may swap in a template | 53 real turns (WS 42, Situs 11) / 11 / 0; no frozen set | `email-personas.ts --live` | Prospect-only path; forced retries replaced; bench pass (Oct 30-31: 26 better / 8 tie / 19 worse); facts on turn N |
| 4 | Text follow-up reply: same loop | Sonnet 5 (`textReply`, shared with tenant texts) | As row 3, no overlay; the router's tour pipeline (Haiku) can book before the model | As row 3 | 0 / 0 / 0 | text the Willows line from a tester number | As row 3 plus the audience split (tenant texts wait) |
| 5 | First reply text, 60 s after the first email (`activities/first-reply-text.ts:163`) | Haiku 4.5 by direct import, no MP row | The lead's message and the delivered email | Every number and time must appear in the email; one retry then a template | 0 | a Willows card with a registered phone and consent | MP row; lowest risk |
| 6 | Tour times, booking, reschedule, cancel: tools inside rows 1-4; pre-turn pipeline (`process-tour.ts:218`) | the turn's model | Turn 1: slots in the facts. Turn N: the model must call `get_tour_slots` | tour-time and booking gates (turn 2+) | inside rows 1 and 3 | `email-personas.ts p1_tour_saturday_confirm`, `p2_tour_reschedule_sunday` | Code calendar read on turn N; booking unproven on Opus (35 of 53 bench follow-ups could not book) |
| 7 | Quiet-lead nudge (+24 h, +48 h, +7 d, +14 d) and re-engagement (`prospect-outreach.ts:476` → GFM:711) | Haiku 4.5 by direct import (GFM:36), no MP row | Own prompt (GFM:554-665): no thread, "NO tour calendar", no ids, no rent except a verified drop | `followUpFinding` (dash, pricing, policy, slots, availability); one retry then held | 0; no recorded input | `email-personas.ts p8_goes_silent`, real schedule | MP row; input recorder; fold into the loop |
| 8 | Application questions: the loop, `send_application`, status and denied blocks | the turn's model | rows 3-4 plus the leasing block | loop checks | 0 | `email-personas.ts p5_application_link` | As rows 3-4; no code for Fede's Oct 31 Situs ruling (applicants get no reply) on main 1bf5423cb8 |

Not in the table: the escalated tour-booking-only turn (CM:18781) writes nothing a person reads; confirmations, reminders and application links are templates; voice is an ElevenLabs-hosted agent with its own prompt.

## 2. Why a separate multi-turn prompt?

### 2a. Rendered prompts

| Writer | Model | System prompt | Thread seen |
|---|---|---|---|
| First email | Opus 5.5 | 268,419 chars (~67k tokens), 23 tools | the card only |
| Email follow-up | Sonnet 5 | 249,589 chars (~62k), 22 tools | full |
| Text follow-up | Sonnet 5 | 223,055 chars (~56k) | full |
| Nudge | Haiku 4.5 | 2,907 chars, no tools | none |

99.5% of the follow-up prompt's words are in the first-email prompt (43,326 of 43,540); the first email adds 3,639 words, the follow-up 214. A production pair (8857096c, 1c981bfa) agrees: 27,385 chars only on the first email, 6,018 only on the follow-up.

### 2b. What is only on one side

| Only on the first email (28 lines) | Count | Belongs |
|---|---|---|
| Rules that read the facts block (opening names the home, gone home, unknown availability, short open list) | 10 | with the facts block, on any turn |
| General writing rules (price per size, money as fact, special as written, never volunteer a gap, book a requested open time) | 11 | shared prompt, every turn |
| First-touch lines (real greeting, one sentence on a PMS-made card, no-promises wording, declare the asks, tour times close the email) | 5 | keep, switched on "nobody has written back yet" |
| Booked-tour close and confirmed-tour exception | 2 | every turn |

Only on follow-ups: the specials hedge "on select apartments, restrictions may apply" (CU:815-822), retired from first emails by the code's own note (CU:1330-1337) for inventing a condition, against Fede's Oct 26 ruling; and the returning-person summary (CU:1992-1995), context. In production it rendered in 4 of 44 follow-up prompts and reached 0 bodies (2d): the one follow-up-only rule did nothing.

### 2c. Where the sides disagree

1. Same special, three rules: email 1 quotes it as written, email 2 may hedge it, the nudge may not mention it (GFM:569).
2. Tour times: the first email must offer real times; the nudge must never propose one (GFM:589-596).
3. A known person's new card gets both "pick up where you left off" and "never reference an earlier message".
4. Forcing: `modelAcceptsForcedToolChoice` (`model-tiers.ts:448`) rejects `claude-opus-5-5`, so every forced retry becomes `auto` plus a reminder (CM:3689); turn 1 reads the calendar in code, turn N depends on forcing.

### 2d. Production threads this week (ids only)

84 prospect writer turns on 34 Western Slope and Situs threads, all on Sonnet 5; 15 threads read turn by turn (42 of the 44 follow-ups).

| Input | Guest-card turn 1 (25) | Follow-ups (44) |
|---|---|---|
| Facts block with tour slots | 25 | 0 |
| Calendar read this turn | 4 by tool, 25 via the facts | 9 |
| Dispatcher "actions taken" note plus company home list | 7 | 29 |
| Specials hedge rule in the prompt / in the body | 0 / 0 (ban in 11 of 14 read) | 4 / 0 |
| Follow-up-only inputs: helped / hurt / nothing | | 8 / 8 / 26 |

Helped (8): 4 tours the dispatcher booked before the writer ran (4ffbe01d T3, 8ee909cf T3, b26a5299 T4, bdaed90a T2), 2 dispatcher calendar answers, 2 home-list answers. All records of something done.

Hurt (8): a named time misread as "more than one option" cost a round trip (3edfcfc7 T3, 1010d08d T3); the card-time "ask them for a date" note rode along for days (17 of 29, 3 while a tour was booked); a false "prospect created" note (fb2adfc2 T2); the home list sat behind all 3 unit-count rewrites, 0 of 39 turns without one; an application never sent: `send_application` got a typed address, not an id (a9a3b173 T4-T5); re-inquiries got no tour times (3aad8363 T3, 3edfcfc7 T6). The quiet-lead texts, which never see the facts, named a different home than the first email on 2 of 3 threads (b9274556, 303e8770). Every hurt is an instruction, a list, or a missing id.

Outside the prompt question: 5 Situs drafts were held with no review card ever created, so never sent (71fa5b88 T1, 2fb269b4 T1-T2, fb2adfc2 T1-T2); approved replies left 1 to 42 min after the turn, one after 9 h.

### 2e. Verdict

**One writer per channel, with the turn as context; the nudge prompt is the one to delete.** The follow-up is already the same writer (2a), its extra inputs helped only as records of done actions (2d), the week's worst misses were missing ids and facts on later turns (2d), and Opus makes those worse because forcing is ignored (2c).

| Option | Risk | Containment |
|---|---|---|
| One writer per channel | Moving the first email's rules onto replies without the facts they read is the regression path; proof is bench plus shadow, not a byte-identical replay | Context first (step B), rules second, one group at a time; today's first email is the bar |
| Keep two | Drift: the specials fix reached one side; the nudge bans what the first email requires; every fix costs two reviews and benches | Discipline only |
| Either | Three models muddy any "follow-ups are worse" reading | Compare both turns on one model first |

## 3. Shared pieces so the funnel moves as one

| Piece | Exists | Missing | Order |
|---|---|---|---|
| A. One model path per prospect job | MP rows `firstEmail`, `emailReply`, `textReply`; reply path by channel; rows 5 and 7 import `FAST_MODEL` | Prospect-only reply paths from the turn's identity; MP rows for rows 5 and 7, else a reply swap moves tenant replies | 1 |
| B. One context builder | Turn 1: facts and code calendar read. Turn N: eight blocks, each its own reader | Facts every turn; ids on each fact line (none today, `guest-card-home-facts.ts:699`); code calendar read on turn N; an open-asks block; "actions taken" as records with ids and results, never the card-time instruction | 2 |
| E. Lookups without forcing | `forcedToolChoiceFor` turns forcing into `auto` on Opus 5.5 | Replace claim-gate retries with code-run reads from B; count a dispatcher read as this turn's read | 3 |
| C. One declaration schema | `declare_deferred_asks` (max 8) on the guest-card email turn only | Same tool on every prospect turn | 4 |
| D. One claims check | Turn 1: fact trace plus 14 checks. Turn N: claim gates and loop checks; three run twice on turn 1 | Fact trace on turn N (ids from B); one list for both stacks; one retry budget | 5 |
| Swaps | first email done | one PR per job: email follow-up, text follow-up (after the split), first reply text, nudge (after a recorder); Fede's ratings as the bar, Situs and Spanish slices in every set, then the Willows path | 6 |

After steps 2 to 5 nothing in the code needs a second prompt; the nudge folds into the loop once B exists, so it gets the calendar and the special it is banned from today.

Opus 5.5 inspection (its "helped 5 of 5" count was corrected by its author to 2 helped, 3 nothing)

Full text
# Leasing funnel inspection (Opus 5.5 reviewer), Oct 31

Read-only. Code: main ff9fe58645. Production: 7 turn snapshots diffed, the draft-stop log (Oct 27 to 31) and 15 multi-turn threads at Western Slope (WS) and Situs. Ids only.

**In short**
- **There is no separate multi-turn prompt in production; what is separate is the first email's inputs, checks and model.** On WS card 3060 the first email and the next email share 1,046 identical prompt lines; 48 are first-email only, 6 reply only.
- Only the first email gets the home facts, tour times read ahead, the declared-asks tool, its own word checks and Opus. Of 47 real later turns, 12 went wrong or missed the ask; none traces to a rule difference, since every later-turn rule also renders on turn 1 (2d, 2e).
- **Verdict: one writer per channel, with the turn as context.** The prompt already is one; "delete, not swap" means giving every turn the first email's inputs and checks, then one model per channel. Do not merge the first-email split as a second prompt.

## 1. Every prospect-facing writer job

**1a. The jobs**

| # | Job | Code (entry → writer) | Model today | Turn 1 vs later turns |
|---|---|---|---|---|
| J1 | First email, guest card | guest-card-engine-turn.ts → agent loop | Opus 5.5 (since 05:11Z) | Only turn with home facts (rent, special per listing, open now), tour times read ahead, stated budget, declared-asks tool, 18 first-email rules |
| J2 | Text right after the first email | first-reply-text-condense.ts | Haiku 4.5 | The sent email only |
| J3 | Cold email, no guest card | inbound-router.ts → agent loop | Sonnet 5 | A first touch run as a reply: no facts, no tour times, no declared asks |
| J4 | Later email replies | agent loop | Sonnet 5 | Thread (80K tokens), unit list without specials or ids, completed actions, tour state; calendar and specials by tool call only |
| J5 | Later text replies | agent loop, no email clauses | Sonnet 5 | Same as J4 |
| J6 | Tour times and booking | J4/J5 tools; Haiku reads run first | Sonnet 5 writes; Haiku 4.5 reads | Turn 1: times read in code. Later: the model must call the tool |
| J7 | Confirmations, reminders, unconfirmed nudge | tour.ts, send-tour-outcome-sms.ts | none: templates | n/a |
| J8 | Reschedule, cancel, decline | template, then the J4/J5 reply | Sonnet 5 | as J4/J5 |
| J9 | Quiet-lead texts and emails | generate-followup-message.ts (two scheduled callers) | Haiku 4.5 | Fields only: no thread (went-quiet gets 4 messages), no rent, no tour times; its prompt bans specials |
| J10 | Application questions and link | J4/J5 reply; link sends are templates | Sonnet 5 | as J4/J5 |
| J11 | Reviewer-asked redraft of a held message | review-redraft.ts → read-only-leasing-draft.ts:46 | Sonnet 5, even for a held first email | Outside the loop, unrecorded |

Out of scope: voice, video, staff desk.

**1b. What proves each job**

| # | Checks fired, WS + Situs, Oct 27 to 31 | Input recorded | Bench | Willows run; before Opus |
|---|---|---|---|---|
| J1 | first-email checks 5 (all sent after a retry); dashes 1, no-tool-call 1 held; Situs review holds 7 | yes | v1 set 73 (Spanish 4); 356-card replay 161/139/56 better/tie/worse | card 365 on Opus today; no customer email read yet |
| J2 | none logged | no | 44-item prototype | none; record input first |
| J3 | 7 stops, all held (Situs) | yes | none; the door cannot rebuild it | email-stress; needs first-touch input |
| J4 | tour time without a calendar read 3, unit count 2, booking promise 1, promise backing 1; Situs review holds 6 (1 approved) | yes, since Oct 24 | 53 real later turns (WS 42, Situs 11, Spanish 0): Opus 26/8/19; frozen reply set empty | email-stress; no Opus run from times to confirmation |
| J5 | silence 3, dashes 1, weekday 1; Situs hold 1 | yes | inside the 53; 26 shadow pairs | sms-stress; as J4 |
| J6 | inside J4 | Haiku reads no | bookings blocked: 35 of 53 lack the confirmation reply | sms-stress tours; needs a bench that books |
| J7 | n/a | n/a | none | tour-confirm harness; nothing to swap |
| J8 | inside J4/J5 | yes | none separate | reschedule gauntlet (16); rides J4/J5 |
| J9 | copy check 2; 15 stops; Situs holds 9; the went-quiet path logs nothing | no | 39 real touches; 155-item writer set, 80 synthetic | timing only, no delivered text; record input, settle the specials ban |
| J10 | inside J4/J5 | yes | 18-case dataset | persona p5; rides J4/J5 |
| J11 | not logged | no | none | none; same writer as J1/J4 |

J4, J5, J6, J8 and J10 share two model settings, so they move together. Several Willows harnesses still email as Fede (Oct 27 rule).

## 2. Why a separate multi-turn prompt? There is none

**2a. What differs between turns** (WS card 3060, conversation 1010d08d, Oct 30, prompt version 26b72399b7)

| Block, characters | First email | Later email | Later text |
|---|---|---|---|
| Leasing rules (every later-turn rule lives here) | 187,288 | identical | identical, less 910 phone lines |
| Home facts: special per listing, open now, tour times | 1,053 | none; unit numbers only (specials only via the unit lookup) | none |
| 18 first-email rules, which "override anything below that disagrees" | 14,902 | none | none |
| Email clauses | 29,658 | 24,076 | none (text rules instead) |
| Whole system prompt | 271,561 (about 95K tokens) | 250,194 | 225,720 |
| Declared-asks tool | yes | no | no |
| Checks on the words | loop checks plus fact trace, draft checks, body guard, retry then hold | loop checks | loop checks |
| Model | Opus 5.5 | Sonnet 5 | Sonnet 5 |

Snapshots tsnap_29c42a08, tsnap_703caa57, tsnap_878096f4. Situs pair tsnap_9dae7e08, tsnap_3c72eb70: same shape.

**2b. How it got here.** Two merges made it one prompt: one email core for every prospect email (#9966, Sep 19: "so a reply in an ongoing conversation reads consistently with the first email"), then the old first-email composer deleted (#21112, Oct 19). The Oct 30 split cut the first email by 23.6%, yet on today's inputs every arm, split or not, avoided all 6 of Fede's misses: the inputs had been the cause.

**2c. What later turns miss, with records**
1. Situs fe4f838f, Oct 30. The facts tied "6 weeks free, about $1,349" to the open 2-bedroom at $1,525; the first email put the offer on the $1,393 home. No check fired: the fact trace asks whether a fact has a source, not which home it belongs to. It passed two human approvals, the email and the next text (eschold_539542e7, in 27 s); that text copied the offer from the thread and AppFolio delivered it (message 1172147801).
2. WS 1010d08d turn 2: the prompt hands later turns a list of open units while the rules say name one home, never how many are open; the draft named two (dstop_de38778d).
3. Cold emails are first touches run as replies: 3 of 6 new Situs email threads this week, 7 stops, all held, none answered.

**2d. Later-turn rules.** 16 rules (23,177 characters) apply only once a thread exists (tour booked, reschedule, staff replied, goodbye); all 16 already render on the first email too.

**2e. Real later turns** (15 threads, 47 later turns: WS 39, Situs 8, all Sonnet; Situs ran supervised, so only 2 Clara-written later replies reached a renter there.)

| Later-turn rule or check | Helped | Hurt | Nothing or missed | Strongest ids |
|---|---|---|---|---|
| Goodbye: close without a reply | 5 | 0 | 0 | a74cc053 |
| Staff run the thread: stay quiet | 0 | 0 | 2 missed | 9cc7dc8f, bbc825d1 drafted anyway; a check held them |
| Forced calendar read, weekday guard, booking promise | 2 | 0 | 3 | ded19e70 caught a wrong weekday; bfaae842 blocked a true "lock in" |
| Unit count, dash retry, tour time this turn | 1 | 3 | 2 | d5953add: the dash retry sent "go ahead and head in" |
| Tour handler line "named more than one option" | 0 | 2 | 1 | f888234d: a bare "10am" falls to the unclear-ask branch (process-tour.ts:2091); the model called it odd, then re-asked |
| Promise backing | 2 | 0 | 3 (2 missed) | ef38ed96 sent "keeping an eye out" |

32 were right; none of the 12 bad ones traces to a rule difference between turns. Causes: checks and code-written lines 4, holds with no record 3 (one after a false check fire), a failed application lookup 1, the first email's wrong rent carried forward 1, the model 3. The quiet-lead writer (J9), the one truly separate follow-up prompt, got 4 of 4 wrong: three sent emails (3aad8363) claimed interest in a home Clara had added, two introducing Clara as "with" that home; the fourth (fb2adfc2) re-asked what the renter had answered. No check caught the problem.

**2f. Verdict**

| Option | What it means | For | Risk |
|---|---|---|---|
| **A. One writer per channel, turn as context (recommended)** | Keep the one prompt. The first-touch block renders whenever Clara has not written yet, cold email included. Every turn gets facts with ids, a calendar read, declared asks and one claims check. Then one model per channel | Already one prompt; no bad later turn traces to a rule difference (2e) | First email keeps about 23% more tokens. Later turns wait for inputs before Opus |
| B. Keep two: merge the split as the first email's own prompt | Two prompts, benched and swapped separately | 23% fewer first-email tokens | No gain on Fede's cards; two prompts to edit, bench and keep from drifting |
| C. Swap later turns to Opus as they are | One model line | Fastest | Marginal bench (26/8/19), no Spanish, no booking turns; later turns lack the facts Opus used well on turn 1 |

Recommend A. Keep the split's other-job and duplicate cuts (about 15K characters) as the first trim of the one prompt, proven on the replay after the inputs land. J2, J9 and J11 are the funnel's real separate prompts; under A each folds into its channel's writer.

## 3. Shared pieces, in Fede's six-step order

| Piece | Today | Missing | Step |
|---|---|---|---|
| One prompt builder | yes, every turn | nothing | done |
| Facts with ids (rent, special per home, open now) | first email only (guest-card-home-facts.ts); later turns get a unit list | every turn, cold email and quiet-lead texts too; ids in the text | 2 (running) |
| This turn's calendar read | first email only | any turn that talks times | 2 |
| Actions taken, with ids | completed-actions block every turn, no ids; nudges and the first-reply text reach the writer as Clara's own replies | ids; label automated texts | 2 |
| Declaration | declared-asks tool, first email only | every turn, plus which ids were used | 3 |
| One claims check | registry exists (claims/facts.ts, promises.ts); fact trace on the first email only | fact trace on every turn; special-to-home match; later-turn gates fold in | 4 |
| One model per channel | Opus first email; Sonnet replies and redraft; Haiku shortener and quiet-lead writer | one setting per channel writer | after 4, one PR per job |

PropFlow Docs