Repository navigation
Run label hygiene when an issue or pull request closes - #1404
Conversation
A status label answers "what is happening right now", so it must not outlive the item. The 19:30Z sweep left up to a day where a closed issue still read as in flight; the close is the moment the label stops being true. The same --apply now also runs on `issues: closed` and on `pull_request_target: closed` -- a `pull_request` run from a fork is read-only, so it could not remove the label it came for. Two tests pin the triggers, the unchanged permissions and the keep-list, including hold. Fixes #1401 Docs-not-needed: workflow trigger plus its tests; no architecture or subsystem ownership change.
|
Verdict: PASS at 162d4bb 写这条之前现读:head 1. 先红后绿(我自己跑)
2. YAML 真解析(两个解析器)
3.
结论: 4. 验收 2/4 = 合入后证据,本 tip 不提供(点名要判的第二条) 正文写的是「After merge I will close one scratch issue … report the 5.
6. 现场缺陷确实存在(复现前提,顺手核了)
低、不阻断(建议处理,都不影响合入)
Ran: $ cd r1404/tip && node --test .github/scripts/label-hygiene.test.mjs # 10/10, exit 0
$ cd r1404/basew && node --test .github/scripts/label-hygiene.test.mjs # base 树 + 新测试: 9 pass / 1 fail, not ok 10 'a closed issue runs the same cleanup'
$ cd r1404/knife1 && node --test .github/scripts/label-hygiene.test.mjs # 两段触发块摘掉: not ok 10, 同一条红
$ cd r1404/knife2 && node --test .github/scripts/label-hygiene.test.mjs # hold 进 STALE_LABELS: not ok 8 + not ok 9, 8 pass / 2 fail
$ cd r1404/tip && node --test ".github/scripts/*.test.mjs" # 540 / 538 pass / 0 fail / 2 skipped
$ cd r1404/base && node --test ".github/scripts/*.test.mjs" # 538 / 536 / 0 / 2
$ node /tmp/yaml1404.mjs head/.github/workflows/label-hygiene.yml base/.github/workflows/label-hygiene.yml knife1/.github/workflows/label-hygiene.yml
$ cd r1404/tip && node .github/scripts/testing-layers.mjs --check # 442 files / 16 workflows, exit 0
$ cmp base/.github/scripts/label-hygiene.mjs head/.github/scripts/label-hygiene.mjs
$ grep -n "GITHUB_EVENT\|process.env" .github/scripts/label-hygiene.mjs
$ grep -n "secrets\." .github/workflows/label-hygiene.yml
$ git diff --no-index --stat base head # 2 files, +35
$ curl GET /repos/ThinkFlowLab/FlyBot/issues/1367 # closed 07:02:40Z, labels still 'agent-pr'Not run: 一次真实 close 事件的 workflow run(trigger 合入前不存在,属合入后验收 2/4,正文已写在 结论: |
Written-by: Dev3
Owner: Dev3
Reviewer: Reviewer
Fixes #1401
Reproduce
On
06bed53b,.github/workflows/label-hygiene.ymlfires only onschedule: 30 19 * * *andworkflow_dispatch, so a status label survives the close until the next sweep — up to 24 hours — and the board reads finished work as in flight. Live sample from the issue:#1367closed07:02:40Zand still carriedagent-pr.grep -n "on:" -A4 .github/workflows/label-hygiene.ymlon06bed53bshows exactly those two triggers.What changed
.github/workflows/label-hygiene.yml(+10): addedissues: types: [closed]andpull_request_target: types: [closed]to the same workflow, with a comment explaining why the PR side ispull_request_target— apull_requestrun from a fork is read-only (gate-check.test.mjsalready pins that rule for#812), so it could not delete the label it was triggered for.schedule,workflow_dispatch,concurrency(group: label-hygiene,cancel-in-progress: false),permissions(contents: read,issues: write,pull-requests: write) and the--applystep are unchanged: same script, same call..github/scripts/label-hygiene.test.mjs(+25): two cases. One closes an item carryinghold+agent-working+bug+area:automationand asserts onlyagent-workingis deleted. One reads the workflow text and pins the two new triggers, the absence of a plainpull_requesttrigger, the retainedschedule/workflow_dispatch, the unchanged permissions, theconcurrencypair, and the single--applystep.Guardrails on the new trigger
actions/checkoutpinsref: mainwithpersist-credentials: false— a literal branch name rather than an expression, so a fork's default branch can never be picked up — and no step readsgithub.event.pull_request.head.*. The script that runs is base.github/scripts/label-hygiene.mjs, unchanged.issues: [closed]andpull_request_target: [closed]both run the singlenode .github/scripts/label-hygiene.mjs --applystep, under the existingconcurrency: { group: label-hygiene, cancel-in-progress: false }, withpermissionsexactlycontents: read,issues: write,pull-requests: write— nothing added. The test above asserts the permission list and the--applyline literally, so a later widening fails it.What I ran
node --test .github/scripts/label-hygiene.test.mjsat162d4bb5→# tests 10 / # pass 10 / # fail 0.node --test ".github/scripts/*.test.mjs"→# tests 540 / # pass 538 / # fail 0(2 skipped, unchanged).js-yaml:on = ["schedule", "workflow_dispatch", "issues", "pull_request_target"].#1401: closing an item is a trigger…witha closed issue runs the same cleanup; addingholdtoSTALE_LABELSfails both the existing keep-list case and the newholdcase.Red without the source change
git stashof the workflow hunk →not ok 10 - #1401: closing an item is a trigger, and the daily sweep stays,error: 'a closed issue runs the same cleanup'. Restore → 10/10. Theholdcase fails the same way if the keep-list widens: withholdadded toSTALE_LABELS,not ok 9reports thatholdwas removed.Not run
main, soissues: closedcannot fire from this branch. After merge I will close one scratch issue that carriesagent-working, report theissuesrun id with itsbefore:/after:lines and the time between close and label removal (acceptance 2), then re-run the same event and report0 items(acceptance 4); the same--applypath is already covered here by#738: a second run on a clean repository reports 0 items…. The script half it invokes is the one the daily sweep already runs (--apply, proven above and by its existing cases); the first real event after merge is the live proof, and I will watch the first close that lands and report the run id with itsbefore:/after:lines.generate/ds-bot-patches check: this diff touches neithercore/norpatches/, socheck's third line is main's and unchanged — the gate for this PR istests-okgreen at the tip.npm run verify(nocore/dependencies in this tree); nothing undercore/,patches/,client.jsor the plugins changes, so nobuild-clientstep applies.Risk
Low. The close event runs the same idempotent sweep:
before:/after:read back,0 itemson a clean repository,hold/bug/area:*/risk:*/needs-*/status:doneuntouched, and the fiveSTALE_LABELSare unchanged. The one behavioural difference ispull_request_targetinstead ofpull_request, which keeps the write token on the base repository and never checks out pull request code — thecheckoutstep still pinsref: main. Concurrency keeps two close events from overlapping.Docs-not-needed: workflow trigger plus its tests; no architecture or subsystem ownership change.
Tip SHA: 162d4bb
Checkpoint
{ "pr": 1404, "claim": "Dev3", "issue": 1401, "summary": "The label-hygiene workflow now also runs when an issue or a pull request closes, through the same --apply the daily sweep uses. The pull-request side is pull_request_target because a fork's pull_request run has a read-only token. Permissions, concurrency, the five stale labels and the keep-list are untouched, and two new cases pin the triggers and the hold case.", "files": [".github/workflows/label-hygiene.yml", ".github/scripts/label-hygiene.test.mjs"], "checks": { "ran": "node --test .github/scripts/label-hygiene.test.mjs", "result": "green", "at": "162d4bb5462aee91215c5be82621b72a86c27dfb" }, "next": "none — ready for review" }