Skip to content

fix(worker): refuse merged or closed pull requests in worker target and block instead of release - #35

Merged
bketelsen merged 1 commit into
mainfrom
fix/target-merged-pull-request
Aug 25, 2026
Merged

fix(worker): refuse merged or closed pull requests in worker target and block instead of release#35
bketelsen merged 1 commit into
mainfrom
fix/target-merged-pull-request

Conversation

@bketelsen

Copy link
Copy Markdown
Contributor

Summary

A pr-review-fix item bound to frostyard/core#118 was requeued by an operator after the pull request had merged (23:57Z merge, 00:10Z requeue). The head branch was deleted on merge, so worker target failed inside git fetch with an opaque "fetch bound pull-request head" error. The worker then retried the helper from other directories (collecting "not the workspace root" / "not a Git working tree" / "not on its Cockpit branch" refusals that were all self-inflicted), released the item, and the next campaign worker repeated the whole cycle every tick — three workers in ten minutes on one undeliverable item.

This PR:

  • internal/worker/target.go — the pull-request projection now carries state and merged; PrepareTarget refuses a merged or closed pull request with an explicit ErrConflict before fetching, and a failed fetch now names the head branch, its repository, and Git's last output line (bounded) so the cause is visible without retrying.
  • internal/worker/worker.go — implementer and reviewer launch prompts: when the helper reports the bound PR is merged or closed, call block_work with that exact reason instead of releasing (release just re-serves it); run the helper only from the workspace root; a refusal is final — do not retry from other directories or bypass with plain git.
  • docs/specs/managed-workers.md — the target contract states the new refusal and the block-not-release rule.
  • Tests: merged and closed refusals happen before any fetch and record no target; fetch-failure detail is surfaced; prompt assertions extended.

Snowcat-side prevention (refuse requeue / auto-cancel PR-bound items on merged or closed PRs) is filed as frostyard/snowcat#252; this change only stops each occurrence from being expensive and opaque.

Risk tier

Risk tier: high — internal/worker/ is review-required at minimum tier high under policies/agent-governance.json. The change adds a refusal path and diagnostic text; it grants no new authority, still fetches only the credential-free https://github.com/<owner>/<repo>.git URL, and touches no credential projection or lifecycle code.

Boundary check

  • Snowcat's MCP contract and databases remain untouched
  • No provider, MCP, GitHub, or lease credential enters args, logs, or state (the surfaced Git line comes from a credential-free fetch and is capped at 200 characters)
  • Writable terminal surfaces remain loopback-only
  • Cleanup remains an explicit operator action

Docs housekeeping

  • New docs started from their category TEMPLATE.md (none added)
  • Every new canonical doc is indexed in docs/README.md (none added)
  • ADR, design, spec, and plan links run both ways (unchanged)
  • Conformance aliases in ADR-0007 were not edited as content

Verification

  • make ci
  • Workflow changes pass actionlint (no workflow changes)
  • Every action is SHA-pinned with a version comment and checkout disables persisted credentials (no workflow changes)

🤖 Generated with Claude Code

…nd block instead of release

A pr-review-fix item bound to frostyard/core#118 was requeued after the pull
request merged. Its head branch had been deleted on merge, so `worker target`
failed inside `git fetch` with an opaque "fetch failure"; the worker retried
the helper from other directories (producing unrelated refusals), released
the item, and the next worker repeated the cycle every tick.

Inspect the bound pull request's state and merged flag before fetching and
refuse a merged or closed pull request with an explicit conflict. Report the
head branch, repository, and Git's last output line when a fetch does fail.
Tell implementers and reviewers to block_work with that reason rather than
release, to run the helper only from the workspace root, and never to retry
or bypass a refusal. Snowcat-side prevention is frostyard/snowcat#252.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@bketelsen
bketelsen marked this pull request as ready for review August 25, 2026 00:42
@bketelsen
bketelsen added this pull request to the merge queue Aug 25, 2026
Merged via the queue into main with commit 31dea20 Aug 25, 2026
5 checks passed
@bketelsen
bketelsen deleted the fix/target-merged-pull-request branch August 25, 2026 00:48
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