instar 1.3.1649 → 1.3.1651

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 (498) hide show
  1. package/dashboard/console/accounts.js +2 -1
  2. package/dashboard/console/agents-model.js +3 -3
  3. package/dashboard/console/agents.js +7 -4
  4. package/dashboard/console/console.css +1 -0
  5. package/dashboard/console/console.js +35 -4
  6. package/dashboard/console/costs-model.js +12 -0
  7. package/dashboard/console/costs.js +6 -3
  8. package/dashboard/console/development-model.js +9 -3
  9. package/dashboard/console/development.js +7 -4
  10. package/dashboard/console/home-model.js +30 -14
  11. package/dashboard/console/mandates.js +3 -3
  12. package/dashboard/console/needs-model.js +105 -0
  13. package/dashboard/console/plans.js +2 -1
  14. package/dashboard/console/secrets.js +2 -2
  15. package/dashboard/console/ticket-model.js +36 -0
  16. package/dashboard/console/ui.js +3 -0
  17. package/dist/cli.js +8 -0
  18. package/dist/cli.js.map +1 -1
  19. package/dist/commands/install.d.ts +9 -7
  20. package/dist/commands/install.d.ts.map +1 -1
  21. package/dist/commands/install.js +2 -19
  22. package/dist/commands/install.js.map +1 -1
  23. package/dist/commands/machine.d.ts +2 -0
  24. package/dist/commands/machine.d.ts.map +1 -1
  25. package/dist/commands/machine.js +19 -0
  26. package/dist/commands/machine.js.map +1 -1
  27. package/dist/commands/reflect.d.ts.map +1 -1
  28. package/dist/commands/reflect.js +2 -0
  29. package/dist/commands/reflect.js.map +1 -1
  30. package/dist/commands/route.d.ts.map +1 -1
  31. package/dist/commands/route.js +2 -0
  32. package/dist/commands/route.js.map +1 -1
  33. package/dist/commands/server.d.ts.map +1 -1
  34. package/dist/commands/server.js +537 -21
  35. package/dist/commands/server.js.map +1 -1
  36. package/dist/commands/setClaudeKey.d.ts +8 -0
  37. package/dist/commands/setClaudeKey.d.ts.map +1 -0
  38. package/dist/commands/setClaudeKey.js +35 -0
  39. package/dist/commands/setClaudeKey.js.map +1 -0
  40. package/dist/config/ConfigDefaults.d.ts.map +1 -1
  41. package/dist/config/ConfigDefaults.js +2 -0
  42. package/dist/config/ConfigDefaults.js.map +1 -1
  43. package/dist/core/AccountFollowMeOrchestrator.d.ts.map +1 -1
  44. package/dist/core/AccountFollowMeOrchestrator.js +4 -0
  45. package/dist/core/AccountFollowMeOrchestrator.js.map +1 -1
  46. package/dist/core/AppMediaStore.d.ts.map +1 -1
  47. package/dist/core/AppMediaStore.js +3 -0
  48. package/dist/core/AppMediaStore.js.map +1 -1
  49. package/dist/core/BackupManager.d.ts.map +1 -1
  50. package/dist/core/BackupManager.js +2 -0
  51. package/dist/core/BackupManager.js.map +1 -1
  52. package/dist/core/ClaudeCliIntelligenceProvider.d.ts.map +1 -1
  53. package/dist/core/ClaudeCliIntelligenceProvider.js +11 -3
  54. package/dist/core/ClaudeCliIntelligenceProvider.js.map +1 -1
  55. package/dist/core/ClaudeKeyHealth.d.ts +141 -0
  56. package/dist/core/ClaudeKeyHealth.d.ts.map +1 -0
  57. package/dist/core/ClaudeKeyHealth.js +467 -0
  58. package/dist/core/ClaudeKeyHealth.js.map +1 -0
  59. package/dist/core/CodexTaskContinuationStore.d.ts.map +1 -1
  60. package/dist/core/CodexTaskContinuationStore.js +7 -0
  61. package/dist/core/CodexTaskContinuationStore.js.map +1 -1
  62. package/dist/core/CoherenceJournal.d.ts +1 -1
  63. package/dist/core/CoherenceJournal.d.ts.map +1 -1
  64. package/dist/core/CoherenceJournal.js +11 -2
  65. package/dist/core/CoherenceJournal.js.map +1 -1
  66. package/dist/core/Config.d.ts +8 -0
  67. package/dist/core/Config.d.ts.map +1 -1
  68. package/dist/core/Config.js +26 -0
  69. package/dist/core/Config.js.map +1 -1
  70. package/dist/core/CredentialSwapExecutor.d.ts.map +1 -1
  71. package/dist/core/CredentialSwapExecutor.js +10 -0
  72. package/dist/core/CredentialSwapExecutor.js.map +1 -1
  73. package/dist/core/DecisionQualityRecorderImpl.d.ts.map +1 -1
  74. package/dist/core/DecisionQualityRecorderImpl.js +6 -0
  75. package/dist/core/DecisionQualityRecorderImpl.js.map +1 -1
  76. package/dist/core/DiscoveryEvaluator.d.ts.map +1 -1
  77. package/dist/core/DiscoveryEvaluator.js +4 -0
  78. package/dist/core/DiscoveryEvaluator.js.map +1 -1
  79. package/dist/core/IdentityReannounceClaimant.d.ts.map +1 -1
  80. package/dist/core/IdentityReannounceClaimant.js +4 -0
  81. package/dist/core/IdentityReannounceClaimant.js.map +1 -1
  82. package/dist/core/IntelligenceRouter.d.ts.map +1 -1
  83. package/dist/core/IntelligenceRouter.js +9 -0
  84. package/dist/core/IntelligenceRouter.js.map +1 -1
  85. package/dist/core/JournalSyncApplier.d.ts +1 -0
  86. package/dist/core/JournalSyncApplier.d.ts.map +1 -1
  87. package/dist/core/JournalSyncApplier.js +48 -0
  88. package/dist/core/JournalSyncApplier.js.map +1 -1
  89. package/dist/core/LeaseCoordinator.d.ts +4 -0
  90. package/dist/core/LeaseCoordinator.d.ts.map +1 -1
  91. package/dist/core/LeaseCoordinator.js +64 -1
  92. package/dist/core/LeaseCoordinator.js.map +1 -1
  93. package/dist/core/MachinePoolRegistry.d.ts +8 -0
  94. package/dist/core/MachinePoolRegistry.d.ts.map +1 -1
  95. package/dist/core/MachinePoolRegistry.js +25 -2
  96. package/dist/core/MachinePoolRegistry.js.map +1 -1
  97. package/dist/core/MessagingToneGate.d.ts +11 -7
  98. package/dist/core/MessagingToneGate.d.ts.map +1 -1
  99. package/dist/core/MessagingToneGate.js +15 -1
  100. package/dist/core/MessagingToneGate.js.map +1 -1
  101. package/dist/core/MobileDeviceKeys.d.ts +10 -0
  102. package/dist/core/MobileDeviceKeys.d.ts.map +1 -1
  103. package/dist/core/MobileDeviceKeys.js +17 -0
  104. package/dist/core/MobileDeviceKeys.js.map +1 -1
  105. package/dist/core/MultiMachineCoordinator.d.ts +12 -0
  106. package/dist/core/MultiMachineCoordinator.d.ts.map +1 -1
  107. package/dist/core/MultiMachineCoordinator.js +115 -3
  108. package/dist/core/MultiMachineCoordinator.js.map +1 -1
  109. package/dist/core/MutualSshRuntime.d.ts +1 -0
  110. package/dist/core/MutualSshRuntime.d.ts.map +1 -1
  111. package/dist/core/MutualSshRuntime.js +17 -1
  112. package/dist/core/MutualSshRuntime.js.map +1 -1
  113. package/dist/core/ObservedEndpointTracker.d.ts +1 -0
  114. package/dist/core/ObservedEndpointTracker.d.ts.map +1 -1
  115. package/dist/core/ObservedEndpointTracker.js +17 -0
  116. package/dist/core/ObservedEndpointTracker.js.map +1 -1
  117. package/dist/core/OverloadShedPlanner.d.ts +63 -7
  118. package/dist/core/OverloadShedPlanner.d.ts.map +1 -1
  119. package/dist/core/OverloadShedPlanner.js +177 -38
  120. package/dist/core/OverloadShedPlanner.js.map +1 -1
  121. package/dist/core/OwnershipApplier.d.ts.map +1 -1
  122. package/dist/core/OwnershipApplier.js +7 -0
  123. package/dist/core/OwnershipApplier.js.map +1 -1
  124. package/dist/core/OwnershipReconciler.d.ts +11 -0
  125. package/dist/core/OwnershipReconciler.d.ts.map +1 -1
  126. package/dist/core/OwnershipReconciler.js +32 -9
  127. package/dist/core/OwnershipReconciler.js.map +1 -1
  128. package/dist/core/PostUpdateMigrator.d.ts +12 -0
  129. package/dist/core/PostUpdateMigrator.d.ts.map +1 -1
  130. package/dist/core/PostUpdateMigrator.js +97 -5
  131. package/dist/core/PostUpdateMigrator.js.map +1 -1
  132. package/dist/core/PrHandLease.d.ts.map +1 -1
  133. package/dist/core/PrHandLease.js +2 -0
  134. package/dist/core/PrHandLease.js.map +1 -1
  135. package/dist/core/ProactiveSwapMonitor.d.ts.map +1 -1
  136. package/dist/core/ProactiveSwapMonitor.js +7 -0
  137. package/dist/core/ProactiveSwapMonitor.js.map +1 -1
  138. package/dist/core/ProjectRoundExecution.d.ts.map +1 -1
  139. package/dist/core/ProjectRoundExecution.js +3 -2
  140. package/dist/core/ProjectRoundExecution.js.map +1 -1
  141. package/dist/core/QueueDrainLoop.d.ts +7 -0
  142. package/dist/core/QueueDrainLoop.d.ts.map +1 -1
  143. package/dist/core/QueueDrainLoop.js +37 -1
  144. package/dist/core/QueueDrainLoop.js.map +1 -1
  145. package/dist/core/RebalancePlanner.d.ts +1 -0
  146. package/dist/core/RebalancePlanner.d.ts.map +1 -1
  147. package/dist/core/RebalancePlanner.js +1 -1
  148. package/dist/core/RebalancePlanner.js.map +1 -1
  149. package/dist/core/RemoteAckStore.d.ts.map +1 -1
  150. package/dist/core/RemoteAckStore.js +4 -0
  151. package/dist/core/RemoteAckStore.js.map +1 -1
  152. package/dist/core/ReplicatedStoreReconcilerWiring.d.ts.map +1 -1
  153. package/dist/core/ReplicatedStoreReconcilerWiring.js +1 -0
  154. package/dist/core/ReplicatedStoreReconcilerWiring.js.map +1 -1
  155. package/dist/core/SecretSync.d.ts +1 -0
  156. package/dist/core/SecretSync.d.ts.map +1 -1
  157. package/dist/core/SecretSync.js +16 -0
  158. package/dist/core/SecretSync.js.map +1 -1
  159. package/dist/core/SessionDrainRunner.d.ts +10 -1
  160. package/dist/core/SessionDrainRunner.d.ts.map +1 -1
  161. package/dist/core/SessionDrainRunner.js +60 -3
  162. package/dist/core/SessionDrainRunner.js.map +1 -1
  163. package/dist/core/SessionManager.d.ts +11 -0
  164. package/dist/core/SessionManager.d.ts.map +1 -1
  165. package/dist/core/SessionManager.js +125 -14
  166. package/dist/core/SessionManager.js.map +1 -1
  167. package/dist/core/SessionPoolFailoverRunner.d.ts.map +1 -1
  168. package/dist/core/SessionPoolFailoverRunner.js +4 -0
  169. package/dist/core/SessionPoolFailoverRunner.js.map +1 -1
  170. package/dist/core/SleepWakeDetector.d.ts.map +1 -1
  171. package/dist/core/SleepWakeDetector.js +10 -0
  172. package/dist/core/SleepWakeDetector.js.map +1 -1
  173. package/dist/core/StageAdvancer.d.ts +19 -0
  174. package/dist/core/StageAdvancer.d.ts.map +1 -1
  175. package/dist/core/StageAdvancer.js +51 -1
  176. package/dist/core/StageAdvancer.js.map +1 -1
  177. package/dist/core/SubscriptionReloginStore.d.ts.map +1 -1
  178. package/dist/core/SubscriptionReloginStore.js +10 -1
  179. package/dist/core/SubscriptionReloginStore.js.map +1 -1
  180. package/dist/core/TopicPinMutation.d.ts.map +1 -1
  181. package/dist/core/TopicPinMutation.js +5 -0
  182. package/dist/core/TopicPinMutation.js.map +1 -1
  183. package/dist/core/UnjustifiedStopGate.d.ts.map +1 -1
  184. package/dist/core/UnjustifiedStopGate.js +22 -0
  185. package/dist/core/UnjustifiedStopGate.js.map +1 -1
  186. package/dist/core/WindowRunCadenceExecutor.d.ts.map +1 -1
  187. package/dist/core/WindowRunCadenceExecutor.js +20 -0
  188. package/dist/core/WindowRunCadenceExecutor.js.map +1 -1
  189. package/dist/core/WriteDomainRegistry.d.ts.map +1 -1
  190. package/dist/core/WriteDomainRegistry.js +12 -0
  191. package/dist/core/WriteDomainRegistry.js.map +1 -1
  192. package/dist/core/claudeChildAuth.d.ts +68 -0
  193. package/dist/core/claudeChildAuth.d.ts.map +1 -0
  194. package/dist/core/claudeChildAuth.js +173 -0
  195. package/dist/core/claudeChildAuth.js.map +1 -0
  196. package/dist/core/claudeKeyProbe.d.ts +23 -0
  197. package/dist/core/claudeKeyProbe.d.ts.map +1 -0
  198. package/dist/core/claudeKeyProbe.js +68 -0
  199. package/dist/core/claudeKeyProbe.js.map +1 -0
  200. package/dist/core/codexDeviceLimitWiring.d.ts.map +1 -1
  201. package/dist/core/codexDeviceLimitWiring.js +12 -0
  202. package/dist/core/codexDeviceLimitWiring.js.map +1 -1
  203. package/dist/core/deliverToConversation.d.ts.map +1 -1
  204. package/dist/core/deliverToConversation.js +11 -0
  205. package/dist/core/deliverToConversation.js.map +1 -1
  206. package/dist/core/leaseMediumSelection.d.ts +8 -0
  207. package/dist/core/leaseMediumSelection.d.ts.map +1 -1
  208. package/dist/core/leaseMediumSelection.js +17 -0
  209. package/dist/core/leaseMediumSelection.js.map +1 -1
  210. package/dist/core/meteredCallEntry.d.ts.map +1 -1
  211. package/dist/core/meteredCallEntry.js +21 -0
  212. package/dist/core/meteredCallEntry.js.map +1 -1
  213. package/dist/core/nobodyPollingActuator.d.ts.map +1 -1
  214. package/dist/core/nobodyPollingActuator.js +5 -0
  215. package/dist/core/nobodyPollingActuator.js.map +1 -1
  216. package/dist/core/operatorSurfaceReferral.d.ts +18 -0
  217. package/dist/core/operatorSurfaceReferral.d.ts.map +1 -0
  218. package/dist/core/operatorSurfaceReferral.js +32 -0
  219. package/dist/core/operatorSurfaceReferral.js.map +1 -0
  220. package/dist/core/ownershipFollowsLiveWork.d.ts.map +1 -1
  221. package/dist/core/ownershipFollowsLiveWork.js +10 -1
  222. package/dist/core/ownershipFollowsLiveWork.js.map +1 -1
  223. package/dist/core/poolReadiness.d.ts +67 -0
  224. package/dist/core/poolReadiness.d.ts.map +1 -0
  225. package/dist/core/poolReadiness.js +156 -0
  226. package/dist/core/poolReadiness.js.map +1 -0
  227. package/dist/core/quietTopicScanner.d.ts +39 -0
  228. package/dist/core/quietTopicScanner.d.ts.map +1 -0
  229. package/dist/core/quietTopicScanner.js +57 -0
  230. package/dist/core/quietTopicScanner.js.map +1 -0
  231. package/dist/core/rebalanceProof.d.ts +114 -0
  232. package/dist/core/rebalanceProof.d.ts.map +1 -0
  233. package/dist/core/rebalanceProof.js +192 -0
  234. package/dist/core/rebalanceProof.js.map +1 -0
  235. package/dist/core/types.d.ts +23 -1
  236. package/dist/core/types.d.ts.map +1 -1
  237. package/dist/core/types.js.map +1 -1
  238. package/dist/core/worktreeDirtyCheck.d.ts.map +1 -1
  239. package/dist/core/worktreeDirtyCheck.js +2 -0
  240. package/dist/core/worktreeDirtyCheck.js.map +1 -1
  241. package/dist/data/stageBCertifiedSet.d.ts +9 -0
  242. package/dist/data/stageBCertifiedSet.d.ts.map +1 -1
  243. package/dist/data/stageBCertifiedSet.js +12 -0
  244. package/dist/data/stageBCertifiedSet.js.map +1 -1
  245. package/dist/data/standards-guard-index.json +1 -1
  246. package/dist/data/standards-guard-index.meta.json +2 -2
  247. package/dist/data/standards-registry.meta.json +1 -1
  248. package/dist/lifeline/TelegramLifeline.d.ts.map +1 -1
  249. package/dist/lifeline/TelegramLifeline.js +17 -3
  250. package/dist/lifeline/TelegramLifeline.js.map +1 -1
  251. package/dist/messaging/attentionHubPolicy.d.ts.map +1 -1
  252. package/dist/messaging/attentionHubPolicy.js +1 -0
  253. package/dist/messaging/attentionHubPolicy.js.map +1 -1
  254. package/dist/monitoring/AgentWorktreeReaper.d.ts.map +1 -1
  255. package/dist/monitoring/AgentWorktreeReaper.js +15 -0
  256. package/dist/monitoring/AgentWorktreeReaper.js.map +1 -1
  257. package/dist/monitoring/ApprenticeshipCycleSlaMonitor.d.ts.map +1 -1
  258. package/dist/monitoring/ApprenticeshipCycleSlaMonitor.js +18 -9
  259. package/dist/monitoring/ApprenticeshipCycleSlaMonitor.js.map +1 -1
  260. package/dist/monitoring/CodexArmSessionSweeper.d.ts.map +1 -1
  261. package/dist/monitoring/CodexArmSessionSweeper.js +11 -0
  262. package/dist/monitoring/CodexArmSessionSweeper.js.map +1 -1
  263. package/dist/monitoring/CrashLoopPauser.d.ts.map +1 -1
  264. package/dist/monitoring/CrashLoopPauser.js +8 -0
  265. package/dist/monitoring/CrashLoopPauser.js.map +1 -1
  266. package/dist/monitoring/DegradationReporter.d.ts.map +1 -1
  267. package/dist/monitoring/DegradationReporter.js +7 -1
  268. package/dist/monitoring/DegradationReporter.js.map +1 -1
  269. package/dist/monitoring/DegradedTmuxGuard.d.ts +2 -0
  270. package/dist/monitoring/DegradedTmuxGuard.d.ts.map +1 -1
  271. package/dist/monitoring/DegradedTmuxGuard.js +14 -0
  272. package/dist/monitoring/DegradedTmuxGuard.js.map +1 -1
  273. package/dist/monitoring/DurableOutputScrubber.d.ts.map +1 -1
  274. package/dist/monitoring/DurableOutputScrubber.js +7 -0
  275. package/dist/monitoring/DurableOutputScrubber.js.map +1 -1
  276. package/dist/monitoring/DurableVaultSession.d.ts.map +1 -1
  277. package/dist/monitoring/DurableVaultSession.js +15 -0
  278. package/dist/monitoring/DurableVaultSession.js.map +1 -1
  279. package/dist/monitoring/ExternalHogSentinel.d.ts +2 -0
  280. package/dist/monitoring/ExternalHogSentinel.d.ts.map +1 -1
  281. package/dist/monitoring/ExternalHogSentinel.js +27 -1
  282. package/dist/monitoring/ExternalHogSentinel.js.map +1 -1
  283. package/dist/monitoring/FailureLedger.d.ts.map +1 -1
  284. package/dist/monitoring/FailureLedger.js +38 -1
  285. package/dist/monitoring/FailureLedger.js.map +1 -1
  286. package/dist/monitoring/FeatureEvidenceLog.d.ts +5 -0
  287. package/dist/monitoring/FeatureEvidenceLog.d.ts.map +1 -1
  288. package/dist/monitoring/FeatureEvidenceLog.js +25 -0
  289. package/dist/monitoring/FeatureEvidenceLog.js.map +1 -1
  290. package/dist/monitoring/GeminiCapacityEscalationMonitor.d.ts.map +1 -1
  291. package/dist/monitoring/GeminiCapacityEscalationMonitor.js +20 -2
  292. package/dist/monitoring/GeminiCapacityEscalationMonitor.js.map +1 -1
  293. package/dist/monitoring/GeminiLoopRunner.d.ts.map +1 -1
  294. package/dist/monitoring/GeminiLoopRunner.js +11 -1
  295. package/dist/monitoring/GeminiLoopRunner.js.map +1 -1
  296. package/dist/monitoring/GreenPrAutoMerger.d.ts.map +1 -1
  297. package/dist/monitoring/GreenPrAutoMerger.js +11 -0
  298. package/dist/monitoring/GreenPrAutoMerger.js.map +1 -1
  299. package/dist/monitoring/GrowthDigestPublisher.d.ts.map +1 -1
  300. package/dist/monitoring/GrowthDigestPublisher.js +16 -0
  301. package/dist/monitoring/GrowthDigestPublisher.js.map +1 -1
  302. package/dist/monitoring/GrowthMilestoneAnalyst.d.ts +3 -0
  303. package/dist/monitoring/GrowthMilestoneAnalyst.d.ts.map +1 -1
  304. package/dist/monitoring/GrowthMilestoneAnalyst.js +45 -1
  305. package/dist/monitoring/GrowthMilestoneAnalyst.js.map +1 -1
  306. package/dist/monitoring/McpProcessReaper.d.ts +2 -0
  307. package/dist/monitoring/McpProcessReaper.d.ts.map +1 -1
  308. package/dist/monitoring/McpProcessReaper.js +32 -0
  309. package/dist/monitoring/McpProcessReaper.js.map +1 -1
  310. package/dist/monitoring/MissingLoginSessionDetector.d.ts +2 -1
  311. package/dist/monitoring/MissingLoginSessionDetector.d.ts.map +1 -1
  312. package/dist/monitoring/MissingLoginSessionDetector.js +23 -0
  313. package/dist/monitoring/MissingLoginSessionDetector.js.map +1 -1
  314. package/dist/monitoring/OrchestratorPoller.d.ts +1 -0
  315. package/dist/monitoring/OrchestratorPoller.d.ts.map +1 -1
  316. package/dist/monitoring/OrchestratorPoller.js +13 -0
  317. package/dist/monitoring/OrchestratorPoller.js.map +1 -1
  318. package/dist/monitoring/OrphanedWorkSentinel.d.ts.map +1 -1
  319. package/dist/monitoring/OrphanedWorkSentinel.js +7 -0
  320. package/dist/monitoring/OrphanedWorkSentinel.js.map +1 -1
  321. package/dist/monitoring/PresenceProxy.d.ts.map +1 -1
  322. package/dist/monitoring/PresenceProxy.js +9 -1
  323. package/dist/monitoring/PresenceProxy.js.map +1 -1
  324. package/dist/monitoring/ProcessFootprintMonitor.d.ts.map +1 -1
  325. package/dist/monitoring/ProcessFootprintMonitor.js +20 -2
  326. package/dist/monitoring/ProcessFootprintMonitor.js.map +1 -1
  327. package/dist/monitoring/PromiseBeacon.d.ts.map +1 -1
  328. package/dist/monitoring/PromiseBeacon.js +20 -0
  329. package/dist/monitoring/PromiseBeacon.js.map +1 -1
  330. package/dist/monitoring/ReleaseReadinessSentinel.d.ts +2 -0
  331. package/dist/monitoring/ReleaseReadinessSentinel.d.ts.map +1 -1
  332. package/dist/monitoring/ReleaseReadinessSentinel.js +26 -0
  333. package/dist/monitoring/ReleaseReadinessSentinel.js.map +1 -1
  334. package/dist/monitoring/RopeHealthMonitor.d.ts.map +1 -1
  335. package/dist/monitoring/RopeHealthMonitor.js +35 -1
  336. package/dist/monitoring/RopeHealthMonitor.js.map +1 -1
  337. package/dist/monitoring/SentinelNotifier.d.ts.map +1 -1
  338. package/dist/monitoring/SentinelNotifier.js +16 -0
  339. package/dist/monitoring/SentinelNotifier.js.map +1 -1
  340. package/dist/monitoring/SessionReaper.d.ts.map +1 -1
  341. package/dist/monitoring/SessionReaper.js +11 -2
  342. package/dist/monitoring/SessionReaper.js.map +1 -1
  343. package/dist/monitoring/SingleMachineFailoverGapDetector.d.ts +2 -0
  344. package/dist/monitoring/SingleMachineFailoverGapDetector.d.ts.map +1 -1
  345. package/dist/monitoring/SingleMachineFailoverGapDetector.js +20 -0
  346. package/dist/monitoring/SingleMachineFailoverGapDetector.js.map +1 -1
  347. package/dist/monitoring/SpeakerElection.d.ts.map +1 -1
  348. package/dist/monitoring/SpeakerElection.js +8 -0
  349. package/dist/monitoring/SpeakerElection.js.map +1 -1
  350. package/dist/monitoring/StrandedTopicSentinel.d.ts +3 -0
  351. package/dist/monitoring/StrandedTopicSentinel.d.ts.map +1 -1
  352. package/dist/monitoring/StrandedTopicSentinel.js +33 -0
  353. package/dist/monitoring/StrandedTopicSentinel.js.map +1 -1
  354. package/dist/native/InstarWedgeCanary.app/Contents/MacOS/InstarWedgeCanary +0 -0
  355. package/dist/native/instar-desktop-host +0 -0
  356. package/dist/providers/adapters/anthropic-headless/transport/oneShotCompletion.d.ts.map +1 -1
  357. package/dist/providers/adapters/anthropic-headless/transport/oneShotCompletion.js +5 -2
  358. package/dist/providers/adapters/anthropic-headless/transport/oneShotCompletion.js.map +1 -1
  359. package/dist/recommended/RecommendedServicesLedger.d.ts +91 -0
  360. package/dist/recommended/RecommendedServicesLedger.d.ts.map +1 -0
  361. package/dist/recommended/RecommendedServicesLedger.js +193 -0
  362. package/dist/recommended/RecommendedServicesLedger.js.map +1 -0
  363. package/dist/recommended/RecommendedServicesReplicatedStore.d.ts +14 -0
  364. package/dist/recommended/RecommendedServicesReplicatedStore.d.ts.map +1 -0
  365. package/dist/recommended/RecommendedServicesReplicatedStore.js +34 -0
  366. package/dist/recommended/RecommendedServicesReplicatedStore.js.map +1 -0
  367. package/dist/recommended/legacyDeclines.d.ts +11 -0
  368. package/dist/recommended/legacyDeclines.d.ts.map +1 -0
  369. package/dist/recommended/legacyDeclines.js +17 -0
  370. package/dist/recommended/legacyDeclines.js.map +1 -0
  371. package/dist/recommended/serviceIds.d.ts +3 -0
  372. package/dist/recommended/serviceIds.d.ts.map +1 -0
  373. package/dist/recommended/serviceIds.js +6 -0
  374. package/dist/recommended/serviceIds.js.map +1 -0
  375. package/dist/scaffold/templates.d.ts +2 -0
  376. package/dist/scaffold/templates.d.ts.map +1 -1
  377. package/dist/scaffold/templates.js +11 -1
  378. package/dist/scaffold/templates.js.map +1 -1
  379. package/dist/scheduler/JobResultTriage.d.ts.map +1 -1
  380. package/dist/scheduler/JobResultTriage.js +10 -0
  381. package/dist/scheduler/JobResultTriage.js.map +1 -1
  382. package/dist/scheduler/JobScheduler.d.ts.map +1 -1
  383. package/dist/scheduler/JobScheduler.js +12 -0
  384. package/dist/scheduler/JobScheduler.js.map +1 -1
  385. package/dist/scheduler/MentorOnboardingRunner.d.ts +3 -0
  386. package/dist/scheduler/MentorOnboardingRunner.d.ts.map +1 -1
  387. package/dist/scheduler/MentorOnboardingRunner.js +24 -2
  388. package/dist/scheduler/MentorOnboardingRunner.js.map +1 -1
  389. package/dist/server/AgentServer.d.ts +2 -0
  390. package/dist/server/AgentServer.d.ts.map +1 -1
  391. package/dist/server/AgentServer.js +78 -15
  392. package/dist/server/AgentServer.js.map +1 -1
  393. package/dist/server/BootHealthBeacon.d.ts +3 -0
  394. package/dist/server/BootHealthBeacon.d.ts.map +1 -1
  395. package/dist/server/BootHealthBeacon.js +9 -0
  396. package/dist/server/BootHealthBeacon.js.map +1 -1
  397. package/dist/server/CapabilityIndex.d.ts.map +1 -1
  398. package/dist/server/CapabilityIndex.js +12 -3
  399. package/dist/server/CapabilityIndex.js.map +1 -1
  400. package/dist/server/LifelineIngressGuard.d.ts.map +1 -1
  401. package/dist/server/LifelineIngressGuard.js +11 -0
  402. package/dist/server/LifelineIngressGuard.js.map +1 -1
  403. package/dist/server/PoolPollCache.d.ts +4 -0
  404. package/dist/server/PoolPollCache.d.ts.map +1 -1
  405. package/dist/server/PoolPollCache.js +33 -0
  406. package/dist/server/PoolPollCache.js.map +1 -1
  407. package/dist/server/machineRoutes.d.ts.map +1 -1
  408. package/dist/server/machineRoutes.js +6 -0
  409. package/dist/server/machineRoutes.js.map +1 -1
  410. package/dist/server/middleware.d.ts.map +1 -1
  411. package/dist/server/middleware.js +6 -0
  412. package/dist/server/middleware.js.map +1 -1
  413. package/dist/server/mobileConsoleTicket.d.ts +113 -0
  414. package/dist/server/mobileConsoleTicket.d.ts.map +1 -0
  415. package/dist/server/mobileConsoleTicket.js +405 -0
  416. package/dist/server/mobileConsoleTicket.js.map +1 -0
  417. package/dist/server/mobileConversationRoutes.d.ts.map +1 -1
  418. package/dist/server/mobileConversationRoutes.js +20 -1
  419. package/dist/server/mobileConversationRoutes.js.map +1 -1
  420. package/dist/server/mobileMediaRoutes.d.ts.map +1 -1
  421. package/dist/server/mobileMediaRoutes.js +3 -0
  422. package/dist/server/mobileMediaRoutes.js.map +1 -1
  423. package/dist/server/mobilePairingRoutes.d.ts +8 -2
  424. package/dist/server/mobilePairingRoutes.d.ts.map +1 -1
  425. package/dist/server/mobilePairingRoutes.js +67 -6
  426. package/dist/server/mobilePairingRoutes.js.map +1 -1
  427. package/dist/server/mobileSessionTerminalRoutes.d.ts +128 -0
  428. package/dist/server/mobileSessionTerminalRoutes.d.ts.map +1 -0
  429. package/dist/server/mobileSessionTerminalRoutes.js +389 -0
  430. package/dist/server/mobileSessionTerminalRoutes.js.map +1 -0
  431. package/dist/server/recommendedServiceRoutes.d.ts +13 -0
  432. package/dist/server/recommendedServiceRoutes.d.ts.map +1 -0
  433. package/dist/server/recommendedServiceRoutes.js +49 -0
  434. package/dist/server/recommendedServiceRoutes.js.map +1 -0
  435. package/dist/server/routes.d.ts +2 -0
  436. package/dist/server/routes.d.ts.map +1 -1
  437. package/dist/server/routes.js +215 -5
  438. package/dist/server/routes.js.map +1 -1
  439. package/dist/testing/selfActionRegistry.d.ts.map +1 -1
  440. package/dist/testing/selfActionRegistry.js +44 -3
  441. package/dist/testing/selfActionRegistry.js.map +1 -1
  442. package/dist/threadline/A2ACheckInProxy.d.ts.map +1 -1
  443. package/dist/threadline/A2ACheckInProxy.js +26 -15
  444. package/dist/threadline/A2ACheckInProxy.js.map +1 -1
  445. package/dist/threadline/AgentTrustManager.d.ts.map +1 -1
  446. package/dist/threadline/AgentTrustManager.js +3 -0
  447. package/dist/threadline/AgentTrustManager.js.map +1 -1
  448. package/dist/threadline/InboundIdLedger.d.ts.map +1 -1
  449. package/dist/threadline/InboundIdLedger.js +18 -1
  450. package/dist/threadline/InboundIdLedger.js.map +1 -1
  451. package/dist/threadline/NegotiatorGate.d.ts.map +1 -1
  452. package/dist/threadline/NegotiatorGate.js +11 -0
  453. package/dist/threadline/NegotiatorGate.js.map +1 -1
  454. package/dist/threadline/PipeSessionSpawner.d.ts.map +1 -1
  455. package/dist/threadline/PipeSessionSpawner.js +8 -0
  456. package/dist/threadline/PipeSessionSpawner.js.map +1 -1
  457. package/dist/threadline/ThreadlineRouter.d.ts.map +1 -1
  458. package/dist/threadline/ThreadlineRouter.js +13 -0
  459. package/dist/threadline/ThreadlineRouter.js.map +1 -1
  460. package/dist/threadline/pairingReplicationWiring.d.ts.map +1 -1
  461. package/dist/threadline/pairingReplicationWiring.js +9 -0
  462. package/dist/threadline/pairingReplicationWiring.js.map +1 -1
  463. package/dist/threadline/relayForward.d.ts.map +1 -1
  464. package/dist/threadline/relayForward.js +13 -2
  465. package/dist/threadline/relayForward.js.map +1 -1
  466. package/dist/threadline/relayUnknownSenderTrust.d.ts +0 -9
  467. package/dist/threadline/relayUnknownSenderTrust.d.ts.map +1 -1
  468. package/dist/threadline/relayUnknownSenderTrust.js +16 -0
  469. package/dist/threadline/relayUnknownSenderTrust.js.map +1 -1
  470. package/package.json +1 -1
  471. package/scripts/check-constitution-pairing.mjs +273 -0
  472. package/scripts/safe-merge.mjs +9 -0
  473. package/src/data/builtin-manifest.json +103 -103
  474. package/src/data/feature-ladders.json +113 -113
  475. package/src/data/stageBCertifiedSet.ts +12 -0
  476. package/src/data/standards-guard-index.json +1 -1
  477. package/src/data/standards-guard-index.meta.json +2 -2
  478. package/src/data/standards-registry.meta.json +1 -1
  479. package/src/data/state-coherence-registry.json +18 -0
  480. package/src/scaffold/templates.ts +12 -1
  481. package/upgrades/1.3.1650.md +105 -0
  482. package/upgrades/1.3.1651.md +30 -0
  483. package/upgrades/mobile-console-device-signin.eli16.md +5 -0
  484. package/upgrades/side-effects/cloud-key-internal-calls.md +116 -0
  485. package/upgrades/side-effects/constitution-alignment.eli16.md +11 -0
  486. package/upgrades/side-effects/constitution-alignment.md +69 -0
  487. package/upgrades/side-effects/feature-evidence-recording.eli16.md +3 -0
  488. package/upgrades/side-effects/feature-evidence-recording.md +66 -0
  489. package/upgrades/side-effects/feedback-reroute-admission-parity.md +77 -0
  490. package/upgrades/side-effects/mobile-console-device-signin.md +102 -0
  491. package/upgrades/side-effects/mobile-native-session-screen.md +88 -0
  492. package/upgrades/side-effects/operator-needs-first-screen.md +87 -0
  493. package/upgrades/side-effects/recommended-services-choices.md +50 -0
  494. package/upgrades/side-effects/rerouted-lifetime-active-process.md +63 -0
  495. package/upgrades/side-effects/session-pool-default-on.md +53 -0
  496. package/upgrades/side-effects/session-pool-rebalancing-finish.md +151 -0
  497. package/upgrades/side-effects/undated-resurfacer-e2e-wait.eli16.md +5 -0
  498. package/upgrades/side-effects/undated-resurfacer-e2e-wait.md +9 -0
