ci: retire the stale-issues workflow under enforce-or-remove - #8957
Conversation
Eight months, 236 scheduled runs, zero successes, zero consumers and zero
external authors on the open board. Every run failed in `Set up job` before
`actions/stale` started, because the workflow's SHA pin resolved to no commit,
so the job never once swept anything. A declared automation nobody uses is
removed, not repaired (director seat, decision batch 89).
The workflow's three declared references go with it, and the exception entry
goes in THIS commit rather than a follow-up:
- `scripts/check-action-ref-convention.mjs` — the `DECLARED_EXCEPTIONS` entry
naming the workflow and `actions/stale`. That gate's rule 2 fails when an
entry matches nothing, and it runs on every pull request, so deleting the
workflow and leaving the entry would have reddened `main` for everyone.
Verified counterfactually: scanning this tree with the entry still present
reports one stale exception.
- `content/docs/guide/ci-cd-pipeline.md` — the Workflow Inventory row, the
section, and the prose naming the file. The page is pinned to
`.github/workflows/` in both directions, so all three had to move.
- `scripts/__tests__/workflow-cache-save-bound.test.ts` — the unbounded-job
entry. Its lookup asserts the job still exists.
Two suites read the real workflow off disk and are repaired, not deleted: the
behaviour they pin still needs pinning. `check-action-ref-convention.test.ts`
reproduces both the stale-exception verdict and the "silences only the entry
that names it" case over synthetic tables and other workflows, which no longer
depends on one particular file surviving.
Part of objectui#8465, whose one SHA pin this disposes of.
Co-authored-by: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FhBNJcLRZLe8M87VcUgpKr
Armed — SQUASH, in the queue at 2026-09-10T09:48:55Z, and the landing probe is written BEFORE the merge
The probe, stated now so it cannot be fitted to the outcomeBaselines read on
⭐ Leg D is the one this seat cares most about, and it is not about ⭐ B1 and B2 are the same fact from both sides, and the pair is the red-main hazard this dispatch was built around: the workflow leaving without its exception entry is precisely what would make the entry match nothing and fail Controls: leg A's firing control is
The measurement that will not appear on
|
Fixes #8548
Fixes #8126
Clause-②: noThe ruling
Director seat, decision batch 89, recorded on objectui#8548 (comment 5582691356, 2026-09-08), from the maintainer's standing delegation — route B, quoted:
So:
.github/workflows/stale.ymlis deleted. Route A (repair) is refused and its pull request is already closed unmerged; route C (a policy or exemption face) is refused. Nothing here repairs the SHA pin or adds an exemption surface.The census — the ruling names three references, the tree held five, and I measured six
Re-derived on this branch's base (
18b8e0961, tip committed 2026-09-10T08:58:15Z), not inherited. Command, run from the repo root:Control, same channel, same run:
git grep -n "zzqqxx-nonexistent-token" -- .exits 1 with no output, so a zero from this channel is a reading.content/docs/guide/ci-cd-pipeline.mdscripts/__tests__/workflow-cache-save-bound.test.tsacceptedarray's entry, plus two comment blocks arguing for itscripts/check-action-ref-convention.mjsDECLARED_EXCEPTIONSentry, plus its rationale in the file headerscripts/__tests__/check-action-ref-convention.test.tsscripts/__tests__/ci-cd-pipeline-doc.test.ts.github/workflows/action-ref-convention.ymlactions/staleas objectui#8465's findingCorrections to the census, all measured
accept-360occurs in exactly two files in this repository —.github/workflows/changelog.ymland the deleted workflow itself — and that test is neither. The real anchor is the stringstale.yml::staleinside theacceptedarray. Read literally, the ruling's phrase returns a clean grep, which reads exactly like the work being already done..ymlfilename, the gate's own parser strips comment lines before counting refs, and it stays true after the deletion — the finding it records happened. Deleting it would delete the reason the gate exists. Left in place on purpose, reported rather than silently kept.ci-cd-pipeline-doc.test.tspins that page to.github/workflows/in both directions: every workflow must have a heading naming it, and every.ymlnamed in the page's prose must exist. So the doc's three sites are not tidiness — the section had to go with the workflow, and the prose paragraph had to stop naming the file, or that suite goes red. The failure-message string itself reads nothing off disk; it is updated only because it pointed readers at a section that no longer exists.18b8e0961was 36 files and 13 distinct. It now carries the measured post-deletion reading (35 files, 110 refs, 12 distinct). ⛔ The floor values are not lowered — they still sit far under the reading, and moving a floor down each time the population shrinks by one is how a floor loses the ability to fail.The red-main hazard, and the proof it is real
scripts/check-action-ref-convention.mjscomputes its stale-exception set as the declared exceptions that matched nothing, and its verdict fails when that set is non-empty.Action Ref Conventionruns on every pull request and onmain. Deleting the workflow while leaving the exception behind would therefore have reddenedmainfor every open pull request.Measured counterfactually against the post-deletion tree, without mutating anything on disk — scanning with the entry still supplied:
Hence: workflow and exception entry in the same commit.
Before / after readings of
check-action-ref-conventionExit codes captured directly, never through a pipe (
cmd > file 2>&1; EXIT=$?).Before, on unmodified
main(18b8e0961) — exit code 0:After, on this branch's commit — exit code 0:
One workflow file, one reference and one distinct ref fewer, which is the deletion and nothing else. The stale-exception count stays at 0 because the entry left with the workflow.
The two repaired suites — what each was pinning, and how it is pinned now
Both read the real workflow off disk, so both broke on the deletion from a second direction. Neither is deleted: the behaviour each pins still needs pinning once the workflow is gone.
goes red on a stale exception — an entry that matches nothing. It was pinning rule 2 of the gate: an exception that no longer matches an off-convention reference must be reported, so an escape hatch cannot rot into a permanent skip-list. It did that by rewriting the real workflow's SHA into a tag. Now it runs over a synthetic exception table and asserts both halves: with the reference off-convention the entry silences it and nothing is reported; then the workflow the entry names is deleted — literally what this pull request did to the real table — and the entry is reported as stale. Pinning the pair matters, because an entry that never silenced anything would satisfy the second half alone. This is strictly stronger than before: it no longer depends on one particular workflow surviving in the tree.a declared exception silences the offender, and only that one. It was pinning that what silences a reference is an entry naming it, not the gate being lax about off-convention spellings. Its "only that one" half leaned on the real workflow's SHA still being present and undeclared under the fake table. Now the test injects a second off-convention reference into a different workflow (shadcn-check.yml), which the fake table does not name, and asserts that exactly that one is reported. Same property, same shape, no dependency on the deleted file. ⛔ The comment says not to drop the second reference and keep only the silenced half — a gate that reported nothing at all would pass that alone.The third suite,
workflow-cache-save-bound.test.ts, is not repaired but reduced: itsacceptedtable pinned two jobs as deliberately unbounded, and one of them no longer exists.changelog.yml::changelogstill holds the rule, and both comment blocks now record why the table lists one key rather than two — including that re-adding the deleted job would not restore a pin, because the lookup would fail on a workflow that is gone.Verification
node scripts/check-action-ref-convention.mjsbeforenode scripts/check-action-ref-convention.mjsaftervitest runover the three named suitesvitest run scripts/__tests__/(whole gate-test population)pnpm lint:root(eslint over the root scope, which is where every changed source file lives)pnpm type-check:scriptsnode scripts/check-control-bytes.mjsnode scripts/check-changeset-presence.mjsThe whole
scripts/__tests__/population was run rather than only the three named suites, because roughly thirty of those suites enumerate.github/workflows/and a deletion changes what they enumerate. Nothing else in that population noticed.⛔ No test was skipped, disabled or quarantined.
Changeset
node scripts/check-changeset-presence.mjsexits 0 and reports:Changeset Declarationruns exactly this script, so the required context is satisfied with no changeset file: nothing here is published source of a released package. Noskip-changesetlabel is applied — in this repository that label object is read by no workflow and exempts nothing.Not done here, on purpose
stalelabel objects in the repository's label set are not touched. Nothing in the tree reads them, and removing label objects is not a code change.🤖 Generated with Claude Code
https://claude.ai/code/session_01FhBNJcLRZLe8M87VcUgpKr
Generated by Claude Code