From b3955bec3c167e811f72f418970653ae2b2dbb5b Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 20 Aug 2026 13:30:07 +0000 Subject: [PATCH] ci(lint): run scripts/pm/ci-failure.mjs --self-test in Lint & Repo Gates MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `scripts/pm/ci-failure.mjs` shipped a `--self-test` that no job ran, unlike the four sibling PM tools (dispatch-gates, the part-of guard, the single-claim guard, the half-state sweeper) which all run theirs as unconditional steps in this same job. It was the odd one out, so it could rot until the next agent reached for it mid-round and found it broken. The rot this prevents is the exact defect the tool's own card was about: the file was found near-complete but never run live, because node 22's `fetch` ignores HTTPS_PROXY, so every read answered 401 and the tool's own transport probe reported PREREQUISITE NOT MET (exit 3) — and looked right doing it. A retrieval tool that has stopped working presents as a tool correctly declining to work. One step in the existing `lint:` job, whose `name:` (`Lint & Repo Gates`) is the required-status-check context and is unchanged — a required context is matched by check-run name, so a step adds no context. No new job, no new check name. Unconditional and un-`if:`-ed, like every self-test beside it. Measured, not assumed: under `strace -f` with full egress available the self-test makes zero socket() and zero connect() calls (the live walk, traced identically, makes 3 and 3), and it exits 0 inside an empty network namespace where the live walk exits 3. Runtime ~0.07-0.17 s. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01DdCnBGcHeufjrq7drTD3wt --- .github/workflows/lint.yml | 47 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 39721ebf65..07714593fe 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -388,6 +388,53 @@ jobs: - name: Verify-lock entry-point self-test run: bash scripts/pm/os-verify-lock.sh --self-test + # ci-failure self-test (#9898). Fifth member of the PM self-test family + # above, and until now the odd one out: `scripts/pm/ci-failure.mjs` — the + # one command from "a check is red" to "here is the failing assertion" — + # shipped a `--self-test` that NO job ran, so it executed only when a + # human or an agent typed it. + # + # This tool is worth the second because the rot it would hide is the exact + # defect its own card was about. The file was found near-complete but + # NEVER RUN LIVE: node 22's `fetch` ignores HTTPS_PROXY, so behind an agent + # container's proxy every read answered 401 and the tool's own transport + # probe reported PREREQUISITE NOT MET (exit 3) — and looked right doing it. + # ⇒ A retrieval tool that has stopped working presents as a tool correctly + # declining to work. Nothing about that shape reads as broken, which is + # what makes an unrun self-test the wrong economy here specifically. + # + # The self-test is also materially larger than when the card was filed: + # #9966/PR #10157 corrected the transport probe (a healthy `/rate_limit` + # was greening containers whose repo-scoped reads are refused — the fourth + # measured container class) and added nine cases, which is why this step + # was deliberately ordered AFTER that fix. Wiring a false green into a + # required job would have pinned it as CI-enforced truth. + # + # Beyond the pure predicates it pins the LIVE WIRING: `resolveStep` is run + # against the real `.github/workflows/` tree, so reshaping the workflows + # until no step name resolves to a `run:` block reddens here rather than + # silently degrading every gate failure from "here is the command" into + # "no substitute available". + # + # Unconditional and un-`if:`-ed, like every self-test above it — an + # exemption is precisely what a self-test must not have, or the gap moves. + # + # NO NETWORK, measured rather than assumed (#9898), because a self-test + # that reached GitHub would put this required context at the mercy of API + # availability — a far worse trade than the rot it prevents. Under + # `strace -f` with full egress available the run makes ZERO `socket()` and + # ZERO `connect()` calls (the live walk, traced identically, makes 3 and + # 3), and it exits 0 inside an empty network namespace where the live walk + # exits 3. The `--self-test` branch is chosen before the transport probe + # and never re-execs, and its two readers are injected. ~0.14 s. + # + # Invoked as `node` rather than through a `pnpm check:*` alias, same as + # the release-rehearsal step above: this card's declared file surface is + # this workflow alone, and dispatch-gates.mjs derives gate families from + # either spelling. + - name: PM ci-failure self-test + run: node scripts/pm/ci-failure.mjs --self-test + # Docs/skills authoring guard (#2035 / ADR-0059): TS code blocks in # Markdown/MDX are not type-checked or ESLinted, so skills/ and # content/docs/ can drift back to teaching the bare `: Page = {}` literal