Skip to content

test(docs): the post-gate hooks and the npm publishers keep only the tests that guard a relation - #216

Merged
Vivswan merged 9 commits into
mainfrom
chore/test-docs-invariants-pass2
Sep 13, 2026
Merged

Vivswan merged 9 commits into
mainfrom
chore/test-docs-invariants-pass2

Conversation

@Vivswan

@Vivswan Vivswan commented Sep 13, 2026 •

Copy link
Copy Markdown
Owner

One deleted test beside what covers it now:

test/docs/post-green-workflow.test.ts (deleted)                    what covers the drift now
  const CALLER_EXPECTED: CallerContract = {                        nothing: a byte-exact copy of post-green.yml
    topLevel: ["jobs", "name", "on"],                              (every step's name, id, uses, if, run, env,
    ...                                                             with) relates to no second artifact; editing
    steps: [{ uses: "actions/checkout@3d3c42e5...", ... }, ...]     the workflow always meant editing the test
  };                                                                (RESTATES, with its 30 mutation controls)
  expect(callerContractOf(wf)).toEqual(CALLER_EXPECTED);

  "a build step that runs the packaging without the token gate"    restored as a relation: every step after a
  (one of the 30 controls, a mutation of the pin above)             probe runs on the probe's verdict, by the
                                                                    steps.<id>.outputs chain back to it

The second pass of the same rule, on the two files PR #203 rewrote. The line count ends above where it began (4302 -> 4420): the two byte-exact workflow pins and their 50 mutation controls are gone, and what stands in their place is the set of relations six codex rounds, three Copilot passes, and the lead gate each showed a silent break for, so the file is no longer a copy of the workflows but is not smaller. The whole-workflow pins of post-green.yml and of the two npm publishers are gone, the properties those pins happened to guard are stated as relations between artifacts (ci.yml's callers and the hooks, a job's grant and its steps, the two publishers and package.json's slug, the library page's claim and the jobs' env), and the bash runs of the probe, the floor guard, and the publish blocks stay. test/root.ts's floating JSDoc now sits on the export it describes.

file lines before lines after deleted kept why the kept ones stay
post-green-workflow.test.ts 718 720 31 5 (+10 relations) hooks reachable through workflow_call alone with their ci.yml callers downstream of all-green; with keys == declared inputs; each job's effective grant covers its pushes and OIDC publishes; the judged sha is every checkout's ref and every SOURCE_SHA; every step after a probe runs on its verdict; the push probe's fence and remedies under bash
npm-publish-workflows.test.ts 455 571 21 12 (+7 relations) both publishers guarded to package.json's owner/name; one lane; the stable one downstream of every other job; no registry token, as library.md promises; the shared steps identical; one registry; probe, floor guard, and publish blocks under bash
workflow-loader.ts 70 70 (helper) SETUP_USES had no user left; Job.env and Workflow.env added for the token scan
test/root.ts 5 4 the JSDoc attaches to ROOT
test/docs total 4302 4420 52 tests

Proof: bun run check exit 0 on every commit (70fab5f, this head: 3371 pass, 0 fail, build:check 12 files match; all-green success, CI run 34779825625); codex rounds 1 to 5 each closed with their fold committed, rounds 6 and 7 returned 0 blocking (7 on the lead gate fold); Copilot's twelve threads fixed or answered and resolved.

Technical details

Line accounting: test files -761 / +879 (net +118, all under test/docs); test/root.ts -2 / +1; branch numstat +880 / -763. Both files end above their start: post-green-workflow.test.ts (718 -> 720) and npm-publish-workflows.test.ts (455 -> 571), because the two-publisher contract pin became nine relations (fork guard from package.json, one literal lane, stable last, no token or npm_config in any env, shared steps identical, build before publish, no step under its own condition, one registry) plus their controls, each of which a reviewer showed a silent break for; post-green-workflow.test.ts went 718 -> 374 -> 720 as five deleted pins came back as relations a reviewer showed a silent break for. test/library, test/sections, and every other test directory are untouched.

Per-test classification

RESTATES = pins one file's text or shape, no second artifact. COVERED = the same drift fails another gate or is loud at runtime (named). INVARIANT = relates two artifacts or a property a later edit breaks with no other check noticing.

