Repository navigation
fix(transport-matrix): typing is the room aggregate of in-flight turns - #108
Merged
Merged
Conversation
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
zooidbot
commented
Oct 5, 2026
zooidbot
left a comment
Collaborator
Author
There was a problem hiding this comment.
Architect review (ZOD091 cycle 1): matches the spec and plan. No blocking findings.
I read the diff against specs/045-ZOD091-typing-lifecycle/PLAN.md and the surrounding transport.ts in the branch.
Correct:
- Registry: it has the two sets from decision 2.
working.size > 0is the indicator, andliveguardsresume, so a wait that ends after its turn has ended can't re-raise the indicator or start an orphaned refresh interval. That's the worst reading of #36, and it's closed off. - Ordering: each slot has one promise chain, and presence has one per user (decision 5).
lowerclears the interval before it queues thefalse, so a refresh that's already in flight always lands before the lower. The "never sends the lower before an in-flight raise has settled" test proves this. - One release point:
runTurnBody'sfinally→typing.exit. Failure, interrupt and harness-limit each have a wiring test. - Resume in the
finally: the elicitation handler'sfinallyresumes, gated oncountForSession === 0(decision 3). "A card that could not be published still resumes typing" covers thefail()path, which the old'resolved'listener missed. - No turn-scoped calls left:
transport.tsnow callssetTyping/setPresenceonly for bootstrap presence (:1918), and the three ZOD078 per-turn sites are gone. The completion checklist item holds. - Session IDs line up:
req.sessionIdin the elicitation handler andsessionIdinrunTurnBodyare the same ACP session ID (sessions.setat:1386), sopauseandresumehit the same slot entry thatenteradded.
Non-blocking nits (fine to leave):
- Startup race: bootstrap
setPresence('online')at:1918bypasses the per-user presence chain. If a turn starts before that call settles, the lateonlinecan overwriteunavailableuntil the next edge. It only happens at startup and only affects presence. Worth a follow-up only if anyone sees it. - Unknown-session warning:
exitwarns for a session it doesn't know. Nothing in production should hit that, so if it shows up in daemon logs, treat it as a signal and don't silence it.
Still open before #36 can be called fixed:
- The lease test hasn't run anywhere. CI is green, but it doesn't include the lease test. Ori: please run the smoke step in the body and paste the measured clear time here. If it fails with "Tuwunel never expired the typing lease", that's a second cause of #36 and it gets its own issue.
- Manual smoke (plan step 4.5), after a local prerelease: one agent in two threads at once, then an
AskUserQuestionround trip. - CI job: once zooidbot has the
workflowscope, add thetyping-leasejob from the<details>block so the lease test runs on every PR.
Keep Refs, not Closes, until (1) and (2) are done.
9 tasks
Run against Tuwunel, the original test always failed: Tuwunel expires the typing lease (a fresh sync shows it cleared) but never pushes the expiry to an incremental /sync, so an open client keeps the stale indicator. Split into a test of the expiry and a test pinning the upstream bug, so the suite is green today and flags the day Tuwunel fixes it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
5 tasks
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.
Refs #36
Typing and presence in
@zooid/transport-matrixare now the room aggregate of an agent's in-flight turns (ZOD091). One turn ending no longer clears another's indicator, a turn waiting on a human shows as not typing, and no refresh can outlive its turn. The Matrix typing lease is the backstop if the daemon dies mid-turn.Client half (test-only): zooid-ai/clients#53
What changed
typing-registry.ts(new): per-room registry of in-flight turns; typing is on while any turn is active and not waiting on a human.transport.ts: routes typing through the registry instead of per-turn set/clear..changeset/typing-lifecycle.md: patch for@zooid/transport-matrix.typing-registry.test.ts,transport.typing.test.ts, andpackages/cli/tests/typing-lease.integration.test.ts(real Tuwunel lease expiry).Ori smoke step (lease test, needs Docker)
It should pass, and it prints the clear time (
[typing-lease] measured ...), which should be ≤45s. A failure saying "Tuwunel never expired the typing lease" is a #36 finding, not a flake.This isn't in CI: zooidbot's token lacks the
workflowscope, so the job couldn't be pushed. The job I wrote is below, ready to paste intoci.ymlonce the scope exists.typing-leasejob for.github/workflows/ci.ymlThe lease test's
CIguard (fail, don't skip, when Docker is missing) stays in the file; it is inert until that job exists.Tests
pnpm -C packages/transport-matrix exec vitest run— 35 files passed, 3 skipped (Docker-gated); 435 tests passed, 4 skipped.pnpm -C packages/transport-matrix exec tsc --noEmit— clean.Not verified
typing-lease.integration.test.ts) needs Docker and Tuwunel, which the sandbox can't reach. It has never run green; the smoke step above is its first run.context-mcpandpi-extensionsocket integration tests fail here withEPERMon socket binds (sandbox). Not touched by this change; reported rather than written off as pre-existing.Knowledge impact
ZOD091.
Plan feedback
.github/workflows/*. Its token has noworkflowscope, so the push was rejected and I had to drop the CI job and move it into this PR body. One scope check up front would have saved a round trip.d7b4453zooid,9cfce66clients) were right: feat(acp): ACP elicitation loop (ZOD078) #101 and fix(transport-matrix): task-thread handoff survives its sync echo beating the send #102 had already merged before the release.🤖 Generated with Claude Code