fix(platform): gate the task-comment automation trigger on the author - #3146
fix(platform): gate the task-comment automation trigger on the author#3146Israeltheminer wants to merge 1 commit into
Conversation
Two 0.4 behaviours the 0.5 port dropped from the task-comment path. An agent- or workflow-authored comment could start the task's owning automation. 0.4 called the trigger from one place — `applyUserTaskComment`, the single write path for a USER comment — while the agent door hard-coded `actorType: 'agent'` and never reached it. 0.5 merged both lanes into one `addTaskComment`, and `maybeTriggerOwningAutomation` ran unconditionally with no author type to check. The result is a self-sustaining loop: the automation comments, the comment restarts the automation, and every iteration is a metered agent turn. `startWorkflowForTask`'s duplicate guard does not catch it — one live run per (automation, task) blocks a concurrent second start, not a sequential loop. The trigger now takes the author type and returns early unless it is `user`, mirroring the agent lane's `dispatchMentionedProjectAgent` gate right below it in the same file. Editing a comment never re-resolved its mentions: `editTaskComment` wrote only `edited_at_ms`, so editing a comment to add `@someone` notified nobody and the stored mention set went stale. It now re-resolves through `resolveSurfaceMentions` and diffs with `addedMentions` — which had survived the port with no production caller — patching the full set onto the meta row and fanning out the ADDED mentions only, as the bell plus `comment.mentioned` with no subscriber re-alert. Rewording prose around an existing `@handle` still notifies nobody. Editing starts no engine. Both are probed in the real-Postgres integration check, each seen red against deliberately broken code: dropping the author gate enqueues a `task.start_workflow` job for the agent-authored comment; reverting the edit path notifies nobody and leaves the stored set stale; fanning out the full set instead of the added ones gives the already-mentioned teammate a second bell. Task DESCRIPTION mentions (`updateTask`) stay PENDING — a separate decision.
a88b5ec to
737ab3e
Compare
|
Rebased onto current One thing worth recording, because it nearly went out silently. The only conflict was Verified against a real Postgres and MinIO:
+2 checks, +3 passes, no new failures. Mine shows five failures where The behavioural pair still holds after the rebase: an agent-authored comment naming the owning automation enqueues nothing, while a human's identical comment enqueues the run. |
An agent- or workflow-authored task comment could start the task's owning automation. Each iteration is a metered agent turn, so it sustains itself: run finishes, posts a comment naming itself, new run.
Refs #3142.
Why
0.4 called the trigger from exactly one place —
applyUserTaskComment, whose docblock calls itself "THE single write path for a USER-authored comment". The agent door was a separate function hard-codingactorType: 'agent'and never reached the trigger. #3071's body states the rule: the trigger runs "from the USER comment path only — agent/workflow-authored comments never trigger, keeping the loop-safety posture".On 0.5 one
addTaskCommentserves both lanes and calledmaybeTriggerOwningAutomationunconditionally.The asymmetry is what proves it was dropped rather than redesigned:
dispatchMentionedProjectAgent, called four lines below, does receiveauthorTypeand gates on it, docblocked "Only a HUMAN's comment dispatches — an agent's own comment naming itself would loop".Reachable through three elevated callers, all of which pass the write check: the workflow
task.commentnative (actorId: 'workflow'), the task-agent's owntask_commenttool, and the overdue nudge cron.startWorkflowForTask's guard is one live run per (automation, task) — it blocks a concurrent second start, not a sequential loop.Observed, not reasoned: with the gate deleted, an agent-authored comment enqueued a real
task.start_workflowjob.What changed
authorTypeis threaded intomaybeTriggerOwningAutomationand gated on'user', mirroring the sibling four lines away rather than inventing a second mechanism.Second fix in the same file: editing a comment never re-resolved its mentions, so editing one to add
@someonenotified nobody and the stored mention set went stale against the rendered body. 0.4's edit path re-parsed, patched the set, and fanned out only the newly added names.editTaskCommentwroteedited_at_msand nothing else.addedMentionssurvived incore/tasks/mentions.tswith no caller — it is now wired, so only added names are notified. Re-notifying everyone on every edit is the bug that diff existed to prevent.Tests
integration-check.ts, run against a real Postgres and MinIO.agentAuthored: startJobs=1 (want 0)— the loop, observededited_at_msaddedBell=0 (want 1)alreadyMentionedBells=2 (unchanged from 1)The bell count is a valid observable here because
mentionis deliberately absent from the coalesce dimension map, so a second bell really is a second row.The three elevated callers were each re-checked against green probes: the workflow native now enqueues nothing (the point), while the task-agent tool still posts its comment and the overdue nudge still posts its nudge.
Scope
Task description mentions still never fan out. That one is named in a
PENDING:note inbackend/MIGRATION.md, so it is a separate decision rather than a dropped fix — though the ledger row is marked done, which is worth correcting.addedMentionsis wired for comments only.The edit path does not surface unresolved mention tokens. 0.4's did not either, and adding it would be new user-visible copy needing all three locales.
Gate:
bun run formatclean,bun run lint0/0 across 17 workspaces,typecheckexit 0, unit suite 72,275 passing, SAST 0 findings. Integration 279/281 — the two failures are ayt-dlp-dependent probe absent from the host and a warm-MinIO bucket collision, both failing identically on the unmodified base.