@groundnuty/macf-channel-server 0.2.38 → 0.2.39

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.
@@ -64,6 +64,14 @@ export type CollisionResult = {
64
64
  * over the existing ping→decide→register sequence — two racing newer instances
65
65
  * degrade to the same race the current `variable_exists` check already has.
66
66
  *
67
+ * Complementary staleness signal (DR-031, groundnuty/macf#568): when the quadrant
68
+ * above would ABORT against a /health-answering peer but that peer's registry
69
+ * `last_heartbeat` has aged past the TTL, the entry is taken over anyway — the
70
+ * stale heartbeat is a SECOND, version-independent liveness signal that resolves
71
+ * the just-killed-port ambiguity (#553) toward "dead". It is purely additive: it
72
+ * only ever turns a would-abort into a takeover, never the reverse, and a fresh or
73
+ * absent heartbeat leaves the quadrant's decision exactly as-is.
74
+ *
67
75
  * @param incomingVersion this instance's channel-server version (PACKAGE_VERSION).
68
76
  */
69
77
  export declare function checkCollision(name: string, registry: Registry, certPaths: {
@@ -1 +1 @@
1
- {"version":3,"file":"collision.d.ts","sourceRoot":"","sources":["../src/collision.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AACjE,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,uBAAuB,CAAC;AACpD,OAAO,EAAE,SAAS,EAAiB,MAAM,uBAAuB,CAAC;AAKjE,qBAAa,cAAe,SAAQ,SAAS;gBAC/B,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM;CAQrD;AAED;;;;;;;GAOG;AACH,qBAAa,iBAAkB,SAAQ,SAAS;gBAClC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,SAAS,GAAG,IAAI;CAYpD;AA2BD;;0EAE0E;AAC1E,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;IACxB,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;CACjC;AA2GD,MAAM,MAAM,eAAe,GACvB;IAAE,QAAQ,CAAC,MAAM,EAAE,UAAU,CAAA;CAAE,GAC/B;IAAE,QAAQ,CAAC,MAAM,EAAE,UAAU,CAAC;IAAC,QAAQ,CAAC,QAAQ,EAAE,SAAS,CAAA;CAAE,GAC7D;IAAE,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,QAAQ,EAAE,SAAS,CAAA;CAAE,CAAC;AAE/D;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AACH,wBAAsB,cAAc,CAClC,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,QAAQ,EAClB,SAAS,EAAE;IACT,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;CAC/B,EACD,eAAe,EAAE,MAAM,EACvB,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,eAAe,CAAC,CAgF1B"}
1
+ {"version":3,"file":"collision.d.ts","sourceRoot":"","sources":["../src/collision.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AACjE,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,uBAAuB,CAAC;AACpD,OAAO,EAAE,SAAS,EAAwD,MAAM,uBAAuB,CAAC;AAKxG,qBAAa,cAAe,SAAQ,SAAS;gBAC/B,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM;CAQrD;AAED;;;;;;;GAOG;AACH,qBAAa,iBAAkB,SAAQ,SAAS;gBAClC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,SAAS,GAAG,IAAI;CAYpD;AA2BD;;0EAE0E;AAC1E,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;IACxB,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;CACjC;AA2GD,MAAM,MAAM,eAAe,GACvB;IAAE,QAAQ,CAAC,MAAM,EAAE,UAAU,CAAA;CAAE,GAC/B;IAAE,QAAQ,CAAC,MAAM,EAAE,UAAU,CAAC;IAAC,QAAQ,CAAC,QAAQ,EAAE,SAAS,CAAA;CAAE,GAC7D;IAAE,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,QAAQ,EAAE,SAAS,CAAA;CAAE,CAAC;AAE/D;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA0CG;AACH,wBAAsB,cAAc,CAClC,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,QAAQ,EAClB,SAAS,EAAE;IACT,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;CAC/B,EACD,eAAe,EAAE,MAAM,EACvB,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,eAAe,CAAC,CAmH1B"}
package/dist/collision.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import { request } from 'node:https';
2
2
  import { readFileSync } from 'node:fs';
3
- import { MacfError, compareSemver } from '@groundnuty/macf-core';
3
+ import { MacfError, compareSemver, isStaleEntry, DEFAULT_REGISTRY_TTL_MS } from '@groundnuty/macf-core';
4
4
  /** Matches a parseable `x.y.z` (optional leading `v`) version string. */
5
5
  const VERSION_PATTERN = /^v?\d+\.\d+\.\d+$/;
6
6
  export class CollisionError extends MacfError {
@@ -173,6 +173,14 @@ async function confirmLiveness(host, port, caCertPath, agentCertPath, agentKeyPa
173
173
  * over the existing ping→decide→register sequence — two racing newer instances
174
174
  * degrade to the same race the current `variable_exists` check already has.
175
175
  *
176
+ * Complementary staleness signal (DR-031, groundnuty/macf#568): when the quadrant
177
+ * above would ABORT against a /health-answering peer but that peer's registry
178
+ * `last_heartbeat` has aged past the TTL, the entry is taken over anyway — the
179
+ * stale heartbeat is a SECOND, version-independent liveness signal that resolves
180
+ * the just-killed-port ambiguity (#553) toward "dead". It is purely additive: it
181
+ * only ever turns a would-abort into a takeover, never the reverse, and a fresh or
182
+ * absent heartbeat leaves the quadrant's decision exactly as-is.
183
+ *
176
184
  * @param incomingVersion this instance's channel-server version (PACKAGE_VERSION).
177
185
  */
178
186
  export async function checkCollision(name, registry, certPaths, incomingVersion, logger) {
@@ -239,6 +247,39 @@ export async function checkCollision(name, registry, certPaths, incomingVersion,
239
247
  });
240
248
  if (takeover)
241
249
  return { action: 'takeover', previous: existing };
250
+ // DR-031 (groundnuty/macf#568) — COMPLEMENTARY staleness override. PURELY
251
+ // ADDITIVE and ONE-DIRECTIONAL: it can only turn a would-ABORT into a
252
+ // takeover, never the reverse. The #424 version quadrant + #553 confirmLiveness
253
+ // above are byte-for-byte unchanged; we only reach here when that quadrant
254
+ // already decided to ABORT against a peer that answered /health on EVERY
255
+ // confirm ping. The registry heartbeat (#589) re-stamps `last_heartbeat` on a
256
+ // coarse cadence, so an entry whose heartbeat aged past the TTL is almost
257
+ // certainly a DEAD instance whose freed/recycled port merely still answers (the
258
+ // #553 just-killed-port race, or a zombie squatting the port) — the stale
259
+ // signal resolves that ambiguity toward "dead → take over", exactly as the
260
+ // dead-`/health` path below already does (which likewise ignores the version
261
+ // policy). Safety: this can ONLY add a takeover, never block one — a FRESH
262
+ // heartbeat leaves the abort exactly as the quadrant decided, and an ABSENT or
263
+ // unparseable `last_heartbeat` is NEVER stale (`isStaleEntry` returns false), so
264
+ // pre-DR-031 entries and heartbeat-disabled-but-live instances take the
265
+ // unchanged path. A genuinely-live instance keeps its heartbeat fresh (it beats
266
+ // every cadence) and registration itself writes no heartbeat — so the only way
267
+ // to be stale here is to have beaten once and then stopped (the ungraceful
268
+ // death this backstops). The TTL slack (3× the 5-min cadence) prevents a
269
+ // healthy-but-briefly-unlucky instance from being judged stale.
270
+ if (isStaleEntry(existing, DEFAULT_REGISTRY_TTL_MS, Date.now())) {
271
+ logger.warn('collision_check', {
272
+ result: 'takeover_stale_heartbeat',
273
+ agent: name,
274
+ prior_basis: basis,
275
+ incoming_version: incomingVersion,
276
+ existing_version: existingVersion,
277
+ last_heartbeat: existing.last_heartbeat ?? null,
278
+ host: existing.host,
279
+ port: existing.port,
280
+ });
281
+ return { action: 'takeover', previous: existing };
282
+ }
242
283
  return { action: 'abort', existing };
243
284
  }
244
285
  logger.info('collision_check', {
@@ -1 +1 @@
1
- {"version":3,"file":"collision.js","sourceRoot":"","sources":["../src/collision.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"collision.js","sourceRoot":"","sources":["../src/collision.ts"],"names":[],"mappings":"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"}
@@ -184,6 +184,83 @@ export declare function backfillProcessed(edges: readonly CommsLedgerEdge[], rec
184
184
  * read, not the authoritative write.
185
185
  */
186
186
  export declare function mergeLedgers(contents: readonly string[]): CommsLedgerEdge[];
187
+ /** Receipt-sink filename (sibling of `channel.log`); the local turn-receipt log. */
188
+ export declare const RECEIPT_SINK_FILENAME = "processed-receipts.jsonl";
189
+ /**
190
+ * Derive the receipt-sink path from the channel-server's `logPath` (`MACF_LOG_PATH`),
191
+ * as a sibling file in the same `.macf/logs/` directory — parallel to
192
+ * `ledgerPathFromLog`. `undefined` when no log path is configured (then
193
+ * `last_processed` is null: there is no sink to read). This is the SAME path the
194
+ * `emit-turn-receipt.sh` hook writes to (`$(dirname MACF_LOG_PATH)/<filename>`).
195
+ */
196
+ export declare function receiptSinkPathFromLog(logPath: string | undefined): string | undefined;
197
+ /**
198
+ * One local turn-receipt line, written by `emit-turn-receipt.sh` (one per routed
199
+ * marker the agent processed in a turn). The compact wire form is exactly
200
+ * `{"ts":<epoch-ms>,"run_id":"<run_id>","agent":"<agent>"}`.
201
+ */
202
+ export declare const ProcessedReceiptSchema: z.ZodObject<{
203
+ ts: z.ZodNumber;
204
+ run_id: z.ZodString;
205
+ agent: z.ZodString;
206
+ }, z.core.$strip>;
207
+ export type ProcessedReceipt = z.infer<typeof ProcessedReceiptSchema>;
208
+ /** The `/health` `last_processed` self-report shape (DR-030 passive-Processed tier). */
209
+ export interface LastProcessedReport {
210
+ /** ISO-8601 timestamp of the most-recent turn-receipt (null if none/unparseable). */
211
+ readonly at: string | null;
212
+ /**
213
+ * GitHub anchor (owner/repo#N). Always `null` for the receipt sink — a turn
214
+ * receipt carries no github_anchor. The field stays in the shape for back-compat
215
+ * with the schema (and a future ledger-join view that could populate it).
216
+ */
217
+ readonly anchor: string | null;
218
+ /** now − ts, clamped ≥ 0; null when `at` is absent or `ts` is non-finite. */
219
+ readonly age_ms: number | null;
220
+ /**
221
+ * The receipt's `run_id` — THE `--inject` CONTRACT. An injector routes a prompt
222
+ * carrying a known `run_id` in its `[macf-route:<run_id>:<agent>]` marker, lets
223
+ * the agent process it in a turn, then reads `/health` and matches this
224
+ * `correlation_token` to confirm ITS OWN message was processed.
225
+ */
226
+ readonly correlation_token: string | null;
227
+ }
228
+ /**
229
+ * Parse a receipt-sink file's text into receipts, tolerantly: blank + malformed
230
+ * lines (incl. a torn final line mid-append) are skipped, never fatal — a corrupt
231
+ * line must not blind the read. Same posture as `mergeLedgers`.
232
+ */
233
+ export declare function parseReceipts(content: string): ProcessedReceipt[];
234
+ /**
235
+ * Select the most-recent receipt (max `ts`), or null when there are none.
236
+ * Single-pass max-`ts` (not a sort) — cheap on the infrequent `/health` path. On
237
+ * equal `ts`, the first-seen wins (a benign tie). Max-`ts` (rather than just the
238
+ * last line) is robust to out-of-order lines under clock skew.
239
+ */
240
+ export declare function selectLastReceipt(receipts: readonly ProcessedReceipt[]): ProcessedReceipt | null;
241
+ /**
242
+ * Map a selected receipt (or null) into the `last_processed` `/health` shape.
243
+ * `at` ← ISO-8601 of the receipt's epoch-ms `ts`; `correlation_token` ← `run_id`
244
+ * (the `--inject` contract); `anchor` ← null (the sink carries no github_anchor);
245
+ * `age_ms` ← now − ts, clamped ≥ 0. A non-finite `ts` yields `at: null` + `age_ms: null`.
246
+ */
247
+ export declare function mapReceiptToLastProcessed(receipt: ProcessedReceipt | null, now: number): LastProcessedReport | null;
248
+ /**
249
+ * Read the agent's most-recent turn-receipt from the receipt sink and map it to
250
+ * the `/health` `last_processed` self-report. NEVER throws — an unset/missing/
251
+ * unreadable/garbage sink (or any read/parse error) degrades to `null`, so it can
252
+ * never break `/health`. Inject `readReceipts` in tests to skip the file entirely.
253
+ *
254
+ * Perf: reads the whole jsonl on each call. A `/health` ping is infrequent and the
255
+ * sink is operator-rotated like the ledger (see `ROTATION_POLICY`), so a bounded
256
+ * full read is fine; a tail-scan optimisation is possible if it ever grows unbounded.
257
+ */
258
+ export declare function readLastProcessed(opts: {
259
+ readonly logPath?: string | undefined;
260
+ readonly receiptSinkPath?: string | undefined;
261
+ readonly now: number;
262
+ readonly readReceipts?: () => readonly ProcessedReceipt[];
263
+ }): LastProcessedReport | null;
187
264
  /**
188
265
  * Rotation/retention policy (DR-025 §"Costs", "no silent caps"):
189
266
  *
@@ -1 +1 @@
1
- {"version":3,"file":"comms-ledger.d.ts","sourceRoot":"","sources":["../src/comms-ledger.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH;;;;GAIG;AACH,eAAO,MAAM,gBAAgB;;;;;;;;EAU3B,CAAC;AACH,MAAM,MAAM,UAAU,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,gBAAgB,CAAC,CAAC;AAE1D,eAAO,MAAM,kBAAkB;;;EAAkC,CAAC;AAClE,MAAM,MAAM,YAAY,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,kBAAkB,CAAC,CAAC;AAE9D,eAAO,MAAM,oBAAoB;;;EAA2B,CAAC;AAC7D,MAAM,MAAM,cAAc,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,oBAAoB,CAAC,CAAC;AAElE;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,qBAAqB;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAahC,CAAC;AACH,MAAM,MAAM,eAAe,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,qBAAqB,CAAC,CAAC;AAEpE,2DAA2D;AAC3D,eAAO,MAAM,kBAAkB,MAAM,CAAC;AAEtC;;;;;;GAMG;AACH,wBAAgB,aAAa,CAC3B,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EAC/B,GAAG,GAAE,MAA2B,GAC/B,MAAM,CAUR;AAED,+EAA+E;AAC/E,eAAO,MAAM,qBAAqB,uBAAuB,CAAC;AAE1D;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS,CAGjF;AAED,MAAM,WAAW,WAAW;IAC1B;;;;;;;;;OASG;IACH,QAAQ,CAAC,UAAU,EAAE,CAAC,IAAI,EAAE,eAAe,KAAK,IAAI,CAAC;IACrD,yEAAyE;IACzE,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,CAAC;CACnC;AASD;;;;;;;;;;;;GAYG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE;IACtC,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACtC,oDAAoD;IACpD,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAC1C,GAAG,WAAW,CAkBd;AAED;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAgB,iBAAiB,CAC/B,KAAK,EAAE,SAAS,eAAe,EAAE,EACjC,WAAW,EAAE,WAAW,CAAC,MAAM,CAAC,EAChC,KAAK,EAAE,CAAC,IAAI,EAAE,eAAe,KAAK,MAAM,GACvC,eAAe,EAAE,CAInB;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,YAAY,CAAC,QAAQ,EAAE,SAAS,MAAM,EAAE,GAAG,eAAe,EAAE,CAW3E;AAYD;;;;;;;;;GASG;AACH,eAAO,MAAM,eAAe,EAAG,4CAAqD,CAAC"}
1
+ {"version":3,"file":"comms-ledger.d.ts","sourceRoot":"","sources":["../src/comms-ledger.ts"],"names":[],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import { appendFileSync, existsSync, mkdirSync, writeFileSync } from 'node:fs';
1
+ import { appendFileSync, existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
2
2
  import { dirname, join } from 'node:path';
3
3
  import { z } from 'zod';
4
4
  /**
@@ -210,6 +210,138 @@ function safeJson(line) {
210
210
  return '{}';
211
211
  }
212
212
  }
213
+ // --- DR-030 phase-1 (groundnuty/macf#568): last_processed via the RECEIPT SINK ---
214
+ //
215
+ // The `/health` `last_processed` field is the agent's passive-Processed
216
+ // self-report: "I processed a routed coordination message at time T", proven
217
+ // LOCALLY with no synthetic injection (DR-030 §3 "Passive-Processed tier").
218
+ //
219
+ // THE LOCAL "PROCESSED" SOURCE IS THE RECEIPT SINK, not the comms-ledger.
220
+ // When the router injects a prompt it appends a `[macf-route:<run_id>:<agent>]`
221
+ // marker (macf-actions#45); the `emit-turn-receipt.sh` UserPromptSubmit hook
222
+ // fires when that prompt is submitted AS A TURN and — alongside the OTLP
223
+ // `turn_processed` span (which feeds Tempo + the #444 reconciler) — appends one
224
+ // receipt line per marker to `processed-receipts.jsonl` (a sibling of
225
+ // `channel.log`, see `receiptSinkPathFromLog`). THAT local append is the proof a
226
+ // turn happened, and it is what this reader surfaces — making the passive tier a
227
+ // real LOCAL self-report rather than a Tempo-only one (the keystone of #568).
228
+ //
229
+ // Why NOT the comms-ledger's `processed` field: every edge site writes
230
+ // `processed: null` — the delivery≠turn join is a DERIVED view (`backfillProcessed`
231
+ // / the #444 reconciler), never written back to the append-only ledger (DR-025).
232
+ // So a `recv` + `processed:true` edge never exists on disk and a ledger scan is
233
+ // always null. The ledger stays the authoritative edge record; this sink is the
234
+ // separate, purpose-built local "I took a turn" proof.
235
+ /** Receipt-sink filename (sibling of `channel.log`); the local turn-receipt log. */
236
+ export const RECEIPT_SINK_FILENAME = 'processed-receipts.jsonl';
237
+ /**
238
+ * Derive the receipt-sink path from the channel-server's `logPath` (`MACF_LOG_PATH`),
239
+ * as a sibling file in the same `.macf/logs/` directory — parallel to
240
+ * `ledgerPathFromLog`. `undefined` when no log path is configured (then
241
+ * `last_processed` is null: there is no sink to read). This is the SAME path the
242
+ * `emit-turn-receipt.sh` hook writes to (`$(dirname MACF_LOG_PATH)/<filename>`).
243
+ */
244
+ export function receiptSinkPathFromLog(logPath) {
245
+ if (!logPath)
246
+ return undefined;
247
+ return join(dirname(logPath), RECEIPT_SINK_FILENAME);
248
+ }
249
+ /**
250
+ * One local turn-receipt line, written by `emit-turn-receipt.sh` (one per routed
251
+ * marker the agent processed in a turn). The compact wire form is exactly
252
+ * `{"ts":<epoch-ms>,"run_id":"<run_id>","agent":"<agent>"}`.
253
+ */
254
+ export const ProcessedReceiptSchema = z.object({
255
+ /** Epoch milliseconds at which the routed prompt was submitted as a turn. */
256
+ ts: z.number(),
257
+ /** The router run id from the `[macf-route:<run_id>:<agent>]` marker. */
258
+ run_id: z.string().min(1),
259
+ /** The kebab agent name from the marker. */
260
+ agent: z.string().min(1),
261
+ });
262
+ /**
263
+ * Parse a receipt-sink file's text into receipts, tolerantly: blank + malformed
264
+ * lines (incl. a torn final line mid-append) are skipped, never fatal — a corrupt
265
+ * line must not blind the read. Same posture as `mergeLedgers`.
266
+ */
267
+ export function parseReceipts(content) {
268
+ const out = [];
269
+ for (const raw of content.split('\n')) {
270
+ const line = raw.trim();
271
+ if (!line)
272
+ continue;
273
+ let json;
274
+ try {
275
+ json = JSON.parse(line);
276
+ }
277
+ catch {
278
+ continue;
279
+ }
280
+ const parsed = ProcessedReceiptSchema.safeParse(json);
281
+ if (parsed.success)
282
+ out.push(parsed.data);
283
+ }
284
+ return out;
285
+ }
286
+ /**
287
+ * Select the most-recent receipt (max `ts`), or null when there are none.
288
+ * Single-pass max-`ts` (not a sort) — cheap on the infrequent `/health` path. On
289
+ * equal `ts`, the first-seen wins (a benign tie). Max-`ts` (rather than just the
290
+ * last line) is robust to out-of-order lines under clock skew.
291
+ */
292
+ export function selectLastReceipt(receipts) {
293
+ let best = null;
294
+ for (const r of receipts) {
295
+ if (best === null || r.ts > best.ts)
296
+ best = r;
297
+ }
298
+ return best;
299
+ }
300
+ /**
301
+ * Map a selected receipt (or null) into the `last_processed` `/health` shape.
302
+ * `at` ← ISO-8601 of the receipt's epoch-ms `ts`; `correlation_token` ← `run_id`
303
+ * (the `--inject` contract); `anchor` ← null (the sink carries no github_anchor);
304
+ * `age_ms` ← now − ts, clamped ≥ 0. A non-finite `ts` yields `at: null` + `age_ms: null`.
305
+ */
306
+ export function mapReceiptToLastProcessed(receipt, now) {
307
+ if (receipt === null)
308
+ return null;
309
+ const finite = Number.isFinite(receipt.ts);
310
+ return {
311
+ at: finite ? new Date(receipt.ts).toISOString() : null,
312
+ anchor: null,
313
+ age_ms: finite ? Math.max(0, Math.floor(now - receipt.ts)) : null,
314
+ correlation_token: receipt.run_id,
315
+ };
316
+ }
317
+ /**
318
+ * Read the agent's most-recent turn-receipt from the receipt sink and map it to
319
+ * the `/health` `last_processed` self-report. NEVER throws — an unset/missing/
320
+ * unreadable/garbage sink (or any read/parse error) degrades to `null`, so it can
321
+ * never break `/health`. Inject `readReceipts` in tests to skip the file entirely.
322
+ *
323
+ * Perf: reads the whole jsonl on each call. A `/health` ping is infrequent and the
324
+ * sink is operator-rotated like the ledger (see `ROTATION_POLICY`), so a bounded
325
+ * full read is fine; a tail-scan optimisation is possible if it ever grows unbounded.
326
+ */
327
+ export function readLastProcessed(opts) {
328
+ try {
329
+ let receipts;
330
+ if (opts.readReceipts) {
331
+ receipts = opts.readReceipts();
332
+ }
333
+ else {
334
+ const path = opts.receiptSinkPath ?? receiptSinkPathFromLog(opts.logPath);
335
+ if (!path || !existsSync(path))
336
+ return null;
337
+ receipts = parseReceipts(readFileSync(path, 'utf8'));
338
+ }
339
+ return mapReceiptToLastProcessed(selectLastReceipt(receipts), opts.now);
340
+ }
341
+ catch {
342
+ return null;
343
+ }
344
+ }
213
345
  /**
214
346
  * Rotation/retention policy (DR-025 §"Costs", "no silent caps"):
215
347
  *
@@ -1 +1 @@
1
- {"version":3,"file":"comms-ledger.js","sourceRoot":"","sources":["../src/comms-ledger.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,UAAU,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAC/E,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH;;;;GAIG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,CAAC,IAAI,CAAC;IACrC,8DAA8D;IAC9D,eAAe;IACf,aAAa;IACb,OAAO;IACP,QAAQ;IACR,qDAAqD;IACrD,cAAc;IACd,SAAS;IACT,iBAAiB;CAClB,CAAC,CAAC;AAGH,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,cAAc,CAAC,CAAC,CAAC;AAGlE,MAAM,CAAC,MAAM,oBAAoB,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;AAG7D;;;;;;;;;;;;;GAaG;AACH,MAAM,CAAC,MAAM,qBAAqB,GAAG,CAAC,CAAC,MAAM,CAAC;IAC5C,EAAE,EAAE,CAAC,CAAC,MAAM,EAAE,EAAE,WAAW;IAC3B,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE;IAChB,EAAE,EAAE,CAAC,CAAC,MAAM,EAAE;IACd,OAAO,EAAE,kBAAkB;IAC3B,KAAK,EAAE,gBAAgB;IACvB,SAAS,EAAE,oBAAoB;IAC/B,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE;IAClB,cAAc,EAAE,CAAC,CAAC,MAAM,EAAE;IAC1B,aAAa,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IACpC,SAAS,EAAE,CAAC,CAAC,OAAO,EAAE;IACtB,SAAS,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE;IACjC,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE;CACrB,CAAC,CAAC;AAGH,2DAA2D;AAC3D,MAAM,CAAC,MAAM,kBAAkB,GAAG,GAAG,CAAC;AAEtC;;;;;;GAMG;AACH,MAAM,UAAU,aAAa,CAC3B,IAA+B,EAC/B,MAAc,kBAAkB;IAEhC,IAAI,CAAC,IAAI;QAAE,OAAO,EAAE,CAAC;IACrB,MAAM,SAAS,GACb,IAAI;SACD,KAAK,CAAC,IAAI,CAAC;SACX,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;SACpB,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC;IACrC,IAAI,SAAS,CAAC,MAAM,IAAI,GAAG;QAAE,OAAO,SAAS,CAAC;IAC9C,iFAAiF;IACjF,OAAO,SAAS,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,GAAG,CAAC,CAAC,GAAG,GAAG,CAAC;AAC3C,CAAC;AAED,+EAA+E;AAC/E,MAAM,CAAC,MAAM,qBAAqB,GAAG,oBAAoB,CAAC;AAE1D;;;;;GAKG;AACH,MAAM,UAAU,iBAAiB,CAAC,OAA2B;IAC3D,IAAI,CAAC,OAAO;QAAE,OAAO,SAAS,CAAC;IAC/B,OAAO,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,qBAAqB,CAAC,CAAC;AACvD,CAAC;AAkBD,MAAM,WAAW,GAAgB;IAC/B,UAAU,EAAE,GAAG,EAAE;QACf,0EAA0E;IAC5E,CAAC;IACD,IAAI,EAAE,SAAS;CAChB,CAAC;AAEF;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,iBAAiB,CAAC,IAIjC;IACC,MAAM,UAAU,GAAG,IAAI,CAAC,UAAU,IAAI,iBAAiB,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IACtE,IAAI,CAAC,UAAU;QAAE,OAAO,WAAW,CAAC;IAEpC,MAAM,GAAG,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;IAChC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC;QAAE,SAAS,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC1D,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC;QAAE,aAAa,CAAC,UAAU,EAAE,EAAE,CAAC,CAAC;IAE3D,OAAO;QACL,IAAI,EAAE,UAAU;QAChB,UAAU,EAAE,CAAC,IAAqB,EAAQ,EAAE;YAC1C,sEAAsE;YACtE,yEAAyE;YACzE,4DAA4D;YAC5D,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,qBAAqB,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC;YAC/D,cAAc,CAAC,UAAU,EAAE,IAAI,GAAG,IAAI,CAAC,CAAC;QAC1C,CAAC;KACF,CAAC;AACJ,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,MAAM,UAAU,iBAAiB,CAC/B,KAAiC,EACjC,WAAgC,EAChC,KAAwC;IAExC,OAAO,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CACrB,CAAC,CAAC,SAAS,KAAK,IAAI,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,SAAS,EAAE,WAAW,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAC1E,CAAC;AACJ,CAAC;AAED;;;;;;;;;;;;;;;GAeG;AACH,MAAM,UAAU,YAAY,CAAC,QAA2B;IACtD,MAAM,KAAK,GAAsB,EAAE,CAAC;IACpC,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;QAC/B,KAAK,MAAM,GAAG,IAAI,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;YACtC,MAAM,IAAI,GAAG,GAAG,CAAC,IAAI,EAAE,CAAC;YACxB,IAAI,CAAC,IAAI;gBAAE,SAAS;YACpB,MAAM,MAAM,GAAG,qBAAqB,CAAC,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YAC3E,IAAI,MAAM,CAAC,OAAO;gBAAE,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;QAC9C,CAAC;IACH,CAAC;IACD,OAAO,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACxE,CAAC;AAED,0FAA0F;AAC1F,SAAS,QAAQ,CAAC,IAAY;IAC5B,IAAI,CAAC;QACH,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QACjB,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,CAAC,MAAM,eAAe,GAAG,4CAAqD,CAAC"}
1
+ {"version":3,"file":"comms-ledger.js","sourceRoot":"","sources":["../src/comms-ledger.ts"],"names":[],"mappings":"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"}
package/dist/health.d.ts CHANGED
@@ -1,3 +1,107 @@
1
- import type { HealthState } from '@groundnuty/macf-core';
2
- export declare function createHealthState(agentName: string, agentType: string): HealthState;
1
+ import type { HealthResponse, HealthState } from '@groundnuty/macf-core';
2
+ import { type ProcessedReceipt } from './comms-ledger.js';
3
+ /**
4
+ * Hard version contract for the `/health` body SHAPE (DR-006 watchdog request,
5
+ * macf-devops-toolkit#115). A consumer asserts `health_schema_version === <known>`
6
+ * and refuses an unknown, so it fails LOUD on ANY breaking change to the
7
+ * `/health` shape — including a same-name SEMANTIC change (e.g. `last_processed.age_ms`
8
+ * meaning, an `at` rename) that additive-optional + presence-checks silently miss.
9
+ * BUMP on any breaking change to the `/health` shape; additive-optional fields do NOT
10
+ * bump it. Distinct from the package `version` (which bumps on every cs release).
11
+ */
12
+ export declare const HEALTH_SCHEMA_VERSION = 1;
13
+ /** The DR-030 `/health` `state` object shape (non-null), derived from the schema. */
14
+ type TurnStateReport = NonNullable<HealthResponse['state']>;
15
+ /**
16
+ * Parse a leaf-cert PEM and return its `notAfter` as an ISO-8601 string, or
17
+ * `null` if the PEM can't be parsed. DR-030 §4 per-agent `cert_expiry`
18
+ * self-report (an expired leaf = silent off-channels; thresholds — warn <30d
19
+ * / crit <7d — are the consumer's call). Uses `node:crypto` (zero-dep):
20
+ * `@peculiar/x509` is only needed to *create* X.509, not to read one.
21
+ */
22
+ export declare function leafCertExpiry(pem: string): string | null;
23
+ /**
24
+ * Map a parsed turn-state marker into the `/health` `state` object, computing
25
+ * `elapsed_ms` against `now` (so it stays fresh through a long, e.g. 20-minute,
26
+ * tool wait). Lenient by construction: the marker is written by an external hook,
27
+ * so any missing/wrong-typed field degrades to `null` rather than throwing, and a
28
+ * marker missing the required `status`/`turn_number` shape maps to `state: null`.
29
+ *
30
+ * elapsed_ms = status === 'busy' ? max(0, now − started_at) : 0
31
+ */
32
+ export declare function mapTurnStateMarker(raw: unknown, now: number): TurnStateReport | null;
33
+ /**
34
+ * Compute the static parts of the `otel` self-report from `process.env`.
35
+ *
36
+ * `endpoint_is_canonical` is **env-driven by design** — we deliberately do NOT
37
+ * hardcode the monitoring-VM host in channel-server code (it would drift the day
38
+ * the fleet's canonical endpoint moves). Instead "canonical" means "the live
39
+ * `OTEL_EXPORTER_OTLP_ENDPOINT` equals `MACF_OTEL_ENDPOINT`", the same env that
40
+ * `macf init`/`update` bake as the canonical default. So: false when no endpoint
41
+ * is set, false when `MACF_OTEL_ENDPOINT` is unset (nothing to be canonical
42
+ * against), false when they differ, true only when they're set + equal.
43
+ */
44
+ export declare function computeOtelEndpointInfo(env: NodeJS.ProcessEnv): {
45
+ readonly endpoint: string | null;
46
+ readonly endpoint_is_canonical: boolean;
47
+ };
48
+ /** Parse `host`/`port` from an OTLP endpoint URL; `null` if unparseable. */
49
+ export declare function parseEndpointHostPort(endpoint: string): {
50
+ readonly host: string;
51
+ readonly port: number;
52
+ } | null;
53
+ export interface OtelReachabilityProbe {
54
+ /** The cached reachability result (default `false` until the first probe completes). */
55
+ readonly get: () => boolean;
56
+ /** Run a single probe now and update the cache (awaitable; used by tests). */
57
+ readonly runOnce: () => Promise<void>;
58
+ /** Kick off an immediate probe + start the periodic interval (no-op if no endpoint). */
59
+ readonly start: () => void;
60
+ /** Clear the periodic interval (idempotent). */
61
+ readonly stop: () => void;
62
+ }
63
+ /**
64
+ * A cached, periodic OTLP-reachability probe. `getHealth()` is synchronous and
65
+ * can't await a TCP connect, so reachability is computed out-of-band on an
66
+ * interval and read from a cached boolean. The interval is `unref()`'d so it
67
+ * never keeps the process alive, and is also clearable via `stop()` on shutdown.
68
+ * The probe is injectable for testing (no real network in unit tests).
69
+ */
70
+ export declare function createOtelReachabilityProbe(endpoint: string | null, opts?: {
71
+ readonly intervalMs?: number;
72
+ readonly timeoutMs?: number;
73
+ readonly probe?: (host: string, port: number, timeoutMs: number) => Promise<boolean>;
74
+ }): OtelReachabilityProbe;
75
+ /** Optional self-report inputs for the DR-030 mesh-layer `/health` extension. */
76
+ export interface HealthStateOpts {
77
+ /** The registration instance id (registry/health staleness disambiguator). */
78
+ readonly instanceId?: string;
79
+ /** Path to the agent's leaf cert, for the `cert_expiry` self-report. */
80
+ readonly certPath?: string;
81
+ /**
82
+ * Path to the turn-state marker file. Defaults to
83
+ * `${MACF_WORKSPACE_DIR}/.macf/turn-state.json`; injectable for testing.
84
+ */
85
+ readonly turnStatePath?: string;
86
+ /** Injectable OTLP-reachability probe (testing — avoids real network). */
87
+ readonly otelProbe?: (host: string, port: number, timeoutMs: number) => Promise<boolean>;
88
+ /** Override the OTLP-reachability probe interval (testing); default 30s. */
89
+ readonly otelProbeIntervalMs?: number;
90
+ /**
91
+ * Channel-server log path (`MACF_LOG_PATH`); the turn-receipt sink lives at a
92
+ * sibling `processed-receipts.jsonl` in the same directory. Source for the
93
+ * DR-030 `last_processed` passive-receipt self-report (the server passes
94
+ * `config.logPath`). When unset (and no `processedReader`), `last_processed`
95
+ * is null — no sink to read.
96
+ */
97
+ readonly logPath?: string;
98
+ /**
99
+ * Injectable turn-receipt reader for `last_processed` (testing — avoids a real
100
+ * on-disk receipt sink). Takes precedence over `logPath`-derived file reads
101
+ * when set.
102
+ */
103
+ readonly processedReader?: () => readonly ProcessedReceipt[];
104
+ }
105
+ export declare function createHealthState(agentName: string, agentType: string, opts?: HealthStateOpts): HealthState;
106
+ export {};
3
107
  //# sourceMappingURL=health.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"health.d.ts","sourceRoot":"","sources":["../src/health.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAkB,WAAW,EAAE,MAAM,uBAAuB,CAAC;AAQzE,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,WAAW,CA4BnF"}
1
+ {"version":3,"file":"health.d.ts","sourceRoot":"","sources":["../src/health.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AACzE,OAAO,EAAqB,KAAK,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAE7E;;;;;;;;GAQG;AACH,eAAO,MAAM,qBAAqB,IAAI,CAAC;AAEvC,qFAAqF;AACrF,KAAK,eAAe,GAAG,WAAW,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC,CAAC;AAU5D;;;;;;GAMG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAMzD;AAuCD;;;;;;;;GAQG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,GAAG,eAAe,GAAG,IAAI,CA6BpF;AAID;;;;;;;;;;GAUG;AACH,wBAAgB,uBAAuB,CACrC,GAAG,EAAE,MAAM,CAAC,UAAU,GACrB;IAAE,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,QAAQ,CAAC,qBAAqB,EAAE,OAAO,CAAA;CAAE,CAO/E;AAED,4EAA4E;AAC5E,wBAAgB,qBAAqB,CACnC,QAAQ,EAAE,MAAM,GACf;IAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAWzD;AAuBD,MAAM,WAAW,qBAAqB;IACpC,wFAAwF;IACxF,QAAQ,CAAC,GAAG,EAAE,MAAM,OAAO,CAAC;IAC5B,8EAA8E;IAC9E,QAAQ,CAAC,OAAO,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IACtC,wFAAwF;IACxF,QAAQ,CAAC,KAAK,EAAE,MAAM,IAAI,CAAC;IAC3B,gDAAgD;IAChD,QAAQ,CAAC,IAAI,EAAE,MAAM,IAAI,CAAC;CAC3B;AAED;;;;;;GAMG;AACH,wBAAgB,2BAA2B,CACzC,QAAQ,EAAE,MAAM,GAAG,IAAI,EACvB,IAAI,GAAE;IACJ,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;CACjF,GACL,qBAAqB,CAwCvB;AAED,iFAAiF;AACjF,MAAM,WAAW,eAAe;IAC9B,8EAA8E;IAC9E,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAC7B,wEAAwE;IACxE,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B;;;OAGG;IACH,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAC;IAChC,0EAA0E;IAC1E,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IACzF,4EAA4E;IAC5E,QAAQ,CAAC,mBAAmB,CAAC,EAAE,MAAM,CAAC;IACtC;;;;;;OAMG;IACH,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAC1B;;;;OAIG;IACH,QAAQ,CAAC,eAAe,CAAC,EAAE,MAAM,SAAS,gBAAgB,EAAE,CAAC;CAC9D;AAED,wBAAgB,iBAAiB,CAC/B,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,MAAM,EACjB,IAAI,GAAE,eAAoB,GACzB,WAAW,CAsEb"}