2026-07-22 22:19:50 +00:00
|
|
|
# Drills
|
|
|
|
|
|
|
|
|
|
What a drill means in this repo: an **end-to-end rehearsal of both doors of
|
|
|
|
|
the release workflow on a disposable repo**. The contract suite proves every
|
|
|
|
|
decision offline — facts → decide → notes against fixtures, the merge door's
|
|
|
|
|
step sequence replayed in release-exercise.yml — but the doors themselves
|
|
|
|
|
only ever run live: gating on a real push event, the tag create, the
|
|
|
|
|
publish, the `-dev` re-arm (release.yml's "what is honestly untested"). The
|
|
|
|
|
drill is where they run live *before* a version rests on them.
|
|
|
|
|
|
|
|
|
|
## The rehearsal
|
|
|
|
|
|
|
|
|
|
1. Create a scratch **private** repo. It is disposable by design — it gets
|
|
|
|
|
deleted at the end.
|
|
|
|
|
2. Install the docs/CONSUMERS.md caller stubs, pinned to the release
|
|
|
|
|
candidate ref. A branch ref works: refs are static identifiers — the
|
|
|
|
|
family's own drill doctrine.
|
2026-07-22 23:40:38 +00:00
|
|
|
|
|
|
|
|
**Except for the first release** (learned drilling 0.1.0, #11): the
|
|
|
|
|
stubs' consumer path fetches ceremony at `CEREMONY_SELF_REF` — the very
|
|
|
|
|
ref the first drill exists to rehearse creating — so the pure pinned
|
|
|
|
|
path cannot run before some `X.Y.Z` ref exists, and a branch named like
|
|
|
|
|
the tag must NOT be created on the canonical repo to paper over it (it
|
|
|
|
|
would shadow the tag for every consumer until someone remembers to
|
|
|
|
|
delete it). The first drill instead pins the callers to a fork ref
|
|
|
|
|
carrying the candidate tree with `CEREMONY_SELF_REF` rewritten to the
|
|
|
|
|
candidate SHA in every pin carrier, and records that one-line deviation
|
|
|
|
|
in its record. From the second release on, this paragraph is moot.
|
2026-07-24 10:24:31 +00:00
|
|
|
3. Give it a fixture `VERSION` / `CHANGELOG.md` / `changelog.d/` /
|
|
|
|
|
`drills/` in the armed state (`X.Y.Z-dev`, the fragments directory with
|
|
|
|
|
its `README.md` marker plus at least one fragment for the ceremony to
|
|
|
|
|
consume).
|
2026-07-22 22:19:50 +00:00
|
|
|
4. Exercise both doors, one probe at a time:
|
|
|
|
|
|
|
|
|
|
1. a merge-door ceremony publishes exactly one release and re-arms main
|
|
|
|
|
to `-dev`;
|
|
|
|
|
2. a mislabeled ordinary PR is a green NOTICE no-op;
|
|
|
|
|
3. a bare-version PR without the `release` label refuses;
|
|
|
|
|
4. a re-run of the completed ceremony refuses;
|
|
|
|
|
5. a tag-door release from a manual tag;
|
|
|
|
|
6. a mismatched tag refuses.
|
|
|
|
|
|
|
|
|
|
Every refusal must refuse **creating nothing** — a probe that leaves a
|
|
|
|
|
tag or a release behind on a refusal path is a failed probe.
|
|
|
|
|
|
|
|
|
|
## The record
|
|
|
|
|
|
|
|
|
|
One file per version, `drills/X.Y.Z.md` — the shape the siblings use: what
|
|
|
|
|
was run, where, the result of each probe, failures written down plainly. The
|
|
|
|
|
record is the evidence; the scratch repo is the evidence's scaffolding and
|
|
|
|
|
is deleted afterwards.
|
|
|
|
|
|
|
|
|
|
`actions/drill-recorded` refuses any bare-version tree whose record is
|
|
|
|
|
missing or blank. A waived drill is still a record: the file says WAIVED and
|
|
|
|
|
why — a maintainer's call, visible and reviewable in the release PR's diff,
|
|
|
|
|
never a silent skip.
|