Skip to content

ci: retire the stale-issues workflow under enforce-or-remove - #8957

Merged
baozhoutao merged 1 commit into
mainfrom
claude/issue-8548-retire-stale-yml
Sep 10, 2026
Merged

ci: retire the stale-issues workflow under enforce-or-remove#8957
baozhoutao merged 1 commit into
mainfrom
claude/issue-8548-retire-stale-yml

Conversation

@baozhoutao

Copy link
Copy Markdown
Contributor

Fixes #8548
Fixes #8126

Clause-②: no

The ruling

Director seat, decision batch 89, recorded on objectui#8548 (comment 5582691356, 2026-09-08), from the maintainer's standing delegation — route B, quoted:

Ruled. The workflow is deleted together with its three references … Eight months, 236 runs, zero successes, zero consumers, zero external authors on the open board: a declared automation nobody uses is removed under enforce-or-remove, not repaired. ⛔ A refused … ⛔ C refused … PR #8463 is closed unmerged (zero rollback cost); objectui#8126 closes with this card's PR; objectui#8465 (the one SHA pin) is disposed by the deletion.

So: .github/workflows/stale.yml is 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:

git grep -n "stale\.yml" -- . ; git grep -n "actions/stale" -- . ; git grep -rn "accept-360" -- .

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.

# Site What was there Measured Disposition
1 content/docs/guide/ci-cd-pipeline.md Workflow Inventory row; the prose reporting 236 runs / 0 successes; the section heading Confirmed, all three, found by string — the section had moved to line 2192 Row deleted, section deleted, prose rewritten so it no longer names the file
2 scripts/__tests__/workflow-cache-save-bound.test.ts the accepted array's entry, plus two comment blocks arguing for it Confirmed Entry removed; both comment blocks rewritten to record the retirement
3 scripts/check-action-ref-convention.mjs the DECLARED_EXCEPTIONS entry, plus its rationale in the file header Confirmed — and it is the red-main hazard Entry deleted in this same commit; header rewritten
4 scripts/__tests__/check-action-ref-convention.test.ts two fixtures that read the real workflow off disk Confirmed Repaired, not deleted — see below
5 scripts/__tests__/ci-cd-pipeline-doc.test.ts one illustrative string inside a failure message Confirmed, and harmless to that page's pins — but see the correction below Example re-pointed at a workflow that still exists
6 .github/workflows/action-ref-convention.yml its header prose names actions/stale as objectui#8465's finding Not in the census — found on re-derivation Left unchanged, deliberately

Corrections to the census, all measured

  • The ruling's name for site 2 is wrong, and taking it literally finds nothing. It calls that the "accept-360 entry". accept-360 occurs in exactly two files in this repository — .github/workflows/changelog.yml and the deleted workflow itself — and that test is neither. The real anchor is the string stale.yml::stale inside the accepted array. Read literally, the ruling's phrase returns a clean grep, which reads exactly like the work being already done.
  • Site 6 is a sixth reference the census did not carry. It is historical provenance for why the convention exists, it names no .yml filename, 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.
  • Site 5's page pins are stricter than "probably harmless" suggests, in the direction that matters. ci-cd-pipeline-doc.test.ts pins that page to .github/workflows/ in both directions: every workflow must have a heading naming it, and every .yml named 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.
  • The gate's floors comment was already stale before this change. It described "today's readings" as 34 workflow files and 13 distinct refs; the actual reading on 18b8e0961 was 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.mjs computes its stale-exception set as the declared exceptions that matched nothing, and its verdict fails when that set is non-empty. Action Ref Convention runs on every pull request and on main. Deleting the workflow while leaving the exception behind would therefore have reddened main for every open pull request.

Measured counterfactually against the post-deletion tree, without mutating anything on disk — scanning with the entry still supplied:

stale exceptions if the entry had been left behind: ["stale.yml::actions/stale"]
=> gate verdict would be: RED (rule 2)

Hence: workflow and exception entry in the same commit.

Before / after readings of check-action-ref-convention

Exit codes captured directly, never through a pipe (cmd > file 2>&1; EXIT=$?).

Before, on unmodified main (18b8e0961) — exit code 0:

✅  check-action-ref-convention: 111 action reference(s) in 36 workflow file(s), 13 distinct; 0 off-convention and undeclared, 0 stale exception(s); control `actions/checkout` present: true

After, on this branch's commit — exit code 0:

✅  check-action-ref-convention: 110 action reference(s) in 35 workflow file(s), 12 distinct; 0 off-convention and undeclared, 0 stale exception(s); control `actions/checkout` present: true

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: its accepted table pinned two jobs as deliberately unbounded, and one of them no longer exists. changelog.yml::changelog still 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

Check Result
node scripts/check-action-ref-convention.mjs before exit 0, green (reading above)
node scripts/check-action-ref-convention.mjs after exit 0, green (reading above)
vitest run over the three named suites 3 files, 96 tests, all passed
vitest run scripts/__tests__/ (whole gate-test population) 133 files passed, 2 skipped; 3890 tests passed, 2 skipped
pnpm lint:root (eslint over the root scope, which is where every changed source file lives) exit 0 — 307 files linted, 0 errors, 32 pre-existing warnings, none in the changed files
pnpm type-check:scripts exit 0
node scripts/check-control-bytes.mjs exit 0 — 7153 tracked text files scanned
node scripts/check-changeset-presence.mjs exit 0 — see below

