Skip to content

The link reading asks whether a PR merged, never whether the thing the issue is about exists #2780

Closed

Description

@pm25coder

What the reading decides

scripts/check-issue-links.py gives an open issue a row from its pull-request timeline: does exactly one open PR declare it, and does the issue name that PR back. When no open PR declares it but a merged one does, _declined_detail() prints the remedy. That is the whole model — Refs carries seven fields, every one of them about PRs, and judge_issues(issues, refs_by_issue, stated_by_pr, now) accepts nothing else.

What it prints

Driving the tool's own Refs and _declined_detail — nothing re-implemented — with the shape a release issue ends in, a bump PR having declared it and merged:

#2359 declared `Closes #2358` and is merged, which is the shape of work that landed and was
never closed - either close this issue with the reading that says the work is done, or state
here what it still leaves

For the issue that produced this shape, that advice was false. Its body wrote the release as three stages — bump the version, cut the tag, verify the published assets — and its bump PR carried the closing keyword, so the merge closed the issue while nothing had been published: no tag on the remote, the release workflow never ran, and the host's installed version still read the previous one. The issue had to be reopened by hand and the remaining stages written into the thread.

So the row offered "the reading that says the work is done" for work that had not begun.

Why the sentence cannot do better

It is not careless prose; it is insensitive to the only fact that decides it. Two arms, run against master 7df4a64e:

  • Arm A — the sentence does not vary with the artifact. The Refs above answers that sentence whether or not the release exists. The seven fields are declared_open, declared_merged, declared_abandoned, mentioned_open, mentioned_landed, mentioned_abandoned, reopened_after_merge. None of them can carry a published artifact, so no input to this tool can express "the release was never published".
  • Control — the function is responsive to what it does carry. Flip the one issue-side fact it models, reopened_after_merge=True, and the same function prints a different sentence: "…the merge is what closed it, so the reopen is the reading that says the landing did not finish the work: do not close this issue on that merge, state here what it still leaves".

That pair says the defect is a missing field rather than a broken branch: the sentence moves when its inputs move, and no input exists for the fact that matters here.

What the fix must satisfy

An issue is finished by its artifact, not by a merge that claims it.

  1. Ask the question the issue was opened for. Where an issue's declared completion is a published artifact, the row names that artifact's own reading instead of inferring completion from a merge. For a release, scripts/check-release-published.py vX.Y.Z already answers it and is already run at the end of every release.
  2. Stop offering a close as one of two equal options when the artifact reading says the artifact is absent. With nothing published, the only honest remedy is "state here what it still leaves".
  3. Unmeasurable stays unmeasurable. Where the tool cannot tell what an issue's completion is, it says so — never a merge implying the work landed.
  4. Both directions tested. A release-shaped issue whose declaring PR merged while the release is published (the row may advise the close, naming the artifact reading), and the same issue with the release absent (the row must not).

Scope

The reopening clause already in the tool answers a different case: an issue a person deliberately reopened after a merge. This one is the case nobody reopened, because no reading had yet told them the work was unfinished.

Activity

  1. how2how2how2-arch commented on Nov 9, 2026

    @how2how2how2-arch
    Collaborator

    Handled by #2783

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

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions