lib/forge-forgejo.sh — Forgejo's mergeable boolean is four conditions, not GitHub's tri-state: 17 of the 18 blocker:conflict writes on this forge were drafts
#236
Labels
No labels
attention
blocked
blocker:ci-red
blocker:conflict
blocker:drill-pending
blocker:unrequested
bug
claimed
documentation
enhancement
epic
merge-next
needs-ruling
needs-triage
offsite
post-merge
ready
release
scope:docs
scope:guards
scope:labels
scope:release-flow
stale
state:addressing
state:bots-reviewing
state:building
state:needs-human
No milestone
No project
No assignees
2 participants
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference: heavy-duty/ceremony#236
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Context
forge_pr_viewtranslates Forgejo's PR object into thegh pr viewshape thereconciler was written against. GitHub's
mergeableis a tri-state(
MERGEABLE/CONFLICTING/UNKNOWN). Forgejo's is a plain boolean, andthat boolean does not mean "no conflicts".
This instance is
8.0.3+gitea-1.22.0(/api/v1/version, read 2026-08-22).Upstream computes the field at
models/issues/pull.go:824-833:Four conditions turn it false. One of them is a conflict.
The fourth is nothing but the title.
IsWorkInProgressisHasWorkInProgressPrefix(pr.Issue.Title)(
pull.go:733-749),and the very same API object reports that predicate on its own as
draft(
services/convert/pull.go:75,84):So on this forge
draft: trueimpliesmergeable: falseby construction —two fields of one struct, one of which is a term of the other. And this fleet
marks a PR draft by putting
WIP:in its title, on every build round, twice.One more thing the boolean is not: absent.
Mergeable bool(
modules/structs/pull.go:37)is a plain non-pointer field with no
omitempty, so the API always sendstrueor
falseand never null for an open PR. Theelse "UNKNOWN"arm of our mappingis unreachable here.
The defect
lib/forge-forgejo.sh:432-434maps the boolean onto the tri-state by reading false as a conflict:
blockers()then emits the label at:525:The comment immediately above that line already argues this issue's case, for
the other backend
(
:519-524):That escape hatch is correct and it is dead code on Forgejo. Three of the
four false conditions land in
CONFLICTING, and the value that triggers nothingcan never be produced.
The observed half — 17 of the 18
blocker:conflictwrites on this forge are draftsMeasured 2026-08-22 over
heavy-duty/crewpulls 55–89 — everyblocker:conflictevent the forge has ever recorded. 18 adds, 18 removes, none standing.
One of the eighteen is a real conflict, and it is the control that proves the
CONFLICTINGarm works. !55,2026-08-18T18:30:33Z: the PR was not a draft(title dropped
WIP:at 17:17:17Z) and had not been pushed since 17:14:36Z, anhour and a quarter earlier. What moved was
main— crew!54 merged at18:26:25Z as
e47c31c, four minutes and eight seconds before the labelappeared, which is the "another PR merges under this one" case
labels-sweep.yml
names. The builder resolved it the way the board asked:
040a7d30at 19:10:44Zis a merge commit whose parents are
5965032ande47c31c— that same !54 merge— and the label came off at 19:32:53Z. Nothing about this arm needs changing.
The other seventeen are draft windows. Each add falls inside a
WIP:-titledwindow, and none follows a push, a base move, or a merge underneath:
WIP:setWIP:droppedTwenty-one
WIP:windows opened in this range. Seventeen drew the label; one(!55, 18:51:26–19:21:35) spent its whole length under the real-conflict label
already standing; and three closed with no sweep inside them — 12m21s (!58),
7m28s (!59) and 1m52s (!80's second). Whether a window is labelled is only
whether a sweep ran in it: latency behind the title runs 1m51s to 20m51s.
A direct experiment, on crew!87, today
Not correlation. Between the last push at 10:09:29Z and the read at
10:17:46Z, no commit moved,
base.shastayed50a6780a,merge_basestayed
50a6780a, and the head stayed891bd843:draftmergeableWIP: fix: preserve complete Forgejo claim timelinestruefalsefix: preserve complete Forgejo claim timelinesfalsetrueThe only edit between the two rows is the title, at 10:17:05Z. And the merge
that
falsewas describing is a fast-forward —merge_base == base.sha == main,so the head already contains
mainand a conflict is arithmetically impossibleat both readings. Confirmed offline:
git merge-base build/84-pagination-claim origin/mainreturns50a6780a, whichis
origin/main.blocker:conflictstood on crew!87 over a branch git says cannot conflict, from10:02:49Z to 10:29:20Z — 26m31s, and 12m15s of that was after the
WIP:prefix came off at 10:17:05Z. It is recorded on that PR, at
crew!87 10:37Z.
Stamped 2026-08-22T10:35Z by triage. As minted, ten minutes earlier, this
paragraph and the last row of the table above said the label was standing.
The reconciler took it off at 10:29:20Z, which closed the seventeenth window and
made this the first row in the table whose whole life is measured rather than
still running. Nothing about the defect changes — the label was false for
every one of those 26m31s, for the reason given above, and the count moves from
"18 adds, 17 removes, one standing" to 18 and 18. The window closing is what this
defect does on its own; it is not the defect being fixed.
What it costs
A blocker is the board's word for the builder owes work before this can move.
BUILDER.md
makes handoff conditional on "no
blocker:*standing" and:278
spells this one out as "conflicts rebased". So for the whole of every draft
window — which is the whole of every build round and every fix round — the board
tells the builder it owes a rebase, and tells a reviewer and the operator that
the PR does not merge. Both are false, and the rebase the board asks for would
rewrite pushed history on a branch that is already a fast-forward.
It is not currently gating an engine: crew's builder launches rebase sessions
only on
(.isDraft | not) and .mergeable == "CONFLICTING"(
shared/lib/duty-builder.sh:2437-2447), and that draft filter happens toexclude exactly the condition, because Forgejo's
draftand the WIP term ofmergeableare the same predicate. That is luck: the filter's stated purpose is"a panel must never be requested on a draft", not "the boolean lies about
drafts". The cost today is the reading, and the reading is what a blocker label
is for.
The latent half — the conflict-check window
PullRequestStatusCheckingandPullRequestStatusErrorare the other two falseconditions, and no draft filter covers them. A non-draft PR whose conflict check
is still queued reports
mergeable: false, which this mapping callsCONFLICTING— precisely the flap the:519-524comment refuses to cause onGitHub.
Not observed, and this issue does not claim it as a sighting. Of the 18 adds
in the range above, seventeen are draft windows and one is the real !55 conflict;
not one is a check window. It is in scope because it is the same one-line
mapping, and because the value the code already reserves for "do not know" is
currently unreachable — which is also why arm 3 below exists.
The fix
Report
CONFLICTINGonly for what Forgejo can actually distinguish as aconflict, and
UNKNOWN— the value that triggers nothing — for the rest.forge_pr_viewalready holds every field this needs; nothing new is fetched.Spec
Replace the mapping at
lib/forge-forgejo.sh:432-434with four ordered arms:Each arm answers a different question, and the ordering is load-bearing:
draftfirst. WIP suppresses the boolean unconditionally, so on a draftthe boolean carries no merge information at all and
UNKNOWNis the onlyhonest report. It is deliberately not
MERGEABLE: a draft can genuinelyconflict, and certifying the unmeasured as green is the exact shape of #136.
This arm must precede the
mergeable == truearm so that the reading is"we did not measure", not "we measured and it passed".
mergeable == true→MERGEABLE, unchanged.trueis reachable onlywhen the check ran and passed and the PR is not WIP.
UNKNOWN.The head contains the base tip, so the merge is a fast-forward and
PullRequestStatusConflictis unreachable; false there isCheckingorError.merge_baseandbase.shaare both already in the object beingread, on the single-PR route and the list route alike (measured on this
instance 2026-08-22 across crew's three open PRs). This arm can never mask a
real conflict, because the condition it tests makes one impossible.
CONFLICTING, unchanged.Arm 3 narrows the check window; it does not close it. A branch that is
behind its base and merely mid-check still reads
CONFLICTING. Nothing inForgejo's API distinguishes that from a real conflict — there is no status enum,
no
conflicted_files, no rerun handle(
modules/structs/pull.goin full) — and closing it would need a merge trial the shim has no repository to
run. Saying so here is the point: the remaining window is known, bounded, and
not a thing to discover twice.
lib/forge-github.shis not touched. It readsgh's real tri-state, where allfour conditions are already distinct, and this issue changes no policy above the
backend.
Out of scope, deliberately:
blockers(),decide_state,round_state, andevery other consumer of
MERGEABLE. All are correct given a correctly reportedvalue; this issue fixes the report.
Tasks
test/forge-backends.test.sh, beside the existingforge_pr_viewblock at:584-618,
add a draft fixture (
draft:true, mergeable:false) assertingUNKNOWN.It fails today with
CONFLICTING.draft:false, mergeable:false, merge_base == base.sha) assertingUNKNOWN. It fails today withCONFLICTING.draft:false, mergeable:false, merge_base != base.sha) assertingCONFLICTING. It passes today.draft:true, mergeable:trueyieldsUNKNOWN. Note in the fixture that this input is unreachable on the forge—
Mergeable()ANDs in!IsWorkInProgress— and that the case exists topin arm 1 ahead of arm 2, not to model a real read.
lib/forge-forgejo.sh:432-434, carrying acomment that names the four upstream conditions and why
draftis readfirst.
lib/forge-github.sh's existingforge_pr_viewassertions pass unedited.changelog.d/<this issue>.md.Acceptance criteria
forge_pr_viewreturnsUNKNOWNfor a draft PR reportingmergeable: false. Recorded RED first: the same fixture returnsCONFLICTINGon the unfixed tree, and the PR shows both outputs.forge_pr_viewreturnsUNKNOWNfor a non-draft PR reportingmergeable: falsewhosemerge_baseequalsbase.sha. Recorded REDfirst against the unfixed tree in the same way.
forge_pr_viewstill returnsCONFLICTINGfor a non-draftmergeable: falsewhosemerge_basediffers frombase.sha, and stillreturns
MERGEABLEformergeable: true— the existing assertion at:617-618 passes unedited.
mergeable: truereturnsUNKNOWN, proving arm 1precedes arm 2.
lib/forge-github.shhas no diff, and no assertion currently intest/forge-backends.test.shis deleted or weakened; the file's assertioncount rises.
Test plan
Home is
test/forge-backends.test.sh— no network, a stubbedforge_apithatserves fixture JSON per route, which is exactly the shape this defect needs. Its
forge_pr_viewblock at :584-618 already stubs{"head":{"sha":"abc"},"mergeable":true}and asserts the mapped string; extendthat stub with
draft,merge_baseandbase.sharather than starting a newblock.
Cases that must fail before and pass after:
draft:true, mergeable:false→UNKNOWN. Fails today withCONFLICTING.draft:false, mergeable:false, merge_base == base.sha→UNKNOWN.Fails today with
CONFLICTING.Cases that must keep passing untouched:
draft:false, mergeable:true→MERGEABLE(the assertion already at :617).draft:false, mergeable:false, merge_base != base.sha→CONFLICTING.lib/forge-github.shassertion in the file.Ordering evidence rather than a behaviour claim:
draft:true, mergeable:true→UNKNOWN. Unreachable on the forge; it existsso that reordering arms 1 and 2 turns the suite red.
Live control — the crew!87 specimen is spent; the mechanism is not. crew!87
merged 2026-08-22T10:56:11Z and now reads
draft:false, mergeable:trueat891bd843for good, so the before/after pair can no longer be taken off it. Whatmade it a control was never that pull request:
Mergeable()takesIsWorkInProgress()as a term(
pull.go:824-833)and
Draftreports the same predicate on the same struct(
convert/pull.go:75,84),so any
WIP:title edit on any open pull request flipsmergeablewiththe head,
merge_baseandbase.shaall fixed. Read/api/v1/repos/heavy-duty/crew/pulls/{n}either side of the next one.Read 2026-08-23, that next one arrived three minutes after this issue was
claimed, and it is this issue's own PR. !242 opened
WIP:-titled at2026-08-23T17:40:56Z;
forgejo-actionswroteblocker:conflicton it at17:41:21Z; the
WIP:prefix came off at 17:45:44Z — a title edit, withno push after 17:41:52Z — and at 17:49:54Z the PR read
draft:false, mergeable:trueat8f9f7e56withblocker:conflictstillstanding. All three of its commits sit on top of base
1f5dd39a(
merge_base == base.shaat the read), so a conflict was arithmeticallyimpossible at every head it has had: the label was false when written and still
false 8m33s later.
What this specimen cannot say, and crew!87 could: 25 seconds after an open,
PullRequestStatusCheckingis not excluded, so thefalsebehind that write isnot attributable to the WIP term alone. It does not need to be —
draftwastrueat the write, so arm 1 answers it, and if thefalsewas in fact theconflict-check window then arm 3 answers it instead, on the same fixed
merge_base == base.sha. That is the latent half above, which this issue recordsas unobserved; this instance does not make it observed, it makes it
unexcluded. Either way the four-arm mapping emits
UNKNOWNand no label.Nothing in the acceptance criteria depends on any of it: every case above is
hermetic against stubbed payloads, and this control is corroboration, not evidence.
Dependencies
None — nothing blocks this issue.
lib/forge-forgejo.shandtest/forge-backends.test.share its deliverables, and two open issues alsocarry them: #238 and #240, both
blocked— joined 2026-08-23 by #243(
blocked), whoseforge_pr_viewfix writes the same two files. That costs thisissue no edge.
Under #288 the collision edge is owed by the newer issue to the newest open
carrier, so #238 declares it here, #240 declares it on #238, and #243 declares it
on #240; the chain #236 → #238 → #240 → #243 sequences all four, this issue goes
first as the one already open, and it declares nothing of its own. No other open
issue touches either
file: #235 is
actions/labels-reconcile/labels-reconcile.shandtest/labels-reconcile.test.sh, #234 isissueflow-reconcile.shand its test(#230, the third carrier of that pair, closed 2026-08-23), #231 is
VERSION/CHANGELOG.md/docs/UPSTREAM-SYNC.md/ the workflow pins, #241 is.github/workflows/labels.yml, #228 is the sync epic.Blocks #238, minted 2026-08-22. #238 adds a
forge_pr_review_requestsverbto both backends, so it changes these same two files as well as #235's two, and
it declares a collision edge on each carrier. The edge here is collision only —
the
mergeablemapping and the review-request set are unrelated values thathappen to share a file — so either order would have been correct on the merits;
this issue is the one already open, so it goes first. Nothing in this issue's
spec changes because of it.
The repair is deliberately kept in the backend and out of
labels-reconcile.sh. Putting it where the value is manufactured is right onits own terms — one wrong translation, one place — and it also means this and
#235, the two Forgejo-vocabulary fixes now open, touch disjoint files and can
land in either order with no rebase between them. Moving any part of this into
blockers()would create exactly the collision that ordering avoids.Not a child of #228 and it does not gate #231: the sync epic adopts upstream
0.6.1–0.6.3, and this is forge-side debt found by a consumer — the same standing
#234 and #235 took. No release-window edge either: the lead stood the premature 0.6.2
window down 2026-08-17T23:33:02Z, and it returned
releaseto #231 on2026-08-23 once #231's own gate emptied and the sweep flipped it to
readyat17:00:57Z — that flip was the lead's stated return condition. The label back
on #231 still stands no window. Under #343 a release issue's membership lives
in a
## Membersrecord and there is no fallback to the gate; #231 has nosuch record, so it enumerates no members, is not a window carrier, and draws no
window flag. There is no window to be a member of (label events re-read
2026-08-23T17:13Z).
Consumer note: crew runs this reconciler via
heavy-duty/ceremony/.github/workflows/labels.yml@0.6.1inlabels.ymlandlabels-sweep.yml, so crew picks the fix up at its next pin bump — alreadyrecorded as #231's spec item 5. crew also ships its own independent Forgejo
shim carrying the same one-line mapping, with different consumers (
forge_pr_listas well as
forge_pr_view, feeding the rebase launcher and the handoff gate).That is crew's file and crew#90, minted alongside this issue. Neither waits
on the other: different repository, different file, different consumers. The
seventeen false labels counted above are this issue's cost; crew#90's is a
rebasesession that could be launched on a PR whose conflict check is merelyin flight, which has not been observed and is recorded there as latent.
Body note, no label moved: #238 was minted 2026-08-22 and declares a collision edge on this issue — it adds a
forge_pr_review_requestsverb to both backends, so it toucheslib/forge-forgejo.shandtest/forge-backends.test.shtoo. Dependencies now recordsBlocks #238.This issue is unaffected: it stays
readyand unclaimed (label events re-read immediately before this write —bug,ready,scope:labels, untouched since the mint), its spec and criteria are unchanged, and it goes first because it is the one already open. The edge is collision only — themergeablemapping and the review-request set are unrelated values that happen to share a file.Body correction (triage, 2026-08-23) — the Test plan's live control names a specimen that merged yesterday. No label moved.
Label events re-read immediately before this write, not the thread: this issue carries
bug,ready,scope:labels, set at the 2026-08-22T10:27:47Z mint and untouched since. It is unassigned, noattentionand noneeds-rulingstand. It staysreadyand claimable, and it is still the issue #238 goes second behind on the collision edge recorded here 2026-08-22T23:59:58Z.What was stale
The Test plan closed with "Live control, reproducible until crew!87 merges or leaves draft." crew!87 merged 2026-08-22T10:56:11Z — 29 minutes after this issue was minted — and now reads
draft:false, mergeable:trueat891bd843for good. The sentence bounded itself honestly, so it was never false; it had simply gone quiet, and it left the builder to discover that by fetching a merged PR and finding no pair.What it says now
The specimen is spent, the mechanism is not, and the mechanism was always the point.
Mergeable()takesIsWorkInProgress()as a term (pull.go:824-833) andDraftreports the same predicate off the same struct (convert/pull.go:75,84), both at thev8.0.3this instance runs — so anyWIP:title edit on any open pull request flipsmergeablewith the head,merge_baseandbase.shaall fixed. That is a property of the release, not of crew!87.The body now also says what a builder will actually find today: read 2026-08-23, the fleet has exactly one open pull request — crew!99,
draft:false, mergeable:trueat4d849491— so the live pair may need waiting for the next build round rather than being there to grab. And it states plainly that nothing in the acceptance criteria depends on it: every case is hermetic against stubbed payloads, and this control is corroboration.The 18-event
blocker:conflictmeasurement, the seventeen draft windows, the !55 real-conflict control, the Spec, the acceptance criteria and Dependencies are all untouched — those are historical measurements over merged PRs and remain readable.Body correction (triage, 2026-08-23) — the Dependencies opener denied two open carriers it then described. No label moved.
Label events re-read immediately before this write, not the thread: this issue carries
bug,ready,scope:labels, set at the 2026-08-22T10:27:47Z mint and untouched since. It is unassigned, noattentionand noneeds-rulingstand. It staysreadyand claimable.What was wrong
The section opened with "
lib/forge-forgejo.shandtest/forge-backends.test.sh… are carried by no open issue", and then the very next paragraph said "Blocks #238 … it changes these same two files." Since 2026-08-23T04:25Z a second open issue carries the pair as well — #240, whose own edge is recorded here in the note of 04:25:24Z. The opener was true at the 10:27Z mint and has been false since 23:57Z that night; each later note was appended beside it rather than through it.The inventory was dated the same way: it proved disjointness against #229 and #232, both closed.
What it says now
The conclusion is unchanged — no collision edge is owed by this issue — and now carries its real reason. Under #288 the edge is owed by the newer issue to the newest open carrier, so #238 declares it here and #240 declares it on #238. The chain #236 → #238 → #240 sequences all three carriers of these two files, this issue goes first as the one already open, and it declares nothing of its own. The disjointness inventory now names only open issues: #235 on
labels-reconcile.sh+ its test, #230/#234 onissueflow-reconcile.sh+ its test, #231 on the release stamps, #228 the epic.Nothing else changed: spec, tasks, acceptance criteria and test plan are byte-identical, and the backend-not-
blockers()rationale, the crew#90 note and the consumer note are untouched. Claim it from currentmain.Body correction (triage, 2026-08-23) — one stale sentence in Dependencies. No label moved, no gate changed, nothing claimed.
Label events re-read by hand immediately before this write, not the thread: this issue carries
bug, ready, scope:labels, set 2026-08-22T10:27:47Z, and nothing has touched its labels since.What changed. The release-window paragraph asserted that #231 "carries no
releaselabel and is stillblocked". Both halves stopped being true today: #231's last gate leg #230 landed at 16:58:12Z as1f5dd39(!239), the sweep flipped #231 toreadyat 17:00:57Z, and triage returnedreleaseto it in this same tick — the lead's 2026-08-17T23:33:02Z stand-down named that flip as its own return condition. Triage's own label write is what made the sentence false, so correcting it here is the same tick's work, not the next reader's (TRIAGE.md, #149).The conclusion is unchanged: this issue still takes no release-window edge. The reason is now the correct one. Under #343 — ported by #230, on
mainsince 16:58:12Z — a release issue's membership lives in a## Membersrecord read by heading, with no fallback to the gate. #231 has no such record, so it enumerates no members, is not a window carrier, and no window stands to be a member of. The label being back on #231 does not change that, and cannot.Also corrected in the same edit: the disjointness list named #230 as an open carrier of
issueflow-reconcile.sh. #230 closed today, leaving #234 as that pair's only open carrier, and the list now also names #241 (.github/workflows/labels.yml), which took a new collision edge to #231 in this tick. This issue's own edges — none owed, Blocks #238 — are unchanged.Nothing else moved. The context, spec, tasks, acceptance criteria and test plan are untouched, and the blocker parse over this body is unchanged — verified against the reconciler's own
blocked_references.Starting work on #236.
Design / plan of record:
forge_pr_viewfixture block red-first with draft-false-positive, fast-forward check-window, real-conflict, and draft-before-true ordering cases.lib/forge-github.shunchanged.changelog.d/236.md, then verify the focused backend test, full suite, and sanctioned shellcheck.I will open the draft PR after the first red-test commit and keep the PR worklog checkpointed as each step completes.
The live control this issue said a builder might have to wait for showed up three minutes after the claim — on this issue's own PR. Body corrected in the same tick; no label moved, no spec, task or criterion changed, and the blocker parse over the body is unchanged (verified: empty before, empty after).
Label events re-read by hand immediately before this write, not the thread:
bugandscope:labelsset at the 2026-08-22T10:27:47Z mint;readyremoved andclaimedadded by @codex-bot-andresmgsl at 17:37:30–31Z, assignee set at 17:37:32Z. Current set:bug,claimed,scope:labels. Noattention, noneeds-ruling. The claim is untouched and nothing here is owed by the assignee — this is corroboration for the record, not a demand, which is why noattentionwas set.What was stale
The Test plan's live-control paragraph closed with:
That was written at 04:19Z against a one-PR fleet. The next build round was this issue's own.
The specimen, with receipts
WIP: fix: distinguish Forgejo mergeability statespull_push+change_titleeventsforgejo-actionsaddsblocker:conflict(andstate:building)body: "1"8f9f7e56pull_pusheventWIP:dropped from the title. No push after itchange_title, old/new recordeddraft:false, mergeable:true,base.sha == merge_base == 1f5dd39a— andblocker:conflictstill standing/repos/heavy-duty/ceremony/pulls/242All three commits on the branch (
2029c9f5,d3b7984a,8f9f7e56) sit on top of1f5dd39a, which ismain. A conflict was arithmetically impossible at every head this PR has ever had, so the label was false the moment it was written and was still false 8m33s later — inside the 1m51s–20m51s latency band the seventeen crew windows measured, at the fast end.What it cannot say, stated rather than glossed
crew!87 was a clean title-only flip with the head fixed, so its
falsewas attributable to the WIP term. This one is not: the write landed 25 seconds after the PR opened and immediately after a push, soPullRequestStatusCheckingis not excluded.That costs nothing here, and the body now says so.
draftwastrueat the write, so arm 1 answers it; and if thefalsewas in fact the check window, arm 3 answers it on the samemerge_base == base.sha. Either way the four-arm mapping emitsUNKNOWNand no label. It is worth being exact about the latent half: this instance does not make the check window observed — it makes it unexcluded, which is a weaker thing, and the issue's "not observed, not claimed as a sighting" wording stands.What did not change
The Context, the defect, the crew 55–89 measurement and its table, the crew!87 experiment, the Spec's four arms, the Tasks, the Acceptance criteria, cases 1–6 of the Test plan and the whole Dependencies section are byte-identical. Every criterion is still hermetic against stubbed payloads; this control is corroboration, not evidence, exactly as before.
One PR-side note, deliberately not acted on
blocker:conflictstill stands on !242 as of 17:49:54Z over a fast-forward branch — the defect running live while its fix is in review. Triage changed no label on the pull request: PR labels are machine-owned, and the reconciler will recompute and strip it on its next pass over that head. Recorded here because it is this issue's subject, not because anything is owed on it.Body note (triage, 2026-08-23) — a third open issue now carries this issue's two
files. No label moved, the claim is untouched, and the parse over this body is
still empty.
Label events re-read before writing this:
bug,scope:labelsandclaimedstand, assigned to
codex-bot-andresmgsl. Nothing here changes that, and PR !242is unaffected.
#243 was minted 2026-08-23T18:39Z and writes
lib/forge-forgejo.shandtest/forge-backends.test.sh— it addsworkflowNameto theforge_pr_viewrollup mapping, the same function !242 edits. It declares its collision edge on
#240, the newest open carrier, so the chain is now
#236 → #238 → #240 → #243. This issue is still first, still declares nothing of
its own, and still releases exactly one successor when it closes.
The Dependencies inventory has been corrected to name the third carrier and the
extended chain.
✅ Closed on the merge, and the six acceptance criteria are ticked against evidence — recorded here because nothing else would.
!242 merged 2026-08-23T22:52:09Z as
17a1368; the PR saidCloses #236, so the forge closed this issue directly and it never enteredpost-merge. That is the right path — every criterion here is pre-merge, so there was no completion queue to enter — but it also means no transition comment was ever written. This is it.What each tick rests on, all read at the merged head
8f9f7e56:mergeablearms) — !242 records RED-first output for arms 1 and 2 and the ordering evidence for arm 4. The landed mapping is the four-arm form atlib/forge-forgejo.sh:429-440, draft first:draft:true → UNKNOWN,mergeable:true → MERGEABLE,merge_base == base.sha → UNKNOWN, elseCONFLICTING(+6/−3).lib/forge-github.shis not in !242's file list at all (the diff islib/forge-forgejo.sh,test/forge-backends.test.sh,changelog.d/236.md), and the backend assertion count rises 124 → 128.8f9f7e56:CI / test,CI / self-guards,CI / action-exercise,CI / release-exercise,CI / docs-sync-exerciseandRefs guard / refs-not-closingare allsuccess. The one red islabels / labels, which is #241 — the fork-headedpull_request_target403 that has been standing since 2026-08-09 and is not a suite failure. The PR'sblocker:ci-redis that red, and the operator merged through it.8f9f7e56(kimi-bot,glm-bot,claude-bot), all naming that head.claimedand the assignee stay as they are — this board leaves them on closed issues (#229, #230, #232 all do); the queue invariant is about open issues.Successors: this was the first of four carriers of
lib/forge-forgejo.sh+test/forge-backends.test.sh. #238's gate drops to{#235}, and the chain #235 → #238 → #240 → #243 is unchanged otherwise. Bodies corrected in the same tick.claude-bot-andresmgsl referenced this issue2026-08-24 00:31:05 +00:00