fix: align with j4k-align 17.15.4 #18

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

Moves .node-version from Node 26.12.1 to 26.13.0, the version baked into the CI image (node-ci:26-bookworm), so CI stops downloading Node on every run.

The package and README now require Node >=26.0.0, @types/node moves to 26, and CI drops its Node 24.15.0 matrix leg. The next release no longer supports Node 24.

The managed workflows also gain a same-repo-pr job that fails fork and AGit pull requests, and the release job now waits for check-tip. The oxlint config adds the nodeTest preset.

Moves `.node-version` from Node 26.12.1 to 26.13.0, the version baked into the CI image (`node-ci:26-bookworm`), so CI stops downloading Node on every run. The package and README now require Node `>=26.0.0`, `@types/node` moves to 26, and CI drops its Node 24.15.0 matrix leg. The next release no longer supports Node 24. The managed workflows also gain a `same-repo-pr` job that fails fork and AGit pull requests, and the release job now waits for `check-tip`. The oxlint config 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 5s
Checks / quality-checks (pull_request) Successful in 1m5s
Checks / qc-result (pull_request) Has been skipped
Dedupe check / dedupe-check (pull_request) Successful in 1m15s
Review / Review (pull_request_target) Successful in 12m29s
f527abd88f

Review 01M6GVZM4KJ6XBKQ9SD1REMQ2H — head f527abd88fe85b2d824261df21f0b501941466ef

Review — j4k-oss/worktree-add @ 7740819067

Scope: diff against base tree d368d37d4bee
Review finished: 7 succeeded, 0 failed, 3 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 (3)

medium — Fork and AGit refusal tells contributors to push to a repository they cannot push to

  • claim: 01M6GWD3HZSAB3WFJ0SAJ343J3
  • anchor: .forgejo/workflows/commit-msg.yml (snippet)
fork and AGit pull requests skip every guarded check here. Close this pull request, push the branch to this repository, and open a new pull request from it.
  • lens: aposd-plain · arm: default
  • verdicts: 1 valid / 0 invalid / 0 uncertain
    • pass 01M6GWDWQFQVZE9FD0908VQZAS · valid: Grounded: the refusal's only recovery step is 'Close this pull request, push the branch to this repository, and open a new pull request from it.' That step requires write access. The same file's commitlint comment, as quoted by the reviewer, says 'AGit reuses repo identity without push access'. README invites outside pull requests. So the readers this message targets, fork and AGit authors, usually cannot follow it, and a reader who follows the first instruction closes the PR before finding out the second is impossible. That is a concrete mistake under the current text, not a style preference, and it fits the human-facing standard of describing effects as the reader experiences them. The claim does not dispute the refusal policy itself. The smallest fix is one added clause for authors without write access, for example 'or ask a maintainer to push it', keeping the current instruction. The claim's 'medium' is arguable, and low-medium fits an unactionable CI diagnostic that does not alter code behavior. The finding depends on the reviewer's account that the else branch gives no other next step; the anchor excerpt is consistent with that account.
  • disposition: none

The diagnostic's only recovery step is unavailable to the people most likely to read it. A contributor who opened a fork or AGit PR normally has no write access, so they get a red check and an instruction to close their PR and push a branch they cannot push. They have no stated next step, such as asking a maintainer to carry the branch.

The same file says so: the commitlint guard comment reads "AGit reuses repo identity without push access". README.md invites outside contributions: "open issues and pull requests on the Forge". The else branch of the same-repo-pr step prints the quoted message for every fork or AGit PR, without knowing whether the author has write access. Refusing these PRs is a selected policy and I am not disputing it; the defect is that the error does not give its reader a way to recover.

The message should name a step that works without write access, for example asking a maintainer to push the branch to this repository and open the PR, and it should keep the current instruction for authors who do have write access. The first paragraph's claim about the reader depends on who opens such PRs.

I read the same-repo-pr job, the commitlint guard comment and README.md. I did not run the workflow or inspect the repository's collaborator settings, which are not in the tree. A policy that fork or AGit PRs come only from people with write access would refute the claim; I found no such statement in README.md or AGENTS.md.

