@feigi/fleet-ctl 3.76.6 → 3.76.8

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.
@@ -53,7 +53,23 @@ tree — so an exit 2 naming a moved or unreadable audited tree is a halt
53
53
  like every other, not a spelling for you to correct.
54
54
 
55
55
  **Confirm every deferral — and every claimed APPLY — has a home that outlives
56
- the merge.** The test is a durable home, not a tracker number: a tracker
56
+ the merge.** A deferral of a finding in the review's result is not yours to
57
+ re-judge when the PR's latest review counted a survived or unverified finding:
58
+ `ledger.mjs dispatch` then dispatched you only once the PR's ledger row held a
59
+ `dispositions-ok` verdict from `dispositions-check.mjs` on that review
60
+ (`dispositionsRefusal`), and that check had already read back where the
61
+ fix-applier's disposition record says each deferral was filed. That verdict is
62
+ the judgement of those homes: do not halt on a home the script accepted, and
63
+ do not re-file one as an open issue. One such home is the PR's own
64
+ `PR #<M> review: the suggestion band, checked` issue, which counts although it
65
+ is closed and labelled `wontfix`. Where the latest review counted no survived
66
+ and no unverified finding, dispatch required no verdict; that record is still
67
+ a home there when it matches the script's own definition — `homeHolds` in
68
+ `dispositions-check.mjs`: state `CLOSED`, labelled `wontfix`, titled exactly
69
+ `recordTitle(<M>)` — and any other closed issue is not. Everything else — a
70
+ claimed APPLY, a deferral the review's result does not carry, and a deferral
71
+ no verdict judged — you judge by hand, by the test below. The test is a
72
+ durable home, not a tracker number: a tracker
57
73
  issue and a committed in-tree comment both qualify, and for a finding whose
58
74
  remedy was measured worse than the defect the in-tree note is the better one.
