You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
[bug] issue-shape gate judges the event payload: a queued run closes an issue an edit already fixed (128 of 185 closed issues pass today) #11007
The issue-shape gate (.github/workflows/needs-boundary.yml, rule specs/policy/issue_shape.t27, #7498) judges the issue as it is when the run starts, not the body and labels frozen in its event payload. Then an edit that fixes the shape is never undone by an older run that was still queued.
Why
Measured 2026-10-19: 185 issues created since 2026-10-18 carry shape-refused and are closed as not planned. For 128 of them the current body passes the generated checker gen/c/policy/issue_shape.c, compiled exactly as the workflow compiles it. The contract "an edit that passes reopens it" did not hold for any of them.
Replay of #10897 (runs of needs-boundary.yml, times UTC):
time
event
run
what the run saw
05:56:53
opened (body without User Scenarios / Requirements)
39207166571
the old body
05:59:27
edited
39207374853
cancelled at 06:06 by the next run of the concurrency group
06:06:17
edited by tri-claw (sections added, body passes)
39208000509
the new body, but REFUSED=false from the payload
06:34:58
run 39207166571 finishes (38 min in the Actions queue)
judges the 05:56 body: labels shape-refused, closes
07:01:39
run 39208000509 finishes
body passes, REFUSED was false at 06:06, so no reopen
Both inputs come from github.event.issue: BODY, REFUSED and STATE. With the queue 38-55 min deep, the last run to finish is not the run of the last edit.
Boundary
.github/workflows/needs-boundary.yml
User Scenarios
Given an issue opened without the four sections and fixed by an edit while the opened run is still queued, when the opened run finishes last, then it reads the fixed body and leaves the issue open.
Given an issue the gate closed, when an edit makes the body pass and its run starts after the close, then the run sees the shape-refused label that is on the issue now and reopens it.
Given an issue whose current body fails, when any queued run of it finishes, then it is closed with the missing sections listed, as today.
Requirements
FR-001: The workflow MUST read body, state and labels with gh issue view at run time; it MUST NOT judge github.event.issue.body or the payload's labels and state.
FR-002: The rule stays in specs/policy/issue_shape.t27 and its gen-c output; the workflow MUST stay plumbing (no new check logic).
FR-003: The change MUST NOT add counted hand-written lines (own-language net <= 0).
Self-heal applied 2026-10-19 ~11:20Z (fix of the workflow itself: #11008).
Of the 185 issues closed by the gate since 2026-10-18, 128 pass gen/c/policy/issue_shape.c with their current body. For each one, the shape-refused label was removed, and then:
88 closed as completed. A merged PR names each one with a closing keyword (found in its cross-reference timeline). Only the reason changed, from not planned to completed:
40 reopened, each with a comment. No merged PR closes them, so the gate's contract ("a passing body stays open") applies. Close any that turn out finished or obsolete:
The 57 issues whose current body still fails were left closed; the gate was right about them.
Method: the search label:shape-refused is:closed created:>=2026-10-18; the checker compiled exactly as the workflow compiles it; merged PRs from timelineItems(CROSS_REFERENCED_EVENT), keeping a PR only when its title or body matches close[sd]?|fix(e[sd])?|resolve[sd]? #N. Every API call returned 2xx.
Activity
gHashTag commentedon Oct 19, 2026
Self-heal applied 2026-10-19 ~11:20Z (fix of the workflow itself: #11008).
Of the 185 issues closed by the gate since 2026-10-18, 128 pass
gen/c/policy/issue_shape.cwith their current body. For each one, theshape-refusedlabel was removed, and then:88 closed as completed. A merged PR names each one with a closing keyword (found in its cross-reference timeline). Only the reason changed, from not planned to completed:
#10199, #10203, #10282, #10284, #10289, #10376, #10383, #10391, #10418, #10423, #10437, #10439, #10440, #10441, #10444, #10450, #10454, #10459, #10469, #10531, #10532, #10533, #10534, #10535, #10536, #10537, #10540, #10541, #10543, #10544, #10550, #10555, #10571, #10573, #10579, #10581, #10583, #10584, #10596, #10599, #10615, #10628, #10629, #10633, #10638, #10643, #10649, #10653, #10693, #10751, #10753, #10754, #10764, #10765, #10766, #10788, #10796, #10798, #10803, #10807, #10810, #10811, #10813, #10818, #10821, #10823, #10825, #10826, #10835, #10837, #10839, #10841, #10843, #10846, #10848, #10850, #10856, #10876, #10877, #10887, #10905, #10921, #10936, #10938, #10954, #10957, #10960, #10974
40 reopened, each with a comment. No merged PR closes them, so the gate's contract ("a passing body stays open") applies. Close any that turn out finished or obsolete:
static mutis recorded under the namemut, so every later fn with alet mutis refused #10829let t = n.value.trim(); t.starts_with(..)is refused while the inline chain converts #10834The 57 issues whose current body still fails were left closed; the gate was right about them.
Method: the search
label:shape-refused is:closed created:>=2026-10-18; the checker compiled exactly as the workflow compiles it; merged PRs fromtimelineItems(CROSS_REFERENCED_EVENT), keeping a PR only when its title or body matchesclose[sd]?|fix(e[sd])?|resolve[sd]? #N. Every API call returned 2xx.ci(issue-shape): judge the issue as it is when the run starts, not it…