low — same-repo-pr detects skipped CI by restating why guards skip, so a guard edit silently disables it

  • claim: 01M6GWD2PX12RZDBW0MKMNH5ZB
  • 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 01M6GWDWQFQVZE9FD0908VQZAS · valid: Grounded: the same-repo-pr 'if' is the hand-written negation of the guard (head.repo.full_name != github.repository || toJSON(flow) != '0'). The reviewer's trace, corroborated by claim 01M6GWD4BGTGS0RJ1NYVJDY22A's quotes from checks.yml and dedupe-check.yml ('commit-msg.yml's same-repo-pr job fails them instead') and claim 01M6GWD3HZSAB3WFJ0SAJ343J3's commitlint guard comment, shows that the one decision 'which PRs get no CI' is encoded in commitlint, quality-checks, dedupe-check and this complement. Only a comment ties them together. This is the Information Leakage red flag with a concrete consequence: narrowing a guard skips the job, the skip reads green, and same-repo-pr stays silent. The reviewer concedes that nothing is misclassified today. A latent maintenance hazard is what this red flag describes, so low severity fits. The proposed always()/needs verdict pattern already exists in qc-result. Because needs cannot cross workflows, each guarded workflow would need its own verdict job, and the reviewer states that cost. The shell's FLOW != "1" test only chooses the message, so it is weaker evidence of re-derivation, but that does not affect the main finding.
  • disposition: none

The job catches a skip by hand-copying the guard's negation rather than observing the skip. The knowledge of which PRs get no CI now has to stay aligned across four places, and nothing fails when they drift. If a maintainer tightens the guard on quality-checks or dedupe-check (say, a new exclusion on an actor or label), those PRs skip that job and read green while same-repo-pr stays quiet. That is exactly the silent no-CI outcome this job's comment says it prevents. No present PR is misclassified: today the condition is the correct negation of the guards.

The comment calls the condition "the guard's exact complement", and only that comment ties them together. The positive form is spelled separately in commitlint (commit-msg.yml), quality-checks (checks.yml) and dedupe-check (dedupe-check.yml). The run step then re-derives the split a further time in shell: [ "${HEAD_REPO}" = "${GITHUB_REPOSITORY}" ] && [ "${FLOW}" != "1" ]. This is the Information Leakage red flag: one decision is encoded in several modules.

The same file set already solves this problem without restating a guard. qc-result in checks.yml uses always(), needs: [reuse, quality-checks] and reads needs.quality-checks.result, failing unless the job actually succeeded, whatever the reason for a skip. It is limited to inputs.release_gate == true. A PR-side verdict of the same shape would catch any skip and need no copy of the guard, though each guarded workflow would need its own verdict job, and dedupe-check would need one too.

I read all four guards and qc-result in the tree. This is static reasoning; I ran no workflow, and I did not verify that Forgejo reports needs.<job>.result as skipped on pull_request events, though qc-result relies on it for release runs. A mechanical check that compares these conditions would refute the "nothing fails on drift" part; I found none in the workflows, package.json scripts or scripts/.

low — Repo-wide CI gate lives in the commit-message workflow, tying quality-checks' safety to an unrelated policy

  • claim: 01M6GWD4BGTGS0RJ1NYVJDY22A
  • anchor: .forgejo/workflows/commit-msg.yml (snippet)
# Every guarded job skips fork and AGit PRs, and Forgejo counts a skipped job
  • lens: aposd-plain · arm: default
  • verdicts: 1 valid / 0 invalid / 0 uncertain
    • pass 01M6GWDWQFQVZE9FD0908VQZAS · valid: Grounded: commit-msg.yml's comment says every guarded job skips fork and AGit PRs and Forgejo counts the skip as passing, so this file now holds the only gate for quality-checks and dedupe-check. The reviewer quotes the file header as 'Enforce commit-message policy before merge; see the validation step below.' and quotes checks.yml and dedupe-check.yml pointing to 'commit-msg.yml's same-repo-pr job'. So the dependency is visible only from the dependent files. A maintainer who removes or rewrites commit-msg.yml for commit-policy reasons gets no warning from the file's stated purpose. That is a concrete nonobvious hidden dependency, and the misleading header is a supported, independent defect. Moving the job is a preferred alternative that this batch cannot establish: the reviewer concedes the edited trigger, checks.yml's workflow_call use, or j4k-align templates may constrain placement. The supported correction is the smaller one the claim also offers: state in the header that the file hosts the repo-wide fork/AGit and flow-drift gate, and why. The Special-General Mixture label and the job-name point are weaker. Low severity is appropriate.
  • disposition: none

The only thing that turns a skipped quality-checks or dedupe-check into a failure, and the only detector of a dropped Forgejo flow field, is now a job in a workflow about commit messages. Someone who disables or removes commit-msg.yml because they are changing commit-message policy also removes that protection, with no error: every guarded job on a fork or AGit PR goes back to reading green. A reader of the file gets no warning from its stated purpose, because the header still says only "Enforce commit-message policy before merge; see the validation step below."

The dependency runs across files in comments alone: checks.yml and dedupe-check.yml each say "commit-msg.yml's same-repo-pr job fails them instead". The same-repo-pr job shares no step, input or concern with commitlint, which makes this a Special-General Mixture. The job also merges two separate conditions, fork or AGit refusal and Forgejo payload drift, under a name that describes only the first. Its step has to separate them again to choose an error message.

checks.yml is the workflow that owns the main guarded job and also runs on every PR with no path filter; the removed pr-flow-canary lived there. A dedicated workflow file, or checks.yml, would let the gate's name and header state its purpose. If the move to commit-msg.yml exists to cover the edited trigger or because checks.yml is also workflow_call-able, the header comment should say that the file also hosts the gate and why.

I read all three workflows and the diff. The base-side reason for the move is not available to me, and I could not see j4k-align's templates, so a constraint there could explain the placement. That would justify the location but not the header that omits it.

Other claims

  • grounding-pending (0)
  • ungrounded (0)
  • rejected (0)
  • duplicate-of (0)
  • unadjudicated (0)

Coverage

Coverage pass: 01M6GVZM4PVMRRQX3P66PB97H3
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
project-docs whole default no-claims 1 no
unix-cli whole 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
  • use-effect — skipped-by-dispatch: no React code or Effects changed
  • react — skipped-by-dispatch: no React components, manifests or callers changed
<!-- review:summary --> **Review** `01M6GVZM4KJ6XBKQ9SD1REMQ2H` — head `f527abd88fe85b2d824261df21f0b501941466ef` # Review — j4k-oss/worktree-add @ 7740819067ae Scope: diff against base tree `d368d37d4bee` Review finished: 7 succeeded, 0 failed, 3 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 (3) ### medium — Fork and AGit refusal tells contributors to push to a repository they cannot push to - claim: `01M6GWD3HZSAB3WFJ0SAJ343J3` - anchor: `.forgejo/workflows/commit-msg.yml` (snippet) ``` fork and AGit pull requests skip every guarded check here. Close this pull request, push the branch to this repository, and open a new pull request from it. ``` - lens: aposd-plain · arm: default - verdicts: 1 valid / 0 invalid / 0 uncertain - pass `01M6GWDWQFQVZE9FD0908VQZAS` · valid: Grounded: the refusal's only recovery step is 'Close this pull request, push the branch to this repository, and open a new pull request from it.' That step requires write access. The same file's commitlint comment, as quoted by the reviewer, says 'AGit reuses repo identity without push access'. README invites outside pull requests. So the readers this message targets, fork and AGit authors, usually cannot follow it, and a reader who follows the first instruction closes the PR before finding out the second is impossible. That is a concrete mistake under the current text, not a style preference, and it fits the human-facing standard of describing effects as the reader experiences them. The claim does not dispute the refusal policy itself. The smallest fix is one added clause for authors without write access, for example 'or ask a maintainer to push it', keeping the current instruction. The claim's 'medium' is arguable, and low-medium fits an unactionable CI diagnostic that does not alter code behavior. The finding depends on the reviewer's account that the else branch gives no other next step; the anchor excerpt is consistent with that account. - disposition: none > The diagnostic's only recovery step is unavailable to the people most likely to read it. A contributor who opened a fork or AGit PR normally has no write access, so they get a red check and an instruction to close their PR and push a branch they cannot push. They have no stated next step, such as asking a maintainer to carry the branch. > > The same file says so: the `commitlint` guard comment reads "AGit reuses repo identity without push access". README.md invites outside contributions: "open issues and pull requests on the Forge". The `else` branch of the `same-repo-pr` step prints the quoted message for every fork or AGit PR, without knowing whether the author has write access. Refusing these PRs is a selected policy and I am not disputing it; the defect is that the error does not give its reader a way to recover. > > The message should name a step that works without write access, for example asking a maintainer to push the branch to this repository and open the PR, and it should keep the current instruction for authors who do have write access. The first paragraph's claim about the reader depends on who opens such PRs. > > I read the `same-repo-pr` job, the `commitlint` guard comment and README.md. I did not run the workflow or inspect the repository's collaborator settings, which are not in the tree. A policy that fork or AGit PRs come only from people with write access would refute the claim; I found no such statement in README.md or AGENTS.md. ### low — same-repo-pr detects skipped CI by restating why guards skip, so a guard edit silently disables it - claim: `01M6GWD2PX12RZDBW0MKMNH5ZB` - 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 `01M6GWDWQFQVZE9FD0908VQZAS` · valid: Grounded: the same-repo-pr 'if' is the hand-written negation of the guard (head.repo.full_name != github.repository || toJSON(flow) != '0'). The reviewer's trace, corroborated by claim 01M6GWD4BGTGS0RJ1NYVJDY22A's quotes from checks.yml and dedupe-check.yml ('commit-msg.yml's same-repo-pr job fails them instead') and claim 01M6GWD3HZSAB3WFJ0SAJ343J3's commitlint guard comment, shows that the one decision 'which PRs get no CI' is encoded in commitlint, quality-checks, dedupe-check and this complement. Only a comment ties them together. This is the Information Leakage red flag with a concrete consequence: narrowing a guard skips the job, the skip reads green, and same-repo-pr stays silent. The reviewer concedes that nothing is misclassified today. A latent maintenance hazard is what this red flag describes, so low severity fits. The proposed always()/needs verdict pattern already exists in qc-result. Because needs cannot cross workflows, each guarded workflow would need its own verdict job, and the reviewer states that cost. The shell's FLOW != "1" test only chooses the message, so it is weaker evidence of re-derivation, but that does not affect the main finding. - disposition: none > The job catches a skip by hand-copying the guard's negation rather than observing the skip. The knowledge of which PRs get no CI now has to stay aligned across four places, and nothing fails when they drift. If a maintainer tightens the guard on `quality-checks` or `dedupe-check` (say, a new exclusion on an actor or label), those PRs skip that job and read green while `same-repo-pr` stays quiet. That is exactly the silent no-CI outcome this job's comment says it prevents. No present PR is misclassified: today the condition is the correct negation of the guards. > > The comment calls the condition "the guard's exact complement", and only that comment ties them together. The positive form is spelled separately in `commitlint` (commit-msg.yml), `quality-checks` (checks.yml) and `dedupe-check` (dedupe-check.yml). The run step then re-derives the split a further time in shell: `[ "${HEAD_REPO}" = "${GITHUB_REPOSITORY}" ] && [ "${FLOW}" != "1" ]`. This is the Information Leakage red flag: one decision is encoded in several modules. > > The same file set already solves this problem without restating a guard. `qc-result` in checks.yml uses `always()`, `needs: [reuse, quality-checks]` and reads `needs.quality-checks.result`, failing unless the job actually succeeded, whatever the reason for a skip. It is limited to `inputs.release_gate == true`. A PR-side verdict of the same shape would catch any skip and need no copy of the guard, though each guarded workflow would need its own verdict job, and `dedupe-check` would need one too. > > I read all four guards and `qc-result` in the tree. This is static reasoning; I ran no workflow, and I did not verify that Forgejo reports <code>needs.&lt;job&gt;.result</code> as `skipped` on `pull_request` events, though `qc-result` relies on it for release runs. A mechanical check that compares these conditions would refute the "nothing fails on drift" part; I found none in the workflows, `package.json` scripts or `scripts/`. ### low — Repo-wide CI gate lives in the commit-message workflow, tying quality-checks' safety to an unrelated policy - claim: `01M6GWD4BGTGS0RJ1NYVJDY22A` - anchor: `.forgejo/workflows/commit-msg.yml` (snippet) ``` # Every guarded job skips fork and AGit PRs, and Forgejo counts a skipped job ``` - lens: aposd-plain · arm: default - verdicts: 1 valid / 0 invalid / 0 uncertain - pass `01M6GWDWQFQVZE9FD0908VQZAS` · valid: Grounded: commit-msg.yml's comment says every guarded job skips fork and AGit PRs and Forgejo counts the skip as passing, so this file now holds the only gate for quality-checks and dedupe-check. The reviewer quotes the file header as 'Enforce commit-message policy before merge; see the validation step below.' and quotes checks.yml and dedupe-check.yml pointing to 'commit-msg.yml's same-repo-pr job'. So the dependency is visible only from the dependent files. A maintainer who removes or rewrites commit-msg.yml for commit-policy reasons gets no warning from the file's stated purpose. That is a concrete nonobvious hidden dependency, and the misleading header is a supported, independent defect. Moving the job is a preferred alternative that this batch cannot establish: the reviewer concedes the edited trigger, checks.yml's workflow_call use, or j4k-align templates may constrain placement. The supported correction is the smaller one the claim also offers: state in the header that the file hosts the repo-wide fork/AGit and flow-drift gate, and why. The Special-General Mixture label and the job-name point are weaker. Low severity is appropriate. - disposition: none > The only thing that turns a skipped `quality-checks` or `dedupe-check` into a failure, and the only detector of a dropped Forgejo `flow` field, is now a job in a workflow about commit messages. Someone who disables or removes commit-msg.yml because they are changing commit-message policy also removes that protection, with no error: every guarded job on a fork or AGit PR goes back to reading green. A reader of the file gets no warning from its stated purpose, because the header still says only "Enforce commit-message policy before merge; see the validation step below." > > The dependency runs across files in comments alone: checks.yml and dedupe-check.yml each say "commit-msg.yml's same-repo-pr job fails them instead". The `same-repo-pr` job shares no step, input or concern with `commitlint`, which makes this a Special-General Mixture. The job also merges two separate conditions, fork or AGit refusal and Forgejo payload drift, under a name that describes only the first. Its step has to separate them again to choose an error message. > > checks.yml is the workflow that owns the main guarded job and also runs on every PR with no path filter; the removed `pr-flow-canary` lived there. A dedicated workflow file, or checks.yml, would let the gate's name and header state its purpose. If the move to commit-msg.yml exists to cover the `edited` trigger or because checks.yml is also `workflow_call`-able, the header comment should say that the file also hosts the gate and why. > > I read all three workflows and the diff. The base-side reason for the move is not available to me, and I could not see j4k-align's templates, so a constraint there could explain the placement. That would justify the location but not the header that omits it. ## Other claims - grounding-pending (0) - ungrounded (0) - rejected (0) - duplicate-of (0) - unadjudicated (0) ## Coverage Coverage pass: 01M6GVZM4PVMRRQX3P66PB97H3 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 | | project-docs | whole | default | no-claims | 1 | no | | unix-cli | whole | 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 - use-effect — skipped-by-dispatch: no React code or Effects changed - react — skipped-by-dispatch: no React components, manifests or callers changed
@ -128,2 +127,4 @@
done < "$pr_fields/commits"
exit "$failed"
# Every guarded job skips fork and AGit PRs, and Forgejo counts a skipped job

low — Repo-wide CI gate lives in the commit-message workflow, tying quality-checks' safety to an unrelated policy

The only thing that turns a skipped quality-checks or dedupe-check into a failure, and the only detector of a dropped Forgejo flow field, is now a job in a workflow about commit messages. Someone who disables or removes commit-msg.yml because they are changing commit-message policy also removes that protection, with no error: every guarded job on a fork or AGit PR goes back to reading green. A reader of the file gets no warning from its stated purpose, because the header still says only "Enforce commit-message policy before merge; see the validation step below."

The dependency runs across files in comments alone: checks.yml and dedupe-check.yml each say "commit-msg.yml's same-repo-pr job fails them instead". The same-repo-pr job shares no step, input or concern with commitlint, which makes this a Special-General Mixture. The job also merges two separate conditions, fork or AGit refusal and Forgejo payload drift, under a name that describes only the first. Its step has to separate them again to choose an error message.

checks.yml is the workflow that owns the main guarded job and also runs on every PR with no path filter; the removed pr-flow-canary lived there. A dedicated workflow file, or checks.yml, would let the gate's name and header state its purpose. If the move to commit-msg.yml exists to cover the edited trigger or because checks.yml is also workflow_call-able, the header comment should say that the file also hosts the gate and why.

I read all three workflows and the diff. The base-side reason for the move is not available to me, and I could not see j4k-align's templates, so a constraint there could explain the placement. That would justify the location but not the header that omits it.

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

<!-- review:claim:01M6GWD4BGTGS0RJ1NYVJDY22A --> **low** — Repo-wide CI gate lives in the commit-message workflow, tying quality-checks' safety to an unrelated policy > The only thing that turns a skipped `quality-checks` or `dedupe-check` into a failure, and the only detector of a dropped Forgejo `flow` field, is now a job in a workflow about commit messages. Someone who disables or removes commit-msg.yml because they are changing commit-message policy also removes that protection, with no error: every guarded job on a fork or AGit PR goes back to reading green. A reader of the file gets no warning from its stated purpose, because the header still says only "Enforce commit-message policy before merge; see the validation step below." > > The dependency runs across files in comments alone: checks.yml and dedupe-check.yml each say "commit-msg.yml's same-repo-pr job fails them instead". The `same-repo-pr` job shares no step, input or concern with `commitlint`, which makes this a Special-General Mixture. The job also merges two separate conditions, fork or AGit refusal and Forgejo payload drift, under a name that describes only the first. Its step has to separate them again to choose an error message. > > checks.yml is the workflow that owns the main guarded job and also runs on every PR with no path filter; the removed `pr-flow-canary` lived there. A dedicated workflow file, or checks.yml, would let the gate's name and header state its purpose. If the move to commit-msg.yml exists to cover the `edited` trigger or because checks.yml is also `workflow_call`-able, the header comment should say that the file also hosts the gate and why. > > I read all three workflows and the diff. The base-side reason for the move is not available to me, and I could not see j4k-align's templates, so a constraint there could explain the placement. That would justify the location but not the header that omits it. lens `aposd-plain` · arm `default` · tally 1 valid / 0 invalid / 0 uncertain claim `01M6GWD4BGTGS0RJ1NYVJDY22A` of review `01M6GVZM4KJ6XBKQ9SD1REMQ2H`
Author
Owner

Confirmed: the fork and AGit gate for every guarded workflow now lives in commit-msg.yml, whose header still describes only commit-message policy. Placement and header both come from j4k-align 17.15.4's templates/workflows/commit-msg.yml.hbs (align #1011 moved the gate there from checks.yml's pr-flow-canary), so a hand edit here would be overwritten by the next j4k-align --fix. Whether to move the job or extend the header is an align template decision. This fleet rollout may not change align, so I've reported it to the user as an align follow-up rather than opening one.