The 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.mjs exits 0 and reports:

Compared the working tree with 18b8e09 (merge-base with origin/main): 6 file(s) changed, 0 of them published source of a package the release covers, 0 of them a manifest whose published contract moved, 0 under a package changesets ignores, 0 changeset(s) added.
✅ No source or published contract of a released package changed in this range, so no changeset is owed.

Changeset Declaration runs exactly this script, so the required context is satisfied with no changeset file: nothing here is published source of a released package. No skip-changeset label is applied — in this repository that label object is read by no workflow and exempts nothing.

Not done here, on purpose

  • Refs: objectui#8465. This pull request does not retire that card. The ruling says its one SHA pin is disposed of by the deletion; what happens to the card itself is the seat's call, and deliberately not a keyword in this body.
  • The pinning posture of the other references is untouched. The gate's own header forbids "unifying" the directory under cover of a change that was about something else.
  • The stale label 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

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
@baozhoutao
baozhoutao marked this pull request as ready for review September 10, 2026 09:48
@baozhoutao
baozhoutao added this pull request to the merge queue Sep 10, 2026
@claude

claude Bot commented Sep 10, 2026

Copy link
Copy Markdown
Contributor

Armed — SQUASH, in the queue at 2026-09-10T09:48:55Z, and the landing probe is written BEFORE the merge

domain:devx @ objectui PM seat (session_01FhBNJcLRZLe8M87VcUgpKr), 2026-09-10T09:49Z. Cards objectui#8548 and objectui#8126.

step reading
CI on 61ed687e7 converged all green, 29 checks, Live E2E (informational) excluded — 09:48:19Z
flip ready ready_for_review @ 09:48:25Z
post-flip Governed Surface Queue Guard completed/success @ 09:48:41Z — after the flip, ⛔ not the pre-flip run
auto-merge armed SQUASH
queue added_to_merge_queue @ 09:48:55Z, from the timeline event — ⛔ not from the auto_merge field

The probe, stated now so it cannot be fitted to the outcome

Baselines read on origin/main = a646262e2, tip committed 2026-09-10T09:29:03Z, at 09:48Z. After the merge each leg is re-read on a re-fetched origin/main.

# leg today expected after
A .github/workflows/stale.yml in the tree present gone
B1 the declared exception entry workflow: 'stale.yml' in the gate 1 0
B2 DECLARED_EXCEPTIONS = [] in the gate 0 1
C stale.yml mentions in content/docs/guide/ci-cd-pipeline.md 3 0
D the FLOORS line, byte-for-byte { workflowFiles: 20, distinctRefs: 8, totalRefs: 40 } unchanged

Leg D is the one this seat cares most about, and it is not about stale.yml at all. Deleting a workflow shrinks the population these floors guard, and lowering a floor to match is exactly the move that turns a floor into a rubber stamp — a gate weakening, and the maintainer's floor. It is pinned here in the same breath as the deletion so that a landing which quietly relaxed it could not read as a success. Verified identical on the branch before arming; the probe re-reads it on main.

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 Action Ref Convention for every open pull request. A leg that only checked the workflow's absence would pass in exactly that disaster.

Controls: leg A's firing control is .github/workflows/action-ref-convention.yml, present today and expected to stay, so an empty answer later means the deletion and ⛔ not a broken path; leg C's is doc-fence-languages.yml, named 2 times in that same page and staying, so a zero for stale.yml is a reading; B1 and B2 are each other's control.

⚠️Not probe legs, deliberately: the two test files still mention stale.yml in history comments, so a residual-mention count there would fail for a good reason and is not a signal. And .github/workflows/action-ref-convention.yml's header still names actions/stale on purpose — it records objectui#8465's finding, which still happened. ⛔ A probe that demanded zero mentions repo-wide would be demanding the deletion of the reason the gate exists.

The measurement that will not appear on main, and is the point anyway

Before, on unmodified main: check-action-ref-convention exit 0 — 111 refs in 36 files, 13 distinct, 0 stale exceptions. After, on the branch: exit 0 — 110 refs in 35 files, 12 distinct, 0 stale exceptions. ⇒ one file, one ref, one distinct ref — the deletion and nothing else. The stale-exception count stays 0 because the entry left in the same commit.

Next: merge-wait, then the five legs on a re-fetched origin/main, then the LANDED note and the label strip on both cards.

⚠️ Owed after landing and ⛔ still unpredicted: one line back on objectui#8548 reading what actually happened to the Actions registry entry once the workflow left the default branch. ⛔ It is not written in advance.


Generated by Claude Code

Merged via the queue into main with commit 3431bed Sep 10, 2026
32 checks passed
@baozhoutao
baozhoutao deleted the claude/issue-8548-retire-stale-yml branch September 10, 2026 10:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

2 participants