feat(intercom): mail rides the same queue as the operator's own typing - #17
Closed
lucy-wolfe wants to merge 12 commits into
Closed
feat(intercom): mail rides the same queue as the operator's own typing#17lucy-wolfe wants to merge 12 commits into
lucy-wolfe wants to merge 12 commits into
Conversation
The word is a claim about whose fault the failure was, and the two invite opposite recoveries: refused invites a corrected call, failed invites a retry. Calling a crash a refusal is the worse direction, because it sends somebody to fix a call that was never wrong. The verb follows the classification rather than a list, so a refusal added next month gets the right word without anyone remembering. One predicate in one place: three renderers build a failure title, and two of them are bespoke titles that would otherwise have kept saying failed for a refusal -- the both-arms property again, found by sweeping for the word rather than trusting the default path to be the only one. One case was not what the classification said. A partial hire carries a status so the card can name the people already hired, which a retry needs so it does not double-hire them -- but the error it wraps may be a genuine crash. A status carried for CONTEXT is not a claim about fault. That path now asks the wrapped error's own type, and a producer in the same position marks itself rather than being enumerated in the renderer, because a list is where the next case is missed. Pinned by a discriminating pair: a classified refusal is refused, an unclassified failure is not, and a context-carried status with fault:true is not. Verified by mutation -- making the predicate return true fails both negative cases. Checked the collapsed card: the verb is one character longer and the title is not what gets truncated, so no card's summary window moves. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…ed a default The field was REQUIRED under a description opening 'DEFAULT: the department YOU head'. An agent read that, reasoned correctly that it should omit the field, met a schema that would not allow it, and improvised the most salient name in context -- the company's. It obeyed the instrument over the claim, which is the right thing for it to do. The field is optional now and the default is resolved in execute using the helper that already existed: the department the caller heads, or failing that the one they sit in. That is word-for-word what the description promised, so the promise was always implementable and simply was not implemented. The worked example now shows the omitted form first. An example that keeps passing the field re-teaches the habit the description is trying to correct. The sweep asked the general question of every parameter in the file -- does the schema permit what the prose promises -- across DEFAULT, omit, omitted, optional and leave empty. Exactly one leaf field disagreed: this one. The only other hit says 'never omit this field' and is required, so its prose and schema agree. No mechanical guard was added: an instrument for a class of one is furniture. My first sweep reported sixteen mismatches. All but one were container objects matching on a nested field's prose -- the detector measured a property adjacent to the question. Refining it to leaf fields gave the real answer. Also caught by an existing guard: the longer tool description exceeded the 1024 characters a strict provider accepts. Trimmed to 993 rather than expanded. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…ng past a lecture What it is in two sentences, the animation, install, and the first company now lead the page. Depth moved into short skimmable sections or linked docs: the crate table went to docs/ARCHITECTURE.md, which already carries it, and the long GIF caption and quick-start asides were trimmed. New: an Everyday commands table, derived from the routed operator verbs in chief-cli's OPERATOR_VERBS, and a Contributing section naming the two open workstreams (finishing apps/web, and multi-machine hosting so one busy company stops pegging a single box's CPU) plus the issue tracker and CONTRIBUTING.md. Every command documented was checked against install.sh and the routed verb table. The Pi floor line keeps Pi and 0.80.10 on one line for pi-floor-single-definition.test.mjs. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TMNbixeJo8rpeijUKyxhD2 Signed-off-by: Lucy Wolfe <lucy@zbox.sh>
The verb moved to the fault marker and the tag did not. The tag still measured only the ABSENCE of a status, so a partial batch carrying one for context while wrapping a real crash said "failed" -- correctly -- and then dropped the crash marker. Somebody debugging that would see a list of people already hired, no fault marker, and reasonably conclude they had passed bad input. One classification, two surfaces. The tag now reads the same marker, and a test asserts the two are complementary rather than merely each correct: nothing may be both a refusal and a system fault, which fails if either rule moves without the other. Verified by mutation -- putting the tag back on the old instrument fails the crash case and only that case. This was the scope note I flagged rather than fixed in the first pass. Review ruled it fix-here, and that was right: shipping the verb on the new instrument and the tag on the old one is a divergence nobody would find again except by hitting it. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The installer already edits the shell profile and reports exactly which file it touched, so the extra line was a second copy of work the script does itself. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TMNbixeJo8rpeijUKyxhD2 Signed-off-by: Lucy Wolfe <lucy@zbox.sh>
The animation speaks for itself; the recording provenance note is not needed on the front page. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TMNbixeJo8rpeijUKyxhD2 Signed-off-by: Lucy Wolfe <lucy@zbox.sh>
Three steps a stranger can paste in order: Pi, chief, first company. The Pi floor stays on one line with the name for the pi-floor guard. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TMNbixeJo8rpeijUKyxhD2 Signed-off-by: Lucy Wolfe <lucy@zbox.sh>
Step 3 says what the first run is (Founder, two questions, then the CEO boots) and step 4 says what every later run is (the same bare chief starts and attaches the company). The transition is the part a stranger cannot guess from the command alone. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TMNbixeJo8rpeijUKyxhD2 Signed-off-by: Lucy Wolfe <lucy@zbox.sh>
…s Pi (#1) The Pi step collapses into a single sentence: the installer installs a missing Pi and asks before upgrading an old one. The version number leaves the README entirely; the floor's single definition stays in pi_floor.rs, and CONTRIBUTING.md remains the document that quotes it. Depends on the installer change (PR tribes-protocol#18) riding in the same integration branch; without it this page describes behavior install.sh does not have. Claude-Session: https://claude.ai/code/session_01TMNbixeJo8rpeijUKyxhD2 Signed-off-by: Lucy Wolfe <lucy@zbox.sh> Co-authored-by: Lucy Wolfe <lucy@zbox.sh> Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
lucy-wolfe
force-pushed
the
feat/mail-rides-steer
branch
2 times, most recently
from
August 28, 2026 17:08
351cb02 to
8ad8ba6
Compare
This was referenced Aug 28, 2026
lucy-wolfe
force-pushed
the
feat/mail-rides-steer
branch
from
August 28, 2026 17:16
8ad8ba6 to
94e2bb0
Compare
A busy person now reads an ordinary message at the next step boundary inside the running turn instead of at the end of it. The operator typing mid-turn has always been submitted as a steering message and consumed within seconds; ordinary mail rode the follow-up queue, which Pi consumes only once the agent has no more tool calls or steering messages. So somebody an hour into a piece of work did not see a teammate's message until the hour was over, while the identical words typed by the operator arrived immediately. Interrupt mail already rode the steering lane, so this widens a production-proven path rather than building one. The digest is untouched: batching is still the answer to twenty messages in one turn, and only the moment of consumption moved. Verified before changing anything, because it would have been a real blocker: the delivery receipt hangs off message_start, not turn_start, so it is written wherever the message is consumed. Interrupts have been consumed mid-turn in production all along and receipted through that same handler, so a normal envelope takes an identical path. Three call sites were considered and two moved. The work-resume prompt keeps follow-up and says why: nobody is waiting on it and it asks the person to pick their own work back up. The input-requeue rescue and the printed-tool-call corrective keep theirs, with rationales already written down that remain true. An unreachable ternary went with it: normal urgency is routed away three lines above the interrupt delivery, so its false arm could never be taken even before this change. The change was unpinnable as written, so it was made pinnable. The delivery table was already covered, but the mode passed into it was two string literals at two call sites -- so the timing of every delivery in the product could change without one test noticing, which is exactly what happened when the first implementation went green. It is one named decision now, with a test that asserts the rule and fails when the mode is reverted. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
lucy-wolfe
force-pushed
the
feat/mail-rides-steer
branch
from
August 28, 2026 17:32
94e2bb0 to
dfd6c62
Compare
Contributor
Author
|
Merged into the v0.5.7 integration branch and shipping in #16. The commit is on that branch verbatim; GitHub could not retarget this pull request because a cross-fork PR's base must live in the base repository, and the integration branch lives on the fork. The review that happened here stands. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
A busy person now reads an ordinary message at the next step boundary inside the running turn, instead of at the end of it.
The gap this closes
The operator typing mid-turn is submitted with
streamingBehavior: "steer"and consumed within seconds. Ordinary organization mail rode the follow-up queue, which Pi consumes only once the agent has no more tool calls or steering messages — the end of the turn.So somebody an hour into a piece of work did not see a teammate's message until the hour was over, while the identical words typed by the operator arrived immediately. Deliveries were already triggered mid-turn; only the consumption point deferred.
Interrupt mail already rode the steering lane. This widens a production-proven path rather than building one.
What does not change
person_activity.operator_wake_at, which this change neither reads nor writes. Nothing in the converge, activity or settle paths is involved.The blocker that was checked before anything was changed
The delivery receipt (
deliveriesConsumedThisTurn) is what tells a sender their message was actually eaten, and if it only fired at turn end then consuming mid-turn would lose it.It hangs off
message_start, notturn_start— so it is written wherever the message is consumed. Interrupts have been consumed mid-turn in production all along and receipted through that same handler. A normal envelope now takes an identical path.Had that not held, this would have stopped here.
Three call sites considered, two moved
The input-requeue rescue and the printed-tool-call corrective also keep follow-up. Both already carry written rationales, and both remain true — a submitter who did not know a turn was running, and a correction to a turn that has just ended.
An unreachable ternary went with it. Normal urgency is routed away three lines above the interrupt delivery, so
isInterruptDelivery ? "steer" : "followUp"could never take its false arm, even before this change.The change was unpinnable as written, so it was made pinnable
This is the part worth reviewing most carefully.
The delivery table was already covered by a test. But which mode the mailbox passed into that table was two string literals at two call sites — so the timing of every delivery in the product could change with every test still green. That is exactly what happened: the first implementation went green immediately, which is what prompted looking for what was missing rather than trusting it.
The mode is one named decision now, and the new test asserts the rule rather than the table. Verified by mutation: reverting the mode to follow-up fails it, where the pre-existing suite passed.
Harness note
The changed surface is the pure mode table, which is unit-pinned. Pi's steering semantics are upstream and proven by two paths already in production — the operator's own typing, and our interrupt mail. Mentioned because an earlier decision entry flagged the missing end-to-end harness and a reader will reasonably ask.
Checks
bun run typecheck,test,lint,lint:reactive,knip, all 98 guards, the tool-contract lanes by path (4 files, 31 tests run), and CI.