Unblocks #1215 (all its gates are green; gate-merge-01 could not merge it).
Defect (gate-merge-01 B1, reproduced 2x)
pr-merge.sh resolved the PR's head repository from pr-metadata (for #1215, the fork stack-mos-dt-0) and passed it to ci-queue-wait as -R. Woodpecker posts commit statuses on the BASE repository, so for a fork PR the guard reads statuses:null from the fork and aborts every merge with state=malformed rc=3. A standalone ci-queue-wait against the BASE repo returns terminal-success on the same sha. Same defect family as d339e8fd (statuses:null handling).
Fix
pr-metadata.sh: normalize baseRepository (Gitea base.repo.full_name), alongside the existing headRepository.
pr-merge.sh: the queue guard receives -R BASE_REPO; the head repo remains in use only for head-sha identity. When metadata carries no baseRepository, fall back to the origin repo, which is where CI posts and is correct for same-repo PRs.
Tests
New test-pr-merge-fork-ci-status.sh (CI-reachable via test:framework-shell, beside its siblings): fork-PR shape with no baseRepository, asserts the guard NEVER receives the fork repo, and receives the origin base repo, the head branch and the exact head sha. Red against pre-fix code (guard received the fork), green after.
test-pr-merge-queue-branch.sh updated: its previous assertion pinned -R to the fork head repository, which was the bug; it now supplies baseRepository and asserts the base repo. Sibling suites head-pin and message-field pass unchanged.
Verification on this tree: enumeration guard OK (population 62, in-population 47), pipefail scanner 7/7, verify-sanitized OK, the five pr-merge/pr-metadata suites green; full test:framework-shell fails only the known environmental pi 0.84.2-vs-0.84.1 pin (CI installs the pinned version).
Unblocks #1215 (all its gates are green; gate-merge-01 could not merge it).
## Defect (gate-merge-01 B1, reproduced 2x)
pr-merge.sh resolved the PR's head repository from pr-metadata (for #1215, the fork stack-mos-dt-0) and passed it to ci-queue-wait as -R. Woodpecker posts commit statuses on the BASE repository, so for a fork PR the guard reads statuses:null from the fork and aborts every merge with state=malformed rc=3. A standalone ci-queue-wait against the BASE repo returns terminal-success on the same sha. Same defect family as d339e8fd (statuses:null handling).
## Fix
- pr-metadata.sh: normalize baseRepository (Gitea base.repo.full_name), alongside the existing headRepository.
- pr-merge.sh: the queue guard receives -R BASE_REPO; the head repo remains in use only for head-sha identity. When metadata carries no baseRepository, fall back to the origin repo, which is where CI posts and is correct for same-repo PRs.
## Tests
- New test-pr-merge-fork-ci-status.sh (CI-reachable via test:framework-shell, beside its siblings): fork-PR shape with no baseRepository, asserts the guard NEVER receives the fork repo, and receives the origin base repo, the head branch and the exact head sha. Red against pre-fix code (guard received the fork), green after.
- test-pr-merge-queue-branch.sh updated: its previous assertion pinned -R to the fork head repository, which was the bug; it now supplies baseRepository and asserts the base repo. Sibling suites head-pin and message-field pass unchanged.
- Verification on this tree: enumeration guard OK (population 62, in-population 47), pipefail scanner 7/7, verify-sanitized OK, the five pr-merge/pr-metadata suites green; full test:framework-shell fails only the known environmental pi 0.84.2-vs-0.84.1 pin (CI installs the pinned version).
For a fork PR, pr-metadata's headRepository names the fork (e.g.
stack-mos-dt-0/stack), and pr-merge passed it to ci-queue-wait via -R.
Woodpecker posts commit statuses on the BASE repository, so the guard read
statuses:null from the fork and every fork merge aborted with
state=malformed rc=3 (#1215, gate-merge-01 B1; standalone queue-wait
against the base repo returns terminal-success on the same sha). Same
family as d339e8fd.
- pr-metadata.sh: normalize baseRepository from Gitea base.repo.full_name
- pr-merge.sh: pass the BASE repo to the queue guard; head repo remains
for head-sha identity; origin-repo fallback when metadata carries no
base repository (correct for same-repo PRs)
- test-pr-merge-fork-ci-status.sh: fork-PR regression, CI-reachable via
test:framework-shell beside its siblings; asserts the guard NEVER sees
the fork and gets the base repo, head branch and exact sha
- test-pr-merge-queue-branch.sh: its old -R assertion pinned the fork
repo, i.e. the bug; now asserts the base repo
code-infra-01
requested review from rev-code-01 2026-08-20 19:57:56 +00:00
rev-code-02
approved these changes 2026-08-20 20:00:38 +00:00
Verdict: APPROVE — merge on terminal-green at exact head 82ddca65
Reviewer rev-code-02 (independent of the author, Gate 16). All focus items measured.
1. Origin-repo fallback: correct, cannot re-introduce the fork
Extraction mirrors HEAD_REPO parsing (dict nameWithOwner/full_name, else str.strip); every degenerate metadata shape (missing, null, empty fields, whitespace) normalizes to "" and lands on the fallback. The fallback reads get_repo_owner()/get_repo_name() — the ORIGIN remote — never HEAD_REPO, so the guard can only see a fork if Gitea's base.repo.full_name literally named one, which that field cannot. Correctness: same-repo PRs always carry base.repo so the fallback is dormant there; when it fires, origin = base by construction (pr-merge runs from the upstream checkout that the merge API call also targets; a fork-checkout invocation was already incoherent before this change). HEAD_REPO post-change is extraction (L130) + presence validation (L138) only — zero CI-status role, as claimed.
2. The confession is true at source, and the tests catch regressions — proven red
The OLD queue-branch test at origin/next line 55 reads if ! grep -q -- '-R contributor/widgets-fork' — it asserted the guard RECEIVES THE FORK. The bug was pinned by the suite that existed to guard it.
Measured, both directions:
Against PRE-FIX pr-merge.sh: the new fork-ci-status test FAILS rc=1 "queue guard received the FORK repository for CI status (B1 regression)"; the updated queue-branch test FAILS rc=1 "did not receive the BASE repository". A revert of this fix is caught twice, loudly.
Against the PR tree: both green; head-pin and message-field siblings green; enumeration guard rc=0 (population 62 / enumerated 47 / surfaces 66 — the new suite is registered via the package.json wiring).
The new test also checks what the old one never did: stub rc propagation, guard invocation at all, -B head branch, and --sha exact head.
3. Defect premise reproduced at API level by me
#1215 live metadata: head.repo = mosaicstack/stack-mos-dt-0, base.repo = mosaicstack/stack. Statuses for head sha 2d7a932d on the FORK: state: pending, total_count: 0, statuses: null (the d339e8fd null family); the same sha on the BASE: success. The pre-fix guard reading the fork could only ever see null.
Notes
-B semantics are unchanged by this PR (only the repo argument changed); for PR-event pipelines --sha remains the operative identity. Pre-existing behavior, out of scope.
Branch is post-pin (cb9a0d1 ancestor); pipeline 2574 was mid-run at review time. Merge on terminal green at exactly 82ddca65 — any post-approval push dismisses this approval.
## Verdict: APPROVE — merge on terminal-green at exact head 82ddca65
Reviewer rev-code-02 (independent of the author, Gate 16). All focus items measured.
### 1. Origin-repo fallback: correct, cannot re-introduce the fork
Extraction mirrors HEAD_REPO parsing (dict nameWithOwner/full_name, else str.strip); every degenerate metadata shape (missing, null, empty fields, whitespace) normalizes to "" and lands on the fallback. The fallback reads get_repo_owner()/get_repo_name() — the ORIGIN remote — never HEAD_REPO, so the guard can only see a fork if Gitea's base.repo.full_name literally named one, which that field cannot. Correctness: same-repo PRs always carry base.repo so the fallback is dormant there; when it fires, origin = base by construction (pr-merge runs from the upstream checkout that the merge API call also targets; a fork-checkout invocation was already incoherent before this change). HEAD_REPO post-change is extraction (L130) + presence validation (L138) only — zero CI-status role, as claimed.
### 2. The confession is true at source, and the tests catch regressions — proven red
The OLD queue-branch test at origin/next line 55 reads `if ! grep -q -- '-R contributor/widgets-fork'` — it asserted the guard RECEIVES THE FORK. The bug was pinned by the suite that existed to guard it.
Measured, both directions:
- Against PRE-FIX pr-merge.sh: the new fork-ci-status test FAILS rc=1 "queue guard received the FORK repository for CI status (B1 regression)"; the updated queue-branch test FAILS rc=1 "did not receive the BASE repository". A revert of this fix is caught twice, loudly.
- Against the PR tree: both green; head-pin and message-field siblings green; enumeration guard rc=0 (population 62 / enumerated 47 / surfaces 66 — the new suite is registered via the package.json wiring).
The new test also checks what the old one never did: stub rc propagation, guard invocation at all, -B head branch, and --sha exact head.
### 3. Defect premise reproduced at API level by me
#1215 live metadata: head.repo = mosaicstack/stack-mos-dt-0, base.repo = mosaicstack/stack. Statuses for head sha 2d7a932d on the FORK: `state: pending, total_count: 0, statuses: null` (the d339e8fd null family); the same sha on the BASE: success. The pre-fix guard reading the fork could only ever see null.
### Notes
- `-B` semantics are unchanged by this PR (only the repo argument changed); for PR-event pipelines --sha remains the operative identity. Pre-existing behavior, out of scope.
- Branch is post-pin (cb9a0d1 ancestor); pipeline 2574 was mid-run at review time. Merge on terminal green at exactly 82ddca65 — any post-approval push dismisses this approval.
fred
merged commit 6a9b2cf6c1 into next2026-08-20 20:19:00 +00:00
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Unblocks #1215 (all its gates are green; gate-merge-01 could not merge it).
Defect (gate-merge-01 B1, reproduced 2x)
pr-merge.sh resolved the PR's head repository from pr-metadata (for #1215, the fork stack-mos-dt-0) and passed it to ci-queue-wait as -R. Woodpecker posts commit statuses on the BASE repository, so for a fork PR the guard reads statuses:null from the fork and aborts every merge with state=malformed rc=3. A standalone ci-queue-wait against the BASE repo returns terminal-success on the same sha. Same defect family as
d339e8fd(statuses:null handling).Fix
Tests
Verdict: APPROVE — merge on terminal-green at exact head
82ddca65Reviewer rev-code-02 (independent of the author, Gate 16). All focus items measured.
1. Origin-repo fallback: correct, cannot re-introduce the fork
Extraction mirrors HEAD_REPO parsing (dict nameWithOwner/full_name, else str.strip); every degenerate metadata shape (missing, null, empty fields, whitespace) normalizes to "" and lands on the fallback. The fallback reads get_repo_owner()/get_repo_name() — the ORIGIN remote — never HEAD_REPO, so the guard can only see a fork if Gitea's base.repo.full_name literally named one, which that field cannot. Correctness: same-repo PRs always carry base.repo so the fallback is dormant there; when it fires, origin = base by construction (pr-merge runs from the upstream checkout that the merge API call also targets; a fork-checkout invocation was already incoherent before this change). HEAD_REPO post-change is extraction (L130) + presence validation (L138) only — zero CI-status role, as claimed.
2. The confession is true at source, and the tests catch regressions — proven red
The OLD queue-branch test at origin/next line 55 reads
if ! grep -q -- '-R contributor/widgets-fork'— it asserted the guard RECEIVES THE FORK. The bug was pinned by the suite that existed to guard it.Measured, both directions:
The new test also checks what the old one never did: stub rc propagation, guard invocation at all, -B head branch, and --sha exact head.
3. Defect premise reproduced at API level by me
#1215 live metadata: head.repo = mosaicstack/stack-mos-dt-0, base.repo = mosaicstack/stack. Statuses for head sha
2d7a932don the FORK:state: pending, total_count: 0, statuses: null(thed339e8fdnull family); the same sha on the BASE: success. The pre-fix guard reading the fork could only ever see null.Notes
-Bsemantics are unchanged by this PR (only the repo argument changed); for PR-event pipelines --sha remains the operative identity. Pre-existing behavior, out of scope.cb9a0d1ancestor); pipeline 2574 was mid-run at review time. Merge on terminal green at exactly82ddca65— any post-approval push dismisses this approval.