FLEET.md mirrors an implementation that now exists in crew — and the mirror is wrong about scope #187

Closed
opened 2026-07-25 22:24:21 +00:00 by dan-claude-bot · 0 comments
dan-claude-bot commented 2026-07-25 22:24:21 +00:00 (Migrated from github.com)

Filed from the sherpa session at danmt's request — a bug report, not a triage ruling. Raised by the question "now that crew exists, can we drop the role docs?" The answer for TRIAGE/REVIEWER/BUILDER is no (below). For FLEET.md it is largely yes, and it is also actively misleading today.

Short answer to the question that prompted this

TRIAGE.md, REVIEWER.md and BUILDER.md must stay. heavy-duty/crew's session prompts delegate to them by name — they are load-bearing runtime dependencies, not background reading:

prompt instruction
triage.txt "act per TRIAGE.md"
mention.txt "answer per TRIAGE.md" … "it never overrides TRIAGE.md"
hygiene.txt "backlog hygiene per TRIAGE.md"
review.txt "REVIEWER.md governs the role"
build.txt "act per BUILDER.md"
resume.txt "BUILDER.md governs"
handoff.txt "Per BUILDER.md's handoff"
fragment-unblockable.txt "flip to ready per TRIAGE.md"

Deleting them leaves every agent session reading instructions that point at nothing. The split is deliberate and stated in the engine itself (duty-triage.sh: "Detection here, judgment in sessions") — crew owns mechanism, these docs own judgment. They encode the issue contract, the verdict doctrine, picking/claiming/building, the round rhythm. None of that is in crew and none of it should be.

FLEET.md is the exception, for two separate reasons.

1. It is a prose mirror of an implementation that now exists

## Anatomy of a duty loop describes the tick/poll/act skeleton:

Tick: cron */5 runs ~/duty/duty.sh under a non-blocking flock; the triage box adds an hourly hygiene sweep under its own lock.

That is now shared/bin/tick.sh and shared/bin/duty.sh, with the hygiene sweep self-scheduling inside the duty tick rather than needing its own cron line. ## The roster is now fleet.roster, a committed file the CLI reads. ## Resilience describes crash recovery the engine implements.

A prose description of running code drifts by default. This one has.

2. It is now factually wrong on the most safety-relevant point

Two passages state the opposite of merged behaviour:

a reviewer's registry is the org itself, and its repos.txt is a backstop that cannot scope it

A review request is authorization, so no repo filter may gate it. Source 2, backstop: the repos.txt poll … only adds candidates

repos.txt is the scope, for every role including reviewer. Requests outside it are logged and never acted on. The rule changed on 2026-07-25 because an unbounded review surface is what made a drill box's containment impossible: narrowing repos.txt confined attention, triage and hygiene but not review — the one module that submits verdicts.

This is the same staleness already fixed in crew's conf/repos-default.txt header, and FLEET.md is the upstream doctrine source that header was written from. Left alone it is the authoritative-looking document that tells the next reader the old rule.

This is not cosmetic. An agent session that reads "no repo filter may gate it" may reasonably conclude a request outside its registry is authorization.

Spec

Split FLEET.md by what owns each part:

  • Mechanism → crew, delete here. Tick cadence, flock, poll/act skeleton, wake-condition implementation, resilience/crash recovery, notifier queue plumbing. shared/README.md already documents these with a provenance table; a second description in another repo is a second thing to keep true.
  • Roster → fleet.roster, delete here. The committed file is the roster; prose about who is on the fleet duplicates it and will drift the moment the single-role split starts.
  • Doctrine → keep, corrected. What a wake means, why attention outranks queues, why a request is authorization within the box's registry, board conventions. That is genuine doctrine and has no home in code.
  • Fix the scope passages regardless of the split — they are wrong today, and that is the urgent half.

Leave a pointer where the mechanism was, so a reader looking for "how does a tick actually work" is routed to crew rather than finding silence.

Tasks

  • Correct both scope passages: repos.txt is the scope for every role; out-of-scope work is logged, never acted on.
  • Move or delete ## Anatomy of a duty loop's mechanism, replacing it with a pointer to crew's shared/README.md.
  • Replace ## The roster prose with a pointer to fleet.roster.
  • Audit the rest of FLEET.md against the merged engine — these two passages were found by reading, not by a systematic pass.
  • Confirm TRIAGE/REVIEWER/BUILDER carry no mechanism claims that crew now owns (spot-checked, not audited).

Acceptance criteria

  • No statement in FLEET.md contradicts crew's merged behaviour.
  • Mechanism is described in exactly one repo.
  • A reader arriving at FLEET.md for "how does a tick work" is routed, not misinformed.
  • The role docs still govern their roles, unchanged in substance.

Test plan

Documentation. The check is a read-through against shared/lib/duty-review.sh, duty-builder.sh, duty-triage.sh and bin/tick.sh at crew's merged head, confirming every remaining behavioural claim in FLEET.md matches. The scope passages are the pinned must-fix: a reader must not be able to conclude that a review request outside repos.txt is authorization.

Dependencies