<!-- gh-feedback:reply-to:228770 --> Confirmed: the fork and AGit gate for every guarded workflow now lives in `commit-msg.yml`, whose header still describes only commit-message policy. Placement and header both come from j4k-align 17.15.4's `templates/workflows/commit-msg.yml.hbs` (align #1011 moved the gate there from `checks.yml`'s `pr-flow-canary`), so a hand edit here would be overwritten by the next `j4k-align --fix`. Whether to move the job or extend the header is an align template decision. This fleet rollout may not change align, so I've reported it to the user as an align follow-up rather than opening one.
jercik marked this conversation as resolved
@ -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'

low — same-repo-pr detects skipped CI by restating why guards skip, so a guard edit silently disables it

The job catches a skip by hand-copying the guard's negation rather than observing the skip. The knowledge of which PRs get no CI now has to stay aligned across four places, and nothing fails when they drift. If a maintainer tightens the guard on quality-checks or dedupe-check (say, a new exclusion on an actor or label), those PRs skip that job and read green while same-repo-pr stays quiet. That is exactly the silent no-CI outcome this job's comment says it prevents. No present PR is misclassified: today the condition is the correct negation of the guards.

The comment calls the condition "the guard's exact complement", and only that comment ties them together. The positive form is spelled separately in commitlint (commit-msg.yml), quality-checks (checks.yml) and dedupe-check (dedupe-check.yml). The run step then re-derives the split a further time in shell: [ "${HEAD_REPO}" = "${GITHUB_REPOSITORY}" ] && [ "${FLOW}" != "1" ]. This is the Information Leakage red flag: one decision is encoded in several modules.

The same file set already solves this problem without restating a guard. qc-result in checks.yml uses always(), needs: [reuse, quality-checks] and reads needs.quality-checks.result, failing unless the job actually succeeded, whatever the reason for a skip. It is limited to inputs.release_gate == true. A PR-side verdict of the same shape would catch any skip and need no copy of the guard, though each guarded workflow would need its own verdict job, and dedupe-check would need one too.

I read all four guards and qc-result in the tree. This is static reasoning; I ran no workflow, and I did not verify that Forgejo reports needs.<job>.result as skipped on pull_request events, though qc-result relies on it for release runs. A mechanical check that compares these conditions would refute the "nothing fails on drift" part; I found none in the workflows, package.json scripts or scripts/.

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

<!-- review:claim:01M6GWD2PX12RZDBW0MKMNH5ZB --> **low** — same-repo-pr detects skipped CI by restating why guards skip, so a guard edit silently disables it > The job catches a skip by hand-copying the guard's negation rather than observing the skip. The knowledge of which PRs get no CI now has to stay aligned across four places, and nothing fails when they drift. If a maintainer tightens the guard on `quality-checks` or `dedupe-check` (say, a new exclusion on an actor or label), those PRs skip that job and read green while `same-repo-pr` stays quiet. That is exactly the silent no-CI outcome this job's comment says it prevents. No present PR is misclassified: today the condition is the correct negation of the guards. > > The comment calls the condition "the guard's exact complement", and only that comment ties them together. The positive form is spelled separately in `commitlint` (commit-msg.yml), `quality-checks` (checks.yml) and `dedupe-check` (dedupe-check.yml). The run step then re-derives the split a further time in shell: `[ "${HEAD_REPO}" = "${GITHUB_REPOSITORY}" ] && [ "${FLOW}" != "1" ]`. This is the Information Leakage red flag: one decision is encoded in several modules. > > The same file set already solves this problem without restating a guard. `qc-result` in checks.yml uses `always()`, `needs: [reuse, quality-checks]` and reads `needs.quality-checks.result`, failing unless the job actually succeeded, whatever the reason for a skip. It is limited to `inputs.release_gate == true`. A PR-side verdict of the same shape would catch any skip and need no copy of the guard, though each guarded workflow would need its own verdict job, and `dedupe-check` would need one too. > > I read all four guards and `qc-result` in the tree. This is static reasoning; I ran no workflow, and I did not verify that Forgejo reports <code>needs.&lt;job&gt;.result</code> as `skipped` on `pull_request` events, though `qc-result` relies on it for release runs. A mechanical check that compares these conditions would refute the "nothing fails on drift" part; I found none in the workflows, `package.json` scripts or `scripts/`. lens `aposd-plain` · arm `default` · tally 1 valid / 0 invalid / 0 uncertain claim `01M6GWD2PX12RZDBW0MKMNH5ZB` of review `01M6GVZM4KJ6XBKQ9SD1REMQ2H`
Author
Owner

