Skip to content

An issue closed as not planned still writes an unresolvable moderation row, because the fold never reads stateReason #232

Description

@Nitjsefnie

Description

Closing a priced issue as not planned — invalid, duplicate, wontfix — writes a NO_CLOSING_PULL_REQUEST row into the moderation queue, exactly as closing it as completed does. The fold cannot tell the two apart, because it never asks.

issuesQuery in src/lib/github/client.ts:680 selects state and not stateReason, and stateReason appears nowhere in src/:

$ git grep -n "stateReason\|state_reason\|NOT_PLANNED" -- 'src/**/*.ts'
(no matches)

So repository-fold.ts:392 sees only issue.state !== "CLOSED", and at line 411 records the closure whenever no merged closing pull request was selected and the evidence window is reachable. A deliberate "this was never going to be done" closure produces the same row as an accidental hand-closure.

Live example. daedalus issue 632 was closed not_planned with the invalid label at 2026-09-07T18:31:55Z. The fold that ran 20:32:57–20:35:49 local wrote its row anyway:

 issue_number |          kind           |          created_at
--------------+-------------------------+-------------------------------
          632 | NO_CLOSING_PULL_REQUEST | 2026-09-07 20:35:49.553307+02

That row cannot be resolved by anyone, which is #174: the queue routes it for correction and correction is the one thing its audience cannot perform. Unlike a rejected settlement, there is nothing to correct — the issue was correctly closed and correctly has no pull request.

What makes this hard to notice is that the fold only materialises issues carrying an opening catalog label — 565 issues in the database, none without one. So an unpriced issue closed by hand never enters the fold and leaves no trace. Issues 191 and 215 were both closed not planned and left nothing, and both were unpriced; that coincidence is why this repository's own working notes record "closing not_planned does not write the row" as though the state reason were the discriminator. It is not. The discriminator is whether the issue was ever priced.

Expected Behavior

An issue closed as not planned records no unwritable closure. Nothing was left undone, so there is nothing to route to a moderator.

An issue closed as completed with no merged closing pull request still records one, because that is a real gap: work was declared done and the ledger cannot say by whom or for how much.

Reproduction Steps

  1. Take an open issue carrying an opening catalog label.
  2. Close it as not planned — gh issue close <n> --reason "not planned".
  3. Let reconciliation run.
  4. Observe a NO_CLOSING_PULL_REQUEST row for it in unwritable_closures, indistinguishable from one written for a completed closure.

Environment / Context

main at f7a8e2c. Related: #174 is why the resulting row is permanent — the moderation queue offers a correction its audience cannot perform, and for this kind there is not even a correction to make.

Discovered During

Auditing why the daedalus rejected-evidence queue held 204 rows against 203 granted corrections, on 2026-09-07. The uncovered row was 632, which an automated correction pass had correctly declined to touch because it is not a rejected settlement.

Suggested Fix

Unverified. Add stateReason to issuesQuery, carry it through the snapshot, and skip the closure record when it is NOT_PLANNED. The fold already has the shape for it — the record is gated on evidenceWindowReachable at the same site, so this is one more condition rather than a new path.

Worth deciding in the same change what happens to rows already written for not-planned closures, since the fold recomputes fully: if the row is simply no longer produced, existing ones disappear on the next pass without a migration.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    area: ledgerScoring, settlement, calibration and moderationbugSomething isn't workingoffered: smallOpening catalog · comparison 3 · reserve 3

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions