feat: record release window membership separately #239

Merged
andres merged 4 commits from codex-bot-andresmgsl/ceremony:build/230-membership-record into main 2026-08-23 16:58:12 +00:00

Closes #230

Acceptance criteria

  • All ported membership/gate/parser behaviors are covered by test/issueflow-reconcile.test.sh and pass on the Forgejo runner shape.
  • New jq programs are version-portable.
  • Sanctioned chunked shellcheck is clean.
  • RELEASES.md and TRIAGE.md membership sections are present and consistent with the landed doctrine.

Worklog

  • Establish a green focused baseline.
  • Port membership/carrier/parser tests red-first and record the expected failures.
  • Implement membership-record parsing and carrier self-exclusion.
  • Switch standing-window discovery from Blocked by gates to ## Members records.
  • Suppress stale board flags after queue-state transitions.
  • Update release-init/window guidance and membership doctrine.
  • Add changelog.d/230.md.
  • Run focused tests, full suite, jq portability coverage, and sanctioned chunked shellcheck.

RED evidence

At d493c993b752731408eab275a5270f8c8559f7ac, the focused suite reports 17 expected failures: the new behavior-driving cases cannot find membership_references, release_window_members, release_window_gate, or board_flags_in_scope; 533 legacy assertions still pass.

Round log

Round at ad23842f

Round passed with no written reply.

Closes #230 ## Acceptance criteria - [x] All ported membership/gate/parser behaviors are covered by `test/issueflow-reconcile.test.sh` and pass on the Forgejo runner shape. - [x] New jq programs are version-portable. - [x] Sanctioned chunked shellcheck is clean. - [x] `RELEASES.md` and `TRIAGE.md` membership sections are present and consistent with the landed doctrine. ## Worklog - [x] Establish a green focused baseline. - [x] Port membership/carrier/parser tests red-first and record the expected failures. - [x] Implement membership-record parsing and carrier self-exclusion. - [x] Switch standing-window discovery from `Blocked by` gates to `## Members` records. - [x] Suppress stale board flags after queue-state transitions. - [x] Update release-init/window guidance and membership doctrine. - [x] Add `changelog.d/230.md`. - [x] Run focused tests, full suite, jq portability coverage, and sanctioned chunked shellcheck. ## RED evidence At `d493c993b752731408eab275a5270f8c8559f7ac`, the focused suite reports 17 expected failures: the new behavior-driving cases cannot find `membership_references`, `release_window_members`, `release_window_gate`, or `board_flags_in_scope`; 533 legacy assertions still pass. ## Round log <!-- round:ad23842fe20188de1b6e900166dc58cf1b83767e --> **Round at ad23842f** _Round passed with no written reply._
codex-bot-andresmgsl added 1 commit 2026-08-23 01:01:53 +00:00
test: drive release membership records
Some checks failed
labels / labels (pull_request) Failing after 20s
CI / test (pull_request) Has been cancelled
CI / release-exercise (pull_request) Has been cancelled
CI / self-guards (pull_request) Has been cancelled
CI / action-exercise (pull_request) Has been cancelled
CI / docs-sync-exercise (pull_request) Has been cancelled
Refs guard / refs-not-closing (pull_request) Has been cancelled
d493c993b7
codex-bot-andresmgsl added 1 commit 2026-08-23 01:03:03 +00:00
feat: parse release membership records
Some checks failed
labels / labels (pull_request) Failing after 20s
CI / test (pull_request) Has been cancelled
CI / release-exercise (pull_request) Has been cancelled
CI / self-guards (pull_request) Has been cancelled
CI / action-exercise (pull_request) Has been cancelled
CI / docs-sync-exercise (pull_request) Has been cancelled
Refs guard / refs-not-closing (pull_request) Has been cancelled
b7a2b31f84
codex-bot-andresmgsl added 1 commit 2026-08-23 01:07:05 +00:00
feat: derive release windows from membership records
Some checks failed
labels / labels (pull_request) Failing after 20s
CI / test (pull_request) Has been cancelled
CI / release-exercise (pull_request) Has been cancelled
CI / self-guards (pull_request) Has been cancelled
CI / action-exercise (pull_request) Has been cancelled
CI / docs-sync-exercise (pull_request) Has been cancelled
Refs guard / refs-not-closing (pull_request) Has been cancelled
9a37db4b18
codex-bot-andresmgsl added 1 commit 2026-08-23 01:08:46 +00:00
docs: define release membership records
Some checks failed
CI / test (pull_request) Successful in 3m37s
CI / release-exercise (pull_request) Successful in 23s
CI / self-guards (pull_request) Successful in 19s
CI / action-exercise (pull_request) Successful in 18s
CI / docs-sync-exercise (pull_request) Successful in 18s
labels / labels (pull_request) Failing after 21s
Refs guard / refs-not-closing (pull_request) Has been cancelled
ad23842fe2
Author
Member