post-green-workflow.test.ts

  • "two self-contained jobs, each gated on its probe, with the judged sha as the only input" (the CALLER_EXPECTED pin of the whole workflow) -> RESTATES, deleted with its six script-text constants (PUSH_PROBE, FENCED_STDERR, OIDC_PROBE, NPM_FLOOR, PUBLISH_NEXT, CONFIRM_NEXT)
  • its 30 mutation controls, by what each guarded:
    • packaging / publish / confirmation without its gate; probe id gone -> INVARIANT, restored: every step after a probe (a step writing proceed= to GITHUB_OUTPUT) carries steps.<id>.outputs.<x> == 'true' where <id> is an earlier step that is the probe or is gated the same way (3 negative controls)
    • a job with a ceiling of its own -> INVARIANT, restored as the grant relation: for every post-gate hook, a job's effective grant (its own block, else the ci.yml caller's) holds contents: write for a step that pushes or writes a release and id-token: write for a step that publishes through OIDC; a block below the ceiling makes the probe warn and skip quietly (1 negative control)
    • checkout of the default branch instead of the judged sha -> INVARIANT, restored: the caller passes github.sha as post-green's one input, and that input is every checkout's ref and every SOURCE_SHA
    • push trigger / dispatch trigger -> INVARIANT, restored: every workflow a ci.yml job downstream of all-green calls has on: [workflow_call] and nothing else; checks.yml (called before the gate) is the control (2 negative controls)
    • optional sha / default / non-string / second required input / declared secret -> COVERED: GitHub validates the call at run start (loud); the cheap equality "ci.yml's with keys == the hook's declared inputs" is kept for every hook
    • undeclared job / calling workflow with inherited secrets / workflow-level lane / checkout token never trying the caller's -> RESTATES (the job set and the lane are design choices of one file; a checkout without a token fails loudly)
    • fetch-depth gone (twice) -> COVERED: package-commit and prerelease-version refuse a shallow checkout loudly
    • confirmation treating behind as a warning -> INVARIANT, restored under bash: the confirm block runs with a stubbed bun printing each outcome literal of the script's ConfirmVerdict union plus an unknown line; behind and the unknown exit 1 with ::error::, unsettled warns, settled notices, and the table of expected verdicts must name every outcome of the union. Publish under the default dist-tag / registry token / probe warning naming one remedy / fenced stderr / fixed fence token -> the other bash runs observe each; the verdict semantics themselves are test/scripts/release-pipeline.test.ts's
    • PAT_SET gone -> INVARIANT, restored: the probe's env must read the same secrets.X the checkout's secrets.X || github.token falls back from, as secrets.X != '', and the script must branch on that env name
    • open to forks -> INVARIANT, kept in npm-publish-workflows.test.ts (guard derived from package.json)
  • the push probe under bash (5) -> kept; the warning assertion loosened from the verbatim sentence to "one ::warning:: naming contents: write and REPO_PLATFORM_TOKEN", the static error to "one ::error:: after the fence"

npm-publish-workflows.test.ts

  • "both publish through OIDC alone, with the same guard and build, and publish-next skips whole without a token" (the EXPECTED contract pin) and its 20 controls -> the pin is gone; the fields became relations:
    • repositoryGuards -> INVARIANT: both if == github.repository == '<package.json repository slug>'
    • lanes -> INVARIANT: the two concurrency blocks are equal, with a literal group (queue/cancel literals dropped: GitHub rejects the bad pairing loudly)
    • stableNeeds -> INVARIANT: publish-npm needs exactly every other job of update-release.yml
    • tokenInputs, setupNodeEnvs -> INVARIANT: library.md says "no registry token exists anywhere", and no env/with/if of either publisher names a secret or a token
    • sameFloor, sameBuild, registries -> INVARIANT: every step the two publishers share (by name, or by action other than the checkout) is the same text, gate and id aside; the registry-url is one string in both
    • stablePermissions -> COVERED by the grant relation in post-green-workflow.test.ts; nextPermissions: undefined -> RESTATES (a block equal to the ceiling is legal); ungatedNextSteps -> COVERED by the probe-gate relation; publishCommands -> the bash runs observe them
    • 4 negative controls kept (fork guard, lane, token, floor drift)
  • the OIDC probe under bash (2) -> kept; the warning assertion loosened to "one ::warning:: naming id-token: write"
  • the npm floor guard under bash (4) -> kept; the floor is read from the script's floor= line
  • the publish blocks under bash (5) -> kept

Codex rounds

