Keep a handoff grant revocable after somebody hides the coworker it points at - #352
Merged
davidmckayv merged 2 commits intoSep 4, 2026
Merged
Conversation
…oints at The Handoff section joins two lists that are not filtered the same way. The grants come from botsReachableFrom, a raw read of this coworker's `bot` grants with no visibility filter of any kind. The roster comes from GET /api/agents, which drops every coworker the signed-in person has hidden - and hidden is a per-person display preference, one row per user in agent_preferences, not a fact about the coworker. So an administrator who tidied a coworker off their own roster stopped being shown the grants pointing at it. No switch was drawn and no note said why, the "N of M" above the list quietly dropped by one, and nothing on any other screen manages these grants, so the grant could no longer be taken away at all. It was still in force. A hop is decided by mayAddress, which calls the same unfiltered botsReachableFrom (server/src/index.ts:346-353), so the coworker went on being asked while the only surface that could stop it had stopped listing it. A boundary you cannot see is one you cannot withdraw, and the comment right above this code already promised the opposite: "a stale grant may still be revoked - taking away is always allowed". The selection moves to lib/agents/handoff-roster.ts so the list and the count cannot disagree again. A coworker on your roster is offered as before. One you have hidden is offered only when a grant already points at it, marked on the row as hidden from your roster: hiding is a preference about clutter and this screen has no business undoing it for a coworker with nothing to withdraw. The count is over the rows actually drawn, which is the question somebody reading it is asking. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
kevin9327
requested review from
MikeRyanDev,
davidmckayv,
guidovizoso and
tylerslaton
as code owners
September 3, 2026 22:03
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
# Conflicts: # CHANGELOG.md
davidmckayv
approved these changes
Sep 4, 2026
davidmckayv
left a comment
Contributor
There was a problem hiding this comment.
Reviewed diff against current main; resolved CHANGELOG keep-both; validated locally (format + composed test run). CI green.
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.
What this changes
The Handoff section joins two lists that are not filtered the same way, and the join silently
dropped live grants off the only screen that manages them.
reachableisbotsReachableFrom(server/src/plugins/store.ts:2360) — a raw read of thiscoworker's
botgrants. No visibility filter of any kind.GET /api/agents→store.list(actor, false)(
server/src/agents/profile-store.ts:282-292), which drops every coworker the signed-in personhas hidden. Hidden is a per-person display preference: one row per
(user, agent)inagent_preferences(server/src/db/schema/coworker.ts:67-79), not a fact about the coworker.So an administrator who tidied a coworker off their own roster stopped being shown the grants
pointing at it.
othersno longer contained it, so noItemand noSwitchwere drawn, no notesaid why, and
{granted} of {others.length}quietly dropped by one. Nothing on any other screenmanages these grants, so the grant could no longer be taken away at all.
And it was still in force. A hop is decided by
mayAddress, which calls the same unfilteredbotsReachableFrom(server/src/index.ts:346-353), read per hop "so revoking a grant applies to thenext hop". Nobody's roster preference is consulted. The coworker went on being asked while the only
surface that could stop it had stopped listing it.
The panel's own comment, added with the dialogs in #317, already promised the opposite:
The line above it — "Hidden Bots are already absent from this list" — was the assumption that made
that promise false.
The fix. The selection moves into
app/src/lib/agents/handoff-roster.ts, a pure function, so thelist and the count are decided once and cannot disagree again:
· hidden from your rosterso it is not an unexplained stranger in the list. Hiding is apreference about clutter and this screen has no business undoing it for a coworker with nothing to
withdraw;
With no hidden grantee — the ordinary case — the rendered list and the count are byte-identical to
before.
Where it runs
return.
GET /api/agents?hidden=trueis the samealready-existing read the roster's own Hidden view uses, and it is scoped to the signed-in
person by
agent_preferences, which is in Postgres.setHandoffGrantMutationOptions→DELETEon the grant, whose write path is unchanged.GET /api/agents?hidden=trueper opendialog, cached under
agentKeys.list(true)and already invalidated by every agent write.Boundary and audit
which grants are visible and revocable, never which are in force.
configuration.changedrow it always did.the browser only decides which rows to draw for it.
Changelog
Hiding a coworker no longer hides the grants pointing at it, underUnreleased.Proof
app/tests/handoff-roster.test.ts— 7 tests. Fail-before confirmed by replacing the function bodywith the panel's previous selection verbatim and re-running:
and the count, asserted on its own against that same previous selection:
With the fix:
Gates:
To see it on a deployment: as an administrator, grant coworker A the right to ask coworker B, then
open B and Hide it, then reopen A's Handoff section. On
mainB's switch is gone and the count hasdropped, while A can still hand work to B. With this change B is listed, marked hidden, and can be
switched off.