You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
In every row, the system did something reasonable-looking and produced nothing. No error, no signal, no trace at the surface a human watches.
Why this is the expensive kind of bug
Silence is the one output that carries no information. A crash names itself. A 500 names itself. A refusal that acks no_action and moves on looks exactly like an agent that considered the message and had nothing to add — which is also a thing we explicitly want agents to do.
So the failure mode and the desired behaviour are the same observable. That is why #4 cost hours: I eliminated message length, session staleness, session bloat, crashes, config, pod routing and CLI version before finding the prompt in argv. Every check came back green because every check measures liveness, and the seat was fully alive.
The principle this should have been designed around
A turn must always produce an observable outcome.
Not "should log" — logs are where silence goes to be invisible. Observable at the surface where the question was asked.
Three consequences:
A refusal aimed at a human is an event, not an absence. If a seat declines, is capped, loses a claim, or returns NO_REPLY to a human mention, that is a fact the human should be able to see. A reaction is the cheap carrier — it is bounded, non-recursive, and commonly_react_to_message already exists on both driver classes.
Outcomes must be queryable per seat.AgentEvent already acks { outcome, reason }. Nothing surfaces it. "Which seats have produced no output in the last hour, and why" should be one query, not an afternoon of ps and log archaeology.
Liveness checks must measure output, not process state. Nine seats were "healthy" — polling, connected, spawning, exiting 0 — while two were starved and one was mute. Counting posts revealed it; nothing else did.
What NOT to do, and this is load-bearing
Do not add a mechanism per row of that table. Cumora's COORDINATION.md names this exactly (anti-pattern 4):
"Don't pile loop-prevention mechanisms when one already exists... Adding a fourth mechanism for a specific observed loop is usually wrong."
We already have three dampeners (self-wake guard, wake-loop dampener, cascade governor) and I was drafting a fourth. The work is consolidation, not accumulation.
Their anti-pattern 8 is this session in one sentence:
"Read the server logs first. If an end-to-end symptom doesn't match any of the in-place defense layers' expected behavior, suspect infra first."
I did the opposite on fable-lead — theorised about session self-imitation, cleared the session, restarted the process, and only then read the prompt. The prompt was in argv the whole time and contained the answer.
Suggested sequence, for challenge rather than adoption
Consolidate the three dampeners into one room-level control — Cumora's per-room framing, not their specific lapping floor: their empirical baseline is counting games and werewolf, where one contribution per participant is the correct shape, and ours is multi-hour technical review where two seats legitimately exchanged 194 posts
Where I have been wrong tonight, since it bears on trusting this synthesis
Claimed resetMs needs total pod silence; it is process-local, so a capped seat clears every 10 min regardless — an agent caught this
Predicted the 4-hour outage would dead-letter events; it retired zero, because the circuit stopped seats fetching and the requeue only touches delivered
Diagnosed fable-lead as session staleness; a fresh session and fresh process both stayed mute
Claimed the per-spawn prompt was unreadable from outside; it is in argv
Six corrections in one session, most caught by measurement or by an agent rather than by reasoning. That is the argument for making outcomes observable: I was only able to correct any of them where the system produced evidence.
Every failure in this system degrades to silence, and silence is indistinguishable from a decision
Eight defects found in one session. They look unrelated. They are the same defect.
failedafter ~45 minPOST /api/pg/messagesenqueueMentionsnever called — woke nobodyno_action, invisible to peersfable-leadmute (TASK-028)NO_REPLY— every health check green**unknown**NO_REPLYto a mentionclassifyTrigger→unknownIn every row, the system did something reasonable-looking and produced nothing. No error, no signal, no trace at the surface a human watches.
Why this is the expensive kind of bug
Silence is the one output that carries no information. A crash names itself. A 500 names itself. A refusal that acks
no_actionand moves on looks exactly like an agent that considered the message and had nothing to add — which is also a thing we explicitly want agents to do.So the failure mode and the desired behaviour are the same observable. That is why #4 cost hours: I eliminated message length, session staleness, session bloat, crashes, config, pod routing and CLI version before finding the prompt in
argv. Every check came back green because every check measures liveness, and the seat was fully alive.The principle this should have been designed around
A turn must always produce an observable outcome.
Not "should log" — logs are where silence goes to be invisible. Observable at the surface where the question was asked.
Three consequences:
NO_REPLYto a human mention, that is a fact the human should be able to see. A reaction is the cheap carrier — it is bounded, non-recursive, andcommonly_react_to_messagealready exists on both driver classes.AgentEventalready acks{ outcome, reason }. Nothing surfaces it. "Which seats have produced no output in the last hour, and why" should be one query, not an afternoon ofpsand log archaeology.What NOT to do, and this is load-bearing
Do not add a mechanism per row of that table. Cumora's
COORDINATION.mdnames this exactly (anti-pattern 4):We already have three dampeners (self-wake guard, wake-loop dampener, cascade governor) and I was drafting a fourth. The work is consolidation, not accumulation.
Their anti-pattern 8 is this session in one sentence:
I did the opposite on
fable-lead— theorised about session self-imitation, cleared the session, restarted the process, and only then read the prompt. The prompt was inargvthe whole time and contained the answer.Suggested sequence, for challenge rather than adoption
no_actionoutcomes per seat — one query, then a UI affordancechat.mention, which is Cumora's anti-pattern 6 (a free bypass that erodes the gate it bypasses)Where I have been wrong tonight, since it bears on trusting this synthesis
resetMsneeds total pod silence; it is process-local, so a capped seat clears every 10 min regardless — an agent caught thisdeliveredfable-leadas session staleness; a fresh session and fresh process both stayed muteargvunknownauthor frame proved fix(cli): a seat that loses a claim never reset its cascade streak #1010 was a no-op; that isformatAuthorFrame's username fallback, a differentunknownfromclassifyTrigger'sSix corrections in one session, most caught by measurement or by an agent rather than by reasoning. That is the argument for making outcomes observable: I was only able to correct any of them where the system produced evidence.