instar 1.3.709 → 1.3.711
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/commands/server.d.ts.map +1 -1
- package/dist/commands/server.js +228 -1
- package/dist/commands/server.js.map +1 -1
- package/dist/config/ConfigDefaults.d.ts.map +1 -1
- package/dist/config/ConfigDefaults.js +25 -0
- package/dist/config/ConfigDefaults.js.map +1 -1
- package/dist/core/HttpLeaseTransport.d.ts +9 -0
- package/dist/core/HttpLeaseTransport.d.ts.map +1 -1
- package/dist/core/HttpLeaseTransport.js +28 -2
- package/dist/core/HttpLeaseTransport.js.map +1 -1
- package/dist/core/MultiMachineCoordinator.d.ts +44 -0
- package/dist/core/MultiMachineCoordinator.d.ts.map +1 -1
- package/dist/core/MultiMachineCoordinator.js +52 -0
- package/dist/core/MultiMachineCoordinator.js.map +1 -1
- package/dist/core/PeerEndpointResolver.d.ts +0 -0
- package/dist/core/PeerEndpointResolver.d.ts.map +1 -1
- package/dist/core/PeerEndpointResolver.js +0 -0
- package/dist/core/PeerEndpointResolver.js.map +1 -1
- package/dist/core/PostUpdateMigrator.d.ts.map +1 -1
- package/dist/core/PostUpdateMigrator.js +19 -0
- package/dist/core/PostUpdateMigrator.js.map +1 -1
- package/dist/core/RopeRecoveryProber.d.ts +126 -0
- package/dist/core/RopeRecoveryProber.d.ts.map +1 -0
- package/dist/core/RopeRecoveryProber.js +266 -0
- package/dist/core/RopeRecoveryProber.js.map +1 -0
- package/dist/core/devGatedFeatures.d.ts.map +1 -1
- package/dist/core/devGatedFeatures.js +12 -0
- package/dist/core/devGatedFeatures.js.map +1 -1
- package/dist/core/ropeProbeContract.d.ts +56 -0
- package/dist/core/ropeProbeContract.d.ts.map +1 -0
- package/dist/core/ropeProbeContract.js +92 -0
- package/dist/core/ropeProbeContract.js.map +1 -0
- package/dist/core/tailscaleStatusParser.d.ts +46 -0
- package/dist/core/tailscaleStatusParser.d.ts.map +1 -0
- package/dist/core/tailscaleStatusParser.js +80 -0
- package/dist/core/tailscaleStatusParser.js.map +1 -0
- package/dist/core/types.d.ts +56 -0
- package/dist/core/types.d.ts.map +1 -1
- package/dist/core/types.js.map +1 -1
- package/dist/monitoring/RopeHealthMonitor.d.ts +243 -0
- package/dist/monitoring/RopeHealthMonitor.d.ts.map +1 -0
- package/dist/monitoring/RopeHealthMonitor.js +659 -0
- package/dist/monitoring/RopeHealthMonitor.js.map +1 -0
- package/dist/monitoring/guardManifest.d.ts.map +1 -1
- package/dist/monitoring/guardManifest.js +45 -0
- package/dist/monitoring/guardManifest.js.map +1 -1
- package/dist/scaffold/templates.d.ts.map +1 -1
- package/dist/scaffold/templates.js +9 -0
- package/dist/scaffold/templates.js.map +1 -1
- package/dist/server/AgentServer.d.ts +2 -0
- package/dist/server/AgentServer.d.ts.map +1 -1
- package/dist/server/AgentServer.js +1 -0
- package/dist/server/AgentServer.js.map +1 -1
- package/dist/server/CapabilityIndex.js +1 -1
- package/dist/server/CapabilityIndex.js.map +1 -1
- package/dist/server/routes.d.ts +3 -0
- package/dist/server/routes.d.ts.map +1 -1
- package/dist/server/routes.js +19 -0
- package/dist/server/routes.js.map +1 -1
- package/package.json +1 -1
- package/scripts/lint-scrape-fixture-realness.js +20 -0
- package/src/data/builtin-manifest.json +65 -65
- package/src/data/state-coherence-registry.json +17 -0
- package/src/scaffold/templates/jobs/instar/rope-health-digest.md +42 -0
- package/src/scaffold/templates.ts +9 -0
- package/upgrades/1.3.710.md +22 -0
- package/upgrades/1.3.711.md +79 -0
- package/upgrades/side-effects/tpo-breaker-flake-fix.md +16 -0
- package/upgrades/side-effects/u4-rope-probe-alerts.md +140 -0
- package/upgrades/tpo-breaker-flake-fix.eli16.md +11 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/commands/server.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AA8CH,OAAO,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAU3D,OAAO,EAAE,eAAe,EAAiC,MAAM,iCAAiC,CAAC;AAyBjG,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAGvD,OAAO,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAC;AA6H7D,OAAO,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAgFtD;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,yBAAyB,CACvC,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,EACf,gBAAgB,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAC1C,OAAO,CAUT;AAyID,UAAU,YAAY;IACpB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb;2DACuD;IACvD,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AA07CD,wBAAgB,mBAAmB,CACjC,QAAQ,EAAE,eAAe,EACzB,cAAc,EAAE,cAAc,EAC9B,YAAY,CAAC,EAAE,YAAY,EAC3B,WAAW,CAAC,EAAE,WAAW,EACzB,WAAW,CAAC,EAAE,WAAW,EACzB,iBAAiB,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,EAGvE,UAAU,CAAC,EAAE,MAAM,OAAO,8BAA8B,EAAE,WAAW,GAAG,IAAI,EAK5E,qBAAqB,CAAC,EAAE,MAAM,OAAO,gCAAgC,EAAE,kBAAkB,GAAG,IAAI,EAKhG,mBAAmB,CAAC,EAAE,MAAM,MAAM,GAAG,IAAI,GAAG,SAAS,GACpD,IAAI,CAijBN;AA2lBD,wBAAsB,WAAW,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/commands/server.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AA8CH,OAAO,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAU3D,OAAO,EAAE,eAAe,EAAiC,MAAM,iCAAiC,CAAC;AAyBjG,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAGvD,OAAO,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAC;AA6H7D,OAAO,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAgFtD;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,yBAAyB,CACvC,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,EACf,gBAAgB,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAC1C,OAAO,CAUT;AAyID,UAAU,YAAY;IACpB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb;2DACuD;IACvD,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AA07CD,wBAAgB,mBAAmB,CACjC,QAAQ,EAAE,eAAe,EACzB,cAAc,EAAE,cAAc,EAC9B,YAAY,CAAC,EAAE,YAAY,EAC3B,WAAW,CAAC,EAAE,WAAW,EACzB,WAAW,CAAC,EAAE,WAAW,EACzB,iBAAiB,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,EAGvE,UAAU,CAAC,EAAE,MAAM,OAAO,8BAA8B,EAAE,WAAW,GAAG,IAAI,EAK5E,qBAAqB,CAAC,EAAE,MAAM,OAAO,gCAAgC,EAAE,kBAAkB,GAAG,IAAI,EAKhG,mBAAmB,CAAC,EAAE,MAAM,MAAM,GAAG,IAAI,GAAG,SAAS,GACpD,IAAI,CAijBN;AA2lBD,wBAAsB,WAAW,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CAyuiBtE;AAED,wBAAsB,UAAU,CAAC,OAAO,EAAE;IAAE,GAAG,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAsDzE;AAED;;;;;;;;;;;GAWG;AACH,wBAAsB,aAAa,CAAC,OAAO,EAAE;IAAE,GAAG,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAuD5E"}
|
package/dist/commands/server.js
CHANGED
|
@@ -4093,6 +4093,12 @@ export async function startServer(options) {
|
|
|
4093
4093
|
// honesty observer that STOPS attempting goes BLIND if the registry recovers.
|
|
4094
4094
|
const MAX_BACKOFF_TICKS = 20;
|
|
4095
4095
|
let leaseCoordinatorRef;
|
|
4096
|
+
// U4.3/U4.5 — hoisted rope-health seams. The resolver + prober are closure-locals
|
|
4097
|
+
// of the mesh-init block; U4.5's RopeHealthMonitor (constructed far below) reads the
|
|
4098
|
+
// REAL resolver snapshot through `_ropeSnapshotSource` (never a copy), and the
|
|
4099
|
+
// prober rides the coordinator's lease-pull tick.
|
|
4100
|
+
let _ropeSnapshotSource = null;
|
|
4101
|
+
let _ropeProber = null;
|
|
4096
4102
|
let liveTailBuffer;
|
|
4097
4103
|
let liveTailSendTransport;
|
|
4098
4104
|
let handoffWireTransport;
|
|
@@ -4394,6 +4400,130 @@ export async function startServer(options) {
|
|
|
4394
4400
|
};
|
|
4395
4401
|
await coordinator.initializeLease();
|
|
4396
4402
|
console.log(pc.dim(` Fenced lease active (epoch ${leaseCoordinator.currentEpoch()}, holder=${leaseCoordinator.currentHolder() ?? 'none'})`));
|
|
4403
|
+
// ── U4.3 — traffic-independent rope-health recovery probe ──────────
|
|
4404
|
+
// (docs/specs/u4-3-breaker-recovery-probe.md). Rides the lease-pull tick
|
|
4405
|
+
// (attachLeasePullTickListener — the carrier, no new loop), dials each
|
|
4406
|
+
// probe-eligible dead rope PINNED via a MeshRpcClient-built signed
|
|
4407
|
+
// envelope (never the router-forward funnel), classifies the response by
|
|
4408
|
+
// the exact typed G4 canary contract, and feeds recordResult on the ONE
|
|
4409
|
+
// health authority. Dev-gated: recoveryProbeEnabled OMITTED from config
|
|
4410
|
+
// ⇒ live (dry-run) on a development agent, dark on the fleet.
|
|
4411
|
+
_ropeSnapshotSource = () => meshResolver.snapshot();
|
|
4412
|
+
try {
|
|
4413
|
+
const probeEnabled = resolveDevAgentGate(meshCfg?.recoveryProbeEnabled, config);
|
|
4414
|
+
if (probeEnabled && meshEnabled()) {
|
|
4415
|
+
const { RopeRecoveryProber } = await import('../core/RopeRecoveryProber.js');
|
|
4416
|
+
const { buildRopeProbeCommand, parseProbeResponse } = await import('../core/ropeProbeContract.js');
|
|
4417
|
+
const probeClientMod = await import('../core/MeshRpcClient.js');
|
|
4418
|
+
const { getFeatureMetricsRecorder } = await import('../core/CircuitBreakingIntelligenceProvider.js');
|
|
4419
|
+
let probeNonce = 0;
|
|
4420
|
+
const probeClient = new probeClientMod.MeshRpcClient({
|
|
4421
|
+
selfMachineId,
|
|
4422
|
+
sign: (c) => signEd25519(c, idMgr.loadSigningKey()),
|
|
4423
|
+
nonce: () => `${selfMachineId}:rope-probe:${Date.now()}:${++probeNonce}`,
|
|
4424
|
+
});
|
|
4425
|
+
const probeDryRun = meshCfg?.recoveryProbeDryRun !== false;
|
|
4426
|
+
const ropeProber = new RopeRecoveryProber({
|
|
4427
|
+
resolver: meshResolver,
|
|
4428
|
+
// The same validated registry view the transport dials: resolve()
|
|
4429
|
+
// validates URL shape per kind + the LAN-subnet gate, so the probe
|
|
4430
|
+
// can never dial a forbidden host.
|
|
4431
|
+
listTargets: () => {
|
|
4432
|
+
try {
|
|
4433
|
+
const reg = idMgr.loadRegistry();
|
|
4434
|
+
const out = [];
|
|
4435
|
+
for (const [id, e] of Object.entries(reg.machines ?? {})) {
|
|
4436
|
+
if (id === selfMachineId || e.revokedAt)
|
|
4437
|
+
continue;
|
|
4438
|
+
if (!e.lastKnownUrl && (e.endpoints?.length ?? 0) === 0)
|
|
4439
|
+
continue;
|
|
4440
|
+
for (const ep of meshResolver.resolve(id, e.endpoints, (e.lastKnownUrl ?? undefined))) {
|
|
4441
|
+
out.push({ machineId: id, kind: ep.kind, url: ep.url });
|
|
4442
|
+
}
|
|
4443
|
+
}
|
|
4444
|
+
return out;
|
|
4445
|
+
}
|
|
4446
|
+
catch {
|
|
4447
|
+
// @silent-fallback-ok: an unreadable registry yields no probe
|
|
4448
|
+
// targets THIS tick — the next tick re-reads; never a crash on
|
|
4449
|
+
// the lease-pull carrier.
|
|
4450
|
+
return [];
|
|
4451
|
+
}
|
|
4452
|
+
},
|
|
4453
|
+
sendProbe: async (target) => {
|
|
4454
|
+
const started = Date.now();
|
|
4455
|
+
try {
|
|
4456
|
+
const env = probeClient.buildEnvelope({ machineId: target.machineId, url: target.url }, buildRopeProbeCommand(selfMachineId, `${Date.now()}-${++probeNonce}`), leaseCoordinatorRef?.currentEpoch() ?? 0);
|
|
4457
|
+
const res = await fetch(`${target.url.replace(/\/$/, '')}/mesh/rpc`, {
|
|
4458
|
+
method: 'POST',
|
|
4459
|
+
headers: { 'Content-Type': 'application/json' },
|
|
4460
|
+
body: JSON.stringify(env),
|
|
4461
|
+
signal: AbortSignal.timeout(10_000),
|
|
4462
|
+
});
|
|
4463
|
+
const raw = await res.text();
|
|
4464
|
+
const verdict = parseProbeResponse(raw, res.status);
|
|
4465
|
+
return {
|
|
4466
|
+
typedSuccess: verdict.typedSuccess,
|
|
4467
|
+
detail: verdict.detail ? `${verdict.classification}:${verdict.detail}` : verdict.classification,
|
|
4468
|
+
latencyMs: Date.now() - started,
|
|
4469
|
+
};
|
|
4470
|
+
}
|
|
4471
|
+
catch (err) {
|
|
4472
|
+
return {
|
|
4473
|
+
typedSuccess: false,
|
|
4474
|
+
detail: `dial-failed: ${err instanceof Error ? err.message : String(err)}`,
|
|
4475
|
+
latencyMs: Date.now() - started,
|
|
4476
|
+
};
|
|
4477
|
+
}
|
|
4478
|
+
},
|
|
4479
|
+
raiseAttention: (item) => telegram?.createAttentionItem({
|
|
4480
|
+
id: item.id,
|
|
4481
|
+
title: item.title,
|
|
4482
|
+
summary: item.body.slice(0, 160),
|
|
4483
|
+
description: item.body,
|
|
4484
|
+
category: 'rope-recovery-probe',
|
|
4485
|
+
priority: 'NORMAL',
|
|
4486
|
+
sourceContext: 'rope-recovery-probe',
|
|
4487
|
+
}),
|
|
4488
|
+
recordMetric: (event) => {
|
|
4489
|
+
try {
|
|
4490
|
+
getFeatureMetricsRecorder()?.record({
|
|
4491
|
+
feature: 'rope-recovery-probe',
|
|
4492
|
+
kind: 'event',
|
|
4493
|
+
outcome: event === 'probe-failure' || event === 'exhaustion-trip'
|
|
4494
|
+
? 'error'
|
|
4495
|
+
: event.startsWith('dry-run')
|
|
4496
|
+
? 'noop'
|
|
4497
|
+
: 'fired',
|
|
4498
|
+
verdictId: event,
|
|
4499
|
+
});
|
|
4500
|
+
}
|
|
4501
|
+
catch {
|
|
4502
|
+
// @silent-fallback-ok: metrics are observability, never authority —
|
|
4503
|
+
// a recorder fault must not break the probe path.
|
|
4504
|
+
}
|
|
4505
|
+
},
|
|
4506
|
+
logger: (m) => console.log(pc.dim(` ${m}`)),
|
|
4507
|
+
}, {
|
|
4508
|
+
dryRun: probeDryRun,
|
|
4509
|
+
floorMs: meshCfg?.recoveryProbeFloorMs ?? 900_000,
|
|
4510
|
+
exhaustAttempts: meshCfg?.recoveryProbeExhaustAttempts ?? 20,
|
|
4511
|
+
reopenEpisodeWindowMs: meshCfg?.recoveryProbeReopenEpisodeWindowMs ?? 600_000,
|
|
4512
|
+
midIntervalMs: meshCfg?.recoveryProbeMidIntervalMs ?? 45_000,
|
|
4513
|
+
maxUnreclaimedSuccesses: meshCfg?.recoveryProbeMaxUnreclaimedSuccesses ?? 20,
|
|
4514
|
+
});
|
|
4515
|
+
_ropeProber = ropeProber;
|
|
4516
|
+
coordinator.attachLeasePullTickListener(() => ropeProber.onTick());
|
|
4517
|
+
coordinator.attachRopeHealthProvider(() => ropeProber.view());
|
|
4518
|
+
console.log(pc.dim(` Rope recovery probe: armed (${probeDryRun ? 'dry-run — sends real probes, never mutates health' : 'LIVE'})`));
|
|
4519
|
+
}
|
|
4520
|
+
else {
|
|
4521
|
+
console.log(pc.dim(' Rope recovery probe: dark (recoveryProbeEnabled resolves off on this agent)'));
|
|
4522
|
+
}
|
|
4523
|
+
}
|
|
4524
|
+
catch (err) {
|
|
4525
|
+
console.warn(pc.yellow(` Rope recovery probe init failed: ${err instanceof Error ? err.message : String(err)}`));
|
|
4526
|
+
}
|
|
4397
4527
|
// ── Handoff ack/yield wire (spec §8 G3d/G3e) ───────────────
|
|
4398
4528
|
// The point-to-point channel the two machines use to negotiate a
|
|
4399
4529
|
// verified, lease-safe planned handoff. The /api/handoff/ack route
|
|
@@ -18807,10 +18937,106 @@ export async function startServer(options) {
|
|
|
18807
18937
|
console.error(' StrandedTopicSentinel wiring failed (non-fatal):', e instanceof Error ? e.message : String(e));
|
|
18808
18938
|
}
|
|
18809
18939
|
}
|
|
18940
|
+
// ── U4.5 — Rope-Health Alerts monitor (docs/specs/u4-5-rope-health-alerts.md) ──
|
|
18941
|
+
// Constructed by the real server boot with its OWN bounded 30s evaluation
|
|
18942
|
+
// loop (R-r2-2), reading the REAL U4.3 resolver snapshot through the hoisted
|
|
18943
|
+
// `_ropeSnapshotSource` seam (never a copy). DEV-GATED: monitoring.ropeHealth
|
|
18944
|
+
// `enabled` is OMITTED from ConfigDefaults so resolveDevAgentGate decides —
|
|
18945
|
+
// LIVE on a development agent day one, DARK on the fleet (route 503s, no
|
|
18946
|
+
// timer). Single-machine installs idle at zero cost (no peers). Torn down in
|
|
18947
|
+
// the shutdown handler. Own try/catch: an init failure leaves it null
|
|
18948
|
+
// (route 503s, deny-safe) and never blocks boot.
|
|
18949
|
+
let ropeHealthMonitor = null;
|
|
18950
|
+
try {
|
|
18951
|
+
const rhCfg = config.monitoring?.ropeHealth;
|
|
18952
|
+
if (resolveDevAgentGate(rhCfg?.enabled, config)) {
|
|
18953
|
+
const { RopeHealthMonitor } = await import('../monitoring/RopeHealthMonitor.js');
|
|
18954
|
+
const { getFeatureMetricsRecorder } = await import('../core/CircuitBreakingIntelligenceProvider.js');
|
|
18955
|
+
const rhSelfId = coordinator?.identity?.machineId ?? machineHeartbeat.config.machineId;
|
|
18956
|
+
ropeHealthMonitor = new RopeHealthMonitor({
|
|
18957
|
+
// U4.3 hard data dependency: the resolver snapshot seam. Null until
|
|
18958
|
+
// the mesh block wires it (single-machine → always []) — the monitor
|
|
18959
|
+
// then idles (UNKNOWN fails toward NOT-urgent).
|
|
18960
|
+
snapshot: () => _ropeSnapshotSource?.() ?? [],
|
|
18961
|
+
selfMachineId: rhSelfId,
|
|
18962
|
+
listPeers: () => (machinePoolRegistry?.getCapacities() ?? [])
|
|
18963
|
+
.filter((c) => c.machineId !== rhSelfId)
|
|
18964
|
+
.map((c) => ({
|
|
18965
|
+
machineId: c.machineId,
|
|
18966
|
+
nickname: c.nickname ?? c.machineId,
|
|
18967
|
+
registryOnline: c.online === true,
|
|
18968
|
+
})),
|
|
18969
|
+
// The mesh-INDEPENDENT liveness discriminator (R-r2-1): the git-synced
|
|
18970
|
+
// coarse MachineHeartbeat file, parsed to epoch-ms.
|
|
18971
|
+
readHeartbeatAtMs: (id) => {
|
|
18972
|
+
const r = machineHeartbeatApi.read(id);
|
|
18973
|
+
if (!r)
|
|
18974
|
+
return null;
|
|
18975
|
+
const t = Date.parse(r.lastHeartbeatAt);
|
|
18976
|
+
return Number.isFinite(t) ? t : null;
|
|
18977
|
+
},
|
|
18978
|
+
raiseAttention: (item) => telegram?.createAttentionItem({
|
|
18979
|
+
id: item.id,
|
|
18980
|
+
title: item.title,
|
|
18981
|
+
summary: item.body.slice(0, 160),
|
|
18982
|
+
description: item.body,
|
|
18983
|
+
category: 'rope-health',
|
|
18984
|
+
priority: 'HIGH',
|
|
18985
|
+
sourceContext: 'rope-health',
|
|
18986
|
+
}),
|
|
18987
|
+
// One episode, one ask: while the lease layer's split-brain surface is
|
|
18988
|
+
// active for this partition, its item wins — the monitor stays quiet.
|
|
18989
|
+
splitBrainItemOpen: () => (coordinator?.getSyncStatus?.().splitBrainState ?? 'clear') !== 'clear',
|
|
18990
|
+
stateFilePath: path.join(config.stateDir, 'state', 'rope-health.json'),
|
|
18991
|
+
recordMetric: (event) => {
|
|
18992
|
+
try {
|
|
18993
|
+
getFeatureMetricsRecorder()?.record({
|
|
18994
|
+
feature: 'rope-health',
|
|
18995
|
+
kind: 'event',
|
|
18996
|
+
outcome: event === 'urgent-episode' || event === 'key-expiry-warning' || event.startsWith('transition-')
|
|
18997
|
+
? 'fired'
|
|
18998
|
+
: event === 'detected-not-notified-retry'
|
|
18999
|
+
? 'error'
|
|
19000
|
+
: 'noop',
|
|
19001
|
+
verdictId: event,
|
|
19002
|
+
});
|
|
19003
|
+
}
|
|
19004
|
+
catch {
|
|
19005
|
+
// @silent-fallback-ok: metrics are observability, never authority —
|
|
19006
|
+
// a recorder fault must not break the evaluation loop.
|
|
19007
|
+
}
|
|
19008
|
+
},
|
|
19009
|
+
logger: (m) => console.log(pc.dim(` ${m}`)),
|
|
19010
|
+
}, {
|
|
19011
|
+
urgentEnabled: rhCfg?.urgentEnabled !== false,
|
|
19012
|
+
urgentDebounceMs: rhCfg?.urgentDebounceMs ?? 60_000,
|
|
19013
|
+
clearSustainMs: rhCfg?.clearSustainMs ?? 600_000,
|
|
19014
|
+
keyExpiryWarnDays: rhCfg?.keyExpiryWarnDays ?? 14,
|
|
19015
|
+
wakeGraceMaxMs: rhCfg?.wakeGraceMaxMs ?? 300_000,
|
|
19016
|
+
});
|
|
19017
|
+
// Self-wake grace feed (the ONE thing SleepWakeDetector can tell us —
|
|
19018
|
+
// OWN-machine wake). BOUNDED inside the monitor by wakeGraceMaxMs:
|
|
19019
|
+
// docs/audits/multi-machine-seamless-ux-audit-2026-07.md finding P1-A7
|
|
19020
|
+
// documented 26 FALSE wake events in one night (event-loop stalls
|
|
19021
|
+
// misread as sleeps), so a wake signal is a short grace, never a veto.
|
|
19022
|
+
sleepWakeDetector.on('wake', () => ropeHealthMonitor?.noteOwnWake());
|
|
19023
|
+
ropeHealthMonitor.start();
|
|
19024
|
+
console.log(pc.dim(' Rope-health monitor: live (own 30s evaluation loop)'));
|
|
19025
|
+
}
|
|
19026
|
+
else {
|
|
19027
|
+
console.log(pc.dim(' Rope-health monitor: dark (monitoring.ropeHealth resolves off on this agent)'));
|
|
19028
|
+
}
|
|
19029
|
+
}
|
|
19030
|
+
catch (err) {
|
|
19031
|
+
// @silent-fallback-ok — reported via console.warn; init failure leaves the
|
|
19032
|
+
// monitor null → route 503s (deny-safe), never blocks boot.
|
|
19033
|
+
console.warn(pc.yellow(` Rope-health monitor init failed (non-fatal): ${err instanceof Error ? err.message : String(err)}`));
|
|
19034
|
+
ropeHealthMonitor = null;
|
|
19035
|
+
}
|
|
18810
19036
|
const server = new AgentServer({ config, sessionManager, state, scheduler, telegram, relationships, feedback, feedbackAnomalyDetector, dispatches, updateChecker, autoUpdater, autoDispatcher, quotaTracker, quotaManager, publisher, viewer, tunnel, evolution, watchdog, topicMemory, triageNurse, projectMapper, cartographer: cartographer ?? undefined, coherenceGate: scopeVerifier, contextHierarchy, canonicalState, operationGate, sentinel, adaptiveTrust, memoryMonitor, orphanReaper, coherenceMonitor, commitmentTracker, subscriptionPool, accountFollowMePeerViews: async () => { const nickById = new Map((_listPoolMachines?.() ?? []).map((m) => [m.machineId, m.nickname ?? m.machineId])); let peers = (_resolvePeerUrls?.() ?? []).map((p) => ({ machineId: p.machineId, nickname: nickById.get(p.machineId) ?? p.machineId, url: p.url })); if (peers.length === 0) {
|
|
18811
19037
|
peers = (_listPoolMachines?.() ?? []).filter((m) => m.machineId !== _meshSelfId && !!m.lastKnownUrl).map((m) => ({ machineId: m.machineId, nickname: m.nickname ?? m.machineId, url: m.lastKnownUrl }));
|
|
18812
19038
|
} if (peers.length === 0)
|
|
18813
|
-
return []; const { fetchPeerSubscriptionViews } = await import('../core/fetchPeerSubscriptionViews.js'); return fetchPeerSubscriptionViews({ peers: () => peers, fetchImpl: fetch, authToken: config.authToken ?? '' }); }, quotaPoller, quotaAwareScheduler: _quotaAwareScheduler ?? undefined, proactiveSwapMonitor: _proactiveSwapMonitor ?? undefined, inUseAccountResolver, enrollmentWizard, accountFollowMeRevocation, credentialRepointing, semanticMemory, activitySentinel, rateLimitSentinel, releaseReadinessSentinel: releaseReadinessSentinel ?? undefined, greenPrAutoMerger: greenPrAutoMerger ?? undefined, guardLatchStore: guardLatchStore ?? undefined, messageRouter, summarySentinel, spawnManager, systemReviewer, capabilityMapper, selfKnowledgeTree, coverageAuditor, topicResumeMap: _topicResumeMap ?? undefined, topicProfile: _topicProfileCtx ?? undefined, sessionRefresh: _sessionRefresh ?? undefined, autonomyManager, trustElevationTracker, autonomousEvolution, coordinator: coordinator.enabled ? coordinator : undefined, meshBindActive: coordinator.managers.identityManager.hasIdentity() && config.multiMachine?.meshTransport?.enabled !== false, localSigningKeyPem, leaseTransport, peerEndpointRecorder, getSelfMeshEndpoints, onLeasePullRequest: () => leaseCoordinatorRef?.currentLease() ?? null, liveTailReceiver, handoffWireTransport, onHandoffBegin, onHandoffInitiate: handoffInitiate, handoffInProgress: handoffSentinelInProgress, messageLedger, currentInboundByTopic, replyMarkerTransport, onReplyMarker: messageLedger ? (marker) => { const m = marker; messageLedger.applyRemoteReplyMarker(m.dedupeKey, { platform: m.platform, replyIdempotencyKey: m.replyIdempotencyKey, epoch: m.epoch, topic: m.topic ?? null }); } : undefined, whatsapp: whatsappAdapter, slack: slackAdapter, imessage: imessageAdapter, whatsappBusinessBackend, messageBridge, hookEventReceiver, worktreeMonitor, subagentTracker, instructionsVerifier, handshakeManager: threadlineHandshake, threadlineRouter, conversationStore, threadLog, threadMessageRecorder, warrantsReplyGate, collaborationSurfacer, threadResumeMap, topicLinkageHandler: topicLinkageHandler ?? undefined, threadlineRelayClient, threadlineReplyWaiters, listenerManager: listenerManager ?? undefined, a2aDeliveryTracker: a2aDeliveryTracker ?? undefined, responseReviewGate, messagingToneGate, outboundDedupGate, telemetryHeartbeat, pasteManager, featureRegistry, discoveryEvaluator, completionEvaluator, unifiedTrust, liveConfig, sharedStateLedger, ledgerSessionRegistry, worktreeManager, oidcEnrolledRepos: parallelDevConfig?.oidcEnrolledRepos, initiativeTracker, projectRoundRunner, projectDriftChecker, machineHeartbeat, machinePoolRegistry, getInboundQueue: () => _inboundQueue, meshRpcDispatcher, workingSetPullCoordinator, commitmentReplicaStore, preferenceReplicaStore, replicatedRecordEmitter, conflictStore, rollbackUnmerge, droppedOriginRegistry, preferencesUnionReader, forwardCommitmentMutate, sessionOwnershipRegistry, topicPinStore: _topicPinStore ?? undefined, ownershipReconciler: _ownershipReconciler ?? undefined, streamTicketStore: _streamTicketStore ?? undefined, poolStreamAllowRemoteInput: config.dashboard?.poolStream?.allowRemoteInput ?? false, poolStreamConnector: _poolStreamConnector ?? undefined, secretSync: _secretSyncHandle ?? undefined, meshSelfId: _meshSelfId ?? undefined, resolveRouterUrl: _resolveRouterUrl ?? undefined, resolvePeerUrls: _resolvePeerUrls ?? undefined, guardRegistry, listPoolMachines: _listPoolMachines ?? undefined, deliverMandateToMachine: _deliverMandateToMachine ?? undefined, poolLink: _poolLink ?? undefined, poolPollCache: _poolPollCache ?? undefined, sessionPoolE2EResultStore, proxyCoordinator, topicIntentStore, topicIntentArcCheck, usherSignalStore, intelligence: sharedIntelligence ?? undefined, telegramBridgeConfig, telegramBridge: telegramBridge ?? undefined, threadlineObservability, briefDeps, workingMemory, taskFlowRegistry, threadlineFlowBridge, sessionReaper, agentWorktreeReaper, orphanedWorkSentinel, mcpProcessReaper, geminiLoopRunner, sleepController, agentActivityState, reapLog, resumeQueue, resumeDrainer, autonomousLivenessReconciler, enforcedTerminationStatus: () => enforcedTerminationWatchdog?.guardStatus() ?? null, prHandLease: prHandLease ?? undefined, operatorStopRecorder: recordOperatorStop, sleepWakeDetector, unjustifiedStopGate, stopGateDb, stopNotifier, liveTestGate, liveTestGateMode, liveTestRunnerCtx }); // Resolve the late-bound topic-operator getter (increment 2e): routing was
|
|
19039
|
+
return []; const { fetchPeerSubscriptionViews } = await import('../core/fetchPeerSubscriptionViews.js'); return fetchPeerSubscriptionViews({ peers: () => peers, fetchImpl: fetch, authToken: config.authToken ?? '' }); }, quotaPoller, quotaAwareScheduler: _quotaAwareScheduler ?? undefined, proactiveSwapMonitor: _proactiveSwapMonitor ?? undefined, inUseAccountResolver, enrollmentWizard, accountFollowMeRevocation, credentialRepointing, semanticMemory, activitySentinel, rateLimitSentinel, releaseReadinessSentinel: releaseReadinessSentinel ?? undefined, greenPrAutoMerger: greenPrAutoMerger ?? undefined, guardLatchStore: guardLatchStore ?? undefined, messageRouter, summarySentinel, spawnManager, systemReviewer, capabilityMapper, selfKnowledgeTree, coverageAuditor, topicResumeMap: _topicResumeMap ?? undefined, topicProfile: _topicProfileCtx ?? undefined, sessionRefresh: _sessionRefresh ?? undefined, autonomyManager, trustElevationTracker, autonomousEvolution, coordinator: coordinator.enabled ? coordinator : undefined, meshBindActive: coordinator.managers.identityManager.hasIdentity() && config.multiMachine?.meshTransport?.enabled !== false, localSigningKeyPem, leaseTransport, peerEndpointRecorder, getSelfMeshEndpoints, onLeasePullRequest: () => leaseCoordinatorRef?.currentLease() ?? null, liveTailReceiver, handoffWireTransport, onHandoffBegin, onHandoffInitiate: handoffInitiate, handoffInProgress: handoffSentinelInProgress, messageLedger, currentInboundByTopic, replyMarkerTransport, onReplyMarker: messageLedger ? (marker) => { const m = marker; messageLedger.applyRemoteReplyMarker(m.dedupeKey, { platform: m.platform, replyIdempotencyKey: m.replyIdempotencyKey, epoch: m.epoch, topic: m.topic ?? null }); } : undefined, whatsapp: whatsappAdapter, slack: slackAdapter, imessage: imessageAdapter, whatsappBusinessBackend, messageBridge, hookEventReceiver, worktreeMonitor, subagentTracker, instructionsVerifier, handshakeManager: threadlineHandshake, threadlineRouter, conversationStore, threadLog, threadMessageRecorder, warrantsReplyGate, collaborationSurfacer, threadResumeMap, topicLinkageHandler: topicLinkageHandler ?? undefined, threadlineRelayClient, threadlineReplyWaiters, listenerManager: listenerManager ?? undefined, a2aDeliveryTracker: a2aDeliveryTracker ?? undefined, responseReviewGate, messagingToneGate, outboundDedupGate, telemetryHeartbeat, pasteManager, featureRegistry, discoveryEvaluator, completionEvaluator, unifiedTrust, liveConfig, sharedStateLedger, ledgerSessionRegistry, worktreeManager, oidcEnrolledRepos: parallelDevConfig?.oidcEnrolledRepos, initiativeTracker, projectRoundRunner, projectDriftChecker, machineHeartbeat, machinePoolRegistry, ropeHealthMonitor, getInboundQueue: () => _inboundQueue, meshRpcDispatcher, workingSetPullCoordinator, commitmentReplicaStore, preferenceReplicaStore, replicatedRecordEmitter, conflictStore, rollbackUnmerge, droppedOriginRegistry, preferencesUnionReader, forwardCommitmentMutate, sessionOwnershipRegistry, topicPinStore: _topicPinStore ?? undefined, ownershipReconciler: _ownershipReconciler ?? undefined, streamTicketStore: _streamTicketStore ?? undefined, poolStreamAllowRemoteInput: config.dashboard?.poolStream?.allowRemoteInput ?? false, poolStreamConnector: _poolStreamConnector ?? undefined, secretSync: _secretSyncHandle ?? undefined, meshSelfId: _meshSelfId ?? undefined, resolveRouterUrl: _resolveRouterUrl ?? undefined, resolvePeerUrls: _resolvePeerUrls ?? undefined, guardRegistry, listPoolMachines: _listPoolMachines ?? undefined, deliverMandateToMachine: _deliverMandateToMachine ?? undefined, poolLink: _poolLink ?? undefined, poolPollCache: _poolPollCache ?? undefined, sessionPoolE2EResultStore, proxyCoordinator, topicIntentStore, topicIntentArcCheck, usherSignalStore, intelligence: sharedIntelligence ?? undefined, telegramBridgeConfig, telegramBridge: telegramBridge ?? undefined, threadlineObservability, briefDeps, workingMemory, taskFlowRegistry, threadlineFlowBridge, sessionReaper, agentWorktreeReaper, orphanedWorkSentinel, mcpProcessReaper, geminiLoopRunner, sleepController, agentActivityState, reapLog, resumeQueue, resumeDrainer, autonomousLivenessReconciler, enforcedTerminationStatus: () => enforcedTerminationWatchdog?.guardStatus() ?? null, prHandLease: prHandLease ?? undefined, operatorStopRecorder: recordOperatorStop, sleepWakeDetector, unjustifiedStopGate, stopGateDb, stopNotifier, liveTestGate, liveTestGateMode, liveTestRunnerCtx }); // Resolve the late-bound topic-operator getter (increment 2e): routing was
|
|
18814
19040
|
// wired before the server existed; from here on inbound binds use the
|
|
18815
19041
|
// server's own store instance.
|
|
18816
19042
|
_agentServerRef = server;
|
|
@@ -19592,6 +19818,7 @@ export async function startServer(options) {
|
|
|
19592
19818
|
registrySyncDebouncer?.stop();
|
|
19593
19819
|
gitSync?.stop();
|
|
19594
19820
|
coordinator.stop();
|
|
19821
|
+
ropeHealthMonitor?.stop();
|
|
19595
19822
|
coherenceMonitor.stop();
|
|
19596
19823
|
commitmentTracker.stop();
|
|
19597
19824
|
commitmentSentinel?.stop();
|