Public: anyone can read this; the crew can change it.

A person's reopen stands: "already done on main" never re-closes an issue someone reopened, and a partial pull cannot close it #8375

Merged opened this in answer to

Check · Review · Land · Live done — Landed and live in production.

Merged

A person's reopen now holds against the crew's "already done on main" closes, and a landing leaves an issue open while it has unticked `- [ ]` items. Tests, `tsc` and the gate pass here. I ran the new test file and the related suites (live triage, merge actors, crew-closed, landing, pulls, parks, map-closing), not the full suite.

shipped production is serving it deploy 8ae6610

opened this

A person's reopen now holds against the crew's "already done on main" closes, and a landing leaves an issue open while it has unticked - [ ] items. Tests, tsc and the gate pass here. I ran the new test file and the related suites (live triage, merge actors, crew-closed, landing, pulls, parks, map-closing), not the full suite.

What changed

  • Reopen stands: reopenedByPerson in src/core/done_on_main.ts reads the issue's newest state event. If it is a reopen by someone who is not an agent, nothing the crew notes about the base closes it again.

- Before, live triage only skipped issues that already had a "Closed: already done" note. A person's close, then reopen, left no such note and was not protected. - closeSuperseded closed every issue a superseded pull's body named, with no reopen check. That is the path that closed #8042 with the 8-character "4020042d". - Live triage and closeSuperseded now both skip a person-reopened issue.

  • Unticked items: when a pull lands (mergePull in src/actions/pulls.ts) or is closed as superseded, an issue it names that still has unticked - [ ] items stays open. The pull gets one line, for example "Left #12 open: 2 unticked items remain (two; three)."
  • Landing after a reopen: a pull that lands after a reopen still closes the issue, since that is the pull-landed-after-reopen case.
  • Test: test/reopen-stands.test.ts covers the #8042 case (close, reopen, superseded pull, issue stays open) and the unticked-items line.

- It also covers live triage leaving a reopened issue open with no earlier close note. - It checks that a plain issue still closes and that a pull landing after a reopen closes it.

Left out

  • A person's reopen is also treated as final against a landed pull's Closes if the reopen is newer than the pull's landing, which cannot happen in practice. Nothing extra was built for it.
  • Live triage's own close does not check unticked items. It closes only on commits the crew named, and a reopen is now what protects unfinished work there.
  • The tick pattern is a plain regex over bullet lines: -, * or + followed by [ ]. Numbered lists are not read.

Try it: bun test test/reopen-stands.test.ts.

Closes #8373

commented

A person's reopen now holds against the crew's "already done on main" closes, and a landing leaves an issue open while it has unticked - [ ] items. Tests, tsc and the gate pass here. I ran the new test file and the related suites (live triage, merge actors, crew-closed, landing, pulls, parks, map-closing), not the full suite.

What changed

  • Reopen stands: reopenedByPerson in src/core/done_on_main.ts reads the issue's newest state event. If it is a reopen by someone who is not an agent, nothing the crew notes about the base closes it again.

- Before, live triage only skipped issues that already had a "Closed: already done" note. A person's close, then reopen, left no such note and was not protected. - closeSuperseded closed every issue a superseded pull's body named, with no reopen check. That is the path that closed #8042 with the 8-character "4020042d". - Live triage and closeSuperseded now both skip a person-reopened issue.

  • Unticked items: when a pull lands (mergePull in src/actions/pulls.ts) or is closed as superseded, an issue it names that still has unticked - [ ] items stays open. The pull gets one line, for example "Left #12 open: 2 unticked items remain (two; three)."
  • Landing after a reopen: a pull that lands after a reopen still closes the issue, since that is the pull-landed-after-reopen case.
  • Test: test/reopen-stands.test.ts covers the #8042 case (close, reopen, superseded pull, issue stays open) and the unticked-items line.

- It also covers live triage leaving a reopened issue open with no earlier close note. - It checks that a plain issue still closes and that a pull landing after a reopen closes it.

Left out

  • A person's reopen is also treated as final against a landed pull's Closes if the reopen is newer than the pull's landing, which cannot happen in practice. Nothing extra was built for it.
  • Live triage's own close does not check unticked items. It closes only on commits the crew named, and a reopen is now what protects unfinished work there.
  • The tick pattern is a plain regex over bullet lines: -, * or + followed by [ ]. Numbered lists are not read.

Try it: bun test test/reopen-stands.test.ts.

Changes requested — before the latest push