Caused by the scope doctrine change in heavy-duty/crew (merged in crew#16). Sibling of the same fix already applied to crew's conf/repos-default.txt.

> Filed from the sherpa session at danmt's request — a bug report, not a triage ruling. Raised by the question "now that crew exists, can we drop the role docs?" The answer for TRIAGE/REVIEWER/BUILDER is **no** (below). For FLEET.md it is largely yes, and it is also actively misleading today. ## Short answer to the question that prompted this **TRIAGE.md, REVIEWER.md and BUILDER.md must stay.** `heavy-duty/crew`'s session prompts delegate to them by name — they are load-bearing runtime dependencies, not background reading: | prompt | instruction | |---|---| | `triage.txt` | "act per TRIAGE.md" | | `mention.txt` | "answer per TRIAGE.md" … "it never overrides TRIAGE.md" | | `hygiene.txt` | "backlog hygiene per TRIAGE.md" | | `review.txt` | "REVIEWER.md governs the role" | | `build.txt` | "act per BUILDER.md" | | `resume.txt` | "BUILDER.md governs" | | `handoff.txt` | "Per BUILDER.md's handoff" | | `fragment-unblockable.txt` | "flip to ready per TRIAGE.md" | Deleting them leaves every agent session reading instructions that point at nothing. The split is deliberate and stated in the engine itself (`duty-triage.sh`: *"Detection here, judgment in sessions"*) — **crew owns mechanism, these docs own judgment.** They encode the issue contract, the verdict doctrine, picking/claiming/building, the round rhythm. None of that is in crew and none of it should be. FLEET.md is the exception, for two separate reasons. ## 1. It is a prose mirror of an implementation that now exists `## Anatomy of a duty loop` describes the tick/poll/act skeleton: > **Tick:** cron `*/5` runs `~/duty/duty.sh` under a non-blocking `flock`; the triage box adds an hourly hygiene sweep under its own lock. That is now `shared/bin/tick.sh` and `shared/bin/duty.sh`, with the hygiene sweep self-scheduling inside the duty tick rather than needing its own cron line. `## The roster` is now `fleet.roster`, a committed file the CLI reads. `## Resilience` describes crash recovery the engine implements. A prose description of running code drifts by default. This one has. ## 2. It is now factually wrong on the most safety-relevant point Two passages state the **opposite** of merged behaviour: > a reviewer's registry is the org itself, and its `repos.txt` is a backstop that cannot scope it > A review request is authorization, so **no repo filter may gate it**. Source 2, backstop: the `repos.txt` poll … only **adds** candidates `repos.txt` **is** the scope, for every role including reviewer. Requests outside it are logged and never acted on. The rule changed on 2026-07-25 because an unbounded review surface is what made a drill box's containment impossible: narrowing `repos.txt` confined attention, triage and hygiene but not review — the one module that submits verdicts. This is the same staleness already fixed in crew's `conf/repos-default.txt` header, and FLEET.md is the upstream doctrine source that header was written from. Left alone it is the authoritative-looking document that tells the next reader the old rule. **This is not cosmetic.** An agent session that reads "no repo filter may gate it" may reasonably conclude a request outside its registry is authorization. ## Spec Split FLEET.md by what owns each part: - **Mechanism → crew, delete here.** Tick cadence, flock, poll/act skeleton, wake-condition implementation, resilience/crash recovery, notifier queue plumbing. `shared/README.md` already documents these with a provenance table; a second description in another repo is a second thing to keep true. - **Roster → `fleet.roster`, delete here.** The committed file is the roster; prose about who is on the fleet duplicates it and will drift the moment the single-role split starts. - **Doctrine → keep, corrected.** What a wake *means*, why attention outranks queues, why a request is authorization **within the box's registry**, board conventions. That is genuine doctrine and has no home in code. - **Fix the scope passages regardless of the split** — they are wrong today, and that is the urgent half. Leave a pointer where the mechanism was, so a reader looking for "how does a tick actually work" is routed to crew rather than finding silence. ## Tasks - [ ] Correct both scope passages: `repos.txt` is the scope for every role; out-of-scope work is logged, never acted on. - [ ] Move or delete `## Anatomy of a duty loop`'s mechanism, replacing it with a pointer to crew's `shared/README.md`. - [ ] Replace `## The roster` prose with a pointer to `fleet.roster`. - [ ] Audit the rest of FLEET.md against the merged engine — these two passages were found by reading, not by a systematic pass. - [ ] Confirm TRIAGE/REVIEWER/BUILDER carry no mechanism claims that crew now owns (spot-checked, not audited). ## Acceptance criteria - [ ] No statement in FLEET.md contradicts crew's merged behaviour. - [ ] Mechanism is described in exactly one repo. - [ ] A reader arriving at FLEET.md for "how does a tick work" is routed, not misinformed. - [ ] The role docs still govern their roles, unchanged in substance. ## Test plan Documentation. The check is a read-through against `shared/lib/duty-review.sh`, `duty-builder.sh`, `duty-triage.sh` and `bin/tick.sh` at crew's merged head, confirming every remaining behavioural claim in FLEET.md matches. The scope passages are the pinned must-fix: a reader must not be able to conclude that a review request outside `repos.txt` is authorization. ## Dependencies Caused by the scope doctrine change in heavy-duty/crew (merged in crew#16). Sibling of the same fix already applied to crew's `conf/repos-default.txt`.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference: heavy-duty/ceremony#187
No description provided.