How a tenant repair text should find the right open work order when the reply writer runs on Opus 5.5, and what to do about the filing thresholds. Design only: no code has changed.
Nov 1, 2026 · row open-order-matching · sources: tenant comms hand-off, the four cases. Ids and counts only.
| Fact | Number | Source |
|---|---|---|
| Work orders with no status | 2,276 of 4,114 | hand-off, Data gaps row |
| Stale open orders per tenant at the larger customer | 8 to 43 | hand-off, Filing not at parity row |
| G3 filing, 20 full-mode texts: add to open / new / ask first / reply only | decomposed on Opus 5 / 3 / 4 / 8 · production 8 / 5 / 0 / 7 | hand-off, G3 filing row |
| Filing after prompt rules 3c to 3e and code check 3f | fell from 25 to between 19 and 22 of 42 | hand-off, Match before filing row |
| Duplicates on Opus vs today, G3 261 episodes | 11% vs 5% | hand-off, G3 row |
| Bench work orders shown with today's status, not the status that day | 64 of 170 | hand-off, slice H caveats |
| Case | Order Clara used | Order the office used | What went wrong |
|---|---|---|---|
| 1 · stove after roaches | new order, plus a note on LAMP-18152 | new order LAMP-18184 | Nothing. The labeler counted it as a duplicate; the office made the same call Clara did. |
| 2 · washer and dryer | LOWR-17614 (air conditioner) | none filed | Wrong attach. An older dryer order, LOWR-17113, existed. The tracker lists its status as unknown, which fits the no-status rows, and it was not in the list the bench showed Clara. |
| 3 · kitchen extractor plus pests | pests on WOOD-17721 (right); extractor on WOOD-17489 (bathroom faucet, wrong) | pests scheduled; no hood order | Wrong attach. An older hood order, WOOD-15393, existed. The tracker lists its status as unknown, and it was not in the bench's list. |
| 4 · indoor AC leak | LAMP-17337 (outdoor spigot) | new order LAMP-17787 | Wrong attach. The only open order was a water leak of a different kind. |
Production builds the list in the dispatcher, in both the text lane and the email lane, from getWorkOrdersByPersonId filtered by !WO_CLOSED_STATUSES.includes(status). A row with no status is not closed, so it counts as open. That is where 8 to 43 stale orders per tenant come from: each one is offered as a place to attach.
The bench door (src/lib/domain/clara-bench/door/load.ts, openAt) counts an order as open only if its status is active, or if it was closed after the text. A row with no status is dropped unless something touched it after the text. That is why the dryer order in Case 2 and the hood order in Case 3 were missing from "the list Clara saw".
So the two symptoms come from one set of rows. On the bench those rows are invisible, which produced the wrong attaches in Cases 2 and 3. In production they are always visible, which produces the stale list. Neither behaviour is what we want, and each makes the other's measurements unreliable: a bench filing number is a number about a list that production never shows.
resolveIntakeDecision (in intake-classify.ts) accepts any existing pick whose id is in the list. With one open order it places the report on that order at any confidence, and with two or more it does so from 0.6 up (and below 0.6 too, under the under-split bias). Nothing checks that the report and the order are about the same thing. The subject check from #22383, reportMatchesWorkOrder, guards only the note tool. It runs after the placement is decided and reads the note text.
Even where it runs, it passes Case 4. "Water" and "leak" count as a shared plumbing subject, so an indoor AC leak matches an outdoor spigot order. The spigot is not in its vocabulary at all.
The ask and new-when-open thresholds (0.6 and 0.8) and the bias toward fewer orders were locked by the owner on 2026-06-10 for a Sonnet classifier. The classifier still runs on AGENT_MODEL: the code default is claude-sonnet-4-6, and the live value is set by environment. On the 20 texts, the decomposed version on Opus asked 4 times where production asked 0. Fede counts noise as the main failure, so an extra ask is a loss even when the order it leads to is right.
WO_CLOSED_STATUSES in src/lib/data/statuses/work-orders.ts. The two dispatcher filters (text lane and email lane in inbound-dispatcher.ts) call it. load.ts openAt calls it with the text's own time, so the bench cuts history the same way.openAt may count as 001's bench core. The driver settles that on the bridge before the PR. The day0b replay grids hold decisions, not filing, so we expect 0 differing cells. If any cell moves, it needs a known-bugs ledger entry and a re-freeze by 001.existing placement on an order whose subject plainly does not match the report becomes new. It never becomes ask, because of two of Fede's rulings: a different problem gets its own order, and noise is the main failure. The check reads each issue separately, never the whole message, so in Case 3 the pest half still goes on the pest order and only the extractor half is split off.reportMatchesWorkOrder. Writing a second copy inside the resolver is not allowed.title for new issues. Part 2 asks it for a short subject on every issue, existing included. That is a change to the classifier prompt, so it passes the prompt gate: a bench row with production in the same hour, and the Spanish slice.report-matches-work-order.ts): bare "water" or "leak" is a weak subject. It counts as a match only when neither side names a specific fixture. Add spigot, hose bib and exterior faucet to the plumbing subjects.intake-classify.ts, which the #22381 lane is editing now. Part 2 starts from main after that PR lands. The vocabulary fix touches only report-matches-work-order.ts and can ship first.| Option | What it means | Verdict |
|---|---|---|
| D1 · classifier stays on Sonnet, thresholds unchanged | Only the writer moves to Opus. The classifier and its 0.6 / 0.8 thresholds stay where they were tuned. | recommended now This matches the hand-off's G3 conclusion. It needs no new owner ruling. |
| D2 · re-tune the thresholds for an Opus classifier | Sweep 0.6 / 0.8 on the 20 full-mode texts and the 261 G3 episodes, after A and B. Pick the setting that makes fewest asks without adding duplicates. | later, once A and B are proven It changes an owner-locked value, so it is Fede's call, presented with the sweep's numbers. |
| D3 · lower the thresholds now so Opus files more | Shrinks the gap with more placements on a list that is still stale. | no It would add wrong attaches (cause a) to close a gap that is mostly asks. |
| Part | Proof | Pass bar |
|---|---|---|
| A | A pure test of the predicate over every status case, with a test that fails on the old filter (a no-status order from long ago is offered). A read-only census: per tenant, open counts before and after, as a distribution (not a mean), over every company with mirrored orders. The same census counts how many no-status rows have a later tenant message tied to them. That number shows which way the window errs: an order that is really open in the PMS but outside the window would drop out, and the tenant's next "still broken" would file a duplicate. Re-run the G3 filing row through the door, production as arm 1 in the same hour. | No active order drops out of the list. Stale counts fall. Few no-status rows outside the window have a recent tied message, and every one that does is listed. A filing row exists for both arms. The day0b compare shows 0 differing cells, or a ledger entry for each one. |
| B | Cases 2, 3 and 4 as synthetic fixtures (fixture ids only, same structure, no real text), each failing on main. A 30-day read-only replay of every production existing placement through the new check, with every flip listed and labelled: right split, or a false split we then fix. Maintenance evals, plus a multi-turn case that replays one case's full conversation. A bench row with production in the same hour and the Spanish slice. | Cases 2 to 4 file a new order. Case 1 is unchanged. No real flip is left unexplained. Asks do not rise. |
| Live | One Willows run (org_sandbox, appfolio-45, existing test tenant, robot number, no new tenants): a different-problem text while an unrelated order is open. | A new order is created in the PMS, the old order gets no note, and the record ids are cited in the PR. |
The day0b replay grids hold decisions, so a clean compare there does not prove a filing change. The filing row and the placement replay above are the proof for this work.
openAt, plus the census. Raise it on the bridge first if the door counts as 001's.report-matches-work-order.ts. Small; can ship at once.Four questions, one per case, each with options and a recommendation. The driver raises them. None of the slices above waits on the answers, except option C.