Skip to content

refactor(web): one predicate decides what anchors into a root's cluster#564

Merged
gbasin merged 1 commit into
masterfrom
refactor/anchor-cluster-predicate
Jul 17, 2026
Merged

refactor(web): one predicate decides what anchors into a root's cluster#564
gbasin merged 1 commit into
masterfrom
refactor/anchor-cluster-predicate

Conversation

@gbasin

@gbasin gbasin commented Jul 17, 2026

Copy link
Copy Markdown
Collaborator

Small invariant cleanup in the same area as #562. No reachable behavior change.

The gap

Two conditions in Timeline.tsx described the same set — agent-voice broadcast events that anchor into their loaded root's cluster — but only one excluded question requests:

// builds answersByRoot (the anchoring map)
isAgentVoiceBroadcast(m) && m.sessionEventType !== 'question_requested' && rootIds.has(m.threadRootEventId)

// removes the message from visibleMessages
isAgentVoiceBroadcast(m) && rootIds.has(m.threadRootEventId)   // ← no guard

A broadcast session.question_requested with a loaded root would be dropped from the feed by the second and skipped by the first — rendering nowhere while still counting toward unread. That's precisely the shape of #562: counted, but impossible to see.

It's unreachable today only because the server emits question requests without broadcast: true. Nothing enforced that; it was an accident waiting to happen.

The fix

Both call sites now derive from one anchorsIntoRootCluster predicate, so they cannot disagree: a message leaves the feed only if the cluster actually takes it. A broadcast question request stays a row of its own instead of vanishing. The type guard also lets the non-null assertion go.

Verification

The new test fails without the fix — Unable to find an element with the text: Should this include the migration?, i.e. the event rendering nowhere.

Local: pnpm lint · typecheck (7/7) · web 776 · e2e 119/119.

🤖 Generated with Claude Code

Two conditions described the same set — agent-voice broadcast events that
anchor into their loaded root's cluster — and only one of them excluded
question requests. A message dropped from the feed by the looser condition but
skipped by the stricter one would render nowhere at all while still counting
toward unread: the same shape as the deleted-tail bug in #562, where something
counted but could never be seen.

Nothing reaches it today, because question requests are not emitted as
broadcasts. Nothing enforced that either. Both call sites now derive from one
predicate, so the two cannot disagree: a message leaves the feed only if the
cluster actually takes it, and a broadcast question request stays a row of its
own rather than vanishing.

No reachable behavior changes.
@gbasin
gbasin added this pull request to the merge queue Jul 17, 2026
Merged via the queue into master with commit c0f028d Jul 17, 2026
16 checks passed
@gbasin
gbasin deleted the refactor/anchor-cluster-predicate branch July 17, 2026 03:24
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant