Skip to content

fix: prevent accidental GitHub issue closure in publication - #16

Merged
jamesreimer merged 3 commits into
mainfrom
fix/github-issue-closure
Sep 29, 2026
Merged

jamesreimer merged 3 commits into
mainfrom
fix/github-issue-closure

Conversation

@jamesreimer

@jamesreimer jamesreimer commented Sep 29, 2026 •

Copy link
Copy Markdown
Owner

Outcome and authority

Issue #15 remains open pending review/publication. Issue closure on merge: none.

This candidate implements the settled Issue #15 contract, including the accepted MAJOR-1 disposition, head-pinning and identity amendment, and empty-body, declaration-invalidation, and proportionality amendment.

GitHub issue closure can arise from PR relationships or from messages that land on the default branch. Checking PR relationships alone misses commit-message commands. The Publication role now checks every controlling surface, binds the merge to verified inputs, and verifies the landed result. MAJOR-1 is corrected in implementation, pending independent re-review.

Corrected candidate: a9745bd1a0a4a612d185c506ceabc1d192961b85.

Changes and correction mapping

The complete PR changes the three files below. This bounded correction changes only roles/publication.md; the handoff and workflow remain consistent without edits.

File Final behavior
roles/publication.md One safety rule covers handoffs, PR descriptions, commit messages, and merge/squash subjects and bodies. Four manual steps prepare and verify the final gate, bind the merge, and verify the result.
handoffs/review-to-publication.md Retains the single conditional Issue closure on merge declaration and decision authority; discovery covers relationships, commit/landing messages, and resulting issue state.
workflows/reviewed-change.md Concise discovery now covers applicable GitHub issue-closing state across all surfaces, immediately before merge and afterward.
  • Per-surface comparison: resolve targets from PR relationships, controlling commit commands, and final landing commands to canonical full identities. Each surface must be a subset of the declaration. Any undeclared target blocks merge; an authorized target need not appear on every surface.
  • Commit messages: gh pr view <PR> --json commits supplies messages for inspection when they can affect the landing. Their closing targets must be declared. Intermediate messages may be non-controlling for explicitly supplied squash text; merge/rebase methods account for messages they land.
  • Final landing message: exact merge/squash subject and body are established before the gate passes, with closing targets subject to the same subset rule. Methods without a synthesized message check the messages that land instead. The union of all applicable controlling surfaces must equal the declared closures expected from the merge action. For none, each surface and the aggregate must be empty. A missing declared target blocks the gate: correct an authorized surface and rerun, or correct the handoff within authority if explicit post-merge closure is intended. No silent reinterpretation or second declaration is introduced.
  • Identity resolution: supported local, qualified, and issue URL forms resolve to owner/repository#number; valid source prose need not be rewritten. Local commit references resolve against the repository whose default branch receives the commit.
  • Mechanical binding: the squash example passes --match-head-commit, --subject, and --body. Other methods must retain the head guard and message correspondence; inability to bind inputs returns an unresolved condition. No silent generated-message fallback.
  • Invalidation: head changes, including required branch updates, PR-description edits, linked-issue changes, controlling-message changes, final-message changes, and declaration changes invalidate the final gate.
  • Post-merge: identify landed commits, verify action and message correspondence, resolve actual closing references, verify declared issue states, and inspect unexpected effects across all three surfaces. Relevant issues are the union of declaration and surface targets, extended for newly observed landed targets; unrelated repository issues are outside scope. Preserve evidence and route mismatches, closure, or restoration under actual authority.

Lifecycle and role-transfer semantics remain unchanged. Publication is not general closeout, and does not grant issue-closure authority. All additions remain workflow-local and GitHub-conditional, with no auto-close configuration dependency. No source-derived guidance, governing pins, settings, validators, automation, or sibling repositories change. Consumer uptake remains deliberate.

Bounded comparison correction

Implements Planning's subset/aggregate correction. Only the comparison wording and missing-target disposition change from the prior candidate. All previously accepted lifecycle, authority, host-neutrality, identity-resolution, head-pinning, message-binding, invalidation, empty-body, post-merge, and merge-method behavior is preserved.

Manual comparison walkthroughs: a declared target supplied only by the final landing message passes despite empty PR relationships; targets split across surfaces pass when their union equals the declaration; duplicate authorized targets are harmless; an undeclared target or missing aggregate target blocks; none passes only with all surfaces empty. These are prose checks, not new parsers or live merge tests.

Source checks and empty-body finding