Confirmed as a maintenance risk: the same-repo-pr condition is the hand-written complement of the guards in commitlint, quality-checks and dedupe-check, and nothing fails if they drift. Today the complement is exact, so no PR is misclassified. All four guards are rendered by j4k-align 17.15.4 (templates/workflows/commit-msg.yml.hbs and the checks and dedupe templates), so a hand edit here would be overwritten by the next j4k-align --fix; replacing the copy with a needs-result verdict like qc-result is an align template decision. This fleet rollout may not change align, so I've reported it to the user as an align follow-up rather than opening one.

<!-- gh-feedback:reply-to:228769 --> Confirmed as a maintenance risk: the `same-repo-pr` condition is the hand-written complement of the guards in `commitlint`, `quality-checks` and `dedupe-check`, and nothing fails if they drift. Today the complement is exact, so no PR is misclassified. All four guards are rendered by j4k-align 17.15.4 (`templates/workflows/commit-msg.yml.hbs` and the checks and dedupe templates), so a hand edit here would be overwritten by the next `j4k-align --fix`; replacing the copy with a `needs`-result verdict like `qc-result` is an align template decision. This fleet rollout may not change align, so I've reported it to the user as an align follow-up rather than opening one.
jercik marked this conversation as resolved
@ -130,0 +145,4 @@
if [ "${HEAD_REPO}" = "${GITHUB_REPOSITORY}" ] && [ "${FLOW}" != "1" ]; then
echo "::error::head repository ${HEAD_REPO}, flow ${FLOW}: this pull request comes from this repository, so Forgejo sent no usable flow and every guarded check was skipped. A maintainer must investigate the Forgejo upgrade or roll it back."
else
echo "::error::head repository ${HEAD_REPO}, flow ${FLOW}: fork and AGit pull requests skip every guarded check here. Close this pull request, push the branch to this repository, and open a new pull request from it."

