Commit graph

474 commits

Author SHA1 Message Date
github-actions[bot]
8c3a4d1dee chore: bump main to 0.6.1-dev — a dev install must not impersonate 0.6.0 2026-08-05 09:35:51 +00:00
Daniel Marin
0ce6cb961a
Merge pull request #323 from cndgrr/build/249-release-0-6-0
release: cut 0.6.0
2026-08-05 10:35:37 +01:00
cndgrr
f832334abe drill 0.6.0: probes 5 and 6, the setup corrections, and the disposal state 2026-08-05 09:14:55 +00:00
cndgrr
6f30989e2a drill 0.6.0: probes 1, 3 and 4 recorded from their runs 2026-08-05 09:11:46 +00:00
cndgrr
24b69aea8e drill 0.6.0: the scratch repo, the candidate ref, and probe 2 2026-08-05 09:05:20 +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
Daniel Marin
d272964dac
Merge pull request #315 from cndgrr/build/311-readme-rewrite
README.md — rewritten whole from the current tree
2026-08-05 00:50:16 +01:00
cndgrr
263bb74652 README: three steps run past the tag, and the publish is one of them
The overview's fail-loudly paragraph said "Only two steps run past the tag"
and attributed the tag-standing/no-release state to the artifact hook alone.
Past `tag the merge commit` (release.yml:224) come three steps: the artifact
hook (:236), `publish the release` (:246) and the -dev re-arm (:267). The
publish is `gh release create --verify-tag`, so it can fail on the API call
or the assets with the tag already standing — the same state, from a second
cause.

State the count as three and sort them by what a failure leaves behind: two
fail before the release exists (hook, publish), both recovered by the tag
door; the third is the re-arm, still the one failure in the file that leaves
a real release behind. The nothing-exists recovery text names the publish
among the causes of a tag with no release too; its remedy is unchanged.
2026-08-04 23:29:12 +00:00
cndgrr
1410c01caf README: the forward pointer cites #317, never a version number
Triage's D6 (#311), added mid-round: the file's single forward-looking
sentence is sanctioned, and bounded. Two corrections to what round 4
landed, both of them the bound rather than the claim -- the claim itself
was re-measured by triage and holds.

- it named 'the 0.7.0 window'. Which release carries that work is a
  scheduling fact owned by the epic and RELEASES.md, where release-init
  may fold an empty window into a later release or skip the version
  outright, so the number can move with no diff under this file while
  every guard stays green. The issue number does not move: #317 is the
  stable name of the work.
- it was present indicative -- 'makes' -- one paragraph after banana
  rides row 6 today. It now reads as work that has not landed, on its
  own, without the reader chasing the link.

Still one sentence, still only in this section, and it weakens no
present-tense claim around it: the -dev half stays unreachable, the
malformed half stays live, and the manual bump stays the remedy today.

Refs #311

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-04 22:57:43 +00:00
cndgrr
a663c631bf README: two tag-door asserts, the artifact hook past the tag, doctrine is mirrored
codex's round-4 blockers, both reproduced against the tree:

- the opening introduced machinery and doctrine together as 'never
  copied', which the doctrine paragraph then contradicts by design — the
  .ceremony/ mirror is a copy, kept honest by a guard rather than by
  absence. The clause now says of each half what is true of it.
- the tag door has two refusing asserts, not one: tag/tree identity
  (release.yml L328-L339) and a publishable version section
  (L340-L352, changelog_section_problem), the second already quoted in
  this page's own troubleshooting catalog.

claude's N1, taken: the zero-artifact boundary is the tag, not the
publish — the consumer's artifact hook runs between them and its
non-zero exit aborts with a tag standing. The re-arm remains the single
failure that leaves a real release behind.