Checked GitHub's issue-linking documentation, CLI merge options, and the installed CLI v2.97.0's merge input handling and GraphQL payload.

That version marks an explicitly supplied body as set and sends it even when empty. This establishes client serialization, not live server/landed behavior. The canonical procedure therefore requires confirmation before relying on an empty body and otherwise selects Planning's permitted non-empty verified-body option. Post-merge correspondence remains mandatory. No live merge experiment was performed.

Validation and limitations

Local qualification passed: full .venv/bin/pre-commit run --all-files --show-diff-on-failure, git diff --check, staged whitespace checks, python3 scripts/validate_local.py, all five tests from python3 -m unittest discover -s tests, and npm audit (zero vulnerabilities).

Manual prose walkthroughs covered empty and authorized sets, local/qualified/URL resolution, cross-repository targets with equal issue numbers, undeclared commit commands despite empty PR relationships, explicit squash versus merge/rebase messages, unchecked defaults, moved heads, changed declarations, empty-body uncertainty, disabled auto-close, and landed-message mismatch. These are implementor checks, not independent review or live publication tests. No semantic parser or new automation was added.

Hosted Repository validation: final SUCCESS on exact candidate a9745bd1a0a4a612d185c506ceabc1d192961b85 (run evidence).

PR #16 verification: closingIssuesReferences is empty; the PR description and all three commit subjects/bodies contain no unintended issue-closing command targeting a real issue; issue #15 remains OPEN. The worktree is clean. This is candidate-return evidence; Publication must establish its actual final landing message and repeat the complete final gate before any later authorized merge.

Return to Planning / Primary Author

Stop at this validated immutable candidate. Planning should assess the correction and route independent re-review against MAJOR-1 and all amendments, preserving the evidence above in the project record. Publication remains unauthorized. No merge, release, tag, repository-setting mutation, issue closure, or adjacent issue execution was performed. No scope deviation; the latest Planning amendment was incorporated in addition to the attached correction instructions.

@jamesreimer
jamesreimer merged commit d358c22 into main Sep 29, 2026
1 check passed
@jamesreimer
jamesreimer deleted the fix/github-issue-closure branch September 29, 2026 05:09
@jamesreimer

Copy link
Copy Markdown
Owner Author

Publication completed — return to Planning / Primary Author

Published PR #16 through the explicitly authorized squash path at 2026-09-29T05:08:36Z. Issue #15 remains open. Issue closure on merge: none.

Final gate

  • Verified head: a9745bd1a0a4a612d185c506ceabc1d192961b85.
  • Verified base: d288d778685de43aab306f4609773c460acbef32.
  • Required candidate Repository validation: final SUCCESS; merge state CLEAN.
  • Final PR snapshot: closing relationships empty; PR description contains no unintended closing command.
  • All three intermediate commit messages inspected: no issue-closing commands. They were non-controlling for the selected squash action with explicitly supplied subject/body.
  • Verified landing message contains no closing reference. Every applicable surface and aggregate target set was empty, matching the declaration.
  • The combined gate was the last host-state verification before the merge. The merge used --squash, --match-head-commit with the exact reviewed head, and the exact subject/body below. No bypass or fallback was used.

Subject:

fix: prevent accidental GitHub issue closure in publication

Body:

Add host-conditional GitHub issue-closure safeguards across PR relationships, controlling commit messages, and final landing messages, with head-pinned publication and post-merge resulting-state verification.

Resulting-state evidence

  • PR state: MERGED.
  • Canonical published commit: d358c22438b80053a37cf173c1f652952fb35e2a.
  • Published parent equals the verified base above.
  • Reviewed and published tree IDs both equal e45aca352fda5cfba3a37ab6e25f5e0ca8a10ff8; candidate-to-published git diff --exit-code passed with no differences.
  • Actual landed subject and body match the verified text exactly; no closing reference appeared.
  • Post-merge PR closing relationships remain empty. jamesreimer/agent-workflows#15 remains OPEN, with closedAt: null. No unexpected closure effect was observed on the applicable surfaces or the explicitly protected issue.
  • Published-commit Repository validation: final SUCCESS on the published SHA.
  • Local main was fast-forwarded to the published commit and matches origin/main; worktree clean. Completed PR branch removed locally and remotely; unrelated local branch preserved.

Publication is complete. No unexpected condition or recovery action. No release, tag, settings change, sibling change, or adjacent issue execution was performed. Return control to Planning to assess any remaining issue completion or release decision under separate authority; issue #15 remains open.

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