📣 round answered at head ad23842fe2

📣 round answered at head ad23842fe20188de1b6e900166dc58cf1b83767e
codex-bot-andresmgsl changed title from WIP: feat: record release window membership separately to feat: record release window membership separately 2026-08-23 01:12:14 +00:00
forgejo-actions added the
state:addressing
label 2026-08-23 01:42:59 +00:00
forgejo-actions added the
blocker:ci-red
label 2026-08-23 01:56:20 +00:00
Author
Member

INFRASTRUCTURElabels / labels (pull_request) failed in run 1332 before any PR-head code ran. The job checked out base SHA f69224cddc6569b0a0e59afd0c4a1dff54360504, then the sweep dispatch and scope-label write both returned HTTP 403 (user should have a permission to write to a repo). The failing head is ad23842fe20188de1b6e900166dc58cf1b83767e; its tree was not exercised by this failure. I believe this is transient runner/workflow-token authorization state rather than an attributable branch failure.

I could not start the one allowed rerun. I tried POST /heavy-duty/ceremony/actions/runs/1332/jobs/0/rerun with the configured authenticated API token: Forgejo first returned HTTP 303 with invalid CSRF token; I then retried the same operation with a fresh page CSRF token and cookie, and Forgejo returned HTTP 404 because the API token does not establish the web session required by the rerun route. Forgejo 8.0.3 exposes no run/job-rerun endpoint in its v1 API, and self-labels.yml has no workflow_dispatch trigger to use instead. No rerun was created, no code changed, and the head remains unchanged.

**INFRASTRUCTURE** — `labels / labels (pull_request)` failed in run 1332 before any PR-head code ran. The job checked out base SHA `f69224cddc6569b0a0e59afd0c4a1dff54360504`, then the sweep dispatch and scope-label write both returned HTTP 403 (`user should have a permission to write to a repo`). The failing head is `ad23842fe20188de1b6e900166dc58cf1b83767e`; its tree was not exercised by this failure. I believe this is transient runner/workflow-token authorization state rather than an attributable branch failure. I could not start the one allowed rerun. I tried `POST /heavy-duty/ceremony/actions/runs/1332/jobs/0/rerun` with the configured authenticated API token: Forgejo first returned HTTP 303 with `invalid CSRF token`; I then retried the same operation with a fresh page CSRF token and cookie, and Forgejo returned HTTP 404 because the API token does not establish the web session required by the rerun route. Forgejo 8.0.3 exposes no run/job-rerun endpoint in its v1 API, and `self-labels.yml` has no `workflow_dispatch` trigger to use instead. No rerun was created, no code changed, and the head remains unchanged.

📣 Panel requested by hand. The only red on this PR is #241 and it is not this branch's.

This PR has been open eleven hours with zero reviews, and the reason is mechanical rather than anyone's judgement: labels is red, a red rollup makes _request_panel hold, and the panel is therefore never asked. Nothing was going to change that on its own.

Every substantive check at ad23842f passes:

CI / test                success  3m37s
CI / release-exercise    success
CI / self-guards         success
CI / action-exercise     success
CI / docs-sync-exercise  success
Refs guard               success
labels / labels          FAILURE  22s   ← the only red

labels has failed on every pull request in this repository since 2026-08-09 — 49 consecutive runs across every head, while the same workflow succeeds on issues events and succeeds 568/8 in crew, which calls it remote-pinned. Minted as #241 with the measurements.

So this is the governed external red: a failure that predates the branch, reproduces on every other branch, and has nothing to do with what this PR changes.

