instar 1.3.1318 → 1.3.1319

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 (52) hide show
  1. package/dist/commands/server.d.ts.map +1 -1
  2. package/dist/commands/server.js +76 -61
  3. package/dist/commands/server.js.map +1 -1
  4. package/dist/core/HttpLeaseTransport.d.ts +1 -0
  5. package/dist/core/HttpLeaseTransport.d.ts.map +1 -1
  6. package/dist/core/HttpLeaseTransport.js +7 -4
  7. package/dist/core/HttpLeaseTransport.js.map +1 -1
  8. package/dist/core/LeaseCoordinator.d.ts +32 -1
  9. package/dist/core/LeaseCoordinator.d.ts.map +1 -1
  10. package/dist/core/LeaseCoordinator.js +101 -7
  11. package/dist/core/LeaseCoordinator.js.map +1 -1
  12. package/dist/core/MachinePoolRegistry.d.ts +6 -0
  13. package/dist/core/MachinePoolRegistry.d.ts.map +1 -1
  14. package/dist/core/MachinePoolRegistry.js +10 -0
  15. package/dist/core/MachinePoolRegistry.js.map +1 -1
  16. package/dist/core/MultiMachineCoordinator.d.ts +9 -0
  17. package/dist/core/MultiMachineCoordinator.d.ts.map +1 -1
  18. package/dist/core/MultiMachineCoordinator.js +16 -0
  19. package/dist/core/MultiMachineCoordinator.js.map +1 -1
  20. package/dist/core/PostUpdateMigrator.d.ts +1 -0
  21. package/dist/core/PostUpdateMigrator.d.ts.map +1 -1
  22. package/dist/core/PostUpdateMigrator.js +12 -0
  23. package/dist/core/PostUpdateMigrator.js.map +1 -1
  24. package/dist/core/leaseLiveness.d.ts +48 -0
  25. package/dist/core/leaseLiveness.d.ts.map +1 -1
  26. package/dist/core/leaseLiveness.js +121 -0
  27. package/dist/core/leaseLiveness.js.map +1 -1
  28. package/dist/core/leaseMediumSelection.d.ts +34 -0
  29. package/dist/core/leaseMediumSelection.d.ts.map +1 -0
  30. package/dist/core/leaseMediumSelection.js +77 -0
  31. package/dist/core/leaseMediumSelection.js.map +1 -0
  32. package/dist/core/types.d.ts +6 -0
  33. package/dist/core/types.d.ts.map +1 -1
  34. package/dist/core/types.js.map +1 -1
  35. package/dist/data/standards-guard-index.json +1 -1
  36. package/dist/data/standards-guard-index.meta.json +2 -2
  37. package/dist/data/standards-registry.meta.json +1 -1
  38. package/dist/monitoring/DegradationReporter.d.ts +4 -0
  39. package/dist/monitoring/DegradationReporter.d.ts.map +1 -1
  40. package/dist/monitoring/DegradationReporter.js +10 -6
  41. package/dist/monitoring/DegradationReporter.js.map +1 -1
  42. package/dist/scaffold/templates.d.ts.map +1 -1
  43. package/dist/scaffold/templates.js +2 -1
  44. package/dist/scaffold/templates.js.map +1 -1
  45. package/package.json +1 -1
  46. package/src/data/builtin-manifest.json +21 -21
  47. package/src/data/standards-guard-index.json +1 -1
  48. package/src/data/standards-guard-index.meta.json +2 -2
  49. package/src/data/standards-registry.meta.json +1 -1
  50. package/src/scaffold/templates.ts +2 -1
  51. package/upgrades/1.3.1319.md +36 -0
  52. package/upgrades/side-effects/lease-unconfirmed-candidate-flap.md +124 -0
