@feigi/fleet-ctl 3.82.16 → 3.82.17
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 +93 -204
- package/skills/run-team/references/correction-tickets.md +6 -0
- package/skills/run-team/references/instruments.md +26 -1
- package/skills/run-team/references/isolation.md +22 -0
- package/skills/run-team/references/member-lifecycle.md +32 -1
- package/skills/run-team/references/merge-bot.md +1 -1
- package/skills/run-team/references/pull.md +13 -0
- package/skills/run-team/references/tick-rows.md +2 -2
package/package.json
CHANGED
package/skills/run-team/SKILL.md
CHANGED
|
@@ -304,6 +304,31 @@ A row with `review=` and no `reviewed=` is a review in flight, and the tick coun
|
|
|
304
304
|
- **The merge bot.** Named `merge-bot-<n>`; `ledger.mjs dispatch merge-bot` numbers it. Never two at once. 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.
|
|
305
305
|
- **The finisher.** Its render and receives are in `references/finisher.md`.
|
|
306
306
|
|
|
307
|
+
**A fleet member is never dispatched with omp's `isolated: true`.** See references/isolation.md.
|
|
308
|
+
|
|
309
|
+
**A member's tree is the claimed worktree, addressed by absolute path.** See references/isolation.md.
|
|
310
|
+
|
|
311
|
+
**The controller's own cwd stays the main checkout, unchanged.** See references/isolation.md.
|
|
312
|
+
|
|
313
|
+
**Name every member.**
|
|
314
|
+
Names follow the unit of work: `impl-<issue#>`, `fix-pr-<pr#>`,
|
|
315
|
+
`review-pr-<pr#>`, `finisher-pr-<pr#>`, `merge-bot-<n>`. See
|
|
316
|
+
references/member-lifecycle.md.
|
|
317
|
+
|
|
318
|
+
**Fresh context per member.** One member, one unit of work, gone. Refill =
|
|
319
|
+
**new** member, **new** name. See references/member-lifecycle.md.
|
|
320
|
+
|
|
321
|
+
**The scratch root is computed, never invented and never recorded.** You run
|
|
322
|
+
`~/.fleet/bin/fleet-run scratch-root.mjs`; a non-zero exit is an environment to
|
|
323
|
+
fix, not a cue to pick another root.
|
|
324
|
+
`<scratch>` in this file is the path it prints, resolved before you send anything: every
|
|
325
|
+
brief that carries one carries the absolute path you passed it — an
|
|
326
|
+
implementer's `<scratch>/impl-<N>/`, the recipe deriver's
|
|
327
|
+
`<scratch>/derive-recipe/`, a fix-applier's, a finisher's and a merge bot's
|
|
328
|
+
`<scratch>/pr<N>/…`, and a review runner's `scratch` argument, which is the
|
|
329
|
+
root itself. A member whose prompt names no path asks you by name and never
|
|
330
|
+
makes one up. See references/isolation.md.
|
|
331
|
+
|
|
307
332
|
### Reading a review result
|
|
308
333
|
|
|
309
334
|
**You read the digest; the findings are the fix-applier's.**
|
|
@@ -439,6 +464,7 @@ It blocks, then prints one line. Which line it is, is the whole protocol:
|
|
|
439
464
|
not a reason to end the run; they are the state a newly triaged ticket arrives
|
|
440
465
|
into. The run ends when you drain it, when the budget goes, or when this
|
|
441
466
|
context does — not because there was briefly nothing to do.
|
|
467
|
+
Zeroes on the cockpit are not yet proof the pipeline is idle.
|
|
442
468
|
|
|
443
469
|
**When you stop on purpose, say why — one command, and it is the last thing
|
|
444
470
|
you owe the next run.** See references/ci-and-staleness.md.
|
|
@@ -1062,6 +1088,25 @@ vs specific finding with paths → paths win. See references/reviewers.md.
|
|
|
1062
1088
|
Suspect a neighbour before a member's own diff — for unexplained failures, and
|
|
1063
1089
|
equally for any **finding** that came from reading source.
|
|
1064
1090
|
|
|
1091
|
+
**Never read a member's silence as assent**, and require members to report their *confirmation state*
|
|
1092
|
+
alongside results — "I escalated X, received no ruling, proceeded on default Y".
|
|
1093
|
+
After any ruling
|
|
1094
|
+
you cannot confirm was received, re-check the artifacts it governed. See references/member-lifecycle.md.
|
|
1095
|
+
|
|
1096
|
+
### Re-check the instruments before a gate
|
|
1097
|
+
|
|
1098
|
+
**You read your instruments out of a tree every member can write to — re-check them before every gate decision.** See references/instruments.md.
|
|
1099
|
+
|
|
1100
|
+
- **Re-check before you act on any instrument reading** — a SHA acceptance, a CI
|
|
1101
|
+
verdict, the reconcile, a reap, a label gate — from the main checkout phase 0 pinned from:
|
|
1102
|
+
`~/.fleet/bin/fleet-run instruments.sh`. **Exit 0 is the only code that
|
|
1103
|
+
lets a gate proceed. Exit 1 (the set changed) and exit 2 (the check could not
|
|
1104
|
+
answer) both refuse: report what it printed and do NOT re-read the
|
|
1105
|
+
instrument** — a guard that fails open on "could not look" protects nothing.
|
|
1106
|
+
- **Re-pin only after a change you made deliberately.** **A mid-run tooling fix**
|
|
1107
|
+
is the one legitimate writer. Re-pinning to clear a refusal you cannot
|
|
1108
|
+
explain discards the check.
|
|
1109
|
+
|
|
1065
1110
|
### Relabel causes
|
|
1066
1111
|
|
|
1067
1112
|
- **Implementer bails before implementing** → `fleet-event.mjs impl-report impl-<N>`
|
|
@@ -1078,6 +1123,9 @@ equally for any **finding** that came from reading source.
|
|
|
1078
1123
|
The call comments the cause and releases the claim — never when `fixed` neither closes nor relabels N — then ticks:
|
|
1079
1124
|
the head the tick names next is a *different* ticket.
|
|
1080
1125
|
|
|
1126
|
+
A member that bails demotes nothing itself; demotion by cause is yours
|
|
1127
|
+
(**Implementer bails before implementing**).
|
|
1128
|
+
|
|
1081
1129
|
### Resolving a finisher halt
|
|
1082
1130
|
|
|
1083
1131
|
A halt at duty 1 reads identical from a bare SHA mismatch whatever caused it,
|
|
@@ -1156,210 +1204,6 @@ and flag the PR for a human. A new review of the PR counts again from none.
|
|
|
1156
1204
|
| Merge bot's gate finds the merge would remove lines `main` gained after the PR's work began (`main-gain-removed:<path>`, exit 1) | Relay `main-gain-removed:<path>-#<pr>` to a human with the hit list and the acknowledgement keys the bot printed. PR stays queued, label untouched, nothing written to the ledger, and no member is dispatched to restore the lines — the removal may be deliberate. It clears when the PR stops removing them or its body carries `main-gain-removal: <path> <key> - <why>` for each hit |
|
|
1157
1205
|
| Merge bot's gate cannot answer the main-gain check (`main-gain-unanswerable`, exit 2) | Report `main-gain-unanswerable-#<pr>` with what it printed, PR stays queued, label untouched |
|
|
1158
1206
|
|
|
1159
|
-
## Rules that fail silently
|
|
1160
|
-
|
|
1161
|
-
These rules fail silently when they are skipped: check each before you act on a member's silence, and stop reading silence as a report or as assent.
|
|
1162
|
-
|
|
1163
|
-
Zeroes on the cockpit are not yet proof the pipeline is idle.
|
|
1164
|
-
|
|
1165
|
-
**A report is delivered, not implied by ending a turn.** Every member owes
|
|
1166
|
-
the controller one report naming its outcome before it exits — including a
|
|
1167
|
-
member whose prompt carries no explicit report line. The "report the SHA",
|
|
1168
|
-
"report PR number" and "stop and report" instructions below *are* that
|
|
1169
|
-
report, not a second obligation on top of it. A member that does the work
|
|
1170
|
-
correctly and ends its turn has reported nothing: the controller learns the
|
|
1171
|
-
outcome only by re-reading artifacts and pinging, and a finding held only in
|
|
1172
|
-
that member's context is lost. Members did exactly this in one run —
|
|
1173
|
-
finishers, a reviewer and merge bots alike, the work done and only the
|
|
1174
|
-
delivery missing. Every brief's report paragraph says it. See
|
|
1175
|
-
references/member-lifecycle.md.
|
|
1176
|
-
|
|
1177
|
-
**The implementer, fix-applier, finisher, merge-bot and review-runner briefs
|
|
1178
|
-
each tell the member you do not acknowledge reports; you never write that line
|
|
1179
|
-
yourself.** A member cannot see whether its report arrived, so silence
|
|
1180
|
-
from you is indistinguishable from loss and it re-sends — three members did in
|
|
1181
|
-
one run, each burning a turn, and in all three the original had in fact arrived.
|
|
1182
|
-
Each of those templates under `briefs/` carries the line: *"The controller does
|
|
1183
|
-
not acknowledge reports. Send once and exit; never re-send unless the controller
|
|
1184
|
-
asks by name."*
|
|
1185
|
-
|
|
1186
|
-
So when a report is missing, **ask by name — that is what the "unless the controller asks by name" clause is for — and do not attribute the gap to the member until it answers.** See references/member-lifecycle.md.
|
|
1187
|
-
|
|
1188
|
-
The ask is the controller's move, not the member's. See references/member-lifecycle.md.
|
|
1189
|
-
|
|
1190
|
-
**Your OWN messages can vanish the same way, and that half is not recoverable by
|
|
1191
|
-
a re-send.** Two controller rulings were lost in one run, both with a
|
|
1192
|
-
`success: true` receipt: a member proceeded on its stated default and filed a
|
|
1193
|
-
tracker issue the lost ruling had said not to file. So **never read a member's
|
|
1194
|
-
silence as assent**, and require members to report their *confirmation state*
|
|
1195
|
-
alongside results — "I escalated X, received no ruling, proceeded on default Y".
|
|
1196
|
-
That sentence is the only thing that made either loss visible. After any ruling
|
|
1197
|
-
you cannot confirm was received, re-check the artifacts it governed.
|
|
1198
|
-
|
|
1199
|
-
**Name every member.** The name is the ledger token and the hub address; omit
|
|
1200
|
-
it and the ledger cannot match the member.
|
|
1201
|
-
Names follow the unit of work: `impl-<issue#>`, `fix-pr-<pr#>`,
|
|
1202
|
-
`review-pr-<pr#>`, `finisher-pr-<pr#>`, `merge-bot-<n>`. See
|
|
1203
|
-
references/member-lifecycle.md.
|
|
1204
|
-
|
|
1205
|
-
**Fresh context per member.** One member, one unit of work, gone. Refill =
|
|
1206
|
-
**new** member, **new** name.
|
|
1207
|
-
|
|
1208
|
-
See references/member-lifecycle.md.
|
|
1209
|
-
|
|
1210
|
-
**You read your instruments out of a tree every member can write to — re-check them before every gate decision.** See references/instruments.md.
|
|
1211
|
-
|
|
1212
|
-
- **Pin once**, at phase 0 step 0 above, from the main checkout you are
|
|
1213
|
-
running this from — never from a member's worktree, which is gitignored
|
|
1214
|
-
and carries no baseline:
|
|
1215
|
-
`~/.fleet/bin/fleet-run instruments.sh --pin`. On a workspace that does not
|
|
1216
|
-
track `plugin/…`, the pin names the plugin checkout once — `--pin --audit
|
|
1217
|
-
<plugin-checkout>` — and every check after it follows the recorded tree.
|
|
1218
|
-
- **Re-check before you act on any instrument reading** — a SHA acceptance, a CI
|
|
1219
|
-
verdict, the reconcile, a reap, a label gate — from that same main checkout:
|
|
1220
|
-
`~/.fleet/bin/fleet-run instruments.sh`. **Exit 0 is the only code that
|
|
1221
|
-
lets a gate proceed. Exit 1 (the set changed) and exit 2 (the check could not
|
|
1222
|
-
answer) both refuse: report what it printed and do NOT re-read the
|
|
1223
|
-
instrument** — a guard that fails open on "could not look" protects nothing.
|
|
1224
|
-
**A label gate and a CI verdict are also taken by dispatched members, not
|
|
1225
|
-
only by you** — the finisher labels, and the merge bot merges on its own
|
|
1226
|
-
reading — and neither is dispatched to read this file, so neither can be
|
|
1227
|
-
reached by stating the rule here. Each carries its own copy: the finisher's
|
|
1228
|
-
in the instrument re-check block of `agents/fleet-finisher.agent.md`, the merge bot's inside
|
|
1229
|
-
`merge-gate.mjs`, step 3 of `run-merge-bot.md`.
|
|
1230
|
-
- **Re-pin only after a change you made deliberately.** The mid-run tooling fix
|
|
1231
|
-
below is the one legitimate writer. Re-pinning to clear a refusal you cannot
|
|
1232
|
-
explain discards the check.
|
|
1233
|
-
|
|
1234
|
-
It covers every tracked file under this repo's own plugin component directories
|
|
1235
|
-
— `plugin/commands/`, `plugin/scripts/`, `plugin/skills/`, `plugin/agents/`,
|
|
1236
|
-
`plugin/workflows/` — the probes, the libraries they source, and these runbooks,
|
|
1237
|
-
which you also read from that tree. Not the whole repo: `docs/metrics/` is
|
|
1238
|
-
appended by THIS run, so covering it would refuse on the run's own bookkeeping
|
|
1239
|
-
every time. It does not cover refs, deliberately: `claim-ticket.sh` creates a
|
|
1240
|
-
branch per ticket and `reap.sh` deletes them in the ref store every worktree
|
|
1241
|
-
shares, so ordinary work moves refs several times a run and a per-gate
|
|
1242
|
-
refusal on that is noise.
|
|
1243
|
-
|
|
1244
|
-
**A member runs its test suite in the foreground and blocks on it.** See references/member-lifecycle.md.
|
|
1245
|
-
|
|
1246
|
-
**The scratch root is computed, never invented and never recorded.** No harness
|
|
1247
|
-
supplies a scratch directory to a member, so a member left to name its own
|
|
1248
|
-
invents one — and the liveness read in **The tick's rows**, which looks at the files under the
|
|
1249
|
-
directory a member's own prompt assigned it, then watches a directory nobody
|
|
1250
|
-
else can find. You run `~/.fleet/bin/fleet-run scratch-root.mjs`: it prints one
|
|
1251
|
-
absolute path, `~/.fleet/scratch/<repo-key>/`, the same from the main checkout
|
|
1252
|
-
and from every linked worktree, and the same again when a compacted or
|
|
1253
|
-
re-invoked controller runs it, so nothing writes it down. It exits non-zero,
|
|
1254
|
-
with its reason, when the root would sit inside a git work tree that does not
|
|
1255
|
-
ignore it; that is an environment to fix, not a cue to pick another root.
|
|
1256
|
-
`<scratch>` in this file is that path, resolved before you send anything: every
|
|
1257
|
-
brief that carries one carries the absolute path you passed it — an
|
|
1258
|
-
implementer's `<scratch>/impl-<N>/`, the recipe deriver's
|
|
1259
|
-
`<scratch>/derive-recipe/`, a fix-applier's, a finisher's and a merge bot's
|
|
1260
|
-
`<scratch>/pr<N>/…`, and a review runner's `scratch` argument, which is the
|
|
1261
|
-
root itself. A member whose prompt names no path asks you by name and never
|
|
1262
|
-
makes one up.
|
|
1263
|
-
|
|
1264
|
-
## Worktree and claim model
|
|
1265
|
-
|
|
1266
|
-
Run none of this by hand: act through `claim-ticket.sh`, `release-ticket.sh`, `reap.sh` and `inflight.sh` as their phases say, and dispatch every member into its claimed worktree by absolute path.
|
|
1267
|
-
|
|
1268
|
-
**Claim, release and reap are unchanged on omp.** `claim-ticket.sh`,
|
|
1269
|
-
`release-ticket.sh`, `reap.sh` and `inflight.sh` are git-native and operate on
|
|
1270
|
-
the single shared ref store every worktree and the main checkout read and
|
|
1271
|
-
write directly (**Phase 1**, the tick's reap, and `release-ticket.sh` under
|
|
1272
|
-
**Failure handling**); nothing in omp's `task` model touches that
|
|
1273
|
-
store, so none of the four scripts carries a dialect branch.
|
|
1274
|
-
|
|
1275
|
-
**A fleet member is never dispatched with omp's `isolated: true`.** See references/isolation.md.
|
|
1276
|
-
|
|
1277
|
-
**A member's tree is the claimed worktree, addressed by absolute path.** See references/isolation.md.
|
|
1278
|
-
|
|
1279
|
-
**The one open gap that probe measured: `task` does not accept a per-dispatch working directory.** See references/isolation.md.
|
|
1280
|
-
|
|
1281
|
-
**The same gap reaches past the filesystem: `task`-dispatched members share one `eval` kernel.** See references/isolation.md.
|
|
1282
|
-
|
|
1283
|
-
**`release-ticket.sh` is not a no-op on omp, and `inflight.sh`'s probes are unaffected by a running member.** See references/isolation.md.
|
|
1284
|
-
|
|
1285
|
-
**The controller's own cwd stays the main checkout, unchanged.** Nothing in
|
|
1286
|
-
this section's dispatch recipe — the cwd recipe above, the isolated-workspace
|
|
1287
|
-
measurement, or the teardown scoping — moves
|
|
1288
|
-
where the controller itself runs from.
|
|
1289
|
-
|
|
1290
|
-
## Why the implementer body carries what it does
|
|
1291
|
-
|
|
1292
|
-
Read this before you edit any `fleet-implementer-<cell>` file, and stop editing when every cell's body is byte-identical again.
|
|
1293
|
-
|
|
1294
|
-
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.
|
|
1295
|
-
|
|
1296
|
-
- **Every implementer body carries the claim discipline, because tickets that restate facts ship new wrong claims** — inherited from the ticket, and minted in prose nobody asked for. See references/correction-tickets.md.
|
|
1297
|
-
- **The settling command for "which files read X" must never be a literal-path
|
|
1298
|
-
grep.** Replace the file with `MUTATED` in a throwaway copy, run the suite, and read off
|
|
1299
|
-
which suites red: that answers which ones **depend on its contents**, which is
|
|
1300
|
-
the question a coverage claim actually needs, and it returns a different set
|
|
1301
|
-
from any spelling of the grep. See references/correction-tickets.md.
|
|
1302
|
-
- **A settling command over literal text uses `grep -F`, and its zero counts only after the same command finds a line known to match.** See references/correction-tickets.md.
|
|
1303
|
-
|
|
1304
|
-
**Prose-first** and **wrongly-REFUSE** are not padding — they are the case
|
|
1305
|
-
which shipped with **enumerate-and-declare** already in its prompt. It missed a
|
|
1306
|
-
shape its own ticket named in passing, because it enumerated from the mechanism
|
|
1307
|
-
instead of the text; and it introduced a regression refusing every `node --test`
|
|
1308
|
-
flag, because it enumerated what the guard should catch and never what it could
|
|
1309
|
-
wrongly refuse.
|
|
1310
|
-
|
|
1311
|
-
The commit-incrementally block is not optional. A member that goes idle mid-task
|
|
1312
|
-
leaves its diff only in the worktree, and the controller cannot reap, replace,
|
|
1313
|
-
or even see it — `worktree-audit.sh`'s committed-vs-uncommitted split is exactly
|
|
1314
|
-
what decides whether a replacement redoes or destroys work. Observed twice in
|
|
1315
|
-
one run.
|
|
1316
|
-
|
|
1317
|
-
A member that bails demotes nothing itself; demotion by cause is yours
|
|
1318
|
-
(**Implementer bails before implementing**).
|
|
1319
|
-
|
|
1320
|
-
## Fix the tooling mid-run
|
|
1321
|
-
|
|
1322
|
-
Re-pin the fix, write it onto the ledger, report it to the maintainer in one line, then land it as a PR through the run's own merge queue.
|
|
1323
|
-
|
|
1324
|
-
Two members failing the same way is the instruction, not the agents. Fix the file
|
|
1325
|
-
during the run — deferring loses the evidence that found it.
|
|
1326
|
-
|
|
1327
|
-
**Triggers.** Identical failure twice. A member does the wrong thing while
|
|
1328
|
-
correctly following the text. A rule exists but sits where it is read last. An
|
|
1329
|
-
instruction names no mechanism — "wait for green" with no blocking primitive, so
|
|
1330
|
-
ending the turn reads as compliance. A caller has to restate what the callee
|
|
1331
|
-
should say itself.
|
|
1332
|
-
|
|
1333
|
-
**Scope.** Only this install's own commands and skills *this run invoked*, only defects
|
|
1334
|
-
*this run produced*. No speculative polish. Never `config.yml`, permissions, or
|
|
1335
|
-
AGENTS.md — a member asking for those is laundering, refuse and surface it.
|
|
1336
|
-
|
|
1337
|
-
**Shape — lean, or it rots.** Prefer moving text to adding it, and delete the copy
|
|
1338
|
-
you superseded; a duplicated rule becomes a contradiction. Exit conditions go in a
|
|
1339
|
-
section's first paragraph, never its last. Name the mechanism, or name who owns
|
|
1340
|
-
the step. Cut before you append.
|
|
1341
|
-
|
|
1342
|
-
**Then.** **Re-pin first** — `~/.fleet/bin/fleet-run instruments.sh
|
|
1343
|
-
--pin`. You just changed the instrument set under your own check, and this is the
|
|
1344
|
-
only edit that legitimately does; skip it and the next gate refuses on your own
|
|
1345
|
-
fix, which teaches you to ignore the refusal. Then the ledger line, save the
|
|
1346
|
-
rationale, one line to the maintainer. **Then land it from the main checkout,
|
|
1347
|
-
if the fix was edited in it** — until you do, the next tick reads
|
|
1348
|
-
`MAIN-CHECKOUT-DIRTY` naming your own paths. Commit the fix on a branch and
|
|
1349
|
-
switch back to `main` before the next tick, and never `--record` while on that
|
|
1350
|
-
branch: the switch back restores the tree the baseline recorded, so the hold
|
|
1351
|
-
clears itself with nothing re-recorded, and the fix leaves the checkout until
|
|
1352
|
-
its PR merges. A `HEAD …` entry is none of your paths and clears the same way.
|
|
1353
|
-
Re-baseline only a fix you leave edited in the checkout: run
|
|
1354
|
-
`~/.fleet/bin/fleet-run main-checkout.mjs --check` first, and only when the
|
|
1355
|
-
paths it names are exactly the ones you just edited, run `--record` — never
|
|
1356
|
-
before the commit, because the switch back would then read your own paths
|
|
1357
|
-
dirty again. Any other path on that line is a stray write — leave the hold for
|
|
1358
|
-
the maintainer, because `--record` would certify it with yours. Live members
|
|
1359
|
-
hold the old text — re-brief only if it changes what they do *now*.
|
|
1360
|
-
|
|
1361
|
-
Plan it as a PR the run's own merge queue lands, never as an edit-and-continue. See references/merge-bot.md.
|
|
1362
|
-
|
|
1363
1207
|
## Failure handling
|
|
1364
1208
|
|
|
1365
1209
|
Match the failure to its row in the table below and run that response; where the row says report or flag, stop there.
|
|
@@ -1406,6 +1250,8 @@ Audit every worktree before dispatching replacements with
|
|
|
1406
1250
|
ahead-count and uncommitted files, the committed-vs-uncommitted distinction that
|
|
1407
1251
|
decides whether a replacement redoes or destroys work.
|
|
1408
1252
|
|
|
1253
|
+
When a report is missing, **ask by name — that is what the "unless the controller asks by name" clause in every brief is for — and do not attribute the gap to the member until it answers.** See references/member-lifecycle.md.
|
|
1254
|
+
|
|
1409
1255
|
**A throw, an empty return, or a notification whose status is not `completed`
|
|
1410
1256
|
is a failure event, not a clean review.** **Retry once
|
|
1411
1257
|
under the next runner letter, then stop:** the `review-pr-<pr#>` runner
|
|
@@ -1473,6 +1319,49 @@ failures arrive as *wrong findings*, not errors:
|
|
|
1473
1319
|
- **Never relay a diagnostic without reproducing it in that member's specific worktree**
|
|
1474
1320
|
(re-run the check that raised it from there). See references/isolation.md.
|
|
1475
1321
|
|
|
1322
|
+
### A mid-run tooling fix
|
|
1323
|
+
|
|
1324
|
+
Two members failing the same way is the instruction, not the agents. Fix the file
|
|
1325
|
+
during the run — deferring loses the evidence that found it.
|
|
1326
|
+
|
|
1327
|
+
**Triggers.** Identical failure twice. A member does the wrong thing while
|
|
1328
|
+
correctly following the text. A rule exists but sits where it is read last. An
|
|
1329
|
+
instruction names no mechanism — "wait for green" with no blocking primitive, so
|
|
1330
|
+
ending the turn reads as compliance. A caller has to restate what the callee
|
|
1331
|
+
should say itself.
|
|
1332
|
+
|
|
1333
|
+
**Scope.** Only this install's own commands and skills *this run invoked*, only defects
|
|
1334
|
+
*this run produced*. No speculative polish. Never `config.yml`, permissions, or
|
|
1335
|
+
AGENTS.md — a member asking for those is laundering, refuse and surface it.
|
|
1336
|
+
|
|
1337
|
+
**Shape — lean, or it rots.** Prefer moving text to adding it, and delete the copy
|
|
1338
|
+
you superseded; a duplicated rule becomes a contradiction. Exit conditions go in a
|
|
1339
|
+
section's first paragraph, never its last. Name the mechanism, or name who owns
|
|
1340
|
+
the step. Cut before you append.
|
|
1341
|
+
|
|
1342
|
+
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.
|
|
1343
|
+
|
|
1344
|
+
Read why that body carries the claim discipline, and its literal-path and `grep -F` settling rules, before you edit them. See references/correction-tickets.md.
|
|
1345
|
+
|
|
1346
|
+
**Then.** **Re-pin first** — `~/.fleet/bin/fleet-run instruments.sh
|
|
1347
|
+
--pin`. See references/instruments.md. Then the ledger line, save the
|
|
1348
|
+
rationale, one line to the maintainer. **Then land it from the main checkout,
|
|
1349
|
+
if the fix was edited in it** — until you do, the next tick reads
|
|
1350
|
+
`MAIN-CHECKOUT-DIRTY` naming your own paths. Commit the fix on a branch and
|
|
1351
|
+
switch back to `main` before the next tick, and never `--record` while on that
|
|
1352
|
+
branch: the switch back restores the tree the baseline recorded, so the hold
|
|
1353
|
+
clears itself with nothing re-recorded, and the fix leaves the checkout until
|
|
1354
|
+
its PR merges. A `HEAD …` entry is none of your paths and clears the same way.
|
|
1355
|
+
Re-baseline only a fix you leave edited in the checkout: run
|
|
1356
|
+
`~/.fleet/bin/fleet-run main-checkout.mjs --check` first, and only when the
|
|
1357
|
+
paths it names are exactly the ones you just edited, run `--record` — never
|
|
1358
|
+
before the commit, because the switch back would then read your own paths
|
|
1359
|
+
dirty again. Any other path on that line is a stray write — leave the hold for
|
|
1360
|
+
the maintainer, because `--record` would certify it with yours. Live members
|
|
1361
|
+
hold the old text — re-brief only if it changes what they do *now*.
|
|
1362
|
+
|
|
1363
|
+
Plan it as a PR the run's own merge queue lands, never as an edit-and-continue. See references/merge-bot.md.
|
|
1364
|
+
|
|
1476
1365
|
## Red flags
|
|
1477
1366
|
|
|
1478
1367
|
Stop when a thought of yours matches one of these, and act on the line it carries instead.
|
|
@@ -64,6 +64,12 @@ under `Verified:` its zero reads as a checked absence.
|
|
|
64
64
|
|
|
65
65
|
## The settling command for "which files read X" is never a literal-path grep
|
|
66
66
|
|
|
67
|
+
**The settling command for "which files read X" must never be a literal-path
|
|
68
|
+
grep.** Replace the file with `MUTATED` in a throwaway copy, run the suite, and read off
|
|
69
|
+
which suites red: that answers which ones **depend on its contents**, which is
|
|
70
|
+
the question a coverage claim actually needs, and it returns a different set
|
|
71
|
+
from any spelling of the grep.
|
|
72
|
+
|
|
67
73
|
The path is assembled in more than one spelling here, one of them behind
|
|
68
74
|
a local `read` helper, so a grep for the path string answers with the files that
|
|
69
75
|
merely *name* it — comments included — and misses the files that build it.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Instruments: why they are re-checked
|
|
2
2
|
|
|
3
|
-
Evidence for the rule SKILL.md states in **
|
|
3
|
+
Evidence for the rule SKILL.md states in **Re-check the instruments before a gate**, keyed by the rule it justifies.
|
|
4
4
|
|
|
5
5
|
## Re-check your instruments before every gate decision
|
|
6
6
|
|
|
@@ -17,3 +17,28 @@ direction — a modified instrument raises no error, shows in no PR and leaves
|
|
|
17
17
|
nothing in the ledger, and it still returns a verdict, just not necessarily the
|
|
18
18
|
right one, so you have no reason to re-check a script you did not know had
|
|
19
19
|
changed.
|
|
20
|
+
|
|
21
|
+
**A label gate and a CI verdict are also taken by dispatched members, not
|
|
22
|
+
only by you** — the finisher labels, and the merge bot merges on its own
|
|
23
|
+
reading — and neither is dispatched to read SKILL.md, so neither can be
|
|
24
|
+
reached by stating the rule there. Each carries its own copy: the finisher's
|
|
25
|
+
in the instrument re-check block of `agents/fleet-finisher.agent.md`, the merge bot's inside
|
|
26
|
+
`merge-gate.mjs`, step 3 of `run-merge-bot.md`.
|
|
27
|
+
|
|
28
|
+
## What the instrument set covers
|
|
29
|
+
|
|
30
|
+
It covers every tracked file under this repo's own plugin component directories
|
|
31
|
+
— `plugin/commands/`, `plugin/scripts/`, `plugin/skills/`, `plugin/agents/`,
|
|
32
|
+
`plugin/workflows/` — the probes, the libraries they source, and these runbooks,
|
|
33
|
+
which you also read from that tree. Not the whole repo: `docs/metrics/` is
|
|
34
|
+
appended by THIS run, so covering it would refuse on the run's own bookkeeping
|
|
35
|
+
every time. It does not cover refs, deliberately: `claim-ticket.sh` creates a
|
|
36
|
+
branch per ticket and `reap.sh` deletes them in the ref store every worktree
|
|
37
|
+
shares, so ordinary work moves refs several times a run and a per-gate
|
|
38
|
+
refusal on that is noise.
|
|
39
|
+
|
|
40
|
+
## Re-pin first after a mid-run tooling fix
|
|
41
|
+
|
|
42
|
+
You just changed the instrument set under your own check, and this is the
|
|
43
|
+
only edit that legitimately does; skip it and the next gate refuses on your own
|
|
44
|
+
fix, which teaches you to ignore the refusal.
|
|
@@ -120,6 +120,13 @@ One flat namespace, generic filenames (`b.min.js`, `probe.mjs`) — one agent ov
|
|
|
120
120
|
|
|
121
121
|
The axis is two-sided: the member partitions, and the parent assigns each child's path. `<scratch>` itself is assigned, never invented: the controller resolves it with `scratch-root.mjs` and writes the absolute path into each member's prompt. A member owns one directory — `<scratch>/impl-<N>/` for an implementer, `<scratch>/pr<N>/…` on the review side — and every agent it dispatches gets a directory under that one, unique to that child and never shared, written into the child's prompt as an absolute path; a child never derives its own. The review side is already laid out this way: `review-core.mjs` makes the run root `<scratch>/pr<N>/run-XXXXXXXX/` with `mktemp` — it appends `pr<N>/` to the scratch root it is handed and refuses a scratch already ending in one, so a review runner is given the root, never `<scratch>/pr<N>` — then writes `<run>/<dim>/` into each specialist's prompt and `<run>/verify-<dim>/f<i>-l<j>/` into each refuter's. A fix-applier makes its own run root the same way — `<scratch>/pr<N>/fix-XXXXXXXX/` with `mktemp` — then resolves `<run>/<finding>/` to an absolute path for the refuter it dispatches on a suggestion; the bare `<scratch>/pr<N>/<finding>/` is not that path, since finding ids restart at 1 each fix-applier round too, and a later round on the same PR would reach for the same directory a prior round's refuter left fixtures in. An implementer's child gets `<scratch>/impl-<N>/<childName>/`, named after its dispatch name. Refuters are grandchildren, not members, which is why the member partition alone is not the rule: the agents that actually collided were ones no member rule reaches, and a parent-assigned path is what reaches them. Read from the object store at a pinned ref, write only under own path.
|
|
122
122
|
|
|
123
|
+
## The scratch root is computed, never invented and never recorded
|
|
124
|
+
|
|
125
|
+
No harness supplies a scratch directory to a member, so a member left to name its own
|
|
126
|
+
invents one — and the liveness read in **The tick's rows**, which looks at the files under the
|
|
127
|
+
directory a member's own prompt assigned it, then watches a directory nobody
|
|
128
|
+
else can find.
|
|
129
|
+
|
|
123
130
|
## IDE/harness diagnostics attribute by bare filename, with no path
|
|
124
131
|
|
|
125
132
|
Probe copies carry same filenames as real tree, so specialist's throwaway mutation surfaces as errors that read exactly like live worktree's — and line numbers can plausibly line up with real in-flight edits. Never relay diagnostic without reproducing it in that member's specific worktree (re-run the check that raised it — the typechecker, the linter — from there). Ran twice in one session: clean first time (sibling's probe), genuinely broken second. Telling implementer to chase phantom in file it is mid-rewrite on is expensive failure.
|
|
@@ -129,6 +136,15 @@ Probe copies carry same filenames as real tree, so specialist's throwaway mutati
|
|
|
129
136
|
Measured 2026-09-09 in a throwaway clone (`/tmp/fleet-probe`)
|
|
130
137
|
that never touched the real checkout.
|
|
131
138
|
|
|
139
|
+
## Claim, release and reap are unchanged on omp
|
|
140
|
+
|
|
141
|
+
**Claim, release and reap are unchanged on omp.** `claim-ticket.sh`,
|
|
142
|
+
`release-ticket.sh`, `reap.sh` and `inflight.sh` are git-native and operate on
|
|
143
|
+
the single shared ref store every worktree and the main checkout read and
|
|
144
|
+
write directly (**Phase 1**, the tick's reap, and `release-ticket.sh` under
|
|
145
|
+
**Failure handling**); nothing in omp's `task` model touches that
|
|
146
|
+
store, so none of the four scripts carries a dialect branch.
|
|
147
|
+
|
|
132
148
|
## A fleet member is never dispatched with omp's `isolated: true`
|
|
133
149
|
|
|
134
150
|
**A fleet member is never dispatched with omp's `isolated: true`.** Measured:
|
|
@@ -220,6 +236,12 @@ the worktree, `git worktree list` and `git branch --list` from the main
|
|
|
220
236
|
checkout reported the claim unchanged before, during and after — `inflight.sh`
|
|
221
237
|
hides nothing from omp.
|
|
222
238
|
|
|
239
|
+
## The controller's own cwd stays the main checkout
|
|
240
|
+
|
|
241
|
+
Nothing in the dispatch recipe above — the cwd recipe, the
|
|
242
|
+
isolated-workspace measurement, or the teardown scoping — moves
|
|
243
|
+
where the controller itself runs from.
|
|
244
|
+
|
|
223
245
|
## A pattern kill reaches siblings
|
|
224
246
|
|
|
225
247
|
**A pattern kill reaches siblings — the implementer, fix-applier and finisher briefs forbid it.** `pkill -f
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Member lifecycle: naming, fresh context, recovery
|
|
2
2
|
|
|
3
|
-
Why member name load-bearing, why every member single-use, how a member's job outcome (`completed`/`failed`/`cancelled`) and peer liveness (`running`/`idle`/`parked`) decide its recovery. Assertions these justify live in SKILL.md's
|
|
3
|
+
Why member name load-bearing, why every member single-use, how a member's job outcome (`completed`/`failed`/`cancelled`) and peer liveness (`running`/`idle`/`parked`) decide its recovery. Assertions these justify live in SKILL.md's wake table, Dispatching the members a wake names, Reading a review result, A member's claims, Failure handling sections; evidence here.
|
|
4
4
|
|
|
5
5
|
## Every member is named
|
|
6
6
|
|
|
@@ -58,6 +58,28 @@ Reviewers go idle waiting on CI, won't resume alone — rebased, pushed, stopped
|
|
|
58
58
|
|
|
59
59
|
Liveness says nothing: `idle` means "not currently executing", not "done"; finished member's finding may never arrive. In one run every member that looked dead had its work in git or on PR — pushed commits, self-removed label, applied ruling. Read `gh pr view`, `gh run view`, `git -C <worktree> status` before messaging: one command settles what round-trip usually doesn't, and member that ignored one ping tends to ignore second. When you message, send specific next action, never "what is your status".
|
|
60
60
|
|
|
61
|
+
## A report is delivered, not implied by ending a turn
|
|
62
|
+
|
|
63
|
+
**A report is delivered, not implied by ending a turn.** Every member owes
|
|
64
|
+
the controller one report naming its outcome before it exits — including a
|
|
65
|
+
member whose prompt carries no explicit report line. A member that does the work
|
|
66
|
+
correctly and ends its turn has reported nothing: the controller learns the
|
|
67
|
+
outcome only by re-reading artifacts and pinging, and a finding held only in
|
|
68
|
+
that member's context is lost. Members did exactly this in one run —
|
|
69
|
+
finishers, a reviewer and merge bots alike, the work done and only the
|
|
70
|
+
delivery missing. Every brief's report paragraph says it.
|
|
71
|
+
|
|
72
|
+
## You never write the do-not-acknowledge line yourself
|
|
73
|
+
|
|
74
|
+
**The implementer, fix-applier, finisher, merge-bot and review-runner briefs
|
|
75
|
+
each tell the member you do not acknowledge reports; you never write that line
|
|
76
|
+
yourself.** A member cannot see whether its report arrived, so silence
|
|
77
|
+
from you is indistinguishable from loss and it re-sends — three members did in
|
|
78
|
+
one run, each burning a turn, and in all three the original had in fact arrived.
|
|
79
|
+
Each of those templates under `briefs/` carries the line: *"The controller does
|
|
80
|
+
not acknowledge reports. Send once and exit; never re-send unless the controller
|
|
81
|
+
asks by name."*
|
|
82
|
+
|
|
61
83
|
## A missing report is not evidence the member failed to send one
|
|
62
84
|
|
|
63
85
|
**But a missing report is NOT evidence the member failed to send one — the
|
|
@@ -84,6 +106,15 @@ Note this cuts against the paragraph above only in appearance: the default stays
|
|
|
84
106
|
*send once*, because unprompted re-sends were measured 2-to-1 false. The ask is
|
|
85
107
|
the controller's move, not the member's.
|
|
86
108
|
|
|
109
|
+
## Never read a member's silence as assent
|
|
110
|
+
|
|
111
|
+
**Your OWN messages can vanish the same way, and that half is not recoverable by
|
|
112
|
+
a re-send.** Two controller rulings were lost in one run, both with a
|
|
113
|
+
`success: true` receipt: a member proceeded on its stated default and filed a
|
|
114
|
+
tracker issue the lost ruling had said not to file. The confirmation-state
|
|
115
|
+
sentence SKILL.md's **A member's claims** requires is the only thing that made
|
|
116
|
+
either loss visible.
|
|
117
|
+
|
|
87
118
|
## A member runs its test suite in the foreground and blocks on it
|
|
88
119
|
|
|
89
120
|
**A member runs its test suite in the foreground and blocks on it.**
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Landing a change on main
|
|
2
2
|
|
|
3
|
-
Evidence for the rules SKILL.md states in **
|
|
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
5
|
## A mid-run tooling fix lands through a PR
|
|
6
6
|
|
|
@@ -517,6 +517,19 @@ mention of the controller is not a statement that the reader is one of its
|
|
|
517
517
|
members. That skill keeps its condition, so a solo session still runs the
|
|
518
518
|
interactive path; this block is what puts a member on the fleet side of it.
|
|
519
519
|
|
|
520
|
+
**Prose-first** and **wrongly-REFUSE** are not padding — they are the case
|
|
521
|
+
which shipped with **enumerate-and-declare** already in its prompt. It missed a
|
|
522
|
+
shape its own ticket named in passing, because it enumerated from the mechanism
|
|
523
|
+
instead of the text; and it introduced a regression refusing every `node --test`
|
|
524
|
+
flag, because it enumerated what the guard should catch and never what it could
|
|
525
|
+
wrongly refuse.
|
|
526
|
+
|
|
527
|
+
The commit-incrementally block is not optional. A member that goes idle mid-task
|
|
528
|
+
leaves its diff only in the worktree, and the controller cannot reap, replace,
|
|
529
|
+
or even see it — `worktree-audit.sh`'s committed-vs-uncommitted split is exactly
|
|
530
|
+
what decides whether a replacement redoes or destroys work. Observed twice in
|
|
531
|
+
one run.
|
|
532
|
+
|
|
520
533
|
## Default: In-flight bound 5
|
|
521
534
|
|
|
522
535
|
**Default: In-flight bound 5, fixed for the run.** The level is set by load, not
|
|
@@ -147,8 +147,8 @@ The full text of each row `fleet-tick.mjs` prints and what it asks of the contro
|
|
|
147
147
|
HEAD is off the run's branch. Never revert the
|
|
148
148
|
paths yourself, and never re-baseline over paths nobody has resolved. The
|
|
149
149
|
changes of yours that trip it are a mid-run tooling fix edited in this
|
|
150
|
-
checkout and the close-out commit's round trip through a branch;
|
|
151
|
-
|
|
150
|
+
checkout and the close-out commit's round trip through a branch; SKILL.md's
|
|
151
|
+
**A mid-run tooling fix** and the commit section of references/close-out.md say how
|
|
152
152
|
each is cleared.
|
|
153
153
|
The maintainer may instead ignore a stray path that is untracked and new since the baseline: an entry in `.git/info/exclude` or in the global excludes file hides it from the check, and the hold clears on the next tick with no re-baseline. Ignoring never clears a tracked or staged file's change, which `git status` reports whatever the excludes say, nor a pattern that also matches a path the baseline holds, which then reads as changed. Ignoring is the maintainer's decision; the controller never writes an exclude or a `.gitignore` entry. Keep the pattern narrow, because an ignored path is invisible to this check, so a member write that matches it is never seen.
|
|
154
154
|
- `MAIN-CHECKOUT-UNKNOWN …` with `HOLD (main checkout unknown)` — the tick
|