instar 1.3.825 → 1.3.826
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 +25 -0
- package/dist/commands/server.js.map +1 -1
- package/dist/core/MachineHeartbeat.d.ts +10 -0
- package/dist/core/MachineHeartbeat.d.ts.map +1 -1
- package/dist/core/MachineHeartbeat.js +17 -0
- package/dist/core/MachineHeartbeat.js.map +1 -1
- package/dist/monitoring/SpeakerElection.d.ts +16 -0
- package/dist/monitoring/SpeakerElection.d.ts.map +1 -1
- package/dist/monitoring/SpeakerElection.js +35 -10
- package/dist/monitoring/SpeakerElection.js.map +1 -1
- package/package.json +1 -1
- package/src/data/builtin-manifest.json +2 -2
- package/upgrades/1.3.826.md +22 -0
- package/upgrades/side-effects/speaker-election-owner-liveness.md +56 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/commands/server.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/commands/server.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAyDH,OAAO,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAU3D,OAAO,EAAE,eAAe,EAAiC,MAAM,iCAAiC,CAAC;AA0BjG,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAGvD,OAAO,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAC;AA6H7D,OAAO,KAAK,EAAW,oBAAoB,EAAe,YAAY,EAAE,MAAM,kBAAkB,CAAC;AACjG,OAAO,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAgFtD;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,yBAAyB,CACvC,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,EACf,gBAAgB,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAC1C,OAAO,CAUT;AAyID,UAAU,YAAY;IACpB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb;2DACuD;IACvD,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAkoDD;;;;;;;;GAQG;AACH,wBAAgB,wBAAwB,CACtC,MAAM,EAAE,YAAY,EACpB,YAAY,EAAE,oBAAoB,GAAG,IAAI,GACxC;IACD,YAAY,EAAE,oBAAoB,GAAG,IAAI,CAAC;IAC1C,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,OAAO,CAAC;IAChB,aAAa,EAAE,MAAM,CAAC;IACtB,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,GAAG,UAAU,GAAG,SAAS,CAAC;IAC3C,QAAQ,EAAE,MAAM,CAAC;CAClB,CAqBA;AAED,wBAAgB,mBAAmB,CACjC,QAAQ,EAAE,eAAe,EACzB,cAAc,EAAE,cAAc,EAC9B,YAAY,CAAC,EAAE,YAAY,EAC3B,WAAW,CAAC,EAAE,WAAW,EACzB,WAAW,CAAC,EAAE,WAAW,EACzB,iBAAiB,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,EAGvE,UAAU,CAAC,EAAE,MAAM,OAAO,8BAA8B,EAAE,WAAW,GAAG,IAAI,EAK5E,qBAAqB,CAAC,EAAE,MAAM,OAAO,gCAAgC,EAAE,kBAAkB,GAAG,IAAI,EAKhG,mBAAmB,CAAC,EAAE,MAAM,MAAM,GAAG,IAAI,GAAG,SAAS,EAQrD,oBAAoB,CAAC,EAAE,MAAM;IAC3B,YAAY,EAAE,OAAO,kBAAkB,EAAE,oBAAoB,GAAG,IAAI,CAAC;IACrE,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,OAAO,CAAC;IAChB,aAAa,EAAE,MAAM,CAAC;IACtB,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,GAAG,UAAU,GAAG,SAAS,CAAC;IAC3C,QAAQ,EAAE,MAAM,CAAC;CAClB,GAAG,IAAI,GACP,IAAI,CAssBN;AAgmBD,wBAAsB,WAAW,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CA6xnBtE;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
|
@@ -21,6 +21,7 @@ const execFileAsync = promisify(execFile);
|
|
|
21
21
|
import { loadConfig, ensureStateDir, detectTmuxPath, detectGeminiPath } from '../core/Config.js';
|
|
22
22
|
import { handleProcessLevelError } from '../core/uncaughtExceptionPolicy.js';
|
|
23
23
|
import { planInboundLossNotices } from '../core/inboundLossRouting.js';
|
|
24
|
+
import { heartbeatFreshEnoughToRerecord } from '../core/MachineHeartbeat.js';
|
|
24
25
|
import { slackRespawnBootstrapIds } from '../core/slackRefreshBinding.js';
|
|
25
26
|
import { configureHostSpawnSemaphore } from '../core/hostSpawnSemaphore.js';
|
|
26
27
|
import { SpawningTopicsRegistry } from '../core/SpawningTopicsRegistry.js';
|
|
@@ -12513,6 +12514,19 @@ export async function startServer(options) {
|
|
|
12513
12514
|
console.log(`[SpeakerElection] topic ${topicId}: speak=${v.speak} (${v.reason})`);
|
|
12514
12515
|
}
|
|
12515
12516
|
},
|
|
12517
|
+
// Owner-liveness (speaker-election-owner-liveness Layer 1). ENFORCE only when
|
|
12518
|
+
// EXPLICITLY enabled AND not dryRun — default (no config) is observe-only, so
|
|
12519
|
+
// the verdict is UNCHANGED at ship. The live enforce-flip is deferred (ACT-1196).
|
|
12520
|
+
ownerLivenessEnforce: () => {
|
|
12521
|
+
const c = config.monitoring?.speakerElection?.ownerLiveness;
|
|
12522
|
+
return c?.enabled === true && c?.dryRun === false;
|
|
12523
|
+
},
|
|
12524
|
+
// Bounded observe surface (captured in the size-rotated server log): measures
|
|
12525
|
+
// how often a placement/stamp owner LOOKED dark (and, downstream, how often it
|
|
12526
|
+
// was a FALSE dark) so the enforce-flip decision has real soak data.
|
|
12527
|
+
onOwnerLivenessObservation: (o) => {
|
|
12528
|
+
console.log(`[SpeakerElection.ownerLiveness] would-fall-through topic=${o.topicId} owner=${o.owner} self=${o.self} rule=${o.rule} online=${o.onlinePool.length}`);
|
|
12529
|
+
},
|
|
12516
12530
|
});
|
|
12517
12531
|
let presenceProxy;
|
|
12518
12532
|
if (sharedIntelligence && telegram) {
|
|
@@ -17861,8 +17875,19 @@ export async function startServer(options) {
|
|
|
17861
17875
|
});
|
|
17862
17876
|
const hbApi = machineHeartbeat?.api;
|
|
17863
17877
|
if (hbApi) {
|
|
17878
|
+
// Layer 0 (speaker-election-owner-liveness): a DEAD peer's git-synced
|
|
17879
|
+
// heartbeat file lingers, and re-recording it every ~30s stamps a fresh
|
|
17880
|
+
// LOCAL receipt (routerReceivedAtMs) → the peer stays online:true FOREVER
|
|
17881
|
+
// locally, so any owner/holder-liveness read silently no-ops. Gate the
|
|
17882
|
+
// re-record on the record's SELF-REPORTED freshness: skip when
|
|
17883
|
+
// lastHeartbeatAt is older than >=2x the ~30min write cadence (~60min), or
|
|
17884
|
+
// unparseable (fail toward not-refreshing). A live git-syncing peer
|
|
17885
|
+
// (mid-interval) is always within the window → never flapped dark; only a
|
|
17886
|
+
// peer silent for >2 cadences (genuinely dead) ages out of `online`.
|
|
17864
17887
|
for (const r of hbApi.listAll()) {
|
|
17865
17888
|
if (r.machineId !== poolSelfId) {
|
|
17889
|
+
if (!heartbeatFreshEnoughToRerecord(r.lastHeartbeatAt, Date.now()))
|
|
17890
|
+
continue;
|
|
17866
17891
|
// COARSE: the file-based MachineHeartbeat is git-synced + written every
|
|
17867
17892
|
// ~30min, so its lastHeartbeatAt is NOT a live clock reading. Mark it coarse
|
|
17868
17893
|
// so it refreshes liveness but never drives the 5-min clock-skew quarantine
|