fix: stop pm tick from re-surfacing finalized issues #15

Merged
erik merged 1 commit from fix/pm-close-no-resurface into main 2026-05-14 10:33:36 +00:00
Member

Summary

Bug: fjx pm close finalized a closed issue, but the next pm tick re-listed it as a closed_candidate. Root cause is the "closed but not yet finalized" window — PR merges auto-closed the issue while the PM ledger still said Status: watching.

Fix follows Option 1 from the issue body:

  • PR convention switches from Closes #<N> to Refs #<N> so PR merges no longer auto-close issues.
  • fjx pm close now closes the issue itself (PATCH state=closed, idempotent) after writing the closed ledger. It is the single canonical close path.
  • linkedIssueFromBody / closesPattern accept Refs in addition to Closes/Fixes/Resolves — legacy PRs and external contributions still link correctly.
  • Belt-and-suspenders: sweep/tick now skip closed issues whose PM ledger already has Status: closed, so finalized issues cannot re-surface even if someone closes manually.

Test plan

  • just validate clean (92 tests pass)
  • linkedIssueFromBody test extended to assert Refs #N matches and that bare #N still doesn't
  • New sweep test asserting closed issues with Status: closed ledger are filtered
  • Reviewer: open + close an issue via fjx pm close <N> end-to-end, confirm subsequent fjx pm tick no longer surfaces it

Refs #5

## Summary Bug: `fjx pm close` finalized a closed issue, but the next `pm tick` re-listed it as a `closed_candidate`. Root cause is the "closed but not yet finalized" window — PR merges auto-closed the issue while the PM ledger still said `Status: watching`. Fix follows Option 1 from the issue body: - PR convention switches from `Closes #<N>` to `Refs #<N>` so PR merges no longer auto-close issues. - `fjx pm close` now closes the issue itself (`PATCH state=closed`, idempotent) after writing the closed ledger. It is the single canonical close path. - `linkedIssueFromBody` / `closesPattern` accept `Refs` in addition to `Closes`/`Fixes`/`Resolves` — legacy PRs and external contributions still link correctly. - Belt-and-suspenders: sweep/tick now skip closed issues whose PM ledger already has `Status: closed`, so finalized issues cannot re-surface even if someone closes manually. ## Test plan - `just validate` clean (92 tests pass) - `linkedIssueFromBody` test extended to assert `Refs #N` matches and that bare `#N` still doesn't - New sweep test asserting closed issues with `Status: closed` ledger are filtered - Reviewer: open + close an issue via `fjx pm close <N>` end-to-end, confirm subsequent `fjx pm tick` no longer surfaces it Refs #5
fix: stop pm tick from re-surfacing finalized issues
All checks were successful
Validate / validate (pull_request) Successful in 21s
a8c79549d1
Closes #5.

PR bodies now reference issues with `Refs #<N>` instead of `Closes #<N>`,
so Forgejo no longer auto-closes the issue on PR merge. The single path
from open to closed is `fjx pm close <N>`, which now also closes the
issue itself (PATCH state=closed) after writing the closed ledger.
This collapses the "closed but not yet finalized" window where a
freshly-closed issue would re-surface as a `closed_candidate` on every
PM tick.

As defense-in-depth for human-closed issues, sweep/tick now filter out
any closed issue whose PM ledger already has `Status: closed`.

`linkedIssueFromBody` and `closesPattern` accept `Refs` in addition to
`Closes`/`Fixes`/`Resolves`, so the existing dev workflow (worktree
branch lookup, `dev done` linked-issue transition) keeps working with
both old and new PR conventions.
erik merged commit ab1d9a82d8 into main 2026-05-14 10:33:36 +00:00
erik deleted branch fix/pm-close-no-resurface 2026-05-14 10:33:37 +00:00
Sign in to join this conversation.
No description provided.