@groundnuty/macf-core 0.2.57 → 0.2.59
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/dist/fleet-driver.d.ts +39 -8
- package/dist/fleet-driver.d.ts.map +1 -1
- package/dist/fleet-driver.js.map +1 -1
- package/dist/fleet-upgrade.d.ts +127 -21
- package/dist/fleet-upgrade.d.ts.map +1 -1
- package/dist/fleet-upgrade.js +124 -14
- package/dist/fleet-upgrade.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/prompt-responses.d.ts +57 -5
- package/dist/prompt-responses.d.ts.map +1 -1
- package/dist/prompt-responses.js +64 -5
- package/dist/prompt-responses.js.map +1 -1
- package/dist/proxy-fetch.d.ts +89 -0
- package/dist/proxy-fetch.d.ts.map +1 -0
- package/dist/proxy-fetch.js +186 -0
- package/dist/proxy-fetch.js.map +1 -0
- package/dist/registry/github-client.d.ts.map +1 -1
- package/dist/registry/github-client.js +26 -3
- package/dist/registry/github-client.js.map +1 -1
- package/dist/registry/local-client.d.ts +1 -0
- package/dist/registry/local-client.d.ts.map +1 -1
- package/dist/registry/types.d.ts +10 -0
- package/dist/registry/types.d.ts.map +1 -1
- package/dist/registry/types.js +29 -0
- package/dist/registry/types.js.map +1 -1
- package/dist/verify-green.d.ts +19 -0
- package/dist/verify-green.d.ts.map +1 -1
- package/dist/verify-green.js +15 -0
- package/dist/verify-green.js.map +1 -1
- package/package.json +2 -1
package/dist/fleet-driver.d.ts
CHANGED
|
@@ -107,12 +107,18 @@ export interface FleetDriver {
|
|
|
107
107
|
* `.claude/.macf/env.*` + `host-prelude.sh`, `CLAUDE.md`, `env.local.*` —
|
|
108
108
|
* see `ROLL_TOUCHED_CONFIG_PATTERNS` in `fleet-upgrade.ts`, narrowed off a
|
|
109
109
|
* `.claude/**` wildcard by DR-040 Decision 6 / macf#698). VM: `git status`
|
|
110
|
-
* in the agent's workspace, filtered to that path set.
|
|
111
|
-
*
|
|
112
|
-
*
|
|
113
|
-
*
|
|
114
|
-
*
|
|
115
|
-
*
|
|
110
|
+
* in the agent's workspace, filtered to that path set. Kept as a boolean
|
|
111
|
+
* convenience alongside `listDirtyConfig` below — `rollFleet`'s pre-flight
|
|
112
|
+
* gate itself calls `classifyDirtyConfig` (it needs the tiered file list
|
|
113
|
+
* to OBJECT with, macf#725/macf#1101), so this predicate form is for OTHER
|
|
114
|
+
* callers that only need the yes/no answer.
|
|
115
|
+
*
|
|
116
|
+
* `true` when the workspace itself couldn't be resolved OR inspected at
|
|
117
|
+
* all (macf#1101) — DISTINCT from `isBusy`'s "DEAD/absent agent is not
|
|
118
|
+
* busy": that predicate concerns SESSION liveness on an agent whose
|
|
119
|
+
* workspace resolved fine; this one concerns whether the workspace could
|
|
120
|
+
* be found/read in the first place. "Couldn't verify" must never read as
|
|
121
|
+
* "verified clean" — the false-pass hazard this issue codifies.
|
|
116
122
|
*/
|
|
117
123
|
readonly isConfigDirty: (agent: string) => Promise<boolean>;
|
|
118
124
|
/**
|
|
@@ -122,7 +128,9 @@ export interface FleetDriver {
|
|
|
122
128
|
* uncommitted paths rather than a boolean. Empty array == clean
|
|
123
129
|
* (equivalent to `isConfigDirty` reading `false`). VM: `git status
|
|
124
130
|
* --porcelain` in the agent's workspace, filtered to that path set, one
|
|
125
|
-
* path per line.
|
|
131
|
+
* path per line. An unresolvable/unreadable workspace (macf#1101) returns
|
|
132
|
+
* a single diagnostic SENTINEL entry (never a real path), not an empty
|
|
133
|
+
* array — see `isConfigDirty`'s doc for why.
|
|
126
134
|
*
|
|
127
135
|
* **Superseded as `rollFleet`'s pre-flight call site by `classifyDirtyConfig`
|
|
128
136
|
* below (DR-040 Decision 3 / macf#698 R1)** — the roll no longer treats
|
|
@@ -152,7 +160,12 @@ export interface FleetDriver {
|
|
|
152
160
|
* Both arrays are empty when the agent has no dirty config surface at all
|
|
153
161
|
* (mirrors `listDirtyConfig`'s empty-array-== -clean contract). VM: reuses
|
|
154
162
|
* `listDirtyConfig` for the raw list, then classifies each path via
|
|
155
|
-
* `classifyDirtyFile`.
|
|
163
|
+
* `classifyDirtyFile`. An unresolvable agent (macf#1101 — no workspace
|
|
164
|
+
* matches this routing label under the driver's bound project) yields a
|
|
165
|
+
* NON-EMPTY `genuineDelta` (a diagnostic sentinel) — this is the gate
|
|
166
|
+
* `rollFleet` actually calls, so its fail-safe direction is load-bearing:
|
|
167
|
+
* an unresolvable agent must OBJECT, never silently read as "nothing
|
|
168
|
+
* dirty."
|
|
156
169
|
*/
|
|
157
170
|
readonly classifyDirtyConfig: (agent: string) => Promise<{
|
|
158
171
|
readonly alreadyCanonical: readonly string[];
|
|
@@ -190,6 +203,24 @@ export interface FleetDriver {
|
|
|
190
203
|
* throws.
|
|
191
204
|
*/
|
|
192
205
|
readonly canonicalBranch: (agent: string) => Promise<string>;
|
|
206
|
+
/**
|
|
207
|
+
* Diagnostic-only: a driver-specific description of WHERE `agent` was
|
|
208
|
+
* inspected — VM: the resolved absolute workspace directory; a future K8s
|
|
209
|
+
* driver: pod/namespace. `null` when `agent` could not be resolved at all
|
|
210
|
+
* (unknown agent, or — VM specifically — no workspace matches BOTH the
|
|
211
|
+
* agent's routing label AND this driver's own bound project; see
|
|
212
|
+
* `vm-driver.ts`'s `resolveTarget`). NEVER used for decision-branching
|
|
213
|
+
* (that stays on `currentBranch`/`classifyDirtyConfig`/etc. — the DR-037
|
|
214
|
+
* hard rule that nothing runtime-specific leaks above the driver line is
|
|
215
|
+
* about DECISIONS, not diagnostics) — its ONLY consumer is `rollFleet`'s
|
|
216
|
+
* pre-flight OBJECT messages (macf#1101), so an operator reading a
|
|
217
|
+
* branch/config-dirty objection can see EXACTLY which on-disk location
|
|
218
|
+
* produced it and catch a misattribution instead of trusting the agent
|
|
219
|
+
* name alone. Optional: a driver that has no meaningful "where" (or
|
|
220
|
+
* predates this field) simply omits it — callers treat the omission the
|
|
221
|
+
* same as `null`.
|
|
222
|
+
*/
|
|
223
|
+
readonly resolveWorkspace?: (agent: string) => Promise<string | null>;
|
|
193
224
|
/**
|
|
194
225
|
* Read the agent's current pane content for stall-signature matching
|
|
195
226
|
* (`macf fleet resume`, DR-037 / macf#686). VM: a single `tmux capture-pane`
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fleet-driver.d.ts","sourceRoot":"","sources":["../src/fleet-driver.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACxC,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AACtD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAEjD;;;;;GAKG;AACH,MAAM,WAAW,eAAe;IAC9B,gDAAgD;IAChD,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,gCAAgC;IAChC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,gCAAgC;IAChC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,oEAAoE;IACpE,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;IACzB;;;;OAIG;IACH,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,wFAAwF;IACxF,QAAQ,CAAC,MAAM,EAAE,cAAc,GAAG,IAAI,CAAC;CACxC;AAED;;;;;;GAMG;AACH,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,MAAM,EAAE,SAAS,eAAe,EAAE,CAAC;CAC7C;AAED;;;;;;;;;;GAUG;AACH,MAAM,WAAW,WAAW;IAC1B;;;;OAIG;IACH,QAAQ,CAAC,KAAK,EAAE,MAAM,OAAO,CAAC,UAAU,CAAC,CAAC;IAE1C;;;;;OAKG;IACH,QAAQ,CAAC,kBAAkB,EAAE,MAAM,SAAS,eAAe,EAAE,CAAC;IAE9D;;;;;;OAMG;IACH,QAAQ,CAAC,MAAM,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IAErD
|
|
1
|
+
{"version":3,"file":"fleet-driver.d.ts","sourceRoot":"","sources":["../src/fleet-driver.ts"],"names":[],"mappings":"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"}
|
package/dist/fleet-driver.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fleet-driver.js","sourceRoot":"","sources":["../src/fleet-driver.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"fleet-driver.js","sourceRoot":"","sources":["../src/fleet-driver.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAuUxC;;;;;GAKG;AACH,MAAM,OAAO,gBAAiB,SAAQ,SAAS;IAC7C,YAAY,OAAe;QACzB,KAAK,CAAC,oBAAoB,EAAE,OAAO,CAAC,CAAC;QACrC,IAAI,CAAC,IAAI,GAAG,kBAAkB,CAAC;IACjC,CAAC;CACF"}
|
package/dist/fleet-upgrade.d.ts
CHANGED
|
@@ -23,6 +23,16 @@ export interface AgentUpgradePlan {
|
|
|
23
23
|
readonly fleet: string;
|
|
24
24
|
/** The agent's live self-reported `/health.version`, or `null` when offline/version-less. */
|
|
25
25
|
readonly runningVersion: string | null;
|
|
26
|
+
/**
|
|
27
|
+
* The agent's live self-reported `/health.instance_id` (DR-030 phase-1 mesh
|
|
28
|
+
* self-report; DR-037 Decision 5 mints a NEW one on every relaunch), or
|
|
29
|
+
* `null` when offline or reporting a body that predates the field. Captured
|
|
30
|
+
* at PLAN time so `classifyHalt` can later tell "the SAME process is still
|
|
31
|
+
* answering /health after the restart" (an honest not-yet-serving unknown)
|
|
32
|
+
* apart from "a genuinely NEW process is serving the wrong version" (a
|
|
33
|
+
* confirmed bad release) — see `classifyHalt`'s doc.
|
|
34
|
+
*/
|
|
35
|
+
readonly runningInstanceId: string | null;
|
|
26
36
|
/** The workspace's on-disk version pin (legible even when the agent is dead). */
|
|
27
37
|
readonly pinnedVersion: string | null;
|
|
28
38
|
/** The version-only disposition (see `UpgradeDisposition`). */
|
|
@@ -56,6 +66,18 @@ export interface AgentUpgradePlan {
|
|
|
56
66
|
* ran) but its stale-old-pin state endangers no
|
|
57
67
|
* OTHER agent, so `rollFleet` skips it and moves
|
|
58
68
|
* on to the next agent in the SAME fleet.
|
|
69
|
+
* - `not-yet-serving-skipped` — (NEW, follow-up to macf#899) verify-green
|
|
70
|
+
* confirmed the agent REACHABLE at its OLD
|
|
71
|
+
* version, but the responder is PROVEN to be the
|
|
72
|
+
* SAME pre-restart process instance (not a fresh
|
|
73
|
+
* one) — `reason: 'not-yet-serving'` (see
|
|
74
|
+
* `HaltReason`). The agent's own relaunch simply
|
|
75
|
+
* hasn't taken over serving yet (a common cause
|
|
76
|
+
* is an unanswered interactive launch prompt);
|
|
77
|
+
* this is an honest UNKNOWN, not a confirmed bad
|
|
78
|
+
* release, and — like `stale-pin-skipped` —
|
|
79
|
+
* endangers no OTHER agent, so `rollFleet` skips
|
|
80
|
+
* it and continues.
|
|
59
81
|
* - `halted` — verify-green did NOT confirm the target version,
|
|
60
82
|
* and the cause is either a confirmed/unverifiable
|
|
61
83
|
* bad release or a genuinely unconfirmed relaunch;
|
|
@@ -64,21 +86,25 @@ export interface AgentUpgradePlan {
|
|
|
64
86
|
*
|
|
65
87
|
* The three pre-flight skip outcomes (`busy-skipped` / `config-dirty-skipped`
|
|
66
88
|
* / `branch-skipped`) are safe to continue past because the agent was NEVER
|
|
67
|
-
* mutated. `stale-pin-skipped` (macf#899)
|
|
68
|
-
*
|
|
69
|
-
*
|
|
70
|
-
*
|
|
71
|
-
*
|
|
72
|
-
*
|
|
73
|
-
*
|
|
74
|
-
*
|
|
89
|
+
* mutated. `stale-pin-skipped` (macf#899) and `not-yet-serving-skipped` ARE
|
|
90
|
+
* safe to continue past DESPITE the agent having been mutated, because each
|
|
91
|
+
* specific cause (a stale LAUNCH pin; a not-yet-superseded pre-restart
|
|
92
|
+
* process) is a property of THIS one workspace, not of the release — see
|
|
93
|
+
* `HaltReason`'s `stale-pin` / `not-yet-serving` docs for the full reasoning.
|
|
94
|
+
* `halted` is always terminal because the agent WAS rolled and its
|
|
95
|
+
* post-restart state is either confirmed-bad, unverifiable, or unconfirmed —
|
|
96
|
+
* none of those three are safe to leave behind while moving on to the next
|
|
97
|
+
* agent (macf#722 Fix A, extended by macf#899).
|
|
75
98
|
*/
|
|
76
|
-
export type RollOutcome = 'upgraded' | 'busy-skipped' | 'config-dirty-skipped' | 'branch-skipped' | 'stale-pin-skipped' | 'halted';
|
|
99
|
+
export type RollOutcome = 'upgraded' | 'busy-skipped' | 'config-dirty-skipped' | 'branch-skipped' | 'stale-pin-skipped' | 'not-yet-serving-skipped' | 'halted';
|
|
77
100
|
/**
|
|
78
101
|
* WHY a roll's verify-green did not confirm the target version:
|
|
79
102
|
* - `bad-release` — verify-green confirmed the agent came back up
|
|
80
|
-
* REACHABLE at its OLD (pre-upgrade) version,
|
|
81
|
-
*
|
|
103
|
+
* REACHABLE at its OLD (pre-upgrade) version, the
|
|
104
|
+
* responder is NOT provably the lingering
|
|
105
|
+
* pre-restart process (see `not-yet-serving`
|
|
106
|
+
* below — ruled out FIRST, `classifyHalt`'s doc),
|
|
107
|
+
* AND (macf#899) its own launch pin either already
|
|
82
108
|
* matches the target (a genuine crash-loop /
|
|
83
109
|
* stuck-old-process release) or could not be
|
|
84
110
|
* read at all (honest-unknown, treated
|
|
@@ -108,15 +134,44 @@ export type RollOutcome = 'upgraded' | 'busy-skipped' | 'config-dirty-skipped' |
|
|
|
108
134
|
* because a stale launch pin on one workspace says
|
|
109
135
|
* nothing about the release quality and endangers
|
|
110
136
|
* no other agent.
|
|
137
|
+
* - `not-yet-serving` — (NEW, follow-up to macf#899) verify-green
|
|
138
|
+
* confirmed the agent REACHABLE at its OLD
|
|
139
|
+
* version, AND the exact same `instance_id` is
|
|
140
|
+
* still answering `/health` as answered BEFORE
|
|
141
|
+
* this roll's own `restart()` call (DR-037
|
|
142
|
+
* Decision 5 mints a fresh `instance_id` per
|
|
143
|
+
* relaunch, so an unchanged one PROVES the
|
|
144
|
+
* pre-restart process was never superseded) — the
|
|
145
|
+
* agent's relaunch simply hasn't taken over
|
|
146
|
+
* serving yet. A common cause is an unanswered
|
|
147
|
+
* interactive launch prompt (Claude Code's trust
|
|
148
|
+
* dialog or the dev-channels confirmation), but
|
|
149
|
+
* this decision layer never touches tmux/
|
|
150
|
+
* capture-pane (DR-037), so it reports the STATE
|
|
151
|
+
* observed (same instance still live), not a
|
|
152
|
+
* confirmed CAUSE. Honest UNKNOWN, never
|
|
153
|
+
* `CONFIRMED` bad-release wording — same floor as
|
|
154
|
+
* `bad-release`'s pin-unreadable case. NOT
|
|
155
|
+
* terminal; `outcome: 'not-yet-serving-skipped'`
|
|
156
|
+
* — `rollFleet` skips this ONE agent and
|
|
157
|
+
* CONTINUES: a slow-to-take-over relaunch on one
|
|
158
|
+
* workspace endangers no other agent, and later
|
|
159
|
+
* fleets are never halted for it. Only reachable
|
|
160
|
+
* when BOTH the pre-restart and post-restart
|
|
161
|
+
* `/health` bodies carry an `instance_id` — an
|
|
162
|
+
* older/mixed-version fleet without that field
|
|
163
|
+
* falls straight through to the `bad-release` /
|
|
164
|
+
* `stale-pin` pin-check below, UNCHANGED.
|
|
111
165
|
*/
|
|
112
|
-
export type HaltReason = 'bad-release' | 'relaunch-unconfirmed' | 'stale-pin';
|
|
166
|
+
export type HaltReason = 'bad-release' | 'relaunch-unconfirmed' | 'stale-pin' | 'not-yet-serving';
|
|
113
167
|
/** The per-agent EXECUTE result. `detail` carries a human-readable summary. */
|
|
114
168
|
export interface AgentRollResult {
|
|
115
169
|
readonly agent: string;
|
|
116
170
|
readonly outcome: RollOutcome;
|
|
117
171
|
/**
|
|
118
172
|
* Set when `outcome === 'halted'` OR `outcome === 'stale-pin-skipped'`
|
|
119
|
-
* (macf#899 added the latter)
|
|
173
|
+
* (macf#899 added the latter) OR `outcome === 'not-yet-serving-skipped'`
|
|
174
|
+
* (NEW, follow-up to macf#899) — see `HaltReason`.
|
|
120
175
|
*/
|
|
121
176
|
readonly reason?: HaltReason;
|
|
122
177
|
readonly detail?: string;
|
|
@@ -267,6 +322,15 @@ export interface FleetRollResult {
|
|
|
267
322
|
* skip counters above, but still safe to continue past — see `HaltReason`.
|
|
268
323
|
*/
|
|
269
324
|
readonly stalePinSkipped: number;
|
|
325
|
+
/**
|
|
326
|
+
* Count of agents skipped because verify-green confirmed them REACHABLE
|
|
327
|
+
* at their OLD version but the responder was PROVEN to be the SAME
|
|
328
|
+
* pre-restart process instance (`reason: 'not-yet-serving'`, NEW —
|
|
329
|
+
* follow-up to macf#899) — POST-flight, like `stalePinSkipped`, but the
|
|
330
|
+
* agent's relaunch simply hasn't taken over serving yet rather than
|
|
331
|
+
* anything about its launch pin.
|
|
332
|
+
*/
|
|
333
|
+
readonly notYetServingSkipped: number;
|
|
270
334
|
}
|
|
271
335
|
/** Progress events for CLI rendering (the RESULT objects are what tests assert on). */
|
|
272
336
|
export type UpgradeEvent = {
|
|
@@ -289,13 +353,18 @@ export type UpgradeEvent = {
|
|
|
289
353
|
* BEFORE the config-dirty tiering / auto-resolve / busy-gate even run for
|
|
290
354
|
* this agent. `current` is the agent's actual branch (`null` on detached
|
|
291
355
|
* HEAD / an unresolvable branch); `canonical` is the resolved expected
|
|
292
|
-
* branch.
|
|
356
|
+
* branch. `workspace` (macf#1101) is the on-disk location the branch check
|
|
357
|
+
* actually inspected (`driver.resolveWorkspace(agent)`, `null` when the
|
|
358
|
+
* driver can't report one or the agent is unresolvable) — surfaced so a
|
|
359
|
+
* misattributed resolution is VISIBLE in the objection rather than silent.
|
|
360
|
+
* Fired INSTEAD of any mutation — nothing was touched.
|
|
293
361
|
*/
|
|
294
362
|
| {
|
|
295
363
|
readonly kind: 'branch-skip';
|
|
296
364
|
readonly agent: string;
|
|
297
365
|
readonly current: string | null;
|
|
298
366
|
readonly canonical: string;
|
|
367
|
+
readonly workspace: string | null;
|
|
299
368
|
}
|
|
300
369
|
/**
|
|
301
370
|
* The pre-flight AUTO-RESOLVE (DR-040 Decision 3 / macf#698 R1) — `files`
|
|
@@ -317,15 +386,20 @@ export type UpgradeEvent = {
|
|
|
317
386
|
* auto-resolved above and are never part of this list). `files` is the
|
|
318
387
|
* exact genuine-delta uncommitted-path list; `message` is the
|
|
319
388
|
* ready-to-forward, agent-directed text (inspect + commit / delete /
|
|
320
|
-
* gitignore, then re-run)
|
|
321
|
-
*
|
|
322
|
-
*
|
|
389
|
+
* gitignore, then re-run) and, per macf#1101, NAMES the workspace the
|
|
390
|
+
* check actually inspected so a misattributed resolution is visible
|
|
391
|
+
* rather than silent. `workspace` carries the same location as a
|
|
392
|
+
* separate structured field for programmatic consumers. Fired INSTEAD of
|
|
393
|
+
* any mutation — nothing on this agent's genuine-delta files was touched
|
|
394
|
+
* (though the already-canonical subset, if any, WAS committed by the
|
|
395
|
+
* preceding `config-auto-resolved`).
|
|
323
396
|
*/
|
|
324
397
|
| {
|
|
325
398
|
readonly kind: 'config-dirty-skip';
|
|
326
399
|
readonly agent: string;
|
|
327
400
|
readonly files: readonly string[];
|
|
328
401
|
readonly message: string;
|
|
402
|
+
readonly workspace: string | null;
|
|
329
403
|
} | {
|
|
330
404
|
readonly kind: 'busy-skip';
|
|
331
405
|
readonly agent: string;
|
|
@@ -365,6 +439,20 @@ export type UpgradeEvent = {
|
|
|
365
439
|
readonly pin: string;
|
|
366
440
|
readonly target: string;
|
|
367
441
|
}
|
|
442
|
+
/**
|
|
443
|
+
* The POST-restart NOT-YET-SERVING skip (NEW, follow-up to macf#899) —
|
|
444
|
+
* verify-green confirmed the agent reachable at its OLD version, but the
|
|
445
|
+
* SAME `instanceId` answered before AND after this roll's own `restart()`
|
|
446
|
+
* call — the relaunch hasn't taken over serving yet, so `rollFleet` skips
|
|
447
|
+
* this agent (NOT a halt) and continues to the next one. Distinct from
|
|
448
|
+
* `stale-pin-skip`: the cause here is a not-yet-superseded process, never
|
|
449
|
+
* the launch pin (which is never even consulted on this path).
|
|
450
|
+
*/
|
|
451
|
+
| {
|
|
452
|
+
readonly kind: 'not-yet-serving-skip';
|
|
453
|
+
readonly agent: string;
|
|
454
|
+
readonly instanceId: string;
|
|
455
|
+
}
|
|
368
456
|
/**
|
|
369
457
|
* DR-043 §D6 write-back (macf#907) — `deps.recordDeployedVersion` (the
|
|
370
458
|
* confirmed-green `fleet.lock` write) rejected. NON-FATAL: `outcome` for
|
|
@@ -448,11 +536,25 @@ export interface RollFleetDeps {
|
|
|
448
536
|
export declare const DEFAULT_WAIT_TIMEOUT_MS = 300000;
|
|
449
537
|
/** Default `--wait` re-poll interval (ms). */
|
|
450
538
|
export declare const DEFAULT_WAIT_POLL_MS = 5000;
|
|
539
|
+
/**
|
|
540
|
+
* Render the inspected-workspace clause shared by both pre-flight OBJECT
|
|
541
|
+
* messages (macf#1101) — `null` reads as an explicit UNRESOLVED diagnostic,
|
|
542
|
+
* never a blank/omitted clause, so a caller can't mistake "the driver didn't
|
|
543
|
+
* report a workspace" for "this gate has nothing to say about location."
|
|
544
|
+
* Pure — exported for CLI-rendering reuse / tests.
|
|
545
|
+
*/
|
|
546
|
+
export declare function describeInspectedWorkspace(workspace: string | null): string;
|
|
451
547
|
/**
|
|
452
548
|
* Build the agent-directed OBJECT message for a config-dirty pre-flight skip
|
|
453
|
-
* (macf#725).
|
|
549
|
+
* (macf#725). `workspace` (macf#1101) names the on-disk location the check
|
|
550
|
+
* actually inspected — the fix for the class of bug where a routing-label
|
|
551
|
+
* collision (or a caller-cwd-dependent resolution) silently attributed a
|
|
552
|
+
* DIFFERENT agent's — or the orchestrator's OWN — dirty files to `agent`;
|
|
553
|
+
* naming the inspected path makes that misattribution visible in the
|
|
554
|
+
* objection itself rather than requiring separate investigation. Pure —
|
|
555
|
+
* exported for CLI-rendering reuse / tests.
|
|
454
556
|
*/
|
|
455
|
-
export declare function buildConfigDirtyMessage(agent: string, files: readonly string[]): string;
|
|
557
|
+
export declare function buildConfigDirtyMessage(agent: string, files: readonly string[], workspace?: string | null): string;
|
|
456
558
|
/**
|
|
457
559
|
* Build the agent-directed post-upgrade modified-files message (macf#725).
|
|
458
560
|
* Pure — exported for CLI-rendering reuse / tests.
|
|
@@ -467,9 +569,13 @@ export declare function buildConfigDirtyMessage(agent: string, files: readonly s
|
|
|
467
569
|
export declare function buildModifiedFilesMessage(agent: string, files: readonly string[]): string;
|
|
468
570
|
/**
|
|
469
571
|
* Build the agent-directed OBJECT message for the branch-gate pre-flight skip
|
|
470
|
-
* (macf#755).
|
|
572
|
+
* (macf#755). `workspace` (macf#1101) names the on-disk location the branch
|
|
573
|
+
* check actually inspected — see `buildConfigDirtyMessage`'s doc for why this
|
|
574
|
+
* matters (the same routing-label-collision / caller-cwd-dependent
|
|
575
|
+
* misattribution class applies to the branch check too). Pure — exported for
|
|
576
|
+
* CLI-rendering reuse / tests.
|
|
471
577
|
*/
|
|
472
|
-
export declare function buildBranchSkipMessage(agent: string, current: string | null, canonical: string): string;
|
|
578
|
+
export declare function buildBranchSkipMessage(agent: string, current: string | null, canonical: string, workspace?: string | null): string;
|
|
473
579
|
/**
|
|
474
580
|
* Roll ONE fleet: for every `behind` plan (in order) run the PRE-FLIGHT gates
|
|
475
581
|
* (branch-gate FIRST, then config-dirty tier-first, then busy) → upgrade →
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fleet-upgrade.d.ts","sourceRoot":"","sources":["../src/fleet-upgrade.ts"],"names":[],"mappings":"AAuFA,OAAO,KAAK,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AACjE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AACtD,OAAO,KAAK,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAE/E;;;;;;;;;GASG;AACH,MAAM,MAAM,kBAAkB,GAAG,QAAQ,GAAG,WAAW,GAAG,SAAS,CAAC;AAEpE,oFAAoF;AACpF,MAAM,WAAW,gBAAgB;IAC/B,gDAAgD;IAChD,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB;;;OAGG;IACH,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,6FAA6F;IAC7F,QAAQ,CAAC,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IACvC,iFAAiF;IACjF,QAAQ,CAAC,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IACtC,+DAA+D;IAC/D,QAAQ,CAAC,WAAW,EAAE,kBAAkB,CAAC;CAC1C;AAED
|
|
1
|
+
{"version":3,"file":"fleet-upgrade.d.ts","sourceRoot":"","sources":["../src/fleet-upgrade.ts"],"names":[],"mappings":"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"}
|
package/dist/fleet-upgrade.js
CHANGED
|
@@ -221,6 +221,12 @@ export function planFleetUpgrade(members, state, targetVersion) {
|
|
|
221
221
|
return members.map((m) => {
|
|
222
222
|
const live = byName.get(m.agent);
|
|
223
223
|
const runningVersion = live?.online ? (live.version ?? null) : null;
|
|
224
|
+
// NEW (follow-up to macf#899) — captured alongside `runningVersion` so
|
|
225
|
+
// `classifyHalt` can later tell "the SAME process is still answering
|
|
226
|
+
// /health post-restart" (not-yet-serving) apart from "a genuinely NEW
|
|
227
|
+
// process is serving the wrong version" (bad-release). `null` when
|
|
228
|
+
// offline or the `/health` body predates the field.
|
|
229
|
+
const runningInstanceId = live?.online ? (live.health?.instance_id ?? null) : null;
|
|
224
230
|
let disposition;
|
|
225
231
|
if (runningVersion === null) {
|
|
226
232
|
disposition = 'offline';
|
|
@@ -235,6 +241,7 @@ export function planFleetUpgrade(members, state, targetVersion) {
|
|
|
235
241
|
agent: m.agent,
|
|
236
242
|
fleet: m.project,
|
|
237
243
|
runningVersion,
|
|
244
|
+
runningInstanceId,
|
|
238
245
|
pinnedVersion: m.versionPin,
|
|
239
246
|
disposition,
|
|
240
247
|
};
|
|
@@ -309,8 +316,34 @@ async function waitForIdle(agent, opts, deps) {
|
|
|
309
316
|
* be read, so the reason string alone is never mistaken for a positively
|
|
310
317
|
* confirmed diagnosis, and the operator's remedy is "check the launch
|
|
311
318
|
* pin/mount," not "assume the release is broken."
|
|
319
|
+
*
|
|
320
|
+
* ## The not-yet-serving discriminator (NEW, follow-up to macf#899)
|
|
321
|
+
*
|
|
322
|
+
* The 0.2.58 roll incident this follow-up is grounded in showed the
|
|
323
|
+
* `pin === targetVersion` branch ABOVE still overstates: it fires unconditional
|
|
324
|
+
* `CONFIRMED` wording even when the agent simply hasn't finished relaunching
|
|
325
|
+
* (e.g. sitting at an unanswered interactive launch prompt) — the SAME
|
|
326
|
+
* pre-restart process was still the one answering `/health` for the whole
|
|
327
|
+
* verify-green budget, which looks IDENTICAL to a genuine crash-loop from the
|
|
328
|
+
* version comparison alone. `restart-self` mints a NEW `instance_id` on every
|
|
329
|
+
* relaunch (DR-037 Decision 5) precisely so this is checkable: if the
|
|
330
|
+
* `instance_id` verify-green saw on its MOST RECENT probe — `lastInstanceId`
|
|
331
|
+
* is cleared on any unreachable probe, never latched like `lastVersion`, see
|
|
332
|
+
* `verify-green.ts` — is the EXACT SAME one recorded before this roll's own
|
|
333
|
+
* `restart()` call, the responder is PROVEN to be STILL CONTINUOUSLY the
|
|
334
|
+
* lingering pre-restart process — not a fresh one running broken code. That
|
|
335
|
+
* is `not-yet-serving`: an honest UNKNOWN (this decision layer never touches
|
|
336
|
+
* tmux/capture-pane, so it cannot confirm WHY the relaunch stalled, only
|
|
337
|
+
* THAT it has), reported and skipped, never a `CONFIRMED` bad-release. Ruled
|
|
338
|
+
* out FIRST, before the pin-check, because a not-yet-superseded process makes
|
|
339
|
+
* the pin question moot — the pin can only describe what the process WILL
|
|
340
|
+
* request once it actually restarts. Only fires when a same-non-null
|
|
341
|
+
* `instance_id` is available on BOTH sides; an older/mixed-version fleet
|
|
342
|
+
* without the field falls straight through to the pin-check UNCHANGED — this
|
|
343
|
+
* is strictly additive, never a behavior change for a fleet that lacks the
|
|
344
|
+
* data.
|
|
312
345
|
*/
|
|
313
|
-
async function classifyHalt(green, oldVersion, targetVersion, agent, driver) {
|
|
346
|
+
async function classifyHalt(green, oldVersion, oldInstanceId, targetVersion, agent, driver) {
|
|
314
347
|
const base = `verify-green ${green.reason} (last=${green.lastVersion ?? 'down'})`;
|
|
315
348
|
const confirmedOldVersion = green.reason === 'wrong-version' &&
|
|
316
349
|
green.lastVersion !== null &&
|
|
@@ -319,8 +352,29 @@ async function classifyHalt(green, oldVersion, targetVersion, agent, driver) {
|
|
|
319
352
|
if (!confirmedOldVersion) {
|
|
320
353
|
return { reason: 'relaunch-unconfirmed', detail: `relaunch-unconfirmed: ${base}` };
|
|
321
354
|
}
|
|
322
|
-
// macf#899 —
|
|
323
|
-
//
|
|
355
|
+
// NEW (follow-up to macf#899) — before implicating the release at all,
|
|
356
|
+
// rule out the simplest honest explanation: the SAME pre-restart process
|
|
357
|
+
// instance is still the one answering /health, i.e. this agent's relaunch
|
|
358
|
+
// has not taken over serving yet. Only possible when BOTH sides carry an
|
|
359
|
+
// `instance_id` — see this function's doc.
|
|
360
|
+
const lastInstanceId = green.lastInstanceId ?? null;
|
|
361
|
+
if (oldInstanceId !== null && lastInstanceId !== null && lastInstanceId === oldInstanceId) {
|
|
362
|
+
return {
|
|
363
|
+
reason: 'not-yet-serving',
|
|
364
|
+
detail: `not-yet-serving: ${base} — the SAME pre-restart instance (${oldInstanceId}) is still ` +
|
|
365
|
+
`the one answering ${agent}'s /health; its relaunch has not taken over serving yet. ` +
|
|
366
|
+
`This is an honest UNKNOWN, not a confirmed bad release — a common cause is an ` +
|
|
367
|
+
`unanswered interactive launch prompt (Claude Code's trust dialog or the dev-channels ` +
|
|
368
|
+
`confirmation); attach to ${agent}'s session, clear any pending prompt, then re-run the ` +
|
|
369
|
+
`upgrade to pick it up. NOT halting the roll — a slow-to-take-over relaunch on one ` +
|
|
370
|
+
`workspace endangers no other agent.`,
|
|
371
|
+
instanceId: oldInstanceId,
|
|
372
|
+
};
|
|
373
|
+
}
|
|
374
|
+
// macf#899 — POSITIVELY confirmed reachable-at-OLD-version (and, whenever
|
|
375
|
+
// instance-id data was available above, confirmed NOT to be the lingering
|
|
376
|
+
// pre-restart process). Read the agent's own launch pin before naming this
|
|
377
|
+
// a bad release.
|
|
324
378
|
const pin = await driver.readVersionPin(agent);
|
|
325
379
|
if (pin === null) {
|
|
326
380
|
return {
|
|
@@ -352,13 +406,30 @@ async function classifyHalt(green, oldVersion, targetVersion, agent, driver) {
|
|
|
352
406
|
pin,
|
|
353
407
|
};
|
|
354
408
|
}
|
|
409
|
+
/**
|
|
410
|
+
* Render the inspected-workspace clause shared by both pre-flight OBJECT
|
|
411
|
+
* messages (macf#1101) — `null` reads as an explicit UNRESOLVED diagnostic,
|
|
412
|
+
* never a blank/omitted clause, so a caller can't mistake "the driver didn't
|
|
413
|
+
* report a workspace" for "this gate has nothing to say about location."
|
|
414
|
+
* Pure — exported for CLI-rendering reuse / tests.
|
|
415
|
+
*/
|
|
416
|
+
export function describeInspectedWorkspace(workspace) {
|
|
417
|
+
return workspace ?? 'UNRESOLVED — no workspace could be matched to this agent for this fleet';
|
|
418
|
+
}
|
|
355
419
|
/**
|
|
356
420
|
* Build the agent-directed OBJECT message for a config-dirty pre-flight skip
|
|
357
|
-
* (macf#725).
|
|
421
|
+
* (macf#725). `workspace` (macf#1101) names the on-disk location the check
|
|
422
|
+
* actually inspected — the fix for the class of bug where a routing-label
|
|
423
|
+
* collision (or a caller-cwd-dependent resolution) silently attributed a
|
|
424
|
+
* DIFFERENT agent's — or the orchestrator's OWN — dirty files to `agent`;
|
|
425
|
+
* naming the inspected path makes that misattribution visible in the
|
|
426
|
+
* objection itself rather than requiring separate investigation. Pure —
|
|
427
|
+
* exported for CLI-rendering reuse / tests.
|
|
358
428
|
*/
|
|
359
|
-
export function buildConfigDirtyMessage(agent, files) {
|
|
429
|
+
export function buildConfigDirtyMessage(agent, files, workspace = null) {
|
|
360
430
|
return (`Fleet upgrade skipped ${agent} — these files have uncommitted changes ` +
|
|
361
|
-
`\`macf update\` would overwrite: ${files.join(', ')}
|
|
431
|
+
`\`macf update\` would overwrite: ${files.join(', ')} ` +
|
|
432
|
+
`(inspected workspace: ${describeInspectedWorkspace(workspace)}). Inspect each and ` +
|
|
362
433
|
`commit, delete, or .gitignore it, then re-run the upgrade.`);
|
|
363
434
|
}
|
|
364
435
|
/**
|
|
@@ -379,11 +450,16 @@ export function buildModifiedFilesMessage(agent, files) {
|
|
|
379
450
|
}
|
|
380
451
|
/**
|
|
381
452
|
* Build the agent-directed OBJECT message for the branch-gate pre-flight skip
|
|
382
|
-
* (macf#755).
|
|
453
|
+
* (macf#755). `workspace` (macf#1101) names the on-disk location the branch
|
|
454
|
+
* check actually inspected — see `buildConfigDirtyMessage`'s doc for why this
|
|
455
|
+
* matters (the same routing-label-collision / caller-cwd-dependent
|
|
456
|
+
* misattribution class applies to the branch check too). Pure — exported for
|
|
457
|
+
* CLI-rendering reuse / tests.
|
|
383
458
|
*/
|
|
384
|
-
export function buildBranchSkipMessage(agent, current, canonical) {
|
|
459
|
+
export function buildBranchSkipMessage(agent, current, canonical, workspace = null) {
|
|
385
460
|
const branchDesc = current === null ? 'a detached HEAD (or an unresolvable branch)' : `branch \`${current}\``;
|
|
386
|
-
return (`Fleet upgrade skipped ${agent} — on ${branchDesc}, expected \`${canonical}
|
|
461
|
+
return (`Fleet upgrade skipped ${agent} — on ${branchDesc}, expected \`${canonical}\` ` +
|
|
462
|
+
`(inspected workspace: ${describeInspectedWorkspace(workspace)}). ` +
|
|
387
463
|
`A mutation (macf update / an auto-resolve commit) or a relaunch would land on the ` +
|
|
388
464
|
`wrong branch. Switch the workspace to \`${canonical}\` (or set canonicalBranch / ` +
|
|
389
465
|
`MACF_CANONICAL_BRANCH if this is a legitimate fork), then re-run the upgrade, or ` +
|
|
@@ -451,10 +527,20 @@ export async function rollFleet(plans, opts, deps) {
|
|
|
451
527
|
let configAutoResolved = 0;
|
|
452
528
|
let branchSkipped = 0;
|
|
453
529
|
let stalePinSkipped = 0;
|
|
530
|
+
let notYetServingSkipped = 0;
|
|
454
531
|
for (const plan of plans) {
|
|
455
532
|
if (plan.disposition !== 'behind')
|
|
456
533
|
continue;
|
|
457
534
|
const agent = plan.agent;
|
|
535
|
+
// macf#1101 — resolve the on-disk location the pre-flight gates below
|
|
536
|
+
// are ABOUT to inspect, ONCE per agent, so both OBJECT messages can name
|
|
537
|
+
// it (a misattribution — e.g. a routing-label collision resolving to a
|
|
538
|
+
// DIFFERENT project's, or the orchestrator's OWN, workspace — becomes
|
|
539
|
+
// visible in the objection instead of silent). `null` when the driver
|
|
540
|
+
// doesn't implement `resolveWorkspace` (optional) or can't resolve
|
|
541
|
+
// `agent` at all. Skipped entirely under `--force`, which bypasses both
|
|
542
|
+
// gates below and never inspects anything.
|
|
543
|
+
const workspace = opts.force ? null : ((await deps.driver.resolveWorkspace?.(agent)) ?? null);
|
|
458
544
|
// PRE-FLIGHT branch-gate (macf#755) — the FIRST gate, before config-dirty
|
|
459
545
|
// or busy. Detached HEAD / unresolvable (`current === null`) is ALWAYS
|
|
460
546
|
// non-canonical.
|
|
@@ -463,9 +549,9 @@ export async function rollFleet(plans, opts, deps) {
|
|
|
463
549
|
const current = await deps.driver.currentBranch(agent);
|
|
464
550
|
if (current === null || current !== canonical) {
|
|
465
551
|
branchSkipped += 1;
|
|
466
|
-
const message = buildBranchSkipMessage(agent, current, canonical);
|
|
552
|
+
const message = buildBranchSkipMessage(agent, current, canonical, workspace);
|
|
467
553
|
results.push({ agent, outcome: 'branch-skipped', detail: message });
|
|
468
|
-
deps.onEvent?.({ kind: 'branch-skip', agent, current, canonical });
|
|
554
|
+
deps.onEvent?.({ kind: 'branch-skip', agent, current, canonical, workspace });
|
|
469
555
|
continue;
|
|
470
556
|
}
|
|
471
557
|
}
|
|
@@ -489,14 +575,14 @@ export async function rollFleet(plans, opts, deps) {
|
|
|
489
575
|
}
|
|
490
576
|
if (genuineDelta.length > 0) {
|
|
491
577
|
configDirtySkipped += 1;
|
|
492
|
-
const message = buildConfigDirtyMessage(agent, genuineDelta);
|
|
578
|
+
const message = buildConfigDirtyMessage(agent, genuineDelta, workspace);
|
|
493
579
|
results.push({
|
|
494
580
|
agent,
|
|
495
581
|
outcome: 'config-dirty-skipped',
|
|
496
582
|
detail: message,
|
|
497
583
|
...(autoResolvedFiles ? { autoResolvedFiles } : {}),
|
|
498
584
|
});
|
|
499
|
-
deps.onEvent?.({ kind: 'config-dirty-skip', agent, files: genuineDelta, message });
|
|
585
|
+
deps.onEvent?.({ kind: 'config-dirty-skip', agent, files: genuineDelta, message, workspace });
|
|
500
586
|
continue;
|
|
501
587
|
}
|
|
502
588
|
// genuineDelta is empty (nothing dirty at all, or everything dirty WAS
|
|
@@ -580,8 +666,30 @@ export async function rollFleet(plans, opts, deps) {
|
|
|
580
666
|
}
|
|
581
667
|
continue;
|
|
582
668
|
}
|
|
583
|
-
const classification = await classifyHalt(green, plan.runningVersion, opts.targetVersion, agent, deps.driver);
|
|
669
|
+
const classification = await classifyHalt(green, plan.runningVersion, plan.runningInstanceId, opts.targetVersion, agent, deps.driver);
|
|
584
670
|
const { reason, detail } = classification;
|
|
671
|
+
if (reason === 'not-yet-serving') {
|
|
672
|
+
// NEW (follow-up to macf#899) — SAFE TO CONTINUE despite the agent
|
|
673
|
+
// having been mutated: the post-restart old-version state is explained
|
|
674
|
+
// by the SAME pre-restart process instance still answering /health
|
|
675
|
+
// (its relaunch hasn't taken over yet), not a bad release, and a
|
|
676
|
+
// slow-to-take-over relaunch on ONE workspace endangers no OTHER
|
|
677
|
+
// agent. Leave the maintenance lock in place (DR-040 Decision 3 —
|
|
678
|
+
// "release ONLY on confirmed clean success"; this agent is NOT
|
|
679
|
+
// confirmed clean): same posture as `stale-pin`. Only the heartbeat
|
|
680
|
+
// stops here; the lock self-clears via MAINT_LOCK_TTL.
|
|
681
|
+
notYetServingSkipped += 1;
|
|
682
|
+
results.push({
|
|
683
|
+
agent,
|
|
684
|
+
outcome: 'not-yet-serving-skipped',
|
|
685
|
+
reason,
|
|
686
|
+
detail,
|
|
687
|
+
...(autoResolvedFiles ? { autoResolvedFiles } : {}),
|
|
688
|
+
});
|
|
689
|
+
deps.onEvent?.({ kind: 'not-yet-serving-skip', agent, instanceId: classification.instanceId });
|
|
690
|
+
stopHeartbeat();
|
|
691
|
+
continue;
|
|
692
|
+
}
|
|
585
693
|
if (reason === 'stale-pin') {
|
|
586
694
|
// macf#899 — SAFE TO CONTINUE despite the agent having been mutated
|
|
587
695
|
// (upgrade + restart already ran): the post-restart old-version state
|
|
@@ -631,6 +739,7 @@ export async function rollFleet(plans, opts, deps) {
|
|
|
631
739
|
configAutoResolved,
|
|
632
740
|
branchSkipped,
|
|
633
741
|
stalePinSkipped,
|
|
742
|
+
notYetServingSkipped,
|
|
634
743
|
};
|
|
635
744
|
}
|
|
636
745
|
return {
|
|
@@ -642,6 +751,7 @@ export async function rollFleet(plans, opts, deps) {
|
|
|
642
751
|
configAutoResolved,
|
|
643
752
|
branchSkipped,
|
|
644
753
|
stalePinSkipped,
|
|
754
|
+
notYetServingSkipped,
|
|
645
755
|
};
|
|
646
756
|
}
|
|
647
757
|
/**
|