fix: align with j4k-align 17.15.4 #21

Merged
jercik merged 1 commit from chore/align-17-15-4 into main 2026-11-03 14:17:33 +00:00
Owner

Moves .node-version from 26.12.1 to 26.13.0, the Node baked into the node-ci:26-bookworm CI image, so CI runs stop downloading Node from GitHub.

The next release drops Node 24: engines.node rises to >=26.0.0, @types/node to ^26.0.0, the README's requirement to match, and the checks workflow drops its Node 24.15.0 matrix leg to run once on .node-version.

The rest is align's current render of the managed files. A new same-repo-pr job fails fork and AGit PRs, which would otherwise read green with every guarded check skipped, and replaces the pr-flow-canary job. Releases now run only from the branch tip, and oxlint.config.ts adds the nodeTest preset.

Moves `.node-version` from 26.12.1 to 26.13.0, the Node baked into the `node-ci:26-bookworm` CI image, so CI runs stop downloading Node from GitHub. The next release drops Node 24: `engines.node` rises to `>=26.0.0`, `@types/node` to `^26.0.0`, the README's requirement to match, and the checks workflow drops its Node 24.15.0 matrix leg to run once on `.node-version`. The rest is align's current render of the managed files. A new `same-repo-pr` job fails fork and AGit PRs, which would otherwise read green with every guarded check skipped, and replaces the `pr-flow-canary` job. Releases now run only from the branch tip, and `oxlint.config.ts` adds the `nodeTest` preset.
fix: align with j4k-align 17.15.4
All checks were successful
Checks / reuse (pull_request) Has been skipped
commit-msg / same-repo-pr (pull_request) Has been skipped
commit-msg / commitlint (pull_request) Successful in 4s
Dedupe check / dedupe-check (pull_request) Successful in 11s
Checks / quality-checks (pull_request) Successful in 18s
Checks / qc-result (pull_request) Has been skipped
Review / Review (pull_request_target) Successful in 6m38s
dd88066a2d

Review 01M6GVF6ZVW02M412RX28YQ68B — head dd88066a2df7520e7ce0644aca492925c39713fb

Review — j4k-oss/fta-check @ d4b4389ee4

Scope: diff against base tree 6c125be78ce4
Review finished: 6 succeeded, 0 failed, 4 skipped by dispatch
Triage: settled
Facts: current review-wide projection

Computed under:

{
  "abandonment": "abandonment-v1",
  "anchor_recipe": 1,
  "batch_policy": "batch-v1",
  "coverage": "coverage-v3",
  "dispatch_policy": "dispatch-v2",
  "grounder_version": 1,
  "grounding_read_rule": "grounding-read-v1",
  "promotion_policy": "promotion-v1",
  "report": "report-v5",
  "tally": "tally-v1",
  "triage_settle": "triage-settle-v2"
}

Findings (1)

medium — The fork/AGit trust rule now lives in four hand-kept copies, and same-repo-pr restates its negation with nothing tying the two together

  • claim: 01M6GVQKPJ3JWV0ZTKRQG2SECZ
  • anchor: .forgejo/workflows/commit-msg.yml (snippet)
    if: github.event.pull_request.head.repo.full_name != github.repository || toJSON(github.event.pull_request.flow) != '0'
  • lens: aposd-plain · arm: default
  • verdicts: 1 valid / 0 invalid / 0 uncertain
    • pass 01M6GVRWP8QCCN0QRVFHAJKBJ8 · valid: Grounded (exact) anchor shows the new same-repo-pr job's condition is a hand-written negation of the trust predicate: head.repo.full_name != github.repository || toJSON(flow) != '0'. The body quotes the positive guard used by commitlint, quality-checks (checks.yml) and dedupe-check (dedupe-check.yml), and the comments it cites say those guarded jobs rely on commit-msg.yml's same-repo-pr to fail fork/AGit PRs. One design decision, who counts as trusted, is therefore encoded in four places that must change together. The complement is correct only while all four agree, and nothing checks that. This is APoSD's Information Leakage red flag, and the claim gives a concrete cost: if one guard is edited, for example to admit AGit flow 1, without the complement, fork PRs are skipped with no failing job and read green, or every same-repo PR fails. The claim acknowledges that workflow expressions can't be shared across files and limits its fix to the realistic one: compute the predicate once in commit-msg.yml as a job output and drive both commitlint and the refusal from it, plus a drift check or comment for the others. No substantive objection survives. The 'probably because of workflow_call from release.yml' explanation for the placement is the reviewer's inference, but the defect does not depend on it. Medium fits: the duplicated knowledge already spans modules that must change in lockstep.
  • disposition: none

