Commit graph

600 commits

Author SHA1 Message Date
codex-bot-andresmgsl
b7a2b31f84 feat: parse release membership records 2026-08-23 01:02:53 +00:00
codex-bot-andresmgsl
d493c993b7 test: drive release membership records 2026-08-23 01:01:17 +00:00
f69224cddc Merge pull request 'test: update roster drift fixture' (#237) from codex-bot-andresmgsl/ceremony:build/232-roster-fixture into main
Reviewed-on: heavy-duty/ceremony#237
Reviewed-by: claude-bot-andresmgsl <andres+1@heavyduty.builders>
Reviewed-by: kimi-bot-andresmgsl <andres+4@heavyduty.builders>
Reviewed-by: glm-bot-andresmgsl <andres+5@heavyduty.builders>
2026-08-23 00:52:04 +00:00
codex-bot-andresmgsl
832a41b647 test: update roster drift fixture 2026-08-22 22:22:53 +00:00
4f887a756f Merge pull request 'docs: adopt upstream 0.6.1 and 0.6.2 doctrine' (#233) from codex-bot-andresmgsl/ceremony:build/229-upstream-doctrine into main
Reviewed-on: heavy-duty/ceremony#233
Reviewed-by: claude-bot-andresmgsl <andres+1@heavyduty.builders>
Reviewed-by: kimi-bot-andresmgsl <andres+4@heavyduty.builders>
Reviewed-by: glm-bot-andresmgsl <andres+5@heavyduty.builders>
2026-08-22 22:16:23 +00:00
claude-lead-andresmgsl
27f702a018 fix: roster names the renamed triage identity
Second leg of the same debt #232 records. The operator renamed
cluade-bot-andresmgsl to claude-bot-andresmgsl on 2026-08-20, closing the
misspelling; the account kept its id so history followed it, but the
roster compares logins as strings and went on naming the old form.

Both functional carriers move together, as #232's spec requires: the
`panel=`/`triage-actors=` lines and the CONTRIBUTING identity table. The
conf/prose sync guard is why they cannot move apart.

Verified: `test/labels.test.sh` is 43/44 before and after — unchanged.
The one failure is #232 spec item 4 (the `glm-reviewer-andresmgsl`
fixture at :249, now a no-op mutation), which is untouched here and
remains that issue's only outstanding work.

Historical attributions elsewhere stay as written, per triage's
2026-08-17 ruling recorded on #232.

Refs #232
2026-08-20 23:23:30 +00:00
codex-bot-andresmgsl
9f07c91faf docs: group the 229 changelog fragment 2026-08-20 01:36:32 +00:00
codex-bot-andresmgsl
78532e0777 docs: define post-merge release edge handling 2026-08-19 03:51:49 +00:00
codex-bot-andresmgsl
df4782ced9 docs: clarify builder waits and handoff ordering 2026-08-19 03:51:20 +00:00
codex-bot-andresmgsl
d12cc3d84f docs: route vendored doctrine through the manifest 2026-08-19 03:50:10 +00:00
cluade-bot-andresmgsl
c2ef6a2fc2 fix: roster names the renamed -bot identities
Emergency operator-authorized hotfix, sibling of crew 36c6745: engine and
sweep panel requests fail on the pre-rename -reviewer names. ceremony#232
records the debt and verifies. Authorized by @andres in-session.
2026-08-17 22:50:13 +00:00
dbe58517dc Merge pull request 'docs: record delivered 0.6.1 runner exercise' (#227) from issue-217-runner-consumer into main
Reviewed-on: heavy-duty/ceremony#227
Reviewed-by: cluade-reviewer-andresmgsl <andres+1@heavyduty.builders>
Reviewed-by: glm-reviewer-andresmgsl <andres+5@heavyduty.builders>
Reviewed-by: kimi-reviewer-andresmgsl <andres+4@heavyduty.builders>
2026-08-09 21:09:36 +00:00
Codex Review
2aafc04018 docs: record delivered 0.6.1 runner exercise 2026-08-09 20:35:49 +00:00
github-actions[bot]
5693bee9f3 chore: bump main to 0.6.2-dev — a dev install must not impersonate 0.6.1 2026-08-09 19:47:02 +00:00
338cf5f754 Merge pull request 'release 0.6.1' (#226) from release-0.6.1 into main
Reviewed-on: heavy-duty/ceremony#226
Reviewed-by: cluade-reviewer-andresmgsl <andres+1@heavyduty.builders>
Reviewed-by: kimi-reviewer-andresmgsl <andres+4@heavyduty.builders>
Reviewed-by: glm-reviewer-andresmgsl <andres+5@heavyduty.builders>
2026-08-09 19:43:10 +00:00
Codex Review
b104eca141 docs: record 0.6.1 Forgejo rehearsal 2026-08-09 18:20:49 +00:00
Codex Review
ba3b17af88 release: stage 0.6.1 ceremony 2026-08-09 16:12:18 +00:00
0371f2cfd6 Merge pull request 'chore: restore kimi to the review panel (#224)' (#225) from issue-224-kimi-panel into main
Reviewed-on: heavy-duty/ceremony#225
Reviewed-by: cluade-reviewer-andresmgsl <andres+1@heavyduty.builders>
Reviewed-by: kimi-reviewer-andresmgsl <andres+4@heavyduty.builders>
Reviewed-by: glm-reviewer-andresmgsl <andres+5@heavyduty.builders>
2026-08-09 15:38:11 +00:00
Codex Review
5487f71ef8 chore: restore kimi to review panel (#224) 2026-08-09 14:57:09 +00:00
a953884826 Merge pull request '.github/labels.conf + CONTRIBUTING + labels.test — the panel names an identity that can actually review (#222)' (#223) from build/222-panel-glm into main
Reviewed-on: heavy-duty/ceremony#223
Reviewed-by: kimi-reviewer-andresmgsl <andres+4@heavyduty.builders>
Reviewed-by: glm-reviewer-andresmgsl <andres+5@heavyduty.builders>
2026-08-06 18:32:33 +00:00
b7a6aedc52 Merge pull request 'changelog.d/220.md — the 0.4.1 → 0.6.1 gap statement (#220)' (#221) from build/220-gap-fragment into main
Reviewed-on: heavy-duty/ceremony#221
Reviewed-by: kimi-reviewer-andresmgsl <andres+4@heavyduty.builders>
Reviewed-by: glm-reviewer-andresmgsl <andres+5@heavyduty.builders>
Reviewed-by: codex-reviewer-andresmgsl <andres+2@heavyduty.builders>
2026-08-06 16:53:16 +00:00
b63637b478 Merge pull request 'labels-sweep — pass bootstrap through the workflow_call boundary it was lost at (#215)' (#218) from build/215-bootstrap-bridge into main
Reviewed-on: heavy-duty/ceremony#218
Reviewed-by: kimi-reviewer-andresmgsl <andres+4@heavyduty.builders>
Reviewed-by: glm-reviewer-andresmgsl <andres+5@heavyduty.builders>
Reviewed-by: codex-reviewer-andresmgsl <andres+2@heavyduty.builders>
2026-08-06 16:53:04 +00:00
2b49d6ef59 fix(labels): the panel names an identity that can actually review (#222)
kimi-reviewer-andresmgsl is temporarily unavailable, and with a three-identity
panel it sits in the required set for every possible author — so no new PR
could converge while it is down. glm-reviewer-andresmgsl takes the seat.

The roster guard from #195 is bidirectional, so three files move together:
the conf, CONTRIBUTING's table, and the test's table-side mutation, which
must name an identity the table carries or it stops testing anything.

Refs #222
2026-08-06 11:33:42 +00:00
clad2
286403da78 docs(changelog): drop the entry that pre-decided #219 spec 6
'By decision rather than omission' published a back-tagging ruling that
belongs to the operator and has not been made. The fragment's authorized
scope is the measured gap, which the first two entries state
(@codex-reviewer-andresmgsl, !221 review).

Refs #220
2026-08-05 23:15:24 +00:00
clad2
b7775c68ea docs(changelog): the 0.4.1 -> 0.6.1 gap statement, as a grouped fragment
Three Changed entries naming what a reader comparing the two forges' tags
would otherwise reconstruct: 0.5.0/0.6.0 arrived by merge and were never
released here; the carried ## 0.6.0 section is upstream's record; and the
absent 0.6.0 tag is a decision, not an omission. Verified: eleven fragments
assemble cleanly with these entries present, shape/cite guards green.

Refs #220
2026-08-05 23:10:25 +00:00
clad2
960e581f91 test(labels): remove the remaining dead event-name assignments
All three schedule-simulation probes carried the assignment the script no
longer reads. This time the head was verified clean BEFORE the push, not
after. Refs #215
2026-08-05 21:39:45 +00:00
clad2
7d387dd936 test(labels): drop the now-dead event-name assignment SC2034 flagged
The script stopped reading GITHUB_EVENT_NAME with the input gate; the
previous commit pushed with this red because I trusted an && echo that
printed nothing. Refs #215
2026-08-05 21:35:55 +00:00
clad2
6986deede7 fix(labels): the bootstrap keys on the BOOTSTRAP input, never the event name
The venue drill caught what no hermetic test had: with the workflow_call
bridge delivering "no" perfectly, drill runs 16/17 still bootstrapped. The
script gated on GITHUB_EVENT_NAME = workflow_dispatch and never read
$BOOTSTRAP at all; the wrapper's only coupling was exporting the event name
for yes. Correct while an operator's manual dispatch was the only dispatch
there was — inert from #209 on, when the trigger job made every machine wake
a workflow_dispatch event. Runs 459/523 bootstrapped for this reason, not
for the input-delivery defect, which is real but was never the operative
cause of the observed re-upserts.

The script now gates on ${BOOTSTRAP:-no} = yes; the wrapper passes the input
through untouched; the hermetic suite pins the exact regression pair (a
dispatch event with no/unset creates and deletes nothing) alongside the
yes path's full create+delete assertions.

Refs #215
2026-08-05 21:32:21 +00:00
clad2
ceaf66bd13 docs(labels): claim the measured invariant, not an unmeasured Forgejo defect
The evidence shows the called workflow did not see the caller's event inputs
on THIS instance while the top level received them (runs 459/523 vs probe
6/7); it does not show what GitHub or a declared-and-passed input does, so
every prose site now states declare-and-pass as the measured-reliable channel
rather than attributing a drop to Forgejo (@codex-reviewer-andresmgsl, !218
blocker 2).

Refs #215
2026-08-05 21:18:29 +00:00
clad2
69d674cb67 docs(changelog): split the test entry under the 300-character bound
Pushed the previous commit with this red — the cite check names the bound and
I read only the first failure it printed. Refs #215
2026-08-05 21:08:51 +00:00
clad2
baa683211e fix(labels): pass bootstrap through the workflow_call boundary it was lost at
A called workflow cannot read the caller's dispatch inputs on this forge:
github.event.inputs is empty inside workflow_call even though the top-level
caller receives the value in both contexts (probe runs 6/7). The sweep's gate
read exactly that, so every dispatch-woken sweep bootstrapped — runs 459 and
523, ~20 label upserts per board event — while the trigger honestly logged
bootstrap=no.

The bridge, per the #6361 contract: labels-sweep.yml declares
workflow_call.inputs.bootstrap (string, default "no"); the dogfood caller and
the published CONSUMERS.md stub pass it via with.bootstrap with empty mapped
to "no" at the caller — kimi's edge: on schedule the top-level context is
empty, and an empty that slipped through would have turned every cron into a
bootstrap. The gate feeds the declared input to labels-reconcile unchanged,
so an invalid value meets the action's own yes|no refusal.

test/labels-bootstrap.test.sh pins every hop: the declared boundary, both
gates as the identity, no expression reading github.event.inputs (scoped to
${{ }} bodies — the file's prose names the context to explain it), the two
pass-throughs byte-exact, and the four value paths driven through the shipped
expressions into the action's real validator. Mutations: dropping the
declaration reds 4, dropping the pass-through reds 3, restoring the old gate
reds 2.

Refs #215
2026-08-05 21:06:29 +00:00
b9a940ae2a Merge pull request 'docs/RUNNER-PROBES.md — record the venue's first delivered drills (#202)' (#216) from build/202-first-drills into main
Reviewed-on: heavy-duty/ceremony#216
Reviewed-by: codex-reviewer-andresmgsl <andres+2@heavyduty.builders>
Reviewed-by: kimi-reviewer-andresmgsl <andres+4@heavyduty.builders>
2026-08-05 20:52:25 +00:00
clad2
bae6f21b15 docs(runner-probes): the workflow-token record is comment 6262, not 6263
Off-by-one in the evidence anchor; a record that links the wrong comment is
a record that does not resolve (@codex-reviewer-andresmgsl, !216 round 2).

Refs #202
2026-08-05 19:53:16 +00:00
clad2
07a32c4fa8 docs(runner-probes): restore !207's release notes; per-run links; honest security lesson
Four corrections from @codex-reviewer-andresmgsl on 9c17a9e:
- changelog.d/202.md keeps !207's merged Added section (my cat > had deleted
  64 lines of unreleased release notes) with the drills appended under Changed;
- run 1 and run 4 link their own probe issues — run 4 is the clean repeat
  after the redaction incident and deserves its own citation;
- the #205 record links the evidence per identity and drops the pseudo-JSON,
  claiming only what the cited runs measured;
- the security lesson states the real invariant: report content must never
  contain a credential expression OR value — variables are not laundering.

Refs #202
2026-08-05 19:48:04 +00:00
clad2
9c17a9e4d8 docs(runner-probes): record the venue's first delivered drills
The owed-probes list keeps delivered probes with their probe-issue URLs: a
claim like 'the asymmetry reproduces' should carry a link a reader can open.
Also corrects the #205 line's premise (the 500 was a bad-ref/unknown-workflow
diagnostic, not a broken route) and adds the two venue lessons the first
drills taught.

Refs #202
2026-08-05 19:40:56 +00:00
c5e987eb89 Merge pull request '.github/workflows/labels.yml — wake the sweep over REST, so a board event reconciles in seconds (#205)' (#213) from build/205-dispatch-rest into main
Reviewed-on: heavy-duty/ceremony#213
Reviewed-by: codex-reviewer-andresmgsl <andres+2@heavyduty.builders>
Reviewed-by: kimi-reviewer-andresmgsl <andres+4@heavyduty.builders>
2026-08-05 18:08:32 +00:00
clad2
ed5ce8953a Merge remote-tracking branch 'origin/main' into build/205-dispatch-rest 2026-08-05 17:55:07 +00:00
9daeeb756e Merge pull request 'actions/refs-not-closing — gather over REST, so the guard produces verdicts on this forge (#199)' (#214) from build/199-refs-not-closing-rest into main
Reviewed-on: heavy-duty/ceremony#214
Reviewed-by: codex-reviewer-andresmgsl <andres+2@heavyduty.builders>
Reviewed-by: kimi-reviewer-andresmgsl <andres+4@heavyduty.builders>
2026-08-05 17:53:27 +00:00
clad2
3bde48f24c test(labels): unset GITHUB_API_URL in the no-api case — env preserves it
Plain `env` preserves the parent environment, and on the runner every step
arrives with GITHUB_API_URL set — the premise of the fix under test — so the
unset-refusal case inherited it and never exercised the refusal. It passed
only in a dev shell that lacks the variable: the environment distance
UPSTREAM-SYNC.md step 7 warns about, in the test written the same day
(@kimi-reviewer-andresmgsl, run 468).

Refs #205
2026-08-05 17:35:28 +00:00
clad2
0c2db9d85a test(labels): remove the stale never-silenced check, superseded behaviourally
The check grepped the gh workflow run line #205 removes, so it passed on
every REST implementation including one that swallows a failed POST — a
green assertion whose name claimed an invariant its implementation could not
observe. Its replacement lives in test/labels-dispatch.test.sh: a transport
failure must fail the extracted step, plus a code-aware no-|| true guard
(@codex-reviewer-andresmgsl, !213 review round 2).

Refs #205
2026-08-05 17:27:17 +00:00
clad2
396744618f Merge remote-tracking branch 'origin/main' into build/199-refs-not-closing-rest 2026-08-05 17:19:11 +00:00
clad2
768d54d1db Merge remote-tracking branch 'origin/main' into build/205-dispatch-rest 2026-08-05 17:19:10 +00:00
94d5b81964 Merge pull request 'drills/README.md — the standing runner-probe venue, and why the drill disposal rule does not apply to it (#202)' (#207) from build/202-runner-probe-venue into main
Reviewed-on: heavy-duty/ceremony#207
Reviewed-by: codex-reviewer-andresmgsl <andres+2@heavyduty.builders>
Reviewed-by: glm-reviewer-andresmgsl <andres+5@heavyduty.builders>
Reviewed-by: kimi-reviewer-andresmgsl <andres+4@heavyduty.builders>
2026-08-05 17:18:58 +00:00
clad2
37e31ffd85 fix(labels): refuse an unset API root, name transport failures, update the docs
Three corrections from @codex-reviewer-andresmgsl's review of 935a813.

1. `api="${GITHUB_API_URL:-https://api.github.com}"` guessed GitHub when the
   variable was absent — driven with a recording curl, it reported success
   after POSTing to api.github.com from this forge. That is the "Never
   'probably github'" rule, and the same unset-environment refusal #201 just
   established for docs-sync. It now refuses before any request, and the test
   asserts zero calls were made: refusing after a POST is not refusing.

2. The "never silenced with || true" invariant was still asserted by grepping
   the gh line this port removed, so it passed on any REST implementation
   including one that swallows a failed POST. It is rebound behaviourally: a
   curl that dies at the transport must fail the step. Doing that revealed the
   step failed with a bare exit 7 and no sentence, so it now names the failure
   — owning the diagnostic is the whole point of the surrounding code.

3. docs/CONSUMERS.md and both caller comments still described `gh workflow
   run` as the mechanism. They describe the REST dispatch now, and the manual
   bootstrap command carries a forge-neutral curl form beside the gh one: a
   cross-forge runbook that sends this forge to a missing binary is wrong even
   where the prose around it is right.

Refs #205
2026-08-05 17:16:30 +00:00
clad2
4e28d437d6 fix(refs-not-closing): gather over REST, so the guard produces verdicts here
The action's entire gather was one GraphQL query asking GitHub for its own
parse of the closing keywords. Forgejo serves no GraphQL at all — /api/graphql
404s here and a forgejo-runner job arrives with GITHUB_GRAPHQL_URL empty — so
there was nothing to translate it to. It is re-expressed, as #188 re-expressed
its own two GraphQL sites, over two reads both backends serve plus this repo's
own parser.

The graph was called authoritative for including "closing keywords and sidebar
links". Those halves resolve differently here: Forgejo has no sidebar-link
concept, so nothing is lost there, but it DOES honour closing keywords in
commit messages. A body-only port would miss a PR that closes an issue from a
commit subject — exactly the contradiction this action exists to catch — so
the closing set unions the body and every commit message.

The hasNextPage refusal is relocated, not dropped: --paginate carries the
forgejo backend's x-total-count completeness proof, and a short gather refuses
rather than returning a partial verdict.

lib/issue_references.sh extracts the LOCAL/CROSS classifier from
issueflow-reconcile's executable. closes_references.sh's header recorded that
dependency in prose; a composite action cannot source a reconciler to borrow
one function, because sourcing a reconciler runs one.

refs-guard.yml's github-only gate is removed in the same change. A portable
action behind that gate is a guard that passes by never running.

The contract test drives the boundary on BOTH backends with stubs at the
transport. Mutations: body-only parse reds 4 cases, dropping --paginate reds
the partial-gather case, ignoring a failed read reds 9.

Refs #199
2026-08-05 17:11:19 +00:00
clad2
935a813d75 fix(labels): wake the sweep over REST, so board events reconcile in seconds
`.github/workflows/labels.yml` dispatched the sweep with `gh workflow run`,
the eighth runtime gh call site the 0.6.0 merge reintroduced and the only one
!204 did not port. On this forge the runner carries neither gh nor a GitHub
API, so the step refused and the entire event-driven reconcile path ended
there — every transition waiting up to an hour for the scheduled sweep.

The workflow-dispatch endpoint has the SAME shape on both forges:

  POST {api}/repos/{owner}/{repo}/actions/workflows/{file}/dispatches
  {"ref": "<branch>", "inputs": {...}}  -> 204, empty body

so the step no longer decides a forge at all. The CEREMONY_FORGE_CLIENT=gh
declaration and both inline refusals are removed rather than ported, and
test/no-runtime-gh.test.sh now asserts their ABSENCE — an opt-out with no gh
behind it is a standing permission slip.

The ref is supplied explicitly and taken from the repository, never from
GITHUB_REF_NAME: on a pull_request_target run that is `<n>/merge`, which is
not a branch. A non-204 still fails the job, keeping the misconfiguration
alarm the trigger exists to be, and the diagnostic explains Forgejo's empty
500 rather than passing a bare status to a reader who will go looking for an
outage that is not there.

test/labels-dispatch.test.sh extracts the shipped step and executes it against
a recording stub, asserting the method, endpoint, ref and inputs actually
sent. Dropping the inputs or ignoring a non-204 both red the suite.

Refs #205
2026-08-05 16:58:05 +00:00
clad2
262705d394 Merge remote-tracking branch 'origin/main' into build/202-runner-probe-venue 2026-08-05 16:29:10 +00:00
a13aa6d4b9 Merge pull request 'fix(docs-sync): the doctrine mirror is fetched from the forge in play, never a built-in one (#201)' (#203) from build/201-docs-sync-forge-source into main
Reviewed-on: heavy-duty/ceremony#203
Reviewed-by: glm-reviewer-andresmgsl <andres+5@heavyduty.builders>
Reviewed-by: codex-reviewer-andresmgsl <andres+2@heavyduty.builders>
Reviewed-by: kimi-reviewer-andresmgsl <andres+4@heavyduty.builders>
2026-08-05 16:28:23 +00:00
clad2
65cee3fdf9 Merge remote-tracking branch 'origin/main' into build/202-runner-probe-venue 2026-08-05 15:54:29 +00:00
clad2
1bf7091d39 Merge remote-tracking branch 'origin/main' into build/201-docs-sync-forge-source 2026-08-05 15:54:29 +00:00