Per triage's steer, one line pointing the rc half of the re-arm refusal
at the 0.7.0 window (#317); the rc recovery prose is not widened.

Refs #311
2026-08-04 22:44:02 +00:00
cndgrr
ca44ee0f84 README: the overview's zero-artifact promise is the pre-publish one
The re-arm section corrected last round said the bump runs after publish and
its refusal leaves a release standing; the overview still promised an
unconditional -dev re-arm and zero artifacts on any failed assert. Scope the
guarantee to the asserts before the publish, name the rc exception where the
reader meets it first, and stop calling a malformed version's refusal
unreachable - only the -dev half is.
2026-08-04 22:12:29 +00:00
cndgrr
6df42797d2 README: reflow the npm entry and drop an overstated clause
The rc path is how this refusal is reached, not 'the one door an
operator actually walks through' -- most releases are bare and never
see it. Also rewrap the npm paragraph, left ragged by the previous
commit.
2026-08-04 21:42:23 +00:00
cndgrr
05e977814f README: point the two new anchors at the lines that carry the claim
version_is_dev's range started one line in, past the signature comment
that states the -dev-only rule; and the npm range stopped at L112,
before the npm pkg set / npm install --package-lock-only lines it was
cited for. L68-L76 and L114-L115.
2026-08-04 21:40:41 +00:00
cndgrr
052c8734b9 README: the re-arm refusal is the rc path, not an unreachable guard
The section called version_next_dev's refusal unreachable by reading
decide's sense of 'bare' (not -dev) into version_next_dev's regex
(^X.Y.Z$). An rc lives between the two: row 6 admits a labeled rc
transition as a shippable ceremony, the bump step gates only on
ceremony=yes, and its VER is the tree's version verbatim -- so an rc
release tags, notes, publishes, then refuses here. State that path and
its remedy (version.sh L78-L82: an rc's next version is a human
decision), keep the guard reading for the -dev/garbage half that really
is unreachable, and close the same conflation in row 6.

Also: version_write runs npm pkg set + a lockfile-only install, not
npm version (which would tag); and drop 'unarmed main' so the section
uses release.yml's one sense of armed.

Reported by claude-bot-andresmgsl on #315.
2026-08-04 21:38:27 +00:00
cndgrr
dac4946e43 README: the re-arm is the merge door's, so state its reach correctly
Self-caught while re-reading the section added in 87f300c. It said
version_next_dev's refusal was "the tag door's edge" — wrong twice. The tag
door does not bump at all (release.yml:303-307, cast's precedent: the
fallback does not rewrite main), and the merge door's bump runs only on
ceremony=yes, which decide rows 5-6 reach only on a transition TO bare. The
message is therefore unreachable through either door as they stand, and the
honest description is a guard against a future decide change, not an edge an
operator can hit today.

Writing a troubleshooting entry that sends an operator looking down the tag
door for a message the tag door cannot emit is the same defect this round is
fixing one paragraph up, so it does not get to ship in the fix.
2026-08-04 21:04:10 +00:00
cndgrr
87f300c453 README: re-measure the incubator drill and close the refusal catalog
The drill paragraph called incubator's drill "TBD". It has been defined in
heavy-duty/incubator since 2026-07-23 (f7851cb, refined 7c20a4e on 07-24):
the pre-release verify of the canonical candidate deployed to staging, its
smoke probe run inside the container on deployed credentials, the record
pinning commit SHA and image digest. Carried from main unmeasured, which is
the one thing D1 forbids. With incubator named the paragraph enumerates five
meanings, not three, so its own tally closes now too.

The refusal catalog claimed to be generated from the sources, but its
regeneration grep never read lib/version.sh — the four version_read messages
it quotes all live there. Adding version.sh to the documented command turned
up four more refusals the catalog was missing: unknown backend on the read
side, and version_next_dev / version_write's two on the post-release re-arm,
which release.yml:275,283 really can emit. The re-arm ones get their own
section because their remedy is unlike every other entry here — the tag and
the publish already happened, so the fix is a manual bump, not a re-run.

One refusal stays outside the grep by construction: "no version field" is a
console.error inside the node one-liner, with no >&2 and no "refuse ". The
section now says so rather than shipping a command that silently
under-produces the catalog it claims to generate.

Answers codex-bot-andresmgsl and kimi-bot-andresmgsl (blocking, both the
incubator claim) and claude-bot-andresmgsl nit 2, at head 57a7b15.
2026-08-04 20:59:30 +00:00
cndgrr
57a7b156ac README.md rewritten whole from the current tree 2026-08-04 20:22:13 +00:00
cndgrr
8080618a70 changelog.d: the README is rewritten whole from the current tree 2026-08-04 20:17:30 +00:00
Daniel Marin
d24a3142a6
Merge pull request #314 from cndgrr/build/307-issueflow-ruling-preread-pin
test/issueflow-reconcile.test.sh — pin the claimed-branch ruling pre-read (#307)
2026-08-04 21:11:57 +01:00
cndgrr
3af132edf7 changelog.d: the claimed-branch ruling pre-read is pinned
Grouped shape, terminal cite, 287 characters.

Refs #307
2026-08-04 19:44:42 +00:00
cndgrr
3bba47bacf test: pin the claimed-branch ruling pre-read against its own diagnostic
`claimed` + `needs-ruling` with no assignee posts `claimed-unassigned`
before the tail, so the top read is the only reason the ruling nudge
below still sees the real quiet. Probe 110 asserts both outputs of one
sweep and reds when that read drifts below the post.

Recovered from ed588a2 by sha — the branch ref was deleted and the push
crossed the merge — then re-measured at fd22bd2, behind #293. 486 -> 488
on this file.

Refs #307
2026-08-04 19:39:05 +00:00
Daniel Marin
fd22bd2fe7
Merge pull request #312 from cndgrr/build/293-issueflow-flags
issueflow-reconcile — the sweep flags what the window and collision rules forbid: unblocked twins, and an unblocked non-member during a standing window
2026-08-04 20:29:42 +01:00
cndgrr
20e35b15da the release note says unblocked, not ready
D3b corrected the window flag to fire on `claimed` too, PR in flight or
not; the fragment still described it as a `ready` non-member, which is
the reading the ruling struck.
2026-08-04 19:03:24 +00:00
cndgrr
13605cf4b6 pin family scoping in the direction that carries it, and D3b on the window side
The family-scoping fixture asserted that a foreign marker does not
SILENCE the flag, which a family-blind grep satisfies too. The property
that is load-bearing is the other one: a foreign family late on the
thread must not make the flag re-post. Made family-blind, the sweep now
reds.

D3b says a claimed non-member is flagged whether or not it has an open
PR, and the fixtures covered that for the collision flag only — the
window side, which is the flag the 18:11Z correction was about, had no
case at all.
2026-08-04 19:00:48 +00:00
cndgrr
4f852ee152 the normalization fixtures fail for the reasons they are named for
check() matches its expectation as a substring, so a bare
`issueflow-reconcile` row was satisfied by `issueflow-reconcile.test`
too: the multi-extension rule stayed green under a normalization that
strips only the last extension. keys_of brackets each key, and the
no-em-dash row asserts its emptiness through grep rather than through an
expectation check() cannot make.

Beside them, the cases the two fixes are named for: a self-folding + title
answers its key once and never chains an issue to its own number, and
`needs-triage` and a label-less issue are outside both flags.
2026-08-04 18:58:21 +00:00
cndgrr
919135db12 the two flags mean one thing by unblocked, and a key set is a set
B1: deliverable_keys answered a multiset, so a `+` title whose segments
normalize to one key made collision_flags find the issue adjacent to
itself and chain it to its own number — the comment asked an issue to
declare `Blocked by` itself, and two such carriers corrupted the chain
between them. The keys are deduped where the set property belongs.

B2: window_in_scope excluded only blocked/epic/post-merge, admitting
`needs-triage` and label-less issues, so the sweep could add
`needs-triage` to an issue and then tell it about a mint-time membership
call in the same pass. Both flags now call one unblocked_claimable
predicate — #293 D2 corrected gives one gloss on `unblocked` and D3b
says D3 uses it.

The window log line says "unblocked", not "ready": D3b corrected exactly
that wording, and the flag fires on `claimed` too.
2026-08-04 18:54:52 +00:00
cndgrr
5d13573c53 fixtures take the corpus correction and the three ruled cases
Triage ruled all three questions (18:11Z) and corrected the corpus: at the
10:28:54Z mint #257 was `ready`, not `claimed`, and #253 was `claimed`
with NO open PR — #285 was not created until 10:49:16Z. The morning board
takes that shape, which also makes the six `ready` non-members come out as
six, and puts the blocked twin on the board rather than only in a decision
probe.

D2's parenthetical is struck: unblocked = open and not blocked, both flags,
one definition. D3b is corrected in the same direction — a non-member
`claimed` WITH an open PR is flagged too, because a non-member holding a
builder and a review round is #292's competition realized, not a mild case
of it. Nothing in the implementation moves: neither flag ever consulted PR
liveness.

Three cases added, so the fixtures pin the rulings and not the prose:

- both carriers `claimed` with their own PRs open -> still flags. The
  ninety-three minutes from #285's creation to its merge are exactly when
  the struck parenthetical went silent on a live collision, which made the
  flag's firing a property of someone's workflow rather than of the board.
- a fifteen-member declaration with every member closed -> D3 dormant, and
  the release issue never flagged as its own non-member. A gate declaration
  never empties; the precondition is its OPEN members, read off the board.
- flagged -> resolved -> recreated unchanged -> silent, asserted as D4's
  stated boundary rather than left accidental.

Plus today's board — the `blocked` sink, a `claimed` gate member, two
`blocked` issues — which draws nothing. Verified live as well as in
fixtures: a DRY_RUN sweep of this branch against heavy-duty/ceremony's real
board draws zero flags of either kind.
2026-08-04 18:21:56 +00:00
cndgrr
bdcc211a0b the sweep flags what the window and collision rules forbid
Two advisory flags on the issue-flow sweep, the mechanical backstop for
#288's collision rule and #292's window rule. Both are prose today, and
both failed silently on the same morning: #284 was minted `ready` into a
file another issue held claimed with a PR in flight, and six `ready`
non-members raced an emptying gate. #262 measured the pattern — the same
class of rule, once in a guard, produced zero misses.

Comments only (D1): no label write, no state change, no new label. The
sweep never guesses intent; it states the board fact and triage resolves.

The collision key is the title's em-dash prefix NORMALIZED, because the
2026-08-04 miss spelled one deliverable two ways — `actions/issueflow-reconcile`
against bare `issueflow-reconcile` — so exact-prefix matching would have
missed the pair it was written for. One leading path segment comes off,
then every extension; a `+`-joined title matches on any segment.

The flag asks for a CHAIN, not a fan (#288 D3): within one key each issue
names the newest open carrier below it, so the declaration it asks for
releases exactly one successor per close.

A standing window is a release issue whose gate still holds an OPEN member.
The board read IS the open set, so membership decides openness with no
extra call, and an all-closed gate is the emptied gate the release's own
blocked -> ready promotion answers — which is why a `ready` release leaves
the flag dormant instead of flagging the whole board.

Dedup is the declaration echo's, extracted into state_marker /
state_echo_needed and scoped per family (D4): the marker is keyed to the
offending state's value and compared against that family's last word on
the thread, so a state that changes always speaks.

Fixtures replay the 2026-08-04 morning board whole and the post-ruling
board beside it: the first draws exactly four collision flags and six
window flags and writes not one label; the second draws none.

Closes #293.
2026-08-04 18:15:00 +00:00
cndgrr
90a35008a1 wip: the collision and window board flags, decisions and gather
Both checks ride the existing sweep walk and write nothing but comments
(#293 D1). The board read now answers the whole payload, because both
decisions are over the WHOLE board — every open issue's labels and title,
and every open release issue's body — and a second pagination for the same
rows would be a second board free to disagree with this one mid-sweep.

Fixtures still owed.
2026-08-04 18:06:03 +00:00
Daniel Marin
2807d34c74
Merge pull request #308 from andriujoseba/build/292-window-graph
docs: make standing release windows explicit graphs
2026-08-04 18:52:48 +01:00
Daniel Marin
b32d8253e7
Merge pull request #310 from dan-claude-bot/build/302-labeler-map-rows
fix: the labeler map learns lib/attention.sh — and the surfaces it never knew
2026-08-04 18:45:46 +01:00
Andriujose
d81b04148e docs: scope window insertion to immediate successors 2026-08-04 17:39:46 +00:00
dan-claude-bot
f5bac7c7ee fix: the labeler map learns lib/attention.sh and the surfaces it never knew (#302)
lib/attention.sh had #267 D4's premise exactly — both reconcilers source
it, nothing release-side does — and [scope:release-flow] alone was a
wrong answer of the class that decision exists to correct. The sweep
workflow pair joins beside its trigger pair (detached in #209), the
shared-lib tests take scope:labels alone (a test inherits no lib/**
glob), and D4's seven enumerated rows land one each. No catch-all, by
decision: both directories span all four scopes. Each of the 13 new map
rows is protected by its own assertion — deleted alone, each reds
exactly its case.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-04 17:28:37 +00:00
Andriujose
ad5d988563 Merge remote-tracking branch 'origin/main' into build/292-window-graph 2026-08-04 17:28:26 +00:00
Daniel Marin
0c7d7e758c
Merge pull request #306 from cndgrr/build/304-reconcile-fixture-roster
fix(test): the labels-reconcile fixtures stop reading the live roster (#304)
2026-08-04 18:25:30 +01:00
Andriujose
630fd116c2 docs: distinguish window fan-out from collision chains 2026-08-04 17:23:03 +00:00
Andriujose
830a643a4b docs: make standing release windows explicit graphs
Add the mint-time membership call, the sink/source/subset invariants, and the release note while the contradictory successor-count criterion awaits triage clarification.\n\nCloses #292.
2026-08-04 17:12:48 +00:00
cndgrr
66a0eb5d65 test(labels-reconcile): fixture roster replaces the live panel by slot
The state-machine fixtures bound BOT1/BOT2/BOT3 to REQUIRED_BOTS by index off
the shipped .github/labels.conf, so three fixtures silently required a
four-member panel=. Shrinking it to three left the third slot unbound and
set -u aborted the file before assertion 1: 217 assertions became 0, on main
and on every branch cut from it.

The fixtures now write their own conf, in test/labels.test.sh's shape, at all
three load sites (top of file, the #205 re-drafted-round block, and the
mutant_blockers subshell). One live-file case survives as a property — the
shipped conf parses and recuses each member from its own panel — with no
index and no expected size, and a copy whose panel= names nobody proves it
still has teeth.

Refs #304
2026-08-04 17:04:09 +00:00
Daniel Marin
97cc00e268
Merge pull request #303 from dan-claude-bot/build/284-ruling-clock-comments-only
fix: the issue-side ruling clock reads comments only — an assignment is the claim's fact
2026-08-04 17:49:57 +01:00
Daniel Marin
404c4f6099
Update labels.conf 2026-08-04 17:39:45 +01:00
Daniel Marin
7e52e35596
Merge pull request #301 from andriujoseba/build/282-triage-slim
docs: slim TRIAGE.md incident narratives
2026-08-04 17:37:33 +01:00
Daniel Marin
b2a3e43ae4
Merge pull request #300 from cndgrr/build/267-labeler-scope
fix(labels): the scope map locates again — changelog.d/** is every PR
2026-08-04 17:37:20 +01:00
dan-claude-bot
48547d5eb1 fix: the issue-side ruling clock reads comments only (#284)
Claiming a needs-ruling issue dated it through the assigned timeline
event, silencing the 7-day escalation nudge at exactly the moment a
builder started working through it. The ruling block now reads
last_issue_comment_activity (D1); the reclaim clock keeps the assignment
(D2) because there the assignment IS the claim; post-merge hands its
evidence read to the ruling block instead of reading again (D6, D7); the
claimed branch reads both clocks at its top, before anything it posts.
LABELS.md and lib/ruling.sh now say what each surface's clock reads
(D4, D5). The #257-era order compositions move to the comments read —
the timeline is no longer an input the issue clocks take, and its
unreadability no longer holds unrelated writes hostage; that narrowing
is pinned rather than implied.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-04 16:16:19 +00:00
cndgrr
abe31a6d4a test(labels): assert each guard row alone, not bundled with its sibling
The D3 guard loop passed the action path and its test path to derives in
one call. derive_labels emits scope:guards when either matches, so any one
of the six rows could be deleted with the case still green — three
assertions standing in for six rows. Split into one assertion per path.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-04 15:56:55 +00:00
Andriujose
f3125631b9 docs: keep answer outcome explicit 2026-08-04 15:51:16 +00:00
Andriujose
de3ab517d7 docs: slim triage doctrine 2026-08-04 15:48:27 +00:00
Daniel Marin
fe45180616
Merge pull request #299 from andriujoseba/build/257-board-read
fix: abort on unreadable issue board
2026-08-04 16:43:32 +01:00
cndgrr
5356702817 docs(changelog): fragment for #267 2026-08-04 15:34:17 +00:00
cndgrr
0fe015da69 fix(labels): the scope map locates again
changelog.d/** matched every PR that changes behavior, so scope:release-flow
was a constant, not a locator (#267).
2026-08-04 15:33:39 +00:00
Daniel Marin
5fd1c1b014
Merge pull request #295 from cndgrr/build/281-builder-slim
docs(builder): BUILDER.md slims to the rules — narratives become bare local cites
2026-08-04 16:27:06 +01:00