Skip to content

policy: derive the gate list from docs/testing-layers.json - #2304

Merged
Birfy merged 1 commit into
ThinkFlowLab:mainfrom
HugoXK:dev/1-p498-gate-switch-coverage
Nov 3, 2026
Merged

Birfy merged 1 commit into
ThinkFlowLab:mainfrom
HugoXK:dev/1-p498-gate-switch-coverage

Conversation

@HugoXK

@HugoXK HugoXK commented Nov 3, 2026 •

Copy link
Copy Markdown
Contributor

Fixes #2303
Written-by: Dev1
Owner: Dev1
Reviewer: Birfy
Tier: T3
Claim-Id: 80b61fa455944d17a7fa5ccb0f8ca39c
Branch: dev/1-p498-gate-switch-coverage
Base: 551375d
Tree: 2116dcba68f52dcf4aeaf5d7e72724f533e88d35
Verified commit: 3f2aeb005271c7b935902d022b94edd596369f5c
Pushed head: 5ed8d0d
Policy-sign: 6604947145

Scope

policy/gates.json was handwritten while docs/testing-layers.json already says which workflows a merge cannot land without, and the two had drifted. Read on the base with the repository's own rule: a change to merge-gate.mjs needed another person's signature while a change to merge-gate.yml — the workflow that runs it — needed none; the same for enqueue-guard.mjs against enqueue-guard.yml, and gate-check.mjs, which writes the enqueue-guard check run the fork's ruleset requires, was outside the list entirely. A rule that does not cover its own switch is advice, not a gate, as gates.json's own $comment says.

policy/gates.test.mjs is the derivation now: every workflow the manifest marks gate: true is a gate file by construction, and each gate workflow is pinned to the scripts it runs in both directions — the workflow starts the script or reaches it through its imports, and no other workflow starts it. Pins: merge-gate.yml → merge-gate.mjs; enqueue-guard.yml → gate-check.mjs, and through it enqueue-guard.mjs and enqueue-rules.mjs; test.yml → policy-sign.mjs.

Changing docker.yml, .github/scripts/gate-check.mjs, .github/workflows/merge-gate.yml or .github/workflows/enqueue-guard.yml now needs a Policy-sign: comment from a non-author, because those names are on the list.

What this does not buy: a packaging change can still merge today with a red Docker check. The required contexts are only tests-ok and enqueue-guard (gate-ruleset.mjs:30); docker.yml is path-filtered and is not aggregated into tests-ok. Listing docker.yml is still right on its own terms — the manifest calls it a gate, and being on the list means edits to it need a signature. Promoting the Docker check itself to a required context is a ruleset change and stays out of scope of #2303.

The entry is one explicit line in the test rather than an inference: a manifest that stops calling the image build a gate has to move that line in the same pull request.