round blocking what it named closed by
1 5 (+1 nit) a gate on an output the probe never writes; a hook's workflow-level permissions ignored; a deleted packaging step or a job-level if passing; the confirmation step or its published output gone; the probe's PAT_SET env unbound gate reads must name written outputs, chained to the probe; effective grant = job, else workflow, else caller; library.md's dist-tag table and build-tag bullet relate each channel to the hook that publishes it, and a hook job's own if is the fork guard or nothing; every written output is read and every read is written; the probe's env reads the same secret the checkout falls back from; assertions and controls read one problem list
Copilot (1st pass) 6 threads fixed fence token; queue: max dropped (out of scope, answered); token in a job's env or a with key; floor derived from the script alone; a release hook moved ahead of the gate; pipeline subcommands not counted as pushes two probe runs must differ; job env and every name scanned; floor must not sort below 11.5.1 with 11.4.2 as the just-below case; hooks = every local call the gate does not judge, each downstream; push-capable subcommands and gh release count as contents consumers
2 3 (+2 nits) a probe under its own if skips the whole job quietly; a publish or packaging step under if: github.event_name == 'release' still satisfies the channel claim; NPM_CONFIG_TAG: next in a job env moves the stable dist-tag a probe carries no condition; a channel's step runs unconditionally or on a verdict gate; any npm_config_* name in env or with fails; the anchor control goes through grantProblems; the header's overclaim removed
Copilot (2nd pass) 3 threads a workflow-level env token unseen; source steps selected by the asserted env, so a dropped SOURCE_SHA passed; the post-fence error not proven static both workflows' env scanned; source steps are those reading $SOURCE_SHA; the error line carries none of git's words
3 3 (+1 nit) a verdict gate copied onto the stable publish read an output no step writes, unchecked outside post-green.yml; the build checkout under its own if left the probe judging an empty workspace; the library build moved after the publish wiring judged in every hook; no step ahead of a probe carries a condition; every shared step precedes the publish
4 1 the stable library build under if: github.event_name == 'release' skips on the push that calls it and publishes a source-only tarball a publisher step under a condition of its own fails; the probed job allows only a verdict gate
5 1 retag-major under if: github.event_name == 'release' skipped on the push that calls it, unchecked in a probe-less job any conditioned step in a probe-less hook job fails
Copilot (4th pass) 1 thread the post-fence error check evaded by transforming stderr before interpolating it answered with the scope (a deliberate rewrite, not drift) per the lead's ruling; no commit
Copilot (3rd pass) 2 threads a caller rewritten to always() stays downstream (out of scope, answered: ci.yml is managed, the platform's skeleton-gate holds the contract); the green-push lookup selected by the absence of release_created the green-push hook is the one caller naming the gate's success, the push event, and refs/heads/main
Lead gate 1 blocking (+2 folds) the confirm step's behind arm downgraded to a warning passed every check while the body claimed the bash runs observed it; the judged-sha relation compared raw expression strings a managed sync could respell; a stale case name the confirm block runs under bash over the union's outcomes; expressions normalized before comparison; the case name had already been fixed in round 3
7 (final) 0 (+2 nits) none: the behind downgrade, a deleted behind arm, exit 1 dropped from the unknown arm, and a union outcome without an arm each fail a named assertion; nits: bare inputs.sha passes condition() but fails loudly at checkout (recorded), two comments restated the table and its stub (trimmed)
6 0 (+1 nit, recorded) none: both round-5 answers hold and the scope reply stands; the green-push negative control reaches its own selector rather than hookFor (recorded)

Recorded, not built

  • The confirm hold (CONFIRM_READS x the read interval) against the publish-next job's timeout-minutes: raising the reads past the timeout is never covered.

  • Both setup-node registry-url values against the script's DEFAULT_REGISTRY.

  • publish-npm's checkout ref (the resolved source sha) against a ref of main: the verdict holds the built manifest to TAG, so this is uncovered by design.

  • Job ids and step names are pinned in the test helpers (publish-next, publish-npm, Build the library, Require an npm ...): renaming one fails four controls by name; acceptable, and stated here.

  • The lane relation compares the two concurrency blocks through JSON.stringify, so a key reorder reads as a different lane.

  • condition() accepts a bare inputs.sha or github.sha where GitHub needs the ${{ }} wrapper; such a value fails loudly at checkout or at the pipeline's exact-sha check.

  • The shared lane's queue: max: one file's setting with no second artifact (the lane relation holds both publishers to one literal lane).

  • A hook's job-level permissions block above the caller's ceiling (GitHub fails the call loudly).

  • The green-push negative control in post-green-workflow.test.ts filters the callers with its own copy of the selector instead of calling hookFor; sharing the selector would let the control fail through the real path.

  • A hook caller rewritten to always() or to a pull_request event: a deliberate change of the managed ci.yml's gate contract; validate-managed-files fails on the drift and the platform's skeleton-gate rule holds the contract.

  • A second publisher spelled without npm publish, or a token reaching npm through a file the workflow writes: deliberate evasion, outside the stated accidental-drift scope.

Out-of-territory findings

  • update-release.yml's verify-release job carries contents: write "read-only in spirit"; the grant relation reads no consumer there and says nothing about it.
  • ci.yml is platform-managed: the hook relations read its post-green, update-release, and update-release-pr callers, so a sync that renames a caller or drops a with key fails here first, naming the platform as the place to fix.

…tests that guard a relation; test/root.ts's comment sits on its export
Copilot AI balanced review requested due to automatic review settings September 13, 2026 19:20
@github-actions

github-actions Bot commented Sep 13, 2026 •

Copy link
Copy Markdown
Contributor

File size check

0 over a hard cap (fails), 14 warning(s).

File Size Tier Cap
.github/scripts/release-pipeline.ts:6 156 chars warn 150
.github/scripts/release-pipeline.ts:449 151 chars warn 150
.github/scripts/release-pipeline.ts:1 30 comment lines (header) warn 25
.github/scripts/release-pipeline.ts:445 14 comment lines warn 10
.github/workflows/post-green.yml:27 153 chars warn 150
.github/workflows/post-green.yml:140 11 comment lines warn 10
.github/workflows/update-release.yml:67 164 chars warn 150
src/flows/settings-write.ts:130 159 chars warn 150
src/flows/settings-write.ts:29 11 comment lines warn 10
src/flows/snapshot.ts:192 13 comment lines warn 10
src/sections/shared/variables-engine.ts:50 151 chars warn 150
test/action/run.test.ts:759 151 chars warn 150
test/action/run.test.ts:780 155 chars warn 150
test/docs/guides.test.ts:451 155 chars warn 150

Split the file, wrap the line, shorten or exempt the comment, or list the path in .file-size-allow.local with a # reason.

4 managed file(s) skipped; repo-platform owns them.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Several replacement tests allow security, permission, queueing, and publishing-contract regressions to pass unnoticed.

Get a fresh assessment by requesting another Copilot review.

Pull request overview

Replaces brittle workflow snapshots with tests of cross-file release and publishing invariants.

Changes:

  • Adds post-gate reachability, permissions, SHA, and probe-gating checks.
  • Adds relational npm publisher checks while retaining Bash behavior tests.
  • Removes an unused helper and fixes JSDoc placement.
File summaries
File Description
test/root.ts Attaches documentation to ROOT.
test/docs/workflow-loader.ts Removes unused SETUP_USES.
test/docs/post-green-workflow.test.ts Reworks post-gate workflow tests.
test/docs/npm-publish-workflows.test.ts Reworks npm publishing tests.
Review details
  • Files reviewed: 4/4 changed files
  • Comments generated: 6
  • Review effort level: Balanced

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread test/docs/post-green-workflow.test.ts
Comment thread test/docs/npm-publish-workflows.test.ts Outdated
Comment thread test/docs/npm-publish-workflows.test.ts Outdated
Comment thread test/docs/npm-publish-workflows.test.ts
Comment thread test/docs/post-green-workflow.test.ts Outdated
Comment thread test/docs/post-green-workflow.test.ts Outdated
@Vivswan Vivswan added the merge-when-green Owner approved: merge once every gate is green label Sep 13, 2026
… publishing claims are relations; a fixed fence token and a token in a job's env fail
Copilot AI review requested due to automatic review settings September 13, 2026 19:31

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Several new assertions allow security-sensitive workflow regressions to pass undetected.

Get a fresh assessment by requesting another Copilot review.

Review details
  • Files reviewed: 4/4 changed files
  • Comments generated: 3
  • Review effort level: Balanced

Comment thread test/docs/npm-publish-workflows.test.ts Outdated
Comment thread test/docs/post-green-workflow.test.ts Outdated
Comment thread test/docs/post-green-workflow.test.ts
…ery call, npm is not configured through the env
Copilot AI review requested due to automatic review settings September 13, 2026 19:39
…the steps that read SOURCE_SHA; the post-fence error carries none of git's words

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Several new relations still permit publishing schedule, output-gate, token, and source-SHA drift to pass unnoticed.

Get a fresh assessment by requesting another Copilot review.

Review details

Suppressed comments (3)

Previously missed (2) — in code that hasn't changed since the last review.

test/docs/npm-publish-workflows.test.ts:44

  • Workflow-level environment variables bypass the token check. Adding env: { NODE_AUTH_TOKEN: "${{ secrets.NPM_TOKEN }}" } at the top of either publisher workflow exposes that token to npm publish, but runnerInputs() only visits the job and its steps, so this test still passes. Include top-level env from both workflows in the scanned inputs.
    test/docs/post-green-workflow.test.ts:245
  • The documentation schedule is reduced to "contains release cut", so unrelated schedules are treated as green pushes. For example, changing the next row to Every pull request still selects post-green.yml and passes, even though that workflow is not called for pull requests; changing the post-green caller to a pull-request condition also passes. Reject unknown schedule text and match the green-push claim to a caller condition that requires a push to refs/heads/main.

This issue also appears on line 257 of the same file.

test/docs/post-green-workflow.test.ts:263

  • A syntactically shaped verdict gate is accepted even when no step can produce its output. Setting the stable publish step to if: steps.missing.outputs.go == 'true' passes VERDICT_GATE, so the documentation test stays green while every release skips publishing. Resolve a verdict gate through an earlier probe/output writer before counting the subcommand as runnable.
const runsSubcommand = (workflow: Workflow, subcommand: string): boolean =>
  Object.values(workflow.jobs).some((job) =>
    (job.steps ?? []).some(
      (step) =>
        new RegExp(`release-pipeline\\.ts ${subcommand}(?![\\w-])`).test(step.run ?? "") &&
        (step.if === undefined || VERDICT_GATE.test(condition(step.if))),
    ),
  • Files reviewed: 4/4 changed files
  • Comments generated: 1
  • Review effort level: Balanced

Comment thread test/docs/post-green-workflow.test.ts Outdated
Copilot AI review requested due to automatic review settings September 13, 2026 19:43
…be is conditioned, the library is built before it is published

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Publisher checks discard stable-step conditions, allowing required build steps to be silently skipped.

Get a fresh assessment by requesting another Copilot review.

Review details
  • Files reviewed: 4/4 changed files
  • Comments generated: 1
  • Review effort level: Balanced

Comment thread test/docs/npm-publish-workflows.test.ts
Copilot AI review requested due to automatic review settings September 13, 2026 19:46

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

The new checks allow post-gate callers and stable publishing prerequisites to be incorrectly gated.

Get a fresh assessment by requesting another Copilot review.

Review details

Suppressed comments (1)

test/docs/npm-publish-workflows.test.ts:146

  • Stripping if lets the stable publisher skip required shared steps without failing this relation. Adding if: ${{ false }} to its Build the library step still leaves the compared bodies and ordering unchanged, but npm publish then runs without producing lib/pkg. Require the stable publisher's shared prerequisites to be unconditional; the next publisher's conditions remain covered by the probe-wiring check.
  for (const [label, a, b] of sharedSteps(next, stable)) {
    if (JSON.stringify(body(a)) !== JSON.stringify(body(b)))
      problems.push(`"${label}" diverged between the publishers`);
  • Files reviewed: 4/4 changed files
  • Comments generated: 2
  • Review effort level: Balanced

Comment thread test/docs/post-green-workflow.test.ts
Comment thread test/docs/post-green-workflow.test.ts Outdated
Copilot AI review requested due to automatic review settings September 13, 2026 19:50

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

The tests allow a post-gate hook to run after a failed all-green gate.

Review details

Suppressed comments (1)

test/docs/post-green-workflow.test.ts:102

  • The downstream check does not prevent a hook from bypassing a failed gate. For example, changing ci.yml's post-green.if to always() keeps needs: [all-green], so misplaced remains empty and this suite passes, but the hook can package and publish a red commit. Assert that direct post-gate callers require needs.all-green.result == 'success', and preserve equivalent success gating along indirect paths.
    expect(misplaced, "hook callers that all-green does not gate").toEqual([]);
  • Files reviewed: 4/4 changed files
  • Comments generated: 0 new
  • Review effort level: Balanced

…hook is the one caller on a push to main behind the gate
Copilot AI review requested due to automatic review settings September 13, 2026 19:55
@Vivswan Vivswan removed the merge-when-green Owner approved: merge once every gate is green label Sep 13, 2026

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

Documentation drift can escape detection, while equivalent concurrency mappings can fail due solely to key order.

Review details

Suppressed comments (3)

Previously missed (3) — in code that hasn't changed since the last review.

test/docs/npm-publish-workflows.test.ts:142

  • The lane comparison treats YAML key order as behavior. Reordering the same group, queue, and cancel-in-progress entries in one workflow makes JSON.stringify report different lanes even though GitHub receives the same concurrency configuration. Normalize the entries before comparing them.
    test/docs/post-green-workflow.test.ts:242
  • Unknown documentation text is silently treated as a green-push claim. For example, changing next's Publishes on cell to Every pull request still selects post-green.yml, so claimProblems(page) returns no problem even though the page is wrong. Reject claim text that names neither supported event.
    test/docs/post-green-workflow.test.ts:283
  • Two matching rows do not guarantee that both channels are documented. Replacing the latest row with a copy of the next row leaves two matches, and both validate against the green-push hook, so deleting the stable-channel documentation passes. Check the captured tag set, not only its length.
  • Files reviewed: 4/4 changed files
  • Comments generated: 0 new
  • Review effort level: Balanced

@Vivswan
Vivswan marked this pull request as ready for review September 13, 2026 20:00
@Vivswan Vivswan added the merge-when-green Owner approved: merge once every gate is green label Sep 13, 2026
@Vivswan
Vivswan marked this pull request as draft September 13, 2026 20:01
…utcomes; expressions normalized before comparison
Copilot AI review requested due to automatic review settings September 13, 2026 20:03

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

Container-level environment variables can bypass the new no-registry-token invariant.

Review details

Suppressed comments (1)

Previously missed (1) — in code that hasn't changed since the last review.

test/docs/npm-publish-workflows.test.ts:156

  • Container-level environment variables bypass this scan even though they reach every publisher step. For example:

    container:
    image: node:24
    env: { NODE_AUTH_TOKEN: "${{ secrets.NPM_TOKEN }}" }

publisherProblems() reports no token problem for that job, so the documented no-registry-token invariant can regress silently. Add container.env to the workflow model and scan its keys and values here too.

  • Files reviewed: 4/4 changed files
  • Comments generated: 0 new
  • Review effort level: Balanced

Copilot AI review requested due to automatic review settings September 13, 2026 20:08

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Several new relation tests have demonstrated blind spots that can silently permit incorrect or unsafe workflow drift.

Get a fresh assessment by requesting another Copilot review.

Review details

Suppressed comments (3)

Previously missed (3) — in code that hasn't changed since the last review.

test/docs/npm-publish-workflows.test.ts:186

  • A later setup-node step can redirect the stable publish without failing this relation. If publish-npm gains a second actions/setup-node before npm publish with another registry-url, both sharedSteps() and setupNode(stable) inspect the first action, so publisherProblems() still returns no problem while npm uses the second registry. Check every setup-node occurrence, or require exactly one in each publisher.
    test/docs/npm-publish-workflows.test.ts:439
  • A valid hyphenated outcome is omitted from this extracted union. Adding { outcome: "timed-out"; ... } while leaving the workflow case block unchanged still leaves outcomes as the original three values, so all confirmation assertions pass despite the missing arm. Capture the complete quoted literal rather than letters only.
    test/docs/post-green-workflow.test.ts:242
  • An unrecognized documentation schedule is silently treated as a green push. For example, changing the next row to Every pull request leaves release false, so hookFor() still selects post-green.yml and claimProblems() returns no problem. Reject claims that do not name exactly one supported schedule before selecting a hook.
  • Files reviewed: 4/4 changed files
  • Comments generated: 1
  • Review effort level: Balanced

Comment thread test/docs/post-green-workflow.test.ts
@Vivswan
Vivswan marked this pull request as ready for review September 13, 2026 20:17
@Vivswan
Vivswan merged commit 700b1c2 into main Sep 13, 2026
36 checks passed
@Vivswan
Vivswan deleted the chore/test-docs-invariants-pass2 branch September 13, 2026 20:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

merge-when-green Owner approved: merge once every gate is green

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants