instar 1.3.347 → 1.3.348
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 +118 -4
- package/dist/commands/server.js.map +1 -1
- package/dist/core/CoherenceJournal.d.ts +13 -0
- package/dist/core/CoherenceJournal.d.ts.map +1 -1
- package/dist/core/CoherenceJournal.js +16 -0
- package/dist/core/CoherenceJournal.js.map +1 -1
- package/dist/core/MeshRpc.d.ts +17 -0
- package/dist/core/MeshRpc.d.ts.map +1 -1
- package/dist/core/MeshRpc.js +5 -1
- package/dist/core/MeshRpc.js.map +1 -1
- package/dist/core/PeerPresencePuller.d.ts +45 -0
- package/dist/core/PeerPresencePuller.d.ts.map +1 -1
- package/dist/core/PeerPresencePuller.js +59 -0
- package/dist/core/PeerPresencePuller.js.map +1 -1
- package/dist/redteam/ScenarioPack.d.ts +22 -5
- package/dist/redteam/ScenarioPack.d.ts.map +1 -1
- package/dist/redteam/ScenarioPack.js +19 -7
- package/dist/redteam/ScenarioPack.js.map +1 -1
- package/package.json +1 -1
- package/src/data/builtin-manifest.json +2 -2
- package/upgrades/1.3.348.md +57 -0
- package/upgrades/coherence-journal-meshwire.eli16.md +9 -0
- package/upgrades/side-effects/coherence-journal-meshwire.md +49 -0
- package/upgrades/side-effects/resolver-verdict-honesty.md +45 -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,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"}
|
package/dist/commands/server.js
CHANGED
|
@@ -2343,6 +2343,15 @@ export async function startServer(options) {
|
|
|
2343
2343
|
// the reaper/ownership wiring that emits into it. Writer runs even on a
|
|
2344
2344
|
// single-machine agent (locally useful); replication is P1.3.
|
|
2345
2345
|
let coherenceJournal;
|
|
2346
|
+
// The journal's OWN machine id (used by the journal-sync SERVE path to read
|
|
2347
|
+
// this machine's own stream files, which are keyed on it). Hoisted so the
|
|
2348
|
+
// mesh dispatcher (wired much later) can drive the shared applier's
|
|
2349
|
+
// buildServeBatch against the right stream.
|
|
2350
|
+
let cjOwnMachineId;
|
|
2351
|
+
// ONE shared JournalSyncApplier (P1.3 engine) — drives both the journal-sync
|
|
2352
|
+
// RECEIVE handler (always-registered; harmless when idle) and the
|
|
2353
|
+
// REPLICATION-GATED puller delta drive. Constructed only when the journal is.
|
|
2354
|
+
let journalSyncApplier;
|
|
2346
2355
|
{
|
|
2347
2356
|
const cjCfg = config.multiMachine?.coherenceJournal;
|
|
2348
2357
|
const cjEnabled = cjCfg?.enabled ?? !!config.developmentAgent;
|
|
@@ -2353,6 +2362,7 @@ export async function startServer(options) {
|
|
|
2353
2362
|
// hostname-derived fallback for single-machine agents (sanitized by
|
|
2354
2363
|
// the journal's own percent-encode rule either way).
|
|
2355
2364
|
const cjMachineId = coordinator.identity?.machineId ?? `m_host_${os.hostname()}`;
|
|
2365
|
+
cjOwnMachineId = cjMachineId;
|
|
2356
2366
|
coherenceJournal = new cjMod.CoherenceJournal({
|
|
2357
2367
|
stateDir: config.stateDir,
|
|
2358
2368
|
machineId: cjMachineId,
|
|
@@ -2367,6 +2377,26 @@ export async function startServer(options) {
|
|
|
2367
2377
|
// Lifecycle funnel (§3.3): every session status transition flows
|
|
2368
2378
|
// through StateManager.saveSession; the diff-derived emit lives there.
|
|
2369
2379
|
state.setCoherenceJournal(coherenceJournal);
|
|
2380
|
+
// ONE shared JournalSyncApplier (P1.3 engine) — the RECEIVE/own-stream
|
|
2381
|
+
// SERVE side of replication. Same guardWrite seam as the writer. The
|
|
2382
|
+
// mesh dispatcher registers an always-on journal-sync handler over it
|
|
2383
|
+
// (harmless when no peer sends), and the REPLICATION-GATED puller drive
|
|
2384
|
+
// shares this same instance. Construction here does NOT enable
|
|
2385
|
+
// replication SEND/drive — that gate is config.multiMachine
|
|
2386
|
+
// .coherenceJournal.replication.enabled === true, checked at the puller
|
|
2387
|
+
// wiring below.
|
|
2388
|
+
try {
|
|
2389
|
+
const applierMod = await import('../core/JournalSyncApplier.js');
|
|
2390
|
+
journalSyncApplier = new applierMod.JournalSyncApplier({
|
|
2391
|
+
stateDir: config.stateDir,
|
|
2392
|
+
guardWrite: (p) => state.guardJournalWrite(p),
|
|
2393
|
+
logger: (m) => console.log(pc.dim(` [journal-sync] ${m}`)),
|
|
2394
|
+
});
|
|
2395
|
+
}
|
|
2396
|
+
catch (e) { /* @silent-fallback-ok: journal observability must never endanger the observed operation (COHERENCE-JOURNAL-SPEC §3.1) */
|
|
2397
|
+
journalSyncApplier = undefined;
|
|
2398
|
+
console.log(pc.dim(` [journal-sync] applier not constructed: ${e instanceof Error ? e.message : String(e)}`));
|
|
2399
|
+
}
|
|
2370
2400
|
// §3.3 autonomous-run journal scanner — observation-based start/stop
|
|
2371
2401
|
// (no single .local.md write funnel exists; polling is the structural
|
|
2372
2402
|
// choice). P19 brakes, declared: constant per-tick cost (bounded by
|
|
@@ -9807,7 +9837,41 @@ export async function startServer(options) {
|
|
|
9807
9837
|
},
|
|
9808
9838
|
handlers: {
|
|
9809
9839
|
'capacity-report': () => machinePoolRegistry?.getCapacities() ?? [],
|
|
9810
|
-
'session-status': () =>
|
|
9840
|
+
'session-status': () => {
|
|
9841
|
+
const base = machinePoolRegistry?.getCapacity(meshSelfId) ?? { machineId: meshSelfId };
|
|
9842
|
+
// COHERENCE-JOURNAL-SPEC §3.4 rule 5: advertise this machine's OWN
|
|
9843
|
+
// durably-flushed stream heads so a peer can compute deltas. {}
|
|
9844
|
+
// when the journal is disabled. Forward/backward compatible — old
|
|
9845
|
+
// peers ignore the extra field, old callers don't read it.
|
|
9846
|
+
const journalAdvert = coherenceJournal
|
|
9847
|
+
? { [cjOwnMachineId ?? meshSelfId]: coherenceJournal.getOwnAdvert() }
|
|
9848
|
+
: {};
|
|
9849
|
+
return { ...base, journalAdvert };
|
|
9850
|
+
},
|
|
9851
|
+
// COHERENCE-JOURNAL-SPEC §3.4 — always-registered journal-sync verb
|
|
9852
|
+
// (harmless when no peer sends): serve our OWN stream on `request`
|
|
9853
|
+
// (first-hop only), durably apply an inbound `batch`. The RBAC gate
|
|
9854
|
+
// already proved a registered peer; the applier's first-hop sender
|
|
9855
|
+
// binding fences forged entries (entry.machine must === env.sender).
|
|
9856
|
+
'journal-sync': (cmd, _sender, env) => {
|
|
9857
|
+
const c = cmd;
|
|
9858
|
+
if (!journalSyncApplier)
|
|
9859
|
+
return { ok: false, reason: 'journal disabled' };
|
|
9860
|
+
if (c.request) {
|
|
9861
|
+
// §3.4 rule 5 serve-batch byte cap (coherenceJournal.replication
|
|
9862
|
+
// .maxBatchBytes; the applier defaults it when absent).
|
|
9863
|
+
const maxBatchBytes = config.multiMachine?.coherenceJournal?.replication?.maxBatchBytes;
|
|
9864
|
+
const served = journalSyncApplier.buildServeBatch(c.request.kind, c.request.fromSeq, cjOwnMachineId ?? meshSelfId, maxBatchBytes);
|
|
9865
|
+
return { batch: [served] };
|
|
9866
|
+
}
|
|
9867
|
+
if (c.batch) {
|
|
9868
|
+
// Apply binds every entry to the AUTHENTICATED envelope sender —
|
|
9869
|
+
// never a payload field — so a forged sender is rejected + counted.
|
|
9870
|
+
const r = journalSyncApplier.apply(env.sender, c.batch);
|
|
9871
|
+
return { ok: true, result: r };
|
|
9872
|
+
}
|
|
9873
|
+
return { ok: true };
|
|
9874
|
+
},
|
|
9811
9875
|
place: ownAction,
|
|
9812
9876
|
claim: ownAction,
|
|
9813
9877
|
transfer: ownAction,
|
|
@@ -10083,21 +10147,71 @@ export async function startServer(options) {
|
|
|
10083
10147
|
// so it authenticates off the mutual identity established at pairing —
|
|
10084
10148
|
// no router role, no epoch fence required.
|
|
10085
10149
|
const presenceMod = await import('../core/PeerPresencePuller.js');
|
|
10150
|
+
// ── REPLICATION ACTIVATION GATE (CRITICAL SAFETY) ────────────────────
|
|
10151
|
+
// The journal-sync SEND/drive path is gated on EXPLICIT-true only:
|
|
10152
|
+
// config.multiMachine.coherenceJournal.replication.enabled === true.
|
|
10153
|
+
// This is DELIBERATELY NOT the `?? !!developmentAgent` dark-feature
|
|
10154
|
+
// gate — the engine + transport land dark even on the dev agent; a
|
|
10155
|
+
// human flips replication on for a monitored live proof. When false
|
|
10156
|
+
// (the default — ConfigDefaults leaves replication.enabled absent), the
|
|
10157
|
+
// delta deps below are left undefined and the puller behaves EXACTLY as
|
|
10158
|
+
// before: a presence-only poll, no journal delta ever requested/applied.
|
|
10159
|
+
const _replicationEnabled = config.multiMachine?.coherenceJournal
|
|
10160
|
+
?.replication?.enabled === true;
|
|
10161
|
+
const _journalDeltaDeps = _replicationEnabled && journalSyncApplier
|
|
10162
|
+
? {
|
|
10163
|
+
requestJournalDelta: async (machineId, url, kind, fromSeq) => {
|
|
10164
|
+
try {
|
|
10165
|
+
const res = await meshClient.send({ machineId, url }, { type: 'journal-sync', request: { machineId, kind, fromSeq } }, 0);
|
|
10166
|
+
if (res.ok && res.result && typeof res.result === 'object' && 'batch' in res.result) {
|
|
10167
|
+
const b = res.result.batch;
|
|
10168
|
+
if (Array.isArray(b) && b.length > 0) {
|
|
10169
|
+
return b[0];
|
|
10170
|
+
}
|
|
10171
|
+
}
|
|
10172
|
+
}
|
|
10173
|
+
catch { /* @silent-fallback-ok: a journal-sync delta fetch to a peer is best-effort + self-healing — an unreachable/rejected peer simply yields no delta this pass and the next presence tick re-requests; never endanger the presence pass (COHERENCE-JOURNAL-SPEC §3.1) */ }
|
|
10174
|
+
return null;
|
|
10175
|
+
},
|
|
10176
|
+
applyDelta: (senderMachineId, batch) => {
|
|
10177
|
+
journalSyncApplier?.apply(senderMachineId, batch);
|
|
10178
|
+
},
|
|
10179
|
+
localAdvertFor: (machineId) => journalSyncApplier?.getAdvertState()[machineId] ?? {},
|
|
10180
|
+
}
|
|
10181
|
+
: {};
|
|
10182
|
+
if (_replicationEnabled) {
|
|
10183
|
+
console.log(pc.yellow(' [journal-sync] REPLICATION SEND/drive ENABLED (replication.enabled===true) — live proof mode'));
|
|
10184
|
+
}
|
|
10185
|
+
// Unwrap the PEER's own-stream slice (keyed on its machine id) from the
|
|
10186
|
+
// nested `{ [ownMachineId]: { kind → {…} } }` session-status advert to the
|
|
10187
|
+
// flat `kind → {incarnation,lastSeq}` shape the puller drive compares
|
|
10188
|
+
// against what we hold for that peer. First-hop: a peer serves only its
|
|
10189
|
+
// OWN stream, so its advert has exactly its own key (fall back to the
|
|
10190
|
+
// first/only entry if the key differs).
|
|
10191
|
+
const _unwrapPeerJournalAdvert = (machineId, nested) => {
|
|
10192
|
+
if (!nested || typeof nested !== 'object')
|
|
10193
|
+
return undefined;
|
|
10194
|
+
return nested[machineId] ?? Object.values(nested)[0];
|
|
10195
|
+
};
|
|
10086
10196
|
const peerPresencePuller = new presenceMod.PeerPresencePuller({
|
|
10087
10197
|
selfMachineId: meshSelfId,
|
|
10088
10198
|
listPeers: () => meshIdMgr
|
|
10089
10199
|
.getActiveMachines()
|
|
10090
10200
|
.filter((m) => !m.entry.revokedAt)
|
|
10091
10201
|
.map((m) => ({ machineId: m.machineId, url: peerUrl(m.machineId) })),
|
|
10202
|
+
recordHeartbeat: (obs) => { machinePoolRegistry?.recordHeartbeat(obs); },
|
|
10203
|
+
log: (line) => console.log(pc.dim(` [peer-presence] ${line}`)),
|
|
10092
10204
|
fetchPeerCapacity: async (machineId, url) => {
|
|
10093
10205
|
const res = await meshClient.send({ machineId, url }, { type: 'session-status' }, 0);
|
|
10094
10206
|
if (res.ok && res.result && typeof res.result === 'object') {
|
|
10095
|
-
|
|
10207
|
+
const cap = res.result;
|
|
10208
|
+
const journalAdvert = _unwrapPeerJournalAdvert(machineId, cap.journalAdvert);
|
|
10209
|
+
return { selfReportedLastSeen: cap.selfReportedLastSeen, loadAvg: cap.loadAvg, journalAdvert };
|
|
10096
10210
|
}
|
|
10097
10211
|
return null;
|
|
10098
10212
|
},
|
|
10099
|
-
|
|
10100
|
-
|
|
10213
|
+
// REPLICATION-GATED: present only when replication.enabled === true.
|
|
10214
|
+
..._journalDeltaDeps,
|
|
10101
10215
|
});
|
|
10102
10216
|
void peerPresencePuller.pullOnce();
|
|
10103
10217
|
const peerPresenceTimer = setInterval(() => { void peerPresencePuller.pullOnce(); }, 30_000);
|