Skip to content

fix(test): delete the required-context claim that rotted, do not correct it - #47

Merged
NSchatz merged 2 commits into
mainfrom
fix/derive-required-contexts
Aug 8, 2026
Merged

fix(test): delete the required-context claim that rotted, do not correct it#47
NSchatz merged 2 commits into
mainfrom
fix/derive-required-contexts

Conversation

@NSchatz

@NSchatz NSchatz commented Aug 8, 2026

Copy link
Copy Markdown
Contributor

What rotted, and why nothing could have caught it

test/install-check.test.mjs asserted, in a comment, that actionlint is this repo's only
required status context
. That was false. Derived just now, not quoted:

$ gh api repos/cosyte/.github/rules/branches/main \
    --jq '.[] | select(.type=="required_status_checks")
                | .parameters.required_status_checks[].context'
actionlint
no-emdash
scripts

It rotted the moment this repository's own scripts job was made required (ruleset 19990161,
integration_id: 15368, 2026-08-07), and nothing in the repository could have noticed, because
nothing in a repository can observe its own ruleset.

A second sentence in the same test had rotted the same way, in the same direction, and was not
in the item as written. The changesets/action sha pin was documented as "not a required status
context, so it does not block the bump"
. That suite now runs under the required scripts context,
so it does block it. The refuter confirmed the reverse mechanically by mutating the pinned sha.

The fix is deletion, not correction

Both claims are deleted. No count and no context list replaces them, in either direction. That
is the standing rule and it is also what cli#35 learned the expensive way: it rewrote an
equivalent note twice, producing a fresh false claim each time, before correctly cutting it out.

What replaces them is a named unobservable plus the derive commands, sited exactly where the
claim rotted, so the next reader reaches for the API rather than for prose. The README bullet that
named this stale count as a known follow-up now records that the follow-up landed by deletion, and
its derive block gains the folded rules/branches/main view, which accounts for an org-level
ruleset by construction, alongside the per-ruleset form with an explicit includes_parents=true.
Both commands were run verbatim, by me and independently by the refuter.

Blast radius: none

Thirteen repositories call this repository's reusable workflows at @main, so anything here
reaches all of them on their next run. This change reaches none of them: it is comment-only, and
the .github/workflows/ tree hash is byte-identical at base and at head (3504bc8d70), verified
independently by the refuter at all three shas. No assertion, regex, script or workflow changed.

This repository ships no package and keeps no CHANGELOG.md by design, so that note lives here and
in the commit message.

Gates

scripts/verify.sh .github declines: the umbrella's scripts/verify-policy.json has no entry
for .github, and the ladder exits with "no pnpm-lock.yaml or package-lock.json, run its gate by
hand"
. Reported as a finding rather than worked around. The repo's own three gates were run by
hand, and re-run independently by the refuter on a fresh export of the head tree:

Gate Result
node --test "test/*.test.mjs" (the required scripts context) 339 pass, 0 fail, 0 skipped
node scripts/check-no-emdash.mjs (the required no-emdash context) exit 0, 48 tracked files, 0 exempt
actionlint (the required actionlint context) exit 0, run unpiped

Gate refuter: NOT REFUTED, on pass 2 of at most 3

Pass 1 refused it and it was a real defect: the sentence written to replace the false claim was
itself a false universal ("Nothing else in this repository reads step order"), with three live
counterexamples, and it contradicted the next sentence, which cites test/release-notes.test.mjs
as its own precedent. Precisely the failure mode the deletion rule exists to prevent.

Remedied in a new commit (da26bc4, nothing amended) by cutting the clause down rather than
enumerating what does read step order, because such a list rots exactly like a list of contexts.

Pass 2 returned NOT REFUTED, and proved the narrowed sentence by mutation rather than by
reading: moving the credential-drop step to the end of the job, and deleting it outright, each red
exactly one test, this one, while actionlint passes both. The claim is now empirically
checkable without a network call.