@@ -3,6 +3,7 @@
3
3
  * the boot-time TCC-protected path detection + /guards row (see the
4
4
  * TccProtectedPathGuard block beside the worktree detector).
5
5
  */
6
+ import { configureClaudeChildAuth, sweepClaudeAuthEnvFiles } from '../core/claudeChildAuth.js';
6
7
  import { slackHistoryLabel } from '../messaging/slack/threadHistoryLabel.js';
7
8
  import { readPairingOwnerName } from '../threadline/pairingOwnerName.js';
8
9
  import { buildThrowawayJobGuard, checkThrowawayExpiry, describeExpiry, takeLastAutoStartRefusal, throwawayStartupDecision } from '../core/ThrowawayAgentGuard.js';
@@ -54,14 +55,17 @@ import { setAspClassifierRef, getAspClassifierRef } from '../core/aspClassifierR
54
55
  import { resolveInboundTelegramMessageId, resolveSignedByAgent, operatorAutoBindPermitted } from '../messaging/shared/signedInbound.js';
55
56
  import { verifiedEntityName } from '../messaging/shared/channelIdentity.js';
56
57
  import { StandDownRegistry } from '../core/StandDownRegistry.js';
57
- import { getActiveOverloadShedPlanner } from '../core/OverloadShedPlanner.js';
58
+ import { getActiveOverloadShedPlanner, getMoveAftercare } from '../core/OverloadShedPlanner.js';
59
+ import { QuietTopicScanner } from '../core/quietTopicScanner.js';
60
+ import { RebalanceProofRunner, getActiveRebalanceProof, proofSpawnBrief, setActiveRebalanceProof, setActiveRebalanceProofStore } from '../core/rebalanceProof.js';
61
+ import { rebalanceProofState } from '../core/StageAdvancer.js';
58
62
  import { buildHandoffContinuationInstruction } from '../core/handoffContinuation.js';
