docs: add release-management doctrine
This commit is contained in:
parent
d225c68fa4
commit
ab60709f49
5 changed files with 112 additions and 2 deletions
|
|
@ -11,6 +11,8 @@ triage bug, and the move is to say so on the issue, not to guess.
|
|||
- Respect dependency order: inside an epic, take the earliest unblocked
|
||||
unclaimed child. Between epics and strays, prefer the issue that unblocks
|
||||
the most other work.
|
||||
- In a repository that adopts version epics, read [RELEASES.md](RELEASES.md)
|
||||
before choosing among release-window members.
|
||||
- **Your own red head outranks a new claim.** A failing check at the head
|
||||
of a PR you authored is picked up **before claiming another issue** —
|
||||
repairing your own red PR comes ahead of new work, which is why the
|
||||
|
|
|
|||
100
RELEASES.md
Normal file
100
RELEASES.md
Normal file
|
|
@ -0,0 +1,100 @@
|
|||
# Release management
|
||||
|
||||
This file describes the release-management pattern available to governed
|
||||
repositories. Adoption is per repository and operator-ruled: a repository
|
||||
without version epics is not out of compliance. A repo-local roadmap is the
|
||||
map; each epic remains the source of truth for its own release. Where an older
|
||||
repo-local description differs from this file, this file governs.
|
||||
|
||||
## The ladder
|
||||
|
||||
Represent each planned release with one version epic. The epic is the working
|
||||
surface for that release: it states the goal, names the members, and records
|
||||
the ordered waves as checklists. Keep the machine-readable progress checklist
|
||||
under the exact heading `## Task list`; the issue-flow sweep reads that heading
|
||||
when it decides whether to nudge triage about a completed epic.
|
||||
|
||||
Keep a short repo-local roadmap beside the epics. The roadmap shows the whole
|
||||
ladder and points to each working surface; it does not duplicate the live
|
||||
member lists or ordering. crew's roadmap discussion [heavy-duty/crew#338](https://github.com/heavy-duty/crew/discussions/338)
|
||||
maps the ladder whose `0.1.2` working surface moved from the crufty ledger
|
||||
[heavy-duty/crew#162](https://github.com/heavy-duty/crew/issues/162) to
|
||||
[heavy-duty/crew#346](https://github.com/heavy-duty/crew/issues/346).
|
||||
|
||||
## Gates
|
||||
|
||||
Each version epic declares the predecessor that opens it. Special ordering —
|
||||
a double gate or an out-of-chain gate — is written explicitly on that epic;
|
||||
there is no hidden global schedule. Shipping closes the current epic, and its
|
||||
close is the signal for triage to open the next release-init cycle by hand.
|
||||
Version epics carry `epic`, not a queue label: `ready` offers work to builders,
|
||||
and builders never pick epics.
|
||||
|
||||
The gate orders windows, not their contents. Members enter a release only by
|
||||
decision during release-init. The double gate on heavy-duty/crew#163 and the
|
||||
out-of-chain track on [heavy-duty/crew#348](https://github.com/heavy-duty/crew/issues/348)
|
||||
are worked examples of exceptions declared where they apply.
|
||||
|
||||
## Release-init
|
||||
|
||||
The preceding epic's close is the trigger. Triage then runs five steps:
|
||||
|
||||
1. Mint the epic's “to mint when this arc opens” list together with findings,
|
||||
deferred work, and discussion outcomes accumulated since the epic was
|
||||
written. Each member initially declares `Blocked by <the epic>`.
|
||||
2. Graph hard `Blocked by` edges and same-file clusters on the epic.
|
||||
3. Write the waves into the epic body as checklists in claim order, with a
|
||||
separate verification lane and the progress view under `## Task list`.
|
||||
4. Ask the operator to bless the order, then have triage open the first wave
|
||||
by applying the flip mechanics below. The operator's blessing is the one
|
||||
step this chain never automates.
|
||||
5. Ship through the repository's cut process, close the epic, and treat that
|
||||
close as the trigger for the next window.
|
||||
|
||||
heavy-duty/crew#346 is the worked wave plan; its graph made both hard edges
|
||||
and shared-file contention visible before builders entered the queue. If init
|
||||
finds no work worth minting, the operator either folds the empty window into a
|
||||
later release or skips the version, recording that ruling on the epic before
|
||||
closing it unshipped.
|
||||
|
||||
## One primary window, declared parallel tracks
|
||||
|
||||
Run one primary release window by default. A cut takes whatever has landed, so
|
||||
interleaving unrelated windows blurs both the release story and the evidence
|
||||
behind it. Gates open windows; they do not silently admit members, so builders
|
||||
still see one deliberately ordered queue.
|
||||
|
||||
The operator may declare a parallel track at init when its footprint is
|
||||
disjoint from the primary window: another repository, another artifact, or
|
||||
provably non-overlapping clusters. The declaration names the boundary and any
|
||||
bridge work that must rejoin the primary. [heavy-duty/crew#348](https://github.com/heavy-duty/crew/issues/348)
|
||||
is the worked example: its app and artifact form a parallel track while its
|
||||
small crew-side bridge remains in the primary window.
|
||||
|
||||
## Flip mechanics
|
||||
|
||||
To admit a member, strike its live `Blocked by <the epic>` declaration and
|
||||
swap `blocked` to `ready` in the same edit. Never preserve history by negating
|
||||
the marker phrase — the blocker parser unions declarations even when prose
|
||||
says they no longer apply. Preserve the old text only after striking or
|
||||
rewriting the parseable clause, then verify the parser's resulting set.
|
||||
|
||||
Release membership is a decision, never a sweep default. Triage performs each
|
||||
flip only after the operator blesses the wave; the issue-flow sweep may resolve
|
||||
ordinary issue dependencies, but it does not choose a release's contents.
|
||||
heavy-duty/crew#346 records the member-by-member flip that opened its first
|
||||
wave.
|
||||
|
||||
## The ledger pattern
|
||||
|
||||
When a release epic has become too crufty to remain a clear working surface,
|
||||
create a replacement and treat the old epic as a ledger. Do not close the old
|
||||
epic until every live member declaration points at the replacement and the
|
||||
blocker parser verifies the new set. Closing early can release every member
|
||||
that still names the old issue.
|
||||
|
||||
The [heavy-duty/crew#162](https://github.com/heavy-duty/crew/issues/162) to
|
||||
[heavy-duty/crew#346](https://github.com/heavy-duty/crew/issues/346)
|
||||
transition is the worked example: all member declarations were re-pointed and
|
||||
parse-verified before #162 closed; #162 remains the historical record while
|
||||
#346 is the release's working surface.
|
||||
|
|
@ -122,6 +122,7 @@ label): the approach, the decisions, the constraint list, and a
|
|||
dependency-ordered task list of child issues. Children reference the epic;
|
||||
the epic's checklist is the progress view. Builders never pick the epic
|
||||
itself. Keep the checklist current — a stale epic misleads every scan.
|
||||
Repositories that adopt version epics follow [RELEASES.md](RELEASES.md).
|
||||
|
||||
## Backlog hygiene
|
||||
|
||||
|
|
|
|||
3
changelog.d/248.md
Normal file
3
changelog.d/248.md
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
### Added
|
||||
|
||||
- Document the optional, operator-ruled release-epic flow for governed repositories.
|
||||
|
|
@ -550,14 +550,18 @@ when the pinned taxonomy declares a core label the repository lacks.
|
|||
Machinery is consumed by reference — GitHub fetches the workflows and
|
||||
actions above from the pin at run time — but documents have no runtime: an
|
||||
agent reads the working tree it stands in. So the agent-facing doc set
|
||||
(ceremony's `docs/VENDORED.txt`: AGENTS.md, TRIAGE.md, BUILDER.md,
|
||||
REVIEWER.md, LABELS.md) is vendored into each consumer at **`.ceremony/`**,
|
||||
declared by ceremony's `docs/VENDORED.txt` is vendored into each consumer at **`.ceremony/`**,
|
||||
byte-identical to ceremony at the pin, plus a generated `.ceremony/README.md`
|
||||
marking the directory machine-managed. `actions/docs-sync` owns the copy:
|
||||
`--fix` writes it (and deletes what the manifest dropped — mirror means
|
||||
mirror), `--check` re-diffs it in CI on every PR, so a hand edit or a stale
|
||||
pin goes red instead of quietly governing.
|
||||
|
||||
`RELEASES.md` joins that mirror with the first tag carrying ceremony#248.
|
||||
It is **unreleased** until that tag exists: consumers add
|
||||
`.ceremony/RELEASES.md` only with the ordinary pin bump and re-sync, never by
|
||||
copying it ahead of their pinned doctrine set.
|
||||
|
||||
The consumer's ci.yml gains the guard alongside the others:
|
||||
|
||||
```yaml
|
||||
|
|
|
|||
Loading…
Reference in a new issue