@feigi/fleet-ctl 3.88.7 → 3.88.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/skills/run-team/SKILL.md +43 -100
- package/skills/run-team/references/ci-watcher.md +9 -0
- package/skills/run-team/references/finisher.md +6 -0
- package/skills/run-team/references/isolation.md +8 -0
- package/skills/run-team/references/merge-bot.md +13 -0
- package/skills/run-team/references/phase-0.md +19 -0
- package/skills/run-team/references/pull.md +40 -0
- package/skills/run-team/references/reaping.md +7 -0
package/package.json
CHANGED
package/skills/run-team/SKILL.md
CHANGED
|
@@ -9,8 +9,7 @@ Run `next-ticket`, `review-and-fix`, `run-merge-bot` as one fleet. You are the
|
|
|
9
9
|
**controller**, in the main thread, never a member.
|
|
10
10
|
|
|
11
11
|
`$ARGUMENTS` = `[in-flight]`, optional, one positive integer, default 5: the
|
|
12
|
-
In-flight bound, the most tickets between Claim and merge at once.
|
|
13
|
-
the tick's `--in-flight` and `tier-roles.mjs --check --in-flight`.
|
|
12
|
+
In-flight bound, the most tickets between Claim and merge at once.
|
|
14
13
|
Merge bot is at most one, not configurable.
|
|
15
14
|
|
|
16
15
|
The war story behind a rule ending `See references/<file>` lives in that file; load
|
|
@@ -35,10 +34,8 @@ The reasoning behind each line is in references/invariants.md.
|
|
|
35
34
|
|
|
36
35
|
This phase is done when `phase0.mjs` exits 0: run it again after an exit 3 (a step failed) or an exit 4 (a `NEED` line asks you to act), and dispatch nothing before.
|
|
37
36
|
|
|
38
|
-
Once per run, at start
|
|
39
|
-
|
|
40
|
-
into one free implementer slot, the moment it frees (phase 1). Nothing in this
|
|
41
|
-
phase, or in any later one, asks the maintainer which tickets to take.
|
|
37
|
+
Once per run, at start; after it, every admission is a **Pull** (phase 1).
|
|
38
|
+
Nothing in this phase, or in any later one, asks the maintainer which tickets to take.
|
|
42
39
|
|
|
43
40
|
0. **Once per run, before anything else.** Run phase 0 from a Python eval
|
|
44
41
|
cell in this main checkout, without `--session`:
|
|
@@ -93,25 +90,19 @@ phase, or in any later one, asks the maintainer which tickets to take.
|
|
|
93
90
|
mandatory, no fallback**: never run `candidates.mjs --allow-fallback` by hand.
|
|
94
91
|
|
|
95
92
|
`candidates.mjs`'s exit 3 reaches you as an empty shortlist whose `dropped`
|
|
96
|
-
names every ticket the to-spec filter took, by number and reason
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
specs awaiting to-tickets, not as no work — read the numbers off
|
|
104
|
-
`dropped` or `specs-dropped=`, not off stderr, which the tick's own
|
|
105
|
-
refresh discards — and still do not pass
|
|
106
|
-
`--allow-fallback`, whose second pass is unfiltered and so reaches the
|
|
107
|
-
`ready-for-human` and untriaged work you have no channel for. A partial
|
|
108
|
-
drop, survivors and specs together, is named the same way.
|
|
93
|
+
names every ticket the to-spec filter took, by number and reason, and as
|
|
94
|
+
`specs-dropped=#<N> (to-spec: User Stories heading)` on the implementer row.
|
|
95
|
+
**Exit 3 is not that empty queue, and never a reason to widen the net**: the
|
|
96
|
+
to-spec filter took every one, so what is queued is to-tickets' input rather
|
|
97
|
+
than claimable tickets. Log it as specs awaiting to-tickets, not as no work —
|
|
98
|
+
read the numbers off `dropped` or `specs-dropped=`, not off stderr — and
|
|
99
|
+
still do not pass `--allow-fallback`. See references/phase-0.md.
|
|
109
100
|
2. **Refresh is the tick's from here on**: it prints `REFRESHED shortlist: <n>
|
|
110
101
|
entries; <k> lifted` (references/tick-rows.md, **Refresh is the tick's**).
|
|
111
102
|
|
|
112
103
|
## The wake table
|
|
113
104
|
|
|
114
|
-
A wake is done when its one `fleet-event.mjs` call has run and you have acted on every line it printed, the tick's last; with nothing left to act on, mark the beat and end your turn.
|
|
105
|
+
A wake is done when its one `fleet-event.mjs` call has run and you have acted on every line it printed, the tick's last; with nothing left to act on, mark the beat and end your turn. The loop has no exit but the run's own end: drain the run when it ends (**End of run**).
|
|
115
106
|
|
|
116
107
|
React to events; never block on one.
|
|
117
108
|
|
|
@@ -126,12 +117,10 @@ merge bot, Pulling a ticket, re-verifying a SHA, filing a follow-up — all proc
|
|
|
126
117
|
unconfirmed. Invoking the command was the opt-in. One exception: **a judgement the
|
|
127
118
|
evidence cannot settle**.
|
|
128
119
|
|
|
129
|
-
**Rule: record, tick, act, beat.** Every wake
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
it prints. There are no hand-run refill or dispatch edges left, and no hand
|
|
134
|
-
edit of the ledger. See references/ci-and-staleness.md.
|
|
120
|
+
**Rule: record, tick, act, beat.** Every wake below is one `fleet-event.mjs`
|
|
121
|
+
call, which makes the wake's writes and ends in one `fleet-tick.mjs`
|
|
122
|
+
invocation; do what it prints, and never hand-edit the ledger.
|
|
123
|
+
See references/ci-and-staleness.md.
|
|
135
124
|
|
|
136
125
|
Run each as `~/.fleet/bin/fleet-run fleet-event.mjs <kind> <args>`, from the main checkout:
|
|
137
126
|
|
|
@@ -182,10 +171,8 @@ owes beyond its call:
|
|
|
182
171
|
expired on arrival; say so. See references/ci-and-staleness.md.
|
|
183
172
|
- **Merge-bot pass reports done** → `fleet-event.mjs merge-bot-report merge-bot-<n>`. A label that
|
|
184
173
|
landed at the last moment reads `DISPATCH
|
|
185
|
-
merge-bot` again: dispatch the next bot straight away. A
|
|
186
|
-
|
|
187
|
-
`conflict-hold:#<pr>` to that PR's row, and the tick turns it into `DISPATCH
|
|
188
|
-
fix-pr PR#<pr>` (**The fix-applier**). The tick's `--apply` reaps after the
|
|
174
|
+
merge-bot` again: dispatch the next bot straight away. A conflict needs no
|
|
175
|
+
record from you (**Failure handling**). The tick's `--apply` reaps after the
|
|
189
176
|
pass. Read `worktreesRemoved` alongside `reaped`: a pass that
|
|
190
177
|
reaps branches and removes no worktrees is a finding, not a quiet success.
|
|
191
178
|
Update the reaped tickets' ledger rows in the same step.
|
|
@@ -238,7 +225,7 @@ A row with `review=` and no `reviewed=` is a review in flight, and the tick coun
|
|
|
238
225
|
- **The fix-applier.** `DISPATCH fix-pr PR#<M>` on a `reviewed=` count that survived or unverified findings, with no fix-applier live: name `fix-pr-<pr#>` (the next suffix if that name is on record), never the PR's implementer; render with `dispatch-prompt.mjs render fix-applier --kind review --member fix-pr-<pr#> …`, then record `ledger.mjs dispatch <pr#> fix-pr-<pr#>` before the call. Its brief carries the PR number, the worktree abs path, the PR's branch, the same `testCmd` you passed the review, and the **path** `<scratch>/pr<pr>/<run>/review.json`, `<run>` off the PR's latest `reviewed=` — never the findings. Every `<scratch>` in that brief is the absolute path `scratch-root.mjs` printed. Its rulings are the fix-applier body's (`agents/fleet-fix-applier.agent.md`); you hold none, and a refuter report that surfaces to you is its to retrieve, never yours to scan or pass on. On a PR carrying `ready-to-merge`, its push moves the head after the label: a fresh finisher, per **Failure handling**.
|
|
239
226
|
- **The conflict hold.** `DISPATCH fix-pr PR#<M>` on a conflict hold: the row carries an unresolved `conflict-hold:#<M>`, the merge bot's or one you recorded off the tick's `CONFLICT` line. It is the same slot with a different job, and no review file to hand over. Name it `fix-pr-<M>`, or the next suffix (`-b`, `-c` …) when that name is on record; render with `dispatch-prompt.mjs render fix-applier --kind conflict --member <name> …`; dispatch with the `agent` `ledger.mjs dispatch` printed, in the PR's existing worktree. Read the definition off that output (`fleet-fix-applier` whatever the row's `tier=`), never recall it. Settle `applied:<head>`, or `no-op` if no conflict was left, which lifts the merge hold; a dispatched-but-live one does not, and `failed`/`killed` leave the PR fix-due for a replacement. It answers the hold and nothing else: review findings the row also carries get a review `DISPATCH fix-pr PR#<M>` once it lands.
|
|
240
227
|
- **Then dispatch a red-check fixer** — on a `check`-job `failure` bound to the PR's current head that is not **solely** staleness (the five-condition note in `agents/fleet-fix-applier.agent.md`). Name `fix-pr-<M>`, or the next free suffix; render with `dispatch-prompt.mjs render fix-applier --kind red-check --member <name> …`, record with `ledger.mjs dispatch <pr#> <name>` before the call, and dispatch with the printed `agent` in the PR's existing worktree. Never while a review or a review fix-applier on the PR is live or still owes its report — a dispositions mismatch awaiting its retry and a conflict hold awaiting its fix-applier included; a red before any review still gets its review first. The tick prints no `DISPATCH` for it: reconcile it yourself, always after the review. The finisher gate applies to it as to a fix-applier. Settle it `applied:<head>` once a fix is pushed; `no-op` only when the red is not its to fix — a flake that passes on rerun, or staleness — with nothing pushed, never for "could not fix"; `failed` when it cannot reach green (**Failure handling**). Its three dispatch edges are under **The finisher gate**; their rationale is in `references/member-lifecycle.md` (The red-check fixer's three edges).
|
|
241
|
-
- **The merge bot.** Named `merge-bot-<n>`; `ledger.mjs dispatch merge-bot` numbers it.
|
|
228
|
+
- **The merge bot.** Named `merge-bot-<n>`; `ledger.mjs dispatch merge-bot` numbers it. Render `--member merge-bot-<n> --n <n> --scratch <scratch>`. Dispatch with the printed agent, omit `model`, and dispatch on the first `ready-to-merge` label without waiting for the finisher report.
|
|
242
229
|
- **The finisher.** Its render and receives are in `references/finisher.md`.
|
|
243
230
|
|
|
244
231
|
**A fleet member is never dispatched with omp's `isolated: true`.** See references/isolation.md.
|
|
@@ -277,7 +264,7 @@ yourself. Each digest field in full: See references/reviewers.md. What the
|
|
|
277
264
|
digest asks of you:
|
|
278
265
|
|
|
279
266
|
- **`testEnvironment` says what the review's shared test run is evidence about**: read it so a degraded review never passes for a clean one.
|
|
280
|
-
- **`resume`** non-null
|
|
267
|
+
- **`resume`** non-null is reported, not acted on: the fix-applier defers what it names.
|
|
281
268
|
- **`unverified`** is *not* "checked and cleared", and **`refuted`** may be reversed: copy the fix-applier's reversals to the ledger's `ruled` line by running `fleet-event.mjs fix-report`.
|
|
282
269
|
- **`suiteVerdict`** — **Exit 75 is not a test result.** In a review it makes
|
|
283
270
|
`suiteVerdict` not usable, `suiteVerdict.reason` beginning "no suite slot within
|
|
@@ -296,12 +283,7 @@ digest asks of you:
|
|
|
296
283
|
`docs/metrics/tier-outcomes.tsv` when you rule each PR's review, with
|
|
297
284
|
`~/.fleet/bin/fleet-run tier-outcomes.mjs append <pr> --closed-own-ticket yes|no --minted-false-claim yes|no --note "<text>"`,
|
|
298
285
|
never by hand** (that file's header carries the column meanings). The script
|
|
299
|
-
fills `
|
|
300
|
-
ran, off the implementer's `tier-ok=` ledger verdict or else its one
|
|
301
|
-
member-outcomes row (a `tier-unverifiable=` member has no ledger verdict, so
|
|
302
|
-
its one member-outcomes row decides), and BLANK with a WARNING naming why
|
|
303
|
-
when neither settles
|
|
304
|
-
it; never type a tier in over that. That append is the whole duty. See references/pull.md.
|
|
286
|
+
fills `tier` itself; never type one in. That append is the whole duty. See references/pull.md.
|
|
305
287
|
|
|
306
288
|
**A verdict is a measurement only if it post-dates the run that produced it.** See references/reviewers.md.
|
|
307
289
|
|
|
@@ -377,10 +359,7 @@ Act on each line the tick prints as its row reads here, then stop: the next wake
|
|
|
377
359
|
Read the depth off the tick and never derive it by hand: act on the row it prints, and when it prints `SUGGEST /triage, hold idle`, hold the implementer row idle and suggest `/triage` in the report. See references/tick-rows.md.
|
|
378
360
|
|
|
379
361
|
**The review backlog never gates, and the merge-queue depth is still no
|
|
380
|
-
signal.** The only gate on a Pull is the In-flight count.
|
|
381
|
-
`DISPATCH review` on the same tick, never a reason to idle an implementer.
|
|
382
|
-
A starved implementer queue never stalls the review or merge side.
|
|
383
|
-
For the merge queue, see references/pull.md.
|
|
362
|
+
signal.** The only gate on a Pull is the In-flight count. See references/pull.md.
|
|
384
363
|
|
|
385
364
|
**Reconcile, do not wait for an event.** With the shortlist empty the tick's rows
|
|
386
365
|
govern — refresh, and never Pull a ticket the shortlist does not hold.
|
|
@@ -456,15 +435,10 @@ Pull, and each head a free slot Pulls gets its own row, read off that head's
|
|
|
456
435
|
<string>`, the string it must add: each runs `staleness.mjs` and asks again.
|
|
457
436
|
`none <why>` (no string settles it) and `done` end the question.
|
|
458
437
|
|
|
459
|
-
**Grep for the ticket's ASKED-FOR CHANGE, not only its subject construct
|
|
460
|
-
the construct check passes on every stale pin ticket, because the construct
|
|
461
|
-
is what the pin is *about* and never went anywhere. So for a ticket asking
|
|
438
|
+
**Grep for the ticket's ASKED-FOR CHANGE, not only its subject construct**:
|
|
462
439
|
for a pin, test or assertion, grep the **test file** for the assertion it
|
|
463
|
-
wants; for
|
|
464
|
-
|
|
465
|
-
a suggestion the implementer is free to reword — an equivalent rewording
|
|
466
|
-
satisfies the ticket while failing a grep for its literal text — and the
|
|
467
|
-
quoted defect is the fact.
|
|
440
|
+
wants; for exact wording, grep the **old** wording the ticket quotes as
|
|
441
|
+
wrong. See references/pull.md.
|
|
468
442
|
|
|
469
443
|
`staleness.mjs` answers each `gone` and `present` in three values:
|
|
470
444
|
|
|
@@ -494,16 +468,12 @@ Pull, and each head a free slot Pulls gets its own row, read off that head's
|
|
|
494
468
|
|
|
495
469
|
Any undecided item → not decided. Name it; that name is the relabel comment's
|
|
496
470
|
missing decision or open fork. **Torn → surface, never guess**: relabel it
|
|
497
|
-
`ready-for-human` as a fork naming the open decision
|
|
498
|
-
Pull surfaces it to the maintainer. Opposite of
|
|
499
|
-
`sizing-a-ticket`'s *torn → take the heavier row*, deliberately — see that skill.
|
|
471
|
+
`ready-for-human` as a fork naming the open decision. See references/pull.md.
|
|
500
472
|
|
|
501
|
-
4. **`collision` (Q3)** — asked after the scan
|
|
502
|
-
|
|
503
|
-
`
|
|
504
|
-
|
|
505
|
-
branch with no PR yet by its name; `behind-issue:#M`, an open issue that
|
|
506
|
-
section sequences this one after; or `paths <p>…`, which scans again.
|
|
473
|
+
4. **`collision` (Q3)** — asked after the collision scan (references/pull.md):
|
|
474
|
+
`clear`; `behind-pr:#M`, an open PR or a branch with no PR yet by its name;
|
|
475
|
+
`behind-issue:#M`, an open issue the brief's `Out of scope` sequences this
|
|
476
|
+
one after; or `paths <p>…`, which scans again.
|
|
507
477
|
|
|
508
478
|
### How a Pull ends
|
|
509
479
|
|
|
@@ -537,12 +507,12 @@ worktree re-created for an already-open PR is in references/isolation.md.
|
|
|
537
507
|
|
|
538
508
|
A dispatch is done when its `task` call is made, in the background, with the `agent` and the name `ledger.mjs dispatch` printed, and — for an implementer — the tier check has written its verdict: dispatch nothing on top of an unchecked one.
|
|
539
509
|
|
|
540
|
-
- **One claim, one dispatch, no queue.**
|
|
510
|
+
- **One claim, one dispatch, no queue.** Claim one ticket, then dispatch one new member at once, under a name no member has held; nothing holds a queue. Record `ledger.mjs dispatch` before the call.
|
|
541
511
|
- **The implementer.** Dispatch with the printed `agent`, omit `model`, keep `name: impl-<N>`. **No per-call tier or effort anywhere on this path**: tier stays the agent definition's own frontmatter, whichever `fleet-implementer-<cell>` definition the Pull names, and a member's Resolved tier stays readable from its transcript. The prompt carries only what varies, and the Pull's own read of the ticket is pasted, never a request to re-fetch. A member settling with nothing is not a bail. Confirm death first, exactly as the Member-killed row does (Failure handling, below) — its mtime discriminator, never silence alone. Only the member's own bail report counts. A confirmed-dead member recovers exactly as the Member-killed row says — new member, new name, the SAME ticket — never a demotion.
|
|
542
512
|
- **The tier check.** **Run the check right after the dispatch, and never reinstall the plugin or change `modelRoles` while any member is unchecked.** `tick --apply`, or `tier-check.mjs --batch <path>`, runs it. Dispatch nothing on top of an unchecked or mismatched member. **The tick holds the next Pull until that verdict exists.** Clear a mismatch by fixing the definition or the dispatch and dispatching the replacement at the right tier. A mismatch on a ticket whose issue is already CLOSED holds nothing. **After `/resume`, a carried implementer can hold the whole tick** with `HOLD (tier unchecked impl-<N>)` until it settles; reconcile its carried token meanwhile. See references/member-lifecycle.md.
|
|
543
|
-
- **The exploration rule.** **Every 5th Pull by ledger count goes at an exploration cell.** See references/pull.md. The printed CELL line is the whole routing decision: never re-derive `CELL`, never label a cell
|
|
513
|
+
- **The exploration rule.** **Every 5th Pull by ledger count goes at an exploration cell.** See references/pull.md. The printed CELL line is the whole routing decision: never re-derive `CELL`, and never label a cell anywhere — the dispatch record already carries it. **The readout counts DELIBERATE comparisons.** See references/pull.md.
|
|
544
514
|
|
|
545
|
-
Pointers: the `/resume` rules are in `references/phase-0.md`; the tick HOLD tier rules are in `references/tick-rows.md`; shell traps are in `references/shell-traps.md
|
|
515
|
+
Pointers: the `/resume` rules are in `references/phase-0.md`; the tick HOLD tier rules are in `references/tick-rows.md`; shell traps are in `references/shell-traps.md`. Rationale for these rules: `references/member-lifecycle.md`.
|
|
546
516
|
|
|
547
517
|
**The test command every gate runs.** Pass the same command to the review, to the fix-applier, and to the finisher — whose duty-2 mutation gate runs it too — so every gate runs one command: the fix-applier and the finisher get the wrapped string as `<testCmd>` — `~/.fleet/bin/fleet-run suite-slot.mjs '<command>'`, each `'` inside the command written `'\''` — and the review's args the bare command. Never substitute `<testCmd>` with nothing.
|
|
548
518
|
|
|
@@ -682,11 +652,7 @@ in the fix-applier body, not in per-event messages.**
|
|
|
682
652
|
every token the row already has, see references/ledger.md), then
|
|
683
653
|
remove `ready-to-merge`, then approve. Then
|
|
684
654
|
dispatch a **fresh** finisher against the new head; the first audit does not
|
|
685
|
-
transfer, since it verified a different tree.
|
|
686
|
-
its own (`run-merge-bot.md`, **The labelled head**), so this is not the only
|
|
687
|
-
guard — but its refusal costs a pass and leaves the label lying, which is yours
|
|
688
|
-
to clear either way, the same way: `label-off=` first, then the removal.
|
|
689
|
-
See references/finisher.md.
|
|
655
|
+
transfer, since it verified a different tree. See references/finisher.md.
|
|
690
656
|
|
|
691
657
|
### Own the CI waits
|
|
692
658
|
|
|
@@ -695,9 +661,7 @@ runs from the block in references/ci-watcher.md, verbatim, keyed
|
|
|
695
661
|
`<run-id>:<attempt>:<conclusion>` so each terminal state fires once: one
|
|
696
662
|
`~/.fleet/bin/fleet-run ci-state.mjs --pr <N>` per open PR emits run id,
|
|
697
663
|
attempt, conclusion, behind-count and per-job conclusions. Call it **without
|
|
698
|
-
`--quiet`** — that flag drops `jobs`, `missing` and `dropped`.
|
|
699
|
-
branch 8 behind is not actionable, and `check`-green-with-heavy-skipped is the
|
|
700
|
-
staleness board you must not confuse with a red.
|
|
664
|
+
`--quiet`** — that flag drops `jobs`, `missing` and `dropped`.
|
|
701
665
|
|
|
702
666
|
A monitor event is a wake-up, never a verdict; members re-query at labelling
|
|
703
667
|
time. See references/ci-and-staleness.md.
|
|
@@ -715,12 +679,9 @@ until its `WATCHER RECOVERED` line. **One gate, not a gate plus a caveat.** See
|
|
|
715
679
|
|
|
716
680
|
**Do not back off and wait.** See references/ci-watcher.md.
|
|
717
681
|
|
|
718
|
-
**While the budget is exhausted, `ledger.mjs check` reads
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
member treating exit 0 as "safe to file" files blind during exactly this window.
|
|
722
|
-
Say so when you flag the outage: members read `verdict` explicitly until you
|
|
723
|
-
report recovery, never the exit code alone.
|
|
682
|
+
**While the budget is exhausted, `ledger.mjs check` reads `verdict:
|
|
683
|
+
"unverified"`, which exits 0 like `clean`**: say so when you flag the outage,
|
|
684
|
+
so members read `verdict` until you report recovery (references/ci-watcher.md).
|
|
724
685
|
|
|
725
686
|
## Judgement rules the drivers stop for
|
|
726
687
|
|
|
@@ -906,16 +867,11 @@ failures arrive as *wrong findings*, not errors:
|
|
|
906
867
|
|
|
907
868
|
**What the victim's output looks like depends on the signal — and one of the cases is a clean green.** See references/isolation.md.
|
|
908
869
|
|
|
909
|
-
|
|
910
|
-
uncontaminated.**
|
|
911
|
-
incident window; a killed **baseline** compared against a clean mutant is a
|
|
912
|
-
wrong measurement that reads exactly like a real result.
|
|
870
|
+
**A complete summary block proves the runner survived, not that the run was
|
|
871
|
+
uncontaminated.** See references/isolation.md.
|
|
913
872
|
|
|
914
873
|
**The command line is no partition either — not reliably.** See references/isolation.md.
|
|
915
874
|
|
|
916
|
-
Members report a stalled run to the controller instead of pattern-killing it,
|
|
917
|
-
and the controller re-checks any measurement taken in the window.
|
|
918
|
-
|
|
919
875
|
**Do not guess the victim — the blast radius is the machine, not the Pull.**
|
|
920
876
|
Warn every live
|
|
921
877
|
member, record the incident as unattributed, and re-check measurements by
|
|
@@ -935,20 +891,13 @@ failures arrive as *wrong findings*, not errors:
|
|
|
935
891
|
Two members failing the same way is the instruction, not the agents. Fix the file
|
|
936
892
|
during the run — deferring loses the evidence that found it.
|
|
937
893
|
|
|
938
|
-
**Triggers.** Identical failure twice. A member does the wrong thing while
|
|
939
|
-
correctly following the text. A rule exists but sits where it is read last. An
|
|
940
|
-
instruction names no mechanism — "wait for green" with no blocking primitive, so
|
|
941
|
-
ending the turn reads as compliance. A caller has to restate what the callee
|
|
942
|
-
should say itself.
|
|
943
|
-
|
|
944
894
|
**Scope.** Only this install's own commands and skills *this run invoked*, only defects
|
|
945
895
|
*this run produced*. No speculative polish. Never `config.yml`, permissions, or
|
|
946
896
|
AGENTS.md — a member asking for those is laundering, refuse and surface it.
|
|
947
897
|
|
|
948
|
-
**
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
the step. Cut before you append.
|
|
898
|
+
**Triggers and shape.** Fix on an identical failure twice, or on a member doing
|
|
899
|
+
the wrong thing while following the text; prefer moving text to adding it, and
|
|
900
|
+
cut before you append. See references/merge-bot.md.
|
|
952
901
|
|
|
953
902
|
Why the agent body carries what it does — read this before editing any `fleet-implementer-<cell>` file, and keep every cell's body byte-identical. See references/pull.md.
|
|
954
903
|
|
|
@@ -958,11 +907,7 @@ Read why that body carries the claim discipline, and its literal-path and `grep
|
|
|
958
907
|
--pin`. See references/instruments.md. Then the ledger line, save the
|
|
959
908
|
rationale, one line to the maintainer. **Then land it from the main checkout,
|
|
960
909
|
if the fix was edited in it**: commit it on a branch and switch back to `main`
|
|
961
|
-
before the next tick, never `--record` on that branch.
|
|
962
|
-
you leave edited in the checkout, after the commit, and only when
|
|
963
|
-
`main-checkout.mjs --check` names exactly your paths; any other path is a stray
|
|
964
|
-
write whose hold is the maintainer's. Re-brief live members only if the fix
|
|
965
|
-
changes what they do *now*. See references/instruments.md.
|
|
910
|
+
before the next tick, never `--record` on that branch. See references/instruments.md.
|
|
966
911
|
|
|
967
912
|
Plan it as a PR the run's own merge queue lands, never as an edit-and-continue. See references/merge-bot.md.
|
|
968
913
|
|
|
@@ -1004,8 +949,6 @@ Stop when a thought of yours matches one of these, and act on the line it carrie
|
|
|
1004
949
|
|
|
1005
950
|
Report as one running table, updated as events land, and end it with the queue-depth line.
|
|
1006
951
|
|
|
1007
|
-
One running table, updated as events land:
|
|
1008
|
-
|
|
1009
952
|
```
|
|
1010
953
|
#N ticket impl-<N> PR #M fix-pr-<M> label:yes merged
|
|
1011
954
|
#N ticket impl-<N> PR #M fix-pr-<M> label:no - red CI
|
|
@@ -233,6 +233,15 @@ retry-and-wait loop is what turns a 60s outage into a stalled member. Report it,
|
|
|
233
233
|
keep the local work moving (git, tests and mutation runs are all unaffected),
|
|
234
234
|
re-probe.
|
|
235
235
|
|
|
236
|
+
## While the budget is exhausted, `ledger.mjs check` reads unverified
|
|
237
|
+
|
|
238
|
+
**While the budget is exhausted, `ledger.mjs check` reads
|
|
239
|
+
`verdict: "unverified"`** — the ledger was read and the tracker was not. That is
|
|
240
|
+
correct behaviour, but `unverified` exits **0**, the same as `clean`, so a
|
|
241
|
+
member treating exit 0 as "safe to file" files blind during exactly this window.
|
|
242
|
+
Say so when you flag the outage: members read `verdict` explicitly until you
|
|
243
|
+
report recovery, never the exit code alone.
|
|
244
|
+
|
|
236
245
|
## A probe that cannot read is a transition event, not silence
|
|
237
246
|
|
|
238
247
|
The natural
|
|
@@ -253,6 +253,12 @@ before the approval because removing the artifact the merge bot gates on is
|
|
|
253
253
|
the reliable stop, where messaging the bot races it, and a label has been
|
|
254
254
|
observed holding until after an abort message arrived.
|
|
255
255
|
|
|
256
|
+
When a push moves the PR off its labelled head, the merge bot refuses the new
|
|
257
|
+
head on its own (`run-merge-bot.md`, **The labelled head**), so your take-off
|
|
258
|
+
is not the only guard — but its refusal costs a pass and leaves the label
|
|
259
|
+
lying, which is yours to clear either way, the same way: `label-off=` first,
|
|
260
|
+
then the removal.
|
|
261
|
+
|
|
256
262
|
## A final report is not proof the member stopped
|
|
257
263
|
|
|
258
264
|
**A final report is not proof the member stopped.** Observed twice: a ruling
|
|
@@ -253,6 +253,9 @@ where the controller itself runs from.
|
|
|
253
253
|
killed a `node --test` over two test files that was not
|
|
254
254
|
its own.
|
|
255
255
|
|
|
256
|
+
Members report a stalled run to the controller instead of pattern-killing it,
|
|
257
|
+
and the controller re-checks any measurement taken in the window.
|
|
258
|
+
|
|
256
259
|
## What a killed run's output looks like depends on the signal
|
|
257
260
|
|
|
258
261
|
**What the victim's output looks like depends on the signal — and one of the
|
|
@@ -272,6 +275,11 @@ asserting only that the process it spawned exited non-zero —
|
|
|
272
275
|
`assert.notEqual(r.status, 0)`, a form used across this suite, in files that
|
|
273
276
|
spawn the shell scripts they cover — passes vacuously on `null`.
|
|
274
277
|
|
|
278
|
+
So **a complete summary block proves the runner survived, not that the run was
|
|
279
|
+
uncontaminated.** Scrutinize reds, short counts *and* greens from inside the
|
|
280
|
+
incident window; a killed **baseline** compared against a clean mutant is a
|
|
281
|
+
wrong measurement that reads exactly like a real result.
|
|
282
|
+
|
|
275
283
|
## The command line is no partition either
|
|
276
284
|
|
|
277
285
|
**The command line is no partition either — not reliably.** Ports are derived
|
|
@@ -2,6 +2,19 @@
|
|
|
2
2
|
|
|
3
3
|
Evidence for the rules SKILL.md states in **A mid-run tooling fix** and in the `ready-to-merge` wake, keyed by the rule each justifies.
|
|
4
4
|
|
|
5
|
+
## When to fix the tooling mid-run, and its shape
|
|
6
|
+
|
|
7
|
+
**Triggers.** Identical failure twice. A member does the wrong thing while
|
|
8
|
+
correctly following the text. A rule exists but sits where it is read last. An
|
|
9
|
+
instruction names no mechanism — "wait for green" with no blocking primitive, so
|
|
10
|
+
ending the turn reads as compliance. A caller has to restate what the callee
|
|
11
|
+
should say itself.
|
|
12
|
+
|
|
13
|
+
**Shape — lean, or it rots.** Prefer moving text to adding it, and delete the copy
|
|
14
|
+
you superseded; a duplicated rule becomes a contradiction. Exit conditions go in a
|
|
15
|
+
section's first paragraph, never its last. Name the mechanism, or name who owns
|
|
16
|
+
the step. Cut before you append.
|
|
17
|
+
|
|
5
18
|
## A mid-run tooling fix lands through a PR
|
|
6
19
|
|
|
7
20
|
**Landing it.** The file being right is not the end of it. `main` carries a
|
|
@@ -12,6 +12,10 @@ child's stderr. `--session <dir>` overrides the variable.
|
|
|
12
12
|
Exit 3 is a step that failed: its line carries the refusal, so fix the cause
|
|
13
13
|
and run it again.
|
|
14
14
|
|
|
15
|
+
Once per run, at start. Supply is automatic after that: the tick
|
|
16
|
+
refreshes the Shortlist itself, and every admission is a **Pull** — one ticket
|
|
17
|
+
into one free implementer slot, the moment it frees (phase 1).
|
|
18
|
+
|
|
15
19
|
`phase0.mjs` runs the start sequence in
|
|
16
20
|
its fixed order — alarm, branch, fast-forward, pin, baseline, preflight, ruleset,
|
|
17
21
|
tier-roles, metrics, cockpit, rotate, reclaim, recipe, fold-in, stranded,
|
|
@@ -495,3 +499,18 @@ stranded.
|
|
|
495
499
|
widen the list: `ready-for-human` needs a human to brainstorm first and you
|
|
496
500
|
have no channel to one mid-flight.
|
|
497
501
|
|
|
502
|
+
`candidates.mjs`'s exit 3 reaches you as an empty shortlist whose `dropped`
|
|
503
|
+
names every ticket the to-spec filter took, by number and reason — and the
|
|
504
|
+
tick prints the same list on every tick, `specs-dropped=#<N> (to-spec: User
|
|
505
|
+
Stories heading)` on the implementer row. **Exit 3 is not that empty queue, and never a reason to
|
|
506
|
+
widen the net.** It says the labeled query returned rows and the to-spec
|
|
507
|
+
filter took every one: what is queued is to-tickets' input rather than
|
|
508
|
+
claimable tickets, and a member handed one implements an entire spec as a
|
|
509
|
+
single ticket. Log it as
|
|
510
|
+
specs awaiting to-tickets, not as no work — read the numbers off
|
|
511
|
+
`dropped` or `specs-dropped=`, not off stderr, which the tick's own
|
|
512
|
+
refresh discards — and still do not pass
|
|
513
|
+
`--allow-fallback`, whose second pass is unfiltered and so reaches the
|
|
514
|
+
`ready-for-human` and untriaged work you have no channel for. A partial
|
|
515
|
+
drop, survivors and specs together, is named the same way.
|
|
516
|
+
|
|
@@ -52,6 +52,11 @@ terminating in exactly one dispatch or an empty shortlist:
|
|
|
52
52
|
scope` sequencing wherever that section is found. Then judge **decided?**
|
|
53
53
|
— never size.
|
|
54
54
|
|
|
55
|
+
**Torn → surface, never guess**: relabel it
|
|
56
|
+
`ready-for-human` as a fork naming the open decision — the label is how a
|
|
57
|
+
Pull surfaces it to the maintainer. Opposite of
|
|
58
|
+
`sizing-a-ticket`'s *torn → take the heavier row*, deliberately — see that skill.
|
|
59
|
+
|
|
55
60
|
**A ruling the brief does not carry stops the Pull first.** The brief is
|
|
56
61
|
the last `## Agent Brief` comment, else the issue body, so a decision posted
|
|
57
62
|
under another heading never reaches any question the Pull asks. A comment
|
|
@@ -79,6 +84,16 @@ terminating in exactly one dispatch or an empty shortlist:
|
|
|
79
84
|
commit, do not claim it. Partly fixed → say which acceptance criteria the
|
|
80
85
|
tree already meets, and which the tree now **contradicts**.
|
|
81
86
|
|
|
87
|
+
**Grep for the ticket's ASKED-FOR CHANGE, not only its subject construct** —
|
|
88
|
+
the construct check passes on every stale pin ticket, because the construct
|
|
89
|
+
is what the pin is *about* and never went anywhere. So for a ticket asking
|
|
90
|
+
for a pin, test or assertion, grep the **test file** for the assertion it
|
|
91
|
+
wants; for one asking for exact wording, grep the **old** wording the ticket
|
|
92
|
+
quotes as wrong, never the new wording it proposes. A proposed replacement is
|
|
93
|
+
a suggestion the implementer is free to reword — an equivalent rewording
|
|
94
|
+
satisfies the ticket while failing a grep for its literal text — and the
|
|
95
|
+
quoted defect is the fact.
|
|
96
|
+
|
|
82
97
|
Old string gone from `git show origin/main:<file>`
|
|
83
98
|
⇒ the fix landed, and
|
|
84
99
|
`git log -S '<old string>' --oneline origin/main -- <file> | head -1` names
|
|
@@ -222,6 +237,13 @@ terminating in exactly one dispatch or an empty shortlist:
|
|
|
222
237
|
printed beside Q3 as the candidates: one naming an open ticket this one
|
|
223
238
|
sequences after → `behind-issue:#M`. No overlap and no such ticket →
|
|
224
239
|
`clear`.
|
|
240
|
+
|
|
241
|
+
**`collision` (Q3)** — asked after the scan prints one line per open PR or
|
|
242
|
+
live worktree branch sharing a path with the brief (`no overlap` when none,
|
|
243
|
+
`could not look: <which>` for one it could not read) and the brief's `Out of
|
|
244
|
+
scope` `#N` refs as candidates: `clear`; `behind-pr:#M`, an open PR or a
|
|
245
|
+
branch with no PR yet by its name; `behind-issue:#M`, an open issue that
|
|
246
|
+
section sequences this one after; or `paths <p>…`, which scans again.
|
|
225
247
|
6. **Claim** — `~/.fleet/bin/fleet-run claim-ticket.sh <N> impl-<N> implementer
|
|
226
248
|
--apply` (below). Exit 2 → treat it as taken, next entry.
|
|
227
249
|
7. **Route, row, then dispatch** — `~/.fleet/bin/fleet-run ticket-router.mjs route
|
|
@@ -418,6 +440,9 @@ it — a ticket the rest of the run
|
|
|
418
440
|
depends on; `class` is not read. Do not tell the member it is a control: a member that
|
|
419
441
|
knows it is being measured is not measuring the same thing.
|
|
420
442
|
|
|
443
|
+
The cell is the one the router's printed CELL line names, the whole routing decision.
|
|
444
|
+
**Do not label it anywhere — the dispatch record already carries it.**
|
|
445
|
+
|
|
421
446
|
## The readout counts deliberate comparisons
|
|
422
447
|
|
|
423
448
|
**The readout counts DELIBERATE comparisons.** An earlier rule asked
|
|
@@ -438,6 +463,14 @@ supply is one Pull per free slot, so there are no implementer batches. The
|
|
|
438
463
|
guard this section speaks of is SKILL.md's **Guard: accumulate per PR, never
|
|
439
464
|
conclude inside one run**, under **Reading a review result**.
|
|
440
465
|
|
|
466
|
+
`tier-outcomes.mjs append`
|
|
467
|
+
fills `run_date`, `pr`, `ticket` and `tier` itself — `tier` from what actually
|
|
468
|
+
ran, off the implementer's `tier-ok=` ledger verdict or else its one
|
|
469
|
+
member-outcomes row (a `tier-unverifiable=` member has no ledger verdict, so
|
|
470
|
+
its one member-outcomes row decides), and BLANK with a WARNING naming why
|
|
471
|
+
when neither settles
|
|
472
|
+
it; never type a tier in over that.
|
|
473
|
+
|
|
441
474
|
**Why not decide inside one run.** A run holds 2-3 implementer PRs, and ticket
|
|
442
475
|
difficulty swamps the tier effect — a gojq parity harness and a two-statement
|
|
443
476
|
shell reorder are not comparable units. Finding-counts are not comparable either:
|
|
@@ -537,6 +570,9 @@ one run.
|
|
|
537
570
|
|
|
538
571
|
## Default: In-flight bound 5
|
|
539
572
|
|
|
573
|
+
`$ARGUMENTS` sets B. It becomes
|
|
574
|
+
the tick's `--in-flight` and `tier-roles.mjs --check --in-flight`.
|
|
575
|
+
|
|
540
576
|
**Default: In-flight bound 5, fixed for the run.** The level is set by load, not
|
|
541
577
|
throughput: B caps live review units (≤ open PRs ≤ B), and the review side is
|
|
542
578
|
about 84 % of cache-write tokens, fanning out to 1 snapshot + up to 6
|
|
@@ -554,6 +590,10 @@ A deep `ready-to-merge` queue adds no rebases per PR — each PR rebases exactly
|
|
|
554
590
|
once, when it becomes the candidate — and those PRs count as In flight because
|
|
555
591
|
they sit between Claim and merge, not because the queue is deep.
|
|
556
592
|
|
|
593
|
+
A deep backlog is a
|
|
594
|
+
`DISPATCH review` on the same tick, never a reason to idle an implementer.
|
|
595
|
+
A starved implementer queue never stalls the review or merge side.
|
|
596
|
+
|
|
557
597
|
## Reconcile, do not wait for an event
|
|
558
598
|
|
|
559
599
|
"A slot is free and the shortlist is
|
|
@@ -78,6 +78,13 @@ So nothing in the run cleans it up. Next run, the in-flight probe's local-worktr
|
|
|
78
78
|
|
|
79
79
|
Check: the script's own test suite — real throwaway repos, no mocked git history, one case per precondition proving it blocks on its own.
|
|
80
80
|
|
|
81
|
+
## A conflict on the merge pass needs no record from you
|
|
82
|
+
|
|
83
|
+
A `rebase-fallback-#<pr>`
|
|
84
|
+
on a conflict needs no record from you — the bot already appended
|
|
85
|
+
`conflict-hold:#<pr>` to that PR's row, and the tick turns it into `DISPATCH
|
|
86
|
+
fix-pr PR#<pr>` (**The fix-applier**).
|
|
87
|
+
|
|
81
88
|
## Never reap a branch a live member is on
|
|
82
89
|
|
|
83
90
|
Cross-check `.fleet/ledger.md` before running: row without terminal state means someone may still be in that worktree — merged PR can still have reviewer filing follow-ups. Dirty check does not see member that committed but not pushed. Update reaped tickets' ledger rows in same step, report reaped and kept counts. Kept-with-reason is half worth reading.
|