docs(skills): sync mentioning/squads source maps with shared trigger computation

The squads source map still pointed the comment-trigger contract at the
pre-refactor call chain (comment.go:940 -> shouldEnqueueSquadLeaderOnComment),
and the mentioning skill referenced the deleted wrapper. Re-anchor both
to computeCommentAgentTriggers / computeAssignedSquadLeaderCommentTrigger
/ computeMentionedAgentCommentTriggers with current line numbers.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Naiyuan Qing
2026-06-10 16:11:47 +08:00
parent 255cc61e5a
commit 5fec5e2443
3 changed files with 43 additions and 41 deletions

View File

@@ -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.

View File

@@ -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

View File

@@ -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/<id>` 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/<id>` 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