59
63
  import { BASELINE_PROCESS_PATTERNS } from '../core/baselineProcessPatterns.js';
60
64
  import { StandDownAudit } from '../core/StandDownAudit.js';
61
65
  import { resolveStandardsRegistry } from '../core/standardsRegistryPath.js';
62
66
  import { chunkLiteralForTmux, buildLiteralSendArgs } from '../core/tmuxLiteralSend.js';
63
67
  import { parseStandardsRegistry } from '../core/StandardsRegistryParser.js';
64
- import { loadConfig, ensureStateDir, detectTmuxPath, detectGeminiPath } from '../core/Config.js';
68
+ import { loadConfig, ensureStateDir, detectTmuxPath, detectGeminiPath, detectClaudePath, readConfiguredAnthropicKey } from '../core/Config.js';
65
69
  import { handleProcessLevelError } from '../core/uncaughtExceptionPolicy.js';
66
70
  import { planInboundLossNotices } from '../core/inboundLossRouting.js';
67
71
  import { heartbeatFreshEnoughToRerecord } from '../core/MachineHeartbeat.js';
@@ -75,6 +79,7 @@ import { SingleInstanceLock, installReleaseHandlers } from '../core/SingleInstan
75
79
  import { resolveDevAgentGate, resolveStateSyncStores } from '../core/devAgentGate.js';
76
80
  import { JOB_LEASE_POOL_AUTHORITY_READY } from '../scheduler/JobLeaseClaimStore.js';
77
81
  import { resolveRelayUnknownSenderTrustMode } from '../threadline/relayUnknownSenderTrust.js';
82
+ import { featureEvidence } from '../monitoring/FeatureEvidenceLog.js';
78
83
  import { resolveEncryptToPinnedMode, encryptToPinnedModeName } from '../threadline/encryptToPinned.js';
79
84
  import { resolveRefuseDowngradeMode } from '../threadline/refuseDowngrade.js';
80
85
  import { MarkedPairingInviteFlow } from '../threadline/PairingPendingAcceptMarkers.js';
@@ -231,7 +236,7 @@ import { AutonomousEvolution } from '../core/AutonomousEvolution.js';
231
236
  import { DispatchScopeEnforcer } from '../core/DispatchScopeEnforcer.js';
232
237
  import { TrustRecovery } from '../core/TrustRecovery.js';
233
238
  import { DegradationReporter } from '../monitoring/DegradationReporter.js';
234
- import { reportLeaseMediumSelection, selectLeaseMedium } from '../core/leaseMediumSelection.js';
239
+ import { gitLeaseHasNoRemote, reportLeaseMediumSelection, selectLeaseMedium } from '../core/leaseMediumSelection.js';
235
240
  import { HumanAsDetectorLog, observeInboundMessage } from '../monitoring/HumanAsDetectorLog.js';
236
241
  import { creditUsherOnMiss } from '../core/UsherActedCorrelator.js';
237
242
  import { resolveStableNodeBinary } from '../utils/resolveNodeBinary.js';
@@ -634,6 +639,8 @@ let _inboundQueue = null;
634
639
  // Late-bound self-capacity refresh. The heartbeat writer is constructed before
635
640
  // the durable inbound queue, whose live handle is one of the advertised fields.
636
641
  let _refreshPoolHeartbeat = () => { };
642
+ /** Boot-cached takeover reading for the pool readiness report; never read from /health. */
643
+ let _takeoverReadiness = { state: 'unknown', reason: 'only a real takeover proves this' };
637
644
  // Module-level handle for the machine-coherence guard (machine-coherence-guard
638
645
  // §6) so `GET /pool/machine-coherence` can read the sentinel constructed deep in
639
646
  // the mesh peer-presence wiring. Null when the guard is dark (route 503s).
@@ -646,6 +653,9 @@ let _singleMachineFailoverGap = null;
646
653
  // `GET /pool/missing-login` can read the detector constructed deep in the mesh
647
654
  // peer-presence wiring. Null when the guard is dark (route 503s).
648
655
  let _missingLoginSession = null;
656
+ // The journal compaction pass runs at boot, before the evidence log is wired by
657
+ // AgentServer; its row is held here and written straight after that construction.
658
+ let _pendingCompactionEvidence = null;
649
659
  // Module-level handle for the SessionPoolFailoverRunner driver (§Rollout, Track H)
650
660
  // so `GET /session-pool/failover-runner` can read its status(). Null when the
651
661
  // runner is dark (dev-gated) — the route 503s. Constructed inside the rollout-gate
@@ -808,6 +818,8 @@ let _pinPlacementMetadata = null;
808
818
  let _ws13SustainedOnline = null;
809
819
  /** Cross-machine secret-sync (spec Phase 4): route-facing handle (push lever + read-only status). */
810
820
  let _secretSyncHandle = null;
821
+ /** The boot-time escrow result, recorded as evidence once the evidence log is wired. Flags only, no key material. */
822
+ let _recoveryEscrowEvidence = null;
811
823
  /** Pool Dashboard Streaming (POOL-DASHBOARD-STREAM-SPEC §2.3): shared single-use
812
824
  * ticket store — minted by the `pool-stream-ticket` mesh verb, consumed by the
813
825
  * WebSocketManager's /pool-stream upgrade. Constructed in the mesh-setup block. */
@@ -987,6 +999,12 @@ let _sessionRefresh = null;
987
999
  let _ownershipReconciler = null;
988
1000
  /** trustworthy-machine-load D: the overload-shed evaluation timer (cleared at shutdown). */
989
1001
  let _overloadShedTimer = null;
1002
+ /** This machine's rebalance proof store (session-pool-rebalancing-finish): built with the rollout gate, read by the shed. */
1003
+ let _rebalanceProofStore = null;
1004
+ let _sessionPoolBuildIdentity = null;
1005
+ let _shedDrainInFlight = false;
1006
+ /** Topics in a shed drain: they journal as `reconcile`, because peers reject an unknown reason. */
1007
+ const _shedDrainTopics = new Set();
990
1008
  // U4.2 stale-owner release — the evidence-upgraded Case C engine, hoisted so the
991
1009
  // GET /pool/stale-owner-release route + the reconciler dep can reach it. Null
992
1010
  // until the pool block constructs it (single-machine / dark → the route 503s).
@@ -1001,6 +1019,7 @@ let _spawnAdmission = null;
1001
1019
  /** Native app conversations (mobile-native-conversations, increment 1) — late-bound for the replication observers. */
1002
1020
  let _appConversationService = null;
1003
1021
  let _ecosystemLedger = null;
1022
+ let _recommendedServicesLedger = null;
1004
1023
  // trustworthy-machine-load C5: one fixed holding notice per topic per overload
1005
1024
  // episode when EVERY machine refuses new work (30-min cooldown; the message
1006
1025
  // itself is already in durable custody, this only tells the user why it waits).
@@ -2484,6 +2503,14 @@ getHubClassifierDeps) {
2484
2503
  modelTier: clsDeps.modelTier,
2485
2504
  });
2486
2505
  const willAct = result.isCommand && !clsDeps.dryRun;