@@ -1 +1 @@
1
- {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/commands/server.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/commands/server.ts"],"names":[],"mappings":"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"}
@@ -168,7 +168,7 @@ import { FencedLease } from '../core/FencedLease.js';
168
168
  import { GitLeaseStore } from '../core/GitLeaseStore.js';
169
169
  import { LocalLeaseStore } from '../core/LocalLeaseStore.js';
170
170
  import { LeaseCoordinator } from '../core/LeaseCoordinator.js';
171
- import { isPeerPresumedDead } from '../core/leaseLiveness.js';
171
+ import { buildLeaseLivenessCallbacks, createLeaseFlapSwitchGetter, isDialableLeasePeer, reportLeaseOrderingDegradation } from '../core/leaseLiveness.js';
172
172
  import { readPollActive, pidAlive as pollPidAlive } from '../core/pollIntent.js';
173
173
  import { checkMultiMachineConfigCoherence, checkMeshLiveStateCoherence, MESH_WARMUP_GRACE_MS } from '../core/configCoherence.js';
174
174
  import { HttpLeaseTransport } from '../core/HttpLeaseTransport.js';
@@ -203,6 +203,7 @@ import { AutonomousEvolution } from '../core/AutonomousEvolution.js';
203
203
  import { DispatchScopeEnforcer } from '../core/DispatchScopeEnforcer.js';
204
204
  import { TrustRecovery } from '../core/TrustRecovery.js';
205
205
  import { DegradationReporter } from '../monitoring/DegradationReporter.js';
206
+ import { reportLeaseMediumSelection, selectLeaseMedium } from '../core/leaseMediumSelection.js';
206
207
  import { HumanAsDetectorLog, observeInboundMessage } from '../monitoring/HumanAsDetectorLog.js';
207
208
  import { creditUsherOnMiss } from '../core/UsherActedCorrelator.js';
208
209
  import { resolveStableNodeBinary } from '../utils/resolveNodeBinary.js';
@@ -4984,6 +4985,9 @@ export async function startServer(options) {
4984
4985
  // window the closures fall back to lastSeen (safe). Function-body scope so it
4985
4986
  // is visible to BOTH the lease closures (deeper) and the registry assignment.
4986
4987
  let leaseLivenessRegistry;
4988
+ const leaseMonoNow = () => Number(process.hrtime.bigint() / 1000000n);
4989
+ const leaseBootMonoMs = leaseMonoNow();
4990
+ const leaseFlapSwitch = createLeaseFlapSwitchGetter((configPath, fallback) => liveConfig.get(configPath, fallback), (message) => console.log(pc.dim(` [lease] ${message}`)));
4987
4991
  // Construct gitSync for BOTH roles when this is a git-backed mesh machine:
4988
4992
  // a standby needs it to pull, and a standby that later self-elects to awake
4989
4993
  // (the Phase-0 scenario) must ALREADY have it so its role-change push fires.
@@ -5002,6 +5006,11 @@ export async function startServer(options) {
5002
5006
  // lease block was nested in the git-gated try, so a gitSync throw left the
5003
5007
  // standby with leaseHolder=null → MeshRpc 'not-router' → transfer dead.)
5004
5008
  let gitSyncRef;
5009
+ let leaseMedium = selectLeaseMedium({
5010
+ projectDir: config.projectDir,
5011
+ registryAbsPath: idMgr.registryPath,
5012
+ hasGitSyncManager: false,
5013
+ });
5005
5014
  if (isGitRepo && gitBackupEnabled) {
5006
5015
  try {
5007
5016
  gitSync = new GitSyncManager({
@@ -5024,19 +5033,37 @@ export async function startServer(options) {
5024
5033
  }
5025
5034
  }
5026
5035
  gitSyncRef = gitSync;
5036
+ leaseMedium = selectLeaseMedium({
5037
+ projectDir: config.projectDir,
5038
+ registryAbsPath: idMgr.registryPath,
5039
+ hasGitSyncManager: true,
5040
+ mediumCheckEnabled: config.multiMachine?.leaseFlapFix?.mediumCheck,
5041
+ });
5042
+ let peerCount = 0;
5043
+ try {
5044
+ peerCount = Object.entries(idMgr.loadRegistry().machines ?? {})
5045
+ .filter(([id, entry]) => id !== selfMachineId && !entry.revokedAt).length;
5046
+ }
5047
+ catch { /* @silent-fallback-ok — peer count only controls diagnostic wording. */ }
5048
+ try {
5049
+ reportLeaseMediumSelection(leaseMedium, peerCount, DegradationReporter.getInstance(), (message) => console.log(pc.dim(` Lease medium: ${message}`)));
5050
+ }
5051
+ catch { /* @silent-fallback-ok — reporting cannot discard an established git substrate. */ }
5027
5052
  // ── G2 wiring (spec §8 G2) — roleChange/leaseEpoch → debounced push ──
5028
5053
  // Without a subscriber the durable registry push never fires; a
5029
5054
  // wiring-integrity test asserts this subscription exists.
5030
- const gitSyncForDebounce = gitSyncRef;
5031
- registrySyncDebouncer = new RegistrySyncDebouncer({
5032
- commitAndPush: (msg, paths) => gitSyncForDebounce.commitAndPush(msg, paths),
5033
- registryAbsPath: coordinator.managers.identityManager.registryPath,
5034
- isAuthoritative: () => coordinator.isAwake,
5035
- debounceMs: seamlessness.registrySyncDebounceMs,
5036
- logger: (m) => console.log(pc.dim(m)),
5037
- });
5038
- wireRegistrySync(coordinator, registrySyncDebouncer);
5039
- console.log(pc.dim(' Registry sync wired (roleChange/leaseEpoch → durable push)'));
5055
+ if (leaseMedium.medium !== 'local') {
5056
+ const gitSyncForDebounce = gitSyncRef;
5057
+ registrySyncDebouncer = new RegistrySyncDebouncer({
5058
+ commitAndPush: (msg, paths) => gitSyncForDebounce.commitAndPush(msg, paths),
5059
+ registryAbsPath: coordinator.managers.identityManager.registryPath,
5060
+ isAuthoritative: () => coordinator.isAwake,
5061
+ debounceMs: seamlessness.registrySyncDebounceMs,
5062
+ logger: (m) => console.log(pc.dim(m)),
5063
+ });
5064
+ wireRegistrySync(coordinator, registrySyncDebouncer);
5065
+ console.log(pc.dim(' Registry sync wired (roleChange/leaseEpoch → durable push)'));
5066
+ }
5040
5067
  }
5041
5068
  catch (err) {
5042
5069
  // @silent-fallback-ok — git medium unavailable (SourceTreeGuard, no
@@ -5046,6 +5073,9 @@ export async function startServer(options) {
5046
5073
  gitSyncRef = undefined;
5047
5074
  }
5048
5075
  }
5076
+ const leaseGitRef = leaseMedium.medium === 'local' ? undefined : gitSyncRef;
5077
+ const leaseStoreName = leaseGitRef ? 'GitLeaseStore' : 'LocalLeaseStore';
5078
+ coordinator.attachLeaseMediumProvider(() => ({ ...leaseMedium, store: leaseStoreName }));
5049
5079
  try {
5050
5080
  // ── G1 fenced-lease integration (spec §6) ──────────────────
5051
5081
  // The lease is the authority for awake/standby + the MeshRpc router-only
@@ -5075,8 +5105,8 @@ export async function startServer(options) {
5075
5105
  failoverThresholdMs: seamlessness.failoverThresholdMs,
5076
5106
  });
5077
5107
  let leaseStore;
5078
- if (gitSyncRef) {
5079
- const gs = gitSyncRef;
5108
+ if (leaseGitRef) {
5109
+ const gs = leaseGitRef;
5080
5110
  leaseStore = new GitLeaseStore({
5081
5111
  machineId: selfMachineId,
5082
5112
  loadRegistry: () => idMgr.loadRegistry(),
@@ -5092,7 +5122,8 @@ export async function startServer(options) {
5092
5122
  filePath: path.join(config.stateDir, 'lease-local.json'),
5093
5123
  logger: (m) => console.log(pc.dim(m)),
5094
5124
  });
5095
- console.log(pc.dim(' Lease store: LocalLeaseStore (no git medium — HTTP transport carries cross-machine lease)'));
5125
+ const why = leaseMedium.reason === 'ignored' ? 'registry is git-ignored' : 'no git medium';
5126
+ console.log(pc.dim(` Lease store: LocalLeaseStore (${why} — HTTP transport carries cross-machine lease)`));
5096
5127
  }
5097
5128
  // Lease wire transport (spec §6) — the low-latency authoritative copy
5098
5129
  // travels over the existing authenticated machine channel. For a
@@ -5166,7 +5197,7 @@ export async function startServer(options) {
5166
5197
  peers: () => {
5167
5198
  const reg = idMgr.loadRegistry();
5168
5199
  return Object.entries(reg.machines ?? {})
5169
- .filter(([id, e]) => id !== selfMachineId && (!!e.lastKnownUrl || (e.endpoints?.length ?? 0) > 0) && !e.revokedAt)
5200
+ .filter(([id, e]) => id !== selfMachineId && isDialableLeasePeer(e))
5170
5201
  .map(([id, e]) => ({
5171
5202
  machineId: id,
5172
5203
  url: (e.lastKnownUrl ?? ''),
@@ -5202,34 +5233,36 @@ export async function startServer(options) {
5202
5233
  peerEndpointRecorder,
5203
5234
  logger: (m) => console.log(pc.dim(m)),
5204
5235
  });
5236
+ const leaseLiveness = buildLeaseLivenessCallbacks({
5237
+ selfMachineId,
5238
+ loadDiskRegistry: () => idMgr.loadRegistry(),
5239
+ getRouter: () => leaseLivenessRegistry,
5240
+ getFreshness: () => leaseCoordinatorRef,
5241
+ getLeaseFlapFixConfig: () => ({
5242
+ ...config.multiMachine?.leaseFlapFix,
5243
+ liveness: leaseFlapSwitch('liveness'),
5244
+ unconfirmedWriteAlert: leaseFlapSwitch('unconfirmedWriteAlert'),
5245
+ }),
5246
+ getSkewImmune: () => resolveDevAgentGate(config.multiMachine?.leaseSelfHeal?.skewImmuneLiveness?.enabled, config),
5247
+ failoverThresholdMs: seamlessness.failoverThresholdMs,
5248
+ bootMonoMs: leaseBootMonoMs,
5249
+ monoNow: leaseMonoNow,
5250
+ wallNow: Date.now,
5251
+ });
5252
+ try {
5253
+ reportLeaseOrderingDegradation(seamlessness.failoverThresholdMs, seamlessness.leaseTtlMs, leaseFlapSwitch('unconfirmedWriteAlert'));
5254
+ }
5255
+ catch { /* @silent-fallback-ok — boot diagnostics cannot abort lease initialization. */ }
5205
5256
  const leaseCoordinator = new LeaseCoordinator({
5206
5257
  lease: fencedLease,
5207
5258
  store: leaseStore,
5208
5259
  tunnel: leaseTransport,
5209
- presumedDeadHolders: () => {
5210
- const reg = idMgr.loadRegistry();
5211
- const nowMs = Date.now();
5212
- // B4 Decision 10 — skew-immune liveness when the flag resolves on AND
5213
- // the in-process registry has actually observed the peer; else legacy
5214
- // lastSeen. enabled OMITTED ⇒ developmentAgent gate.
5215
- const skewImmune = resolveDevAgentGate(config.multiMachine?.leaseSelfHeal?.skewImmuneLiveness?.enabled, config);
5216
- const dead = new Set();
5217
- for (const [id, e] of Object.entries(reg.machines ?? {})) {
5218
- if (id === selfMachineId)
5219
- continue;
5220
- const cap = leaseLivenessRegistry?.getCapacity(id);
5221
- if (isPeerPresumedDead({
5222
- lastSeenMs: Date.parse(e.lastSeen),
5223
- routerObserved: !!cap?.routerReceivedAt,
5224
- routerOnline: !!cap?.online,
5225
- nowMs,
5226
- failoverThresholdMs: seamlessness.failoverThresholdMs,
5227
- skewImmune,
5228
- }))
5229
- dead.add(id);
5230
- }
5231
- return dead;
5232
- },
5260
+ presumedDeadHolders: leaseLiveness.presumedDeadHolders,
5261
+ getLivenessEnabled: () => leaseFlapSwitch('liveness'),
5262
+ getUnconfirmedWriteAlertEnabled: () => leaseFlapSwitch('unconfirmedWriteAlert'),
5263
+ sampleLiveness: leaseLiveness.sample,
5264
+ reportDegradation: (event) => DegradationReporter.getInstance().report(event),
5265
+ monotonicNow: leaseMonoNow,
5233
5266
  onEpochAdvance: (epoch) => coordinator.emit('leaseEpochChange', epoch),
5234
5267
  // F2 (multi-machine-lease-self-heal staleHolderTakeover) — DARK by default.
5235
5268
  // Resolved LIVE each call so a config flip needs no restart; off ⇒ canAcquire
@@ -5253,26 +5286,7 @@ export async function startServer(options) {
5253
5286
  const pref = config.multiMachine?.leaseSelfHeal?.preferredAwakeMachineId;
5254
5287
  return !!pref && pref === selfMachineId;
5255
5288
  },
5256
- allPeersPresumedGone: () => {
5257
- const reg = idMgr.loadRegistry();
5258
- const nowMs = Date.now();
5259
- const peerIds = Object.keys(reg.machines ?? {}).filter((id) => id !== selfMachineId && !reg.machines[id].revokedAt);
5260
- if (peerIds.length === 0)
5261
- return false; // a solo machine never "holds against" a peer
5262
- // B4 Decision 10 — same skew-immune liveness as presumedDeadHolders.
5263
- const skewImmune = resolveDevAgentGate(config.multiMachine?.leaseSelfHeal?.skewImmuneLiveness?.enabled, config);
5264
- return peerIds.every((id) => {
5265
- const cap = leaseLivenessRegistry?.getCapacity(id);
5266
- return isPeerPresumedDead({
5267
- lastSeenMs: Date.parse(reg.machines[id].lastSeen),
5268
- routerObserved: !!cap?.routerReceivedAt,
5269
- routerOnline: !!cap?.online,
5270
- nowMs,
5271
- failoverThresholdMs: seamlessness.failoverThresholdMs,
5272
- skewImmune,
5273
- });
5274
- });
5275
- },
5289
+ allPeersPresumedGone: leaseLiveness.allPeersPresumedGone,
5276
5290
  onSelfSuspend: (reason) => console.log(pc.yellow(` [lease] self-suspend: ${reason}`)),
5277
5291
  onEscalate: (info) => console.log(pc.yellow(` [lease] split-brain escalation: ${info.reason} (holder ${info.holder})`)),
5278
5292
  logger: (m) => console.log(pc.dim(m)),
@@ -5326,7 +5340,7 @@ export async function startServer(options) {
5326
5340
  // Claimant self-connectivity proof (evidence 4): an authenticated probe
5327
5341
  // of a THIRD peer; 2-machine case → verified reach of the durable lease
5328
5342
  // authority (git). A claimer with a broken NIC must never claim.
5329
- _hasDurableLeaseAuthority = () => !!gitSyncRef;
5343
+ _hasDurableLeaseAuthority = () => !!leaseGitRef;
5330
5344
  _staleOwnerSelfProof = async () => {
5331
5345
  try {
5332
5346
  const reg = idMgr.loadRegistry();
@@ -5352,7 +5366,7 @@ export async function startServer(options) {
5352
5366
  return false;
5353
5367
  }
5354
5368
  // 2-machine mesh: verified reach of the durable lease authority.
5355
- if (gitSyncRef) {
5369
+ if (leaseGitRef) {
5356
5370
  const read = leaseStore.read();
5357
5371
  return read !== null && read !== undefined;
5358
5372
  }
@@ -20125,6 +20139,7 @@ export async function startServer(options) {
20125
20139
  })),
20126
20140
  clockSkewToleranceMs,
20127
20141
  failoverThresholdMs,
20142
+ monoNow: leaseMonoNow,
20128
20143
  logger: (m) => console.log(pc.dim(` [pool] ${m}`)),
20129
20144
  });
20130
20145
  // B4 Decision 10 — hand the skew-immune registry to the lease-liveness