fix(teams): scope team tasks to the delegation origin, not the delivery channel - #1530
fix(teams): scope team tasks to the delegation origin, not the delivery channel#1530yatul wants to merge 2 commits into
Conversation
|
Addressed the merge gates from the #1529 triage — both named tests are in, and each fails when the fix is reverted.
Together with the two tests already in the PR (create persists the origin; a non-delegated run is unchanged) that covers persistence, notification routing, isolation, and the identity case.
|
…ry channel
A delegated run is delivered on the internal "delegate" channel while its real
origin is preserved separately — buildAgentLinkRunRequest is explicit about it:
// preserves the origin's authorization-bearing identity while keeping
// delegation on its internal delivery channel.
Channel: "delegate",
WorkspaceChannel: req.Channel,
WorkspaceChatID: req.ChatID,
The team tools did not consult that origin, so a task created by a lead reached
through delegate was stamped with the delivery channel. Nothing is registered
for it, so every notification about that task — completion, failure, blocker
escalation, ask_user — was dropped:
unknown channel for outbound message channel=delegate
The delegatee's first answer still arrived, because it travels back as the
delegation result rather than through a channel; everything the lead said after
the delegation closed was lost. One session produced 16 such drops, including a
blocker escalation the user needed to see.
Add OriginChannelFromCtx / OriginChatIDFromCtx next to the existing workspace
scope propagation helpers, and use them where team scoping and notification
routing are decided: task records, list/search scoping, dispatch fallbacks,
event payloads, escalation tasks, ask_user and leader notifications. The
resolution is the identity when no delegation origin is present, so
non-delegated flows are unchanged.
Deliberately not touched: the channel used in authorization decisions
(checkTeamAccess, requireLead, approve/reject lead bypass). Those ask "how did
this call arrive", not "where should the answer go", and widening them is a
separate question.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…tion Triage on nextlevelbuilder#1529 named two gates this PR had not met: regression coverage for delegated lead task completion, and a guard that unrelated origins cannot receive the notification. The existing tests only covered what create persists. TestDelegatedLeadCompletionNotifiesOrigin completes a task raised in a delegated context and asserts the completion event is addressed to the caller's origin. Reverting team_event_helpers.go to the delivery channel fails it with "addressed to delegate/system". TestCompletionNotificationStaysWithinItsOwnOrigin puts two tasks from different origins on one board, completes one, and asserts no completion notification carries the other origin. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
b951ec3 to
4b9337f
Compare
clark-cant
left a comment
There was a problem hiding this comment.
Review: fix(teams): scope team tasks to the delegation origin, not the delivery channel
Verdict: Approve ✅
Risk level: Low — focused, consistent change across 10 files with comprehensive tests.
Mandatory gates:
- Duplicate / prior implementation: clear — no overlap with existing work. Sibling PR #1537 addresses a different concern (team workspace for delegated lead).
- Project standards: clear — follows established context-key helper pattern (WorkspaceChannelFromCtx/WorkspaceChatIDFromCtx).
- Strategic necessity: clear value — fixes 16 notification drops in a single session, including missed blocker escalations.
Findings: None. The change is clean:
- New
OriginChannelFromCtx/OriginChatIDFromCtxhelpers correctly prefer workspace origin over delivery channel, with identity fallback for non-delegated runs. - All call sites consistently updated (create, list, search, followup, attach, dispatch, escalation, event helpers, validation).
- Authorization paths deliberately untouched — correct security boundary awareness.
- 4 tests cover: delegation origin persistence, non-delegated identity, completion notification routing, and cross-origin isolation.
- PR body is excellent: problem statement, fix rationale, test strategy, live deployment verification with before/after evidence.
Posted by github-maintain at 2026-09-01T13:42:00Z
|
Force-pushed to strip build output that should never have been in this branch.
The diff was 421 files for a ten-line behavioural change. That is on me, and it made this PR unreviewable at a glance — quite possibly why it has sat while its siblings (#1528, #1533) were triaged and merged. Now: Both commits keep their original messages, authorship and dates; only the file set of the first changed. Verified: diffing the old head against the new one while excluding Nothing else about the PR changed — the fix and Unrelated, but perhaps worth a line in |
Fixes #1529. Sibling of #1527 / #1528 — same underlying assumption, no code overlap. The two are independent and can land in either order.
Problem
buildAgentLinkRunRequestis explicit that a delegated run is delivered on an internal channel while its real origin is kept aside:The team tools never consulted that origin, so a task created by a lead reached through
delegatewas stamped with the delivery channel. Nothing is registered for"delegate", sointernal/channels/dispatch.godropped every notification about that task — completion, failure, blocker escalation,ask_user:The delegatee's first answer still arrived, because it travels back as the delegation result rather than through a channel. Everything the lead said afterwards was lost — one session produced 16 such drops, including an escalation the user needed:
Change
Add
OriginChannelFromCtx/OriginChatIDFromCtxbeside the existing workspace-scope helpers, and use them where team scoping and notification routing are decided: task records, list/search scoping, dispatch fallbacks, event payloads, escalation tasks,ask_user, leader notifications. Both resolve to the identity when no delegation origin is present, so non-delegated flows are untouched.Create and read had to move together — the create lock key and the
listchat filter must agree, or a lead would stop seeing its own board.Deliberately not changed: the channel used in authorization decisions —
checkTeamAccess,requireLead, and the approve/reject lead bypass. Those ask "how did this call arrive", not "where should the answer go"; widening them is a separate question and a separate risk.Test
Two subtests around
executeCreate: one shapes the context the waybuildAgentLinkRunRequestdoes (delivery channel"delegate", origin preserved separately) and asserts the task records the origin; the other asserts a non-delegated lead still records its own channel and chat. The first fails ondev:go test ./internal/tools/ ./cmd/... ./internal/gateway/... ./internal/http/... ./internal/agent/...is green.Verified in a live deployment
Built with this change (on top of #1528, so the tasks actually dispatch) and deployed to Kubernetes. Same delegated-lead flow:
That last line is the point: the completion announce is now delivered into the caller's session instead of a delegation session that closed minutes earlier. Drops on
channel=delegatewent from 16 in the previous session to 2, and both remaining ones come from tasks created before the change — their bad channel is already persisted, so the fix is forward-looking only. Existing stuck tasks keep routing nowhere until they are recreated; worth a note in release notes, or a migration if you would rather backfill fromTaskMetaOriginSession.