2506
+ // Same scope as the audit below: LLM-engaged verdicts, never the prefilter-skip bulk.
2507
+ if (result.source !== 'prefilter-skip') {
2508
+ featureEvidence.record('threadline.hubIntent', {
2509
+ kind: result.source === 'fail-open' ? 'error' : 'fired',
2510
+ reason: result.source === 'fail-open' ? 'classifier-fail-open' : result.isCommand ? (willAct ? 'swallow' : 'would-swallow') : 'would-pass',
2511
+ context: { topicId, dryRun: clsDeps.dryRun, source: result.source, intent: result.intent ?? null, confidence: result.confidence ?? null, targetTopicId: result.targetTopicId ?? null },
2512
+ });
2513
+ }
2487
2514
  // Audit the soak: log LLM-engaged decisions (a prefilter-skip is the
2488
2515
  // bulk of traffic and always a would-pass — skipping it cuts volume
2489
2516
  // AND the message-preview privacy surface). Never gates the message.
@@ -2528,6 +2555,7 @@ getHubClassifierDeps) {
2528
2555
  }
2529
2556
  catch (err) {
2530
2557
  console.warn(`[telegram] hub-command intercept error (fail-open): ${err instanceof Error ? err.message : err}`);
2558
+ featureEvidence.record('threadline.hubIntent', { kind: 'error', reason: 'intercept-threw-fail-open', context: { errorName: err instanceof Error ? err.name : 'unknown' } });
2531
2559
  }
2532
2560
  }
2533
2561
  // ── Fix commands from notification messages ──────────────────────
@@ -2576,7 +2604,7 @@ getHubClassifierDeps) {
2576
2604
  // mesh) instead of handling it locally. DARK (the default) skips this block
2577
2605
  // entirely → byte-identical to single-machine dispatch. Any error falls back
2578
2606
  // to the local path below (fail-safe). The live-transfer behavior is gated by
2579
- // the staged rollout (StageAdvancer); shadow records ownership but stays local.
2607
+ // the staged rollout (StageAdvancer). Any stage past dark places for real, shadow included.
2580
2608
  // SpawnAdmission TOCTOU guard (ownership-gated-spawn §3.1 item 2): stash the
2581
2609
  // router's verdict for THIS message so the seam at the spawn callsites below
2582
2610
  // CONSUMES it instead of re-resolving — the admission decision and the
@@ -3861,6 +3889,10 @@ export async function startServer(options) {
3861
3889
  watchPaths: ['updates.autoApply', 'sessions.maxSessions', 'monitoring'],
3862
3890
  });
3863
3891
  liveConfig.start();
3892
+ // Every server-side `claude` child gets the configured sign-in key from here, read per call so a
3893
+ // restored key applies at once (spec cloud-key-internal-calls). Off: sessions.claudeChildAuth.enabled.
3894
+ configureClaudeChildAuth(() => liveConfig.get('sessions.claudeChildAuth.enabled', true) === false ? undefined : config.sessions?.anthropicApiKey, () => config.sessions?.anthropicBaseUrl);
3895
+ sweepClaudeAuthEnvFiles(config.stateDir);
3864
3896
  // Threadline → Telegram bridge config — settings surface for the bridge
3865
3897
  // module. Default-OFF auto-create ships from day one;
3866
3898
  // see TelegramBridgeConfig for the policy.
