Drop the claim label when an issue closes #103

Merged
yonlu merged 1 commits from ci/unclaim-on-close into main 2026-08-18 21:57:11 +00:00
Owner

Set-and-forget for the gap #101 exposed: a Closes footer closes the issue and leaves Status/In Progress on it, so #100 was closed and marked as being actively worked on at the same time.

Why the close and not the merge

You could strip the label in the PR. That is a per-PR habit, and habits are precisely what the footer removed — the point of Closes #N is that nobody has to remember anything at merge time.

on: issues: [closed] covers every path an issue can close by: the footer on merge, scripts/issue.sh close, or someone clicking Close in the web UI. Nothing to remember at any of them. Gitea is 1.27.2, so the issues event is available.

What it does

Look the label id up by name, DELETE it from the issue, exit 0 when the label does not exist. The DELETE is idempotent — an issue that never carried the label answers the same as one that did, which is what makes it safe to run on every close rather than only claimed ones.

Verified against the live API: the lookup resolves Status/In Progress to id 39, cross-checked two ways. The YAML parses and the step's shell passes bash -n.

Three things stated in the file rather than discovered later

  • It is not instant. The runner has capacity 1 and is shared with an index build that can hold it for three hours, so a label tweak can queue behind one. Stale for an afternoon beats stale forever, which is the status quo.
  • Reopening does not restore the label. Reopening says the work was not finished, not that somebody is at a keyboard doing it now — the claim gets re-made by whoever picks it up.
  • It is an eighth workflow, so CLAUDE.md's "Seven workflows" count moves with it, and unclaim.yml is described there as housekeeping that gates nothing.

The one thing I could not test

Whether the automatic secrets.GITEA_TOKEN carries issue-write scope in this Gitea. release.yml already uses that token, but for pushing a tag — a different permission. If the DELETE comes back 403, the fix is one line: swap it for secrets.PACKAGE_TOKEN, which is a user PAT and definitely has it.

The test is the merge itself. This PR's footer is Closes #102. If #102 ends up closed and without the label, both mechanisms are confirmed at once. I will check and report either way — and if it 403s, fix it rather than leave a workflow that fails on every close from then on.

The audit stays in CLAUDE.md regardless, because a workflow that silently stops firing is the failure mode this area has already produced once:

./scripts/issue.sh list --state closed --label "Status/In Progress"

Closes #102

Set-and-forget for the gap #101 exposed: a `Closes` footer closes the issue and leaves `Status/In Progress` on it, so #100 was closed and marked as being actively worked on at the same time. ## Why the close and not the merge You could strip the label in the PR. That is a per-PR habit, and habits are precisely what the footer removed — the point of `Closes #N` is that nobody has to remember anything at merge time. `on: issues: [closed]` covers **every** path an issue can close by: the footer on merge, `scripts/issue.sh close`, or someone clicking Close in the web UI. Nothing to remember at any of them. Gitea is 1.27.2, so the `issues` event is available. ## What it does Look the label id up by name, `DELETE` it from the issue, exit 0 when the label does not exist. The `DELETE` is idempotent — an issue that never carried the label answers the same as one that did, which is what makes it safe to run on every close rather than only claimed ones. Verified against the live API: the lookup resolves `Status/In Progress` to id `39`, cross-checked two ways. The YAML parses and the step's shell passes `bash -n`. ## Three things stated in the file rather than discovered later - **It is not instant.** The runner has capacity 1 and is shared with an index build that can hold it for three hours, so a label tweak can queue behind one. Stale for an afternoon beats stale forever, which is the status quo. - **Reopening does not restore the label.** Reopening says the work was not finished, not that somebody is at a keyboard doing it now — the claim gets re-made by whoever picks it up. - **It is an eighth workflow**, so CLAUDE.md's "Seven workflows" count moves with it, and `unclaim.yml` is described there as housekeeping that gates nothing. ## The one thing I could not test Whether the automatic `secrets.GITEA_TOKEN` carries issue-write scope in this Gitea. `release.yml` already uses that token, but for pushing a tag — a different permission. If the `DELETE` comes back 403, the fix is one line: swap it for `secrets.PACKAGE_TOKEN`, which is a user PAT and definitely has it. **The test is the merge itself.** This PR's footer is `Closes #102`. If #102 ends up closed *and* without the label, both mechanisms are confirmed at once. I will check and report either way — and if it 403s, fix it rather than leave a workflow that fails on every close from then on. The audit stays in CLAUDE.md regardless, because a workflow that silently stops firing is the failure mode this area has already produced once: ``` ./scripts/issue.sh list --state closed --label "Status/In Progress" ``` Closes #102
yonlu self-assigned this 2026-08-18 21:36:37 +00:00
yonlu added 1 commit 2026-08-18 21:36:38 +00:00
ci: drop the claim label when an issue closes
CI / check (push) Skipped
CI / e2e (push) Skipped
CI / check (pull_request) Successful in 2m27s
CI / e2e (pull_request) Successful in 6m17s
0c944f2382
A `Closes #N` footer closes the issue on merge and leaves
`Status/In Progress` on it, because Gitea's auto-close touches state
and nothing else. #100 was closed and simultaneously marked as being
actively worked on. `scripts/issue.sh close` does drop the label, and
is exactly the call the footer exists to avoid making.

This hooks the close rather than the merge. Stripping the label in the
PR would work and would be a per-PR habit, which is what the footer
removed in the first place; `issues: [closed]` covers the footer,
issue.sh close and a click in the web UI alike, and asks nothing of
anyone at any of them.

Reopening deliberately does not restore the label: reopening says the
work was not finished, not that somebody is at a keyboard now.

Two costs, both stated in the file rather than discovered later. The
runner has capacity 1 and is shared with an index build that can hold
it for three hours, so this is not instant -- stale for an afternoon
beats stale forever, which is what it was. And it is an eighth
workflow, so CLAUDE.md's count moves with it.

The audit stays, because a workflow that silently stops firing is the
failure mode this area has already produced once:

  ./scripts/issue.sh list --state closed --label "Status/In Progress"

Closes #102
yonlu merged commit e049a71458 into main 2026-08-18 21:57:11 +00:00
Sign in to join this conversation.