The rule "a PR is trusted only if its head repo is this repo and toJSON(flow) == '0'" is a single design decision, but this change adds a fourth hand-written copy of it. The guards in commit-msg.yml (commitlint), checks.yml (quality-checks) and dedupe-check.yml (dedupe-check) each spell out github.event.pull_request.head.repo.full_name == github.repository && toJSON(github.event.pull_request.flow) == '0'. The new same-repo-pr job writes the negation by hand. Its comment says "This job's condition is the guard's exact complement", but that claim is true only while all four strings agree. Nothing checks that. Suppose someone edits one guard, say to admit trusted AGit flow 1 or to change the toJSON comparison, and leaves the complement alone. Then either fork PRs are skipped by the guard and also skipped by same-repo-pr, so they read green with no CI, which is exactly the failure this job exists to stop. Or every same-repo PR fails. Both outcomes come from editing a different file than the one that breaks.

The change also adds a cross-file dependency. The guarded jobs' comments in checks.yml and dedupe-check.yml now say "commit-msg.yml's same-repo-pr job fails them instead". So those files' safety depends on a job inside a workflow whose stated purpose is "Enforce commit-message policy before merge". If commit-msg.yml is removed, renamed or re-triggered, the protection disappears without notice. This is information leakage, plus special-purpose and general-purpose code mixed in one place. The repo-wide trust check sits in the commit-message workflow, probably because checks.yml is also workflow_called from release.yml, where the same if would fail the release. That reason is not written down anywhere.

Correction: within commit-msg.yml, compute the predicate once. Add a job that reads only event fields and outputs trusted. commitlint would then use needs plus if: needs.<job>.outputs.trusted == 'true', and the refusal would fail when it is not 'true'. That removes the complement from this file. Then write the reason for the placement (it must not run under workflow_call) next to same-repo-pr, so a maintainer doesn't move it back into checks.yml. The other workflows' copies can't share an expression across files. A check that the three guard strings match would at least stop them drifting apart without anyone noticing.

What I examined: the full if: conditions and comments of commitlint and same-repo-pr in commit-msg.yml, quality-checks in checks.yml, and dedupe-check in dedupe-check.yml. I also read the removed pr-flow-canary in the diff and the workflow_call use of checks.yml from release.yml. I found no script in the tree that compares the guard strings. Whether j4k-align renders or checks these workflows is unverified: unlike review.yml, none of them has a "Rendered by j4k-align" header. A drift check outside this repo would weaken the claim.

Other claims

  • grounding-pending (0)
  • ungrounded (0)
  • rejected (1)
    • 01M6GVQXZNFP5FBFXGKT3T2NQS medium — The new engines floor of Node 26.0.0 is promised to users, but CI now runs only 26.13.0, so nothing checks the promise
  • duplicate-of (0)
  • unadjudicated (0)

Coverage

Coverage pass: 01M6GVF70DYMAYCZDQPDVR0T8N
Accounting: complete (all slots terminal; see slot results for failures)
Slot health: healthy

lens part arm unit status runs loss
general-bug whole default no-claims 1 no
writing-quality whole default no-claims 1 no
restated-sets whole default no-claims 1 no
unix-cli workflow-shell default no-claims 1 no
module-design whole default no-claims 1 no
aposd-plain whole default claims-emitted 1 no
  • test-trimming — skipped-by-dispatch: no tests changed
  • project-docs — skipped-by-dispatch: no CONTEXT.md, ADR or project documentation changed beyond a README version line
  • use-effect — skipped-by-dispatch: no React code changed
  • react — skipped-by-dispatch: no React code changed
