instar 1.3.366 → 1.3.368
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 +282 -2
- package/dist/commands/server.js.map +1 -1
- package/dist/config/ConfigDefaults.d.ts.map +1 -1
- package/dist/config/ConfigDefaults.js +29 -0
- package/dist/config/ConfigDefaults.js.map +1 -1
- package/dist/core/CommitmentsSync.d.ts +144 -0
- package/dist/core/CommitmentsSync.d.ts.map +1 -0
- package/dist/core/CommitmentsSync.js +293 -0
- package/dist/core/CommitmentsSync.js.map +1 -0
- package/dist/core/MeshRpc.d.ts +14 -0
- package/dist/core/MeshRpc.d.ts.map +1 -1
- package/dist/core/MeshRpc.js +7 -1
- package/dist/core/MeshRpc.js.map +1 -1
- package/dist/core/PeerPresencePuller.d.ts +25 -0
- package/dist/core/PeerPresencePuller.d.ts.map +1 -1
- package/dist/core/PeerPresencePuller.js +12 -0
- package/dist/core/PeerPresencePuller.js.map +1 -1
- package/dist/core/PeerVisibilityGuard.d.ts +83 -0
- package/dist/core/PeerVisibilityGuard.d.ts.map +1 -0
- package/dist/core/PeerVisibilityGuard.js +204 -0
- package/dist/core/PeerVisibilityGuard.js.map +1 -0
- package/dist/core/PendingPullLedger.d.ts +129 -0
- package/dist/core/PendingPullLedger.d.ts.map +1 -0
- package/dist/core/PendingPullLedger.js +239 -0
- package/dist/core/PendingPullLedger.js.map +1 -0
- package/dist/core/PostUpdateMigrator.d.ts.map +1 -1
- package/dist/core/PostUpdateMigrator.js +20 -0
- package/dist/core/PostUpdateMigrator.js.map +1 -1
- package/dist/core/WorkingSetManifest.d.ts +2 -0
- package/dist/core/WorkingSetManifest.d.ts.map +1 -1
- package/dist/core/WorkingSetManifest.js +13 -1
- package/dist/core/WorkingSetManifest.js.map +1 -1
- package/dist/core/WorkingSetPull.d.ts +157 -0
- package/dist/core/WorkingSetPull.d.ts.map +1 -0
- package/dist/core/WorkingSetPull.js +546 -0
- package/dist/core/WorkingSetPull.js.map +1 -0
- package/dist/core/WorkingSetPullCoordinator.d.ts +134 -0
- package/dist/core/WorkingSetPullCoordinator.d.ts.map +1 -0
- package/dist/core/WorkingSetPullCoordinator.js +306 -0
- package/dist/core/WorkingSetPullCoordinator.js.map +1 -0
- package/dist/core/types.d.ts +39 -1
- package/dist/core/types.d.ts.map +1 -1
- package/dist/core/types.js.map +1 -1
- package/dist/monitoring/CommitmentTracker.d.ts +40 -0
- package/dist/monitoring/CommitmentTracker.d.ts.map +1 -1
- package/dist/monitoring/CommitmentTracker.js +95 -4
- package/dist/monitoring/CommitmentTracker.js.map +1 -1
- package/dist/scaffold/templates.d.ts.map +1 -1
- package/dist/scaffold/templates.js +4 -0
- package/dist/scaffold/templates.js.map +1 -1
- package/dist/server/AgentServer.d.ts +6 -0
- package/dist/server/AgentServer.d.ts.map +1 -1
- package/dist/server/AgentServer.js +2 -0
- package/dist/server/AgentServer.js.map +1 -1
- package/dist/server/routes.d.ts +9 -0
- package/dist/server/routes.d.ts.map +1 -1
- package/dist/server/routes.js +44 -1
- package/dist/server/routes.js.map +1 -1
- package/package.json +1 -1
- package/src/data/builtin-manifest.json +64 -64
- package/src/data/state-coherence-registry.json +61 -13
- package/src/scaffold/templates.ts +4 -0
- package/upgrades/1.3.367.md +134 -0
- package/upgrades/1.3.368.md +52 -0
- package/upgrades/side-effects/commitments-sync-p15a.md +93 -0
- package/upgrades/side-effects/working-set-ci-absorb.md +29 -0
- package/upgrades/side-effects/working-set-parity-absorb.md +35 -0
- package/upgrades/side-effects/working-set-pull-p22a.md +121 -0
- package/upgrades/side-effects/working-set-trigger-p22b.md +115 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/commands/server.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AA6SH,UAAU,YAAY;IACpB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb;2DACuD;IACvD,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAuxDD,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;AA6SH,UAAU,YAAY;IACpB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb;2DACuD;IACvD,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAuxDD,wBAAsB,WAAW,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CAk/StE;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
|
@@ -2352,6 +2352,21 @@ export async function startServer(options) {
|
|
|
2352
2352
|
// RECEIVE handler (always-registered; harmless when idle) and the
|
|
2353
2353
|
// REPLICATION-GATED puller delta drive. Constructed only when the journal is.
|
|
2354
2354
|
let journalSyncApplier;
|
|
2355
|
+
// Working-set serve side (WORKING-SET-HANDOFF-SPEC §3.7): constructed ONLY
|
|
2356
|
+
// when replication is EXPLICITLY enabled (=== true, never the dark-ship
|
|
2357
|
+
// gate) — the pull is meaningless without replication's mesh path and must
|
|
2358
|
+
// never out-activate it. The dispatcher's working-set-pull handler answers
|
|
2359
|
+
// 'disabled' while this stays undefined.
|
|
2360
|
+
let workingSetPullServer;
|
|
2361
|
+
// The pull side (§3.3 trigger + §3.4 ledger/drain + the reflex route).
|
|
2362
|
+
// Hoisted here so the deliverMessage onAccepted seam (wired earlier than
|
|
2363
|
+
// the mesh client) can reference it lazily; constructed in the mesh-wiring
|
|
2364
|
+
// block ONLY under the same explicit replication gate.
|
|
2365
|
+
let workingSetPullCoordinator;
|
|
2366
|
+
// Commitments-coherence receive side (COMMITMENTS-COHERENCE-SPEC §3.2) —
|
|
2367
|
+
// same explicit replication gate; undefined = dark (verb answers
|
|
2368
|
+
// 'disabled', merge layer returns own rows only).
|
|
2369
|
+
let commitmentReplicaStore;
|
|
2355
2370
|
{
|
|
2356
2371
|
const cjCfg = config.multiMachine?.coherenceJournal;
|
|
2357
2372
|
const cjEnabled = cjCfg?.enabled ?? !!config.developmentAgent;
|
|
@@ -2397,6 +2412,35 @@ export async function startServer(options) {
|
|
|
2397
2412
|
journalSyncApplier = undefined;
|
|
2398
2413
|
console.log(pc.dim(` [journal-sync] applier not constructed: ${e instanceof Error ? e.message : String(e)}`));
|
|
2399
2414
|
}
|
|
2415
|
+
// Working-set serve side (WORKING-SET-HANDOFF-SPEC §3.2/§3.7) —
|
|
2416
|
+
// gated on the EXPLICIT replication enable, same gate as the
|
|
2417
|
+
// replication SEND/drive below. Serves OWN jailed working files
|
|
2418
|
+
// behind a fresh-manifest allowlist; chunked ≤ pullMaxBatchBytes.
|
|
2419
|
+
if (cjCfg?.replication?.enabled === true) {
|
|
2420
|
+
try {
|
|
2421
|
+
const wsMod = await import('../core/WorkingSetPull.js');
|
|
2422
|
+
const wsReaderMod = await import('../core/CoherenceJournalReader.js');
|
|
2423
|
+
const wsReader = new wsReaderMod.CoherenceJournalReader({ stateDir: config.stateDir });
|
|
2424
|
+
const ws = cjCfg?.workingSet;
|
|
2425
|
+
workingSetPullServer = new wsMod.WorkingSetPullServer({
|
|
2426
|
+
stateDir: config.stateDir,
|
|
2427
|
+
readRuns: (topic) => wsReader.readOwnAutonomousRuns(topic, cjMachineId),
|
|
2428
|
+
caps: {
|
|
2429
|
+
...(ws?.maxFileBytes != null ? { maxFileBytes: ws.maxFileBytes } : {}),
|
|
2430
|
+
...(ws?.headlineFileBytes != null ? { headlineFileBytes: ws.headlineFileBytes } : {}),
|
|
2431
|
+
...(ws?.maxFiles != null ? { maxFiles: ws.maxFiles } : {}),
|
|
2432
|
+
...(ws?.maxTotalBytes != null ? { maxTotalBytes: ws.maxTotalBytes } : {}),
|
|
2433
|
+
},
|
|
2434
|
+
...(ws?.pullMaxBatchBytes != null ? { pullMaxBatchBytes: ws.pullMaxBatchBytes } : {}),
|
|
2435
|
+
...(ws?.serveConcurrency != null ? { serveConcurrency: ws.serveConcurrency } : {}),
|
|
2436
|
+
logger: (m) => console.log(pc.dim(` [working-set] ${m}`)),
|
|
2437
|
+
});
|
|
2438
|
+
}
|
|
2439
|
+
catch (e) { /* @silent-fallback-ok: working-set serve construction failure degrades to 'disabled' responses — never blocks server boot (WORKING-SET-HANDOFF-SPEC §4) */
|
|
2440
|
+
workingSetPullServer = undefined;
|
|
2441
|
+
console.log(pc.dim(` [working-set] serve side not constructed: ${e instanceof Error ? e.message : String(e)}`));
|
|
2442
|
+
}
|
|
2443
|
+
}
|
|
2400
2444
|
// §3.3 autonomous-run journal scanner — observation-based start/stop
|
|
2401
2445
|
// (no single .local.md write funnel exists; polling is the structural
|
|
2402
2446
|
// choice). P19 brakes, declared: constant per-tick cost (bounded by
|
|
@@ -6310,6 +6354,9 @@ export async function startServer(options) {
|
|
|
6310
6354
|
const commitmentTracker = new CommitmentTracker({
|
|
6311
6355
|
stateDir: config.stateDir,
|
|
6312
6356
|
liveConfig,
|
|
6357
|
+
// P1.5 §3.1: the creator stamp — (originMachineId, id) is the
|
|
6358
|
+
// cross-machine identity (ids are per-machine sequential counters).
|
|
6359
|
+
...(cjOwnMachineId ? { originMachineId: cjOwnMachineId } : {}),
|
|
6313
6360
|
onViolation: (commitment, detail) => {
|
|
6314
6361
|
notify('IMMEDIATE', 'commitment', `You asked me to "${commitment.userRequest}" but it looks like that setting reverted. ${detail}`);
|
|
6315
6362
|
},
|
|
@@ -9706,6 +9753,13 @@ export async function startServer(options) {
|
|
|
9706
9753
|
// double-gate on stage!=='dark' to be safe. Fire-and-forget: the durable receipt
|
|
9707
9754
|
// is already recorded + ACKed before this runs.
|
|
9708
9755
|
onAccepted: (cmd) => {
|
|
9756
|
+
// Working-set move trigger (WORKING-SET-HANDOFF §3.3) — fire-and-forget,
|
|
9757
|
+
// BEFORE the stage gate (the coordinator carries its own gates; dark ⇒ undefined).
|
|
9758
|
+
{
|
|
9759
|
+
const wsTopic = Number(cmd.session);
|
|
9760
|
+
if (Number.isFinite(wsTopic))
|
|
9761
|
+
workingSetPullCoordinator?.onTopicAccepted(wsTopic);
|
|
9762
|
+
}
|
|
9709
9763
|
if (_sessionPoolStage() === 'dark' || !telegram)
|
|
9710
9764
|
return;
|
|
9711
9765
|
const tg = telegram;
|
|
@@ -9846,7 +9900,13 @@ export async function startServer(options) {
|
|
|
9846
9900
|
const journalAdvert = coherenceJournal
|
|
9847
9901
|
? { [cjOwnMachineId ?? meshSelfId]: coherenceJournal.getOwnAdvert() }
|
|
9848
9902
|
: {};
|
|
9849
|
-
|
|
9903
|
+
// COMMITMENTS-COHERENCE-SPEC §3.2: the commitments advert —
|
|
9904
|
+
// answered from MEMORY (never a disk read on the presence
|
|
9905
|
+
// tick). Omitted while the layer is dark; old peers ignore it.
|
|
9906
|
+
const commitmentsAdvert = commitmentReplicaStore
|
|
9907
|
+
? commitmentTracker.getReplicationAdvert() ?? undefined
|
|
9908
|
+
: undefined;
|
|
9909
|
+
return { ...base, journalAdvert, ...(commitmentsAdvert ? { commitmentsAdvert } : {}) };
|
|
9850
9910
|
},
|
|
9851
9911
|
// COHERENCE-JOURNAL-SPEC §3.4 — always-registered journal-sync verb
|
|
9852
9912
|
// (harmless when no peer sends): serve our OWN stream on `request`
|
|
@@ -9872,6 +9932,36 @@ export async function startServer(options) {
|
|
|
9872
9932
|
}
|
|
9873
9933
|
return { ok: true };
|
|
9874
9934
|
},
|
|
9935
|
+
// WORKING-SET-HANDOFF-SPEC §3.2 — the chunked working-set serve
|
|
9936
|
+
// verb. Registered always (lockstep with the union+RBAC edits so
|
|
9937
|
+
// a mixed-version caller gets a clean answer, never no-handler
|
|
9938
|
+
// surprises within one version); answers 'disabled' until the
|
|
9939
|
+
// §3.7 replication gate constructs the serve side above.
|
|
9940
|
+
'working-set-pull': (cmd) => {
|
|
9941
|
+
if (!workingSetPullServer)
|
|
9942
|
+
return { ok: false, reason: 'working-set disabled' };
|
|
9943
|
+
return workingSetPullServer.handle(cmd);
|
|
9944
|
+
},
|
|
9945
|
+
// COMMITMENTS-COHERENCE-SPEC §3.2 — serve OWN commitment records
|
|
9946
|
+
// as seq-windowed delta pages. Registered always (lockstep with
|
|
9947
|
+
// the union+RBAC edits); answers 'disabled' until the replication
|
|
9948
|
+
// gate constructs the layer AND the tracker advertises.
|
|
9949
|
+
'commitments-sync': async (cmd) => {
|
|
9950
|
+
const c = cmd;
|
|
9951
|
+
if (!commitmentReplicaStore || !commitmentTracker)
|
|
9952
|
+
return { ok: false, reason: 'commitments-sync disabled' };
|
|
9953
|
+
const advert = commitmentTracker.getReplicationAdvert();
|
|
9954
|
+
if (!advert)
|
|
9955
|
+
return { ok: false, reason: 'commitments-sync disabled' };
|
|
9956
|
+
const syncMod = await import('../core/CommitmentsSync.js');
|
|
9957
|
+
const wsCfgC = config.multiMachine?.coherenceJournal?.commitments;
|
|
9958
|
+
return syncMod.buildCommitmentsSyncPage(c.request, {
|
|
9959
|
+
ownMachineId: cjOwnMachineId ?? meshSelfId,
|
|
9960
|
+
records: commitmentTracker.getAll(),
|
|
9961
|
+
advert,
|
|
9962
|
+
syncPageBytes: wsCfgC?.syncPageBytes,
|
|
9963
|
+
});
|
|
9964
|
+
},
|
|
9875
9965
|
place: ownAction,
|
|
9876
9966
|
claim: ownAction,
|
|
9877
9967
|
transfer: ownAction,
|
|
@@ -9959,6 +10049,162 @@ export async function startServer(options) {
|
|
|
9959
10049
|
const selfNickTimer = setInterval(() => { void convergeSelfNickname(); }, 60_000);
|
|
9960
10050
|
if (typeof selfNickTimer.unref === 'function')
|
|
9961
10051
|
selfNickTimer.unref();
|
|
10052
|
+
// ── Working-set pull coordinator (WORKING-SET-HANDOFF §3.3/§3.4) ──
|
|
10053
|
+
// Constructed here (after meshClient + peerUrl exist) ONLY when the
|
|
10054
|
+
// serve side was constructed above — i.e. the same explicit
|
|
10055
|
+
// replication.enabled === true gate. Wires the move trigger (the
|
|
10056
|
+
// onAccepted seam reads the hoisted variable), the reflex route, the
|
|
10057
|
+
// returning-peer staggered drain, and the slow sweep tick.
|
|
10058
|
+
if (workingSetPullServer) {
|
|
10059
|
+
try {
|
|
10060
|
+
const wscMod = await import('../core/WorkingSetPullCoordinator.js');
|
|
10061
|
+
const ledgerMod = await import('../core/PendingPullLedger.js');
|
|
10062
|
+
const wsPullMod = await import('../core/WorkingSetPull.js');
|
|
10063
|
+
const wsReaderMod2 = await import('../core/CoherenceJournalReader.js');
|
|
10064
|
+
const wsCfg = config.multiMachine?.coherenceJournal?.workingSet;
|
|
10065
|
+
const wsLedger = new ledgerMod.PendingPullLedger({
|
|
10066
|
+
stateDir: config.stateDir,
|
|
10067
|
+
ttlDays: wsCfg?.pendingPullTtlDays,
|
|
10068
|
+
onCorrupt: (qPath) => {
|
|
10069
|
+
void telegram?.createAttentionItem({
|
|
10070
|
+
id: `WS-LEDGER-CORRUPT-${Date.now()}`,
|
|
10071
|
+
title: 'Working-set pending-pull ledger was unreadable',
|
|
10072
|
+
summary: `The pending-pull ledger could not be parsed and was quarantined to ${path.basename(qPath)}. Stranded-recovery records may be lost — workspaces awaiting an offline machine may need a manual POST /coherence/fetch-working-set once that machine returns.`,
|
|
10073
|
+
category: 'agent-health',
|
|
10074
|
+
priority: 'NORMAL',
|
|
10075
|
+
lane: 'agent-health',
|
|
10076
|
+
sourceContext: 'working-set-handoff',
|
|
10077
|
+
}).catch(() => { });
|
|
10078
|
+
},
|
|
10079
|
+
onExpired: (rec) => {
|
|
10080
|
+
void telegram?.createAttentionItem({
|
|
10081
|
+
id: `WS-PULL-EXPIRED-${rec.topic}-${rec.epoch}`,
|
|
10082
|
+
title: `Topic ${rec.topic}'s working set was never recovered`,
|
|
10083
|
+
summary: `A working-set pull for topic ${rec.topic} from ${rec.nominee} stayed unrecoverable for the full retention window (reason: ${rec.reason}, ${rec.attempts} attempts). The files remain on ${rec.nominee}; bring it back online or run POST /coherence/fetch-working-set {"topic":${rec.topic}} once reachable.`,
|
|
10084
|
+
category: 'agent-health',
|
|
10085
|
+
priority: 'NORMAL',
|
|
10086
|
+
lane: 'agent-health',
|
|
10087
|
+
sourceContext: 'working-set-handoff',
|
|
10088
|
+
}).catch(() => { });
|
|
10089
|
+
},
|
|
10090
|
+
logger: (m) => console.log(pc.dim(` [working-set] ${m}`)),
|
|
10091
|
+
});
|
|
10092
|
+
const wsReader2 = new wsReaderMod2.CoherenceJournalReader({ stateDir: config.stateDir });
|
|
10093
|
+
const wsSelf = cjOwnMachineId ?? meshSelfId;
|
|
10094
|
+
const wsOwnerOf = (topic) => {
|
|
10095
|
+
const rec = sessionOwnershipRegistry?.read(String(topic));
|
|
10096
|
+
return { owner: rec?.ownerMachineId ?? null, epoch: rec?.ownershipEpoch ?? null };
|
|
10097
|
+
};
|
|
10098
|
+
workingSetPullCoordinator = new wscMod.WorkingSetPullCoordinator({
|
|
10099
|
+
stateDir: config.stateDir,
|
|
10100
|
+
ownMachineId: wsSelf,
|
|
10101
|
+
reader: wsReader2,
|
|
10102
|
+
ledger: wsLedger,
|
|
10103
|
+
ownerOf: wsOwnerOf,
|
|
10104
|
+
makePuller: (nominee, topic, epoch) => {
|
|
10105
|
+
const url = peerUrl(nominee);
|
|
10106
|
+
if (!url)
|
|
10107
|
+
return null;
|
|
10108
|
+
return new wsPullMod.WorkingSetPuller({
|
|
10109
|
+
stateDir: config.stateDir,
|
|
10110
|
+
send: async (cmd) => {
|
|
10111
|
+
const r = await meshClient.send({ machineId: nominee, url }, cmd, 0);
|
|
10112
|
+
if (!r.ok)
|
|
10113
|
+
throw new Error(`mesh ${r.status}: ${r.reason ?? 'error'}`);
|
|
10114
|
+
return r.result;
|
|
10115
|
+
},
|
|
10116
|
+
senderShortId: nominee,
|
|
10117
|
+
stillCurrent: () => {
|
|
10118
|
+
const o = wsOwnerOf(topic);
|
|
10119
|
+
return o.owner === wsSelf && o.epoch === epoch;
|
|
10120
|
+
},
|
|
10121
|
+
pullMaxBatchBytes: wsCfg?.pullMaxBatchBytes,
|
|
10122
|
+
chunkRestartCap: wsCfg?.chunkRestartCap,
|
|
10123
|
+
chunksPerTick: wsCfg?.chunksPerTick,
|
|
10124
|
+
busyRetryCap: wsCfg?.busyRetryCap,
|
|
10125
|
+
logger: (m) => console.log(pc.dim(` [working-set] ${m}`)),
|
|
10126
|
+
});
|
|
10127
|
+
},
|
|
10128
|
+
rearmConcurrency: wsCfg?.rearmConcurrency,
|
|
10129
|
+
logger: (m) => console.log(pc.dim(` [working-set] ${m}`)),
|
|
10130
|
+
});
|
|
10131
|
+
// The slow tick: TTL sweep + live-source re-arm (§3.4). 10 min.
|
|
10132
|
+
const wsSweepTimer = setInterval(() => {
|
|
10133
|
+
void workingSetPullCoordinator?.sweep().catch(() => { });
|
|
10134
|
+
}, 600_000);
|
|
10135
|
+
if (typeof wsSweepTimer.unref === 'function')
|
|
10136
|
+
wsSweepTimer.unref();
|
|
10137
|
+
// ── Peer-visibility guard (§3.6, the rider) ──
|
|
10138
|
+
// Improper revocations surface on boot + a registry recheck each
|
|
10139
|
+
// guard tick; disappearances are checked against the pool
|
|
10140
|
+
// registry's online view. All notices ride the agent-health
|
|
10141
|
+
// attention lane (coalescing, never topic-per-event).
|
|
10142
|
+
const guardMod = await import('../core/PeerVisibilityGuard.js');
|
|
10143
|
+
const visibilityGuard = new guardMod.PeerVisibilityGuard({
|
|
10144
|
+
stateDir: config.stateDir,
|
|
10145
|
+
selfMachineId: meshSelfId,
|
|
10146
|
+
strandedTopicsFor: async (machineId) => {
|
|
10147
|
+
const recs = await wsLedger.pendingForPeer(machineId);
|
|
10148
|
+
return [...new Set(recs.map((r) => r.topic))];
|
|
10149
|
+
},
|
|
10150
|
+
notify: (notice) => {
|
|
10151
|
+
void telegram?.createAttentionItem({
|
|
10152
|
+
id: `WS-GUARD-${notice.kind}-${notice.machineId}-${Date.now()}`,
|
|
10153
|
+
title: notice.title,
|
|
10154
|
+
summary: notice.body,
|
|
10155
|
+
category: 'agent-health',
|
|
10156
|
+
priority: 'NORMAL',
|
|
10157
|
+
lane: 'agent-health',
|
|
10158
|
+
sourceContext: 'peer-visibility-guard',
|
|
10159
|
+
}).catch(() => { });
|
|
10160
|
+
},
|
|
10161
|
+
logger: (m) => console.log(pc.dim(` [visibility-guard] ${m}`)),
|
|
10162
|
+
});
|
|
10163
|
+
// Boot check (§3.6.1) — the Mini's 10-invisible-hours case.
|
|
10164
|
+
try {
|
|
10165
|
+
visibilityGuard.checkRevocations(meshIdMgr.loadRegistry());
|
|
10166
|
+
}
|
|
10167
|
+
catch { /* @silent-fallback-ok: a guard boot-check failure must never block server boot; the guard-tick recheck covers it (WORKING-SET-HANDOFF-SPEC §3.6) */
|
|
10168
|
+
}
|
|
10169
|
+
const wsGuardTimer = setInterval(() => {
|
|
10170
|
+
try {
|
|
10171
|
+
const reg = meshIdMgr.loadRegistry();
|
|
10172
|
+
visibilityGuard.checkRevocations(reg);
|
|
10173
|
+
const expected = Object.entries(reg.machines ?? {})
|
|
10174
|
+
.filter(([, e]) => !e.revokedAt)
|
|
10175
|
+
.map(([id]) => id);
|
|
10176
|
+
const online = new Set((machinePoolRegistry?.getCapacities() ?? [])
|
|
10177
|
+
.filter((c) => c.online)
|
|
10178
|
+
.map((c) => c.machineId));
|
|
10179
|
+
void visibilityGuard.checkDisappearances(expected, online).catch(() => { });
|
|
10180
|
+
}
|
|
10181
|
+
catch { /* @silent-fallback-ok: the guard is observability — a failed tick is skipped, never compounds (WORKING-SET-HANDOFF-SPEC §3.6) */
|
|
10182
|
+
}
|
|
10183
|
+
}, 300_000);
|
|
10184
|
+
if (typeof wsGuardTimer.unref === 'function')
|
|
10185
|
+
wsGuardTimer.unref();
|
|
10186
|
+
console.log(pc.dim(' [working-set] pull coordinator wired (trigger + reflex + drain + sweep + visibility guard)'));
|
|
10187
|
+
// ── Commitments-coherence receive side (P1.5a §3.2) ──
|
|
10188
|
+
// Same explicit replication gate. The puller drive below pulls
|
|
10189
|
+
// delta pages whenever a peer's advert is ahead of our cursor.
|
|
10190
|
+
try {
|
|
10191
|
+
const csMod = await import('../core/CommitmentsSync.js');
|
|
10192
|
+
commitmentReplicaStore = new csMod.CommitmentReplicaStore({
|
|
10193
|
+
stateDir: config.stateDir,
|
|
10194
|
+
logger: (m) => console.log(pc.dim(` [commitments-sync] ${m}`)),
|
|
10195
|
+
});
|
|
10196
|
+
console.log(pc.dim(' [commitments-sync] replica store wired (serve + receive + advert)'));
|
|
10197
|
+
}
|
|
10198
|
+
catch (e) { /* @silent-fallback-ok: commitments-sync construction failure degrades to local-only commitments — never blocks boot (COMMITMENTS-COHERENCE-SPEC §4) */
|
|
10199
|
+
commitmentReplicaStore = undefined;
|
|
10200
|
+
console.log(pc.dim(` [commitments-sync] not constructed: ${e instanceof Error ? e.message : String(e)}`));
|
|
10201
|
+
}
|
|
10202
|
+
}
|
|
10203
|
+
catch (e) { /* @silent-fallback-ok: working-set pull wiring failure degrades to serve-only (the verb still answers); never blocks server boot (WORKING-SET-HANDOFF-SPEC §4) */
|
|
10204
|
+
workingSetPullCoordinator = undefined;
|
|
10205
|
+
console.log(pc.dim(` [working-set] coordinator not constructed: ${e instanceof Error ? e.message : String(e)}`));
|
|
10206
|
+
}
|
|
10207
|
+
}
|
|
9962
10208
|
// ── Secret-sync OUTBOUND provisioner (push-on-provision, spec Phase 4) ──
|
|
9963
10209
|
// Constructed here (after meshClient + peerUrl exist). Encrypts the secret set
|
|
9964
10210
|
// PER online peer to that peer's X25519 key and pushes a signed `secret-share`.
|
|
@@ -10201,6 +10447,7 @@ export async function startServer(options) {
|
|
|
10201
10447
|
.map((m) => ({ machineId: m.machineId, url: peerUrl(m.machineId) })),
|
|
10202
10448
|
recordHeartbeat: (obs) => { machinePoolRegistry?.recordHeartbeat(obs); },
|
|
10203
10449
|
log: (line) => console.log(pc.dim(` [peer-presence] ${line}`)),
|
|
10450
|
+
onPeerRecorded: (machineId) => workingSetPullCoordinator?.onPeerRecorded(machineId), // working-set re-arm (§3.4); no-op when dark
|
|
10204
10451
|
fetchPeerCapacity: async (machineId, url) => {
|
|
10205
10452
|
const res = await meshClient.send({ machineId, url }, { type: 'session-status' }, 0);
|
|
10206
10453
|
if (res.ok && res.result && typeof res.result === 'object') {
|
|
@@ -10212,6 +10459,39 @@ export async function startServer(options) {
|
|
|
10212
10459
|
},
|
|
10213
10460
|
// REPLICATION-GATED: present only when replication.enabled === true.
|
|
10214
10461
|
..._journalDeltaDeps,
|
|
10462
|
+
// COMMITMENTS-COHERENCE-SPEC §3.2 — pull delta pages when the
|
|
10463
|
+
// peer's advert is ahead of our replica cursor; bounded pages per
|
|
10464
|
+
// tick (the remainder rides the next pass). No-op while dark.
|
|
10465
|
+
driveCommitmentsSync: async (machineId, url, advert) => {
|
|
10466
|
+
if (!commitmentReplicaStore)
|
|
10467
|
+
return;
|
|
10468
|
+
const cursor = commitmentReplicaStore.cursorFor(machineId);
|
|
10469
|
+
const upToDate = cursor.incarnation === advert.incarnation && cursor.sinceSeq >= advert.replicationSeq;
|
|
10470
|
+
if (upToDate)
|
|
10471
|
+
return;
|
|
10472
|
+
const csCfg = config.multiMachine?.coherenceJournal?.commitments;
|
|
10473
|
+
const maxPages = csCfg?.maxSyncPagesPerTick ?? 4;
|
|
10474
|
+
let since = cursor.incarnation === advert.incarnation ? cursor.sinceSeq : 0;
|
|
10475
|
+
let inc = cursor.incarnation;
|
|
10476
|
+
for (let i = 0; i < maxPages; i++) {
|
|
10477
|
+
const res = await meshClient.send({ machineId, url }, { type: 'commitments-sync', request: { sinceSeq: since, ...(inc ? { incarnation: inc } : {}) } }, 0);
|
|
10478
|
+
if (!res.ok || !res.result || typeof res.result !== 'object')
|
|
10479
|
+
return;
|
|
10480
|
+
const page = res.result;
|
|
10481
|
+
if (!page.incarnation)
|
|
10482
|
+
return; // 'disabled' answer shape
|
|
10483
|
+
commitmentReplicaStore.applyPage(machineId, page);
|
|
10484
|
+
if (page.incarnationChanged) {
|
|
10485
|
+
inc = page.incarnation;
|
|
10486
|
+
since = 0;
|
|
10487
|
+
continue;
|
|
10488
|
+
}
|
|
10489
|
+
since = page.nextSinceSeq;
|
|
10490
|
+
inc = page.incarnation;
|
|
10491
|
+
if (page.done)
|
|
10492
|
+
return;
|
|
10493
|
+
}
|
|
10494
|
+
},
|
|
10215
10495
|
});
|
|
10216
10496
|
void peerPresencePuller.pullOnce();
|
|
10217
10497
|
const peerPresenceTimer = setInterval(() => { void peerPresencePuller.pullOnce(); }, 30_000);
|
|
@@ -10452,7 +10732,7 @@ export async function startServer(options) {
|
|
|
10452
10732
|
catch (err) {
|
|
10453
10733
|
console.log(pc.dim(` [session-pool] rollout gate not wired: ${err instanceof Error ? err.message : String(err)}`));
|
|
10454
10734
|
}
|
|
10455
|
-
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, coherenceGate: scopeVerifier, contextHierarchy, canonicalState, operationGate, sentinel, adaptiveTrust, memoryMonitor, orphanReaper, coherenceMonitor, commitmentTracker, semanticMemory, activitySentinel, rateLimitSentinel, releaseReadinessSentinel: releaseReadinessSentinel ?? undefined, messageRouter, summarySentinel, spawnManager, systemReviewer, capabilityMapper, selfKnowledgeTree, coverageAuditor, topicResumeMap: _topicResumeMap ?? undefined, sessionRefresh: _sessionRefresh ?? undefined, autonomyManager, trustElevationTracker, autonomousEvolution, coordinator: coordinator.enabled ? coordinator : undefined, localSigningKeyPem, leaseTransport, 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, warrantsReplyGate, collaborationSurfacer, threadResumeMap, topicLinkageHandler: topicLinkageHandler ?? undefined, threadlineRelayClient, threadlineReplyWaiters, listenerManager: listenerManager ?? undefined, responseReviewGate, messagingToneGate, outboundDedupGate, telemetryHeartbeat, pasteManager, featureRegistry, discoveryEvaluator, completionEvaluator, unifiedTrust, liveConfig, sharedStateLedger, ledgerSessionRegistry, worktreeManager, oidcEnrolledRepos: parallelDevConfig?.oidcEnrolledRepos, initiativeTracker, projectRoundRunner, projectDriftChecker, machineHeartbeat, machinePoolRegistry, meshRpcDispatcher, sessionOwnershipRegistry, topicPinStore: _topicPinStore ?? undefined, secretSync: _secretSyncHandle ?? undefined, meshSelfId: _meshSelfId ?? undefined, resolveRouterUrl: _resolveRouterUrl ?? undefined, resolvePeerUrls: _resolvePeerUrls ?? undefined, sessionPoolE2EResultStore, proxyCoordinator, topicIntentStore, topicIntentArcCheck, usherSignalStore, intelligence: sharedIntelligence ?? undefined, telegramBridgeConfig, telegramBridge: telegramBridge ?? undefined, threadlineObservability, briefDeps, workingMemory, taskFlowRegistry, threadlineFlowBridge, sessionReaper, agentWorktreeReaper, mcpProcessReaper, geminiLoopRunner, sleepController, agentActivityState, reapLog, sleepWakeDetector, unjustifiedStopGate, stopGateDb, stopNotifier });
|
|
10735
|
+
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, coherenceGate: scopeVerifier, contextHierarchy, canonicalState, operationGate, sentinel, adaptiveTrust, memoryMonitor, orphanReaper, coherenceMonitor, commitmentTracker, semanticMemory, activitySentinel, rateLimitSentinel, releaseReadinessSentinel: releaseReadinessSentinel ?? undefined, messageRouter, summarySentinel, spawnManager, systemReviewer, capabilityMapper, selfKnowledgeTree, coverageAuditor, topicResumeMap: _topicResumeMap ?? undefined, sessionRefresh: _sessionRefresh ?? undefined, autonomyManager, trustElevationTracker, autonomousEvolution, coordinator: coordinator.enabled ? coordinator : undefined, localSigningKeyPem, leaseTransport, 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, warrantsReplyGate, collaborationSurfacer, threadResumeMap, topicLinkageHandler: topicLinkageHandler ?? undefined, threadlineRelayClient, threadlineReplyWaiters, listenerManager: listenerManager ?? undefined, responseReviewGate, messagingToneGate, outboundDedupGate, telemetryHeartbeat, pasteManager, featureRegistry, discoveryEvaluator, completionEvaluator, unifiedTrust, liveConfig, sharedStateLedger, ledgerSessionRegistry, worktreeManager, oidcEnrolledRepos: parallelDevConfig?.oidcEnrolledRepos, initiativeTracker, projectRoundRunner, projectDriftChecker, machineHeartbeat, machinePoolRegistry, meshRpcDispatcher, workingSetPullCoordinator, commitmentReplicaStore, sessionOwnershipRegistry, topicPinStore: _topicPinStore ?? undefined, secretSync: _secretSyncHandle ?? undefined, meshSelfId: _meshSelfId ?? undefined, resolveRouterUrl: _resolveRouterUrl ?? undefined, resolvePeerUrls: _resolvePeerUrls ?? undefined, sessionPoolE2EResultStore, proxyCoordinator, topicIntentStore, topicIntentArcCheck, usherSignalStore, intelligence: sharedIntelligence ?? undefined, telegramBridgeConfig, telegramBridge: telegramBridge ?? undefined, threadlineObservability, briefDeps, workingMemory, taskFlowRegistry, threadlineFlowBridge, sessionReaper, agentWorktreeReaper, mcpProcessReaper, geminiLoopRunner, sleepController, agentActivityState, reapLog, sleepWakeDetector, unjustifiedStopGate, stopGateDb, stopNotifier });
|
|
10456
10736
|
// Boot-recovery (tunnel-failure-resilience spec Part 6): if the agent
|
|
10457
10737
|
// died mid-relay-episode, the persisted tunnel.json carries
|
|
10458
10738
|
// rotationPending=true. Rotate the dashboard PIN + authToken BEFORE
|