Deliberately not taken here

  • Whether run-actionlint should exist at all. A policy change across 13 repos at @main.
    Census first, its own slice, per the backlog item.
  • A CI job that curls the ruleset API. Already refused in writing: 60 requests/hour anonymous,
    charged per shared runner IP. It trades a false green for a flaky red on a required context.
  • The dated historical measurements in this README and in release.yml (hl7 3 to 5, ccda
    against 4), and the LIVE_INTERNAL_ONLY_HEADLINES corpus, which quotes other repos' shipped
    changelogs verbatim as classifier input. Censused, argued, left alone.
  • no-emdash.yml:46 and README ~1490 still read as "not yet required" while it is. Logged
    PRE-EXISTING by the refuter, and left alone on purpose: PR feat(ci): make this repo's own suite a gating context, and pin what could un-require it [DO NOT MERGE: gate refused] #45 is DIRTY over those exact
    regions.
    No conflict with this branch, which touches README.md:127-148 only.

Refs RUN-ACTIONLINT-SILENTLY-UNREQUIRES.

NSchatz added 2 commits August 8, 2026 18:18
…ect it

`test/install-check.test.mjs` asserted in a comment that `actionlint` is this
repository's only required status context. That was false: the ruleset requires
three. It rotted the moment this repo's own `scripts` job was made required on
2026-08-07, and nothing could have caught it, because nothing in a repository
can observe its own ruleset.

Derived, not quoted:

  gh api repos/cosyte/.github/rules/branches/main \
    --jq '.[] | select(.type=="required_status_checks")
                | .parameters.required_status_checks[].context'
  -> actionlint, no-emdash, scripts

A second sentence in the same test had rotted the same way and in the same
direction: the `changesets/action` sha pin was documented as "not a required
status context, so it does not block the bump". That suite now runs under the
required `scripts` context, so it does block it.

Both claims are DELETED rather than corrected, per the standing rule and per
`cli#35`, which rewrote an equivalent note twice and produced a fresh false
claim each time before cutting it out. No count and no context list replaces
them. What replaces them is a named unobservable plus the derive commands, at
the exact site where the claim rotted, so the next reader reaches for the API
rather than for prose.

The README bullet that named this stale count as a known follow-up is updated
to record that the follow-up landed by deletion, and its derive block now shows
the folded `rules/branches/main` view, which accounts for an org-level ruleset
by construction, alongside the per-ruleset form with an explicit
`includes_parents=true`.

Comment-only. No workflow, script or assertion behaviour changed, so the
thirteen repositories that call this repository's workflows at `@main` are
unaffected on their next run: the tree of every file under `.github/workflows/`
is byte-identical. This repository ships no package and keeps no CHANGELOG, so
that blast-radius note lives here.

Gates, run by hand because `scripts/verify-policy.json` in the umbrella has no
entry for `.github` and `verify.sh` declines it: `node --test "test/*.test.mjs"`
339/339, `node scripts/check-no-emdash.mjs` clean over 48 tracked files,
`actionlint` exit 0.

Refs RUN-ACTIONLINT-SILENTLY-UNREQUIRES
Pass 1 of the gate refused `2d1a631` on the one sentence that is the whole
deliverable. "Nothing else in this repository reads step order" is a universal
claim and it is false: `test/install-check.test.mjs` itself orders the release
step against the install gate, and `test/release-notes.test.mjs` pins the
caller checkout to `steps[1]` and places `prepare`/`assert` on named sides of
the changesets step. The comment then names that second file two lines later as
the precedent it copied, so it contradicted itself inside one block.

Cut the clause down to what is actually true and cannot drift: nothing else
pins where THIS step sits. Deleted rather than enumerated, because a list of
what does read step order rots exactly like a list of required contexts.

Comment-only, as the commit it remedies was. Workflow tree unchanged.

Refs RUN-ACTIONLINT-SILENTLY-UNREQUIRES
@NSchatz
NSchatz merged commit fba3834 into main Aug 8, 2026
4 checks passed
@NSchatz
NSchatz deleted the fix/derive-required-contexts branch August 8, 2026 18:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant