Skip to content

feat(#5650): add /fs-stop to skip auto agent triggers - #5920

Closed
ascerra wants to merge 11 commits into
mainfrom
feat/fs-stop-agent
Closed

feat(#5650): add /fs-stop to skip auto agent triggers#5920
ascerra wants to merge 11 commits into
mainfrom
feat/fs-stop-agent

Conversation

@ascerra

@ascerra ascerra commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

Summary

Adds /fs-stop <agent> (and /fs-fix-stop alias) so humans can apply fullsend-no-* labels that skip auto-triggered agent runs. Dispatch enforces the labels on auto paths; on-demand /fs-<agent> commands still bypass them. In-flight workflow cancellation is intentionally deferred (unsafe substring matching was rejected in review).

Related Issue

Addresses #5650 (labeling + dispatch enforcement; cancel follow-up still open)

Changes

  • Rename shim stop-fixstop-agent; support /fs-stop, bare /fs-stop, and /fs-fix-stop
  • Auth via collaborator API + issue/PR author hatch (ADR 0054)
  • Bare /fs-stop applies labels meaningful for the item type (issue: triage/code; PR: review/fix/retro)
  • Enforce fullsend-no-{triage,code,review,fix,retro} on auto paths in both dispatch copies (including needs-info → triage)
  • Docs for agent control labels; ADR 0033/0034 rename annotations
  • Scaffold runtime tests for auth, parsing, issue vs PR paths, and fromJSON newline matchers

Testing

  • go test ./internal/scaffold/ -run 'TestShim|TestDispatch|TestReusable|TestManaged'
  • Pre-commit hooks (including workflow size + actionlint)
  • make lint on staged tree in CI

Checklist

  • PR title follows Conventional Commits (correct type, ! for breaking changes)
  • Commits are signed off (DCO) — human and human-directed agent sessions only
  • I wrote this contribution myself and can explain all changes in it

Made with Cursor

@ascerra
ascerra requested a review from a team as a code owner August 5, 2026 02:05
@fullsend-ai-review

fullsend-ai-review Bot commented Aug 5, 2026

Copy link
Copy Markdown

🤖 Finished Review · ✅ Success · Started 2:06 AM UTC · Completed 2:22 AM UTC
Commit: 7423e1f · View workflow run →

@qodo-code-review

Copy link
Copy Markdown

PR Summary by Qodo

Add /fs-stop to apply fullsend-no-* labels and gate auto agent dispatch

✨ Enhancement ⚙️ Configuration changes 📝 Documentation 🧪 Tests 🕐 40+ Minutes

Grey Divider

AI Description

• Add /fs-stop [agent] (and /fs-fix-stop alias) to disable auto agent triggers via labels.
• Enforce fullsend-no-* labels in dispatch auto-routing while keeping /fs- on-demand runs
 working.
• Update ADRs/docs and add scaffold tests to prevent shim/dispatch drift.
Diagram

graph TD
  U["Human comment (/fs-stop or /fs-<agent>)"] --> S["Shim workflow: stop-agent"] --> L["GitHub labels: fullsend-no-*"] --> D["Dispatch routing (reusable + scaffold)"] --> A["Auto agent workflows"]
  U --> D
Loading
High-Level Assessment

The following are alternative approaches to this PR:

1. Factor stop-agent bash into a shared script/composite action
  • ➕ Eliminates duplicated bash across managed shim + two templates
  • ➕ Simplifies drift-prevention tests (assert script version/hash instead of large YAML hunks)
  • ➕ Easier to extend (new agents/labels) with less copy/paste risk
  • ➖ May require repo checkout or additional workflow plumbing to access the script
  • ➖ Composite action introduces its own versioning/review surface
  • ➖ Harder to keep 'no external deps beyond GITHUB_TOKEN' property if not done carefully
2. Implement in-flight cancellation via concurrency groups (follow-up)
  • ➕ Matches user expectation: stop also halts currently running jobs
  • ➕ Avoids brittle substring-based workflow run selection
  • ➖ Requires careful concurrency design to avoid blocking unrelated jobs
  • ➖ May not be viable for BYOA/per-repo installs depending on workflow topology

Recommendation: The PR’s approach (labels + dispatch enforcement, with explicit bypass for /fs-) is the right safety/complexity tradeoff for now because it relies only on standard GitHub primitives and the existing permission model (ADR 0054). Consider a small follow-up to reduce duplication by extracting stop-agent logic into a shared script/action once the behavior stabilizes; keep cancellation as a separate, safer design effort (e.g., concurrency-based) rather than run-name matching.

Files changed (16) +642 / -145

Enhancement (1) +125 / -19
fullsend.yamlGeneralize stop-fix into stop-agent with /fs-stop parsing and labeling +125/-19

Generalize stop-fix into stop-agent with /fs-stop parsing and labeling

• Renames the shim job to 'stop-agent', broadens triggering to '/fs-stop' (bare or with an agent) and keeps '/fs-fix-stop' as an alias. Adds bash parsing to apply 'fullsend-no-{triage,code,review,fix,retro}' labels appropriately for issues vs PRs, with collaborator-API authorization and an author escape hatch.

.github/workflows/fullsend.yaml

Tests (2) +154 / -51
scaffold_test.goExpand scaffold tests for stop-agent, label gating, and parsing behavior +147/-49

Expand scaffold tests for stop-agent, label gating, and parsing behavior

• Renames stop-fix tests to stop-agent, adds runtime tests using a stubbed 'gh' binary to validate authorization, parsing, issue vs PR edit paths, unknown-agent handling, and fromJSON newline matchers. Adds drift guards to ensure managed shim and templates stay aligned with the new logic and label gates.

internal/scaffold/scaffold_test.go

workflow_call_alignment_test.goAdd dispatch alignment assertions for fullsend-no-* routing gates +7/-2

Add dispatch alignment assertions for fullsend-no-* routing gates

• Extends reusable-dispatch alignment tests to assert the presence of new 'fullsend-no-*' checks and '/fs-stop|/fs-fix-stop' handling. Updates retro close-path assertion to allow ungated actors while still honoring 'fullsend-no-retro'.

internal/scaffold/workflow_call_alignment_test.go

Documentation (9) +49 / -18
0033-per-repo-installation-mode.mdAnnotate stop-fix rename to stop-agent +1/-0

Annotate stop-fix rename to stop-agent

• Documents that the historical 'stop-fix' shim job was renamed to 'stop-agent' when generalized for '/fs-stop', pointing readers to ADR 0034 for context.

docs/ADRs/0033-per-repo-installation-mode.md

0034-centralized-shim-routing-via-dispatch.mdUpdate ADR text for stop-agent and new triage gating behavior +10/-6

Update ADR text for stop-agent and new triage gating behavior

• Renames references from 'stop-fix' to 'stop-agent' and clarifies that '/fs-stop <agent>' applies 'fullsend-no-{agent}' labels without cancelling in-flight runs. Notes that needs-info triage re-entry is skipped when 'fullsend-no-triage' is present.

docs/ADRs/0034-centralized-shim-routing-via-dispatch.md

code.mdDocument /fs-stop code and fullsend-no-code label semantics +3/-0

Document /fs-stop code and fullsend-no-code label semantics

• Adds '/fs-stop code' to the command table and documents 'fullsend-no-code' as the control label that suppresses auto-triggered code runs while leaving '/fs-code' unaffected.

docs/agents/code.md

fix.mdReframe /fs-fix-stop as /fs-stop fix alias and document label usage +7/-4

Reframe /fs-fix-stop as /fs-stop fix alias and document label usage

• Updates the fix agent docs to describe '/fs-fix-stop' as an alias of '/fs-stop fix', expands scope to issue or PR comments, and clarifies that labels only block auto runs (slash commands still work).

docs/agents/fix.md

prioritize.mdClarify prioritize is slash-only and not affected by /fs-stop +4/-0

Clarify prioritize is slash-only and not affected by /fs-stop

• Documents that '/fs-stop' does not apply to prioritize because there is no auto-trigger path for prioritize in dispatch.

docs/agents/prioritize.md

retro.mdDocument /fs-stop retro and fullsend-no-retro +3/-0

Document /fs-stop retro and fullsend-no-retro

• Adds '/fs-stop retro' and describes 'fullsend-no-retro' as the label that suppresses auto retro on PR close while keeping '/fs-retro' functional.

docs/agents/retro.md

review.mdDocument /fs-stop review and fullsend-no-review auto gate +5/-1

Document /fs-stop review and fullsend-no-review auto gate

• Adds '/fs-stop review' to the command table, clarifies auth requirements for stop, and documents that auto-review is skipped when 'fullsend-no-review' is present while '/fs-review' remains available on demand.

docs/agents/review.md

triage.mdDocument /fs-stop triage and fullsend-no-triage behavior +4/-1

Document /fs-stop triage and fullsend-no-triage behavior

• Adds '/fs-stop triage' to triage docs, updates auth notes for stop, and documents 'fullsend-no-triage' as suppressing auto triage including needs-info re-entry.

docs/agents/triage.md

bugfix-workflow.mdAdd user-facing guide for /fs-stop and stopping automation +12/-6

Add user-facing guide for /fs-stop and stopping automation

• Updates the pipeline control table to include '/fs-stop [agent]' and clarifies '/fs-fix-stop' as an alias. Expands the 'Stopping automation' section to explain label effects, issue-vs-PR scope, and that in-flight runs are not cancelled.

docs/guides/user/bugfix-workflow.md

Other (4) +314 / -57
reusable-dispatch.ymlGate auto-routing on fullsend-no-* labels and ignore /fs-stop commands +31/-9

Gate auto-routing on fullsend-no-* labels and ignore /fs-stop commands

• Adds a no-route case for '/fs-stop' and '/fs-fix-stop' since the shim handles them. Enforces 'fullsend-no-{triage,code,review,retro}' checks on auto-trigger paths (including needs-info re-entry) while preserving slash-command routing behavior.

.github/workflows/reusable-dispatch.yml

dispatch.ymlEnforce fullsend-no-* gates in scaffold dispatch routing +32/-10

Enforce fullsend-no-* gates in scaffold dispatch routing

• Mirrors reusable-dispatch gating by preventing auto stage selection when the relevant 'fullsend-no-*' label is present and by ignoring '/fs-stop' commands. Increases workflow size lint limit to accommodate new routing checks.

internal/scaffold/fullsend-repo/.github/workflows/dispatch.yml

shim-per-repo.yamlUpdate per-repo shim template to stop-agent and /fs-stop support +126/-19

Update per-repo shim template to stop-agent and /fs-stop support

• Renames 'stop-fix' to 'stop-agent', updates the job-level command matchers (including newline handling via fromJSON), and applies 'fullsend-no-*' labels to issues or PRs based on the comment context.

internal/scaffold/fullsend-repo/templates/shim-per-repo.yaml

shim-workflow-call.yamlUpdate workflow-call shim template to generalized stop-agent +125/-19

Update workflow-call shim template to generalized stop-agent

• Generalizes the shim job to support '/fs-stop' and '/fs-fix-stop', parses the agent argument, and applies the corresponding 'fullsend-no-*' label(s) with proper authorization and PR/issue handling.

internal/scaffold/fullsend-repo/templates/shim-workflow-call.yaml

@github-actions

github-actions Bot commented Aug 5, 2026

Copy link
Copy Markdown

Site preview

Preview: https://5a592edd-site.fullsend-ai.workers.dev

Commit: 2dc6384fc3732992ecdf8cc8a58480c120102a98

@qodo-code-review

qodo-code-review Bot commented Aug 5, 2026

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (0) 📘 Rule violations (0) 📜 Skill insights (0)

Grey Divider


Action required

1. Bugfix guide lacks prerequisites ✓ Resolved 📜 Skill insight ✧ Quality
Description
docs/guides/user/bugfix-workflow.md contains procedural command guidance (including newly added
/fs-stop controls) but has no clearly labeled ## Prerequisites section before those procedures.
This violates the documentation guide requirement to state prerequisites prior to step-by-step
instructions.
Code

docs/guides/user/bugfix-workflow.md[R65-66]

+| `/fs-fix-stop` | Issue or PR comment | Alias of `/fs-stop fix` — disables bot-triggered fix runs (human `/fs-fix` still works). On an issue, the label only affects that issue (no carry-over to a later PR). |
+| `/fs-stop [agent]` | Issue or PR comment | Applies `fullsend-no-{agent}` (or all agents meaningful for this item type if omitted); skips auto-triggers. Does not cancel in-flight runs. |
Relevance

●●● Strong

Docs/guides changes lacking explicit “Prerequisites” section have been repeatedly enforced and
accepted in prior PRs.

PR-#2663
PR-#2277

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
PR Compliance ID 1062078 requires every guide under docs/guides/ to include a clearly labeled
prerequisites section before procedural steps. The updated guide adds procedural command guidance
(/fs-stop [agent], /fs-fix-stop) but still has no Prerequisites section anywhere in the
document.

docs/guides/user/bugfix-workflow.md[1-5]
docs/guides/user/bugfix-workflow.md[55-75]
Skill: writing-user-docs

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The modified guide `docs/guides/user/bugfix-workflow.md` includes procedural guidance (slash commands and step-like lists) but does not include a clearly labeled `## Prerequisites` section before any procedure, as required.

## Issue Context
This PR adds/updates procedural content about `/fs-stop`/`/fs-fix-stop` in the bugfix workflow guide, increasing the need to clearly state what a reader must have (installation/enrollment state, required GitHub permissions, etc.) before following the guide.

## Fix Focus Areas
- docs/guides/user/bugfix-workflow.md[1-40]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Remediation recommended

2. mktemp aborts stop-agent ⊘ Outdated 🐞 Bug ☼ Reliability
Description
The stop-agent script runs with set -euo pipefail but uses BODY_FILE="$(mktemp)" without error
handling, so a temp-dir/filesystem hiccup will abort the job before it can post the intended
explanatory comment. This makes /fs-stop fail in a non-diagnostic way even though the job is
designed to be fail-closed with user-facing output.
Code

.github/workflows/fullsend.yaml[R166-167]

+              BODY_FILE="$(mktemp)"
+              {
Relevance

●●● Strong

Team previously accepted guarding mktemp under set -euo pipefail to avoid aborting before
diagnostics.

PR-#1688

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
set -euo pipefail causes an unhandled mktemp failure to terminate the script immediately; the
new code introduces multiple unguarded BODY_FILE="$(mktemp)" assignments before posting comments
back to GitHub.

.github/workflows/fullsend.yaml[98-105]
.github/workflows/fullsend.yaml[165-177]
.github/workflows/fullsend.yaml[206-210]
internal/scaffold/fullsend-repo/templates/shim-per-repo.yaml[161-174]
internal/scaffold/fullsend-repo/templates/shim-per-repo.yaml[202-224]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The stop-agent job uses `mktemp` in command substitution without checking for failure while `set -euo pipefail` is enabled. If `mktemp` fails, the step exits immediately and no comment is posted back to the issue/PR.

## Issue Context
This logic is duplicated across the managed shim and scaffold templates, so the fix should be applied consistently to keep the templates and managed workflow in sync.

## Fix Focus Areas
- .github/workflows/fullsend.yaml[98-210]
- internal/scaffold/fullsend-repo/templates/shim-workflow-call.yaml[96-227]
- internal/scaffold/fullsend-repo/templates/shim-per-repo.yaml[161-224]

## Implementation notes
- Wrap `mktemp` with an explicit guard, e.g. `BODY_FILE=$(mktemp) || { echo "::warning::..."; exit 0; }`.
- Consider using a `trap 'rm -f "$BODY_FILE"' EXIT` to ensure cleanup on all paths.
- Apply the same pattern to both `BODY_FILE` allocations (unknown-agent message and final summary message).

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Informational

3. Stop comments still dispatch ✓ Resolved 🐞 Bug ➹ Performance
Description
Routing now explicitly ignores /fs-stop and /fs-fix-stop, so dispatch runs triggered by those
comments will always exit with “No stage matched — skipping dispatch”. The shim dispatch jobs still
run on those comments, causing avoidable workflow runs and log/concurrency noise.
Code

.github/workflows/reusable-dispatch.yml[R229-231]

+                /fs-stop|/fs-fix-stop)
+                  # Handled by the shim stop-agent job — do not route.
+                  ;;
Relevance

●● Moderate

No close precedent; team has previously tolerated silent no-op dispatch paths, so may not prioritize
extra filtering.

PR-#2473

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
Dispatch routing explicitly does nothing for /fs-stop//fs-fix-stop, and the dispatcher exits
early when no stage is selected; meanwhile, the shim dispatch jobs still run on issue_comment events
without filtering these stop commands.

.github/workflows/reusable-dispatch.yml[182-244]
internal/scaffold/fullsend-repo/.github/workflows/dispatch.yml[166-176]
internal/scaffold/fullsend-repo/.github/workflows/dispatch.yml[272-276]
.github/workflows/fullsend.yaml[46-54]
internal/scaffold/fullsend-repo/templates/shim-per-repo.yaml[34-40]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`/fs-stop` and `/fs-fix-stop` are intentionally handled by the shim (stop-agent) and are ignored by dispatch routing, which means dispatch workflows triggered by these comments always no-op. The shim still invokes dispatch for issue comments, so stop commands produce extra workflow runs without functional benefit.

## Issue Context
This happens in both workflow-call (managed) and per-repo shim templates because their dispatch job-level `if:` only filters bots/installation PRs, not stop commands.

## Fix Focus Areas
- .github/workflows/fullsend.yaml[46-54]
- internal/scaffold/fullsend-repo/templates/shim-workflow-call.yaml[44-55]
- internal/scaffold/fullsend-repo/templates/shim-per-repo.yaml[34-40]

## Implementation notes
- Add an additional clause to the shim `dispatch` job `if:` to exclude stop commands, matching the same token rules used by `stop-agent` (including newline/CR handling via `fromJSON('"...\n"')`).
- Keep the exclusion narrow (only `/fs-stop` and `/fs-fix-stop`) so needs-info re-entry and other comment-driven routes keep working.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

Context used
✅ Compliance rules (platform): 61 rules

Grey Divider

Tip of the day
💡 Did you know, you can reply 'qodo' on any finding to push back, ask questions, or dig deeper

More tips ↗ | Customize Qodo ↗ | Qodo docs ↗

Grey Divider

Qodo Logo

@codecov

codecov Bot commented Aug 5, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 75.00000% with 2 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
internal/scaffold/installfiles.go 75.00% 1 Missing and 1 partial ⚠️

📢 Thoughts on this report? Let us know!

Comment thread docs/guides/user/bugfix-workflow.md
Comment thread .github/workflows/fullsend.yaml Outdated
Comment thread .github/workflows/reusable-dispatch.yml Outdated
@fullsend-ai-review

fullsend-ai-review Bot commented Aug 5, 2026

Copy link
Copy Markdown

Review

Findings

Medium

  • [logic-error] internal/scaffold/fullsend-repo/templates/shim-workflow-call.yaml — The stop-agent job hardcodes runs-on: ubuntu-24.04 instead of using the __GH_RUNNER__ placeholder. The base-branch template used __GH_RUNNER__ for the old stop-fix job, and the sibling shim-per-repo.yaml correctly uses __GH_RUNNER__ for its stop-agent job. Enrolled repos using the workflow_call mode with a custom runner will have the stop-agent job execute on ubuntu-24.04 while their dispatch job uses the configured runner.
    Remediation: Change runs-on: ubuntu-24.04 to runs-on: __GH_RUNNER__ in shim-workflow-call.yaml for the stop-agent job.

  • [protected-path] .github/scripts/stop-agent.sh, .github/workflows/fullsend.yaml, .github/workflows/reusable-dispatch.yml — PR modifies files under protected paths (.github/). The PR links to issue Add /fs-stop <agent> slash command with in-flight cancellation #5650 and explains the rationale for these changes (generalized /fs-stop command with dispatch-side label enforcement). Human approval is always required for protected-path changes, regardless of context.

Low

  • [edge-case] .github/workflows/fullsend.yaml:54 — The dispatch job's if: condition uses !contains(github.event.comment.body, '/fs-stop') to skip dispatch when a stop command is present, and the stop-agent job's if: uses contains() to trigger on the same substring. Since contains() does substring matching, a multi-line comment where line 1 is a legitimate slash command (e.g., /fs-review) but a later line mentions /fs-stop would suppress dispatch and trigger the stop-agent job. The PR author acknowledges this is "intentionally coarse" (see YAML comments); exact token matching is deferred to stop-agent.sh, which exits cleanly for non-matching commands.

  • [stale-doc] docs/guides/getting-started/operations.md:75 — The manual unenrollment steps say to delete .github/workflows/fullsend.yaml but do not mention .github/scripts/stop-agent.sh, which is now a second managed file deployed during enrollment and cleaned up by the automated reconcile script. Users following the manual unenrollment procedure would leave an orphaned stop-agent script.
    Remediation: Update the manual unenrollment steps to include .github/scripts/stop-agent.sh in the list of files to delete.


Next steps:

  • /fs-fix — agent addresses review findings automatically
  • /fs-fix <your instruction> — agent fixes with your specific guidance
  • Push commits directly — review re-runs automatically on push
  • /fs-fix-stop — disable automatic fix runs for this PR
Previous run

Review

Findings

Medium

  • [protected-path] .github/scripts/stop-agent.sh, .github/workflows/fullsend.yaml, .github/workflows/reusable-dispatch.yml — PR modifies files under protected paths (.github/). The PR links to issue Add /fs-stop <agent> slash command with in-flight cancellation #5650 and explains the rationale for these changes (generalized /fs-stop command with dispatch-side label enforcement). Human approval is always required for protected-path changes, regardless of context.

Low

  • [authorization-policy-coherence] docs/ADRs/0086-fs-stop-agent-and-no-agent-labels.md:47 — Authorization asymmetry: issue/PR authors can stop fix (via /fs-stop fix or /fs-fix-stop) but cannot stop review. ADR 0086 Decision Use AI to help formalise intent after rapid local prototyping #4 restricts the author escape hatch to fix-only with rationale "authors cannot unilaterally suppress security-relevant auto-gates." The code comments in stop-agent.sh reinforce this distinction, but the ADR could be more explicit about why fix differs from review (fix pushes code to the author’s branch; review is a security gate).
    Remediation: Add a sentence to ADR 0086 Decision Use AI to help formalise intent after rapid local prototyping #4 explaining the fix/review distinction.

  • [GHA workflow command injection] .github/scripts/stop-agent.sh:107 — COMMENT_USER_LOGIN is interpolated into ::warning:: and ::notice:: workflow commands (lines 107, 111, 116, 118) without :: sanitization, while api_err on the preceding line IS sanitized (api_err_safe="${api_err_safe//::/_}"). GitHub usernames are restricted to [a-zA-Z0-9-] and cannot contain ::, so exploitation is structurally impossible. This is a defense-in-depth consistency gap, not a vulnerability.
    Remediation: Apply ${COMMENT_USER_LOGIN//::/_} sanitization for consistency with the existing api_err_safe pattern.

  • [edge-case] .github/workflows/fullsend.yaml:54 — The dispatch job’s if: condition uses !contains(github.event.comment.body, '/fs-stop') to skip dispatch when a stop command is present. Since contains() does substring matching, a multi-line comment where line 1 is a legitimate slash command (e.g., /fs-review) but a later line mentions /fs-stop would suppress dispatch for the entire comment, silently dropping the legitimate command. The PR author acknowledges this is "intentionally coarse" (see YAML comments).

  • [edge-case] .github/workflows/fullsend.yaml:81 — The stop-agent job-level if: uses contains() which matches any comment containing the substring /fs-stop anywhere. This is intentionally documented as a coarse filter with exact matching deferred to the script, which exits cleanly for non-matching commands. Security impact is minimal: the job runs but takes no action on false positives, and the authorization check runs before any mutation.

  • [user-experience-complexity] .github/scripts/stop-agent.sh:51 — Cross-context label application: script allows /fs-stop fix on issues (where fix doesn’t auto-trigger) and warns "has no effect on this item type." This creates potential label pollution but the warning is clearly surfaced to the user.

  • [error-handling-idiom] .github/scripts/stop-agent.sh:105 — Error message sanitization uses piped tr commands (lines 105–106: tr -d '\r' then tr '\n' ' ') while the FIRST variable parsing (line 29) uses a different pipeline style (sed | head | sed | tr). Minor stylistic inconsistency within the script.

  • [scope-authorization-gap] docs/ADRs/0086-fs-stop-agent-and-no-agent-labels.md:28 — Scope reduction (in-flight cancellation deferred) is documented in the PR body and ADR 0086 Decision docs: add agent infrastructure problem document #5, which cross-references Add /fs-cancel slash command to let humans stop in-flight agent runs #5445. A brief rationale in the ADR Context section would clarify the deferral for future readers.
    Remediation: Add a sentence to the ADR Context section explaining the deferral.

  • [missing-doc] docs/glossary.md:197 — The "Slash Command" glossary entry now includes /fs-stop and explains control commands, but still omits /fs-fix-stop. Users encountering /fs-fix-stop (mentioned in agent docs and supported by the code) won’t find it in the glossary’s example list.
    Remediation: Add /fs-fix-stop to the example list.

Previous run (2)

Review

Findings

Medium

  • [protected-path] .github/scripts/stop-agent.sh, .github/workflows/fullsend.yaml, .github/workflows/reusable-dispatch.yml — PR modifies files under protected paths (.github/). The PR links to issue Add /fs-stop <agent> slash command with in-flight cancellation #5650 and explains the rationale for these changes (generalized /fs-stop command with dispatch-side label enforcement). Human approval is always required for protected-path changes, regardless of context.

  • [authorization-policy-coherence] docs/ADRs/0086-fs-stop-agent-and-no-agent-labels.md:47 — Authorization asymmetry: issue/PR authors can stop fix (via /fs-stop fix or /fs-fix-stop) but cannot stop review, despite both being mutations triggered by author actions. ADR 0086 Decision Use AI to help formalise intent after rapid local prototyping #4 restricts the author escape hatch to fix-only with rationale "authors cannot unilaterally suppress security-relevant auto-gates." The asymmetry is defensible (review is a security gate; fix pushes code to the author's branch), but ADR 0086 does not articulate this distinction directly, leaving the policy rationale incomplete.
    Remediation: Document in ADR 0086 why review differs from fix (e.g., "review is external feedback / security gate; fix is self-mutation to the author's branch").

Low

  • [scope-authorization-gap] docs/ADRs/0086-fs-stop-agent-and-no-agent-labels.md:50 — Scope reduction (in-flight cancellation deferred) is documented in the PR body and ADR 0086 Decision docs: add agent infrastructure problem document #5, which cross-references Add /fs-cancel slash command to let humans stop in-flight agent runs #5445. A brief rationale in the ADR Context section would clarify the deferral for future readers.
    Remediation: Add a sentence to the ADR Context section explaining the deferral.

  • [GHA workflow command injection] .github/scripts/stop-agent.sh:109 — COMMENT_USER_LOGIN is interpolated into ::warning:: workflow commands without :: sanitization, while api_err on the preceding line IS sanitized (api_err_safe="${api_err_safe//::/_}"). GitHub usernames are restricted to [a-zA-Z0-9-] and cannot contain ::, so exploitation is structurally impossible. This is a defense-in-depth consistency gap, not a vulnerability.
    Remediation: Apply ${COMMENT_USER_LOGIN//::/_} sanitization for consistency with the existing api_err_safe pattern.

  • [edge-case] .github/workflows/fullsend.yaml:242 — The dispatch job's if: condition uses !contains(github.event.comment.body, '/fs-stop') to skip dispatch when a stop command is present. Since contains() does substring matching, a multi-line comment where line 1 is a legitimate slash command (e.g., /fs-review) but a later line mentions /fs-stop would suppress dispatch for the entire comment, silently dropping the legitimate command. The PR author acknowledges this is "intentionally coarse" (see YAML comments).

  • [edge-case] .github/workflows/fullsend.yaml:269 — The stop-agent job-level if: uses contains() which matches any comment containing the substring /fs-stop anywhere. This is intentionally documented as a coarse filter with exact matching deferred to the script, which exits cleanly for non-matching commands. Security impact is minimal: the job runs but takes no action on false positives, and the authorization check runs before any mutation.

  • [user-experience-complexity] .github/scripts/stop-agent.sh:51 — Cross-context label application: script allows /fs-stop fix on issues (where fix doesn't auto-trigger) and warns "has no effect on this item type." This creates potential label pollution but the warning is clearly surfaced to the user.

  • [missing-doc] docs/glossary.md:197 — The "Slash Command" glossary entry now includes /fs-stop and explains control commands, but still omits /fs-fix-stop. Users encountering /fs-fix-stop (mentioned in agent docs and supported by the code) won't find it in the glossary's example list.
    Remediation: Add /fs-fix-stop to the example list.

Previous run (3)

Review

Findings

Medium

  • [protected-path] .github/scripts/stop-agent.sh, .github/workflows/fullsend.yaml, .github/workflows/reusable-dispatch.yml — PR modifies files under protected paths (.github/). The PR links to issue Add /fs-stop <agent> slash command with in-flight cancellation #5650 and explains the rationale for these changes (generalized /fs-stop command with dispatch-side label enforcement). Human approval is always required for protected-path changes, regardless of context.

Low

  • [edge-case] .github/workflows/fullsend.yaml:73 — The dispatch job's if: condition uses !contains(github.event.comment.body, '/fs-stop') to skip dispatch when a stop command is present. Since contains() does substring matching, a multi-line comment where line 1 is a legitimate slash command (e.g., /fs-review) but a later line mentions /fs-stop would suppress dispatch for the entire comment, silently dropping the legitimate command. The PR author acknowledges this is "intentionally coarse" (see YAML comments). Practical risk is very low. See also: [Overly broad job trigger] finding at line 228.

  • [Overly broad job trigger] .github/workflows/fullsend.yaml:228 — The stop-agent job-level if: uses contains() which matches any comment containing the substring /fs-stop anywhere. This is intentionally documented as a coarse filter with exact matching deferred to the script, which exits cleanly for non-matching commands. Security impact is minimal: the job runs but takes no action on false positives, and the authorization check runs before any mutation. See also: [edge-case] finding at line 73.

  • [missing-doc] docs/glossary.md:197 — The "Slash Command" glossary entry now includes /fs-stop and explains control commands, but still omits /fs-fix-stop. Users encountering /fs-fix-stop (mentioned in agent docs and supported by the code) won't find it in the glossary's example list.
    Remediation: Add /fs-fix-stop to the example list.

Previous run (4)

Review

Findings

Medium

  • [protected-path] .github/scripts/stop-agent.sh, .github/workflows/fullsend.yaml, .github/workflows/reusable-dispatch.yml — PR modifies files under protected paths (.github/). The PR links to issue Add /fs-stop <agent> slash command with in-flight cancellation #5650 and explains the rationale for these changes (generalized /fs-stop command with dispatch-side label enforcement). Human approval is always required for protected-path changes, regardless of context.

  • [logic-error] internal/scaffold/fullsend-repo/scripts/reconcile-repos.sh — The unenrollment flow (Phase 2) deletes only the shim workflow (.github/workflows/fullsend.yaml) but does not delete the newly added stop-agent script (.github/scripts/stop-agent.sh). Enrollment writes both files via write_shim_to_branch_from_default, but Phase 2 only issues a single DELETE for SHIM_PATH. The orphaned script is inert (only invoked by the deleted shim) but the asymmetry should be addressed.
    Remediation: After deleting the shim workflow, also delete STOP_AGENT_PATH, or use the Git tree API to remove both files atomically.

  • [missing-doc] docs/glossary.md:197 — The "Slash Command" glossary entry lists /fs-triage, /fs-code, /fs-review as examples but does not include the new /fs-stop command or /fs-fix-stop. The description also states commands "manually trigger an agent workflow," but /fs-stop suppresses auto-triggers rather than triggering a workflow.
    Remediation: Add /fs-stop to the example list and update the description to cover both trigger and control commands.

Low

  • [edge-case] .github/workflows/fullsend.yaml — The dispatch job's if: condition uses !contains(github.event.comment.body, '/fs-stop') to skip dispatch when a stop command is present. Since contains() does substring matching, a multi-line comment where line 1 is a legitimate slash command (e.g., /fs-review) but a later line mentions /fs-stop would suppress dispatch for the entire comment, silently dropping the legitimate command. The PR author acknowledges this is "intentionally coarse" (see the YAML comment). Practical risk is very low — /fs-stop is unlikely to appear as a natural-language substring.

  • [GHA workflow command injection] .github/scripts/stop-agent.sh:105 — The ::warning:: workflow command interpolates $(cat "${api_err}") (API error output) without sanitizing :: sequences. While ${COMMENT_USER_LOGIN} is constrained by GitHub to alphanumeric+hyphen (cannot contain ::), the API error output could contain arbitrary server-returned text. The SAFE_CMD pattern (${CMD//::/_}) is applied on line 34 but not to this interpolation. Risk is low — exploiting this requires controlling the GitHub API error response content.
    Remediation: Apply ${VAR//::/_} sanitization to the API error output before interpolating into the ::warning:: command.

Previous run (5)

Review

Findings

Medium

  • [protected-path] .github/scripts/stop-agent.sh, .github/workflows/fullsend.yaml, .github/workflows/reusable-dispatch.yml — PR modifies files under protected paths (.github/). The PR links to issue Add /fs-stop <agent> slash command with in-flight cancellation #5650 and explains the rationale for these changes (generalized /fs-stop command with dispatch-side label enforcement). Human approval is always required for protected-path changes, regardless of context.

Low

  • [edge-case] .github/workflows/fullsend.yaml — The dispatch job's if: condition uses !contains(github.event.comment.body, '/fs-stop') to skip dispatch when a stop command is present. Since contains() does substring matching, a multi-line comment where line 1 is a legitimate slash command (e.g., /fs-review) but a later line mentions /fs-stop would suppress dispatch for the entire comment, silently dropping the legitimate command. The PR author acknowledges this is "intentionally coarse" (see the YAML comment). Practical risk is very low — /fs-stop is unlikely to appear as a natural-language substring.

  • [GHA workflow command injection] .github/scripts/stop-agent.sh:44 — The ::warning:: workflow command interpolates $(cat "${api_err}") (API error output) without sanitizing :: sequences. While ${COMMENT_USER_LOGIN} is constrained by GitHub to alphanumeric+hyphen (cannot contain ::), the API error output could contain arbitrary server-returned text. The else branch at line 111 correctly uses SAFE_CMD="${CMD//::/_}", but the reachable authorization-failure paths at lines 44/48/56 lack equivalent sanitization for their interpolated values. Risk is low — exploiting this requires controlling the GitHub API error response content.
    Remediation: Apply ${VAR//::/_} sanitization to the API error output before interpolating into the ::warning:: command on line 44.

Previous run (6)

Review

Findings

Medium

  • [protected-path] .github/scripts/stop-agent.sh, .github/workflows/fullsend.yaml, .github/workflows/reusable-dispatch.yml — PR modifies files under protected paths (.github/). The PR links to issue Add /fs-stop <agent> slash command with in-flight cancellation #5650 and explains the rationale for these changes (generalized /fs-stop command with dispatch-side label enforcement). Human approval is always required for protected-path changes, regardless of context.

Low

  • [edge-case] .github/workflows/fullsend.yaml — The dispatch job's if: condition uses !contains(github.event.comment.body, '/fs-stop') to skip dispatch when a stop command is present. Since contains() does substring matching, a multi-line comment where line 1 is a legitimate slash command (e.g., /fs-review) but a later line mentions /fs-stop would suppress dispatch for the entire comment, silently dropping the legitimate command. The PR author acknowledges this is "intentionally coarse" (see the YAML comment). Practical risk is very low — /fs-stop is unlikely to appear as a natural-language substring.

  • [GHA workflow command injection] .github/scripts/stop-agent.sh:44 — The ::warning:: workflow command interpolates $(cat "${api_err}") (API error output) without sanitizing :: sequences. While ${COMMENT_USER_LOGIN} is constrained by GitHub to alphanumeric+hyphen (cannot contain ::), the API error output could contain arbitrary server-returned text. The else branch at line 111 correctly uses SAFE_CMD="${CMD//::/_}", but the reachable authorization-failure paths at lines 44/48/56 lack equivalent sanitization for their interpolated values. Risk is low — exploiting this requires controlling the GitHub API error response content.
    Remediation: Apply ${VAR//::/_} sanitization to the API error output before interpolating into the ::warning:: command on line 44.

Previous run (7)

Review

Findings

Medium

  • [protected-path] .github/workflows/fullsend.yaml, .github/workflows/reusable-dispatch.yml — PR modifies files under protected paths (.github/). The PR links to issue Add /fs-stop <agent> slash command with in-flight cancellation #5650 and explains the rationale for these changes (generalized stop-agent command with dispatch-side label enforcement). Human approval is always required for protected-path changes, regardless of context.

  • [scope-alignment] .github/workflows/reusable-dispatch.yml — The PR implements dispatch-side enforcement of fullsend-no-* labels in bash (adding ! has_label checks to all auto-trigger paths), which issue Add /fs-stop <agent> slash command with in-flight cancellation #5650 explicitly excluded from scope. The issue body states: "Dispatch-side enforcement of fullsend-no-{agent} labels... belongs in the per-agent CEL trigger ports (Epic: ADR 0061 — per-repo harness CEL dispatch #2888)" and "adding more bash label guards to reusable-dispatch.yml would be throwaway work." The PR adds these guards as a pragmatic choice (labels without enforcement have no effect), but the scope deviation should be documented in the issue.
    Remediation: Add a comment to issue Add /fs-stop <agent> slash command with in-flight cancellation #5650 documenting the decision to implement bash enforcement now rather than defer to CEL, and update the issue's "What this issue does NOT cover" section accordingly.

Low

  • [GHA workflow command injection] .github/workflows/fullsend.yaml — The else branch interpolates ${CMD} into a ::notice:: workflow command without sanitizing :: sequences. This branch is effectively unreachable at runtime: the job-level if: constrains COMMENT_BODY to start with /fs-stop or /fs-fix-stop, and CMD (extracted via awk '{print $1}') will always match one of the if/elifbranches above theelse. Risk is negligible, but defense-in-depth suggests sanitizing: ${CMD//::/_}`.

Labels: PR implements a new /fs-stop feature affecting dispatch routing, CI workflows, and documentation.

fullsend-ai-review[bot]

This comment was marked as outdated.

@fullsend-ai-review fullsend-ai-review Bot added requires-manual-review Review requires human judgment type/feature New capability request component/dispatch Workflow dispatch and triggers component/ci CI pipelines and checks component/docs User-facing documentation labels Aug 5, 2026

@waynesun09 waynesun09 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review-only sweep — two additional findings not covered by existing comments on this PR.

Comment thread .github/workflows/fullsend.yaml
Comment thread internal/scaffold/fullsend-repo/.github/workflows/dispatch.yml Outdated
@ascerra

ascerra commented Aug 5, 2026

Copy link
Copy Markdown
Contributor Author

Addressed the review-agent findings on head 44e5cbbe:

@fullsend-ai-review

fullsend-ai-review Bot commented Aug 5, 2026

Copy link
Copy Markdown

🤖 Finished Review · ✅ Success · Started 4:10 PM UTC · Completed 4:32 PM UTC
Commit: 44e5cbb · View workflow run →

fullsend-ai-review[bot]

This comment was marked as outdated.

@waynesun09 waynesun09 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review-only sweep — additional findings not covered by existing comments on this PR.

HIGH: reconcile-repos.sh drift detection never compares stop-agent.sh content, so future script fixes won't propagate to enrolled repos (internal/scaffold/fullsend-repo/scripts/reconcile-repos.sh, around the enroll/update comparison loop — not attachable inline since that region falls outside this PR's diff hunks)

The enroll/update loop fetches only .github/workflows/fullsend.yaml (SHIM_PATH) from the remote repo, computes REMOTE_MANAGED/EXPECTED_MANAGED via managed_content_b64, and if they match prints "already enrolled (shim up to date)" and skips. STOP_AGENT_SCRIPT/STOP_AGENT_PATH (defined near the top of the file) are used only for a local-file existence check and to build the git tree in write_shim_to_branch_from_default when a write actually happens — there is no gh api repos/$ORG/$REPO/contents/$STOP_AGENT_PATH fetch or comparison anywhere in the file.

Once every enrolled repo's shim YAML converges to this PR's content (so the YAML comparison passes), this script will report every repo as "up to date" forever, even if .github/scripts/stop-agent.sh is edited later (e.g. a security fix analogous to issue #5421, which is precisely the class of authorization bug this script's logic guards against). Enrolled repos would silently keep running the stale/vulnerable script with no update PR ever generated.

Suggestion: fetch the deployed .github/scripts/stop-agent.sh via gh api repos/$ORG/$REPO/contents/$STOP_AGENT_PATH and include its content in the drift comparison (same "managed content vs expected content" pattern already used for the shim YAML), so a stop-agent.sh-only change is also detected as drift requiring an update PR.

Remaining findings are posted as inline comments on the diff.

Comment thread internal/scaffold/scaffold_test.go
Comment thread .github/scripts/stop-agent.sh Outdated
Comment thread .github/scripts/stop-agent.sh Outdated
Comment thread .github/scripts/stop-agent.sh Outdated
Comment thread .github/workflows/fullsend.yaml
@ascerra
ascerra force-pushed the feat/fs-stop-agent branch from 44e5cbb to 3ea4ea5 Compare August 6, 2026 11:16
@ascerra

ascerra commented Aug 6, 2026

Copy link
Copy Markdown
Contributor Author

@waynesun09 addressed your second review sweep on head 3ea4ea5e (rebased onto latest main):

Inline

  • Script content parity in TestManagedShimStopAgentNotStale
  • Author hatch restricted to /fs-stop fix / /fs-fix-stop only (write required for review/etc.)
  • Leading blank lines skipped before parse
  • Cross-context confirmation no longer overstates enforcement
  • Checkout pinned to github.event.repository.default_branch

Review-body HIGH (reconcile drift)

  • reconcile-repos.sh now fetches .github/scripts/stop-agent.sh and treats script-only drift (or a missing script) as stale, opening/updating the enrollment PR the same way shim YAML drift does.

@fullsend-ai-review

fullsend-ai-review Bot commented Aug 6, 2026

Copy link
Copy Markdown

🤖 Finished Review · ✅ Success · Started 11:17 AM UTC · Completed 11:37 AM UTC
Commit: 3ea4ea5 · View workflow run →

fullsend-ai-review[bot]

This comment was marked as outdated.

@waynesun09 waynesun09 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Additional finding not anchorable to a diff line (outside the changed hunks in this PR):

MEDIUM: Unenrollment (Phase 2) never deletes stop-agent.sh, leaving it orphaned in disconnected reposinternal/scaffold/fullsend-repo/scripts/reconcile-repos.sh, around line 594

This PR's write_shim_to_branch_from_default() now writes both SHIM_PATH (.github/workflows/fullsend.yaml) and the new STOP_AGENT_PATH (.github/scripts/stop-agent.sh) in one tree commit on enroll/update, and drift detection now also compares stop-agent.sh content. However, the unenroll/disable block only checks for and DELETEs SHIM_PATHSTOP_AGENT_PATH is never referenced anywhere in that block (confirmed the unenroll section is untouched by this PR's diff). After a repo is disabled in config.yaml, it keeps a dangling .github/scripts/stop-agent.sh even though the PR's own unenroll PR body text says the repo "will no longer dispatch events to the fullsend agent pipeline." No test in reconcile-repos-test.sh covers removal of stop-agent.sh on unenroll either.

Suggestion: Extend the unenroll block to also fetch the SHA of and DELETE .github/scripts/stop-agent.sh (mirroring the SHIM_PATH delete, or via a shared delete-file helper), guarding for repos enrolled before this PR merged (script may not exist yet on their branch). Add a reconcile-repos-test.sh case asserting the script is removed alongside the shim on unenroll.

Comment thread docs/ADRs/0034-centralized-shim-routing-via-dispatch.md Outdated
Comment thread docs/agents/fix.md Outdated
Comment thread .github/scripts/stop-agent.sh
@ascerra
ascerra force-pushed the feat/fs-stop-agent branch from 3ea4ea5 to 4c0ad13 Compare August 6, 2026 15:22
ascerra and others added 6 commits August 9, 2026 09:14
Extract stop-agent bash into a shared script, skip dispatch for stop
comments, tolerate leading whitespace, guard mktemp failures, sanitize
workflow notices, and add bugfix-workflow prerequisites.

Signed-off-by: Adam Scerra <ascerra@redhat.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Restrict author escape hatch to fix-only, skip leading blank lines,
clarify cross-context messaging, pin checkout to default_branch, assert
script content parity, and detect stop-agent.sh drift in reconcile.

Signed-off-by: Adam Scerra <ascerra@redhat.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Add ADR 0086 for stop-agent generalization, restore ADR 0034 Decision
prose to an annotation, delete stop-agent.sh on unenroll, fix docs, and
document the fix-only author escape hatch on #5650.

Signed-off-by: Adam Scerra <ascerra@redhat.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Document that dispatch still takes the literal first comment line,
give stop-agent unenroll its own commit message, and cover
/fs-fix-stop on issues in the runtime auth tests.

Signed-off-by: Adam Scerra <ascerra@redhat.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Signed-off-by: Adam Scerra <ascerra@redhat.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Treat unenroll as complete only when both the shim and stop-agent.sh
are gone, and stop persisting credentials on the stop-agent checkout.

Signed-off-by: Adam Scerra <ascerra@redhat.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
@ascerra
ascerra force-pushed the feat/fs-stop-agent branch from 865e754 to 8c73c1c Compare August 9, 2026 13:16
@fullsend-ai-review

fullsend-ai-review Bot commented Aug 9, 2026

Copy link
Copy Markdown

🤖 Review · ⚠️ Cancelled · Started 1:17 PM UTC · Ended 1:19 PM UTC

Commit: 8c73c1c · View workflow run →

Fold fullsend-no-* gates into existing conditions instead of raising
lint-workflow-size past main's 610-line limit.

Signed-off-by: Adam Scerra <ascerra@redhat.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
@fullsend-ai-review

fullsend-ai-review Bot commented Aug 9, 2026

Copy link
Copy Markdown

🤖 Review · ⚠️ Cancelled · Started 1:20 PM UTC · Ended 1:33 PM UTC

Commit: 005304a · View workflow run →

Bring the branch up to date with the base branch.

Signed-off-by: Adam Scerra <ascerra@redhat.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
@fullsend-ai-review

fullsend-ai-review Bot commented Aug 9, 2026

Copy link
Copy Markdown

🤖 Finished Review · ✅ Success · Started 1:34 PM UTC · Completed 1:48 PM UTC

Commit: f63613c · View workflow run →

Bring the branch up to date with the base branch.
@fullsend-ai-review

fullsend-ai-review Bot commented Aug 10, 2026

Copy link
Copy Markdown

🤖 Finished Review · ✅ Success · Started 10:33 AM UTC · Completed 10:51 AM UTC

Commit: 77c6ec2 · View workflow run →

fullsend-ai-review[bot]

This comment was marked as outdated.

Clarify author-hatch and cancel-deferral in ADR 0086, sanitize
COMMENT_USER_LOGIN in workflow commands, and document /fs-fix-stop.

Signed-off-by: Adam Scerra <ascerra@redhat.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
@fullsend-ai-review

fullsend-ai-review Bot commented Aug 10, 2026

Copy link
Copy Markdown

🤖 Finished Review · ✅ Success · Started 10:59 AM UTC · Completed 11:16 AM UTC

Commit: 2dc6384 · View workflow run →

@fullsend-ai-review fullsend-ai-review Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See the review comment for full details.

Comment thread .github/workflows/fullsend.yaml
@fullsend-ai-review fullsend-ai-review Bot removed the requires-manual-review Review requires human judgment label Aug 10, 2026
@ascerra

ascerra commented Aug 11, 2026

Copy link
Copy Markdown
Contributor Author

Closing without merge — /fs-stop generalization withdrawn

Closing #5920 unmerged. Team decision 2026-08-10 (notes): do not ship generalized /fs-stop / ADR 0086.

Also close #5650 as not planned / superseded by this direction. Existing /fs-fix-stopfullsend-no-fix (ADR 0034) stays. In-flight cancel remains separate (#5445).

ADR 0086 on this branch must not be treated as accepted policy — it never merged to main.

Why close #5920 — the need is real, this shape is wrong

#5920 solves “skip auto-triggers for an agent on this item” by adding a platform slash command, fullsend-no-* labels, and more bash gates in reusable-dispatch.yml / scaffold dispatch. That fights the direction already decided in ADR 0061 and tracked in epic #2888: move routing off shared bash and onto per-harness CEL trigger expressions evaluated by fullsend dispatch.

Closing this PR is safe because #2888 is the place that capability belongs, and it can cover the same user need without a new /fs-stop surface:

#5920 approach #2888 / ADR 0061 approach
Slash command + managed-workflow bash User applies a label (write permission = auth; no slash ACL matrix)
Hard-coded fullsend-no-{triage,code,review,fix,retro} in platform dispatch Each harness’s CEL trigger includes “label absent” (or equivalent) over NormalizedEvent
Only works for agents we wire into dispatch bash Works for default agents and BYOA — custom harnesses ship their own trigger (building custom agents, BYOA)
Deepens bash router debt ahead of cutover Aligns with #2888 plan: port agents to CEL, then remove bash routing

How skip-via-#2888 should look (outline, not a new ADR)

When default agents are ported under #2888:

  1. Convention: pick a small label vocabulary (e.g. one freeze/stop label, or per-agent skip labels — naming TBD in the CEL port work). Applying/removing the label is the user API; no /fs-stop required.
  2. Auth: ADR 0054 stays a platform gate before CEL. Who may apply labels is already forge permission; we don’t invent a second slash-command authorization ladder (the mess feat(#5650): add /fs-stop to skip auto agent triggers #5920 hit with “author may stop fix, not review”).
  3. Routing: each harness trigger CEL matches the usual event/command/label entry conditions and excludes the skip/freeze label(s). Example shape (illustrative): event has the auto-trigger condition and !"fullsend-stop" in event.labels (exact field paths follow the normative event + agent port PRs in #2888).
  4. BYOA: custom agents opt in by writing the same clause into their harness trigger — no platform dispatch edit (ADR 0061 goal: custom agents as harness files, not bash edits).
  5. Slash on-demand: /fs-review etc. remain expressible in CEL as today planned; skip labels gate auto paths. Manual fullsend run / intentional slash can still be allowed when product wants that (same split feat(#5650): add /fs-stop to skip auto agent triggers #5920 wanted, without bash duplication).
  6. Issue→PR inheritance: design when porting agents under #2888 — don’t ship a slash command first and discover it later (open question from sync).
  7. Not covered by Epic: ADR 0061 — per-repo harness CEL dispatch #2888: killing an already-running job → #5445. Repo-wide disable remains config (customizing agents).

Until CEL cutover, use existing tools: /fs-fix-stop for fix (ADR 0034), repo agent config, and for WIP pin targets close draft PRs / keep branches (agents #11, #86, #87 — work continues on branches).

Other reasons not to land #5920 now

  • Auth asymmetry in the proposed author escape hatch is a smell that the slash-command API is the wrong abstraction.
  • Growing bash fullsend-no-* gates is transitional debt #2888 is explicitly trying to delete after agents are ported.

@ascerra ascerra closed this Aug 11, 2026
@fullsend-ai-retro

fullsend-ai-retro Bot commented Aug 11, 2026

Copy link
Copy Markdown

🤖 Finished Retro · ✅ Success · Started 12:41 AM UTC · Completed 12:49 AM UTC

Commit: 2dc6384 · View workflow run →

@ascerra

ascerra commented Aug 11, 2026

Copy link
Copy Markdown
Contributor Author

Correction: #5650 should not be closed.

#5920 is withdrawn (wrong shape). #5650 remains the place to deliver skip-auto-trigger capability — via label + CEL under #2888 / ADR 0061, not by re-landing this PR’s slash-command + bash gates. #5650 has been reopened.

@fullsend-ai-retro

Copy link
Copy Markdown

Retro: PR #5920/fs-stop agent control feature (closed without merge)

Timeline

PR #5920 (27 files, +1052/−360) added a /fs-stop slash command to let humans apply fullsend-no-* labels that skip auto-triggered agent runs. Over 6 days (Aug 5–10), the review agent ran 9 times (7 success, 2 cancelled). The PR was ultimately closed without merge after a team decision that the approach (bash-based dispatch gating) conflicted with the accepted architectural direction in ADR 0061 / epic #2888 (CEL-based trigger expressions).

Review quality gap

The review agent found only LOW-severity items across all 7 successful reviews — GHA command injection edge cases, glossary gaps, contains() substring matching, and cross-context label UX. Its effective verdict was approval in every cycle.

Human reviewer waynesun09 found 4 HIGH and 10 MEDIUM findings including:

  • HIGH (security): Author escape hatch generalized to let PR authors suppress auto-review — a security gate bypass without requiring write permission
  • HIGH (process): Rewriting an Accepted ADR's Decision section instead of creating a new ADR
  • HIGH (test coverage): TestManagedShimStopAgentNotStale checking file existence but not content parity
  • HIGH (operational): reconcile-repos.sh drift detection never comparing stop-agent.sh content

The review agent's intent-coherence sub-agent reads CLAUDE.md, AGENTS.md, and referenced ADRs, but never flagged the fundamental architectural conflict with ADR 0061. Had this been surfaced in the first review, the team could have evaluated the approach much earlier, potentially saving 6+ review cycles and significant author rework.

Evidence for existing issues (not re-proposed)

  • Security authorization detection (agents #316, fullsend #4066, #2644): The security sub-agent (Opus) missed the author escape hatch allowing PR authors to suppress security-critical review automation. This is a concrete case where tracing authorization flow on permission gate modifications (exactly what fix: improve dispatch token PAT instructions for manual permissions #316 proposes) would have caught a HIGH-severity finding.
  • Severity calibration (fullsend #5264, agents #545): Systematic LOW-only ratings across 7 cycles while a human reviewer found 4 HIGH issues supports the need for concrete impact examples before severity assignment.
  • ADR immutability (agents #404): The agent did not flag rewriting an Accepted ADR's Decision section — a process violation the human reviewer caught immediately.
  • Refactoring plan awareness (agents #542): The intent-coherence sub-agent did not discover that epic Epic: ADR 0061 — per-repo harness CEL dispatch #2888 is actively replacing the dispatch mechanism this PR extended.

Proposals filed

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

component/ci CI pipelines and checks component/dispatch Workflow dispatch and triggers component/docs User-facing documentation type/feature New capability request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants