From 3fbf4bfbdaa66757975e34e00dcb2f6b6b4a1974 Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 13 Aug 2026 18:12:52 +0000 Subject: [PATCH] test(pm): run the half-state sweeper self-test in CI MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `scripts/pm/check-half-states.mjs` carried a 79-case --self-test that no CI job ran — it executed only when a human or an agent typed it. Since the part-of/closing-keyword guard landed, a PR-scoped BLOCKING check imports the file's H7 predicate, so a break in it now reddens or silently greens every PR in the repo; that guard's own self-test pins only the H7 behaviours it depends on, leaving H1-H6, the seat-sticker parser and the transport classifier with no CI coverage at all. - new `check:pm-half-states` running the self-test only, wired as an unconditional step in lint.yml beside the other pm gates - the live sweep stays out of CI: it is report-only by design (a completed sweep exits 0 on any finding count) and its non-zero exits classify the environment, not the PR - pointed straight at the script, no gate file in between: measured on this tree under the landed module-body masking, it yields exactly one watch hint (the repo slug in its API base), which covers no input path — so the fixture-pollution that forced a separate file for check:pm-dispatch-gates does not apply here Fixes #8528 Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_018WuTtyckQa1VcXwgd52JpN --- .github/workflows/lint.yml | 35 +++++++++++++++++++++++++++++++++++ package.json | 1 + 2 files changed, 36 insertions(+) diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 09bf34eaa8..1867995cd1 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -210,6 +210,41 @@ jobs: - name: Part-of closing-keyword guard self-test run: pnpm check:partof-closing-keyword + # PM half-state sweeper self-test (#8528). `scripts/pm/check-half-states.mjs` + # carried a 79-case --self-test — the H1..H7 predicates, the seat-sticker + # parser, the transport classifier and its measured container classes — + # that NO job ran: it executed only when a human or an agent typed it. + # Fourth member of the same family as the three steps above, and the one + # with a blocking consumer: since #8527 the H7 predicate + # (`h7PartOfWithClosingKeyword` and `stripMarkdownCode` beneath it) is + # imported by the PR-scoped guard whose self-test runs in the step above, + # so a break there now reddens — or silently greens — every PR in the repo. + # That incidental coverage is real but bounded: it pins only the H7 + # behaviours the guard depends on. H1..H6, the seat parser and the whole + # transport classifier had none. Unconditional for the family's reason: an + # exemption is what a self-test must not have, or the gap simply moves. + # + # The gate runs the SELF-TEST only. The live sweep + # (`node scripts/pm/check-half-states.mjs`) reads a shared board over the + # GitHub API, is report-only by design (a completed sweep exits 0 whether + # it found 0 or 40 half-states), and its non-zero exits classify the + # ENVIRONMENT — no token, exhausted quota, unreachable host — which is not + # a verdict about the PR running it. The script's own header argues both + # halves. The self-test is offline: no network, no token, ~0.05s. + # + # Pointed straight at the script, with no gate file in between, unlike + # `check:pm-dispatch-gates` next door — that one needs its own file because + # the tool's fixtures are path strings that become watch hints and + # fabricate MATCHED leads across the tree. Measured here on the current + # tree, under the module-body masking that now blanks comments and + # self-tests before the scan: this script yields exactly ONE hint, the repo + # slug in its API base, which is not a repo path and covers no input path. + # The fixtures are issue-shaped objects and prose, and they sit inside the + # masked self-test. So the pollution that forced a separate file there does + # not exist here, and the direct entry is the same shape as the step above. + - name: PM half-state sweeper self-test + run: pnpm check:pm-half-states + # 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 diff --git a/package.json b/package.json index c2c33863e3..6782dcc5db 100644 --- a/package.json +++ b/package.json @@ -47,6 +47,7 @@ "check:pm-skill-ratchet": "node scripts/pm/check-skill-line-ratchet.mjs --self-test && node scripts/pm/check-skill-line-ratchet.mjs", "check:pm-skill-id-lint": "node scripts/pm/check-skill-id-lint.mjs --self-test && node scripts/pm/check-skill-id-lint.mjs", "check:pm-dispatch-gates": "node scripts/pm/check-dispatch-gates.mjs", + "check:pm-half-states": "node scripts/pm/check-half-states.mjs --self-test", "check:partof-closing-keyword": "node scripts/check-partof-closing-keyword.mjs --self-test", "check:adr-anchors": "node scripts/check-adr-anchors.mjs --self-test && node scripts/check-adr-anchors.mjs", "check:adr-links": "node scripts/check-adr-links.mjs --self-test && node scripts/check-adr-links.mjs",