instar 1.3.346 → 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 +121 -5
- 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/monitoring/RateLimitSentinel.d.ts +5 -2
- package/dist/monitoring/RateLimitSentinel.d.ts.map +1 -1
- package/dist/monitoring/RateLimitSentinel.js.map +1 -1
- package/dist/monitoring/sentinelWiring.d.ts +13 -4
- package/dist/monitoring/sentinelWiring.d.ts.map +1 -1
- package/dist/monitoring/sentinelWiring.js +10 -8
- package/dist/monitoring/sentinelWiring.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.347.md +76 -0
- package/upgrades/1.3.348.md +57 -0
- package/upgrades/coherence-journal-meshwire.eli16.md +9 -0
- package/upgrades/rate-limit-resume-nudge-internal-channel.eli16.md +35 -0
- package/upgrades/side-effects/coherence-journal-meshwire.md +49 -0
- package/upgrades/side-effects/rate-limit-resume-nudge-internal-channel.md +102 -0
- package/upgrades/side-effects/resolver-verdict-honesty.md +45 -0
- package/upgrades/1.3.346.md +0 -57
|
@@ -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
|
|
@@ -5856,7 +5886,9 @@ export async function startServer(options) {
|
|
|
5856
5886
|
const { buildRateLimitRecoveryDeps } = await import('../monitoring/sentinelWiring.js');
|
|
5857
5887
|
const { resumeFn: rateLimitResume, notifyFn: rateLimitNotify } = buildRateLimitRecoveryDeps({
|
|
5858
5888
|
isSessionAlive: (name) => sessionManager.isSessionAlive(name),
|
|
5859
|
-
|
|
5889
|
+
// Resume nudge is infrastructure, never a user message — it goes through
|
|
5890
|
+
// the internal recovery channel ONLY (no `[telegram:N]` prefix), so the
|
|
5891
|
+
// agent can't mistake it for the user and relay a contradictory reply.
|
|
5860
5892
|
injectInternalNudge: (name, text) => sessionManager.injectInternalMessage(name, text, 'sentinel-recovery'),
|
|
5861
5893
|
getTopicForSession: (name) => telegram?.getTopicForSession(name),
|
|
5862
5894
|
getLifelineTopicId: () => telegram?.getLifelineTopicId?.(),
|
|
@@ -9805,7 +9837,41 @@ export async function startServer(options) {
|
|
|
9805
9837
|
},
|
|
9806
9838
|
handlers: {
|
|
9807
9839
|
'capacity-report': () => machinePoolRegistry?.getCapacities() ?? [],
|
|
9808
|
-
'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
|
+
},
|
|
9809
9875
|
place: ownAction,
|
|
9810
9876
|
claim: ownAction,
|
|
9811
9877
|
transfer: ownAction,
|
|
@@ -10081,21 +10147,71 @@ export async function startServer(options) {
|
|
|
10081
10147
|
// so it authenticates off the mutual identity established at pairing —
|
|
10082
10148
|
// no router role, no epoch fence required.
|
|
10083
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
|
+
};
|
|
10084
10196
|
const peerPresencePuller = new presenceMod.PeerPresencePuller({
|
|
10085
10197
|
selfMachineId: meshSelfId,
|
|
10086
10198
|
listPeers: () => meshIdMgr
|
|
10087
10199
|
.getActiveMachines()
|
|
10088
10200
|
.filter((m) => !m.entry.revokedAt)
|
|
10089
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}`)),
|
|
10090
10204
|
fetchPeerCapacity: async (machineId, url) => {
|
|
10091
10205
|
const res = await meshClient.send({ machineId, url }, { type: 'session-status' }, 0);
|
|
10092
10206
|
if (res.ok && res.result && typeof res.result === 'object') {
|
|
10093
|
-
|
|
10207
|
+
const cap = res.result;
|
|
10208
|
+
const journalAdvert = _unwrapPeerJournalAdvert(machineId, cap.journalAdvert);
|
|
10209
|
+
return { selfReportedLastSeen: cap.selfReportedLastSeen, loadAvg: cap.loadAvg, journalAdvert };
|
|
10094
10210
|
}
|
|
10095
10211
|
return null;
|
|
10096
10212
|
},
|
|
10097
|
-
|
|
10098
|
-
|
|
10213
|
+
// REPLICATION-GATED: present only when replication.enabled === true.
|
|
10214
|
+
..._journalDeltaDeps,
|
|
10099
10215
|
});
|
|
10100
10216
|
void peerPresencePuller.pullOnce();
|
|
10101
10217
|
const peerPresenceTimer = setInterval(() => { void peerPresencePuller.pullOnce(); }, 30_000);
|