The HTTP CreateComment handler read X-Task-ID for parent-id validation and
the no_action gate, but never stamped source_task_id on the comment row.
That silently broke the originator inheritance chain used by every task the
comment triggers downstream (resolveOriginatorFromTriggerComment climbs
comment.source_task_id → parent task's originator_user_id).
Consequence: on a squad-assigned issue where the leader agent is private
(the default permission_mode for agents), the leader → worker mention hop
would enqueue the worker's task with originator_user_id = NULL. When the
worker later posts its result comment, invokeOriginatorFromRequest reads
that NULL back out, opts.OriginatorUserID becomes "", and
routeAssignedSquadLeaderFallback → canInvokeAgent denies the leader wake
(private agents admit only the owner, and effectiveUser is empty). The
leader → worker → leader coordination loop stayed broken until the leader
was triggered by something else. Public-to-workspace leaders papered over
the issue via the workspaceBroad admittance path in canInvokeAgent.
Fix: capture the same X-Task-ID the handler already reads and pass it as
SourceTaskID on the CreateComment call. Only stamp when the task belongs to
this issue — a same-agent, different-issue comment must not attribute
itself to an unrelated task's originator. All existing gates
(parent_id-vs-trigger_comment mismatch, no_action) still fire before the
stamp is applied.
Regression coverage in squad_worker_comment_wakes_leader_test.go:
- worker-agent completion comment wakes a public_to squad leader
(baseline: was passing before the fix, kept as guardrail)
- worker-agent completion coalesces when a leader task is already queued
- worker-agent completion wakes a PRIVATE squad leader through the
leader → worker mention hop (the failing case, red before → green after)
Co-authored-by: Eve <[email protected]>
Co-authored-by: multica-agent <[email protected]>