<!-- review:summary --> **Review** `01M6GVF6ZVW02M412RX28YQ68B` — head `dd88066a2df7520e7ce0644aca492925c39713fb` # Review — j4k-oss/fta-check @ d4b4389ee4dc Scope: diff against base tree `6c125be78ce4` Review finished: 6 succeeded, 0 failed, 4 skipped by dispatch Triage: settled Facts: current review-wide projection Computed under: ```json { "abandonment": "abandonment-v1", "anchor_recipe": 1, "batch_policy": "batch-v1", "coverage": "coverage-v3", "dispatch_policy": "dispatch-v2", "grounder_version": 1, "grounding_read_rule": "grounding-read-v1", "promotion_policy": "promotion-v1", "report": "report-v5", "tally": "tally-v1", "triage_settle": "triage-settle-v2" } ``` ## Findings (1) ### medium — The fork/AGit trust rule now lives in four hand-kept copies, and `same-repo-pr` restates its negation with nothing tying the two together - claim: `01M6GVQKPJ3JWV0ZTKRQG2SECZ` - anchor: `.forgejo/workflows/commit-msg.yml` (snippet) ``` if: github.event.pull_request.head.repo.full_name != github.repository || toJSON(github.event.pull_request.flow) != '0' ``` - lens: aposd-plain · arm: default - verdicts: 1 valid / 0 invalid / 0 uncertain - pass `01M6GVRWP8QCCN0QRVFHAJKBJ8` · valid: Grounded (exact) anchor shows the new same-repo-pr job's condition is a hand-written negation of the trust predicate: head.repo.full_name != github.repository || toJSON(flow) != '0'. The body quotes the positive guard used by commitlint, quality-checks (checks.yml) and dedupe-check (dedupe-check.yml), and the comments it cites say those guarded jobs rely on commit-msg.yml's same-repo-pr to fail fork/AGit PRs. One design decision, who counts as trusted, is therefore encoded in four places that must change together. The complement is correct only while all four agree, and nothing checks that. This is APoSD's Information Leakage red flag, and the claim gives a concrete cost: if one guard is edited, for example to admit AGit flow 1, without the complement, fork PRs are skipped with no failing job and read green, or every same-repo PR fails. The claim acknowledges that workflow expressions can't be shared across files and limits its fix to the realistic one: compute the predicate once in commit-msg.yml as a job output and drive both commitlint and the refusal from it, plus a drift check or comment for the others. No substantive objection survives. The 'probably because of workflow_call from release.yml' explanation for the placement is the reviewer's inference, but the defect does not depend on it. Medium fits: the duplicated knowledge already spans modules that must change in lockstep. - disposition: none > The rule "a PR is trusted only if its head repo is this repo and `toJSON(flow) == '0'`" is a single design decision, but this change adds a fourth hand-written copy of it. The guards in `commit-msg.yml` (commitlint), `checks.yml` (quality-checks) and `dedupe-check.yml` (dedupe-check) each spell out `github.event.pull_request.head.repo.full_name == github.repository && toJSON(github.event.pull_request.flow) == '0'`. The new `same-repo-pr` job writes the negation by hand. Its comment says "This job's condition is the guard's exact complement", but that claim is true only while all four strings agree. Nothing checks that. Suppose someone edits one guard, say to admit trusted AGit flow 1 or to change the toJSON comparison, and leaves the complement alone. Then either fork PRs are skipped by the guard and also skipped by `same-repo-pr`, so they read green with no CI, which is exactly the failure this job exists to stop. Or every same-repo PR fails. Both outcomes come from editing a different file than the one that breaks. > > The change also adds a cross-file dependency. The guarded jobs' comments in `checks.yml` and `dedupe-check.yml` now say "commit-msg.yml's same-repo-pr job fails them instead". So those files' safety depends on a job inside a workflow whose stated purpose is "Enforce commit-message policy before merge". If `commit-msg.yml` is removed, renamed or re-triggered, the protection disappears without notice. This is information leakage, plus special-purpose and general-purpose code mixed in one place. The repo-wide trust check sits in the commit-message workflow, probably because `checks.yml` is also `workflow_call`ed from `release.yml`, where the same `if` would fail the release. That reason is not written down anywhere. > > Correction: within `commit-msg.yml`, compute the predicate once. Add a job that reads only event fields and outputs `trusted`. `commitlint` would then use `needs` plus <code>if: needs.&lt;job&gt;.outputs.trusted == 'true'</code>, and the refusal would fail when it is not `'true'`. That removes the complement from this file. Then write the reason for the placement (it must not run under `workflow_call`) next to `same-repo-pr`, so a maintainer doesn't move it back into `checks.yml`. The other workflows' copies can't share an expression across files. A check that the three guard strings match would at least stop them drifting apart without anyone noticing. > > What I examined: the full `if:` conditions and comments of commitlint and same-repo-pr in `commit-msg.yml`, quality-checks in `checks.yml`, and dedupe-check in `dedupe-check.yml`. I also read the removed `pr-flow-canary` in the diff and the `workflow_call` use of `checks.yml` from `release.yml`. I found no script in the tree that compares the guard strings. Whether j4k-align renders or checks these workflows is unverified: unlike `review.yml`, none of them has a "Rendered by j4k-align" header. A drift check outside this repo would weaken the claim. ## Other claims - grounding-pending (0) - ungrounded (0) - rejected (1) - `01M6GVQXZNFP5FBFXGKT3T2NQS` medium — The new `engines` floor of Node 26.0.0 is promised to users, but CI now runs only 26.13.0, so nothing checks the promise - duplicate-of (0) - unadjudicated (0) ## Coverage Coverage pass: 01M6GVF70DYMAYCZDQPDVR0T8N Accounting: complete (all slots terminal; see slot results for failures) Slot health: healthy | lens | part | arm | unit status | runs | loss | | --- | --- | --- | --- | --- | --- | | general-bug | whole | default | no-claims | 1 | no | | writing-quality | whole | default | no-claims | 1 | no | | restated-sets | whole | default | no-claims | 1 | no | | unix-cli | workflow-shell | default | no-claims | 1 | no | | module-design | whole | default | no-claims | 1 | no | | aposd-plain | whole | default | claims-emitted | 1 | no | - test-trimming — skipped-by-dispatch: no tests changed - project-docs — skipped-by-dispatch: no CONTEXT.md, ADR or project documentation changed beyond a README version line - use-effect — skipped-by-dispatch: no React code changed - react — skipped-by-dispatch: no React code changed
@ -130,0 +132,4 @@
# the guard's exact complement: it fails those PRs and runs none of their code.
# It also fails every PR if Forgejo stops sending a usable `flow`.
same-repo-pr:
if: github.event.pull_request.head.repo.full_name != github.repository || toJSON(github.event.pull_request.flow) != '0'