@@ -4075,6 +4107,7 @@ export async function startServer(options) {
4075
4107
  // covers the window on the fleet. D4-verified read-only (localhost-only inbound
4076
4108
  // socket, zero outbound). Belt-and-suspenders, not a boot reorder.
4077
4109
  let bootBeacon;
4110
+ let bootBeaconBindErrorCode = null;
4078
4111
  if (resolveDevAgentGate(config.monitoring?.bootHealthBeacon?.enabled, config)) {
4079
4112
  try {
4080
4113
  bootBeacon = new BootHealthBeacon(config.port);
@@ -4086,6 +4119,7 @@ export async function startServer(options) {
4086
4119
  // failure must NEVER block the server boot (the startupGrace bump still
4087
4120
  // covers the health window). Logged here, not swallowed silently.
4088
4121
  bootBeacon = undefined;
4122
+ bootBeaconBindErrorCode = err?.code ?? 'unknown';
4089
4123
  console.error(' Boot health beacon failed to start (non-fatal):', err instanceof Error ? err.message : err);
4090
4124
  }
4091
4125
  }
@@ -4779,6 +4813,9 @@ export async function startServer(options) {
4779
4813
  // docs/specs/ecosystem-idea-pipeline.md: inert registration; the store is injected below whenever the pipeline is on.
4780
4814
  const { ECOSYSTEM_IDEAS_KIND_REGISTRATION } = await import('../ecosystem/EcosystemIdeasReplicatedStore.js');
4781
4815
  replicatedKindRegistry.register(ECOSYSTEM_IDEAS_KIND_REGISTRATION);
4816
+ // docs/specs/recommended-services.md: a person's choices follow them across machines.
4817
+ const { RECOMMENDED_SERVICES_KIND_REGISTRATION } = await import('../recommended/RecommendedServicesReplicatedStore.js');
4818
+ replicatedKindRegistry.register(RECOMMENDED_SERVICES_KIND_REGISTRATION);
4782
4819
  // mobile-native-conversations §4.8 — the `mobileDeviceKeyLedger` kind (inert registration; on
4783
4820
  // whenever native app conversations are on, so a signed record can be checked on any machine).
4784
4821
  const { DEVICE_KEY_LEDGER_KIND_REGISTRATION } = await import('../core/MobileDeviceKeyLedgerReplicatedStore.js');
@@ -4940,13 +4977,35 @@ export async function startServer(options) {
4940
4977
  const compactionConfig = config.multiMachine?.coherenceJournal?.replication?.compaction;
4941
4978
  if (compactionConfig?.run === true) {
4942
4979
  const { ReplicatedJournalCompactor } = await import('../core/ReplicatedJournalCompactor.js');
4943
- new ReplicatedJournalCompactor({
4944
- stateDir: config.stateDir,
4945
- registry: replicatedKindRegistry,
4946
- enabled: true,
4947
- dryRun: compactionConfig.dryRun ?? true,
4948
- logger: (m) => console.log(pc.dim(` ${m}`)),
4949
- }).run();
4980
+ try {
4981
+ const compaction = new ReplicatedJournalCompactor({
4982
+ stateDir: config.stateDir,
4983
+ registry: replicatedKindRegistry,
4984
+ enabled: true,
4985
+ dryRun: compactionConfig.dryRun ?? true,
4986
+ logger: (m) => console.log(pc.dim(` ${m}`)),
4987
+ }).run();
4988
+ _pendingCompactionEvidence = {
4989
+ kind: 'fired',
4990
+ reason: compaction.dryRun ? 'would-compact' : 'compacted',
4991
+ context: {
4992
+ dryRun: compaction.dryRun,
4993
+ filesCompacted: compaction.filesCompacted,
4994
+ originalRecords: compaction.originalRecords,
4995
+ compactedRecords: compaction.compactedRecords,
4996
+ bytesBefore: compaction.bytesBefore,
4997
+ bytesAfter: compaction.bytesAfter,
4998
+ },
4999
+ };
5000
+ }
5001
+ catch (compactionErr) {
5002
+ _pendingCompactionEvidence = {
5003
+ kind: 'error',
5004
+ reason: 'compaction-failed',
5005
+ context: { dryRun: compactionConfig.dryRun ?? true, errorName: compactionErr instanceof Error ? compactionErr.name : 'unknown' },
5006
+ };
5007
+ throw compactionErr;
5008
+ }
4950
5009
  // A real run replaced streams atomically; rebuild from the committed files.
4951
5010
  }
4952
5011
  coherenceJournal.setReplicatedRecordCommitObserver((kind, entries) => {
@@ -4973,6 +5032,14 @@ export async function startServer(options) {
4973
5032
  for (const e of entries)
4974
5033
  _ecosystemLedger.ingestReplicated(e.data.event);
4975
5034
  }
5035
+ // A person's choices: each row lands only when it verifies under the machine it names.
5036
+ if (kind === 'recommended-service-record' && _recommendedServicesLedger) {
5037
+ for (const e of entries) {
5038
+ const r = _recommendedServicesLedger.ingestReplicated(e.data.row);
5039
+ if (r === 'bad-signature' || r === 'unverifiable')
5040
+ console.warn(` [recommended-services] a replicated row was not accepted (${r})`);
5041
+ }
5042
+ }
4976
5043
  // Device-key ledger rows: each lands only when it verifies under the pinned key of the machine it names.
4977
5044
  if (kind === 'mobile-device-key-ledger-row' && _appConversationService?.deps.keyLedger) {
4978
5045
  const ledger = _appConversationService.deps.keyLedger;
@@ -5088,6 +5155,11 @@ export async function startServer(options) {
5088
5155
  const _appNativeOn = _isMobileNativeEnabled(config);
5089
5156
  const _stateSyncStoresResolved = (() => {
5090
5157
  let s = _stateSyncStoresBase ?? {};
5158
+ // On wherever the journal is live: a yes or no belongs to the person, not one machine
5159
+ // (docs/specs/recommended-services.md). Without the journal there is no applier, so it isn't advertised.
5160
+ const _recommendedServicesOn = !!coherenceJournal && _stateSyncStoresBase?.recommendedServices?.enabled !== false;
5161
+ if (_recommendedServicesOn)
5162
+ s = { ...s, recommendedServices: { enabled: true } };
5091
5163
  if (_appNativeOn)
5092
5164
  s = { ...s, appConversations: { enabled: true }, mobileDeviceKeyLedger: { enabled: true } };
5093
5165
  if (resolveDevAgentGate(config.ecosystemIdeas?.enabled, config))
@@ -5098,7 +5170,7 @@ export async function startServer(options) {
5098
5170
  s = { ...s, topicPins: { enabled: true } };
5099
5171
  if (_staleOwnerReleaseResolved)
5100
5172
  s = { ...s, topicClaimAnnotations: { enabled: true } };
5101
- return _appNativeOn || _accountFollowMeEnabled || _pinReplicateEnabled || _staleOwnerReleaseResolved || _stateSyncStoresBase ? s : _stateSyncStoresBase;
5173
+ return _recommendedServicesOn || _appNativeOn || _accountFollowMeEnabled || _pinReplicateEnabled || _staleOwnerReleaseResolved || _stateSyncStoresBase ? s : _stateSyncStoresBase;
5102
5174
  })();
5103
5175
  // WS2 send-side: the generic journal-backed record emitter (the concrete emitter
5104
5176
  // the per-store managers' emit hooks call). Needs the journal sink, the HLC clock,
@@ -5465,6 +5537,9 @@ export async function startServer(options) {
5465
5537
  const leaseGitRef = leaseMedium.medium === 'local' ? undefined : gitSyncRef;
5466
5538
  const leaseStoreName = leaseGitRef ? 'GitLeaseStore' : 'LocalLeaseStore';
5467
5539
  coordinator.attachLeaseMediumProvider(() => ({ ...leaseMedium, store: leaseStoreName }));
5540
+ if (leaseGitRef && gitLeaseHasNoRemote(config.projectDir) === true) {
5541
+ _takeoverReadiness = { state: 'failing', reason: 'this machine uses the git lease with no git remote, so it cannot take over' };
5542
+ }
5468
5543
  try {
5469
5544
  // ── G1 fenced-lease integration (spec §6) ──────────────────
5470
5545
  // The lease is the authority for awake/standby + the MeshRpc router-only
@@ -7682,6 +7757,7 @@ export async function startServer(options) {
7682
7757
  // Never let a pauser fault take down the boot path or the interval.
7683
7758
  clpLastError = err instanceof Error ? err.message : String(err);
7684
7759
  console.error(pc.red(` CrashLoopPauser pass failed: ${clpLastError}`));
7760
+ featureEvidence.record('monitoring.crashLoopPauser', { kind: 'error', reason: 'pause pass failed', context: { dryRun: clpDryRun, errorName: err instanceof Error ? err.name : 'unknown' } });
7685
7761
  }
7686
7762
  };
7687
7763
  const clpInitialDelay = clpCfg.initialPassDelayMs ?? 10 * 60_000;
@@ -8808,6 +8884,50 @@ export async function startServer(options) {
8808
8884
  console.warn(` [app-conversations] wiring failed: ${err instanceof Error ? err.message : String(err)}`);
8809
8885
  }
8810
8886
  }
8887
+ // docs/specs/recommended-services.md: built here so its rows replicate; no identity means no ledger, and the routes answer 503.
8888
+ try {
8889
+ const { loadMachineSigner, identityKeyLookup } = await import('../core/AppRecordSignatures.js');
8890
+ const { RecommendedServicesLedger } = await import('../recommended/RecommendedServicesLedger.js');
8891
+ const recRepl = await import('../recommended/RecommendedServicesReplicatedStore.js');
8892
+ const signer = loadMachineSigner(config.stateDir);
8893
+ if (signer) {
8894
+ const ledger = new RecommendedServicesLedger({ stateDir: config.stateDir, signer, keyLookup: identityKeyLookup(config.stateDir) });
8895
+ if (replicatedRecordEmitter) {
8896
+ const emitter = replicatedRecordEmitter;
8897
+ const emitRow = (row) => {
8898
+ const { outcome } = emitter.emit(recRepl.RECOMMENDED_SERVICES_STORE_KEY, recRepl.deriveRecommendedServiceRecordKey(row.eventId), recRepl.buildRecommendedServiceRecordData(row));
8899
+ if (outcome !== 'emitted')
8900
+ console.warn(` [recommended-services] a choice was not replicated yet (${outcome}); it is sent again at next boot`);
8901
+ };
8902
+ ledger.setReplicationHook(emitRow);
8903
+ ledger.setReplicating(_stateSyncStoresResolved?.recommendedServices?.enabled === true && config.multiMachine?.coherenceJournal?.replication?.enabled === true);
8904
+ // Rows written while the journal was off, or dropped by a rate cap, go out now.
8905
+ if (replicatedPeerStreamReader && cjOwnMachineId) {
8906
+ for (const row of ledger.all()) {
8907
+ if (row.machineId !== signer.machineId())
8908
+ continue;
8909
+ const rk = recRepl.deriveRecommendedServiceRecordKey(row.eventId);
8910
+ if (!replicatedPeerStreamReader.loadOriginRecords(recRepl.RECOMMENDED_SERVICES_STORE_KEY, rk).some((o) => o.origin === cjOwnMachineId))
8911
+ emitRow(row);
8912
+ }
8913
+ }
8914
+ }
8915
+ if (replicatedPeerStreamReader && cjOwnMachineId) {
8916
+ const reader = replicatedPeerStreamReader;
8917
+ for (const rk of reader.listRecordKeys(recRepl.RECOMMENDED_SERVICES_STORE_KEY)) {
8918
+ for (const r of reader.loadOriginRecords(recRepl.RECOMMENDED_SERVICES_STORE_KEY, rk)) {
8919
+ if (r.origin !== cjOwnMachineId)
8920
+ ledger.ingestReplicated(r.data.row);
8921
+ }
8922
+ }
8923
+ }
8924
+ _recommendedServicesLedger = ledger;
8925
+ }
8926
+ }
8927
+ catch (err) {
8928
+ // @silent-fallback-ok: reported; the routes answer 503 and nothing else depends on this
8929
+ console.warn(` [recommended-services] ledger wiring failed: ${err instanceof Error ? err.message : String(err)}`);
8930
+ }
8811
8931
  // docs/specs/ecosystem-idea-pipeline.md: the ledger is built here so its events replicate; AgentServer builds the service.
8812
8932
  if (resolveDevAgentGate(config.ecosystemIdeas?.enabled, config)) {
8813
8933
  try {
@@ -14068,9 +14188,26 @@ export async function startServer(options) {
14068
14188
  if (replicatedRecordEmitter && _accountFollowMeEnabled) {
14069
14189
  const emitter = replicatedRecordEmitter;
14070
14190
  const { SUBSCRIPTION_ACCOUNT_META_STORE_KEY, deriveSubscriptionAccountMetaRecordKey, buildSubscriptionAccountMetaData, buildSubscriptionAccountMetaTombstoneData, } = await import('../core/SubscriptionAccountMetaReplicatedStore.js');
14191
+ // Every quota change re-projects an account, so one row per op and outcome per ten minutes. No account ids.
14192
+ const followMeEvidence = (op, outcome) => {
14193
+ const failed = outcome === 'error' || outcome === 'unconfirmed' || outcome.startsWith('dropped:');
14194
+ featureEvidence.recordAtMostEvery('multiMachine.accountFollowMe', `${op}:${outcome}`, 600_000, {
14195
+ kind: outcome === 'emitted' ? 'fired' : failed ? 'error' : 'held',
14196
+ reason: `account-meta-${op}:${outcome}`,
14197
+ context: { op, outcome },
14198
+ });
14199
+ };
14071
14200
  subscriptionPool.setMetaReplicationEmitter({
14072
- emitPut: (acct) => emitter.emit(SUBSCRIPTION_ACCOUNT_META_STORE_KEY, deriveSubscriptionAccountMetaRecordKey(acct.id), (hlc, origin, observed) => buildSubscriptionAccountMetaData({ account: acct, hlc, origin, observed })),
14073
- emitDelete: (accountId, deletedAt) => emitter.emit(SUBSCRIPTION_ACCOUNT_META_STORE_KEY, deriveSubscriptionAccountMetaRecordKey(accountId), (hlc, origin, observed) => buildSubscriptionAccountMetaTombstoneData({ accountId, hlc, origin, deletedAt, observed })),
14201
+ emitPut: (acct) => {
14202
+ const projected = emitter.emit(SUBSCRIPTION_ACCOUNT_META_STORE_KEY, deriveSubscriptionAccountMetaRecordKey(acct.id), (hlc, origin, observed) => buildSubscriptionAccountMetaData({ account: acct, hlc, origin, observed }));
14203
+ followMeEvidence('put', projected.outcome);
14204
+ return projected;
14205
+ },
14206
+ emitDelete: (accountId, deletedAt) => {
14207
+ const projected = emitter.emit(SUBSCRIPTION_ACCOUNT_META_STORE_KEY, deriveSubscriptionAccountMetaRecordKey(accountId), (hlc, origin, observed) => buildSubscriptionAccountMetaTombstoneData({ accountId, hlc, origin, deletedAt, observed }));
14208
+ followMeEvidence('delete', projected.outcome);
14209
+ return projected;
14210
+ },
14074
14211
  });
14075
14212
  }
14076
14213
  // POOL-AWARE QUOTA THROTTLE wiring (docs/specs/POOL-AWARE-QUOTA-THROTTLE-SPEC.md):
@@ -16350,6 +16487,23 @@ export async function startServer(options) {
16350
16487
  externalBlockSweepMs: aoftRawCfg.externalBlockSweepMs,
16351
16488
  holdsLease: () => (leaseCoordinatorRef ? leaseCoordinatorRef.holdsLease() : true),
16352
16489
  });
16490
+ // The aoft.* events have no other reader: keep them, with no message text (ids and reason codes only).
16491
+ for (const [event, kind] of [
16492
+ ['aoft.would-suppress', 'fired'], ['aoft.suppressed', 'fired'],
16493
+ ['aoft.would-reroute-terminal', 'fired'], ['aoft.terminal-rerouted', 'fired'],
16494
+ ['aoft.would-deadletter-external', 'fired'], ['aoft.deadlettered-external', 'fired'],
16495
+ ['aoft.external-block-recorded-internal', 'held'],
16496
+ ['aoft.graveyard-reconciled', 'fired'],
16497
+ ['aoft.beacon-id-leak', 'error'],
16498
+ ]) {
16499
+ promiseBeacon.on(event, (e) => {
16500
+ featureEvidence.record('commitments.agentOwnedFollowthrough', {
16501
+ kind,
16502
+ reason: event.replace('aoft.', '') + (e?.reason ? `: ${e.reason}` : ''),
16503
+ context: { commitmentId: e?.id ?? null, topicId: e?.topicId ?? null, sendKind: e?.kind ?? null, dryRun: event.includes('would-') || e?.dryRun === true, closed: e?.closed ?? null, wouldClose: e?.wouldClose ?? null, leakedTerms: Array.isArray(e?.terms) ? e.terms.length : null },
16504
+ });
16505
+ });
16506
+ }
16353
16507
  promiseBeacon.start();
16354
16508
  globalThis.__instarPromiseBeacon = promiseBeacon;
16355
16509
  // ── AutonomousProgressHeartbeat ──────────────────────────────────
@@ -16467,6 +16621,30 @@ export async function startServer(options) {
16467
16621
  maxHeartbeatsPerRun: ahRawCfg.maxHeartbeatsPerRun,
16468
16622
  recentOutputChangeWindowMs: ahRawCfg.recentOutputChangeWindowMs,
16469
16623
  });
16624
+ // The focus line is a session's own words: never in a row. Suppressions run every tick, so only a change of reason per topic writes one.
16625
+ const ahLastHold = new Map();
16626
+ autonomousHeartbeat.on('would-emit', (e) => {
16627
+ ahLastHold.delete(e.topicId);
16628
+ featureEvidence.record('monitoring.autonomousHeartbeat', { kind: 'fired', reason: 'would emit (dry run)', context: { topicId: e.topicId, minutesSilent: e.minutesSilent, dryRun: true } });
16629
+ });
16630
+ autonomousHeartbeat.on('emitted', (e) => {
16631
+ ahLastHold.delete(e.topicId);
16632
+ featureEvidence.record('monitoring.autonomousHeartbeat', { kind: 'fired', reason: 'emitted', context: { topicId: e.topicId, minutesSilent: e.minutesSilent, dryRun: false } });
16633
+ });
16634
+ autonomousHeartbeat.on('send-error', (e) => {
16635
+ featureEvidence.record('monitoring.autonomousHeartbeat', { kind: 'error', reason: 'send failed', context: { topicId: e.topicId, errorName: e.err instanceof Error ? e.err.name : 'unknown' } });
16636
+ });
16637
+ autonomousHeartbeat.on('tick-error', (err) => {
16638
+ featureEvidence.recordAtMostEvery('monitoring.autonomousHeartbeat', 'tick-error', 60 * 60 * 1000, { kind: 'error', reason: 'tick failed', context: { errorName: err instanceof Error ? err.name : 'unknown' } });
16639
+ });
16640
+ autonomousHeartbeat.on('suppressed', (e) => {
16641
+ if (ahLastHold.get(e.topicId) === e.reason)
16642
+ return;
16643
+ if (ahLastHold.size >= 256)
16644
+ ahLastHold.clear();
16645
+ ahLastHold.set(e.topicId, e.reason);
16646
+ featureEvidence.record('monitoring.autonomousHeartbeat', { kind: 'held', reason: `suppressed: ${e.reason}`, context: { topicId: e.topicId } });
16647
+ });
16470
16648
  autonomousHeartbeat.start();
16471
16649
  globalThis.__instarAutonomousHeartbeat = autonomousHeartbeat;
16472
16650
  guardRegistry.register('monitoring.autonomousHeartbeat.enabled', () => autonomousHeartbeat.guardStatus());
@@ -19599,6 +19777,17 @@ export async function startServer(options) {
19599
19777
  });
19600
19778
  if (featureRegistryReady) {
19601
19779
  featureRegistry.bootstrap(config);
19780
+ // docs/specs/recommended-services.md: old declines carry over before any list is built.
19781
+ if (_recommendedServicesLedger) {
19782
+ try {
19783
+ const { importLegacyDeclines } = await import('../recommended/legacyDeclines.js');
19784
+ importLegacyDeclines(_recommendedServicesLedger, (id) => featureRegistry.getState(id, 'default')?.discoveryState ?? null);
19785
+ }
19786
+ catch (err) {
19787
+ // @silent-fallback-ok: reported; idempotent, so it retries at next boot, and optional work never blocks startup
19788
+ console.warn(` [recommended-services] old declines could not be imported yet: ${err instanceof Error ? err.message : String(err)}`);
19789
+ }
19790
+ }
19602
19791
  }
19603
19792
  {
19604
19793
  const summaries = featureRegistry.getSummaries();
@@ -20474,6 +20663,102 @@ export async function startServer(options) {
20474
20663
  _swapAntiThrashEngine = null;
20475
20664
  _swapWorkGate = null;
20476
20665
  }
20666
+ // A dead sign-in key on a key-only agent: confirmed, told, recovered (spec cloud-key-internal-calls).
20667
+ // Wired here, outside the subscription pool block, because these agents may have no pool.
20668
+ {
20669
+ const { ClaudeKeyHealth, claudeKeyFingerprint, setActiveClaudeKeyHealth } = await import('../core/ClaudeKeyHealth.js');
20670
+ const { buildClaudeKeyProbe } = await import('../core/claudeKeyProbe.js');
20671
+ const { configuredClaudeOauthKey, setClaudeCallOutcomeListener } = await import('../core/claudeChildAuth.js');
20672
+ const keyHealthOn = () => liveConfig.get('sessions.claudeKeyHealth.enabled', true) !== false;
20673
+ const sendToSlackKey = async (routingKey, text) => {
20674
+ const [channelId, threadTs] = routingKey.split(':');
20675
+ await _slackAdapter.sendToChannel(channelId, text, threadTs ? { thread_ts: threadTs } : undefined);
20676
+ };
20677
+ // The disk read covers a topic bound after this server booted, as SessionRefresh does.
20678
+ const topicForSession = (name) => telegram?.getTopicForSession(name) ?? telegram?.resolveTopicForSessionFromDisk?.(name) ?? null;
20679
+ const claudeKeyHealth = new ClaudeKeyHealth({
20680
+ stateFile: path.join(config.stateDir, 'state', 'claude-key-health.json'),
20681
+ currentKey: () => (keyHealthOn() ? configuredClaudeOauthKey() : undefined),
20682
+ currentRawKey: () => config.sessions.anthropicApiKey,
20683
+ readKeyFromDisk: () => (keyHealthOn() ? readConfiguredAnthropicKey(config.stateDir) : undefined),
20684
+ applyKey: (key) => {
20685
+ config.sessions.anthropicApiKey = key ?? undefined;
20686
+ sessionManager.setAnthropicKey(key);
20687
+ },
20688
+ probe: buildClaudeKeyProbe({
20689
+ claudePath: () => resolveFrameworkBinaryPath({
20690
+ framework: 'claude-code',
20691
+ frameworkBinaryPaths: config.sessions.frameworkBinaryPaths,
20692
+ claudePath: config.sessions.claudePath,
20693
+ configuredFramework: config.sessions.framework,
20694
+ }) ?? detectClaudePath(),
20695
+ baseUrl: () => config.sessions.anthropicBaseUrl,
20696
+ }),
20697
+ // Fixed server text straight to the adapters: the model is what is down, and `notify` returns
20698
+ // nothing, so it can't say whether anyone was told.
20699
+ notifyOperator: async (text) => {
20700
+ let delivered = false;
20701
+ const hubTopicId = state.get('agent-attention-topic') ?? 0;
20702
+ if (telegram && hubTopicId) {
20703
+ try {
20704
+ await telegram.sendToTopic(hubTopicId, text);
20705
+ delivered = true;
20706
+ }
20707
+ catch (err) { /* @silent-fallback-ok: `delivered` stays false, which drives the retry and its capped report */
20708
+ console.warn(`[ClaudeKeyHealth] Telegram notice failed: ${err instanceof Error ? err.message : String(err)}`);
20709
+ }
20710
+ }
20711
+ const attentionChannel = state.get('slack-attention-channel');
20712
+ if (_slackAdapter && attentionChannel) {
20713
+ try {
20714
+ await _slackAdapter.sendToChannel(attentionChannel, text);
20715
+ delivered = true;
20716
+ }
20717
+ catch (err) { /* @silent-fallback-ok: `delivered` stays false, which drives the retry and its capped report */
20718
+ console.warn(`[ClaudeKeyHealth] Slack notice failed: ${err instanceof Error ? err.message : String(err)}`);
20719
+ }
20720
+ }
20721
+ return delivered;
20722
+ },
20723
+ notifyPerson: async (sessionName, text) => {
20724
+ const topicId = topicForSession(sessionName);
20725
+ if (topicId !== null) {
20726
+ await telegram.sendToTopic(topicId, text);
20727
+ return true;
20728
+ }
20729
+ const routingKey = _slackAdapter?.getChannelForSession(sessionName) ?? null;
20730
+ if (routingKey !== null) {
20731
+ await sendToSlackKey(routingKey, text);
20732
+ return true;
20733
+ }
20734
+ return false;
20735
+ },
20736
+ listStuckSessions: async () => (await sessionManager.listSessionsAtLoginScreen()).filter((name) => topicForSession(name) !== null || (_slackAdapter?.getChannelForSession(name) ?? null) !== null),
20737
+ sessionLaunchFingerprint: (tmuxSession) => {
20738
+ const launched = sessionManager.sessionLaunchKey(tmuxSession);
20739
+ return launched ? claudeKeyFingerprint(launched) : null;
20740
+ },
20741
+ refresh: async (sessionName, prompt) => {
20742
+ if (!_sessionRefresh)
20743
+ return { ok: false, reason: 'session refresh not available' };
20744
+ const r = await _sessionRefresh.refreshSession({ sessionName, followUpPrompt: prompt, reason: 'claude-key-restored' });
20745
+ return r.ok ? { ok: true, newSessionName: r.newSessionName } : { ok: false, reason: r.code };
20746
+ },
20747
+ clearLoginReports: () => sessionManager.clearInteractiveLoginReports(),
20748
+ report: ({ reason, impact }) => DegradationReporter.getInstance().report({
20749
+ feature: 'ClaudeKeyHealth',
20750
+ primary: 'the configured Claude sign-in key authenticates every model call',
20751
+ fallback: 'the operator is told and stuck conversations wait for a working key',
20752
+ reason,
20753
+ impact,
20754
+ }),
20755
+ logger: { log: (m) => console.log(m), warn: (m) => console.warn(m) },
20756
+ });
20757
+ setActiveClaudeKeyHealth(claudeKeyHealth);
20758
+ setClaudeCallOutcomeListener((outcome) => claudeKeyHealth.noteCallOutcome(outcome));
20759
+ sessionManager.prependInteractiveLoginExpiredSink((signal) => claudeKeyHealth.handle(signal));
20760
+ void claudeKeyHealth.boot().catch((err) => console.warn(`[ClaudeKeyHealth] boot failed: ${err instanceof Error ? err.message : String(err)}`));
20761
+ }
20477
20762
  // SessionRefresh — agent-initiated session respawn. Requires a Telegram
20478
20763
  // adapter (v1 scope: Telegram-bound sessions only). The respawner closure
20479
20764
  // captures `topicMemory` by reference, so even if topicMemory is wired up
@@ -22885,7 +23170,22 @@ export async function startServer(options) {
22885
23170
  };
22886
23171
  _refreshPoolHeartbeat = refreshPool;
22887
23172
  refreshPool();
22888
- const poolTimer = setInterval(refreshPool, 30_000);
23173
+ const readinessMod = await import('../core/poolReadiness.js');
23174
+ const durableOwnershipMod = await import('../core/durableOwnershipActivation.js');
23175
+ const poolReadinessDeps = {
23176
+ peerIds: () => Object.entries(coordinator.managers.identityManager.loadRegistry().machines ?? {})
23177
+ .filter(([id, entry]) => id !== poolSelfId && !entry.revokedAt)
23178
+ .map(([id]) => id),
23179
+ capacity: (id) => machinePoolRegistry.getCapacityForReport(id),
23180
+ ownChannels: () => selfServesChannels(),
23181
+ durableOwnership: () => durableOwnershipMod.shouldActivateDurableOwnership(config, resolveDevAgentGate),
23182
+ duplicateCheck: () => _duplicateReconciler?.status() ?? null,
23183
+ takeover: () => _takeoverReadiness,
23184
+ };
23185
+ readinessMod.setActivePoolReadiness(poolReadinessDeps);
23186
+ const poolReadinessLog = new readinessMod.PoolReadinessLog(poolReadinessDeps, path.join(config.stateDir, '..', 'logs', 'pool-readiness.jsonl'));
23187
+ const poolBeat = () => { refreshPool(); poolReadinessLog.tick(); };
23188
+ const poolTimer = setInterval(poolBeat, 30_000);
22889
23189
  if (typeof poolTimer.unref === 'function')
22890
23190
  poolTimer.unref();
22891
23191
  // Boot-time pool-flag-coherence check (multi-machine-replicated-store-
@@ -23415,6 +23715,7 @@ export async function startServer(options) {
23415
23715
  // root at already-paired peers remains an explicit operator/PIN step;
23416
23716
  // the bearer recovery path can never become the first root writer.
23417
23717
  const escrow = machineRecoveryKey.ensure(meshSelfId, own.recoveryEpoch ?? 0, own.recoveryPublicKey);
23718
+ _recoveryEscrowEvidence = { minted: !!escrow, recoveryEpoch: own.recoveryEpoch ?? 0, hadRoot: !!own.recoveryPublicKey };
23418
23719
  if (own.recoveryPublicKey && !escrow) {
23419
23720
  try {
23420
23721
  _meshAttentionRaise?.({
@@ -24121,6 +24422,43 @@ export async function startServer(options) {
24121
24422
  return []; /* @silent-fallback-ok — no planner → no overload moves (today's behavior) */
24122
24423
  }
24123
24424
  },
24425
+ // A shed move goes through the owner-side drain: it closes the session and hands
24426
+ // over custody. One at a time; the slot is held until the runner settles, so a
24427
+ // hung drain blocks further moves rather than stacking them.
24428
+ drainMove: (mv, epoch) => {
24429
+ const planner = getActiveOverloadShedPlanner();
24430
+ if (!planner)
24431
+ return;
24432
+ if (_shedDrainInFlight)
24433
+ return;
24434
+ if (!_drainRunner) {
24435
+ planner.noteMoveOutcome(mv.sessionKey, { status: 'refused-no-drain-runner' });
24436
+ return;
24437
+ }
24438
+ const target = machinePoolRegistry?.getCapacity(mv.target);
24439
+ if (!target || target.liveness?.state !== 'live' || target.loadVerdict !== 'ok' || target.loadReport?.acceptingWork === false) {
24440
+ planner.noteMoveOutcome(mv.sessionKey, { status: 'refused-target-changed' });
24441
+ return;
24442
+ }
24443
+ _shedDrainInFlight = true;
24444
+ const startedAt = Date.now();
24445
+ _shedDrainTopics.add(mv.sessionKey);
24446
+ void _drainRunner.run({ sessionKey: mv.sessionKey, target: mv.target, senderObservedEpoch: epoch, onNotQuiet: 'abort' })
24447
+ .then((o) => {
24448
+ if (o.status === 'drained' || o.status === 'drained-interrupted') {
24449
+ const topicNum = Number(mv.sessionKey);
24450
+ if (Number.isFinite(topicNum)) {
24451
+ try {
24452
+ getMoveAftercare()?.(mv.target, topicNum);
24453
+ }
24454
+ catch { /* @silent-fallback-ok — the kick has bounded retries; the target can still fetch */ }
24455
+ }
24456
+ }
24457
+ planner.noteMoveOutcome(mv.sessionKey, { status: o.status, claimLanded: o.claimLanded, durationMs: Date.now() - startedAt, ...(o.detail ? { detail: o.detail } : {}) });
24458
+ })
24459
+ .catch((err) => { planner.noteMoveOutcome(mv.sessionKey, { status: 'refused-drain-threw', detail: err instanceof Error ? err.message : String(err) }); })
24460
+ .finally(() => { _shedDrainInFlight = false; _shedDrainTopics.delete(mv.sessionKey); });
24461
+ },
24124
24462
  // Live only when overload shed is enabled AND out of dry-run: driving unpinned
24125
24463
  // transfers (claim / abort past the deadline) is real authority over every
24126
24464
  // unpinned in-flight transfer, so the soft dry-run lever must hold it too.
@@ -24185,6 +24523,7 @@ export async function startServer(options) {
24185
24523
  enabled: resolveDevAgentGate(c?.enabled, config),
24186
24524
  dryRun: c?.dryRun ?? dflt.dryRun,
24187
24525
  sourceAfterMs: c?.sourceAfterMs ?? dflt.sourceAfterMs,
24526
+ topicCooldownMs: c?.topicCooldownMs ?? dflt.topicCooldownMs,
24188
24527
  maxMovesPerHour: c?.maxMovesPerHour ?? dflt.maxMovesPerHour,
24189
24528
  recentShedMs: c?.recentShedMs ?? dflt.recentShedMs,
24190
24529
  };
@@ -24198,6 +24537,39 @@ export async function startServer(options) {
24198
24537
  return true; /* @silent-fallback-ok — an unreadable pin view treats the topic as pinned (never moved) */
24199
24538
  }
24200
24539
  };
24540
+ const shedProofTopics = () => new Set(config.multiMachine?.sessionPool?.rebalanceProofTopics ?? []);
24541
+ // Topics with a running session here, with when the conversation last moved.
24542
+ // One cached listing; the work-state reads stay off the planner's sync tick.
24543
+ const quietScanner = new QuietTopicScanner({
24544
+ runningTopicSessions: () => {
24545
+ if (!telegram)
24546
+ return [];
24547
+ const out = [];
24548
+ for (const s of sessionManager.getCachedRunningSessions().sessions) {
24549
+ const topic = telegram.getTopicForSession(s.tmuxSession);
24550
+ if (topic === null || topic === undefined)
24551
+ continue;
24552
+ const last = telegram.getTopicHistory(topic, 1)[0];
24553
+ const at = last ? Date.parse(last.timestamp) : NaN;
24554
+ out.push({ sessionKey: String(topic), tmuxSession: s.tmuxSession, lastActivityAt: Number.isFinite(at) ? at : null });
24555
+ }
24556
+ return out;
24557
+ },
24558
+ workState: (tmux) => sessionManager.checkSessionWorkState(tmux),
24559
+ movable: (key) => {
24560
+ const r = ownReg.read(key);
24561
+ if (r?.status !== 'active' || r.ownerMachineId !== _meshSelfId)
24562
+ return false;
24563
+ if (shedPinned(key) || shedProofTopics().has(Number(key)))
24564
+ return false;
24565
+ try {
24566
+ return !autoSessionsMod.listAutonomousJobs(config.stateDir).find((j) => j.topic === key && j.active && !j.paused);
24567
+ }
24568
+ catch {
24569
+ return false; /* @silent-fallback-ok: unreadable run registry: treat the topic as not movable */
24570
+ }
24571
+ },
24572
+ });
24201
24573
  const planner = new shedMod.OverloadShedPlanner({
24202
24574
  config: shedCfg,
24203
24575
  selfMachineId: () => _meshSelfId,
@@ -24205,7 +24577,16 @@ export async function startServer(options) {
24205
24577
  capacities: () => machinePoolRegistry?.getCapacities() ?? [],
24206
24578
  ownedTopics: () => ownReg.all()
24207
24579
  .filter((r) => r.status === 'active' && r.ownerMachineId === _meshSelfId)
24208
- .map((r) => ({ sessionKey: r.sessionKey, pinned: shedPinned(r.sessionKey) })),
24580
+ .map((r) => ({ sessionKey: r.sessionKey, pinned: shedPinned(r.sessionKey), lastMovedAt: r.timestamp })),
24581
+ poolStage: () => liveConfig.get('multiMachine.sessionPool.stage', 'dark'),
24582
+ proofFresh: () => {
24583
+ if (!_rebalanceProofStore)
24584
+ return false;
24585
+ return rebalanceProofState(_rebalanceProofStore, Date.now()).fresh;
24586
+ },
24587
+ quietTopics: () => quietScanner.current(),
24588
+ moveActuatorLive: () => resolveDevAgentGate(ws13Cfg().ws13Reconcile, config) && ws13Cfg().ws13DryRun === false,
24589
+ isProofTopic: (key) => shedProofTopics().has(Number(key)),
24209
24590
  ownerOf: (key) => ownReg.read(key)?.ownerMachineId,
24210
24591
  statusOf: (key) => {
24211
24592
  const r = ownReg.read(key);
@@ -24229,7 +24610,81 @@ export async function startServer(options) {
24229
24610
  log: (line) => console.log(pc.yellow(` [overload-shed] ${line}`)),
24230
24611
  });
24231
24612
  shedMod.setActiveOverloadShedPlanner(planner);
24613
+ // The rebalance proof: drives this planner's real path, judged from outside it.
24614
+ const proofMarker = path.join(config.stateDir, 'rebalance-proof-in-flight');
24615
+ setActiveRebalanceProof(new RebalanceProofRunner({
24616
+ selfMachineId: () => _meshSelfId,
24617
+ isProofTopic: (t) => shedProofTopics().has(t),
24618
+ stage: () => liveConfig.get('multiMachine.sessionPool.stage', 'dark'),
24619
+ stageAllowsProof: () => {
24620
+ const st = liveConfig.get('multiMachine.sessionPool.stage', 'dark');
24621
+ return st === 'live-transfer' || st === 'rebalance';
24622
+ },
24623
+ readRecord: (t) => ownReg.read(String(t)),
24624
+ hasLocalSession: (t) => {
24625
+ const tmux = telegram?.getSessionForTopic(t);
24626
+ return !!tmux && sessionManager.isSessionAlive(tmux);
24627
+ },
24628
+ ensureIdleSession: async (t, timeoutMs) => {
24629
+ if (!telegram)
24630
+ return false;
24631
+ const live = () => { const m = telegram.getSessionForTopic(t); return m && sessionManager.isSessionAlive(m) ? m : null; };
24632
+ if (!live()) {
24633
+ const name = await spawnSessionForTopic(sessionManager, telegram, `proof-${t}`, t, proofSpawnBrief());
24634
+ telegram.registerTopicSession(t, name, `proof-${t}`);
24635
+ }
24636
+ const deadline = Date.now() + timeoutMs;
24637
+ while (Date.now() < deadline) {
24638
+ const tmux = live();
24639
+ if (tmux && (await sessionManager.checkSessionWorkState(tmux)) === 'idle')
24640
+ return true;
24641
+ await new Promise((r) => setTimeout(r, 5_000));
24642
+ }
24643
+ return false;
24644
+ },
24645
+ move: (t, to) => planner.proofMove(String(t), to),
24646
+ sendProbe: async (t, text, messageId) => {
24647
+ if (!_sessionRouter)
24648
+ return 'no-router';
24649
+ const o = await _sessionRouter.route({ sessionKey: String(t), messageId, payload: text, senderEnvelope: null });
24650
+ return o.action;
24651
+ },
24652
+ readHistory: async (t) => {
24653
+ const r = await fetch(`http://127.0.0.1:${config.port}/telegram/topics/${t}/messages?scope=pool&limit=50`, {
24654
+ headers: { Authorization: `Bearer ${config.authToken}`, 'X-Instar-AgentId': config.projectName },
24655
+ });
24656
+ if (!r.ok)
24657
+ throw new Error(`history ${r.status}`);
24658
+ const j = await r.json();
24659
+ return { rows: j.messages ?? [], failed: (j.pool?.failed ?? []).map((f) => (typeof f === 'string' ? f : f.machineId ?? '')) };
24660
+ },
24661
+ record: (result, evidenceRef) => {
24662
+ _rebalanceProofStore?.recordResult(3, result, _sessionPoolBuildIdentity?.() ?? 'unknown', evidenceRef);
24663
+ },
24664
+ writeEvidence: (ev) => {
24665
+ const dir = path.join(config.stateDir, '..', 'logs', 'rebalance-proof');
24666
+ fs.mkdirSync(dir, { recursive: true });
24667
+ const file = path.join(dir, `${new Date().toISOString().replace(/[:.]/g, '-')}.json`);
24668
+ fs.writeFileSync(file, JSON.stringify(ev, null, 2));
24669
+ return file;
24670
+ },
24671
+ newNonce: () => crypto.randomUUID().replace(/-/g, '').slice(0, 12),
24672
+ markInFlight: (runId) => fs.writeFileSync(proofMarker, runId),
24673
+ readInFlight: () => { try {
24674
+ return fs.readFileSync(proofMarker, 'utf8').trim() || null;
24675
+ }
24676
+ catch {
24677
+ return null; /* @silent-fallback-ok — no marker means no unfinished run */
24678
+ } },
24679
+ clearInFlight: () => { SafeFsExecutor.safeRmSync(proofMarker, { force: true, operation: 'rebalance-proof: run finished' }); },
24680
+ log: (line) => console.log(pc.dim(` [rebalance-proof] ${line}`)),
24681
+ }));
24232
24682
  _overloadShedTimer = setInterval(() => {
24683
+ // The scan is cheap to skip: it only matters while this machine is a source.
24684
+ if (planner.status().isSource === true)
24685
+ void quietScanner.refresh();
24686
+ else
24687
+ quietScanner.clear();
24233
24688
  try {
24234
24689
  planner.tick();
24235
24690
  }
@@ -24619,6 +25074,9 @@ export async function startServer(options) {
24619
25074
  // release replicates exactly like the user-move release does. A lost CAS
24620
25075
  // (peer advanced the epoch first) is a no-op here — we never retry/force.
24621
25076
  emitPlacement(sk, r, 'released', prevOwner);
25077
+ featureEvidence.record('multiMachine.ownershipFollowsLiveWork', r.ok
25078
+ ? { kind: 'fired', reason: 'release-on-complete: ownership released', context: { topicId: sk, part: 'release-on-complete', prevOwner: prevOwner ?? null } }
25079
+ : { kind: 'error', reason: 'release-on-complete: compare-and-set refused', context: { topicId: sk, part: 'release-on-complete', prevOwner: prevOwner ?? null } });
24622
25080
  }
24623
25081
  catch {
24624
25082
  // @silent-fallback-ok — release-on-complete is best-effort housekeeping
@@ -25028,9 +25486,16 @@ export async function startServer(options) {
25028
25486
  const r = ownReg.cas(action, c);
25029
25487
  // Journal pairing (§3.3): the drain's transfer/abort/claim CASes
25030
25488
  // record placement history like every other CAS site.
25031
- emitPlacement(c.sessionKey, r, 'user-move', prev);
25489
+ emitPlacement(c.sessionKey, r, _shedDrainTopics.has(c.sessionKey) ? 'reconcile' : 'user-move', prev);
25032
25490
  return r;
25033
25491
  },
25492
+ sessionIdleNow: async (sk) => {
25493
+ const topicNum = Number(sk);
25494
+ const tmux = Number.isFinite(topicNum) ? telegram?.getSessionForTopic(topicNum) : null;
25495
+ if (!tmux || !sessionManager.isSessionAlive(tmux))
25496
+ return true; // nothing local to disturb
25497
+ return (await sessionManager.checkSessionWorkState(tmux)) === 'idle';
25498
+ },
25034
25499
  suspendAutonomousRun: (topic, target) => autoMod.suspendAutonomousTopicForMove(config.stateDir, topic, target, coherenceJournal ?? undefined),
25035
25500
  sessionQuiet: (sk) => {
25036
25501
  const topicNum = Number(sk);
@@ -27921,6 +28386,11 @@ export async function startServer(options) {
27921
28386
  }
27922
28387
  runMachineCoherenceEffects?.(effects, { telegram: () => tg ?? null });
27923
28388
  };
28389
+ const meshEvidence = (kind, reason) => {
28390
+ featureEvidence.record('monitoring.meshCoherenceLiveCheck', { kind, reason, context: { uptimeSec: Math.round(process.uptime()), emitCap: config.monitoring?.meshCoherenceLiveCheck?.emitCap ?? null } });
28391
+ };
28392
+ const meshFired = (code) => { meshEvidence('fired', `divergence:${code}`); return true; };
28393
+ const meshHeld = (code) => meshEvidence('held', `emit-cap:${code}`);
27924
28394
  const peerPresenceTick = () => {
27925
28395
  void reconcileIdentityActivation().catch((err) => {
27926
28396
  console.warn(`[identity-recovery] periodic activation reconciliation failed: ${err instanceof Error ? err.message : String(err)}`);
@@ -27960,8 +28430,10 @@ export async function startServer(options) {
27960
28430
  if (emitCap === undefined || count < emitCap) { // emitCap is READ here
27961
28431
  console.log(pc.yellow(` ⚠ mesh-live-coherence [${w.code}]: ${w.message}`));
27962
28432
  _meshCoherenceEmitCounts.set(w.code, count + 1);
27963
- firedThisTick = true;
28433
+ firedThisTick = meshFired(w.code);
27964
28434
  }
28435
+ else
28436
+ meshHeld(w.code);
27965
28437
  }
27966
28438
  }
27967
28439
  recorder?.record({ feature: 'mesh-coherence-live', kind: 'event', outcome: firedThisTick ? 'fired' : 'noop' });
@@ -27979,6 +28451,8 @@ export async function startServer(options) {
27979
28451
  _meshCoherenceFailing = true;
27980
28452
  }
27981
28453
  _meshCoherenceConsecFailures += 1;
28454
+ if (_meshCoherenceConsecFailures === 1)
28455
+ meshEvidence('error', 'live-state-read-failed');
27982
28456
  }
27983
28457
  }
27984
28458
  }
@@ -28452,6 +28926,30 @@ export async function startServer(options) {
28452
28926
  bootCommitSha = `package:${startupVersion}`;
28453
28927
  }
28454
28928
  const currentSessionPoolBuildIdentity = () => bootCommitSha || 'unknown';
28929
+ _sessionPoolBuildIdentity = currentSessionPoolBuildIdentity;
28930
+ // The rebalance proof has its own signed store: the failover rows prove failover, and
28931
+ // 770 of them once sat at stage 3 proving nothing about rebalancing.
28932
+ _rebalanceProofStore = new e2eMod.SessionPoolE2EResultStore({
28933
+ filePath: path.join(config.stateDir, 'session-pool-rebalance-proof.json'),
28934
+ sign: hmac,
28935
+ verifySig: (c, s) => {
28936
+ try {
28937
+ const exp = hmac(c);
28938
+ return s.length === exp.length && crypto.timingSafeEqual(Buffer.from(s), Buffer.from(exp));
28939
+ }
28940
+ catch {
28941
+ return false; /* @silent-fallback-ok: HMAC verify fails closed — a malformed input is an invalid signature, never accepted */
28942
+ }
28943
+ },
28944
+ });
28945
+ setActiveRebalanceProofStore(_rebalanceProofStore);
28946
+ // A failure here must not cost the agent its rollout gate below.
28947
+ try {
28948
+ getActiveRebalanceProof()?.recoverInterrupted();
28949
+ }
28950
+ catch (err) {
28951
+ console.warn('[rebalance-proof] could not record an interrupted run:', err instanceof Error ? err.message : String(err)); /* @silent-fallback-ok (logged): the marker stays and the next boot retries */
28952
+ }
28455
28953
  // ONE authoritative stage read for the rollout gate and its proof producer.
28456
28954
  // Splitting these previously let the runner stamp every green as stage 0
28457
28955
  // while StageAdvancer was already waiting for a green at stage 2.
@@ -28463,6 +28961,7 @@ export async function startServer(options) {
28463
28961
  currentCommitSha: currentSessionPoolBuildIdentity,
28464
28962
  readStage: readSessionPoolStage,
28465
28963
  writeStageConfig: (s) => liveConfig.set(guardMod.STAGE_CONFIG_PATH, s, { stageWriteToken: guardMod.STAGE_WRITE_TOKEN }),
28964
+ rebalanceProof: () => stageMod.rebalanceProofState(_rebalanceProofStore, Date.now()),
28466
28965
  audit: (event, detail) => console.log(pc.dim(` [stage-advancer] ${event} ${JSON.stringify(detail)}`)),
28467
28966
  });
28468
28967
  // ── Promotion activation ────────────────────────────────────────────────
@@ -28614,7 +29113,7 @@ export async function startServer(options) {
28614
29113
  currentCommitSha: currentSessionPoolBuildIdentity,
28615
29114
  // Credit the proof to the stage that is actually running. The next
28616
29115
  // promotion reads this same current-stage index as its prior-stage gate.
28617
- provenStage: () => stageMod.stageIndex(readSessionPoolStage()),
29116
+ provenStage: () => stageMod.failoverProvenStage(readSessionPoolStage()),
28618
29117
  audit: (event, detail) => console.log(pc.dim(` [failover-runner] ${event} ${JSON.stringify(detail)}`)),
28619
29118
  });
28620
29119
  if (_sessionPoolFailoverRunnerDriver) {
@@ -29642,10 +30141,12 @@ export async function startServer(options) {
29642
30141
  console.warn('[instar] Windows desktop bootstrap diagnostic could not be persisted');
29643
30142
  }
29644
30143
  }
29645
- const server = new AgentServer({ config, ecosystemLedger: _ecosystemLedger ?? undefined, singleInstanceLock, agentIdentity: _agentIdentityDeps, terminateSessionAuthority: terminateWithAuthority, subscriptionEmailBinding: credentialLocationLedger, subscriptionEmailBarrier, subscriptionIdentityOracle, sessionManager, llmQueue: sharedLlmQueue, state, scheduler, telegram, telegramOrigin: telegramOriginBoot?.runtime, relationships, feedback, feedbackAnomalyDetector, dispatches, updateChecker, autoUpdater, autoDispatcher, quotaTracker, quotaManager, publisher, viewer, jobAnomalySendAutomationReply: sendAutomationReply, tunnel, evolution, watchdog, topicMemory, triageNurse, projectMapper, cartographerRoots: cartographerRoots ?? undefined, coherenceGate: scopeVerifier, contextHierarchy, canonicalState, operationGate, sentinel, adaptiveTrust, memoryMonitor, orphanReaper, coherenceMonitor, commitmentTracker, subscriptionPool, accountFollowMePeerViews: async () => { const nickById = new Map((_listPoolMachines?.() ?? []).map((m) => [m.machineId, verifiedEntityName(m.machineId, m.nickname) ?? ''])); let peers = (_resolvePeerUrls?.() ?? []).map((p) => ({ machineId: p.machineId, nickname: nickById.get(p.machineId) ?? '', url: p.url })); if (peers.length === 0) {
30144
+ const server = new AgentServer({ config, ecosystemLedger: _ecosystemLedger ?? undefined, recommendedServicesLedger: _recommendedServicesLedger ?? undefined, singleInstanceLock, agentIdentity: _agentIdentityDeps, terminateSessionAuthority: terminateWithAuthority, subscriptionEmailBinding: credentialLocationLedger, subscriptionEmailBarrier, subscriptionIdentityOracle, sessionManager, llmQueue: sharedLlmQueue, state, scheduler, telegram, telegramOrigin: telegramOriginBoot?.runtime, relationships, feedback, feedbackAnomalyDetector, dispatches, updateChecker, autoUpdater, autoDispatcher, quotaTracker, quotaManager, publisher, viewer, jobAnomalySendAutomationReply: sendAutomationReply, tunnel, evolution, watchdog, topicMemory, triageNurse, projectMapper, cartographerRoots: cartographerRoots ?? undefined, coherenceGate: scopeVerifier, contextHierarchy, canonicalState, operationGate, sentinel, adaptiveTrust, memoryMonitor, orphanReaper, coherenceMonitor, commitmentTracker, subscriptionPool, accountFollowMePeerViews: async () => { const nickById = new Map((_listPoolMachines?.() ?? []).map((m) => [m.machineId, verifiedEntityName(m.machineId, m.nickname) ?? ''])); let peers = (_resolvePeerUrls?.() ?? []).map((p) => ({ machineId: p.machineId, nickname: nickById.get(p.machineId) ?? '', url: p.url })); if (peers.length === 0) {
29646
30145
  peers = (_listPoolMachines?.() ?? []).filter((m) => m.machineId !== _meshSelfId && !!m.lastKnownUrl).map((m) => ({ machineId: m.machineId, nickname: verifiedEntityName(m.machineId, m.nickname) ?? '', url: m.lastKnownUrl }));
29647
30146
  } if (peers.length === 0)
29648
- return []; const { fetchPeerSubscriptionViews } = await import('../core/fetchPeerSubscriptionViews.js'); return fetchPeerSubscriptionViews({ peers: () => peers, fetchImpl: fetch, authToken: config.authToken ?? '' }); }, quotaPoller, quotaAwareScheduler: _quotaAwareScheduler ?? undefined, proactiveSwapMonitor: _proactiveSwapMonitor ?? undefined, inUseAccountResolver, enrollmentWizard, accountFollowMeRevocation, credentialRepointing, semanticMemory, activitySentinel, rateLimitSentinel, releaseReadinessSentinel: releaseReadinessSentinel ?? undefined, greenPrAutoMerger: greenPrAutoMerger ?? undefined, localVerify: localVerifyService ?? undefined, localVerifyStatus: localVerifyStatus ?? undefined, guardLatchStore: guardLatchStore ?? undefined, agentStopSurfacer: agentStopSurfacer ?? undefined, messageRouter, summarySentinel, spawnManager, systemReviewer, capabilityMapper, selfKnowledgeTree, coverageAuditor, topicResumeMap: _topicResumeMap ?? undefined, topicProfile: _topicProfileCtx ?? undefined, sessionRefresh: _sessionRefresh ?? undefined, autonomyManager, trustElevationTracker, autonomousEvolution, coordinator: coordinator.enabled ? coordinator : undefined, meshBindActive: coordinator.managers.identityManager.hasIdentity() && config.multiMachine?.meshTransport?.enabled !== false, localSigningKeyPem, leaseTransport, peerEndpointRecorder, getSelfMeshEndpoints, onLeasePullRequest: () => leaseCoordinatorRef?.currentLease() ?? null, liveTailReceiver, handoffWireTransport, onHandoffBegin, onHandoffInitiate: handoffInitiate, handoffInProgress: handoffSentinelInProgress, messageLedger, currentInboundByTopic, replyMarkerTransport, onReplyMarker: messageLedger ? (marker) => { const m = marker; messageLedger.applyRemoteReplyMarker(m.dedupeKey, { platform: m.platform, replyIdempotencyKey: m.replyIdempotencyKey, epoch: m.epoch, topic: m.topic ?? null }); } : undefined, whatsapp: whatsappAdapter, slack: slackAdapter, imessage: imessageAdapter, conversationRegistry, conversationBindAuth, appConversations: _appConversationService ?? undefined, slackInboundDispatch: () => _slackInboundDispatch, conversationFollowThrough, whatsappBusinessBackend, messageBridge, hookEventReceiver, worktreeMonitor, subagentTracker, instructionsVerifier, handshakeManager: threadlineHandshake, threadlineRouter, conversationStore, threadLog, threadMessageRecorder, warrantsReplyGate, collaborationSurfacer, peerHomebaseRelay, threadResumeMap, topicLinkageHandler: topicLinkageHandler ?? undefined, threadlineRelayClient, pairingInvites: threadlinePairingInvites, getLastRelayEvent: threadlineGetLastRelayEvent, a2aRelayForward: _a2aRelayForwardCtx ?? undefined, threadlineReplyWaiters, threadlineMcpHttp, listenerManager: listenerManager ?? undefined, a2aDeliveryTracker: a2aDeliveryTracker ?? undefined, relayVerdictCounters: threadlineRelayClient ? (() => ({ ...threadlineRelayClient.relayVerdictCounters, expiredMismatchIgnored: a2aDeliveryTracker?.expiredMismatchIgnored ?? 0 })) : undefined, inboundIdLedger: _inboundIdLedger ?? undefined, inboundIdLedgerDaemonDeferred: () => _inboundIdLedgerDaemonDeferred, responseReviewGate, reviewCanaryBattery, messagingToneGate, outboundDedupGate, telemetryHeartbeat, pasteManager, featureRegistry, discoveryEvaluator, completionEvaluator, unifiedTrust, liveConfig, sharedStateLedger, ledgerSessionRegistry, worktreeManager, oidcEnrolledRepos: parallelDevConfig?.oidcEnrolledRepos, initiativeTracker, projectRoundRunner, projectDriftChecker, machineHeartbeat, machinePoolRegistry, ropeHealthMonitor, writeAdmission: writeAdmission ?? undefined, getInboundQueue: () => _inboundQueue, getMachineCoherence: () => _machineCoherenceSentinel, getSingleMachineFailoverGap: () => _singleMachineFailoverGap, getMissingLoginSession: () => _missingLoginSession, getSessionPoolFailoverRunner: () => _sessionPoolFailoverRunnerDriver?.status() ?? null, sessionPoolPromotionActivation: _sessionPoolPromotionActivation, meshRpcDispatcher, deliverA2aToMachine: _deliverA2aToMachine ?? undefined, workingSetPullCoordinator, workingSetArtifactManager, orchestratorPoller, commitmentReplicaStore, preferenceReplicaStore, replicatedRecordEmitter, replicatedStoreReconciler, conflictStore, rollbackUnmerge, droppedOriginRegistry, preferencesUnionReader, jevMemoryPicker, forwardCommitmentMutate, sessionOwnershipRegistry, sendDrain: _sendDrain ?? undefined, claimTopicOwnershipOnSpawn: (topicId) => _claimOwnershipForAutonomousSpawn ? _claimOwnershipForAutonomousSpawn(topicId) : 'unwired', topicPinStore: _topicPinStore ?? undefined, topicPinSkewQuarantine: _topicPinSkewQuarantine ?? undefined, topicPinFoldView: _topicPinFoldView ?? undefined, ownershipReconciler: _ownershipReconciler ?? undefined, staleOwnerEngine: _staleOwnerEngine ?? undefined, duplicateReconciler: _duplicateReconciler ?? undefined, ownerDarkLadder: _ownerDarkLadder ?? undefined, spawnAdmission: _spawnAdmission ?? undefined, judgmentProvenance: _judgmentProvenance ?? undefined, leaseHandback: _leaseHandbackCtx ?? undefined, streamTicketStore: _streamTicketStore ?? undefined, poolStreamAllowRemoteInput: config.dashboard?.poolStream?.allowRemoteInput ?? false, poolStreamConnector: _poolStreamConnector ?? undefined, secretSync: _secretSyncHandle ?? undefined, meshSelfId: _meshSelfId ?? undefined, resolveRouterUrl: _resolveRouterUrl ?? undefined, resolvePeerUrls: _resolvePeerUrls ?? undefined, recordRopeResult: _recordRopeResult ?? undefined, guardRegistry, listPoolMachines: _listPoolMachines ?? undefined, deliverMandateToMachine: _deliverMandateToMachine ?? undefined, passkeyRevokeOutbox: _passkeyRevokeOutbox ? () => _passkeyRevokeOutbox : undefined, passkeyPeerOnline: _passkeyPeerOnline, passkeyPoolReader: _passkeyPoolReader ? () => _passkeyPoolReader : undefined, passkeyProofBrowser: async (profileDir) => { const { ChromeCdpReloginBrowser } = await import('../core/ChromeCdpReloginBrowser.js'); return new ChromeCdpReloginBrowser({ userDataDir: profileDir, passkeyMode: true, headless: true, launchTimeoutMs: 30_000, operationTimeoutMs: 20_000 }); }, poolLink: _poolLink ?? undefined, poolPollCache: _poolPollCache ?? undefined, sessionPoolE2EResultStore, proxyCoordinator, topicIntentStore, topicIntentArcCheck, usherSignalStore, intelligence: sharedIntelligence ?? undefined, telegramBridgeConfig, telegramBridge: telegramBridge ?? undefined, threadlineObservability, briefDeps, workingMemory, taskFlowRegistry, threadlineFlowBridge, sessionReaper, agentWorktreeReaper, externalHogSentinel, orphanedWorkSentinel, mcpProcessReaper, codexArmSessionSweeper, geminiLoopRunner, sleepController, agentActivityState, reapLog, resumeQueue, resumeDrainer, autonomousLivenessReconciler, enforcedTerminationStatus: () => enforcedTerminationWatchdog?.guardStatus() ?? null, prHandLease: prHandLease ?? undefined, standDownRegistry: _standDownRegistry ?? undefined, standDownAudit: _standDownAudit ?? undefined, operatorStopRecorder: recordOperatorStop, sleepWakeDetector, unjustifiedStopGate, stopGateDb, stopNotifier, liveTestGate, liveTestGateMode, liveTestRunnerCtx }); // Resolve the late-bound topic-operator getter (increment 2e): routing was
30147
+ return []; const { fetchPeerSubscriptionViews } = await import('../core/fetchPeerSubscriptionViews.js'); return fetchPeerSubscriptionViews({ peers: () => peers, fetchImpl: fetch, authToken: config.authToken ?? '' }); }, quotaPoller, quotaAwareScheduler: _quotaAwareScheduler ?? undefined, proactiveSwapMonitor: _proactiveSwapMonitor ?? undefined, inUseAccountResolver, enrollmentWizard, accountFollowMeRevocation, credentialRepointing, semanticMemory, activitySentinel, rateLimitSentinel, releaseReadinessSentinel: releaseReadinessSentinel ?? undefined, greenPrAutoMerger: greenPrAutoMerger ?? undefined, localVerify: localVerifyService ?? undefined, localVerifyStatus: localVerifyStatus ?? undefined, guardLatchStore: guardLatchStore ?? undefined, agentStopSurfacer: agentStopSurfacer ?? undefined, messageRouter, summarySentinel, spawnManager, systemReviewer, capabilityMapper, selfKnowledgeTree, coverageAuditor, topicResumeMap: _topicResumeMap ?? undefined, topicProfile: _topicProfileCtx ?? undefined, sessionRefresh: _sessionRefresh ?? undefined, autonomyManager, trustElevationTracker, autonomousEvolution, coordinator: coordinator.enabled ? coordinator : undefined, meshBindActive: coordinator.managers.identityManager.hasIdentity() && config.multiMachine?.meshTransport?.enabled !== false, localSigningKeyPem, leaseTransport, peerEndpointRecorder, getSelfMeshEndpoints, onLeasePullRequest: () => leaseCoordinatorRef?.currentLease() ?? null, liveTailReceiver, handoffWireTransport, onHandoffBegin, onHandoffInitiate: handoffInitiate, handoffInProgress: handoffSentinelInProgress, messageLedger, currentInboundByTopic, replyMarkerTransport, onReplyMarker: messageLedger ? (marker) => { const m = marker; messageLedger.applyRemoteReplyMarker(m.dedupeKey, { platform: m.platform, replyIdempotencyKey: m.replyIdempotencyKey, epoch: m.epoch, topic: m.topic ?? null }); } : undefined, whatsapp: whatsappAdapter, slack: slackAdapter, imessage: imessageAdapter, conversationRegistry, conversationBindAuth, appConversations: _appConversationService ?? undefined, slackInboundDispatch: () => _slackInboundDispatch, conversationFollowThrough, whatsappBusinessBackend, messageBridge, hookEventReceiver, worktreeMonitor, subagentTracker, instructionsVerifier, handshakeManager: threadlineHandshake, threadlineRouter, conversationStore, threadLog, threadMessageRecorder, warrantsReplyGate, collaborationSurfacer, peerHomebaseRelay, threadResumeMap, topicLinkageHandler: topicLinkageHandler ?? undefined, threadlineRelayClient, pairingInvites: threadlinePairingInvites, getLastRelayEvent: threadlineGetLastRelayEvent, a2aRelayForward: _a2aRelayForwardCtx ?? undefined, threadlineReplyWaiters, threadlineMcpHttp, listenerManager: listenerManager ?? undefined, a2aDeliveryTracker: a2aDeliveryTracker ?? undefined, relayVerdictCounters: threadlineRelayClient ? (() => ({ ...threadlineRelayClient.relayVerdictCounters, expiredMismatchIgnored: a2aDeliveryTracker?.expiredMismatchIgnored ?? 0 })) : undefined, inboundIdLedger: _inboundIdLedger ?? undefined, inboundIdLedgerDaemonDeferred: () => _inboundIdLedgerDaemonDeferred, responseReviewGate, reviewCanaryBattery, messagingToneGate, outboundDedupGate, telemetryHeartbeat, pasteManager, featureRegistry, discoveryEvaluator, completionEvaluator, unifiedTrust, liveConfig, sharedStateLedger, ledgerSessionRegistry, worktreeManager, oidcEnrolledRepos: parallelDevConfig?.oidcEnrolledRepos, initiativeTracker, projectRoundRunner, projectDriftChecker, machineHeartbeat, machinePoolRegistry, ropeHealthMonitor, writeAdmission: writeAdmission ?? undefined, getInboundQueue: () => _inboundQueue, getMachineCoherence: () => _machineCoherenceSentinel, getSingleMachineFailoverGap: () => _singleMachineFailoverGap, getMissingLoginSession: () => _missingLoginSession, getSessionPoolFailoverRunner: () => _sessionPoolFailoverRunnerDriver?.status() ?? null, sessionPoolPromotionActivation: _sessionPoolPromotionActivation, meshRpcDispatcher, deliverA2aToMachine: _deliverA2aToMachine ?? undefined, workingSetPullCoordinator, workingSetArtifactManager, orchestratorPoller, commitmentReplicaStore, preferenceReplicaStore, replicatedRecordEmitter, replicatedStoreReconciler, conflictStore, rollbackUnmerge, droppedOriginRegistry, preferencesUnionReader, jevMemoryPicker, forwardCommitmentMutate, sessionOwnershipRegistry, sendDrain: _sendDrain ?? undefined, claimTopicOwnershipOnSpawn: (topicId) => _claimOwnershipForAutonomousSpawn ? _claimOwnershipForAutonomousSpawn(topicId) : 'unwired', topicPinStore: _topicPinStore ?? undefined, topicPinSkewQuarantine: _topicPinSkewQuarantine ?? undefined, topicPinFoldView: _topicPinFoldView ?? undefined, ownershipReconciler: _ownershipReconciler ?? undefined, staleOwnerEngine: _staleOwnerEngine ?? undefined, duplicateReconciler: _duplicateReconciler ?? undefined, ownerDarkLadder: _ownerDarkLadder ?? undefined, spawnAdmission: _spawnAdmission ?? undefined, judgmentProvenance: _judgmentProvenance ?? undefined, leaseHandback: _leaseHandbackCtx ?? undefined, streamTicketStore: _streamTicketStore ?? undefined, poolStreamAllowRemoteInput: config.dashboard?.poolStream?.allowRemoteInput ?? false, poolStreamConnector: _poolStreamConnector ?? undefined, secretSync: _secretSyncHandle ?? undefined, meshSelfId: _meshSelfId ?? undefined, resolveRouterUrl: _resolveRouterUrl ?? undefined, resolvePeerUrls: _resolvePeerUrls ?? undefined, recordRopeResult: _recordRopeResult ?? undefined, guardRegistry, listPoolMachines: _listPoolMachines ?? undefined, deliverMandateToMachine: _deliverMandateToMachine ?? undefined, passkeyRevokeOutbox: _passkeyRevokeOutbox ? () => _passkeyRevokeOutbox : undefined, passkeyPeerOnline: _passkeyPeerOnline, passkeyPoolReader: _passkeyPoolReader ? () => _passkeyPoolReader : undefined, passkeyProofBrowser: async (profileDir) => { const { ChromeCdpReloginBrowser } = await import('../core/ChromeCdpReloginBrowser.js'); return new ChromeCdpReloginBrowser({ userDataDir: profileDir, passkeyMode: true, headless: true, launchTimeoutMs: 30_000, operationTimeoutMs: 20_000 }); }, poolLink: _poolLink ?? undefined, poolPollCache: _poolPollCache ?? undefined, sessionPoolE2EResultStore, proxyCoordinator, topicIntentStore, topicIntentArcCheck, usherSignalStore, intelligence: sharedIntelligence ?? undefined, telegramBridgeConfig, telegramBridge: telegramBridge ?? undefined, threadlineObservability, briefDeps, workingMemory, taskFlowRegistry, threadlineFlowBridge, sessionReaper, agentWorktreeReaper, externalHogSentinel, orphanedWorkSentinel, mcpProcessReaper, codexArmSessionSweeper, geminiLoopRunner, sleepController, agentActivityState, reapLog, resumeQueue, resumeDrainer, autonomousLivenessReconciler, enforcedTerminationStatus: () => enforcedTerminationWatchdog?.guardStatus() ?? null, prHandLease: prHandLease ?? undefined, standDownRegistry: _standDownRegistry ?? undefined, standDownAudit: _standDownAudit ?? undefined, operatorStopRecorder: recordOperatorStop, sleepWakeDetector, unjustifiedStopGate, stopGateDb, stopNotifier, liveTestGate, liveTestGateMode, liveTestRunnerCtx });
30148
+ if (_pendingCompactionEvidence)
30149
+ featureEvidence.record('multiMachine.coherenceJournal.replication.compaction', _pendingCompactionEvidence); // Resolve the late-bound topic-operator getter (increment 2e): routing was
29649
30150
  const readIdentityProjectionPeerRows = async () => {
29650
30151
  const peers = _resolvePeerUrls?.() ?? [];
29651
30152
  const extra = config.multiMachine?.peerUrlAllowlist;
@@ -29996,6 +30497,7 @@ export async function startServer(options) {
29996
30497
  subjectMachineId: proposed.machineId, epoch: proposed.recoveryEpoch ?? 0,
29997
30498
  contentHash: operatorGrantMod.recoveryRootDelegationHash(proposed), dryRun,
29998
30499
  });
30500
+ featureEvidence.record('multiMachine.recoveryKeyEscrow', { kind: 'fired', reason: dryRun ? 'would rotate the recovery root from a peer' : 'rotated the recovery root from a peer', context: { machineId: proposed.machineId, recoveryEpoch: proposed.recoveryEpoch ?? 0, dryRun } });
29999
30501
  if (dryRun)
30000
30502
  return 'would-rotate';
30001
30503
  identityStore.apply({
@@ -30590,10 +31092,14 @@ export async function startServer(options) {
30590
31092
  // port (force-closes lingering sockets, awaits 'close') BEFORE listen, so the
30591
31093
  // gap is sub-second and the supervisor never observes a hole. No-op if the
30592
31094
  // beacon was never started (dark) or already failed.
31095
+ // A failed bind happened before the evidence log was wired (at AgentServer construction), so it is kept and written here.
31096
+ if (bootBeaconBindErrorCode)
31097
+ featureEvidence.record('monitoring.bootHealthBeacon', { kind: 'error', reason: 'could not bind during boot', context: { code: bootBeaconBindErrorCode, port: config.port } });
30593
31098
  try {
30594
31099
  await bootBeacon?.stop();
30595
31100
  }
30596
31101
  catch (err) {
31102
+ featureEvidence.record('monitoring.bootHealthBeacon', { kind: 'error', reason: 'handoff failed: stop threw', context: { port: config.port, errorName: err instanceof Error ? err.name : 'unknown' } });
30597
31103
  // @silent-fallback-ok — a beacon stop failure must not stop the real server
30598
31104
  // from binding; logged, and the OS releases the listening socket regardless.
30599
31105
  console.error(' Boot health beacon stop failed (continuing to bind real server):', err instanceof Error ? err.message : err);
@@ -30604,6 +31110,16 @@ export async function startServer(options) {
30604
31110
  // no per-session write admission.
30605
31111
  sessionManager.startMonitoring();
30606
31112
  await server.start();
31113
+ // Boot recovery runs before the evidence log exists, so its verdict is recorded here.
31114
+ if (resolveDevAgentGate(config.multiMachine?.recoveryKeyEscrow?.enabled, config)) {
31115
+ const escrowDryRun = config.multiMachine?.recoveryKeyEscrow?.dryRun !== false;
31116
+ featureEvidence.record('multiMachine.recoveryKeyEscrow', {
31117
+ kind: bootRecoveryOutcome === 'disabled' || (_recoveryEscrowEvidence && !_recoveryEscrowEvidence.minted && _recoveryEscrowEvidence.hadRoot) ? 'error'
31118
+ : bootRecoveryOutcome === 'coherence-held' ? 'held' : 'fired',
31119
+ reason: bootRecoveryOutcome === 'disabled' ? 'boot recovery unavailable' : `boot recovery: ${bootRecoveryOutcome}`,
31120
+ context: { outcome: bootRecoveryOutcome, dryRun: escrowDryRun, minted: _recoveryEscrowEvidence?.minted ?? null, hadRoot: _recoveryEscrowEvidence?.hadRoot ?? null, recoveryEpoch: _recoveryEscrowEvidence?.recoveryEpoch ?? null },
31121
+ });
31122
+ }
30607
31123
  // After listen: a stop's condition usually turns met across a restart onto the
30608
31124
  // fixed version, and the wake brief sends a session straight to a route.
30609
31125
  agentStopSurfacer?.start();