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
This commit is contained in:
cndgrr 2026-08-04 22:44:02 +00:00
parent ca44ee0f84
commit a663c631bf

View file

@ -2,7 +2,9 @@
The heavy-duty family's **governance repo**: the machinery every repo in the The heavy-duty family's **governance repo**: the machinery every repo in the
family runs, and the doctrine every agent in the family reads. Implemented family runs, and the doctrine every agent in the family reads. Implemented
once here, tested once here, consumed everywhere else — never copied. once here, tested once here, consumed everywhere else — the machinery never
copied at all, the doctrine only as a mirror a guard keeps byte-identical to
the pin.
Two kinds of thing live in this tree, and they are consumed in two different Two kinds of thing live in this tree, and they are consumed in two different
ways because they have two different runtimes. ways because they have two different runtimes.
@ -118,10 +120,15 @@ decision rather than arithmetic, so the re-arm stops for you to make it
([The re-arm refused](#the-re-arm-refused-releaseyml)). The machine does the ([The re-arm refused](#the-re-arm-refused-releaseyml)). The machine does the
transcription because humans err silently and machines fail loudly: transcription because humans err silently and machines fail loudly:
**everything asserts its way to certainty and fails loudly, creating **everything asserts its way to certainty and fails loudly, creating
nothing** — a wrong release is worse than a missing one, so every assert that nothing** — a wrong release is worse than a missing one, so every assert in
fails *before* the publish leaves zero artifacts: no tag, no release, no this file fires *before its door creates anything*, and one that fails leaves
bump. The re-arm is the one assert past that line, and its refusal is the zero artifacts of the run's own: no tag it made, no release, no bump. Only two
single failure in this file that leaves a real release behind. steps run past the tag. The consumer's
[artifact hook](docs/CONSUMERS.md#the-artifact-hook) sits between the tag and
the publish, so its non-zero exit aborts with a tag standing and no release —
a state the [nothing-exists assert](#the-merge-door-refused-releaseyml) names,
and recovers by the tag door. The re-arm runs after the publish, and its
refusal is the single failure in this file that leaves a real release behind.
## The two doors ## The two doors
@ -137,8 +144,12 @@ single failure in this file that leaves a real release behind.
**no `v` prefix**, box's 0.6.0 set the scheme **no `v` prefix**, box's 0.6.0 set the scheme
([release.yml](.github/workflows/release.yml#L303-L371)) — publishes the ([release.yml](.github/workflows/release.yml#L303-L371)) — publishes the
same way. The tag is the operator's explicit act, so there is no decide same way. The tag is the operator's explicit act, so there is no decide
and no label check; the one assert is that **the tag names the tree's own and no label check — what is left is two asserts: **the tag names the
version**, and a mismatch refuses, creating nothing. No `-dev` bump either tree's own version**
([L328L339](.github/workflows/release.yml#L328-L339)) and **the tagged
tree carries a publishable `## X.Y.Z` section**
([L340L352](.github/workflows/release.yml#L340-L352)); either failing
refuses, creating nothing. No `-dev` bump either
— the fallback does not rewrite main (cast's precedent). Use it when the — the fallback does not rewrite main (cast's precedent). Use it when the
merge path is red, for backfills, and for the merge path is red, for backfills, and for the
[first-release edge](#what-happens-when-my-pr-lands-on-main) (row 4). [first-release edge](#what-happens-when-my-pr-lands-on-main) (row 4).
@ -534,7 +545,10 @@ half, and *that* half is unreachable as the doors stand — rows 12 send `-de
to a no-op, and the tag door never bumps. A malformed version is not: nothing to a no-op, and the tag door never bumps. A malformed version is not: nothing
upstream checks the shape ([version_read](lib/version.sh#L22-L33) checks only upstream checks the shape ([version_read](lib/version.sh#L22-L33) checks only
that a version is present and non-empty), so `banana` rides row 6 exactly as that a version is present and non-empty), so `banana` rides row 6 exactly as
an rc does, and the same manual bump is the remedy. an rc does, and the same manual bump is the remedy. The rc half has a shelf
life: the 0.7.0 window makes rc cuts native and their re-arm deterministic
(#317), after which no rc reaches this refusal — the malformed half still
does.
> version_write: npm is required for version-source: package-json > version_write: npm is required for version-source: package-json