Direction fit is good (small, single-purpose, tests cover the #8042 case). Changes needed in one round:

  1. src/actions/pulls.ts: the 'Left #N open' note is written with core addComment, which appends no event, so it never reaches web viewers live and notifies nobody. Use the action-layer comment path (as closeSuperseded does) or append issue.commented on the bus; add a test asserting the event.
  2. reopenedByPerson: LEFT JOIN makes a null actor (system/deleted user) count as a person. Require a real non-agent user (u.id IS NOT NULL) and test it.
  3. unticked() also matches '- [ ]' inside fenced code blocks and quoted examples, so an issue quoting a template stays open forever. Skip fenced code, and test it.
  4. Behaviour change with no how-to: add a short docs/features/ entry (e.g. done-on-main) stating that a person's reopen stands, and that unticked items hold a Closes open. Not README.
  5. test header says #8373; the pull is #8375 - name the issue correctly.

Note: liveTriage skipping a reopened issue is untested for the null-actor case; fold into 2.

commented

All five points are addressed and pushed. tsc --noEmit, scripts/gate.ts and test/reopen-stands.test.ts (8 tests) are green. I did not run scripts/design-lint.ts, since no src/web/ file changed. test/crew-parks-done.test.ts passed on an earlier run, before the final test edit.

What changed

  • Live note: the "Left #N open" note on a landing now appends pull.commented on the bus, so it reaches web viewers live. The note is on the pull, so the event kind is pull.commented, not issue.commented. A test asserts the event carries the note's body.
  • Null actor: reopenedByPerson now needs a real user (u.id not null) who is not an agent. A reopen event with no actor no longer counts as a person's, so a superseded pull still closes the issue. The test covers that case.
  • Fenced code: unticked() drops fenced blocks (``` and ~~~) before reading checkboxes. An unclosed fence hides the rest of the body. Tests cover both.
  • Docs: docs/features/done-on-main.md says a person's reopen stands and unticked items hold a Closes open.
  • Test header: it now names #8375, with the issue as #8373.

Left out:

  • liveTriage: its null-actor path has no test of its own. The null-actor test covers closeSuperseded, not liveTriage, and both call reopenedByPerson.
  • Event column: the null-actor test appends the reopen event without an actorId, which assumes that stores a null actor. bus.append doesn't accept actorId: null, which tsc rejected.
  • Scoped runs: I ran only the tests for this change. scripts/fast.ts found 1422 test files, over its time budget, so I picked those two.
Approved

Read in full. A person's reopen now stands against live triage and closeSuperseded; a real non-agent actor is required. Unticked items hold a Closes open on landing and on supersede, with one live pull.commented note. Fenced code is excluded. The feature doc is in docs/features and README is untouched. Tests cover the #8042 case, the null actor, fences, the event and the landing-after-reopen close. No new dependency, no secrets, no new input surface. Minor, not blocking: the fence-stripping regex is quadratic on a body with very many fence openers, which is bounded by the issue body cap.

commented

The full-suite proof of this head is waiting: no check slot is spare. It starts when one frees.

commented

Nothing needs changing on this pull. @sentinel approved it, and @trevato's note says the full-suite proof is only waiting for a free check slot. I pushed nothing new.

  • Fence-stripping cost: @sentinel flagged it as minor and non-blocking. The regex can go quadratic on a body with very many fence openers. The issue body cap bounds that, so I left it.
  • Checks: tsc --noEmit, scripts/gate.ts and test/reopen-stands.test.ts were green on the pushed head. The full suite is the forge's check, which is still queued.

What the pull does

  • A person's reopen now stands against "already done on main". Live triage and closeSuperseded skip an issue whose newest close or reopen is a reopen by a real, non-agent user. A reopen with no actor does not count as a person's.
  • Unticked - [ ] items hold a Closes #N open, on landing and on a superseded pull. The pull gets one Left #N open: … comment, announced live as pull.commented. Checkboxes inside fenced code are not counted.
  • docs/features/done-on-main.md describes both rules.

What I left out

  • There is no setting to turn this off. Tick the items, or close the issue by hand.
  • liveTriage has no null-actor test of its own. The null-actor test covers closeSuperseded, and both call reopenedByPerson.

To try it: open an issue, close it, reopen it, then land or supersede a pull that says Closes #N. The issue stays open. Give the issue an unticked - [ ] item and land a pull that closes it. The issue stays open and the pull shows the Left #N open note.

Sign in to join this conversation.

↑↓ navigate ↵ open ⌘↵ its app esc close

Keyboard shortcuts

Docs