@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.
- package/dist/collision.d.ts +8 -0
- package/dist/collision.d.ts.map +1 -1
- package/dist/collision.js +42 -1
- package/dist/collision.js.map +1 -1
- package/dist/comms-ledger.d.ts +77 -0
- package/dist/comms-ledger.d.ts.map +1 -1
- package/dist/comms-ledger.js +133 -1
- package/dist/comms-ledger.js.map +1 -1
- package/dist/health.d.ts +106 -2
- package/dist/health.d.ts.map +1 -1
- package/dist/health.js +240 -2
- package/dist/health.js.map +1 -1
- package/dist/https.d.ts +31 -0
- package/dist/https.d.ts.map +1 -1
- package/dist/https.js +54 -1
- package/dist/https.js.map +1 -1
- package/dist/notify-peer.d.ts.map +1 -1
- package/dist/notify-peer.js +20 -5
- package/dist/notify-peer.js.map +1 -1
- package/dist/registry-heartbeat.d.ts +53 -0
- package/dist/registry-heartbeat.d.ts.map +1 -0
- package/dist/registry-heartbeat.js +102 -0
- package/dist/registry-heartbeat.js.map +1 -0
- package/dist/server.js +41 -2
- package/dist/server.js.map +1 -1
- package/dist/shutdown.d.ts +23 -1
- package/dist/shutdown.d.ts.map +1 -1
- package/dist/shutdown.js +61 -3
- package/dist/shutdown.js.map +1 -1
- package/package.json +2 -2
package/dist/collision.d.ts
CHANGED
|
@@ -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: {
|
package/dist/collision.d.ts.map
CHANGED
|
@@ -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,
|
|
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', {
|
package/dist/collision.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"collision.js","sourceRoot":"","sources":["../src/collision.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AACrC,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAGvC,OAAO,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;
|
|
1
|
+
{"version":3,"file":"collision.js","sourceRoot":"","sources":["../src/collision.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AACrC,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAGvC,OAAO,EAAE,SAAS,EAAE,aAAa,EAAE,YAAY,EAAE,uBAAuB,EAAE,MAAM,uBAAuB,CAAC;AAExG,yEAAyE;AACzE,MAAM,eAAe,GAAG,mBAAmB,CAAC;AAE5C,MAAM,OAAO,cAAe,SAAQ,SAAS;IAC3C,YAAY,IAAY,EAAE,IAAY,EAAE,IAAY;QAClD,KAAK,CACH,iBAAiB,EACjB,UAAU,IAAI,2BAA2B,IAAI,IAAI,IAAI,IAAI;YACzD,kDAAkD,CACnD,CAAC;QACF,IAAI,CAAC,IAAI,GAAG,gBAAgB,CAAC;IAC/B,CAAC;CACF;AAED;;;;;;;GAOG;AACH,MAAM,OAAO,iBAAkB,SAAQ,SAAS;IAC9C,YAAY,IAAY,EAAE,OAAyB;QACjD,KAAK,CACH,qBAAqB,EACrB,OAAO,KAAK,IAAI;YACd,CAAC,CAAC,UAAU,IAAI,uDAAuD;gBACrE,6EAA6E;YAC/E,CAAC,CAAC,UAAU,IAAI,0DAA0D;gBACxE,qBAAqB,OAAO,CAAC,IAAI,IAAI,OAAO,CAAC,IAAI,cAAc,OAAO,CAAC,WAAW,KAAK;gBACvF,sCAAsC,CAC3C,CAAC;QACF,IAAI,CAAC,IAAI,GAAG,mBAAmB,CAAC;IAClC,CAAC;CACF;AAED,MAAM,sBAAsB,GAAG,IAAI,CAAC;AAEpC;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,uBAAuB,GAAG,CAAC,CAAC;AAClC,MAAM,uBAAuB,GAAG,GAAG,CAAC;AAEpC,MAAM,KAAK,GAAG,CAAC,EAAU,EAAiB,EAAE,CAC1C,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,CAAC;AAUpD;;;;GAIG;AACH,SAAS,UAAU,CACjB,IAAY,EACZ,IAAY,EACZ,UAAkB,EAClB,aAAqB,EACrB,YAAoB,EACpB,YAAoB,sBAAsB;IAE1C,qEAAqE;IACrE,iEAAiE;IACjE,4DAA4D;IAC5D,kEAAkE;IAClE,gEAAgE;IAChE,iEAAiE;IACjE,mEAAmE;IACnE,iCAAiC;IACjC,IAAI,EAAU,CAAC;IACf,IAAI,IAAY,CAAC;IACjB,IAAI,GAAW,CAAC;IAChB,IAAI,CAAC;QACH,EAAE,GAAG,YAAY,CAAC,UAAU,CAAC,CAAC;QAC9B,IAAI,GAAG,YAAY,CAAC,aAAa,CAAC,CAAC;QACnC,GAAG,GAAG,YAAY,CAAC,YAAY,CAAC,CAAC;IACnC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,OAAO,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC;IAC1D,CAAC;IAED,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;QAC7B,MAAM,GAAG,GAAG,OAAO,CACjB;YACE,QAAQ,EAAE,IAAI;YACd,IAAI;YACJ,MAAM,EAAE,KAAK;YACb,IAAI,EAAE,SAAS;YACf,EAAE;YACF,IAAI;YACJ,GAAG;YACH,kBAAkB,EAAE,IAAI;YACxB,OAAO,EAAE,SAAS;SACnB,EACD,CAAC,GAAG,EAAE,EAAE;YACN,MAAM,KAAK,GAAG,GAAG,CAAC,UAAU,KAAK,SAAS,IAAI,GAAG,CAAC,UAAU,IAAI,GAAG,IAAI,GAAG,CAAC,UAAU,GAAG,GAAG,CAAC;YAC5F,IAAI,CAAC,KAAK,EAAE,CAAC;gBACX,GAAG,CAAC,MAAM,EAAE,CAAC,CAAC,QAAQ;gBACtB,OAAO,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC;gBACzC,OAAO;YACT,CAAC;YACD,kEAAkE;YAClE,qEAAqE;YACrE,0DAA0D;YAC1D,MAAM,MAAM,GAAa,EAAE,CAAC;YAC5B,GAAG,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,CAAS,EAAE,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;YAC9C,GAAG,CAAC,EAAE,CAAC,KAAK,EAAE,GAAG,EAAE;gBACjB,IAAI,OAAO,GAAkB,IAAI,CAAC;gBAClC,IAAI,CAAC;oBACH,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,CAA0B,CAAC;oBAC1F,IAAI,OAAO,IAAI,CAAC,OAAO,KAAK,QAAQ;wBAAE,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC;gBAC/D,CAAC;gBAAC,MAAM,CAAC;oBACP,6CAA6C;gBAC/C,CAAC;gBACD,OAAO,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,CAAC;YACpC,CAAC,CAAC,CAAC;YACH,GAAG,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;QACjE,CAAC,CACF,CAAC;QAEF,GAAG,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;QAChE,GAAG,CAAC,EAAE,CAAC,SAAS,EAAE,GAAG,EAAE;YACrB,GAAG,CAAC,OAAO,EAAE,CAAC;YACd,OAAO,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC;QAC3C,CAAC,CAAC,CAAC;QACH,GAAG,CAAC,GAAG,EAAE,CAAC;IACZ,CAAC,CAAC,CAAC;AACL,CAAC;AAED;;;;;;;;GAQG;AACH,KAAK,UAAU,eAAe,CAC5B,IAAY,EACZ,IAAY,EACZ,UAAkB,EAClB,aAAqB,EACrB,YAAoB;IAEpB,IAAI,MAAM,GAAqB,EAAE,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;IAC/D,KAAK,IAAI,OAAO,GAAG,CAAC,EAAE,OAAO,GAAG,uBAAuB,EAAE,OAAO,IAAI,CAAC,EAAE,CAAC;QACtE,IAAI,OAAO,GAAG,CAAC;YAAE,MAAM,KAAK,CAAC,uBAAuB,CAAC,CAAC;QACtD,MAAM,GAAG,MAAM,UAAU,CAAC,IAAI,EAAE,IAAI,EAAE,UAAU,EAAE,aAAa,EAAE,YAAY,CAAC,CAAC;QAC/E,IAAI,CAAC,MAAM,CAAC,KAAK;YAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;IAC5D,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAOD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA0CG;AACH,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,IAAY,EACZ,QAAkB,EAClB,SAIC,EACD,eAAuB,EACvB,MAAc;IAEd,MAAM,QAAQ,GAAG,MAAM,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IAE1C,IAAI,QAAQ,KAAK,IAAI,EAAE,CAAC;QACtB,MAAM,CAAC,IAAI,CAAC,iBAAiB,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;QACjE,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,CAAC;IAChC,CAAC;IAED,MAAM,CAAC,IAAI,CAAC,iBAAiB,EAAE;QAC7B,MAAM,EAAE,iBAAiB;QACzB,KAAK,EAAE,IAAI;QACX,IAAI,EAAE,QAAQ,CAAC,IAAI;QACnB,IAAI,EAAE,QAAQ,CAAC,IAAI;QACnB,WAAW,EAAE,QAAQ,CAAC,WAAW;KAClC,CAAC,CAAC;IAEH,8EAA8E;IAC9E,6EAA6E;IAC7E,2EAA2E;IAC3E,wDAAwD;IACxD,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,eAAe,EAAE,GAAG,MAAM,eAAe,CAC/D,QAAQ,CAAC,IAAI,EACb,QAAQ,CAAC,IAAI,EACb,SAAS,CAAC,UAAU,EACpB,SAAS,CAAC,aAAa,EACvB,SAAS,CAAC,YAAY,CACvB,CAAC;IAEF,IAAI,KAAK,EAAE,CAAC;QACV,MAAM,uBAAuB,GAAG,OAAO,CAAC,GAAG,CAAC,0BAA0B,CAAC,KAAK,GAAG,CAAC;QAChF,MAAM,iBAAiB,GAAG,eAAe,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC;QAEhE,oEAAoE;QACpE,IAAI,QAAiB,CAAC;QACtB,IAAI,KAAa,CAAC;QAClB,IAAI,uBAAuB,EAAE,CAAC;YAC5B,QAAQ,GAAG,KAAK,CAAC;YACjB,KAAK,GAAG,iCAAiC,CAAC;QAC5C,CAAC;aAAM,IAAI,CAAC,iBAAiB,EAAE,CAAC;YAC9B,uDAAuD;YACvD,QAAQ,GAAG,KAAK,CAAC;YACjB,KAAK,GAAG,4BAA4B,CAAC;QACvC,CAAC;aAAM,IAAI,eAAe,KAAK,IAAI,EAAE,CAAC;YACpC,mEAAmE;YACnE,QAAQ,GAAG,IAAI,CAAC;YAChB,KAAK,GAAG,+BAA+B,CAAC;QAC1C,CAAC;aAAM,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC,eAAe,CAAC,EAAE,CAAC;YAClD,yEAAyE;YACzE,0EAA0E;YAC1E,yEAAyE;YACzE,4CAA4C;YAC5C,QAAQ,GAAG,IAAI,CAAC;YAChB,KAAK,GAAG,+BAA+B,CAAC;QAC1C,CAAC;aAAM,IAAI,aAAa,CAAC,eAAe,EAAE,eAAe,CAAC,GAAG,CAAC,EAAE,CAAC;YAC/D,QAAQ,GAAG,IAAI,CAAC;YAChB,KAAK,GAAG,wBAAwB,CAAC;QACnC,CAAC;aAAM,CAAC;YACN,QAAQ,GAAG,KAAK,CAAC;YACjB,KAAK,GAAG,qBAAqB,CAAC;QAChC,CAAC;QAED,MAAM,CAAC,IAAI,CAAC,iBAAiB,EAAE;YAC7B,MAAM,EAAE,KAAK;YACb,KAAK,EAAE,IAAI;YACX,gBAAgB,EAAE,eAAe;YACjC,gBAAgB,EAAE,eAAe;YACjC,IAAI,EAAE,QAAQ,CAAC,IAAI;YACnB,IAAI,EAAE,QAAQ,CAAC,IAAI;SACpB,CAAC,CAAC;QAEH,IAAI,QAAQ;YAAE,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,QAAQ,EAAE,QAAQ,EAAE,CAAC;QAEhE,0EAA0E;QAC1E,sEAAsE;QACtE,gFAAgF;QAChF,2EAA2E;QAC3E,yEAAyE;QACzE,8EAA8E;QAC9E,0EAA0E;QAC1E,gFAAgF;QAChF,0EAA0E;QAC1E,2EAA2E;QAC3E,6EAA6E;QAC7E,2EAA2E;QAC3E,+EAA+E;QAC/E,iFAAiF;QACjF,wEAAwE;QACxE,gFAAgF;QAChF,+EAA+E;QAC/E,2EAA2E;QAC3E,yEAAyE;QACzE,gEAAgE;QAChE,IAAI,YAAY,CAAC,QAAQ,EAAE,uBAAuB,EAAE,IAAI,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC;YAChE,MAAM,CAAC,IAAI,CAAC,iBAAiB,EAAE;gBAC7B,MAAM,EAAE,0BAA0B;gBAClC,KAAK,EAAE,IAAI;gBACX,WAAW,EAAE,KAAK;gBAClB,gBAAgB,EAAE,eAAe;gBACjC,gBAAgB,EAAE,eAAe;gBACjC,cAAc,EAAE,QAAQ,CAAC,cAAc,IAAI,IAAI;gBAC/C,IAAI,EAAE,QAAQ,CAAC,IAAI;gBACnB,IAAI,EAAE,QAAQ,CAAC,IAAI;aACpB,CAAC,CAAC;YACH,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,QAAQ,EAAE,QAAQ,EAAE,CAAC;QACpD,CAAC;QAED,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE,CAAC;IACvC,CAAC;IAED,MAAM,CAAC,IAAI,CAAC,iBAAiB,EAAE;QAC7B,MAAM,EAAE,UAAU;QAClB,KAAK,EAAE,IAAI;QACX,iBAAiB,EAAE,QAAQ,CAAC,WAAW;KACxC,CAAC,CAAC;IACH,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,QAAQ,EAAE,QAAQ,EAAE,CAAC;AACpD,CAAC"}
|
package/dist/comms-ledger.d.ts
CHANGED
|
@@ -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;
|
|
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;AAmCD,oFAAoF;AACpF,eAAO,MAAM,qBAAqB,6BAA6B,CAAC;AAEhE;;;;;;GAMG;AACH,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS,CAGtF;AAED;;;;GAIG;AACH,eAAO,MAAM,sBAAsB;;;;iBAOjC,CAAC;AACH,MAAM,MAAM,gBAAgB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,sBAAsB,CAAC,CAAC;AAEtE,wFAAwF;AACxF,MAAM,WAAW,mBAAmB;IAClC,qFAAqF;IACrF,QAAQ,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B;;;;OAIG;IACH,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,6EAA6E;IAC7E,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B;;;;;OAKG;IACH,QAAQ,CAAC,iBAAiB,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3C;AAED;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,gBAAgB,EAAE,CAejE;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAC/B,QAAQ,EAAE,SAAS,gBAAgB,EAAE,GACpC,gBAAgB,GAAG,IAAI,CAMzB;AAED;;;;;GAKG;AACH,wBAAgB,yBAAyB,CACvC,OAAO,EAAE,gBAAgB,GAAG,IAAI,EAChC,GAAG,EAAE,MAAM,GACV,mBAAmB,GAAG,IAAI,CAS5B;AAED;;;;;;;;;GASG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE;IACtC,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACtC,QAAQ,CAAC,eAAe,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC9C,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,SAAS,gBAAgB,EAAE,CAAC;CAC3D,GAAG,mBAAmB,GAAG,IAAI,CAc7B;AAED;;;;;;;;;GASG;AACH,eAAO,MAAM,eAAe,EAAG,4CAAqD,CAAC"}
|
package/dist/comms-ledger.js
CHANGED
|
@@ -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
|
*
|
package/dist/comms-ledger.js.map
CHANGED
|
@@ -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;
|
|
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
|
-
|
|
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
|
package/dist/health.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"health.d.ts","sourceRoot":"","sources":["../src/health.ts"],"names":[],"mappings":"
|
|
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"}
|