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.
Files changed (70) hide show
  1. package/dist/commands/server.d.ts.map +1 -1
  2. package/dist/commands/server.js +282 -2
  3. package/dist/commands/server.js.map +1 -1
  4. package/dist/config/ConfigDefaults.d.ts.map +1 -1
  5. package/dist/config/ConfigDefaults.js +29 -0
  6. package/dist/config/ConfigDefaults.js.map +1 -1
  7. package/dist/core/CommitmentsSync.d.ts +144 -0
  8. package/dist/core/CommitmentsSync.d.ts.map +1 -0
  9. package/dist/core/CommitmentsSync.js +293 -0
  10. package/dist/core/CommitmentsSync.js.map +1 -0
  11. package/dist/core/MeshRpc.d.ts +14 -0
  12. package/dist/core/MeshRpc.d.ts.map +1 -1
  13. package/dist/core/MeshRpc.js +7 -1
  14. package/dist/core/MeshRpc.js.map +1 -1
  15. package/dist/core/PeerPresencePuller.d.ts +25 -0
  16. package/dist/core/PeerPresencePuller.d.ts.map +1 -1
  17. package/dist/core/PeerPresencePuller.js +12 -0
  18. package/dist/core/PeerPresencePuller.js.map +1 -1
  19. package/dist/core/PeerVisibilityGuard.d.ts +83 -0
  20. package/dist/core/PeerVisibilityGuard.d.ts.map +1 -0
  21. package/dist/core/PeerVisibilityGuard.js +204 -0
  22. package/dist/core/PeerVisibilityGuard.js.map +1 -0
  23. package/dist/core/PendingPullLedger.d.ts +129 -0
  24. package/dist/core/PendingPullLedger.d.ts.map +1 -0
  25. package/dist/core/PendingPullLedger.js +239 -0
  26. package/dist/core/PendingPullLedger.js.map +1 -0
  27. package/dist/core/PostUpdateMigrator.d.ts.map +1 -1
  28. package/dist/core/PostUpdateMigrator.js +20 -0
  29. package/dist/core/PostUpdateMigrator.js.map +1 -1
  30. package/dist/core/WorkingSetManifest.d.ts +2 -0
  31. package/dist/core/WorkingSetManifest.d.ts.map +1 -1
  32. package/dist/core/WorkingSetManifest.js +13 -1
  33. package/dist/core/WorkingSetManifest.js.map +1 -1
  34. package/dist/core/WorkingSetPull.d.ts +157 -0
  35. package/dist/core/WorkingSetPull.d.ts.map +1 -0
  36. package/dist/core/WorkingSetPull.js +546 -0
  37. package/dist/core/WorkingSetPull.js.map +1 -0
  38. package/dist/core/WorkingSetPullCoordinator.d.ts +134 -0
  39. package/dist/core/WorkingSetPullCoordinator.d.ts.map +1 -0
  40. package/dist/core/WorkingSetPullCoordinator.js +306 -0
  41. package/dist/core/WorkingSetPullCoordinator.js.map +1 -0
  42. package/dist/core/types.d.ts +39 -1
  43. package/dist/core/types.d.ts.map +1 -1
  44. package/dist/core/types.js.map +1 -1
  45. package/dist/monitoring/CommitmentTracker.d.ts +40 -0
  46. package/dist/monitoring/CommitmentTracker.d.ts.map +1 -1
  47. package/dist/monitoring/CommitmentTracker.js +95 -4
  48. package/dist/monitoring/CommitmentTracker.js.map +1 -1
  49. package/dist/scaffold/templates.d.ts.map +1 -1
  50. package/dist/scaffold/templates.js +4 -0
  51. package/dist/scaffold/templates.js.map +1 -1
  52. package/dist/server/AgentServer.d.ts +6 -0
  53. package/dist/server/AgentServer.d.ts.map +1 -1
  54. package/dist/server/AgentServer.js +2 -0
  55. package/dist/server/AgentServer.js.map +1 -1
  56. package/dist/server/routes.d.ts +9 -0
  57. package/dist/server/routes.d.ts.map +1 -1
  58. package/dist/server/routes.js +44 -1
  59. package/dist/server/routes.js.map +1 -1
  60. package/package.json +1 -1
  61. package/src/data/builtin-manifest.json +64 -64
  62. package/src/data/state-coherence-registry.json +61 -13
  63. package/src/scaffold/templates.ts +4 -0
  64. package/upgrades/1.3.367.md +134 -0
  65. package/upgrades/1.3.368.md +52 -0
  66. package/upgrades/side-effects/commitments-sync-p15a.md +93 -0
  67. package/upgrades/side-effects/working-set-ci-absorb.md +29 -0
  68. package/upgrades/side-effects/working-set-parity-absorb.md +35 -0
  69. package/upgrades/side-effects/working-set-pull-p22a.md +121 -0
  70. 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,CAmuStE;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"}
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"}
@@ -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
- return { ...base, journalAdvert };
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