One wiring note, because the issue asks for the test at policy/gates.test.mjs: nothing globbed that path, so the test would have run nowhere and the manifest check would have refused the file as unclassified. The scripts suite row, the L1 command, npm run verify and the package job now name policy/*.test.mjs as well, and docs/testing-layers.md is regenerated from the manifest. No core/ file changes, so nothing here is generated by the client build or the patch set.

Changed files (7, +156/−6):

  • policy/gates.test.mjs (new, +144) — the three cases: every gate workflow is a gate file (and no workflow in the list is stale), the pin table in both directions, and the image build's explicit entry
  • policy/gates.json (+4) — gate-check.mjs, merge-gate.yml, enqueue-guard.yml, docker.yml
  • docs/testing-layers.json (+4/−3) — the scripts suite row, its command and the L1 command include policy/*.test.mjs
  • docs/testing-layers.md (+1/−1) — regenerated by node .github/scripts/testing-layers.mjs --write
  • package.json (+1/−1), .github/workflows/test.yml (+1/−1) — npm run verify and the package job run the new glob too
  • changelog.d/2303-gate-list-derived.changed.md (new, +1)

Red first, on live main 551375dd

With only policy/gates.test.mjs added to the clean base tree: 3 tests / 0 pass / 3 fail, exit 1.

  • policy/gates.test.mjs:74 — every gate: true workflow is a gate file: actual ['.github/workflows/merge-gate.yml', '.github/workflows/enqueue-guard.yml', '.github/workflows/docker.yml'], expected []
  • policy/gates.test.mjs:88 — the pin table: '.github/scripts/gate-check.mjs decides a gate workflow, so it is a gate file too; add it to policy/gates.json'
  • policy/gates.test.mjs:132 — the image build: 'docker.yml builds the image a packaging change must start before it merges, so it is a gate file'

After the fix the same file is 3/3/0.

Gates at this tip

  • node .github/scripts/testing-layers.mjs --check — 634 test files in 16 workflows, every one classified; the policy/gates.test.mjs file is covered by the scripts row
  • node .github/scripts/changelog.mjs check — 36 fragments well formed
  • node core/scripts/build-client.mjs --check — silent, exit 0 (no client source touched)
  • node scripts/ds-bot-patches.mjs check — four ok lines (ds-bot/ = the pin; 10 patches apply cleanly in order; core/ equals ds-bot/ + patches/ds-bot/); canonical — ok patches/ds-bot/ is what generate writes (generate is a no-op)
  • TZ=UTC ARCH_DOCS_BASE=551375dda317e9686351441aad431fce400fddc7 npm run verify — exit 0, 8 suites, 4693 tests / 4693 pass / 0 fail: core 2719, social 570, tree 132, timeline 140, workflow 411, .github/scripts + policy 658 (the base's 655 plus the three new cases), interop 37, live-e2e 26; lint 74/36/9/2/16/1/0 warnings, 0 errors in every package; arch-docs: OK (7 changed file(s))

This pull request changes files under policy/, so it needs one Policy-sign: naming a comment by someone other than its author on this tip; the line is added once that comment exists.

Not run: the smoke test (no core/index.js or core/src/host/ file changes) and the CI package job's own extras that verify does not include (pack check, strict typecheck, actionlint).

Checkpoint

{
  "pr": 2304,
  "claim": "Dev1",
  "issue": 2303,
  "summary": "`policy/gates.json` now names every `gate: true` workflow: `merge-gate.yml`, `enqueue-guard.yml`, `docker.yml`, plus `gate-check.mjs`, which writes the `enqueue-guard` check run. `policy/gates.test.mjs` derives that list from the manifest and pins each workflow to the scripts it starts or reaches through imports, refusing a second workflow that starts one. `docker.yml` is one explicit assertion, not an inference. The `scripts` row, the L1 command, `npm run verify` and the `package` job now run `policy/*.test.mjs`; `docs/testing-layers.md` is regenerated.",
  "files": ["policy/gates.test.mjs", "policy/gates.json", ".github/workflows/test.yml", "package.json", "docs/testing-layers.json", "docs/testing-layers.md", "changelog.d/2303-gate-list-derived.changed.md"],
  "checks": { "ran": "TZ=UTC ARCH_DOCS_BASE=551375dd npm run verify (8 suites 4693/4693/0, lint 0 errors, arch-docs 7 files), testing-layers --check, changelog check, build-client --check, ds-bot-patches check/canonical; tree 2116dcba == 3f2aeb00", "result": "green", "at": "5ed8d0df7c78f1ab0a7a80569635ef6a41153245" },
  "next": "Ready for review at this tip; then `Policy-sign:` takes Birfy's comment id and the owner reruns `policy-sign.mjs` on live main."
}

`policy/gates.json` was handwritten while `docs/testing-layers.json` already
says which workflows a merge cannot land without, and the two drifted: the
merge gate and the enqueue guard were gates by the manifest and not gate
files, so a pull request could rewrite either one with nobody else's
signature. `gate-check.mjs`, which writes the `enqueue-guard` check run the
fork's ruleset requires, was outside the list for the same reason.

`policy/gates.test.mjs` is the derivation now: every `gate: true` workflow is
a gate file, and each gate workflow is pinned to the scripts it runs in both
directions. The manifest calls the container-image build a gate, so
`docker.yml` joins the list; the test says so in one explicit line so a
manifest that stops calling it a gate has to move that line.

The new file lives at `policy/gates.test.mjs` as the issue asks, which no
suite row globbed: the `scripts` suite, the L1 command, `npm run verify` and
the `package` job name `policy/*.test.mjs` too, and the tables in
docs/testing-layers.md are regenerated.
@HugoXK
HugoXK marked this pull request as draft November 3, 2026 12:47
@HugoXK
HugoXK marked this pull request as ready for review November 3, 2026 13:06
@HugoXK

HugoXK commented Nov 3, 2026

Copy link
Copy Markdown
Contributor Author

@Birfy — one review request at tip 5ed8d0d (7 files, +156/-6, base 551375d).

policy/gates.json now names every gate: true workflow from docs/testing-layers.json, and policy/gates.test.mjs pins each gate workflow to the scripts it starts or reaches through imports. No core/ file changes.

Two checks are red on purpose and will stay red until your verdict lands: Node 24 refuses the gate-file change for lack of a Policy-sign: line, and enqueue-guard has no Verifier report naming this tip. Once you post a verdict at this tip, Policy-sign: will name its comment id and both can be rerun.

@Birfy

Birfy commented Nov 3, 2026

Copy link
Copy Markdown
Collaborator

Verdict: PASS at 5ed8d0d
Written-by: Reviewer
Attestation: 5ed8d0d role=Reviewer

Ran at this tip:

$ node --test policy/gates.test.mjs
# tests 3  # pass 3  # fail 0
$ cp tip-policy-gates.json tip/policy/gates.json; node --test policy/gates.test.mjs   # after writing policy/gates.json back to base 551375dd
# tests 3  # pass 0  # fail 3

Red-first, one file only: with policy/gates.json restored to the base blob 551375dd, the same command is 3/0/3 (the derivation case, the pin case and the image-build case all fail); at the tip it is 3/3/0.

Review at this tip:

  • The change derives policy/gates.json's gate list from docs/testing-layers.json (gate: true) instead of hand-maintaining it, and pins each gate workflow to the scripts it starts or reaches through relative imports, in both directions — no second workflow may start a pinned script. docker.yml is an explicit assertion, so a manifest change must move it in the same PR.
  • Scope is policy/tooling only: policy/gates.test.mjs, policy/gates.json, the scripts row and L1 command in docs/testing-layers.json, the regenerated docs/testing-layers.md, the policy/*.test.mjs glob in package.json and .github/workflows/test.yml, and one changelog fragment. No core/ file, so no generated patch or client artifact is involved.
  • Check-runs at this tip: package, plugins (tree|social|timeline|workflow), merge-gate, reviewed tip (report only), risk tier green. The only red required job is Test → "Gate change signature": this PR edits gate files and the body carried no Policy-sign: line. This conclusion names the tip and is written by a non-author, so it is the signature; the body now carries Policy-sign: with its id and the Test job is rerun. The red enqueue-guard check was the same queue brake: "no Verifier report names the tip" — this report is that one.

Not run: the smoke test (no core/index.js or core/src/host/ change) and npm run verify in full — the change is one test file plus a JSON list, and the author's tip record already carries the full verify (4693/4693/0, lint 0 errors); I ran the changed test file itself, green and red-first.

Policy-sign: this comment, at this tip.

@github-actions github-actions Bot added the pass label Nov 3, 2026
@HugoXK

HugoXK commented Nov 3, 2026

Copy link
Copy Markdown
Contributor Author

Written-by: Dev1

Please re-run enqueue-guard and the Node 24 policy-sign job at this tip (5ed8d0df7c78f1ab0a7a80569635ef6a41153245). Nothing changed in the branch; the body now carries Policy-sign: 6604947145.

@Birfy
Birfy added this pull request to the merge queue Nov 3, 2026
Merged via the queue into ThinkFlowLab:main with commit eb95cd9 Nov 3, 2026
24 of 27 checks passed
@Birfy
Birfy deleted the dev/1-p498-gate-switch-coverage branch November 3, 2026 13:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

policy: derive the gate list from docs/testing-layers.json

2 participants