medium — The fork/AGit trust rule now lives in four hand-kept copies, and same-repo-pr restates its negation with nothing tying the two together

The rule "a PR is trusted only if its head repo is this repo and toJSON(flow) == '0'" is a single design decision, but this change adds a fourth hand-written copy of it. The guards in commit-msg.yml (commitlint), checks.yml (quality-checks) and dedupe-check.yml (dedupe-check) each spell out github.event.pull_request.head.repo.full_name == github.repository && toJSON(github.event.pull_request.flow) == '0'. The new same-repo-pr job writes the negation by hand. Its comment says "This job's condition is the guard's exact complement", but that claim is true only while all four strings agree. Nothing checks that. Suppose someone edits one guard, say to admit trusted AGit flow 1 or to change the toJSON comparison, and leaves the complement alone. Then either fork PRs are skipped by the guard and also skipped by same-repo-pr, so they read green with no CI, which is exactly the failure this job exists to stop. Or every same-repo PR fails. Both outcomes come from editing a different file than the one that breaks.

The change also adds a cross-file dependency. The guarded jobs' comments in checks.yml and dedupe-check.yml now say "commit-msg.yml's same-repo-pr job fails them instead". So those files' safety depends on a job inside a workflow whose stated purpose is "Enforce commit-message policy before merge". If commit-msg.yml is removed, renamed or re-triggered, the protection disappears without notice. This is information leakage, plus special-purpose and general-purpose code mixed in one place. The repo-wide trust check sits in the commit-message workflow, probably because checks.yml is also workflow_called from release.yml, where the same if would fail the release. That reason is not written down anywhere.

Correction: within commit-msg.yml, compute the predicate once. Add a job that reads only event fields and outputs trusted. commitlint would then use needs plus if: needs.<job>.outputs.trusted == 'true', and the refusal would fail when it is not 'true'. That removes the complement from this file. Then write the reason for the placement (it must not run under workflow_call) next to same-repo-pr, so a maintainer doesn't move it back into checks.yml. The other workflows' copies can't share an expression across files. A check that the three guard strings match would at least stop them drifting apart without anyone noticing.

What I examined: the full if: conditions and comments of commitlint and same-repo-pr in commit-msg.yml, quality-checks in checks.yml, and dedupe-check in dedupe-check.yml. I also read the removed pr-flow-canary in the diff and the workflow_call use of checks.yml from release.yml. I found no script in the tree that compares the guard strings. Whether j4k-align renders or checks these workflows is unverified: unlike review.yml, none of them has a "Rendered by j4k-align" header. A drift check outside this repo would weaken the claim.

lens aposd-plain · arm default · tally 1 valid / 0 invalid / 0 uncertain
claim 01M6GVQKPJ3JWV0ZTKRQG2SECZ of review 01M6GVF6ZVW02M412RX28YQ68B

