Skip to content

factory: buzz agent PRs say 'Part of', not 'Closes' — merges never close the ticket and reviews silently drop the Spec axis - #191

Merged
ALLiDoizCode merged 4 commits into
mainfrom
sandcastle/issue-170
Aug 13, 2026
Merged

factory: buzz agent PRs say 'Part of', not 'Closes' — merges never close the ticket and reviews silently drop the Spec axis#191
ALLiDoizCode merged 4 commits into
mainfrom
sandcastle/issue-170

Conversation

@toon-backlog-bot

Copy link
Copy Markdown

Fixes the factory's open-PR prompt so agent-opened PRs use a Closes #N closing keyword instead of Part of #N, and adds a guard that fails loudly if an opened PR lacks a closing keyword.

Previously, PRs opened by the buzz agent referenced their issue with Part of #N, which does not trigger GitHub's auto-close on merge — issues stayed open after merge, and review tooling that keys off closing keywords silently dropped the Spec axis. This PR:

  • Adds a shared closing-keyword matcher
  • Fails loud when an opened PR lacks a closing keyword
  • Updates open-pr-prompt.md to require Closes #N, not Part of #N
  • Clarifies the closing-keyword guard

Part of #170

This PR was produced by the sandcastle agent:implement runner and is awaiting human review.

🤖 Generated with Claude Code

sandcastle-agent added 4 commits August 13, 2026 11:30
Extracts the "Closes #n / Fixes #n / Resolves #n" regex into a small
pure module with unit tests, so review-verdict.ts's issue resolver and
the implement runner's new fail-loud PR-body guard share one definition
of what counts as a closing keyword instead of drifting independently.

Task: #170.
Signed-off-by: sandcastle-agent <sandcastle-agent@users.noreply.github.com>
buzz was the sole fleet repo instructing its agent PR-open step to write
"Part of #N" and explicitly forbidding "Closes #N" — correct when a
human merged and closed by hand, but block#285 made the merge itself the
reviewed/gated event, so the ticket now never auto-closes and the
unblock dispatcher never fires. Also fixes review-verdict.ts's
resolveIssueFromPrBody, which resolves the Spec-axis target issue from
that same keyword: buzz PRs always returned null, silently degrading
every review to Standards-only.

resolveIssueFromPrBody now delegates to the shared
matchClosingKeywordIssueNumber (previous commit) instead of duplicating
the regex inline.

Task: #170 AC1, AC2, AC3.
Signed-off-by: sandcastle-agent <sandcastle-agent@users.noreply.github.com>
The open-pr phase is an agent step (open-pr-prompt.md), not deterministic
host code, so its "COMPLETE" cannot be trusted any more than the
existing push/PR-exists checks it sits next to. After confirming the PR
is open, the runner now fetches its body from the host and asserts it
contains a same-repo `Closes #<issue>` (or Fixes/Resolves) via the
shared matchClosingKeywordIssueNumber. A mismatch or missing keyword
fails the job with the same loud, non-zero-exit path as a missing PR,
instead of silently submitting a verdict for a PR that will never close
its ticket.

Verified via a temp-env smoke import (module loads and reaches its
first real env check cleanly) and the pinned @biomejs/biome (no new
findings on the touched lines; two flagged lines are pre-existing and
untouched by this diff). No TypeScript project covers .sandcastle/, so
also spot-checked with `tsc --strict --module nodenext` against a
synthesized @types/node — same residual .mjs-import warning the
pre-existing needs-human-evaluator.mjs import already has, nothing new.

Task: #170 AC4.
Signed-off-by: sandcastle-agent <sandcastle-agent@users.noreply.github.com>
Review refinements, no behaviour change:

- drop the redundant String() around issueNumber (already a string, as
  every other use in this file assumes) and name the matched value
  closesIssueNumber.
- document why the failure path deliberately skips submitFactoryOpsVerdict:
  approving a PR that will not close its ticket would let the auto-merge
  shim re-create the very dead-end the guard prevents.
- cover the same-repo-only rule with a cross-repo test case.

Signed-off-by: sandcastle-agent <sandcastle-agent@users.noreply.github.com>

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

Reviewer verdict: CLEAN — approved by factory-ops

This approval is a machine verdict: it attests that the gate passed and the sandcastle reviewer found nothing blocking (reviewed against issue #170, "factory: buzz agent PRs say Part of, not Closes — merges never close the ticket and reviews silently drop the Spec axis", and its acceptance criteria). It is not human judgement. See FACTORY.md, "What a factory-ops approval attests" (toon-protocol/toon-meta#282).

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant