agent-coord-mcp 0.26.18 → 0.26.19
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/build.js +113 -0
- package/dist/build.js.map +1 -0
- package/dist/capabilities.js +158 -0
- package/dist/capabilities.js.map +1 -0
- package/dist/prefix.js +64 -0
- package/dist/prefix.js.map +1 -0
- package/dist/roles.js +132 -0
- package/dist/roles.js.map +1 -0
- package/dist/server-identity.js +82 -0
- package/dist/server-identity.js.map +1 -0
- package/dist/server.js +647 -0
- package/dist/server.js.map +1 -0
- package/dist/store.js +553 -0
- package/dist/store.js.map +1 -0
- package/dist/tools/admin.js +323 -0
- package/dist/tools/admin.js.map +1 -0
- package/dist/tools/attention.js +73 -0
- package/dist/tools/attention.js.map +1 -0
- package/dist/tools/away.js +285 -0
- package/dist/tools/away.js.map +1 -0
- package/dist/tools/board-ref.js +208 -0
- package/dist/tools/board-ref.js.map +1 -0
- package/dist/tools/event-kinds.js +39 -0
- package/dist/tools/event-kinds.js.map +1 -0
- package/dist/tools/events.js +234 -0
- package/dist/tools/events.js.map +1 -0
- package/dist/tools/index.js +14 -0
- package/dist/tools/index.js.map +1 -0
- package/dist/tools/logwatch.js +85 -0
- package/dist/tools/logwatch.js.map +1 -0
- package/dist/tools/messaging.js +706 -0
- package/dist/tools/messaging.js.map +1 -0
- package/dist/tools/record-events.js +380 -0
- package/dist/tools/record-events.js.map +1 -0
- package/dist/tools/records.js +1027 -0
- package/dist/tools/records.js.map +1 -0
- package/dist/tools/registry.js +500 -0
- package/dist/tools/registry.js.map +1 -0
- package/dist/tools/render.js +2 -0
- package/dist/tools/render.js.map +1 -0
- package/dist/tools/rooms.js +210 -0
- package/dist/tools/rooms.js.map +1 -0
- package/dist/tools/rotate.js +143 -0
- package/dist/tools/rotate.js.map +1 -0
- package/dist/tools/scopes.js +126 -0
- package/dist/tools/scopes.js.map +1 -0
- package/dist/tools/shared.js +104 -0
- package/dist/tools/shared.js.map +1 -0
- package/dist/tools/stall.js +414 -0
- package/dist/tools/stall.js.map +1 -0
- package/dist/tools/transport.js +1878 -0
- package/dist/tools/transport.js.map +1 -0
- package/dist/tools/work.js +373 -0
- package/dist/tools/work.js.map +1 -0
- package/dist/tools/worktrees.js +581 -0
- package/dist/tools/worktrees.js.map +1 -0
- package/dist/typed-records.js +174 -0
- package/dist/typed-records.js.map +1 -0
- package/dist/work.js +2 -0
- package/dist/work.js.map +1 -0
- package/hooks/peek-coord.mjs +0 -0
- package/hooks/tmux-pusher.mjs +0 -0
- package/package.json +11 -14
- package/scripts/coord-attention-clock.mjs +0 -0
- package/scripts/coord-node.sh +0 -0
- package/scripts/coord-stall-clock.mjs +0 -0
- package/scripts/coord-token.mjs +0 -0
- package/scripts/probe-tmux-liveness.sh +0 -0
- package/scripts/spawn-agent.sh +0 -0
- package/scripts/stop-agent.sh +0 -0
- package/scripts/typed-record-stats.mjs +0 -0
- package/src/server.ts +9 -1
- package/src/tools/worktrees.ts +234 -32
|
@@ -0,0 +1,414 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* `stall_check` — a predicate over the board and the bus, plus a HALT flag.
|
|
3
|
+
*
|
|
4
|
+
* Stall has been "notice the room" until now, which means it is noticed when
|
|
5
|
+
* somebody happens to look. The measured cost elsewhere: ~42 hours of dead merge
|
|
6
|
+
* path across four incidents in three days, with `main` advancing throughout so
|
|
7
|
+
* every commit-based liveness check read green.
|
|
8
|
+
*
|
|
9
|
+
* A MISS IS SILENT TO THE DUTY OFFICER AND NEVER SILENT TO THE RECORD.
|
|
10
|
+
*
|
|
11
|
+
* This is the whole design constraint (3.3b). "HIT DMs, MISS silent" answers the
|
|
12
|
+
* noise question and makes a DEAD CLOCK look exactly like a healthy fleet — the
|
|
13
|
+
* absence-read-as-evidence rule, inside the verb built to watch for absence. So
|
|
14
|
+
* every run leaves a mark, HIT or MISS, and "no alert" becomes distinguishable
|
|
15
|
+
* from "nothing ran". A check that only speaks when it fires cannot be told from
|
|
16
|
+
* a broken one.
|
|
17
|
+
*/
|
|
18
|
+
import { existsSync, readFileSync, writeFileSync, mkdirSync } from "node:fs";
|
|
19
|
+
import { execFileSync } from "node:child_process";
|
|
20
|
+
import path from "node:path";
|
|
21
|
+
import { z } from "zod";
|
|
22
|
+
import { parseWorkDoc, workstreamsV1RowsOf } from "@davidbalzan/groundwork-seam";
|
|
23
|
+
import { ROOT, AGENTS_FILE, readJson } from "../store.js";
|
|
24
|
+
import { classifyBoardRef, refInCell } from "./board-ref.js";
|
|
25
|
+
import { loadLiveTransports } from "./registry.js";
|
|
26
|
+
const BOARD_DOC = "docs/WORKSTREAMS.md";
|
|
27
|
+
const STALL_MS = 30 * 60 * 1000;
|
|
28
|
+
const runFile = () => path.join(ROOT, "stall-check.json");
|
|
29
|
+
const haltFile = () => path.join(ROOT, "halt.json");
|
|
30
|
+
// ---------- halt ----------
|
|
31
|
+
export const setHaltSchema = {
|
|
32
|
+
reason: z.string().min(1),
|
|
33
|
+
by: z.string().min(1),
|
|
34
|
+
clear: z.boolean().optional(),
|
|
35
|
+
};
|
|
36
|
+
/**
|
|
37
|
+
* A NAMED state, never a mood.
|
|
38
|
+
*
|
|
39
|
+
* "Production feels down" is not a halt: a halt blocks every claim in the fleet,
|
|
40
|
+
* so the thing that sets it must be nameable and therefore arguable — a board
|
|
41
|
+
* cutover, a cited `BLOCKER:`, a documented red pipeline. The reason is required
|
|
42
|
+
* for that reason, not for the log.
|
|
43
|
+
*/
|
|
44
|
+
export async function setHaltTool(args) {
|
|
45
|
+
mkdirSync(ROOT, { recursive: true });
|
|
46
|
+
if (args.clear) {
|
|
47
|
+
writeFileSync(haltFile(), JSON.stringify({ halted: false, clearedBy: args.by, clearedAt: Date.now(), lastReason: args.reason }, null, 2));
|
|
48
|
+
return { ok: true, halted: false, clearedBy: args.by };
|
|
49
|
+
}
|
|
50
|
+
const state = { halted: true, reason: args.reason, by: args.by, at: Date.now() };
|
|
51
|
+
writeFileSync(haltFile(), JSON.stringify(state, null, 2));
|
|
52
|
+
return { ok: true, ...state };
|
|
53
|
+
}
|
|
54
|
+
export function haltState() {
|
|
55
|
+
try {
|
|
56
|
+
const raw = JSON.parse(readFileSync(haltFile(), "utf8"));
|
|
57
|
+
return raw?.halted ? raw : { halted: false };
|
|
58
|
+
}
|
|
59
|
+
catch {
|
|
60
|
+
return { halted: false };
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
// ---------- the run mark ----------
|
|
64
|
+
/** Every run leaves this, HIT or MISS. It is what makes a dead clock visible. */
|
|
65
|
+
/**
|
|
66
|
+
* Record a run that FAILED.
|
|
67
|
+
*
|
|
68
|
+
* Acceptance from the queue item, and the clause most easily skipped: "a
|
|
69
|
+
* scheduled check reports its FETCH FAILURES, or a broken check is
|
|
70
|
+
* indistinguishable from a quiet registry". Without this, a clock that fires
|
|
71
|
+
* every 30 minutes and throws every time leaves NO marks at all — identical on
|
|
72
|
+
* disk to a clock that was never installed.
|
|
73
|
+
*/
|
|
74
|
+
export function markRunFailure(reason) {
|
|
75
|
+
mkdirSync(ROOT, { recursive: true });
|
|
76
|
+
let history = [];
|
|
77
|
+
try {
|
|
78
|
+
history = JSON.parse(readFileSync(runFile(), "utf8")).history ?? [];
|
|
79
|
+
}
|
|
80
|
+
catch {
|
|
81
|
+
/* first run */
|
|
82
|
+
}
|
|
83
|
+
history.push({ at: Date.now(), hits: 0, checked: 0, failed: reason });
|
|
84
|
+
writeFileSync(runFile(), JSON.stringify({ history: history.slice(-200) }, null, 2));
|
|
85
|
+
}
|
|
86
|
+
function markRun(result) {
|
|
87
|
+
mkdirSync(ROOT, { recursive: true });
|
|
88
|
+
let history = [];
|
|
89
|
+
try {
|
|
90
|
+
history = JSON.parse(readFileSync(runFile(), "utf8")).history ?? [];
|
|
91
|
+
}
|
|
92
|
+
catch {
|
|
93
|
+
/* first run */
|
|
94
|
+
}
|
|
95
|
+
// COVERAGE IS RECORDED WITH THE RUN, because a status tool that cannot
|
|
96
|
+
// express its own blindness is worse than no status tool. Measured: the clock
|
|
97
|
+
// reported `runs 8, failures 0` — all green — while every one of those runs
|
|
98
|
+
// had covered 0 of 3 agents. Nothing in the mark could say so, and this is the
|
|
99
|
+
// instrument meant to cover an absence.
|
|
100
|
+
history.push({ at: Date.now(), hits: result.hits.length, checked: result.checked, measurable: result.measurable ?? 0 });
|
|
101
|
+
// A RUN OF MISSES MUST BE VISIBLE AS RUNS, not as absence — so the marks are a
|
|
102
|
+
// list, not a single timestamp. "Ten quiet checks" and "one check ten hours ago"
|
|
103
|
+
// are different states and only the first is a healthy fleet.
|
|
104
|
+
writeFileSync(runFile(), JSON.stringify({ history: history.slice(-200) }, null, 2));
|
|
105
|
+
}
|
|
106
|
+
export const lastRanSchema = { maxAgeMinutes: z.number().optional() };
|
|
107
|
+
/**
|
|
108
|
+
* Is the clock alive? Readable by a human or another check, which is the point —
|
|
109
|
+
* MISS is silent to the WATCHER, not to the record.
|
|
110
|
+
*/
|
|
111
|
+
export async function stallClockStatusTool(args) {
|
|
112
|
+
const maxAge = (args.maxAgeMinutes ?? 60) * 60 * 1000;
|
|
113
|
+
let history = [];
|
|
114
|
+
try {
|
|
115
|
+
history = JSON.parse(readFileSync(runFile(), "utf8")).history ?? [];
|
|
116
|
+
}
|
|
117
|
+
catch {
|
|
118
|
+
return {
|
|
119
|
+
ok: false,
|
|
120
|
+
error: "stall_check has NEVER run — no run mark exists. That is not a quiet fleet, it is an unwatched one: a check that only speaks when it fires cannot be told from a broken one.",
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
const last = history[history.length - 1];
|
|
124
|
+
// A RUN THAT FAILED IS NOT A RUN THAT PASSED. Without this the clock reads
|
|
125
|
+
// "fresh" off a mark it wrote while erroring — the age is honest and the
|
|
126
|
+
// health is not, which is the same shape as a fresh heartbeat from a stuck
|
|
127
|
+
// agent.
|
|
128
|
+
const failures = history.filter((h) => h.failed);
|
|
129
|
+
const lastFailed = last?.failed;
|
|
130
|
+
const age = Date.now() - (last?.at ?? 0);
|
|
131
|
+
// `>=`, NOT `>`, AND THE DIFFERENCE IS A REAL RACE RATHER THAN PEDANTRY.
|
|
132
|
+
//
|
|
133
|
+
// With `>`, a window of 0 and a mark written in the SAME MILLISECOND gives
|
|
134
|
+
// `0 > 0` = false: the clock reads FRESH at the instant it was asked to treat
|
|
135
|
+
// everything as stale. It passed locally and on one CI run and failed on
|
|
136
|
+
// another — green in two environments, red in one — because it depended on at
|
|
137
|
+
// least a millisecond elapsing.
|
|
138
|
+
//
|
|
139
|
+
// The window having ELAPSED is the condition, so equality is inside it: a
|
|
140
|
+
// 0-minute window means nothing is ever fresh, which is what a caller asking
|
|
141
|
+
// for one means.
|
|
142
|
+
const stale = age >= maxAge;
|
|
143
|
+
const misses = history.filter((h) => !h.failed && h.hits === 0).length;
|
|
144
|
+
const hits = history.filter((h) => !h.failed && h.hits > 0).length;
|
|
145
|
+
// A RUN THAT COVERED NOTHING IS NOT A RUN THAT FOUND NOTHING. Marks written
|
|
146
|
+
// before coverage was recorded carry no `measurable` field: they are reported
|
|
147
|
+
// as UNKNOWN rather than assumed covered, because assuming is what produced
|
|
148
|
+
// the green this exists to correct.
|
|
149
|
+
const graded = history.filter((h) => !h.failed && typeof h.measurable === "number");
|
|
150
|
+
const blindRuns = graded.filter((h) => h.checked > 0 && h.measurable === 0).length;
|
|
151
|
+
const ungraded = history.filter((h) => !h.failed && typeof h.measurable !== "number").length;
|
|
152
|
+
const lastBlind = last && !last.failed && (last.checked ?? 0) > 0 && last.measurable === 0;
|
|
153
|
+
return {
|
|
154
|
+
// A FAILING CLOCK IS NOT A HEALTHY ONE. It writes marks on schedule, so the
|
|
155
|
+
// age looks fresh while nothing is being measured — a fresh heartbeat from
|
|
156
|
+
// a stuck agent, one level up.
|
|
157
|
+
ok: !stale && !lastFailed && !lastBlind,
|
|
158
|
+
...(stale
|
|
159
|
+
? {
|
|
160
|
+
error: `stall_check last ran ${Math.round(age / 60000)}m ago, past the ${args.maxAgeMinutes ?? 60}m window — THE CLOCK IS STOPPED. No alerts is not the same as no stalls.`,
|
|
161
|
+
}
|
|
162
|
+
: lastFailed
|
|
163
|
+
? {
|
|
164
|
+
error: `the clock is RUNNING but its last run FAILED: ${lastFailed}. It is firing on schedule and measuring nothing, which reads as fresh and is not.`,
|
|
165
|
+
}
|
|
166
|
+
: lastBlind
|
|
167
|
+
? {
|
|
168
|
+
error: `the clock is RUNNING and BLIND: its last run checked ${last?.checked} in-flight row(s) and could measure ${last?.measurable} of them. ` +
|
|
169
|
+
`It fires on schedule, reports no hits, and that "no hits" is not evidence of a healthy fleet — it is evidence of nothing. ` +
|
|
170
|
+
`Read stall_check's own 'unmeasurable' list for the cause; the usual one is a board 'Branch · Worktree' cell holding a PATH rather than a branch ref.`,
|
|
171
|
+
}
|
|
172
|
+
: {}),
|
|
173
|
+
lastRanMinutesAgo: Math.round(age / 60000),
|
|
174
|
+
runs: history.length,
|
|
175
|
+
misses,
|
|
176
|
+
hits,
|
|
177
|
+
failures: failures.length,
|
|
178
|
+
// The number the old shape could not express.
|
|
179
|
+
coverage: {
|
|
180
|
+
lastRun: last && !last.failed ? { checked: last.checked, measurable: last.measurable ?? null } : null,
|
|
181
|
+
blindRuns,
|
|
182
|
+
ungraded,
|
|
183
|
+
note: "blindRuns are runs that checked rows and measured none of them — green by every other field. " +
|
|
184
|
+
"ungraded are marks written before coverage was recorded: UNKNOWN, never assumed covered.",
|
|
185
|
+
},
|
|
186
|
+
};
|
|
187
|
+
}
|
|
188
|
+
// ---------- the predicate ----------
|
|
189
|
+
export const stallCheckSchema = { repo: z.string().optional(), stallMinutes: z.number().optional() };
|
|
190
|
+
/**
|
|
191
|
+
* A row somebody is WORKING — the population the stall clock watches.
|
|
192
|
+
*
|
|
193
|
+
* It was `/🚧/` alone, and that read a fleet living in review as an EMPTY
|
|
194
|
+
* fleet (q-507e80c4). Measured on a consumer fleet 2026-09-02: a board of 3× `🔍 In
|
|
195
|
+
* Review` and 0× `🚧` returned `checked: 0, measurable: 0`, and `coord_away`
|
|
196
|
+
* armed at 0/0 — correct and vacuous at once. A clock watching nothing and a
|
|
197
|
+
* clock watching a healthy fleet return identical green.
|
|
198
|
+
*
|
|
199
|
+
* `🔍 In Review` is a lane with an owner and a branch that can stop moving
|
|
200
|
+
* exactly as an authoring lane can; the review that never gets re-gated is
|
|
201
|
+
* THE stall shape of a QA-gated fleet. It is read here, on the row as written
|
|
202
|
+
* — relabelling `🔍`→`🚧` to satisfy the old predicate was the item's
|
|
203
|
+
* forbidden move, because it satisfies a guard by editing what it reads and
|
|
204
|
+
* reports authoring lanes that do not exist.
|
|
205
|
+
*
|
|
206
|
+
* NOT widened further, deliberately: `⏸ Parked`, `⏳ Queued`, `⛔ Blocked`,
|
|
207
|
+
* `🚫 Unstaffable`, `✅ Done` have no lane to stall. Widening to everything
|
|
208
|
+
* would be the 0/0 defect inverted.
|
|
209
|
+
*
|
|
210
|
+
* One predicate, exported: `coord_away` measures coverage by calling
|
|
211
|
+
* `stall_check` and reading `checked`/`measurable`, so it inherits this
|
|
212
|
+
* population without a change of its own. Anything else that asks "which rows
|
|
213
|
+
* are in flight" should ask here rather than re-derive it from a glyph.
|
|
214
|
+
*/
|
|
215
|
+
export const IN_FLIGHT_STATUS = /🚧|🔍/;
|
|
216
|
+
export const isInFlightStatus = (status) => IN_FLIGHT_STATUS.test(status);
|
|
217
|
+
export async function stallCheckTool(args) {
|
|
218
|
+
const repo = args.repo ?? process.cwd();
|
|
219
|
+
const limit = (args.stallMinutes ?? 30) * 60 * 1000;
|
|
220
|
+
const board = path.join(repo, BOARD_DOC);
|
|
221
|
+
if (!existsSync(board))
|
|
222
|
+
return { ok: false, error: `no ${BOARD_DOC} under '${repo}'` };
|
|
223
|
+
const liveTransports = await loadLiveTransports();
|
|
224
|
+
const rows = workstreamsV1RowsOf(parseWorkDoc(readFileSync(board, "utf8")));
|
|
225
|
+
const inFlight = rows.filter((r) => isInFlightStatus(r.status));
|
|
226
|
+
const reg = await readJson(AGENTS_FILE, {});
|
|
227
|
+
const now = Date.now();
|
|
228
|
+
const hits = [];
|
|
229
|
+
/** Rows whose VCS activity could not be measured. NOT stall claims. */
|
|
230
|
+
const unmeasurable = [];
|
|
231
|
+
/**
|
|
232
|
+
* Rows a predicate actually reached a VERDICT about — hit or clean.
|
|
233
|
+
*
|
|
234
|
+
* Tracked explicitly rather than inferred from "2 predicates minus the
|
|
235
|
+
* unmeasurable ones", because a predicate that is SKIPPED pushes no
|
|
236
|
+
* unmeasurable entry and the arithmetic then counts it as having measured.
|
|
237
|
+
* That is the same defect as the `continue` above, one level up: a silent
|
|
238
|
+
* skip and a clean pass produce the same number.
|
|
239
|
+
*/
|
|
240
|
+
const measured = new Set();
|
|
241
|
+
for (const row of inFlight) {
|
|
242
|
+
const agentId = row.owner.replace(/[`*]/g, "").trim();
|
|
243
|
+
const entry = reg[agentId];
|
|
244
|
+
if (!entry) {
|
|
245
|
+
// NOT SKIPPED IN SILENCE. An owner with no registry entry has no
|
|
246
|
+
// heartbeat to read, which is a missing signal and must be reported as
|
|
247
|
+
// one — a row whose owner the bus has never heard of is exactly the row
|
|
248
|
+
// you would want named before going away.
|
|
249
|
+
unmeasurable.push({ agentId, value: "", why: "no registry entry for this owner — there is no heartbeat to read, and the name may not be an agent id at all" });
|
|
250
|
+
}
|
|
251
|
+
if (entry) {
|
|
252
|
+
const age = now - entry.lastHeartbeat;
|
|
253
|
+
// A HEARTBEAT IS ONLY EVIDENCE WHERE SOMETHING WRITES ONE.
|
|
254
|
+
//
|
|
255
|
+
// `heartbeat` is called by the PUSHER, never by the agent. Only
|
|
256
|
+
// `coord-pusher.mjs` (the REMOTE pusher) calls it, and it must: a remote
|
|
257
|
+
// marker cannot be pid-probed across machines, so its liveness IS the
|
|
258
|
+
// heartbeat. `hooks/tmux-pusher.mjs` — what this fleet actually runs —
|
|
259
|
+
// never calls it, because a LOCAL marker's liveness is `isPidAlive`.
|
|
260
|
+
//
|
|
261
|
+
// So for a local transport there is no heartbeat SOURCE at all. Before
|
|
262
|
+
// kit#137, `list_agents` stamped these agents and that fabrication was
|
|
263
|
+
// the only thing keeping the field moving; removing it left the field
|
|
264
|
+
// honest and empty. Measured: three attached, working agents at an
|
|
265
|
+
// IDENTICAL 44.7m — the uniform signature of one shared cause, not three
|
|
266
|
+
// stalls.
|
|
267
|
+
//
|
|
268
|
+
// WHY NOT JUST MAKE tmux-pusher HEARTBEAT: because the signal would mean
|
|
269
|
+
// "the pusher process is alive", which `isPidAlive` already answers for
|
|
270
|
+
// local markers. During the 17-hour stall every transport was live the
|
|
271
|
+
// whole time, so a pusher heartbeat would have read FRESH for all 17
|
|
272
|
+
// hours. It would restore a field without restoring a detector — and the
|
|
273
|
+
// case this verb exists for is exactly the one it would miss. The vcs
|
|
274
|
+
// half is what catches "alive and not progressing"; saying so is more
|
|
275
|
+
// honest than a green field.
|
|
276
|
+
//
|
|
277
|
+
// Unknown is not stalled (kit#138). This does NOT narrow Task 3.5: an
|
|
278
|
+
// agent with no transport, or a REMOTE one where the heartbeat genuinely
|
|
279
|
+
// is the liveness mechanism, still HITs on a dead heartbeat.
|
|
280
|
+
const marker = liveTransports.get(agentId);
|
|
281
|
+
if (age > limit && marker && marker.transport === "tmux-push") {
|
|
282
|
+
unmeasurable.push({
|
|
283
|
+
agentId,
|
|
284
|
+
value: marker.transport,
|
|
285
|
+
why: `heartbeat is ${Math.round(age / 60000)}m old, but nothing writes heartbeats for a local 'tmux-push' transport — hooks/tmux-pusher.mjs does not call heartbeat, and this marker's liveness is its pid. There is no heartbeat SOURCE here, so the age measures nothing about this agent`,
|
|
286
|
+
});
|
|
287
|
+
// FALL THROUGH TO THE VCS PREDICATE — do not `continue`.
|
|
288
|
+
//
|
|
289
|
+
// This used to skip the row entirely, and the consequence was total: on
|
|
290
|
+
// this fleet, 3 of 3 in-flight rows were local tmux-push agents, so
|
|
291
|
+
// EVERY row exited here and the check reported `checked 3 · measurable
|
|
292
|
+
// 0`. The half that was blind (heartbeat, deliberately, for the reason
|
|
293
|
+
// above) was taking the half that works (vcs activity) down with it.
|
|
294
|
+
//
|
|
295
|
+
// The two predicates answer different questions and only one of them is
|
|
296
|
+
// unanswerable for a local transport. "Is it alive" has no source here;
|
|
297
|
+
// "is its branch moving" has a perfectly good one, and it is the half
|
|
298
|
+
// that catches the case this verb exists for — alive and not
|
|
299
|
+
// progressing. An unmeasurable heartbeat is a missing signal, not a
|
|
300
|
+
// reason to stop measuring the signal that is present.
|
|
301
|
+
}
|
|
302
|
+
else if (age > limit) {
|
|
303
|
+
hits.push({ kind: "no-heartbeat", agentId, stream: row.stream.slice(0, 60), minutes: Math.round(age / 60000) });
|
|
304
|
+
measured.add(agentId);
|
|
305
|
+
continue;
|
|
306
|
+
}
|
|
307
|
+
// A FRESH HEARTBEAT IS *NOT* A VERDICT, AND THIS IS A CORRECTION TO WHAT
|
|
308
|
+
// THIS CODE CLAIMED WHEN IT MERGED.
|
|
309
|
+
//
|
|
310
|
+
// It read "a fresh heartbeat IS a verdict — alive" and credited coverage
|
|
311
|
+
// for it. Measured since, by reading agents.json directly (`list_agents`
|
|
312
|
+
// refreshes the CALLER's mark, so it cannot be used to measure the
|
|
313
|
+
// caller): an agent's mark aged from 9611s to 9623s across a `post_status`
|
|
314
|
+
// call. BUS TOOL CALLS DO NOT WRITE HEARTBEATS.
|
|
315
|
+
//
|
|
316
|
+
// `heartbeat` age is TIME SINCE JOIN. Not activity, and not even
|
|
317
|
+
// time-since-restart — a server can restart mid-session without the mark
|
|
318
|
+
// moving, because nothing rejoined. So freshness says "recently joined",
|
|
319
|
+
// and crediting it as coverage lets `/coord-away` arm on a fleet whose
|
|
320
|
+
// only evidence is that somebody reconnected.
|
|
321
|
+
//
|
|
322
|
+
// The inverse is worse and is why this is not merely tidiness: reading
|
|
323
|
+
// age as activity marks the two most CONTINUOUSLY ACTIVE agents on a bus
|
|
324
|
+
// as stale at 2.6h, while a freshly-rejoined idle agent reads healthy —
|
|
325
|
+
// a false-stall generator aimed at exactly the agents that must not be
|
|
326
|
+
// false-stalled while nobody is watching.
|
|
327
|
+
//
|
|
328
|
+
// The HIT above is kept: for an agent with no transport at all, "has not
|
|
329
|
+
// rejoined and has no live marker" is still the death signal Task 3.5
|
|
330
|
+
// specifies. What is removed is the coverage credit for freshness, which
|
|
331
|
+
// leaves coverage resting on the vcs predicate — the one that measures
|
|
332
|
+
// something the agent DID.
|
|
333
|
+
}
|
|
334
|
+
// A FRESH HEARTBEAT IS NOT PROGRESS. An agent can be alive and stuck, which is
|
|
335
|
+
// the case "notice the room" never catches: the pane is responsive, so nobody
|
|
336
|
+
// looks. Ask the branch instead.
|
|
337
|
+
//
|
|
338
|
+
// RESOLVE A REF, AND SAY SO WHEN THE VALUE IS NOT ONE.
|
|
339
|
+
//
|
|
340
|
+
// `git log -1 <value>` accepts a PATHSPEC exactly as readily as a ref, and
|
|
341
|
+
// the old guard only required a `/` — which every path has. So the board's
|
|
342
|
+
// `Branch · Worktree` cells, which hold PATHS, were fed to git and silently
|
|
343
|
+
// measured as paths: the aide was reported at 2,271 minutes, the age of
|
|
344
|
+
// `docs/phases/phase5`'s last commit, not of any activity by that agent.
|
|
345
|
+
// Verified: `docs/phases/phase5` does not resolve as a ref, yet
|
|
346
|
+
// `git log -1 --format=%cI docs/phases/phase5` returns a date.
|
|
347
|
+
//
|
|
348
|
+
// Other rows read plausibly only by coincidence — a path that happens to be
|
|
349
|
+
// committed often looks like an active branch.
|
|
350
|
+
//
|
|
351
|
+
// UNKNOWN IS NOT STALLED, which this verb already gets right for
|
|
352
|
+
// heartbeats. An unresolvable value is REPORTED as unmeasurable rather than
|
|
353
|
+
// skipped in silence: a silent `continue` and a healthy agent produce the
|
|
354
|
+
// same output, which is the failure this whole verb exists to avoid.
|
|
355
|
+
// ONE CLASSIFIER, SHARED WITH `claim` (board-ref.ts). The old block asked
|
|
356
|
+
// only "does it resolve", and three of the four ways this cell has been
|
|
357
|
+
// wrong resolved cleanly — a shared ref, a local-only ref, and a merged
|
|
358
|
+
// ref. Resolution was never the property; the property is whether the ref's
|
|
359
|
+
// movement is THIS AGENT'S WORK.
|
|
360
|
+
const verdict = classifyBoardRef(repo, agentId, row.branchWorktree);
|
|
361
|
+
if (verdict.kind === "merged") {
|
|
362
|
+
// A VERDICT, NOT AN ABSENCE — and it counts as coverage, because the check
|
|
363
|
+
// did learn something about this lane: its work landed and its row is
|
|
364
|
+
// stale. Reported as its own kind rather than as a stall, which is what
|
|
365
|
+
// the frozen ref was reporting it as.
|
|
366
|
+
hits.push({ kind: "stale-row", agentId, branch: refInCell(row.branchWorktree), why: verdict.why });
|
|
367
|
+
measured.add(agentId);
|
|
368
|
+
continue;
|
|
369
|
+
}
|
|
370
|
+
if (verdict.kind !== "measurable") {
|
|
371
|
+
unmeasurable.push({ agentId, value: refInCell(row.branchWorktree), why: verdict.why });
|
|
372
|
+
continue;
|
|
373
|
+
}
|
|
374
|
+
try {
|
|
375
|
+
// The resolved SHA, and `--`: a ref can then never be re-read as a
|
|
376
|
+
// pathspec, which is the ambiguity that produced the wrong number.
|
|
377
|
+
const sha = execFileSync("git", ["rev-parse", "--verify", "--quiet", `${verdict.ref}^{commit}`], {
|
|
378
|
+
cwd: repo, encoding: "utf8", stdio: ["ignore", "pipe", "ignore"],
|
|
379
|
+
}).trim();
|
|
380
|
+
const iso = execFileSync("git", ["log", "-1", "--format=%cI", sha, "--"], {
|
|
381
|
+
cwd: repo, encoding: "utf8", stdio: ["ignore", "pipe", "ignore"],
|
|
382
|
+
}).trim();
|
|
383
|
+
const age = now - Date.parse(iso);
|
|
384
|
+
measured.add(agentId);
|
|
385
|
+
if (age > limit) {
|
|
386
|
+
hits.push({ kind: "no-vcs-activity", agentId, branch: verdict.ref, minutes: Math.round(age / 60000) });
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
catch {
|
|
390
|
+
unmeasurable.push({ agentId, value: verdict.ref, why: "resolved as a ref but its log could not be read" });
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
// COVERAGE, not "did it run". A row is COVERED when a predicate produced a
|
|
394
|
+
// verdict about it; a row where every predicate came back unmeasurable was
|
|
395
|
+
// looked at and not measured, and counting it as checked is how "the clock
|
|
396
|
+
// ran" gets mistaken for "the fleet is observed".
|
|
397
|
+
const owners = inFlight.map((r) => r.owner.replace(/[`*]/g, "").trim()).filter(Boolean);
|
|
398
|
+
const blind = [...new Set(owners)].filter((id) => !measured.has(id));
|
|
399
|
+
const measurable = Math.max(0, inFlight.length - blind.length);
|
|
400
|
+
const result = { hits, checked: inFlight.length, unmeasurable, measurable, blind };
|
|
401
|
+
markRun({ hits, checked: inFlight.length, measurable });
|
|
402
|
+
return {
|
|
403
|
+
ok: true,
|
|
404
|
+
...result,
|
|
405
|
+
halted: haltState().halted,
|
|
406
|
+
// MISS is silent to the DUTY OFFICER — the caller decides whether to DM — and
|
|
407
|
+
// never silent to the record, which markRun just wrote.
|
|
408
|
+
dm: hits.length > 0,
|
|
409
|
+
note: hits.length === 0
|
|
410
|
+
? `MISS — ${inFlight.length} in-flight row(s), none stalled${unmeasurable.length ? `; ${unmeasurable.length} row(s) UNMEASURABLE for VCS activity (${unmeasurable.map((u) => u.agentId).join(", ")}) — reported, not counted as healthy` : ""}. No DM. The run IS recorded: read it with stall_clock_status, because no alert and nothing running look identical from here.`
|
|
411
|
+
: undefined,
|
|
412
|
+
};
|
|
413
|
+
}
|
|
414
|
+
//# sourceMappingURL=stall.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stall.js","sourceRoot":"","sources":["../../src/tools/stall.ts"],"names":[],"mappings":"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"}
|