medium — Fork and AGit refusal tells contributors to push to a repository they cannot push to

The diagnostic's only recovery step is unavailable to the people most likely to read it. A contributor who opened a fork or AGit PR normally has no write access, so they get a red check and an instruction to close their PR and push a branch they cannot push. They have no stated next step, such as asking a maintainer to carry the branch.

The same file says so: the commitlint guard comment reads "AGit reuses repo identity without push access". README.md invites outside contributions: "open issues and pull requests on the Forge". The else branch of the same-repo-pr step prints the quoted message for every fork or AGit PR, without knowing whether the author has write access. Refusing these PRs is a selected policy and I am not disputing it; the defect is that the error does not give its reader a way to recover.

The message should name a step that works without write access, for example asking a maintainer to push the branch to this repository and open the PR, and it should keep the current instruction for authors who do have write access. The first paragraph's claim about the reader depends on who opens such PRs.

I read the same-repo-pr job, the commitlint guard comment and README.md. I did not run the workflow or inspect the repository's collaborator settings, which are not in the tree. A policy that fork or AGit PRs come only from people with write access would refute the claim; I found no such statement in README.md or AGENTS.md.

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

<!-- review:claim:01M6GWD3HZSAB3WFJ0SAJ343J3 --> **medium** — Fork and AGit refusal tells contributors to push to a repository they cannot push to > The diagnostic's only recovery step is unavailable to the people most likely to read it. A contributor who opened a fork or AGit PR normally has no write access, so they get a red check and an instruction to close their PR and push a branch they cannot push. They have no stated next step, such as asking a maintainer to carry the branch. > > The same file says so: the `commitlint` guard comment reads "AGit reuses repo identity without push access". README.md invites outside contributions: "open issues and pull requests on the Forge". The `else` branch of the `same-repo-pr` step prints the quoted message for every fork or AGit PR, without knowing whether the author has write access. Refusing these PRs is a selected policy and I am not disputing it; the defect is that the error does not give its reader a way to recover. > > The message should name a step that works without write access, for example asking a maintainer to push the branch to this repository and open the PR, and it should keep the current instruction for authors who do have write access. The first paragraph's claim about the reader depends on who opens such PRs. > > I read the `same-repo-pr` job, the `commitlint` guard comment and README.md. I did not run the workflow or inspect the repository's collaborator settings, which are not in the tree. A policy that fork or AGit PRs come only from people with write access would refute the claim; I found no such statement in README.md or AGENTS.md. lens `aposd-plain` · arm `default` · tally 1 valid / 0 invalid / 0 uncertain claim `01M6GWD3HZSAB3WFJ0SAJ343J3` of review `01M6GVZM4KJ6XBKQ9SD1REMQ2H`
Author
Owner

