One tour-move decider or two?
Decision page · DECIDED (Fede, 2026-08-11): keep the current solution — the refactor does not ship · Follow-up to the duplicate-reschedule RCA
The refactor was fully built anyway (five review rounds to a clean approval, evals passing, provably inert when off) and is parked on its branch as a ready fallback — its PR is closed, the branch stays. On first real evaluation the refactor also scored better than unmodified main on the shared pipeline check (2/10 vs 0/10), so it was not rejected on quality: it was judged not worth the risk/effort while the shipped fix holds. Tripwire stands: one more cross-decider interference incident reopens this decision, starting from the parked branch. Learnings, gaps, and the long-term vision are merged to the repo as docs/planning/tour-write-path-learnings-2026-08.md.
Correct on both counts. Today a tour move can be decided by two different brains: the deterministic message parser (added July, because trusting Clara alone dropped 3 of 5 real reschedules) and Clara's own tool call (needed for ambiguity, negotiation, and voice). They share one write function, and since PR #5644 they share evidence — but two independent deciders is why the duplicate-notification bug was possible at all, and any future third path could recreate the class.
Options
- What we have after the fix: the parser's moves are recorded where Clara can see them; redundant re-moves are no-ops; the nightly gauntlet enforces exactly-once.
- Pro: zero further work; proven live end-to-end today.
- Con: the bug class is fenced, not extinct — correctness rests on both deciders staying polite forever.
- The parser stops writing. When it can parse a concrete, available move, it hands Clara a pre-approved "execute exactly this" instruction; a post-turn enforcer applies the move deterministically only if her turn ends without the call.
- At most one decider ever acts per turn by construction — the July reliability problem stays solved (the enforcer is the safety net), and the duplicate class becomes impossible rather than guarded against.
- Pro: one mental model, one transcript story, no cross-decider etiquette to maintain.
- Con: real engineering (a turn-boundary enforcer with its own tests); adds up to one turn of latency in the rare enforcer-fires case. Not urgent — the live bleeding stopped today.
- Delete the agent's ability to move tours entirely.
- Con: "any chance we could come earlier?", offer-acceptance, and phone calls genuinely need judgment; the parser would grow into a worse agent. Not viable.
Pick one
A. Stay on Option 1 — the fix is enough, revisit only if the class recurs.
B. (Recommended) Option 2 as a scheduled follow-up — file it as a card, build it when tour work is next touched.
C. Option 2 now — prioritize this week.
The history investigation (2026-08-10, full git archaeology)
The track record is real, and it is not decaying. Twenty tour incidents are traceable in five months. Seven came from the agent not acting when it should (the July cluster that birthed the automatic path); seven came from the two paths interfering with each other — duplicate tours, duplicate confirmations, duplicate PM notifications, a confirmed tour silently demoted. The interference incidents cluster March (4), July (2), August (1): the July/August ones happened after the March fixes, in a system carrying far more coordination code. One known interference bug is still quarantined out of the nightly gate today.
The etiquette tax: roughly 1,100 lines across 15 files exist solely to keep the two deciders from colliding — tool-stripping, prompt rules, the new transcript record, idempotency guards, refuse-guards, counting checks. Three different mechanisms encode the same fact ("this was already done") with three different lifetimes, which is exactly how this incident happened.
Surprise finding: there are arguably three deciders, not two — an older phone-keyed confirm/cancel state machine (flagged in ADR-0090) can still commit with live side effects before the hardened pipeline runs on the same turn.
Why not refactor now: two evidence-based reasons. Today's fix has zero days of bake — and it is the first time the automatic path's actions are durable, which is the exact substrate the refactor needs; the cheap experiment is to watch it. And "parser proposes, agent executes" is only safe if the backstop can execute the move itself when the agent drops it — today every guard in the tree can block or hold a reply, but nothing can act. Handing the commit back to the agent without an executing enforcer re-opens the July failure the automatic path was built to stop (measured then at 3 of 5 real reschedules dropped).
Determination
Next quarter, sequenced — with a tripwire that promotes it to now.
- 1. Bake (30 days): let today's fix run with the exactly-once nightly scenario as the standing detector; un-quarantine the one still-excluded interference scenario so the gate has full coverage.
- 2. Build the executing enforcer on the existing review-gate + schedule-chokepoint plumbing (~60% of it already exists). Valuable on its own regardless of the refactor — it is also the missing backstop for the July failure class.
- 3. Flip the parser from decider to proposer behind a per-property flag, exactly like the two prior single-writer collapses that already shipped safely.
- Tripwire: one more interference incident — any duplicate tour, duplicate PM notification, or state demotion attributable to both paths acting — promotes this to now.
Follow-ups noted while closing the incident
- Willows test property has no leasing calendar / PM email since mid-July — full-chain nightly assertions are muted (Trello: "Reconnect The Willows test property's leasing calendar").
- Sentry: "PM tour confirmation NOT delivered" fired ~196×/day as of tonight — the deliberate loud alarm for confirmation emails that fail to land; pre-existing, needs its own look.