diff --git a/server/internal/service/builtin_skills/multica-mentioning/SKILL.md b/server/internal/service/builtin_skills/multica-mentioning/SKILL.md index 948d11131..2293e4ff1 100644 --- a/server/internal/service/builtin_skills/multica-mentioning/SKILL.md +++ b/server/internal/service/builtin_skills/multica-mentioning/SKILL.md @@ -57,11 +57,10 @@ match, or the link resolves to the wrong entity (or to nothing). | link a person | `member` | member.user_id | renders a link; enqueues NOTHING — no agent run | | reference an issue | `issue` | issue.id | renders a link; enqueues NOTHING — always safe | -The enqueue logic lives in `enqueueMentionedAgentTasks` -(`server/internal/handler/comment.go`). The actual mention trigger set is -computed by `computeMentionedAgentCommentTriggers`, then the comment path -passes that result through `computeCommentAgentTriggers` before enqueueing. It -acts on two types only: the `squad` branch resolves the squad and adds its +The mention trigger set is computed by `computeMentionedAgentCommentTriggers` +(`server/internal/handler/comment.go`); the comment path folds that result into +`computeCommentAgentTriggers` and enqueues it via `enqueueCommentAgentTriggers`. +It acts on two types only: the `squad` branch resolves the squad and adds its leader to the trigger set; everything that is not `agent` after that is skipped (`if m.Type != "agent" { continue }`), then the `agent` branch adds that agent. A `member` or `issue` mention reaches neither branch, so it enqueues no task. diff --git a/server/internal/service/builtin_skills/multica-mentioning/references/mentioning-source-map.md b/server/internal/service/builtin_skills/multica-mentioning/references/mentioning-source-map.md index bb689339e..9844503af 100644 --- a/server/internal/service/builtin_skills/multica-mentioning/references/mentioning-source-map.md +++ b/server/internal/service/builtin_skills/multica-mentioning/references/mentioning-source-map.md @@ -30,37 +30,37 @@ a pointer. Branch where verified: `feat/builtin-skills`. | Fact | Source | | --- | --- | -| `computeCommentAgentTriggers` is the shared comment trigger computation used before enqueueing | `server/internal/handler/comment.go:1101-1133` | -| `enqueueMentionedAgentTasks` now delegates to the mention trigger computation and shared enqueue helper | `server/internal/handler/comment.go:1308-1310` | -| It is called for comment creation via `triggerTasksForComment`, which computes triggers, applies suppressions, then enqueues | `server/internal/handler/comment.go:1037-1040` | -| `squad` branch: resolve squad in workspace, read `LeaderID`, add the leader trigger | `server/internal/handler/comment.go:1330-1369` | -| `squad` → shared enqueue helper calls `EnqueueTaskForSquadLeader` | `server/internal/handler/comment.go:1083-1089` | -| Everything not `agent` after the squad branch is skipped: `if m.Type != "agent" { continue }` | `server/internal/handler/comment.go:1372-1374` | -| `agent` branch: load agent in workspace, then add the agent trigger | `server/internal/handler/comment.go:1375-1402` | -| `agent` → shared enqueue helper calls `EnqueueTaskForMention` (a run for that agent) | `server/internal/handler/comment.go:1090-1096` | -| **`member` and `issue` mentions reach neither branch — they enqueue NOTHING.** A `member` mention fails the `!= "agent"` skip at lines 1372-1374 (the squad branch above it only matches `squad`); an `issue` mention does the same. | `server/internal/handler/comment.go:1330,1372-1374` | +| `computeCommentAgentTriggers` is the shared comment trigger computation used before enqueueing | `server/internal/handler/comment.go:1124-1160` | +| `computeMentionedAgentCommentTriggers` builds the mention trigger set; `enqueueCommentAgentTriggers` is the shared enqueue helper | `server/internal/handler/comment.go:1335,1089` | +| Comment creation runs `triggerTasksForComment`, which computes triggers, applies suppressions, then enqueues | `server/internal/handler/comment.go:1057-1064` | +| `squad` branch: resolve squad in workspace, read `LeaderID`, add the leader trigger | `server/internal/handler/comment.go:1352-1391` | +| `squad` → shared enqueue helper calls `EnqueueTaskForSquadLeader` | `server/internal/handler/comment.go:1104-1112` | +| Everything not `agent` after the squad branch is skipped: `if m.Type != "agent" { continue }` | `server/internal/handler/comment.go:1394-1396` | +| `agent` branch: load agent in workspace, then add the agent trigger | `server/internal/handler/comment.go:1397-1424` | +| `agent` → shared enqueue helper calls `EnqueueTaskForMention` (a run for that agent) | `server/internal/handler/comment.go:1113-1119` | +| **`member` and `issue` mentions reach neither branch — they enqueue NOTHING.** A `member` mention fails the `!= "agent"` skip at lines 1394-1396 (the squad branch above it only matches `squad`); an `issue` mention does the same. | `server/internal/handler/comment.go:1352,1394-1396` | ## Preview and suppression | Fact | Source | | --- | --- | -| Preview route: `POST /api/issues/{id}/comments/trigger-preview` | `server/cmd/server/router.go:667` | -| Preview handler loads the issue and parent comment, expands issue identifiers, then calls `computeCommentAgentTriggers` | `server/internal/handler/comment.go:830-874` | -| Preview response returns agent `id`, `name`, optional `avatar_url`, `source`, and `reason` | `server/internal/handler/comment.go:781-827` | -| `CreateCommentRequest` accepts optional `suppress_agent_ids` | `server/internal/handler/comment.go:768-774` | -| `suppress_agent_ids` is parsed as request-boundary UUID input | `server/internal/handler/comment.go:920-927` | -| Create comment computes the full trigger set, then applies `filterSuppressedCommentAgentTriggers` before enqueueing | `server/internal/handler/comment.go:1037-1064` | +| Preview route: `POST /api/issues/{id}/comments/trigger-preview` | `server/cmd/server/router.go:707` | +| Preview handler loads the issue and parent comment, expands issue identifiers, then calls `computeCommentAgentTriggers` | `server/internal/handler/comment.go:832-877` | +| Preview response returns agent `id`, `name`, optional `avatar_url`, `source`, and `reason` | `server/internal/handler/comment.go:783-793` | +| `CreateCommentRequest` accepts optional `suppress_agent_ids` | `server/internal/handler/comment.go:770-776` | +| `suppress_agent_ids` is parsed as request-boundary UUID input | `server/internal/handler/comment.go:925-928` | +| Create comment computes the full trigger set, then applies `filterSuppressedCommentAgentTriggers` before enqueueing | `server/internal/handler/comment.go:1057-1087` | ## Guards that make a valid mention a silent no-op | Guard | Source | | --- | --- | -| agent archived / no runtime → `continue` (`RuntimeID` invalid or `ArchivedAt` set) | `server/internal/handler/comment.go:1382-1387` | -| squad leader archived / no runtime → `continue` | `server/internal/handler/comment.go:1349-1355` | -| private agent the actor cannot access → `continue` (`canAccessPrivateAgent`) | `server/internal/handler/comment.go:1389-1392` | -| private squad leader the actor cannot trigger → `continue` (`canAccessPrivateAgent`) | `server/internal/handler/comment.go:1357-1360` | -| already-pending dedup (agent) → `HasPendingTaskForIssueAndAgent` → `continue` | `server/internal/handler/comment.go:1394-1400` | -| already-pending dedup (squad leader) → `continue` | `server/internal/handler/comment.go:1361-1368` | +| agent archived / no runtime → `continue` (`RuntimeID` invalid or `ArchivedAt` set) | `server/internal/handler/comment.go:1408-1410` | +| squad leader archived / no runtime → `continue` | `server/internal/handler/comment.go:1376-1378` | +| private agent the actor cannot access → `continue` (`canAccessPrivateAgent`) | `server/internal/handler/comment.go:1413-1415` | +| private squad leader the actor cannot trigger → `continue` (`canAccessPrivateAgent`) | `server/internal/handler/comment.go:1380-1382` | +| already-pending dedup (agent) → `HasPendingTaskForIssueAndAgent` → `continue` | `server/internal/handler/comment.go:1417-1423` | +| already-pending dedup (squad leader) → `continue` | `server/internal/handler/comment.go:1384-1390` | | `canAccessPrivateAgent` definition | `server/internal/handler/agent_access.go` (search `func (h *Handler) canAccessPrivateAgent`) | | `canEnqueueSquadLeader` (loads leader, delegates to `canAccessPrivateAgent`) | `server/internal/handler/agent_access.go:82-91` | @@ -68,10 +68,10 @@ a pointer. Branch where verified: `feat/builtin-skills`. | Fact | Source | | --- | --- | -| `commentMentionsOthersButNotAssignee` — decides whether to suppress the assignee's on-comment trigger | `server/internal/handler/comment.go:1179` | -| `@all` is treated as a broadcast → returns true → assignee auto-trigger suppressed | `server/internal/handler/comment.go:1191-1194` | -| Comment-flow computation that consults it | `server/internal/handler/comment.go:1113-1115` | -| `@all` never enqueues a specific agent: it is neither `squad` nor `agent`, so it is skipped in the mention trigger computation | `server/internal/handler/comment.go:1372-1374` | +| `commentMentionsOthersButNotAssignee` — decides whether to suppress the assignee's on-comment trigger | `server/internal/handler/comment.go:1206` | +| `@all` is treated as a broadcast → returns true → assignee auto-trigger suppressed | `server/internal/handler/comment.go:1217-1221` | +| Comment-flow computation that consults it | `server/internal/handler/comment.go:1140-1142` | +| `@all` never enqueues a specific agent: it is neither `squad` nor `agent`, so it is skipped in the mention trigger computation | `server/internal/handler/comment.go:1394-1396` | ## CLI id sources (where the UUID comes from) @@ -87,9 +87,9 @@ a pointer. Branch where verified: `feat/builtin-skills`. The skill deliberately does **not** assert that a `member` mention "sends a notification." `server/internal/handler/comment.go` has no notification -delivery path for member (or issue) mentions: `enqueueMentionedAgentTasks` +delivery path for member (or issue) mentions: `computeMentionedAgentCommentTriggers` branches only on `squad` and `agent` -(`server/internal/handler/comment.go:1330,1372-1374`), and a grep of the file for +(`server/internal/handler/comment.go:1352,1394-1396`), and a grep of the file for `notif` returns only an unrelated comment about avoiding "log spam" on unchanged threads — no member-notification call. The verified contract is narrow: a `member` or `issue` mention renders as a link and enqueues no agent diff --git a/server/internal/service/builtin_skills/multica-squads/references/squad-source-map.md b/server/internal/service/builtin_skills/multica-squads/references/squad-source-map.md index a5a43a78e..206893a74 100644 --- a/server/internal/service/builtin_skills/multica-squads/references/squad-source-map.md +++ b/server/internal/service/builtin_skills/multica-squads/references/squad-source-map.md @@ -121,23 +121,26 @@ Contracts: Source: ```text -server/internal/handler/comment.go # comment-trigger ~940-941, squad mention ~1089 -server/internal/handler/squad.go # shouldEnqueueSquadLeaderOnComment ~909, enqueueSquadLeaderTask ~1027 +server/internal/handler/comment.go # comment triggers ~1057-1199, squad mention branch ~1352 +server/internal/handler/squad.go # enqueueSquadLeaderTask ~986 (assign/backlog paths), lastTaskWasLeader ~915 server/internal/service/task.go # EnqueueTaskForSquadLeader ``` Contracts: -- commenting on a squad-assigned issue can wake the leader - (comment.go:940-941 → shouldEnqueueSquadLeaderOnComment at squad.go:909); -- explicit `mention://squad/` resolves squad and enqueues leader - (comment.go:1089); +- commenting on a squad-assigned issue can wake the leader — the comment path + computes triggers via `computeCommentAgentTriggers` (comment.go:1124), whose + assigned-squad branch is `computeAssignedSquadLeaderCommentTrigger` + (comment.go:1162-1199); the same computation backs the trigger-preview + endpoint; +- explicit `mention://squad/` resolves squad and adds the leader trigger + (comment.go:1352-1391); - squad mention does not fan out to members — enqueue targets `squad.LeaderID` - only (squad.go:1050); + only (comment.go:1104-1112, and squad.go:1007 on the assign/backlog paths); - leader task uses `is_leader_task=true` (via `EnqueueTaskForSquadLeader`); - leader self-trigger loops are guarded — same-leader / last-task-was-leader - guards (squad.go:929-932, lastTaskWasLeader at squad.go:959) and member - explicit-mention skip (squad.go:939-941). + guards (comment.go:1173-1176, lastTaskWasLeader at squad.go:915) and member + explicit-mention skip (comment.go:1177-1179). ## Autopilot