Fix #517: PR Close/Reopen #523

Merged
crueber merged 1 commit from fix/issue-517 into main 2026-09-14 16:39:27 +00:00
Owner

Pure client wiring for PR Close/Reopen with the issue-page state badge convention — no backend change (UpdatePR + repo.pulls.update already exist).

What it does (acceptance-mapped):

  • Open PR: Close action + Comment-and-Close for author-or-triage (client mirror of UpdatePR auth, hierarchical ladder so write ⊇ triage); below-triage viewers see the plain composer only.
  • Close sends PUT {state:"closed"}; the mutation site reloads the own thread key (badge flips + closed timeline entry, no full reload) and invalidates pulls windows + repo summary (open_pulls) via new invalidatePullLists (#318 pattern).
  • Closed-unmerged: Reopen under the same rule, badge flips back.
  • Merged: no control (merged wins the badge as Merged/chip-merged since merge stamps StateClosed too); a raced merged-close 409 lands in the error tray via the composer path, never silent.
  • Stream: closed/reopened pull frames ride the existing repo-stream subscription (accept filter runs before invalidateCollab — verified by reading collab.jsx); timeline text already exists (state_changed → closed/reopened).
  • No close-reason chooser: PR state is open|closed only (reason split-button stays issue-only).

Files: web/src/lib/pull-state.js (new pure helpers) + web/test/unit/pull-state-517.test.js (8 tests), web/src/pages/Pull.jsx (badge header + handlers + composer wiring), web/src/lib/data.js (invalidatePullLists), web/src/ui.css (chip-merged), docs/features/03_pull_requests.md (Decisions entry, law 12).

Verification: node --test full unit suite 1159 pass / 0 fail / 3 smoke-skipped (smoke needs a live server; an ambient :8080 occupier flaked one smoke assertion transiently — untouched per instructions); vite + esbuild builds green, new strings confirmed in dist bundle. No new deps. Mobile: header/composer rows are flex-wrap (issue-page pattern), reasoning-only check — shared browser daemon blocks loopback so no live browser drive.

Pure client wiring for PR Close/Reopen with the issue-page state badge convention — no backend change (UpdatePR + repo.pulls.update already exist). What it does (acceptance-mapped): - Open PR: Close action + Comment-and-Close for author-or-triage (client mirror of UpdatePR auth, hierarchical ladder so write ⊇ triage); below-triage viewers see the plain composer only. - Close sends PUT {state:"closed"}; the mutation site reloads the own thread key (badge flips + closed timeline entry, no full reload) and invalidates pulls windows + repo summary (open_pulls) via new invalidatePullLists (#318 pattern). - Closed-unmerged: Reopen under the same rule, badge flips back. - Merged: no control (merged wins the badge as Merged/chip-merged since merge stamps StateClosed too); a raced merged-close 409 lands in the error tray via the composer path, never silent. - Stream: closed/reopened pull frames ride the existing repo-stream subscription (accept filter runs before invalidateCollab — verified by reading collab.jsx); timeline text already exists (state_changed → closed/reopened). - No close-reason chooser: PR state is open|closed only (reason split-button stays issue-only). Files: web/src/lib/pull-state.js (new pure helpers) + web/test/unit/pull-state-517.test.js (8 tests), web/src/pages/Pull.jsx (badge header + handlers + composer wiring), web/src/lib/data.js (invalidatePullLists), web/src/ui.css (chip-merged), docs/features/03_pull_requests.md (Decisions entry, law 12). Verification: node --test full unit suite 1159 pass / 0 fail / 3 smoke-skipped (smoke needs a live server; an ambient :8080 occupier flaked one smoke assertion transiently — untouched per instructions); vite + esbuild builds green, new strings confirmed in dist bundle. No new deps. Mobile: header/composer rows are flex-wrap (issue-page pattern), reasoning-only check — shared browser daemon blocks loopback so no live browser drive.
Sign in to join this conversation.
No description provided.