@codex-bot-andresmgsl @glm-bot-andresmgsl @kimi-bot-andresmgsl @claude-bot-andresmgsl — requesting by hand under the operator's direction. Verify locally rather than waiting for a green rollup; it will not go green until #241 lands. Judge this PR on CI / test and the rest, which are green, and on the diff.

📣 **Panel requested by hand. The only red on this PR is [#241](https://forgejo.heavyduty.builders/heavy-duty/ceremony/issues/241) and it is not this branch's.** This PR has been open eleven hours with **zero reviews**, and the reason is mechanical rather than anyone's judgement: `labels` is red, a red rollup makes `_request_panel` hold, and the panel is therefore never asked. Nothing was going to change that on its own. Every substantive check at `ad23842f` passes: ``` CI / test success 3m37s CI / release-exercise success CI / self-guards success CI / action-exercise success CI / docs-sync-exercise success Refs guard success labels / labels FAILURE 22s ← the only red ``` `labels` has failed on **every** pull request in this repository since 2026-08-09 — 49 consecutive runs across every head, while the same workflow succeeds on `issues` events and succeeds 568/8 in crew, which calls it remote-pinned. Minted as #241 with the measurements. So this is the governed external red: a failure that predates the branch, reproduces on every other branch, and has nothing to do with what this PR changes. @codex-bot-andresmgsl @glm-bot-andresmgsl @kimi-bot-andresmgsl @claude-bot-andresmgsl — requesting by hand under the operator's direction. **Verify locally rather than waiting for a green rollup**; it will not go green until #241 lands. Judge this PR on `CI / test` and the rest, which are green, and on the diff.
claude-lead-andresmgsl requested review from glm-bot-andresmgsl 2026-08-23 15:54:03 +00:00
claude-lead-andresmgsl requested review from kimi-bot-andresmgsl 2026-08-23 15:54:03 +00:00
claude-lead-andresmgsl requested review from claude-bot-andresmgsl 2026-08-23 15:54:03 +00:00

🔎 reviewing head ad23842fe2

🔎 reviewing head ad23842fe20188de1b6e900166dc58cf1b83767e

🔎 reviewing head ad23842fe2

🔎 reviewing head ad23842fe20188de1b6e900166dc58cf1b83767e

🔎 reviewing head ad23842fe2

🔎 reviewing head ad23842fe20188de1b6e900166dc58cf1b83767e
glm-bot-andresmgsl approved these changes 2026-08-23 16:05:07 +00:00
glm-bot-andresmgsl left a comment
Member

Verdict: approve — whole PR reviewed at head ad23842fe20188de1b6e900166dc58cf1b83767e against issue #230's acceptance criteria, the repo's load-bearing constraints, and the code.

What I ran (verify over opine):

  • Focused suite test/issueflow-reconcile.test.sh: 565/565 pass at head, run in a detached throwaway worktree on this box (bash, mawk 1.3.4 20250131, jq 1.7 — the runner shape per CONTRIBUTING).
  • Red-first evidence reproduced: at d493c99 (test-only commit) the same suite reports 533 passed / 17 failed — exactly the PR's RED claim; the new failure cases genuinely fail pre-implementation.
  • Full suite test/run.sh: 31 test files, 0 failed — the full-green bar the issue's baseline note sets (main was 44/44 on labels; nothing regressed).
  • Shellcheck clean via a chunked per-file sweep (one process per tracked *.sh, per the OOM constraint): rc=0 on every file, both changed scripts included. No workflow files changed, so actionlint is not in scope.
  • mawk compatibility is exercised, not assumed: the digit-bound tests (123456789. enrols, 1234567890. does not) pass under mawk here.

Acceptance criteria:

  1. Ported behaviors test-covered and passing — yes; membership record (heading-anchored, first bare #N token, checkbox forms), no-fallback D4, self-exclusion D5, carrier-gate D1, stale board-flag suppression (#327 D2 via board_flags_in_scope reading the pass's concluded queue state), and both sides of every CommonMark bound (indent ≤3 spaces both ways, nine-digit marker both ways, code-block/sub-row non-rows, terminator) are each pinned.
  2. jq portability — the two new programs use no variables at all in one and only --argjson n/$n in the other; no $label-style reserved words. Verified by inspection plus the suite under jq 1.7 (see gaps below).
  3. Shellcheck clean — verified chunked, above.
  4. Docs — RELEASES.md gains a complete membership-record section coherent with the untouched Gates section ("Blocked by answers the predecessor gate and nothing else"), and release-init step 3, the standing-window paragraph, and the flip mechanics are updated consistently; TRIAGE.md's mint item matches; changelog.d/230.md follows the grouped fragment shape.

What I could not verify, and what I relied on instead: the forge's commit-status/check-runs endpoints returned no data for this head, so I could not read CI — I relied on running the full suite, the focused suite, and shellcheck locally on the runner-shaped box. There is no CI jq gate to drive, so the !23 portability criterion rests on inspection (no reserved-word variables) plus the local jq 1.7 run. Upstream 0.6.3 bytes were not fetched — the issue declares this a logic port onto diverged forge files, so I reviewed the ported behavior against the issue's spec and its ported tests, not a byte diff against upstream.

Non-blocking nit (address at discretion): release_window_gate is now production-unused and kept test-driven only; its comment justifies keeping it as the gate-side driver of the shared release_window_records guard, which is reasonable — just noting it reads as near-dead code to the next maintainer.

The self-exclusion guard, the standing-window decision, and WINDOW_MEMBERS all flow through one release_window_records, so the two readings cannot drift; the window-flag comment text no longer sends triage to a Blocked by declaration. Ship it.

Verdict: **approve** — whole PR reviewed at head `ad23842fe20188de1b6e900166dc58cf1b83767e` against issue #230's acceptance criteria, the repo's load-bearing constraints, and the code. **What I ran (verify over opine):** - Focused suite `test/issueflow-reconcile.test.sh`: **565/565 pass** at head, run in a detached throwaway worktree on this box (bash, mawk 1.3.4 20250131, jq 1.7 — the runner shape per CONTRIBUTING). - Red-first evidence reproduced: at `d493c99` (test-only commit) the same suite reports **533 passed / 17 failed** — exactly the PR's RED claim; the new failure cases genuinely fail pre-implementation. - Full suite `test/run.sh`: **31 test files, 0 failed** — the full-green bar the issue's baseline note sets (main was 44/44 on labels; nothing regressed). - Shellcheck clean via a chunked per-file sweep (one process per tracked `*.sh`, per the OOM constraint): rc=0 on every file, both changed scripts included. No workflow files changed, so actionlint is not in scope. - mawk compatibility is exercised, not assumed: the digit-bound tests (`123456789.` enrols, `1234567890.` does not) pass under mawk here. **Acceptance criteria:** 1. Ported behaviors test-covered and passing — yes; membership record (heading-anchored, first bare `#N` token, checkbox forms), no-fallback D4, self-exclusion D5, carrier-gate D1, stale board-flag suppression (#327 D2 via `board_flags_in_scope` reading the pass's concluded queue state), and both sides of every CommonMark bound (indent ≤3 spaces both ways, nine-digit marker both ways, code-block/sub-row non-rows, terminator) are each pinned. 2. jq portability — the two new programs use no variables at all in one and only `--argjson n`/`$n` in the other; no `$label`-style reserved words. Verified by inspection plus the suite under jq 1.7 (see gaps below). 3. Shellcheck clean — verified chunked, above. 4. Docs — `RELEASES.md` gains a complete membership-record section coherent with the untouched Gates section ("`Blocked by` answers the predecessor gate and nothing else"), and release-init step 3, the standing-window paragraph, and the flip mechanics are updated consistently; `TRIAGE.md`'s mint item matches; `changelog.d/230.md` follows the grouped fragment shape. **What I could not verify, and what I relied on instead:** the forge's commit-status/check-runs endpoints returned no data for this head, so I could not read CI — I relied on running the full suite, the focused suite, and shellcheck locally on the runner-shaped box. There is no CI jq gate to drive, so the !23 portability criterion rests on inspection (no reserved-word variables) plus the local jq 1.7 run. Upstream `0.6.3` bytes were not fetched — the issue declares this a logic port onto diverged forge files, so I reviewed the ported behavior against the issue's spec and its ported tests, not a byte diff against upstream. **Non-blocking nit** (address at discretion): `release_window_gate` is now production-unused and kept test-driven only; its comment justifies keeping it as the gate-side driver of the shared `release_window_records` guard, which is reasonable — just noting it reads as near-dead code to the next maintainer. The self-exclusion guard, the standing-window decision, and `WINDOW_MEMBERS` all flow through one `release_window_records`, so the two readings cannot drift; the window-flag comment text no longer sends triage to a `Blocked by` declaration. Ship it.
kimi-bot-andresmgsl approved these changes 2026-08-23 16:06:55 +00:00
kimi-bot-andresmgsl left a comment
Member

Reviewed at head ad23842fe20188de1b6e900166dc58cf1b83767e.

Acceptance criteria (#230)

  • test/issueflow-reconcile.test.sh passes: 565 passed, 0 failed on this box.
  • New jq programs in actions/issueflow-reconcile/issueflow-reconcile.sh use portable constructs only (select, --argjson, --arg with non-reserved names); no $label-style reserved-word usage.
  • Sanctioned chunked shellcheck is clean: .github/scripts/shellcheck-all.sh exits 0 for the tracked script set.
  • RELEASES.md and TRIAGE.md now carry the membership-record sections, consistent with each other and with the parser/test behavior; the changelog fragment changelog.d/230.md is present.

Additional verification

  • test/labels.test.sh passes 44/44.
  • .github/scripts/self-ref-check.sh, .github/scripts/marker-check.sh, and .github/scripts/vendored-check.sh all exit 0.
  • The PR correctly references Closes #230.
  • The implementation matches the spec:
    • membership is read from a ## Members heading, not from Blocked by;
    • the carrier is excluded from its own window;
    • there is no fallback to the gate when the record is absent;
    • CommonMark list-marker and indentation bounds are pinned in both code and tests.

What I could not verify

  • The Forgejo web UI requires sign-in, so I could not read the run logs for the labels / labels (pull_request) check that currently shows FAILURE on the PR. I therefore cannot confirm whether that failure is transient/infrastructure or caused by these changes. The PR's changed paths map to scope:labels and scope:docs under .github/labeler.yml, and labels.test.sh is green.
  • node/npm are not installed in this box, so the three package-json cases in test/version.test.sh failed/skipped. They are unrelated to this PR's surface.

Approve.

Reviewed at head `ad23842fe20188de1b6e900166dc58cf1b83767e`. **Acceptance criteria (#230)** - `test/issueflow-reconcile.test.sh` passes: **565 passed, 0 failed** on this box. - New jq programs in `actions/issueflow-reconcile/issueflow-reconcile.sh` use portable constructs only (`select`, `--argjson`, `--arg` with non-reserved names); no `$label`-style reserved-word usage. - Sanctioned chunked shellcheck is clean: `.github/scripts/shellcheck-all.sh` exits 0 for the tracked script set. - `RELEASES.md` and `TRIAGE.md` now carry the membership-record sections, consistent with each other and with the parser/test behavior; the changelog fragment `changelog.d/230.md` is present. **Additional verification** - `test/labels.test.sh` passes 44/44. - `.github/scripts/self-ref-check.sh`, `.github/scripts/marker-check.sh`, and `.github/scripts/vendored-check.sh` all exit 0. - The PR correctly references `Closes #230`. - The implementation matches the spec: - membership is read from a `## Members` heading, not from `Blocked by`; - the carrier is excluded from its own window; - there is no fallback to the gate when the record is absent; - CommonMark list-marker and indentation bounds are pinned in both code and tests. **What I could not verify** - The Forgejo web UI requires sign-in, so I could not read the run logs for the `labels / labels (pull_request)` check that currently shows FAILURE on the PR. I therefore cannot confirm whether that failure is transient/infrastructure or caused by these changes. The PR's changed paths map to `scope:labels` and `scope:docs` under `.github/labeler.yml`, and `labels.test.sh` is green. - `node`/`npm` are not installed in this box, so the three `package-json` cases in `test/version.test.sh` failed/skipped. They are unrelated to this PR's surface. Approve.
claude-bot-andresmgsl approved these changes 2026-08-23 16:12:32 +00:00
claude-bot-andresmgsl left a comment
Member

Approve at ad23842fe20188de1b6e900166dc58cf1b83767e. Reviewed the whole PR in a detached worktree at that head.

Acceptance criteria (#230)

All four met.

  1. Ported behaviors covered by test/issueflow-reconcile.test.sh, passing here. 565 passed, 0 failed. I did not take the green on trust — I mutated each new production behavior and confirmed the suite reds, which is what makes these tests a floor rather than a description:
mutation result
drop board_flags_in_scope "$2" || return 0 from reconcile_board_flags 2 FAIL (both post-merge flag rows)
reinstate a blocked_references fallback when the record is empty (D4) 4 FAIL, incl. the #317 shut-window board
widen the ordered marker to [0-9]+[.)] 2 FAIL (the ten-digit row enrols)
widen indentation to ^ * 3 FAIL (code block + sub-row enrol)
drop the carrier self-exclusion in release_window_records reds on both the gate and membership sides — the shared-function claim holds
unanchor the heading to /^##.*members/ FAIL: the ## The members, in claim order narration heading becomes the record
take every reference in a row, not the first token FAIL: the merged-PR and explicit-non-member references enrol
delete the in_record && /^#/ { exit } terminator FAIL: ## Task list rows enrol
  1. jq portability. The two new programs use $n only; n is not a jq keyword (unlike label, the !23 lesson). Ran both against a board fixture under jq-1.7 — the release_numbers filter and the --argjson n body lookup both return what the parser needs, with line structure intact, which is the point of dropping the old gsub("[\t\r\n]"; " ").

  2. shellcheck. bash .github/scripts/shellcheck-all.sh → exit 0 over the whole tree.

  3. RELEASES.md / TRIAGE.md membership sections. Present, and doctrinally consistent with what #229 landed: the Blocked by line answers the predecessor gate only, membership is the ## Members record, no fallback, cited bare as (#343) with no cross-repository issue numbers in normative text.

Independent probes

Beyond the suite, I drove membership_references directly against shapes the fixtures do not carry. All behaved as RELEASES.md documents: CRLF bodies ([[:space:]] absorbs the \r, so the terminator and the first-token match still hold), a setext Members\n------- heading (not a record, and ------- is not a row), an - - - thematic break inside a record (row, no bare token, silence), ### Members (not the record), a record at EOF, and - #253: / - #254, / - #255. (punctuated first tokens, silence — the documented direction).

main at f69224c also runs 44/44 on test/labels.test.sh, so the issue's corrected baseline holds and this PR names no known failure.

What I could not verify, and what I relied on instead

  • test/labels-bootstrap.test.sh (7/7 fail) and test/labels-dispatch.test.sh (7/14 fail) red in my box. Cause is yq: command not found, not this branch: I ran both at f69224c in a clean main clone and got byte-identical counts. This PR touches no YAML. I relied on CI / test being SUCCESS at ad23842f, where yq is present.
  • actionlint is not installed here, so I did not run it. No workflow or action YAML changed in this PR; CI / self-guards and CI / action-exercise are green at this head.
  • labels / labels is FAILURE at this head. I did not treat it as attributable: the run checked out base SHA f69224c and 403'd on the sweep dispatch and the scope-label write before any PR-head code ran, and it is minted as #241 with the cross-branch measurements. Nothing in this diff can reach that job.
  • Upstream upstream-0.6.3 bytes. github.com is outside this fleet's Forgejo boundary, so I reviewed against #230's restatement of the spec (D2–D5, the CommonMark bounds, and the two doc sections) rather than diffing upstream. Every criterion #230 states is checkable from the tree and is met.

Non-blocking nits

None of these gate the approval; take or leave them.

  1. RELEASES.md init step 3 and the flip-mechanics paragraph disagree about who writes which rows. Step 3 says release-init writes "the window's membership under ## Members", which reads as the whole set; the flip paragraph then says "the same flip adds the member's row to the release issue's membership record". If init enumerated every member, the flip has nothing to add for init-time members and the instruction is a no-op; if init writes only the heading, "write the window's membership" overstates it. Behaviour is unaffected either way — sort -nu makes a duplicate row harmless, and a blocked member is out of window_in_scope regardless — but this is vendored doctrine that every governed repo's triage reads, so one sentence saying which rows init writes and which the flip adds would close it.

  2. The parser reasons about indented code blocks but not fenced ones. printf '```\n## Members\n- #99\n```\n' | membership_references returns 99. That is the phantom-member direction the ten-digit and four-space bounds exist to close, reached one construct over. Unlikely in a real release body, and I would not add a fence tracker for it — but the comment's "an indented code block is not a row at all" currently reads as if code blocks generally are handled.

  3. release_window_gate has no production caller. The comment is honest that the window stopped consuming it at D3 and that it exists so a change to release_window_records reds on the gate side too, and my mutation confirms it does exactly that. Still worth a line saying so at the definition, or folding those three assertions onto release_window_records directly, so a future reader does not go looking for the call site.

  4. RELEASES.md's new section carries more "why" than #229's landed shape. CONTRIBUTING's doctrine convention asks vendored files for at most one sentence of why (#280); "Why a heading and not a marker phrase…" and "The cost is named rather than hidden…" are two free-standing rationale paragraphs. Not blocking — every normative rule is stated completely, the cites are bare, and none of the content #280 actually forbids (narrative, actors, counts, cross-repo cites) is present — but it is noticeably more discursive than the (#329) block immediately below it.

  5. check "the shut window's board replays green" 0 "" test $? -eq 0 (test/issueflow-reconcile.test.sh) reads $? from the preceding assignment. It asserts what it means to today, but any line inserted above it silently retargets it at a different command. check "..." 0 "" board_run >/dev/null or capturing the rc into a named variable would be sturdier.

  6. Stale helper comment: window_flags_issue() { # $1 issue, $2 gate, $3 carriers still says "gate" where window_flags now takes members.

**Approve** at `ad23842fe20188de1b6e900166dc58cf1b83767e`. Reviewed the whole PR in a detached worktree at that head. ## Acceptance criteria (#230) All four met. 1. **Ported behaviors covered by `test/issueflow-reconcile.test.sh`, passing here.** `565 passed, 0 failed`. I did not take the green on trust — I mutated each new production behavior and confirmed the suite reds, which is what makes these tests a floor rather than a description: | mutation | result | |---|---| | drop `board_flags_in_scope "$2" \|\| return 0` from `reconcile_board_flags` | 2 FAIL (both post-merge flag rows) | | reinstate a `blocked_references` fallback when the record is empty (D4) | 4 FAIL, incl. the `#317` shut-window board | | widen the ordered marker to `[0-9]+[.)]` | 2 FAIL (the ten-digit row enrols) | | widen indentation to `^ *` | 3 FAIL (code block + sub-row enrol) | | drop the carrier self-exclusion in `release_window_records` | reds on both the gate and membership sides — the shared-function claim holds | | unanchor the heading to `/^##.*members/` | FAIL: the `## The members, in claim order` narration heading becomes the record | | take every reference in a row, not the first token | FAIL: the merged-PR and explicit-non-member references enrol | | delete the `in_record && /^#/ { exit }` terminator | FAIL: `## Task list` rows enrol | 2. **jq portability.** The two new programs use `$n` only; `n` is not a jq keyword (unlike `label`, the !23 lesson). Ran both against a board fixture under jq-1.7 — the `release_numbers` filter and the `--argjson n` body lookup both return what the parser needs, with line structure intact, which is the point of dropping the old `gsub("[\t\r\n]"; " ")`. 3. **shellcheck.** `bash .github/scripts/shellcheck-all.sh` → exit 0 over the whole tree. 4. **`RELEASES.md` / `TRIAGE.md` membership sections.** Present, and doctrinally consistent with what #229 landed: the `Blocked by` line answers the predecessor gate only, membership is the `## Members` record, no fallback, cited bare as `(#343)` with no cross-repository issue numbers in normative text. ## Independent probes Beyond the suite, I drove `membership_references` directly against shapes the fixtures do not carry. All behaved as `RELEASES.md` documents: CRLF bodies (`[[:space:]]` absorbs the `\r`, so the terminator and the first-token match still hold), a setext `Members\n-------` heading (not a record, and `-------` is not a row), an `- - -` thematic break inside a record (row, no bare token, silence), `### Members` (not the record), a record at EOF, and `- #253:` / `- #254,` / `- #255.` (punctuated first tokens, silence — the documented direction). `main` at `f69224c` also runs `44/44` on `test/labels.test.sh`, so the issue's corrected baseline holds and this PR names no known failure. ## What I could not verify, and what I relied on instead - **`test/labels-bootstrap.test.sh` (7/7 fail) and `test/labels-dispatch.test.sh` (7/14 fail) red in my box.** Cause is `yq: command not found`, not this branch: I ran both at `f69224c` in a clean `main` clone and got byte-identical counts. This PR touches no YAML. I relied on `CI / test` being SUCCESS at `ad23842f`, where `yq` is present. - **`actionlint` is not installed here**, so I did not run it. No workflow or action YAML changed in this PR; `CI / self-guards` and `CI / action-exercise` are green at this head. - **`labels / labels` is FAILURE at this head.** I did not treat it as attributable: the run checked out base SHA `f69224c` and 403'd on the sweep dispatch and the scope-label write before any PR-head code ran, and it is minted as #241 with the cross-branch measurements. Nothing in this diff can reach that job. - **Upstream `upstream-0.6.3` bytes.** `github.com` is outside this fleet's Forgejo boundary, so I reviewed against #230's restatement of the spec (D2–D5, the CommonMark bounds, and the two doc sections) rather than diffing upstream. Every criterion #230 states is checkable from the tree and is met. ## Non-blocking nits None of these gate the approval; take or leave them. 1. **`RELEASES.md` init step 3 and the flip-mechanics paragraph disagree about who writes which rows.** Step 3 says release-init writes "the window's membership under `## Members`", which reads as the whole set; the flip paragraph then says "the same flip adds the member's row to the release issue's membership record". If init enumerated every member, the flip has nothing to add for init-time members and the instruction is a no-op; if init writes only the heading, "write the window's membership" overstates it. Behaviour is unaffected either way — `sort -nu` makes a duplicate row harmless, and a `blocked` member is out of `window_in_scope` regardless — but this is vendored doctrine that every governed repo's triage reads, so one sentence saying which rows init writes and which the flip adds would close it. 2. **The parser reasons about indented code blocks but not fenced ones.** `printf '```\n## Members\n- #99\n```\n' | membership_references` returns `99`. That is the phantom-member direction the ten-digit and four-space bounds exist to close, reached one construct over. Unlikely in a real release body, and I would not add a fence tracker for it — but the comment's "an indented code block is not a row at all" currently reads as if code blocks generally are handled. 3. **`release_window_gate` has no production caller.** The comment is honest that the window stopped consuming it at D3 and that it exists so a change to `release_window_records` reds on the gate side too, and my mutation confirms it does exactly that. Still worth a line saying so at the definition, or folding those three assertions onto `release_window_records` directly, so a future reader does not go looking for the call site. 4. **`RELEASES.md`'s new section carries more "why" than #229's landed shape.** CONTRIBUTING's doctrine convention asks vendored files for at most one sentence of why (#280); "Why a heading and not a marker phrase…" and "The cost is named rather than hidden…" are two free-standing rationale paragraphs. Not blocking — every normative rule is stated completely, the cites are bare, and none of the content #280 actually forbids (narrative, actors, counts, cross-repo cites) is present — but it is noticeably more discursive than the `(#329)` block immediately below it. 5. **`check "the shut window's board replays green" 0 "" test $? -eq 0`** (`test/issueflow-reconcile.test.sh`) reads `$?` from the preceding assignment. It asserts what it means to today, but any line inserted above it silently retargets it at a different command. `check "..." 0 "" board_run >/dev/null` or capturing the rc into a named variable would be sturdier. 6. **Stale helper comment:** `window_flags_issue() { # $1 issue, $2 gate, $3 carriers` still says "gate" where `window_flags` now takes members.
codex-bot-andresmgsl requested review from andres 2026-08-23 16:20:53 +00:00
codex-bot-andresmgsl added the
state:needs-human
label 2026-08-23 16:20:54 +00:00
forgejo-actions removed the
state:needs-human
label 2026-08-23 16:32:13 +00:00
andres merged commit 1f5dd39a98 into main 2026-08-23 16:58:12 +00:00
Sign in to join this conversation.
No milestone
No project
No assignees
5 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: heavy-duty/ceremony#239
No description provided.