Commit graph

26 commits

Author SHA1 Message Date
Codex Review
f766752090 drill: arm 0.6.1 candidate ref 2026-08-09 16:14:28 +00:00
Codex Review
ba3b17af88 release: stage 0.6.1 ceremony 2026-08-09 16:12:18 +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
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
adf907c963 fix(198): the action fails closed, the caller decides scheduling, the guard decides the forge (#198)
@codex-reviewer-andresmgsl's second review, both points taken.

The refs action goes back to `forge_preflight || exit 1`. 97e63ac had it exit 0
with a notice so the PR check would not be red, and that conflated two
different questions: "this action cannot produce a verdict" is the ACTION's
contract and must stay a refusal, while "this check should not block the
board" is the CALLER's decision. The caller now carries it —
refs-guard.yml skips unless github.server_url is github.com, mirroring
forge_detect positively. A skipped check is a green head; an action that
reports success it did not earn is not. The leaked preflight_err temp file
goes with the revert.

The workflow guard asked the wrong question. `command -v gh` alone passes the
moment a Forgejo runner image happens to ship gh, and then dispatches against
a forge that cannot serve it — the client/forge mismatch forge_preflight
exists to prevent. It decides the FORGE first now, mirroring forge_detect
positively, and the binary second. The source guard splits to match: a
declaration guarded only by binary presence is reported, with a fixture that
fails on exactly that shape.

The warning text was also wrong on the facts, as noted: issue-event sweeps ARE
this caller's event-driven wakes, so they are precisely what is lost. It now
says the hourly scheduled sweep survives and every event-driven wake through
this caller does not, until #205.

Point 1 of that review — jq 1.6 accepting an empty payload — was already fixed
in 728102a, pushed before the review landed.

Verified under the runner's jq 1.6 as well as 1.7: 28 test files, 0 failed
both ways. shellcheck 0.10.0 (CI's pin), actionlint, self-ref, marker,
vendored, changelog-armed all clean with every file tracked.

Refs #198
2026-08-05 12:30:28 +00:00
06f05aebec fix(198): the workflow declares and refuses instead of being exempted by name (#198)
@codex-reviewer-andresmgsl's blocker 1 is right and the filename exemption was
the wrong shape. It exempted the whole FILE — any later `gh` call anywhere in
labels.yml would have ridden in free — and it let the merge ship a step that
dies with `command not found` on every sweep on this forge, which #197's bar
does not permit.

The declaration mechanism already existed; a workflow simply could not reach
it. It can: `CEREMONY_FORGE_CLIENT: gh` in the step's env is the same
declaration actions/refs-not-closing carries, and the refusal that a script
gets from forge_preflight is inline here because a workflow has no shell to
call it from. The dispatch now warns by name, cites #205, and exits 0 rather
than reddening every sweep for a known gap.

So the guard needs no exemption list at all. It now requires the pair —
declared AND refusing — and reports a declaration that carries no refusal,
which is a permission slip for `command not found`.

That predicate was wrong on its first write, and its mutation test caught it:
`refuses_when_unavailable` matched the word `forge_preflight` inside
labels.yml's own comment explaining that it has NO forge_preflight to call. A
guard reading prose as evidence is the blind sweep again, in the guard written
to forbid it. Comments are stripped now, as gh_calls already stripped them.

Blocker 4: the nudge strips a trailing slash from the server URL. Reverting the
strip reds two cases.

Blockers 2 and 3 were already fixed in 97e63ac, before either review landed.

test/run.sh 28 files 0 failed under CI's env; shellcheck 0.10.0 (CI's pin),
actionlint, self-ref, marker, vendored and changelog-armed all clean, with
every file tracked this time.

Refs #198
2026-08-05 12:16:53 +00:00
cndgrr
fb8f8282a9 release: cut 0.6.0
Thirty-five fragments assembled into '## 0.6.0 — 2026-08-05'; VERSION to
bare 0.6.0; the three CEREMONY_SELF_REF carriers stamped "0.6.0" in this
one commit; the three docs/CONSUMERS.md availability markers cleared to
name 0.6.0 — refs-not-closing (#218), the RELEASES.md mirror entry (#248)
and the vendored-manifest completeness guarantee (#251).

drills/0.6.0.md opens with the measurement that decides its shape: the
doors-unchanged conditions do NOT all hold at this candidate, because
lib/changelog.sh moved on the release path since the last rehearsed tag
0.4.0. A full disposable-repo rehearsal is owed and is in progress; the
record is committed early and filled from the runs as they happen.

Refs #249.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-05 00:01:03 +00:00
dan-claude-bot
e5e7555184 release: cut 0.5.0
Five fragments assembled into '## 0.5.0 — 2026-08-03' (#205 #216 #221
#224 #226); VERSION to bare 0.5.0; the three CEREMONY_SELF_REF carriers
stamped "0.5.0" in this one commit; the panel-rows unreleased marker in
docs/CONSUMERS.md cleared to name 0.5.0; drills/0.5.0.md records the
doors-unchanged ruling with the measurements as they are at 0ac3a6f.

Refs #233.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-03 12:01:05 +00:00
dan-claude-bot
74d59e9554 release: cut 0.4.1
Consume the two displacement-fix fragments into the 0.4.1 section, stamp
VERSION and every CEREMONY_SELF_REF carrier, and record the doors-unchanged
drill ruling with the candidate-head evidence table.

Refs #212

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-01 17:54:47 +00:00
dan-claude-bot
be660358f2 docs: spell out crew's four-edit migration; fold in crew#250 field facts (#209)
crew#250 verified two facts the design prose now carries: a queue-
displaced run is not independently rerunnable (gh run rerun / --failed /
--job all refuse), so a victim PR had no manual escape hatch; and the
displacing burst is deterministic — one review_requested event per
panelist per request — so displacement is the steady state of a working
fleet, scaling with panel size, not a traffic spike.

CONSUMERS.md now walks the adoption as one atomic four-edit PR with crew
as the worked example: the pin bump in every ceremony uses: reference,
the new labels-sweep.yml caller, the cron RELOCATED (bold warning: a
copied-not-moved schedule double-fires sweeps into the one shared group
and reads as the bug getting worse after the fix), and actions: write
replacing the labels caller's actions: read.

Refs #209

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-01 17:25:26 +00:00
dan-claude-bot
45aa806207 labels: detach the reconcile sweep from PR-triggered runs (#209)
The sweep rode the same workflow run as the PR event that woke it, so
every displacement in the shared labels-reconcile queue recorded a
CANCELLED reconcile check on some PR — fake red CI that held review
requests. The reconcile + issueflow jobs move, unchanged, to a new
reusable labels-sweep.yml behind their own caller; labels.yml gains a
trigger job that dispatches the consumer's sweep caller with the plain
GITHUB_TOKEN (workflow_dispatch is a documented no-retrigger exemption)
on every event that used to run reconcile. A displaced sweep now cancels
on the Actions tab, attached to no PR; PR checks show scope + trigger.

Because every trigger-driven wake arrives as workflow_dispatch, the event
name alone no longer separates the operator's manual bootstrap from an
event-woken sweep: the sweep caller's bootstrap dispatch input does — the
trigger passes no, a bare manual dispatch defaults to yes. The sweep
reusable also takes pr_workflow_name, exported as SELF_WORKFLOW for the
#208 reconciler (harmless to earlier ones; zero file overlap with #208).

The trigger is deliberately loud: a pin bumped without the sweep caller,
its bootstrap input, or actions: write on the labels caller goes red at
the trigger job instead of silently never sweeping again — documented in
docs/CONSUMERS.md with the split stubs and the atomic-adoption note.

Refs #209

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-01 16:20:00 +00:00
codex-bot-andresmgsl
7c755bcd40 release: stamp 0.4.0 candidate 2026-07-29 10:51:51 +00:00
claude-bot-andresmgsl
8cf3c335df labels: name what the hourly cron uniquely covers (#199 round)
The trigger comments, CONSUMERS stub, changelog, and reusable labels.yml
comment said "events carry every real state change in seconds; the cron
only backstops a forgotten handoff." That is backwards: no subscribed
event wakes this sweep for a review verdict landing (no pull_request_review
trigger), blocker:ci-red set/cleared, blocker:conflict when another PR
merges, or the time-based stale/48h-reclaim. The hourly cron is the sole
discovery path for those four classes, not a forgotten-handoff net —
so the comments now name them and warn against deleting the cron (AC5).

codex-2 / kimi-2 (both blocking, round 2 @0a812c4b).
2026-07-28 19:26:40 +00:00
claude-bot-andresmgsl
0a812c4b19 labels: keep edited/reopened on issues; correct 0.3.0 adoption prose (#199 round)
Round fixes on #200.

codex-1 (blocking): the issues narrowing dropped `edited`/`reopened`, but both
carry a queue-state change an event uniquely carries — `edited` a body rewrite
of the `Blocked by #N` declaration the sweep parses
(issueflow-reconcile.sh:179), `reopened` a closed issue re-entering the queue.
Dropping them tripped #199's must-fail. Narrow to
`[opened, closed, edited, reopened]`, dropping only the churn/validation
actions labeled/unlabeled/assigned/unassigned. Trigger tests now pin
edited/reopened present and the four dropped; labels.test.sh exact-list updated.

kimi (blocking): the "supersedes unreleased #144" prose was false — #144's
edited/reopened shipped in 0.3.0. Dissolved: we now keep them. CONSUMERS prose
rewritten to the real version history (0.2.0 #32 / 0.3.0 #144 / #199 narrows),
and the #137 review-request line corrected from "unreleased" to shipped-in-0.3.0.

kimi (non-blocking): reusable labels.yml comment no longer cites */15.

codex-2 (AC1 after-measurement / closing) escalated to triage on #199 — held,
not guessed.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-28 19:04:27 +00:00
codex-bot-andresmgsl
da186729c5 release: prepare 0.3.0 2026-07-24 17:06:25 +00:00
Daniel Marin
6a16a30bab
Merge pull request #143 from claude-bot-andresmgsl/build/137-review-request-wake
fix: review_requested wakes the labels sweep — blocker:unrequested clears when the ask lands
2026-07-24 14:33:11 +01:00
Daniel Marin
ad5c175d0c
Merge pull request #133 from claude-bot-andresmgsl/build/130-labels-scope-clobber
fix: labels/scope writes additively — a label applied mid-job survives
2026-07-24 14:14:03 +01:00
claude-bot-andresmgsl
c0e796b6c9 fix: review_requested wakes the sweep — blocker:unrequested clears when the ask lands
The reconciler's rule was right and blind: the caller never listened on
review_requested/review_request_removed, so the one event that falsifies
(or restores) blocker:unrequested could not clear it, and a quiet repo
wore the red flag until the advisory cron (#137's timeline: 93 seconds,
cleared only by an unrelated PR's push).

- self-labels.yml + the CONSUMERS.md stub gain both types; the scope job
  skips them (no paths change; running labeler there widens #130's window)
- test/labels.test.sh: caller/stub parity row with mutation cases —
  dropped type either side, one-sided reorder, all red
- CONSUMERS.md no longer claims trigger adoption is a bare pin bump; the
  pending stub edit is named and rides the first tag carrying ceremony#137

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-24 12:50:09 +00:00
claude-bot-andresmgsl
40029242cb fix(round): labeler.yml header tells the truth; labels-scope maps to scope:labels
The mapping header still described actions/labeler@v5 + sync-labels —
the exact mechanism this PR removed; it now describes labels-scope's
base-ref read and additive POST, keeping the #128 incident. The
scope:labels row gains actions/labels-scope/** and its test, and two
fixtures derive against the real mapping so the coverage is tested, not
just present. The reconcile job comment names labels-scope instead of
labeler (grok nit 3).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-24 12:22:09 +00:00
claude-bot-andresmgsl
53efbfba2a fix: scope job derives additively — labeler v5's PUT clobbered mid-job labels
actions/labeler@v5 writes the whole label set (setLabels PUT) even under
sync-labels: false, so a label applied between its read and its write is
silently removed — ceremony#128 lost `release` that way. v6/v7 write the
same way. Replace the step with actions/labels-scope: same labeler.yml
mapping (changed-files/any-glob-to-any-file subset, refused loudly
otherwise), changed paths via the API, and an additive POST as the only
write.

Part of #130.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-24 11:51:48 +00:00
codex-bot-andresmgsl
b632c19e97 release: assemble 0.2.0 2026-07-24 11:21:26 +00:00
codex-bot-andresmgsl
70db91fa1a fix: wire dogfood issue reconciliation 2026-07-23 10:47:30 +00:00
codex-bot-andresmgsl
8174080c9d feat: reconcile the issue work queue 2026-07-23 10:31:15 +00:00
claude-bot-andresmgsl
9782687bd7 feat: dogfood bootstrap — ceremony adopts its own ceremony (#11)
VERSION at 0.1.0-dev, the armed CHANGELOG.md, drills/README.md (what a
drill means here), the self-callers (self-release.yml, self-labels.yml —
local uses:, the one form consumers must never copy), .github/labeler.yml
for the scope job, and the three self-guards in CI. labels.yml gains the
self-consumption bypass (release.yml's twin) so the label bootstrap can run
before any release tag exists; action-exercise's armed/drill-recorded
scratch steps move to self-guards per their own eviction note.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-22 22:19:50 +00:00
codex-bot-andresmgsl
1ff660f539 docs: preserve labels workflow safety rationale 2026-07-22 18:21:11 +00:00
codex-bot-andresmgsl
60e417a13c feat: centralize labels machinery 2026-07-22 18:18:18 +00:00