instar 1.3.688 → 1.3.690
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 +106 -0
- package/dist/commands/server.js.map +1 -1
- package/dist/config/ConfigDefaults.d.ts.map +1 -1
- package/dist/config/ConfigDefaults.js +11 -0
- package/dist/config/ConfigDefaults.js.map +1 -1
- package/dist/core/SessionManager.d.ts.map +1 -1
- package/dist/core/SessionManager.js +8 -0
- package/dist/core/SessionManager.js.map +1 -1
- package/dist/core/devGatedFeatures.d.ts.map +1 -1
- package/dist/core/devGatedFeatures.js +5 -0
- package/dist/core/devGatedFeatures.js.map +1 -1
- package/dist/core/leaseGatedSpawn.d.ts +232 -0
- package/dist/core/leaseGatedSpawn.d.ts.map +1 -0
- package/dist/core/leaseGatedSpawn.js +216 -0
- package/dist/core/leaseGatedSpawn.js.map +1 -0
- package/dist/core/nobodyPollingRecovery.d.ts +138 -0
- package/dist/core/nobodyPollingRecovery.d.ts.map +1 -0
- package/dist/core/nobodyPollingRecovery.js +147 -0
- package/dist/core/nobodyPollingRecovery.js.map +1 -0
- package/dist/server/CapabilityIndex.d.ts.map +1 -1
- package/dist/server/CapabilityIndex.js +1 -0
- package/dist/server/CapabilityIndex.js.map +1 -1
- package/dist/server/routes.d.ts.map +1 -1
- package/dist/server/routes.js +95 -0
- package/dist/server/routes.js.map +1 -1
- package/package.json +1 -1
- package/src/data/builtin-manifest.json +47 -47
- package/upgrades/1.3.689.md +30 -0
- package/upgrades/1.3.690.md +28 -0
- package/upgrades/side-effects/mesh-self-heal-g2-core.md +32 -0
- package/upgrades/side-effects/mesh-self-heal-g2-observe.md +34 -0
- package/upgrades/side-effects/mesh-self-heal-g3.md +45 -0
- package/upgrades/side-effects/mesh-self-heal-spec.md +37 -0
package/dist/server/routes.js
CHANGED
|
@@ -8,9 +8,11 @@ import { Router } from 'express';
|
|
|
8
8
|
import { execFileSync } from 'node:child_process';
|
|
9
9
|
import { createHash, timingSafeEqual, randomUUID } from 'node:crypto';
|
|
10
10
|
import { classifyActionClaim } from '../core/action-claim.js';
|
|
11
|
+
import { sharedG3SoakLedger, decideLeaseGatedSpawn } from '../core/leaseGatedSpawn.js';
|
|
11
12
|
import { getHostSpawnSemaphore, configuredSpawnAcquireMs, configuredSpawnWaitersMax } from '../core/hostSpawnSemaphore.js';
|
|
12
13
|
import { activeSpawnPollers } from '../core/SpawnCapIntelligenceProvider.js';
|
|
13
14
|
import { poolPollerVerdict } from '../core/pollerCount.js';
|
|
15
|
+
import { decideNobodyPollingClaim, sharedG2NobodyPollingLedger } from '../core/nobodyPollingRecovery.js';
|
|
14
16
|
import { canonicalPushKey } from '../core/PrHandLease.js';
|
|
15
17
|
import { enrollPaneSessionName } from '../core/FrameworkLoginDriver.js';
|
|
16
18
|
import fs from 'node:fs';
|
|
@@ -4561,6 +4563,21 @@ export function createRoutes(ctx) {
|
|
|
4561
4563
|
}
|
|
4562
4564
|
res.json(ctx.sessionReaper.snapshot());
|
|
4563
4565
|
});
|
|
4566
|
+
// G3 lease-gated-spawn soak evidence (MESH-SELF-HEAL-SPEC §3.3). The operator's
|
|
4567
|
+
// PROMOTION-EVIDENCE surface — the answer to "is this dark feature actually
|
|
4568
|
+
// doing anything, and should I promote it?" (operator directive 2026-06-27:
|
|
4569
|
+
// observe-mode must produce an evaluable promotion recommendation, not rot
|
|
4570
|
+
// dark forever). `summary` carries the counterfactual `wouldHavePreventedDuplicate`;
|
|
4571
|
+
// `promotion` is the deterministic recommendation (promote | keep-soaking |
|
|
4572
|
+
// consider-removal | enforcing). Read-only; never gates.
|
|
4573
|
+
router.get('/mesh-selfheal/g3', (_req, res) => {
|
|
4574
|
+
res.json({
|
|
4575
|
+
feature: 'lease-gated-spawn',
|
|
4576
|
+
flag: 'multiMachine.sessionPool.ownershipCheckedSpawn',
|
|
4577
|
+
summary: sharedG3SoakLedger.summary(),
|
|
4578
|
+
promotion: sharedG3SoakLedger.promotionSignal(),
|
|
4579
|
+
});
|
|
4580
|
+
});
|
|
4564
4581
|
// AgentWorktreeReaper (RESPONSIBLE-RESOURCE-USAGE — OS resource hygiene). The
|
|
4565
4582
|
// pull-surface answer to "which stale worktrees can be reclaimed, and why is
|
|
4566
4583
|
// each kept?": every `.worktrees/` worktree's verdict (active-lock /
|
|
@@ -11389,6 +11406,56 @@ document.getElementById('mcpForm').addEventListener('submit', async function (e)
|
|
|
11389
11406
|
machines: caps.map((c) => ({ machineId: c.machineId, nickname: c.nickname, online: c.online, pollingActive: c.pollingActive })),
|
|
11390
11407
|
});
|
|
11391
11408
|
});
|
|
11409
|
+
// G2 nobody-polling silence debounce — module-scoped streak across reads, so a
|
|
11410
|
+
// transient handoff-gap silence never reads as confirmed (Adv-F9).
|
|
11411
|
+
const G2_NOBODY_POLLING_CONFIRM_OBSERVATIONS = 3;
|
|
11412
|
+
let _g2SilenceStreak = 0;
|
|
11413
|
+
// GET /mesh-selfheal/g2 — MESH-SELF-HEAL-SPEC §3.2 G2 OBSERVE surface (increment
|
|
11414
|
+
// 2: detector + single-claimant election, REPORT-only). Computes the B5 verdict
|
|
11415
|
+
// over the live pool, debounces a `silence` across reads (nobodyPollingConfirmObservations),
|
|
11416
|
+
// runs the pure G2 decision (who should claim poll-ownership), records the
|
|
11417
|
+
// counterfactual to the shared soak ledger, and returns it. OBSERVE-only: it
|
|
11418
|
+
// does NOT actuate (no fenced-CAS acquire, no poll-lever write) — the enforce
|
|
11419
|
+
// actuation is the next increment. Read-driven: each poll advances the soak.
|
|
11420
|
+
router.get('/mesh-selfheal/g2', (_req, res) => {
|
|
11421
|
+
const caps = ctx.machinePoolRegistry?.getCapacities() ?? [];
|
|
11422
|
+
const sync = ctx.coordinator ? ctx.coordinator.getSyncStatus() : null;
|
|
11423
|
+
const selfMachineId = ctx.coordinator?.identity?.machineId ?? null;
|
|
11424
|
+
const verdict = poolPollerVerdict(caps.map((c) => ({ machineId: c.machineId, online: c.online, pollingActive: c.pollingActive })), false);
|
|
11425
|
+
// Debounce a silence across reads (Adv-F9: a normal handoff gap is transient
|
|
11426
|
+
// and must not trip a claim). Module-scoped streak counter.
|
|
11427
|
+
if (verdict.verdict === 'silence')
|
|
11428
|
+
_g2SilenceStreak += 1;
|
|
11429
|
+
else
|
|
11430
|
+
_g2SilenceStreak = 0;
|
|
11431
|
+
const silenceConfirmed = _g2SilenceStreak >= G2_NOBODY_POLLING_CONFIRM_OBSERVATIONS;
|
|
11432
|
+
// fit (observe approximation): heartbeat-fresh = a candidate that COULD take
|
|
11433
|
+
// over polling. In a `silence` NOBODY is polling, so fitness is NOT tied to
|
|
11434
|
+
// pollingActive (that would exclude exactly the idle-but-healthy machines that
|
|
11435
|
+
// should claim). The enforce increment refines this with the machine-local
|
|
11436
|
+
// pollSucceededMonoMs re-verify (post-CAS) + self-exclusion advertisement.
|
|
11437
|
+
const machines = caps.map((c) => ({ machineId: c.machineId, fit: !!c.online }));
|
|
11438
|
+
const decision = decideNobodyPollingClaim({
|
|
11439
|
+
selfMachineId: selfMachineId ?? '(unknown)',
|
|
11440
|
+
pollerVerdict: verdict.verdict,
|
|
11441
|
+
silenceConfirmed,
|
|
11442
|
+
preferredAwakeMachineId: sync?.preferredAwakeMachineId ?? null,
|
|
11443
|
+
machines,
|
|
11444
|
+
// Peer-evidence-of-global-outage plumbing is the enforce increment; observe
|
|
11445
|
+
// never claims a global outage (false → a confirmed silence proceeds to elect).
|
|
11446
|
+
globalOutageEvidence: false,
|
|
11447
|
+
});
|
|
11448
|
+
sharedG2NobodyPollingLedger.recordClaim(decision, new Date().toISOString());
|
|
11449
|
+
res.json({
|
|
11450
|
+
enabled: !!ctx.machinePoolRegistry,
|
|
11451
|
+
verdict,
|
|
11452
|
+
silenceStreak: _g2SilenceStreak,
|
|
11453
|
+
silenceConfirmed,
|
|
11454
|
+
selfMachineId,
|
|
11455
|
+
decision,
|
|
11456
|
+
ledger: sharedG2NobodyPollingLedger.summary(),
|
|
11457
|
+
});
|
|
11458
|
+
});
|
|
11392
11459
|
// GET /pool/poll-cache — WS4.4(f) global pool-cache observability
|
|
11393
11460
|
// (MULTI-MACHINE-SEAMLESSNESS-SPEC §WS4.4 clause (f)). Read-only: reports
|
|
11394
11461
|
// whether the shared per-peer poll cache is wired, its TTL + load-shed
|
|
@@ -14645,6 +14712,34 @@ document.getElementById('mcpForm').addEventListener('submit', async function (e)
|
|
|
14645
14712
|
if (resumeSessionId) {
|
|
14646
14713
|
console.log(`[telegram-forward] Found resume UUID for topic ${topicId}: ${resumeSessionId} (source: TopicResumeMap — trusted)`);
|
|
14647
14714
|
}
|
|
14715
|
+
// G3 — record the lease-gated-spawn decision for this SECONDARY spawn
|
|
14716
|
+
// entry (the /internal/telegram-forward auto-spawn). This route is
|
|
14717
|
+
// same-machine-only (injectionDropped respawn @server.ts + the lifeline
|
|
14718
|
+
// poll) — cross-machine delivery bypasses it via MeshRpc→durable queue —
|
|
14719
|
+
// so there is NO forward seam here and gating can never ping-pong.
|
|
14720
|
+
// forwardAvailable:false makes this RECORD-ONLY: it always spawns
|
|
14721
|
+
// (never strands a local re-entry), but feeds the shared soak ledger so
|
|
14722
|
+
// the promotion evidence covers BOTH spawn entries, not just the cold
|
|
14723
|
+
// path. Dark+dryRun by default ⇒ strict no-op on behavior.
|
|
14724
|
+
try {
|
|
14725
|
+
const o = ctx.config?.multiMachine?.sessionPool?.ownershipCheckedSpawn ?? {};
|
|
14726
|
+
const g3 = decideLeaseGatedSpawn({
|
|
14727
|
+
holdsLease: ctx.coordinator ? ctx.coordinator.holdsLease() : true,
|
|
14728
|
+
flagEnabled: o.enabled === true,
|
|
14729
|
+
dryRun: o.dryRun !== false,
|
|
14730
|
+
singleMachine: ctx.coordinator === null,
|
|
14731
|
+
forwardAvailable: false,
|
|
14732
|
+
});
|
|
14733
|
+
sharedG3SoakLedger.record(g3, new Date().toISOString());
|
|
14734
|
+
if (g3.action !== 'spawn') {
|
|
14735
|
+
console.log(`[g3-spawn-gate] (telegram-forward) topic ${topicId}: action=${g3.action} reason=${g3.reason} (record-only — local re-entry, no forward seam)`);
|
|
14736
|
+
}
|
|
14737
|
+
}
|
|
14738
|
+
catch (err) {
|
|
14739
|
+
// @silent-fallback-ok — the soak record is observability only; a record
|
|
14740
|
+
// failure must never block the spawn (the safe direction).
|
|
14741
|
+
console.warn(`[g3-spawn-gate] (telegram-forward) record failed (non-fatal): ${err instanceof Error ? err.message : String(err)}`);
|
|
14742
|
+
}
|
|
14648
14743
|
ctx.sessionManager.spawnInteractiveSession(bootstrapMessage, topicName, { telegramTopicId: topicId, resumeSessionId }).then((newSessionName) => {
|
|
14649
14744
|
// Clear resume entry after successful spawn
|
|
14650
14745
|
if (resumeSessionId) {
|