docs(fleet): move roster ownership to operator config

This commit is contained in:
codex-bot-andresmgsl 2026-07-28 10:48:03 +00:00
parent c96d2d8f4e
commit 5757e24cd4
2 changed files with 44 additions and 48 deletions

View file

@ -1,43 +1,32 @@
# FLEET.md — the roster, and how it actually runs # FLEET.md — the fleet shape, and how it actually runs
> **Status:** descriptive snapshot, not doctrine. This file records how the > **Status:** descriptive snapshot, not doctrine. This file records how the
> agent fleet that builds this repo is wired *today*, so the setup can later be > heavy-duty operator fleet is wired *today*. It is **not** part of the
> solidified into a replicable fleet-management solution. It is **not** part of > vendored doctrine set (`.ceremony/`) and is never mirrored to consumer
> the vendored doctrine set (`.ceremony/`) and is never mirrored to consumer > repos. [Crew](https://github.com/heavy-duty/crew) is a general tool: its
> repos. The doctrine files (AGENTS.md, TRIAGE.md, BUILDER.md, REVIEWER.md, > repository ships the engine, while the fleet definition belongs to the
> LABELS.md, CONTRIBUTING.md) say what roles *must* do; this file says how the > operator; heavy-duty is one operator of it. Membership, repository scope,
> current bench *physically* does it — and since the duty engine converged > agent-profile overrides and doctrine paths belong to that definition;
> into [heavy-duty/crew](https://github.com/heavy-duty/crew) (private to the > membership itself lives outside every checkout. Crew's shipped defaults
> org; the fleet can read it), the *mechanism* lives there and this file only > name heavy-duty's AGENTS.md, TRIAGE.md, BUILDER.md and REVIEWER.md, but
> points at it. Last reconciled against the merged engine at > those are compatibility defaults, not vocabulary compiled into the engine
> [`heavy-duty/crew@4da17c4`](https://github.com/heavy-duty/crew/tree/4da17c49594c2d86bd3793fa3567846cbca38e90), > — operator `doctrine.conf` values can replace them.
> 2026-07-27 — a descriptive file with no reconciliation stamp gives the next > The *mechanism* lives with crew and this file points at it. Last reconciled
> against the merged engine at
> [`heavy-duty/crew@eaeb302`](https://github.com/heavy-duty/crew/tree/eaeb3022aa47d90e797f2b9e007b831df7ca8406),
> 2026-07-28 — a descriptive file with no reconciliation stamp gives the next
> reader nothing to diff, which is exactly how the #149 drift went unnoticed. > reader nothing to diff, which is exactly how the #149 drift went unnoticed.
## The roster ## Fleet shape
One box (an isolated, disposable VM) per GitHub identity. Boxes are credential One box (an isolated, disposable VM) per GitHub identity. Boxes are credential
boundaries; sessions inside a box are role boundaries. No box has an inbound boundaries; sessions inside a box are role boundaries. No box has an inbound
network path — GitHub is the only queue. network path — GitHub is the only queue. Fleet membership is the operator's
definition and lives outside every checkout; this file deliberately carries
no second roster.
| Identity | Box | CLI | Roles | Review panel per PR = the governed repo's `.github/labels.conf` `panel=` line
|---|---|---|---| minus the PR's author, as [REVIEWER.md](REVIEWER.md) specifies (recusal by
| `dan-claude-bot` | triage-box | Claude Code | **triage** — the only issue-minter |
| `claude-bot-andresmgsl` | claude-box | Claude Code | builder (hard machinery) + reviewer |
| `codex-bot-andresmgsl` | codex-box | Codex CLI | builder (mechanical) + reviewer |
| `grok-bot-andresmgsl` | grok-box | Grok CLI | reviewer |
| `kimi-bot-andresmgsl` | kimi-box | Kimi CLI | reviewer |
This table is the **as-built** bench — five boxes, two of them dual-role. It
is not the same thing as crew's
[`fleet.roster`](https://github.com/heavy-duty/crew/blob/4da17c49594c2d86bd3793fa3567846cbca38e90/fleet.roster),
whose own header declares it the **target** environment: seven single-role
boxes, the dual-role claude and codex boxes each split into a builder and a
reviewer member. The delta is exactly that split (plus each new box needing
its own identity at login); until it is deployed, this table is the record of
what actually runs, and `fleet.roster` is where it is going.
Review panel per PR = the reviewer bench minus the PR's author (recusal by
construction). Only humans merge — enforced as permissions (the agents team construction). Only humans merge — enforced as permissions (the agents team
holds the triage role, not write), not as convention. holds the triage role, not write), not as convention.
@ -49,16 +38,17 @@ second repo is a second thing to keep true — this one drifted (it said cron
ran `duty.sh` directly and gave the hygiene sweep its own cron line; crew's ran `duty.sh` directly and gave the hygiene sweep its own cron line; crew's
`duty.sh` records that separate line as the bug it fixed, sharing `duty.sh` records that separate line as the bug it fixed, sharing
`~/duty/work` unlocked). How a tick actually works — cron fires `~/duty/work` unlocked). How a tick actually works — cron fires
[`bin/tick.sh`](https://github.com/heavy-duty/crew/blob/4da17c49594c2d86bd3793fa3567846cbca38e90/shared/bin/tick.sh), [`bin/tick.sh`](https://github.com/heavy-duty/crew/blob/eaeb3022aa47d90e797f2b9e007b831df7ca8406/shared/bin/tick.sh),
the only cron target, which wraps the only cron target, which wraps
[`bin/duty.sh`](https://github.com/heavy-duty/crew/blob/4da17c49594c2d86bd3793fa3567846cbca38e90/shared/bin/duty.sh) [`bin/duty.sh`](https://github.com/heavy-duty/crew/blob/eaeb3022aa47d90e797f2b9e007b831df7ca8406/shared/bin/duty.sh)
in a non-blocking `flock` with one evidence line per boundary; the boot gate in a non-blocking `flock` with one evidence line per boundary; the boot gate
and crash recovery; the session runner; backlog hygiene self-scheduling and crash recovery; the session runner; backlog hygiene self-scheduling
inside the duty tick under the same lock — lives with the code: inside the duty tick under the same lock — lives with the code:
[`shared/README.md`](https://github.com/heavy-duty/crew/blob/4da17c49594c2d86bd3793fa3567846cbca38e90/shared/README.md) [`shared/README.md`](https://github.com/heavy-duty/crew/blob/eaeb3022aa47d90e797f2b9e007b831df7ca8406/shared/README.md)
is the map, provenance table included. Sessions stay stateless and is the map, provenance table included. Sessions stay disposable: durable work
disposable — all state lives on the board (issues, PRs, labels) and in git state lives on the board (issues, PRs, labels) and in git branches, while the
branches; detection is the engine's, judgment is the session's. engine keeps only operational evidence and deduplication state under
`~/duty`; detection is the engine's, judgment is the session's.
What belongs here is what a wake *means*: What belongs here is what a wake *means*:
@ -70,7 +60,7 @@ What belongs here is what a wake *means*:
The 2026-07-25 scope ruling (crew#16) closed the org-wide review and The 2026-07-25 scope ruling (crew#16) closed the org-wide review and
author-side write surface; the crew#66 attention ruling closed the last author-side write surface; the crew#66 attention ruling closed the last
exemption. Crew's exemption. Crew's
[`repos-default.txt` header](https://github.com/heavy-duty/crew/blob/4da17c49594c2d86bd3793fa3567846cbca38e90/shared/conf/repos-default.txt) [`examples/repos.txt` header](https://github.com/heavy-duty/crew/blob/eaeb3022aa47d90e797f2b9e007b831df7ca8406/examples/repos.txt)
is the pinned source for how that rule is implemented and reported. is the pinned source for how that rule is implemented and reported.
### Wake conditions ### Wake conditions
@ -96,7 +86,7 @@ write authority outside the registry, and the one hole left in the
containment story. Rows are now partitioned against the registry: inside it, containment story. Rows are now partitioned against the registry: inside it,
a session as before; outside it, reported and never acted on, exactly like an a session as before; outside it, reported and never acted on, exactly like an
out-of-scope review request or authored PR. out-of-scope review request or authored PR.
[`lib/duty-attention.sh`](https://github.com/heavy-duty/crew/blob/4da17c49594c2d86bd3793fa3567846cbca38e90/shared/lib/duty-attention.sh) [`lib/duty-attention.sh`](https://github.com/heavy-duty/crew/blob/eaeb3022aa47d90e797f2b9e007b831df7ca8406/shared/lib/duty-attention.sh)
implements the partition and states the ruling in its header. implements the partition and states the ruling in its header.
The cost was argued before the ruling rather than discovered after it: an The cost was argued before the ruling rather than discovered after it: an
@ -135,7 +125,7 @@ wake is no longer on paper: `duty-attention.sh` is deployed engine, and
`duty.sh` runs it first on every box, whatever its roles. `duty.sh` runs it first on every box, whatever its roles.
The engine's duty order is fleet-standard The engine's duty order is fleet-standard
([`bin/duty.sh`](https://github.com/heavy-duty/crew/blob/4da17c49594c2d86bd3793fa3567846cbca38e90/shared/bin/duty.sh)): ([`bin/duty.sh`](https://github.com/heavy-duty/crew/blob/eaeb3022aa47d90e797f2b9e007b831df7ca8406/shared/bin/duty.sh)):
**attention → triage signals → review queue → resume → ci-red → build → **attention → triage signals → review queue → resume → ci-red → build →
handoff → rebase → worktree hygiene → backlog hygiene (hourly)** — attention handoff → rebase → worktree hygiene → backlog hygiene (hourly)** — attention
role-independent and first, then each duty family the box's roles enable. role-independent and first, then each duty family the box's roles enable.
@ -228,7 +218,8 @@ for the engine-side update:
- **The second query.** Alongside the `state:needs-human` PR poll, `notify.sh` - **The second query.** Alongside the `state:needs-human` PR poll, `notify.sh`
polls **open issues and PRs labelled `needs-ruling`** across every repo in polls **open issues and PRs labelled `needs-ruling`** across every repo in
the notifier's deliberately wider registry. `notify-repos.txt`, which is deliberately wider than the duty registry:
a cross-repo handoff is precisely what the operator cannot discover alone.
- **One tracked message per item, edited in place** — the same - **One tracked message per item, edited in place** — the same
one-message-per-item discipline the PR poll already uses, so an aging one-message-per-item discipline the PR poll already uses, so an aging
ruling reads as a **live queue**, not a feed. The message is removed when ruling reads as a **live queue**, not a feed. The message is removed when
@ -290,9 +281,9 @@ cheaper than a number that has to be recounted every time a wake lands.
This wiring proved itself on day one (seven merged PRs, unanimous three-model This wiring proved itself on day one (seven merged PRs, unanimous three-model
review convergence on #39, and a full-fleet crash recovery), and the plan it review convergence on #39, and a full-fleet crash recovery), and the plan it
carried has since half-happened: the five per-box duty scripts converged into carried has become **heavy-duty/crew** — a shared engine, CLI, operator
**heavy-duty/crew** — the shared engine, the `crew` CLI, and the fixture configuration model, real-host rehearsal and fixture tests — so standing up
tests — so standing up a box is a bootstrap, not an archaeology dig. What a fleet is a bootstrap, not an archaeology dig. What remains is adoption:
remains is the roster: `fleet.roster` names the seven-box single-role target, crew#85 tracks the road to a `0.1.0` another operator can use without a fork.
and the bench above is still the five-box as-built. Until the split lands, Membership stays in the operator definition; this file remains the map of
this file is the map of what runs — and crew is the map of how. what a wake means, and crew is the map of how it runs.

5
changelog.d/193.md Normal file
View file

@ -0,0 +1,5 @@
### Changed
- `FLEET.md` removes its duplicate bench roster, records crew as a general
operator-configured tool, and advances its whole-file audit stamp to
`crew@eaeb302` with every surviving crew link re-pinned (#193).