<!-- review:claim:01M6GVQKPJ3JWV0ZTKRQG2SECZ --> **medium** — The fork/AGit trust rule now lives in four hand-kept copies, and `same-repo-pr` restates its negation with nothing tying the two together > The rule "a PR is trusted only if its head repo is this repo and `toJSON(flow) == '0'`" is a single design decision, but this change adds a fourth hand-written copy of it. The guards in `commit-msg.yml` (commitlint), `checks.yml` (quality-checks) and `dedupe-check.yml` (dedupe-check) each spell out `github.event.pull_request.head.repo.full_name == github.repository && toJSON(github.event.pull_request.flow) == '0'`. The new `same-repo-pr` job writes the negation by hand. Its comment says "This job's condition is the guard's exact complement", but that claim is true only while all four strings agree. Nothing checks that. Suppose someone edits one guard, say to admit trusted AGit flow 1 or to change the toJSON comparison, and leaves the complement alone. Then either fork PRs are skipped by the guard and also skipped by `same-repo-pr`, so they read green with no CI, which is exactly the failure this job exists to stop. Or every same-repo PR fails. Both outcomes come from editing a different file than the one that breaks. > > The change also adds a cross-file dependency. The guarded jobs' comments in `checks.yml` and `dedupe-check.yml` now say "commit-msg.yml's same-repo-pr job fails them instead". So those files' safety depends on a job inside a workflow whose stated purpose is "Enforce commit-message policy before merge". If `commit-msg.yml` is removed, renamed or re-triggered, the protection disappears without notice. This is information leakage, plus special-purpose and general-purpose code mixed in one place. The repo-wide trust check sits in the commit-message workflow, probably because `checks.yml` is also `workflow_call`ed from `release.yml`, where the same `if` would fail the release. That reason is not written down anywhere. > > Correction: within `commit-msg.yml`, compute the predicate once. Add a job that reads only event fields and outputs `trusted`. `commitlint` would then use `needs` plus <code>if: needs.&lt;job&gt;.outputs.trusted == 'true'</code>, and the refusal would fail when it is not `'true'`. That removes the complement from this file. Then write the reason for the placement (it must not run under `workflow_call`) next to `same-repo-pr`, so a maintainer doesn't move it back into `checks.yml`. The other workflows' copies can't share an expression across files. A check that the three guard strings match would at least stop them drifting apart without anyone noticing. > > What I examined: the full `if:` conditions and comments of commitlint and same-repo-pr in `commit-msg.yml`, quality-checks in `checks.yml`, and dedupe-check in `dedupe-check.yml`. I also read the removed `pr-flow-canary` in the diff and the `workflow_call` use of `checks.yml` from `release.yml`. I found no script in the tree that compares the guard strings. Whether j4k-align renders or checks these workflows is unverified: unlike `review.yml`, none of them has a "Rendered by j4k-align" header. A drift check outside this repo would weaken the claim. lens `aposd-plain` · arm `default` · tally 1 valid / 0 invalid / 0 uncertain claim `01M6GVQKPJ3JWV0ZTKRQG2SECZ` of review `01M6GVF6ZVW02M412RX28YQ68B`
Author
Owner

The guards are tied together, in align rather than in the rendered files. These workflows are managed renders of j4k-align 17.15.4, and a direct edit is drift that the next audit reports. At tag v17.15.4, src/workflow-untrusted-checkout-auth.test.ts asserts that same-repo-pr's condition is the exact complement of the fork guard (line 1971). It also asserts that every other accepted job guard wraps the fork guard and skips with it (line 1983), and it reports any plain pull_request job whose if: is outside that allowlist. A new guarded job with a different condition, or an edited guard, fails align's tests before it can be rendered into a repository.

Align renders commit-msg.yml with same-repo-pr beside checks.yml in every Forgejo repository it manages: all seven PRs in this rollout add the job. You said yourself that you found no current coverage gap, and no repository receives checks.yml without it.

<!-- gh-feedback:reply-to:228394 --> The guards are tied together, in align rather than in the rendered files. These workflows are managed renders of j4k-align 17.15.4, and a direct edit is drift that the next audit reports. At tag `v17.15.4`, `src/workflow-untrusted-checkout-auth.test.ts` asserts that `same-repo-pr`'s condition is the exact complement of the fork guard (line 1971). It also asserts that every other accepted job guard wraps the fork guard and skips with it (line 1983), and it reports any plain `pull_request` job whose `if:` is outside that allowlist. A new guarded job with a different condition, or an edited guard, fails align's tests before it can be rendered into a repository. Align renders `commit-msg.yml` with `same-repo-pr` beside `checks.yml` in every Forgejo repository it manages: all seven PRs in this rollout add the job. You said yourself that you found no current coverage gap, and no repository receives `checks.yml` without it.
jercik marked this conversation as resolved
jercik merged commit 06f2133281 into main 2026-11-03 14:17:33 +00:00
jercik deleted branch chore/align-17-15-4 2026-11-03 14:17:33 +00:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No assignees
2 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
j4k-oss/fta-check!21
No description provided.