59
75
  What fails is a promise living only in a PR body, or on the PR's *own* source
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@feigi/fleet-ctl",
3
- "version": "3.76.6",
3
+ "version": "3.76.8",
4
4
  "description": "Agent fleet: run-team controller, merge bot, PR reviewer, and the ticket pipeline they share",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {
@@ -22,8 +22,10 @@
22
22
  // readers — a member with no assistant turn yet still resolves off its
23
23
  // dispatch-time `session_init` record, never treated as absent). An
24
24
  // entry that names neither a `session` nor a `transcript` takes the
25
- // `session` the phase-0 receipt `.fleet/phase0.json` records, and is
26
- // exit 2 naming the receipt when it records none. That session is taken
25
+ // `session` the phase-0 receipt `.fleet/phase0.json` records — the one
26
+ // in the workspace holding `--ledger`, or the cwd's when `--ledger` is
27
+ // omitted, resolved the same way the default ledger is — and is exit 2
28
+ // naming the receipt when it records none. That session is taken
27
29
  // as the receipt stands: whether the receipt is this run's is judged by
28
30
  // fleet-tick.mjs's phase-0 gate, not here, and a message about it names
29
31
  // the receipt's session where it would name `--session`.
@@ -77,14 +79,16 @@
77
79
  // LIVE member may yet write one; a member settled `PR#M`, `bailed`, `blocked`
78
80
  // or `tier-mismatch` ran, so its transcript exists and the `session` is the
79
81
  // wrong directory; a `session` that is empty, missing or not a directory,
80
- // or omitted with none in the phase-0 receipt, is exit 2 whether the member
81
- // is live or settled; and a session
82
+ // or omitted with none in the phase-0 receipt — a `--ledger` outside any
83
+ // repository or in a directory that does not exist among them, since no
84
+ // workspace holds it and so there is no receipt to read — is exit 2 whether
85
+ // the member is live or settled; and a session
82
86
  // directory that cannot be searched (EACCES) is exit 2 naming the errno,
83
87
  // never read as holding no transcript.
84
88
 
85
89
  import { readFileSync, existsSync, statSync } from "node:fs";
86
90
  import { execFileSync } from "node:child_process";
87
- import { join, dirname, isAbsolute } from "node:path";
91
+ import { join, dirname, isAbsolute, resolve } from "node:path";
88
92
  import { fileURLToPath } from "node:url";
89
93
  import { isCLI } from "./is-cli.mjs";
90
94
  import { makeDie, defineFlags } from "./arg.mjs";
@@ -328,6 +332,19 @@ function sessionLacksTranscript(repoRoot, sessionPath, member) {
328
332
  // tier can still be judged.
329
333
  const NO_TRANSCRIPT_OUTCOMES = new Set(["killed", "released"]);
330
334
 
335
+ // Where the phase-0 receipt is read from: the workspace the ledger in use
336
+ // belongs to, so a `--ledger` naming another workspace's judges that
337
+ // workspace's transcripts, not the cwd's. `--ledger` takes any path, not
338
+ // always one under a `.fleet/` — so the workspace is the one git names for
339
+ // the ledger's directory, the same answer ledger.mjs's own default gives
340
+ // from the cwd. A ledger under no repository, or in a directory that does not
341
+ // exist, has no workspace and so no receipt: sessionFromReceipt refuses
342
+ // naming why, and the whole batch is exit 2 with nothing written. Omitted,
343
+ // the cwd's.
344
+ function receiptOpts(ledgerFile) {
345
+ return ledgerFile ? { cwd: dirname(resolve(ledgerFile)) } : undefined;
346
+ }
347
+
331
348
  function runLedger(ledgerFile, args, what) {
332
349
  try {
333
350
  return execFileSync(process.execPath, [LEDGER_SCRIPT, ...(ledgerFile ? ["--file", ledgerFile] : []), ...args], { encoding: "utf8" });
@@ -480,7 +497,7 @@ function main() {
480
497
  // session directory the phase-0 receipt records — read once per
481
498
  // batch — and refuses naming the receipt when it records none. A
482
499
  // given one always wins.
483
- const session = raw.session ?? (raw.transcript ? undefined : (receiptSession ??= sessionFromReceipt()));
500
+ const session = raw.session ?? (raw.transcript ? undefined : (receiptSession ??= sessionFromReceipt(receiptOpts(ledgerFile))));
484
501
  // Said as the caller's flag only when the caller gave it.
485
502
  const where = raw.session ? `--session ${session}` : `the phase-0 receipt's session ${session}`;
486
503
  if (session) {
@@ -740,10 +740,11 @@ dispatched under.
740
740
  Pull, a batch of one, the member just dispatched: `{member}`.
741
741
  `member` is the AgentId the dispatch returns (`impl-<N>`). An entry that
742
742
  names neither `session` nor `transcript` takes the session directory phase
743
- 0's receipt `.fleet/phase0.json` records, and is exit 2 naming the receipt
744
- when it records none; the check reads the member's own
745
- `<session>/<member>.jsonl` directly, so a member with no assistant turn yet
746
- still resolves off its dispatch-time record. A `session` the entry gives
743
+ 0's receipt `.fleet/phase0.json` of `--ledger`'s workspace (else the cwd's,
744
+ resolved as the default ledger is) records, and is exit 2 naming the receipt
745
+ when it records none; the check reads `<session>/<member>.jsonl`, so a
746
+ member with no assistant turn yet still resolves off its dispatch-time
747
+ record. A `session` the entry gives
747
748
  wins over the receipt's; a caller already holding the exact transcript path
748
749
  may give `transcript` instead. The agent type an implementer was dispatched
749
750
  as lives only in its transcript. `resolvedModel`
@@ -18,7 +18,23 @@ What does not empty it is noticing the question and dispatching anyway.
18
18
  ## Duty 2: every deferral, and every claimed APPLY, has a home that outlives the merge
19
19
 
20
20
  **Confirm every deferral — and every claimed APPLY — has a home that outlives
21
- the merge.** The test is a durable home, not a tracker number: a tracker
21
+ the merge.** A deferral of a finding in the review's result is not yours to
22
+ re-judge when the PR's latest review counted a survived or unverified finding:
23
+ `ledger.mjs dispatch` then dispatched you only once the PR's ledger row held a
24
+ `dispositions-ok` verdict from `dispositions-check.mjs` on that review
25
+ (`dispositionsRefusal`), and that check had already read back where the
26
+ fix-applier's disposition record says each deferral was filed. That verdict is
27
+ the judgement of those homes: do not halt on a home the script accepted, and
28
+ do not re-file one as an open issue. One such home is the PR's own
29
+ `PR #<M> review: the suggestion band, checked` issue, which counts although it
30
+ is closed and labelled `wontfix`. Where the latest review counted no survived
31
+ and no unverified finding, dispatch required no verdict; that record is still
32
+ a home there when it matches the script's own definition — `homeHolds` in
33
+ `dispositions-check.mjs`: state `CLOSED`, labelled `wontfix`, titled exactly
34
+ `recordTitle(<M>)` — and any other closed issue is not. Everything else — a
35
+ claimed APPLY, a deferral the review's result does not carry, and a deferral
36
+ no verdict judged — you judge by hand, by the test below. The test is a
37
+ durable home, not a tracker number: a tracker
22
38
  issue and a committed in-tree comment both qualify, and for a finding whose
23
39
  remedy was measured worse than the defect the in-tree note is the better one.
24
40
  What fails is a promise living only in a PR body, or on the PR's *own* source