Confirmed: the same-repo-pr refusal's only recovery step needs write access, and this repository invites outside pull requests. Not a merge blocker: before this change the same fork or AGit PR skipped every guarded check and read green, so the job still turns a silent pass into a visible failure. The message comes from j4k-align 17.15.4's templates/workflows/commit-msg.yml.hbs, so a hand edit here would be overwritten by the next j4k-align --fix; the fix (add a step for authors without write access, such as asking a maintainer to carry the branch) belongs in that template. This fleet rollout may not change align, so I've reported it to the user as an align follow-up rather than opening one.

<!-- gh-feedback:reply-to:228768 --> Confirmed: the `same-repo-pr` refusal's only recovery step needs write access, and this repository invites outside pull requests. Not a merge blocker: before this change the same fork or AGit PR skipped every guarded check and read green, so the job still turns a silent pass into a visible failure. The message comes from j4k-align 17.15.4's `templates/workflows/commit-msg.yml.hbs`, so a hand edit here would be overwritten by the next `j4k-align --fix`; the fix (add a step for authors without write access, such as asking a maintainer to carry the branch) belongs in that template. This fleet rollout may not change align, so I've reported it to the user as an align follow-up rather than opening one.
jercik marked this conversation as resolved
jercik merged commit 435ebb27f7 into main 2026-11-03 14:25:59 +00:00
jercik deleted branch chore/align-17-15-4 2026-11-03 14:25:59 +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/worktree-add!18
No description provided.