instar 0.28.76 → 0.28.78
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dashboard/index.html +486 -0
- package/dist/cli.js +5 -8
- package/dist/cli.js.map +1 -1
- package/dist/commands/discovery.d.ts.map +1 -1
- package/dist/commands/discovery.js +2 -2
- package/dist/commands/discovery.js.map +1 -1
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +22 -4
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/job.d.ts.map +1 -1
- package/dist/commands/job.js +2 -2
- package/dist/commands/job.js.map +1 -1
- package/dist/commands/ledgerCleanup.d.ts.map +1 -1
- package/dist/commands/ledgerCleanup.js +2 -2
- package/dist/commands/ledgerCleanup.js.map +1 -1
- package/dist/commands/listener.d.ts.map +1 -1
- package/dist/commands/listener.js +7 -12
- package/dist/commands/listener.js.map +1 -1
- package/dist/commands/nuke.d.ts.map +1 -1
- package/dist/commands/nuke.js +11 -21
- package/dist/commands/nuke.js.map +1 -1
- package/dist/commands/server.d.ts.map +1 -1
- package/dist/commands/server.js +79 -5
- package/dist/commands/server.js.map +1 -1
- package/dist/commands/setup.d.ts.map +1 -1
- package/dist/commands/setup.js +11 -15
- package/dist/commands/setup.js.map +1 -1
- package/dist/commands/slack-cli.d.ts.map +1 -1
- package/dist/commands/slack-cli.js +5 -8
- package/dist/commands/slack-cli.js.map +1 -1
- package/dist/commands/whatsapp.d.ts.map +1 -1
- package/dist/commands/whatsapp.js +2 -2
- package/dist/commands/whatsapp.js.map +1 -1
- package/dist/commands/worktree.d.ts.map +1 -1
- package/dist/commands/worktree.js +2 -2
- package/dist/commands/worktree.js.map +1 -1
- package/dist/core/AgentConnector.d.ts.map +1 -1
- package/dist/core/AgentConnector.js +9 -10
- package/dist/core/AgentConnector.js.map +1 -1
- package/dist/core/AgentRegistry.d.ts.map +1 -1
- package/dist/core/AgentRegistry.js +3 -4
- package/dist/core/AgentRegistry.js.map +1 -1
- package/dist/core/AutoDispatcher.d.ts.map +1 -1
- package/dist/core/AutoDispatcher.js +2 -2
- package/dist/core/AutoDispatcher.js.map +1 -1
- package/dist/core/AutoUpdater.d.ts.map +1 -1
- package/dist/core/AutoUpdater.js +2 -2
- package/dist/core/AutoUpdater.js.map +1 -1
- package/dist/core/AutonomousEvolution.d.ts.map +1 -1
- package/dist/core/AutonomousEvolution.js +2 -2
- package/dist/core/AutonomousEvolution.js.map +1 -1
- package/dist/core/BackupManager.d.ts.map +1 -1
- package/dist/core/BackupManager.js +2 -2
- package/dist/core/BackupManager.js.map +1 -1
- package/dist/core/BranchManager.d.ts.map +1 -1
- package/dist/core/BranchManager.js +3 -3
- package/dist/core/BranchManager.js.map +1 -1
- package/dist/core/CaffeinateManager.d.ts.map +1 -1
- package/dist/core/CaffeinateManager.js +2 -2
- package/dist/core/CaffeinateManager.js.map +1 -1
- package/dist/core/DeferredDispatchTracker.d.ts.map +1 -1
- package/dist/core/DeferredDispatchTracker.js +2 -2
- package/dist/core/DeferredDispatchTracker.js.map +1 -1
- package/dist/core/DispatchManager.d.ts.map +1 -1
- package/dist/core/DispatchManager.js +3 -4
- package/dist/core/DispatchManager.js.map +1 -1
- package/dist/core/EvolutionManager.d.ts.map +1 -1
- package/dist/core/EvolutionManager.js +2 -2
- package/dist/core/EvolutionManager.js.map +1 -1
- package/dist/core/ExecutionJournal.d.ts.map +1 -1
- package/dist/core/ExecutionJournal.js +2 -2
- package/dist/core/ExecutionJournal.js.map +1 -1
- package/dist/core/FeedbackManager.d.ts.map +1 -1
- package/dist/core/FeedbackManager.js +2 -2
- package/dist/core/FeedbackManager.js.map +1 -1
- package/dist/core/FileClassifier.d.ts.map +1 -1
- package/dist/core/FileClassifier.js +8 -17
- package/dist/core/FileClassifier.js.map +1 -1
- package/dist/core/ForegroundRestartWatcher.d.ts.map +1 -1
- package/dist/core/ForegroundRestartWatcher.js +3 -4
- package/dist/core/ForegroundRestartWatcher.js.map +1 -1
- package/dist/core/GitStateManager.d.ts.map +1 -1
- package/dist/core/GitStateManager.js +3 -12
- package/dist/core/GitStateManager.js.map +1 -1
- package/dist/core/GitSync.d.ts.map +1 -1
- package/dist/core/GitSync.js +6 -6
- package/dist/core/GitSync.js.map +1 -1
- package/dist/core/GlobalInstallCleanup.d.ts.map +1 -1
- package/dist/core/GlobalInstallCleanup.js +3 -4
- package/dist/core/GlobalInstallCleanup.js.map +1 -1
- package/dist/core/GlobalSecretStore.d.ts.map +1 -1
- package/dist/core/GlobalSecretStore.js +3 -4
- package/dist/core/GlobalSecretStore.js.map +1 -1
- package/dist/core/HandoffManager.d.ts.map +1 -1
- package/dist/core/HandoffManager.js +5 -5
- package/dist/core/HandoffManager.js.map +1 -1
- package/dist/core/JargonDetector.d.ts +28 -0
- package/dist/core/JargonDetector.d.ts.map +1 -0
- package/dist/core/JargonDetector.js +59 -0
- package/dist/core/JargonDetector.js.map +1 -0
- package/dist/core/LedgerSessionRegistry.d.ts.map +1 -1
- package/dist/core/LedgerSessionRegistry.js +2 -2
- package/dist/core/LedgerSessionRegistry.js.map +1 -1
- package/dist/core/MachineIdentity.d.ts.map +1 -1
- package/dist/core/MachineIdentity.js +2 -2
- package/dist/core/MachineIdentity.js.map +1 -1
- package/dist/core/MessagingToneGate.d.ts +42 -5
- package/dist/core/MessagingToneGate.d.ts.map +1 -1
- package/dist/core/MessagingToneGate.js +40 -6
- package/dist/core/MessagingToneGate.js.map +1 -1
- package/dist/core/ParallelDevWiring.d.ts.map +1 -1
- package/dist/core/ParallelDevWiring.js +3 -6
- package/dist/core/ParallelDevWiring.js.map +1 -1
- package/dist/core/PostUpdateMigrator.d.ts +26 -0
- package/dist/core/PostUpdateMigrator.d.ts.map +1 -1
- package/dist/core/PostUpdateMigrator.js +249 -46
- package/dist/core/PostUpdateMigrator.js.map +1 -1
- package/dist/core/ProjectMapper.d.ts.map +1 -1
- package/dist/core/ProjectMapper.js +5 -11
- package/dist/core/ProjectMapper.js.map +1 -1
- package/dist/core/RelationshipManager.d.ts.map +1 -1
- package/dist/core/RelationshipManager.js +4 -5
- package/dist/core/RelationshipManager.js.map +1 -1
- package/dist/core/SafeGitExecutor.d.ts +11 -5
- package/dist/core/SafeGitExecutor.d.ts.map +1 -1
- package/dist/core/SafeGitExecutor.js +87 -1
- package/dist/core/SafeGitExecutor.js.map +1 -1
- package/dist/core/ScopeVerifier.d.ts.map +1 -1
- package/dist/core/ScopeVerifier.js +3 -6
- package/dist/core/ScopeVerifier.js.map +1 -1
- package/dist/core/SecretStore.d.ts.map +1 -1
- package/dist/core/SecretStore.js +2 -2
- package/dist/core/SecretStore.js.map +1 -1
- package/dist/core/SharedStateLedger.d.ts.map +1 -1
- package/dist/core/SharedStateLedger.js +2 -2
- package/dist/core/SharedStateLedger.js.map +1 -1
- package/dist/core/SoulManager.d.ts.map +1 -1
- package/dist/core/SoulManager.js +3 -4
- package/dist/core/SoulManager.js.map +1 -1
- package/dist/core/StateManager.d.ts.map +1 -1
- package/dist/core/StateManager.js +4 -6
- package/dist/core/StateManager.js.map +1 -1
- package/dist/core/SyncOrchestrator.d.ts.map +1 -1
- package/dist/core/SyncOrchestrator.js +6 -7
- package/dist/core/SyncOrchestrator.js.map +1 -1
- package/dist/core/UpdateChecker.d.ts.map +1 -1
- package/dist/core/UpdateChecker.js +3 -4
- package/dist/core/UpdateChecker.js.map +1 -1
- package/dist/core/UpgradeGuideProcessor.d.ts.map +1 -1
- package/dist/core/UpgradeGuideProcessor.js +3 -4
- package/dist/core/UpgradeGuideProcessor.js.map +1 -1
- package/dist/core/WorktreeManager.d.ts.map +1 -1
- package/dist/core/WorktreeManager.js +9 -14
- package/dist/core/WorktreeManager.js.map +1 -1
- package/dist/knowledge/KnowledgeManager.d.ts.map +1 -1
- package/dist/knowledge/KnowledgeManager.js +2 -2
- package/dist/knowledge/KnowledgeManager.js.map +1 -1
- package/dist/lifeline/ServerSupervisor.d.ts +28 -0
- package/dist/lifeline/ServerSupervisor.d.ts.map +1 -1
- package/dist/lifeline/ServerSupervisor.js +171 -73
- package/dist/lifeline/ServerSupervisor.js.map +1 -1
- package/dist/lifeline/TelegramLifeline.d.ts.map +1 -1
- package/dist/lifeline/TelegramLifeline.js +10 -4
- package/dist/lifeline/TelegramLifeline.js.map +1 -1
- package/dist/lifeline/detectLaunchdSupervised.d.ts +43 -0
- package/dist/lifeline/detectLaunchdSupervised.d.ts.map +1 -0
- package/dist/lifeline/detectLaunchdSupervised.js +106 -0
- package/dist/lifeline/detectLaunchdSupervised.js.map +1 -0
- package/dist/lifeline/droppedMessages.d.ts.map +1 -1
- package/dist/lifeline/droppedMessages.js +2 -2
- package/dist/lifeline/droppedMessages.js.map +1 -1
- package/dist/memory/EpisodicMemory.d.ts.map +1 -1
- package/dist/memory/EpisodicMemory.js +2 -2
- package/dist/memory/EpisodicMemory.js.map +1 -1
- package/dist/memory/TopicMemory.d.ts.map +1 -1
- package/dist/memory/TopicMemory.js +5 -8
- package/dist/memory/TopicMemory.js.map +1 -1
- package/dist/messaging/AgentTokenManager.d.ts.map +1 -1
- package/dist/messaging/AgentTokenManager.js +2 -2
- package/dist/messaging/AgentTokenManager.js.map +1 -1
- package/dist/messaging/DropPickup.d.ts.map +1 -1
- package/dist/messaging/DropPickup.js +2 -2
- package/dist/messaging/DropPickup.js.map +1 -1
- package/dist/messaging/GitSyncTransport.d.ts.map +1 -1
- package/dist/messaging/GitSyncTransport.js +4 -6
- package/dist/messaging/GitSyncTransport.js.map +1 -1
- package/dist/messaging/MessageStore.d.ts.map +1 -1
- package/dist/messaging/MessageStore.js +3 -4
- package/dist/messaging/MessageStore.js.map +1 -1
- package/dist/messaging/TelegramAdapter.d.ts.map +1 -1
- package/dist/messaging/TelegramAdapter.js +5 -8
- package/dist/messaging/TelegramAdapter.js.map +1 -1
- package/dist/messaging/backends/BaileysBackend.d.ts.map +1 -1
- package/dist/messaging/backends/BaileysBackend.js +3 -4
- package/dist/messaging/backends/BaileysBackend.js.map +1 -1
- package/dist/messaging/local-tone-check.d.ts +61 -0
- package/dist/messaging/local-tone-check.d.ts.map +1 -0
- package/dist/messaging/local-tone-check.js +78 -0
- package/dist/messaging/local-tone-check.js.map +1 -0
- package/dist/messaging/pending-relay-store.d.ts +153 -0
- package/dist/messaging/pending-relay-store.d.ts.map +1 -0
- package/dist/messaging/pending-relay-store.js +351 -0
- package/dist/messaging/pending-relay-store.js.map +1 -0
- package/dist/messaging/secret-patterns.d.ts +35 -0
- package/dist/messaging/secret-patterns.d.ts.map +1 -0
- package/dist/messaging/secret-patterns.js +70 -0
- package/dist/messaging/secret-patterns.js.map +1 -0
- package/dist/messaging/shared/EncryptedAuthStore.d.ts.map +1 -1
- package/dist/messaging/shared/EncryptedAuthStore.js +3 -4
- package/dist/messaging/shared/EncryptedAuthStore.js.map +1 -1
- package/dist/messaging/shared/MessageLogger.d.ts.map +1 -1
- package/dist/messaging/shared/MessageLogger.js +2 -2
- package/dist/messaging/shared/MessageLogger.js.map +1 -1
- package/dist/messaging/shared/PrivacyConsent.d.ts.map +1 -1
- package/dist/messaging/shared/PrivacyConsent.js +2 -2
- package/dist/messaging/shared/PrivacyConsent.js.map +1 -1
- package/dist/messaging/shared/SessionChannelRegistry.d.ts.map +1 -1
- package/dist/messaging/shared/SessionChannelRegistry.js +2 -2
- package/dist/messaging/shared/SessionChannelRegistry.js.map +1 -1
- package/dist/messaging/system-templates.d.ts +87 -0
- package/dist/messaging/system-templates.d.ts.map +1 -0
- package/dist/messaging/system-templates.js +236 -0
- package/dist/messaging/system-templates.js.map +1 -0
- package/dist/messaging/whoami-cache.d.ts +66 -0
- package/dist/messaging/whoami-cache.d.ts.map +1 -0
- package/dist/messaging/whoami-cache.js +149 -0
- package/dist/messaging/whoami-cache.js.map +1 -0
- package/dist/moltbridge/ProfileCompiler.d.ts.map +1 -1
- package/dist/moltbridge/ProfileCompiler.js +13 -7
- package/dist/moltbridge/ProfileCompiler.js.map +1 -1
- package/dist/monitoring/CommitmentTracker.d.ts.map +1 -1
- package/dist/monitoring/CommitmentTracker.js +2 -2
- package/dist/monitoring/CommitmentTracker.js.map +1 -1
- package/dist/monitoring/CredentialProvider.d.ts.map +1 -1
- package/dist/monitoring/CredentialProvider.js +2 -2
- package/dist/monitoring/CredentialProvider.js.map +1 -1
- package/dist/monitoring/DegradationReporter.d.ts +41 -0
- package/dist/monitoring/DegradationReporter.d.ts.map +1 -1
- package/dist/monitoring/DegradationReporter.js +96 -4
- package/dist/monitoring/DegradationReporter.js.map +1 -1
- package/dist/monitoring/HealthChecker.d.ts.map +1 -1
- package/dist/monitoring/HealthChecker.js +2 -2
- package/dist/monitoring/HealthChecker.js.map +1 -1
- package/dist/monitoring/HookEventReceiver.d.ts.map +1 -1
- package/dist/monitoring/HookEventReceiver.js +2 -2
- package/dist/monitoring/HookEventReceiver.js.map +1 -1
- package/dist/monitoring/InstructionsVerifier.d.ts.map +1 -1
- package/dist/monitoring/InstructionsVerifier.js +2 -2
- package/dist/monitoring/InstructionsVerifier.js.map +1 -1
- package/dist/monitoring/PresenceProxy.d.ts.map +1 -1
- package/dist/monitoring/PresenceProxy.js +5 -8
- package/dist/monitoring/PresenceProxy.js.map +1 -1
- package/dist/monitoring/QuotaTracker.d.ts.map +1 -1
- package/dist/monitoring/QuotaTracker.js +2 -2
- package/dist/monitoring/QuotaTracker.js.map +1 -1
- package/dist/monitoring/SessionMigrator.d.ts.map +1 -1
- package/dist/monitoring/SessionMigrator.js +2 -2
- package/dist/monitoring/SessionMigrator.js.map +1 -1
- package/dist/monitoring/SessionRecovery.d.ts.map +1 -1
- package/dist/monitoring/SessionRecovery.js +2 -2
- package/dist/monitoring/SessionRecovery.js.map +1 -1
- package/dist/monitoring/TelemetryAuth.d.ts.map +1 -1
- package/dist/monitoring/TelemetryAuth.js +3 -4
- package/dist/monitoring/TelemetryAuth.js.map +1 -1
- package/dist/monitoring/TokenLedger.d.ts +130 -0
- package/dist/monitoring/TokenLedger.d.ts.map +1 -0
- package/dist/monitoring/TokenLedger.js +523 -0
- package/dist/monitoring/TokenLedger.js.map +1 -0
- package/dist/monitoring/TokenLedgerPoller.d.ts +26 -0
- package/dist/monitoring/TokenLedgerPoller.d.ts.map +1 -0
- package/dist/monitoring/TokenLedgerPoller.js +44 -0
- package/dist/monitoring/TokenLedgerPoller.js.map +1 -0
- package/dist/monitoring/TriageOrchestrator.d.ts.map +1 -1
- package/dist/monitoring/TriageOrchestrator.js +3 -4
- package/dist/monitoring/TriageOrchestrator.js.map +1 -1
- package/dist/monitoring/WorktreeReaper.d.ts.map +1 -1
- package/dist/monitoring/WorktreeReaper.js +5 -7
- package/dist/monitoring/WorktreeReaper.js.map +1 -1
- package/dist/monitoring/delivery-failure-sentinel/recovery-policy.d.ts +83 -0
- package/dist/monitoring/delivery-failure-sentinel/recovery-policy.d.ts.map +1 -0
- package/dist/monitoring/delivery-failure-sentinel/recovery-policy.js +218 -0
- package/dist/monitoring/delivery-failure-sentinel/recovery-policy.js.map +1 -0
- package/dist/monitoring/delivery-failure-sentinel.d.ts +177 -0
- package/dist/monitoring/delivery-failure-sentinel.d.ts.map +1 -0
- package/dist/monitoring/delivery-failure-sentinel.js +598 -0
- package/dist/monitoring/delivery-failure-sentinel.js.map +1 -0
- package/dist/monitoring/probes/PlatformProbe.d.ts.map +1 -1
- package/dist/monitoring/probes/PlatformProbe.js +3 -4
- package/dist/monitoring/probes/PlatformProbe.js.map +1 -1
- package/dist/monitoring/templates-drift-verifier.d.ts +109 -0
- package/dist/monitoring/templates-drift-verifier.d.ts.map +1 -0
- package/dist/monitoring/templates-drift-verifier.js +324 -0
- package/dist/monitoring/templates-drift-verifier.js.map +1 -0
- package/dist/paste/PasteManager.d.ts.map +1 -1
- package/dist/paste/PasteManager.js +5 -8
- package/dist/paste/PasteManager.js.map +1 -1
- package/dist/publishing/PrivateViewer.d.ts.map +1 -1
- package/dist/publishing/PrivateViewer.js +2 -2
- package/dist/publishing/PrivateViewer.js.map +1 -1
- package/dist/scheduler/JobScheduler.d.ts.map +1 -1
- package/dist/scheduler/JobScheduler.js +2 -2
- package/dist/scheduler/JobScheduler.js.map +1 -1
- package/dist/server/AgentServer.d.ts +22 -0
- package/dist/server/AgentServer.d.ts.map +1 -1
- package/dist/server/AgentServer.js +199 -1
- package/dist/server/AgentServer.js.map +1 -1
- package/dist/server/WebSocketManager.d.ts +11 -0
- package/dist/server/WebSocketManager.d.ts.map +1 -1
- package/dist/server/WebSocketManager.js +28 -0
- package/dist/server/WebSocketManager.js.map +1 -1
- package/dist/server/boot-id.d.ts +58 -0
- package/dist/server/boot-id.d.ts.map +1 -0
- package/dist/server/boot-id.js +121 -0
- package/dist/server/boot-id.js.map +1 -0
- package/dist/server/middleware.d.ts +14 -1
- package/dist/server/middleware.d.ts.map +1 -1
- package/dist/server/middleware.js +81 -1
- package/dist/server/middleware.js.map +1 -1
- package/dist/server/routes.d.ts +76 -0
- package/dist/server/routes.d.ts.map +1 -1
- package/dist/server/routes.js +626 -11
- package/dist/server/routes.js.map +1 -1
- package/dist/threadline/AgentDiscovery.d.ts.map +1 -1
- package/dist/threadline/AgentDiscovery.js +2 -2
- package/dist/threadline/AgentDiscovery.js.map +1 -1
- package/dist/threadline/AgentTrustManager.d.ts.map +1 -1
- package/dist/threadline/AgentTrustManager.js +2 -2
- package/dist/threadline/AgentTrustManager.js.map +1 -1
- package/dist/threadline/BackfillCore.d.ts +70 -0
- package/dist/threadline/BackfillCore.d.ts.map +1 -0
- package/dist/threadline/BackfillCore.js +117 -0
- package/dist/threadline/BackfillCore.js.map +1 -0
- package/dist/threadline/CircuitBreaker.d.ts.map +1 -1
- package/dist/threadline/CircuitBreaker.js +2 -2
- package/dist/threadline/CircuitBreaker.js.map +1 -1
- package/dist/threadline/ComputeMeter.d.ts.map +1 -1
- package/dist/threadline/ComputeMeter.js +2 -2
- package/dist/threadline/ComputeMeter.js.map +1 -1
- package/dist/threadline/ContextThreadMap.d.ts.map +1 -1
- package/dist/threadline/ContextThreadMap.js +2 -2
- package/dist/threadline/ContextThreadMap.js.map +1 -1
- package/dist/threadline/HeartbeatWatchdog.d.ts +78 -0
- package/dist/threadline/HeartbeatWatchdog.d.ts.map +1 -0
- package/dist/threadline/HeartbeatWatchdog.js +212 -0
- package/dist/threadline/HeartbeatWatchdog.js.map +1 -0
- package/dist/threadline/HeartbeatWriter.d.ts +79 -0
- package/dist/threadline/HeartbeatWriter.d.ts.map +1 -0
- package/dist/threadline/HeartbeatWriter.js +109 -0
- package/dist/threadline/HeartbeatWriter.js.map +1 -0
- package/dist/threadline/InvitationManager.d.ts.map +1 -1
- package/dist/threadline/InvitationManager.js +2 -2
- package/dist/threadline/InvitationManager.js.map +1 -1
- package/dist/threadline/ListenerSessionManager.d.ts +59 -0
- package/dist/threadline/ListenerSessionManager.d.ts.map +1 -1
- package/dist/threadline/ListenerSessionManager.js +79 -0
- package/dist/threadline/ListenerSessionManager.js.map +1 -1
- package/dist/threadline/MCPAuth.d.ts.map +1 -1
- package/dist/threadline/MCPAuth.js +2 -2
- package/dist/threadline/MCPAuth.js.map +1 -1
- package/dist/threadline/PipeSessionSpawner.d.ts.map +1 -1
- package/dist/threadline/PipeSessionSpawner.js +3 -4
- package/dist/threadline/PipeSessionSpawner.js.map +1 -1
- package/dist/threadline/RateLimiter.d.ts.map +1 -1
- package/dist/threadline/RateLimiter.js +2 -2
- package/dist/threadline/RateLimiter.js.map +1 -1
- package/dist/threadline/RelaySpawnFailureHandler.d.ts +53 -0
- package/dist/threadline/RelaySpawnFailureHandler.d.ts.map +1 -0
- package/dist/threadline/RelaySpawnFailureHandler.js +73 -0
- package/dist/threadline/RelaySpawnFailureHandler.js.map +1 -0
- package/dist/threadline/SessionLifecycle.d.ts.map +1 -1
- package/dist/threadline/SessionLifecycle.js +2 -2
- package/dist/threadline/SessionLifecycle.js.map +1 -1
- package/dist/threadline/SpawnLedger.d.ts +94 -0
- package/dist/threadline/SpawnLedger.d.ts.map +1 -0
- package/dist/threadline/SpawnLedger.js +194 -0
- package/dist/threadline/SpawnLedger.js.map +1 -0
- package/dist/threadline/SpawnNonce.d.ts +49 -0
- package/dist/threadline/SpawnNonce.d.ts.map +1 -0
- package/dist/threadline/SpawnNonce.js +99 -0
- package/dist/threadline/SpawnNonce.js.map +1 -0
- package/dist/threadline/TelegramBridge.d.ts +140 -0
- package/dist/threadline/TelegramBridge.d.ts.map +1 -0
- package/dist/threadline/TelegramBridge.js +224 -0
- package/dist/threadline/TelegramBridge.js.map +1 -0
- package/dist/threadline/TelegramBridgeConfig.d.ts +79 -0
- package/dist/threadline/TelegramBridgeConfig.d.ts.map +1 -0
- package/dist/threadline/TelegramBridgeConfig.js +168 -0
- package/dist/threadline/TelegramBridgeConfig.js.map +1 -0
- package/dist/threadline/ThreadlineBootstrap.d.ts.map +1 -1
- package/dist/threadline/ThreadlineBootstrap.js +2 -2
- package/dist/threadline/ThreadlineBootstrap.js.map +1 -1
- package/dist/threadline/ThreadlineMCPServer.d.ts.map +1 -1
- package/dist/threadline/ThreadlineMCPServer.js +5 -0
- package/dist/threadline/ThreadlineMCPServer.js.map +1 -1
- package/dist/threadline/ThreadlineObservability.d.ts +95 -0
- package/dist/threadline/ThreadlineObservability.d.ts.map +1 -0
- package/dist/threadline/ThreadlineObservability.js +310 -0
- package/dist/threadline/ThreadlineObservability.js.map +1 -0
- package/dist/threadline/WakeSocketServer.d.ts.map +1 -1
- package/dist/threadline/WakeSocketServer.js +3 -4
- package/dist/threadline/WakeSocketServer.js.map +1 -1
- package/dist/threadline/listener-daemon.d.ts.map +1 -1
- package/dist/threadline/listener-daemon.js +3 -4
- package/dist/threadline/listener-daemon.js.map +1 -1
- package/dist/users/UserManager.d.ts.map +1 -1
- package/dist/users/UserManager.js +2 -2
- package/dist/users/UserManager.js.map +1 -1
- package/dist/users/UserOnboarding.d.ts.map +1 -1
- package/dist/users/UserOnboarding.js +2 -2
- package/dist/users/UserOnboarding.js.map +1 -1
- package/dist/utils/jsonl-rotation.d.ts.map +1 -1
- package/dist/utils/jsonl-rotation.js +2 -2
- package/dist/utils/jsonl-rotation.js.map +1 -1
- package/package.json +1 -1
- package/scripts/analyze-release.js +7 -12
- package/scripts/check-contract-evidence.js +27 -10
- package/scripts/fix-better-sqlite3.cjs +0 -2
- package/scripts/instar-dev-precommit.js +0 -2
- package/scripts/lint-no-direct-destructive.js +24 -4
- package/scripts/lint-template-sha-history.ts +183 -0
- package/scripts/migrate-incident-2026-04-17.mjs +2 -2
- package/scripts/run-migration.js +500 -0
- package/scripts/test-bootstrap-relay.mjs +2 -2
- package/scripts/threadline-bridge-backfill.mjs +379 -0
- package/scripts/verify-deployed-templates.ts +87 -0
- package/src/data/builtin-manifest.json +140 -132
- package/src/templates/scripts/git-sync-gate.sh +0 -4
- package/src/templates/scripts/telegram-reply.sh +318 -13
- package/upgrades/0.28.77.md +133 -0
- package/upgrades/0.28.78.md +90 -0
- package/upgrades/side-effects/agent-health-alert-authority-routing.md +121 -0
- package/upgrades/side-effects/comprehensive-destructive-tool-containment-migration.md +82 -0
- package/upgrades/side-effects/deferral-detector-orphan-todo.md +101 -0
- package/upgrades/side-effects/lifeline-self-heal-hardening.md +151 -0
- package/upgrades/side-effects/relay-spawn-ghost-reply-phase1.md +139 -0
- package/upgrades/side-effects/telegram-delivery-robustness-layer-2.md +320 -0
- package/upgrades/side-effects/telegram-delivery-robustness-layer-3.md +202 -0
- package/upgrades/side-effects/telegram-delivery-robustness-layer-7.md +339 -0
- package/upgrades/side-effects/telegram-delivery-robustness.md +178 -0
- package/upgrades/side-effects/threadline-bridge-backfill.md +203 -0
- package/upgrades/side-effects/threadline-canonical-inbox-write.md +218 -0
- package/upgrades/side-effects/threadline-observability-tab.md +206 -0
- package/upgrades/side-effects/threadline-tg-bridge-module.md +196 -0
- package/upgrades/side-effects/threadline-tg-bridge-settings-surface.md +208 -0
- package/upgrades/side-effects/token-ledger-bounded-scan.md +230 -0
- package/upgrades/side-effects/token-ledger-phase1.md +123 -0
- package/upgrades/NEXT.md +0 -53
- /package/upgrades/side-effects/{telegram-lifeline-version-missing-info.md → 0.28.76.md} +0 -0
|
@@ -0,0 +1,339 @@
|
|
|
1
|
+
# Side-Effects Review — telegram-delivery-robustness Layer 7 (Templates Drift Verifier)
|
|
2
|
+
|
|
3
|
+
**Version / slug:** `telegram-delivery-robustness-layer-7`
|
|
4
|
+
**Date:** `2026-04-27`
|
|
5
|
+
**Author:** `echo`
|
|
6
|
+
**Second-pass reviewer:** `not required (see Conclusion for justification)`
|
|
7
|
+
|
|
8
|
+
## Summary of the change
|
|
9
|
+
|
|
10
|
+
Ships Layer 7 of the `telegram-delivery-robustness` spec on top of the
|
|
11
|
+
already-merged Layer 1 (commit `f9b5e3bb`, PR #100), Layer 2 (commit
|
|
12
|
+
`5b953c17`, PR #101), and Layer 3 (commit `60c64f8e`, PR #103). Layer 7
|
|
13
|
+
is the **templates-drift verifier** — the final piece that closes the
|
|
14
|
+
"no orphan TODO" loop on the original incident's root cause: a deployed
|
|
15
|
+
relay script that drifts away from any known-shipped instar version
|
|
16
|
+
silently, with no operator-visible signal until the next failure
|
|
17
|
+
occurs.
|
|
18
|
+
|
|
19
|
+
The verifier scans deployed instar relay scripts across all agents on
|
|
20
|
+
the host, computes SHA-256 of each on-disk copy, and compares against a
|
|
21
|
+
canonical SHA history. Drifted templates fire a `template-drift-
|
|
22
|
+
detected` `DegradationReporter` event with persistent dedup so a
|
|
23
|
+
long-running drift produces ONE event, not 365. A companion CI lint
|
|
24
|
+
asserts that every historical shipped `telegram-reply.sh` SHA on `main`
|
|
25
|
+
is in the migrator's `TELEGRAM_REPLY_PRIOR_SHIPPED_SHAS` set — closing
|
|
26
|
+
the failure mode where future template upgrades silently strand prior
|
|
27
|
+
deployed agents in the user-modified `.new` candidate path.
|
|
28
|
+
|
|
29
|
+
Files added:
|
|
30
|
+
|
|
31
|
+
- `src/monitoring/templates-drift-verifier.ts` — the verifier core,
|
|
32
|
+
exporting `runVerifier(opts)` (≈260 LoC).
|
|
33
|
+
- `scripts/verify-deployed-templates.ts` — thin CLI wrapper invoked by
|
|
34
|
+
the daily job; reads the kill switch from `.instar/config.json`.
|
|
35
|
+
- `scripts/lint-template-sha-history.ts` — CI lint with a public
|
|
36
|
+
`lintTemplateShaHistory()` export so the unit test can drive it
|
|
37
|
+
without forking a process.
|
|
38
|
+
- `tests/unit/verify-deployed-templates.test.ts` — 7 cases covering
|
|
39
|
+
current/prior/novel SHA fixtures, dedup behavior, kill switch,
|
|
40
|
+
per-agent partial-install, default-discovery, and canonical
|
|
41
|
+
registration.
|
|
42
|
+
- `tests/unit/lint-template-sha-history.test.ts` — 2 cases covering the
|
|
43
|
+
positive lint pass and the regression-on-removal case.
|
|
44
|
+
|
|
45
|
+
Files modified:
|
|
46
|
+
|
|
47
|
+
- `src/core/PostUpdateMigrator.ts` — extends
|
|
48
|
+
`TELEGRAM_REPLY_PRIOR_SHIPPED_SHAS` to include all six historical
|
|
49
|
+
shipped SHAs reachable via `git log --first-parent main` on `src/
|
|
50
|
+
templates/scripts/telegram-reply.sh` (Tier-1 init through Layer 2).
|
|
51
|
+
Visibility flipped from `private static` to `public static readonly`
|
|
52
|
+
so the verifier can reference the same set without duplicating it.
|
|
53
|
+
- `src/commands/init.ts` — registers a new built-in job
|
|
54
|
+
`templates-drift-verifier` (daily at 02:00 local, `haiku` model,
|
|
55
|
+
script-type, low priority). The job's pre-flight gate honors the
|
|
56
|
+
same `config.monitoring.templatesDriftVerifier.enabled` flag the
|
|
57
|
+
verifier itself checks. `refreshJobs()` propagates the new entry
|
|
58
|
+
to existing agents on next `instar update`.
|
|
59
|
+
- `src/data/builtin-manifest.json` — regenerated (entry count 186 → 187).
|
|
60
|
+
|
|
61
|
+
## Decision-point inventory
|
|
62
|
+
|
|
63
|
+
- `runVerifier` (templates-drift-verifier) — **add** — pure read-only
|
|
64
|
+
scan over `.claude/scripts/`, `.instar/scripts/`, and `<root>/scripts/`
|
|
65
|
+
per agent root, compares on-disk SHA against canonical + prior-shipped
|
|
66
|
+
set, emits `template-drift-detected` events deduped via a persistent
|
|
67
|
+
jsonl seen-log.
|
|
68
|
+
- `TELEGRAM_REPLY_PRIOR_SHIPPED_SHAS` (PostUpdateMigrator) — **modify** —
|
|
69
|
+
visibility flipped (private → public static readonly) and the set
|
|
70
|
+
extended to cover six older historical shipped SHAs the prior set was
|
|
71
|
+
missing. No semantic change to migrator behavior; the set was already
|
|
72
|
+
the source of truth, only its membership widened.
|
|
73
|
+
- `getDefaultJobs.templates-drift-verifier` (init.ts) — **add** — daily
|
|
74
|
+
built-in job; new agents get it on first init, existing agents get it
|
|
75
|
+
on next update via `refreshJobs()`.
|
|
76
|
+
- `lintTemplateShaHistory` (CI lint) — **add** — dev-time-only assertion
|
|
77
|
+
that every historical SHA reachable via `git log --first-parent main`
|
|
78
|
+
is in the prior-shipped set OR matches the current bundled template.
|
|
79
|
+
|
|
80
|
+
---
|
|
81
|
+
|
|
82
|
+
## 1. Over-block
|
|
83
|
+
|
|
84
|
+
**What legitimate inputs does this change reject that it shouldn't?**
|
|
85
|
+
|
|
86
|
+
The verifier has no block/allow surface — it never modifies on-disk
|
|
87
|
+
content and never refuses any operation. The only "rejection" surface
|
|
88
|
+
is the CI lint, which would block a commit that ships a new template
|
|
89
|
+
SHA without adding the just-superseded SHA to the prior-shipped set.
|
|
90
|
+
This is the correct shape: it forces the developer who's bumping the
|
|
91
|
+
template to update the migration trail in the same PR, which is the
|
|
92
|
+
exact orphan-TODO failure mode this layer exists to prevent.
|
|
93
|
+
|
|
94
|
+
The lint does NOT block on novel commits to unrelated files; it only
|
|
95
|
+
walks `git log -- src/templates/scripts/telegram-reply.sh` and asserts
|
|
96
|
+
SHA coverage on commits that touched that one file.
|
|
97
|
+
|
|
98
|
+
**Conclusion: no over-block.**
|
|
99
|
+
|
|
100
|
+
---
|
|
101
|
+
|
|
102
|
+
## 2. Under-block
|
|
103
|
+
|
|
104
|
+
**What failure modes does this still miss?**
|
|
105
|
+
|
|
106
|
+
- **Other relay templates (slack, whatsapp, imessage).** The verifier
|
|
107
|
+
scans them and emits drift events for any deployed copy that doesn't
|
|
108
|
+
match the bundled source, but they have no prior-shipped SHA tracking
|
|
109
|
+
yet. A user-modified slack-reply.sh that was shipped two versions ago
|
|
110
|
+
would fire a drift event today; that's by design (the operator should
|
|
111
|
+
know), but it's noisier than the telegram-reply.sh path. Mitigation:
|
|
112
|
+
the kill switch silences the entire verifier; per-template kill
|
|
113
|
+
switches were intentionally not added (one switch is the minimum
|
|
114
|
+
surface area).
|
|
115
|
+
- **Templates installed at non-standard paths.** The verifier checks
|
|
116
|
+
three known deployment locations per agent root: `.claude/scripts/`,
|
|
117
|
+
`.instar/scripts/`, and (when the root itself is `.instar/`) the
|
|
118
|
+
immediate `scripts/`. An operator who installed a relay script at,
|
|
119
|
+
e.g., `~/bin/telegram-reply.sh` will not be scanned. This matches
|
|
120
|
+
the deploy paths the migrator writes to, so the only miss is custom
|
|
121
|
+
installs the migrator already doesn't manage.
|
|
122
|
+
- **Project-wide deployments under `~/Documents/Projects/*/.instar/`.**
|
|
123
|
+
Per-project install paths are NOT scanned by default; the verifier
|
|
124
|
+
enumerates `~/.instar/agents/*` only. Per-project agents will get a
|
|
125
|
+
drift event the next time the operator runs `instar update` (the
|
|
126
|
+
migrator runs the same SHA check inline). The trade-off: scanning
|
|
127
|
+
every project under `~/Documents/Projects/` would slow the daily job
|
|
128
|
+
to a crawl on hosts with thousands of unrelated projects, and would
|
|
129
|
+
also cross trust boundaries (those projects may be other users'
|
|
130
|
+
agents; we shouldn't be reading their relay scripts uninvited).
|
|
131
|
+
- **The CI lint can't catch SHA removal in CI.** A future PR that
|
|
132
|
+
deletes a SHA from `TELEGRAM_REPLY_PRIOR_SHIPPED_SHAS` will be caught
|
|
133
|
+
if at least one historical commit's SHA matches the deleted entry —
|
|
134
|
+
which is true today for every entry. If a developer deletes a SHA
|
|
135
|
+
AND also rebases history to remove the commit that produced it, the
|
|
136
|
+
lint won't catch it. This is acceptable because the rebase requires
|
|
137
|
+
force-pushing main, which is itself blocked by a separate gate.
|
|
138
|
+
|
|
139
|
+
---
|
|
140
|
+
|
|
141
|
+
## 3. Level-of-abstraction fit
|
|
142
|
+
|
|
143
|
+
**Is this at the right layer?**
|
|
144
|
+
|
|
145
|
+
The verifier is a **detector**, not an authority. It reads the
|
|
146
|
+
filesystem, computes hashes, and emits structured signals into the
|
|
147
|
+
existing `DegradationReporter` channel. It owns no block/allow
|
|
148
|
+
authority; the migrator (`PostUpdateMigrator.migrateReplyScriptToPort
|
|
149
|
+
Config`) is the only piece of code that mutates a deployed relay
|
|
150
|
+
script, and that code path is already gated on SHA membership in the
|
|
151
|
+
prior-shipped set.
|
|
152
|
+
|
|
153
|
+
The split keeps detection (cheap, daily, host-wide) separate from
|
|
154
|
+
mutation (per-`instar update`, per-agent, gated). The CI lint is at
|
|
155
|
+
the right layer too — it asserts an invariant about the prior-shipped
|
|
156
|
+
set's coverage of git history, which is a developer-time concern, not
|
|
157
|
+
a runtime concern.
|
|
158
|
+
|
|
159
|
+
A previous version of this design considered making the verifier
|
|
160
|
+
auto-write a `.new` candidate alongside drifted scripts. That was
|
|
161
|
+
rejected: the migrator already does that on `instar update`, and
|
|
162
|
+
having two code paths that mutate deployed scripts (with different
|
|
163
|
+
trigger frequencies) would race during update. The current design has
|
|
164
|
+
exactly one mutator (the migrator) and one detector (the verifier),
|
|
165
|
+
with no overlap.
|
|
166
|
+
|
|
167
|
+
---
|
|
168
|
+
|
|
169
|
+
## 4. Signal vs authority compliance
|
|
170
|
+
|
|
171
|
+
**Required reference:** [docs/signal-vs-authority.md](../../docs/signal-vs-authority.md)
|
|
172
|
+
|
|
173
|
+
**Does this change hold blocking authority with brittle logic?**
|
|
174
|
+
|
|
175
|
+
- [x] **No** — this change produces a signal consumed by an existing
|
|
176
|
+
smart gate. The verifier emits `DegradationReporter.report({...})`
|
|
177
|
+
events, which feed the existing operator-visible degradation channel
|
|
178
|
+
(Telegram alerts via the `degradation-digest` job, dashboard panel,
|
|
179
|
+
health endpoint). The verifier itself never blocks anything; it's a
|
|
180
|
+
detector that lights up a downstream signal lane.
|
|
181
|
+
|
|
182
|
+
The CI lint does hold blocking authority over commits, but its logic
|
|
183
|
+
is **deterministic and finite**: walk N commits, compute hashes,
|
|
184
|
+
compare against a fixed allowed-set. There is no judgment, no
|
|
185
|
+
synonym-matching, no LLM. The signal-vs-authority doc reserves
|
|
186
|
+
"brittle" for string/regex matching on free-form content; SHA-256
|
|
187
|
+
comparison on git-tracked file contents is structurally precise and
|
|
188
|
+
collision-resistant. The lint is the correct shape for this gate.
|
|
189
|
+
|
|
190
|
+
---
|
|
191
|
+
|
|
192
|
+
## 5. Interactions
|
|
193
|
+
|
|
194
|
+
**Does this interact with existing checks, recovery paths, or infrastructure?**
|
|
195
|
+
|
|
196
|
+
- **Shadowing:** the verifier runs daily; the migrator runs on
|
|
197
|
+
`instar update`. They both read the same `TELEGRAM_REPLY_PRIOR_
|
|
198
|
+
SHIPPED_SHAS` set. The verifier never writes; the migrator writes
|
|
199
|
+
only on `instar update`. Order doesn't matter — neither shadows the
|
|
200
|
+
other. If a drift event fires today and the operator runs `instar
|
|
201
|
+
update` tomorrow, the migrator will write a `.new` candidate and emit
|
|
202
|
+
a `relay-script-modified-locally` event (which is a different event
|
|
203
|
+
feature than `template-drift-detected`); the operator gets two
|
|
204
|
+
related signals on the same drift, which is the desired behavior
|
|
205
|
+
(one says "I noticed", one says "I wrote a candidate fix").
|
|
206
|
+
- **Double-fire:** the verifier dedups via the persistent
|
|
207
|
+
`.instar/state/drift-verifier-seen.jsonl` log, keyed on
|
|
208
|
+
`(deployed-path, current-SHA)`. The dedup persists across runs, so
|
|
209
|
+
the daily job emits AT MOST one event per drift. If the operator
|
|
210
|
+
edits the script (creating a new SHA on the same path), the verifier
|
|
211
|
+
emits one fresh event for the new SHA — which is the correct
|
|
212
|
+
behavior because the operator's intent may have changed.
|
|
213
|
+
- **Races:** the seen-log is append-only (`fs.appendFileSync`); the
|
|
214
|
+
verifier runs in a single process. Two concurrent verifiers (e.g.,
|
|
215
|
+
manual run while daily job is firing) would both append a duplicate
|
|
216
|
+
entry; readers tolerate duplicates because the seen-set is built
|
|
217
|
+
from a `Set<string>` of `path::sha` keys. No corruption risk.
|
|
218
|
+
- **Feedback loops:** the verifier emits `template-drift-detected`
|
|
219
|
+
events; the existing `degradation-digest` job reads them and may
|
|
220
|
+
send a Telegram alert. If the alert send itself relied on a drifted
|
|
221
|
+
`telegram-reply.sh`, the alert would fail — and the failure would
|
|
222
|
+
enqueue via the Layer 2 SQLite queue and retry via the Layer 3
|
|
223
|
+
sentinel. So the worst case is: drift detected → alert queued →
|
|
224
|
+
alert recovered after the operator fixes the relay script. No
|
|
225
|
+
infinite loop.
|
|
226
|
+
|
|
227
|
+
---
|
|
228
|
+
|
|
229
|
+
## 6. External surfaces
|
|
230
|
+
|
|
231
|
+
**Does this change anything visible outside the immediate code path?**
|
|
232
|
+
|
|
233
|
+
- **Wire format:** none. No new HTTP endpoints, no new headers, no new
|
|
234
|
+
message shapes.
|
|
235
|
+
- **Telegram users:** the new `template-drift-detected` event flows
|
|
236
|
+
through the existing degradation pipeline; users on hosts with
|
|
237
|
+
drifted scripts will see one Telegram alert per novel drift via
|
|
238
|
+
the `degradation-digest` job. The alert is a fixed-template
|
|
239
|
+
narrative composed by `DegradationReporter.narrativeFor` (no
|
|
240
|
+
template excerpting, no agent text).
|
|
241
|
+
- **Persistent state:** new file at
|
|
242
|
+
`~/.instar/state/drift-verifier-seen.jsonl` (append-only, mode
|
|
243
|
+
0644). Capped implicitly by the finite set of `(path, sha)` pairs
|
|
244
|
+
any host can have; in practice <100 entries even after years of
|
|
245
|
+
agent churn. No retention policy is needed beyond what
|
|
246
|
+
`BackupManager`'s default exclusion already covers (state files
|
|
247
|
+
under `.instar/state/` are not backed up).
|
|
248
|
+
- **Other agents on the same machine:** the verifier reads files
|
|
249
|
+
under `~/.instar/agents/*/` — directories owned by the same
|
|
250
|
+
user account that runs the daily job. No cross-user surface.
|
|
251
|
+
- **CI surface:** the new lint adds ≈3s to a pre-push run via
|
|
252
|
+
`npx tsx scripts/lint-template-sha-history.ts`. It is NOT yet wired
|
|
253
|
+
into `pnpm test:push` — adding it as a test under `tests/unit/`
|
|
254
|
+
was the chosen integration path, which means `pnpm test` covers it.
|
|
255
|
+
Wiring a separate `lint:templates` script can come in a follow-up if
|
|
256
|
+
the test path proves insufficient (it shouldn't).
|
|
257
|
+
- **Default-on flag:** the verifier ships default-on per spec. Operators
|
|
258
|
+
with intentionally customized scripts will see ONE event after
|
|
259
|
+
upgrade and can flip the flag off. This is the spec-mandated
|
|
260
|
+
behavior; we have the rollback path documented in §7.
|
|
261
|
+
|
|
262
|
+
---
|
|
263
|
+
|
|
264
|
+
## 7. Rollback cost
|
|
265
|
+
|
|
266
|
+
**If this turns out wrong in production, what's the back-out?**
|
|
267
|
+
|
|
268
|
+
- **Hot-fix release:** revert the source. The seen-log file becomes
|
|
269
|
+
inert (no readers). Existing daily-job entries in `jobs.json` will
|
|
270
|
+
fail-soft because the verifier script is gone — the gate-then-execute
|
|
271
|
+
shape exits silently when the source isn't found. Operators who
|
|
272
|
+
hand-deleted the daily job entry are unaffected.
|
|
273
|
+
- **Feature flag toggle:** the cleanest rollback is
|
|
274
|
+
`monitoring.templatesDriftVerifier.enabled = false` in the host
|
|
275
|
+
config. No data migration, no user-visible regression. The spec
|
|
276
|
+
documents this as the operator-facing customization path; reverts
|
|
277
|
+
inherit it.
|
|
278
|
+
- **Persistent state:** the seen-log is at
|
|
279
|
+
`~/.instar/state/drift-verifier-seen.jsonl`. A rollback that wipes
|
|
280
|
+
this file leaves the host in a clean state (the next verifier run
|
|
281
|
+
re-emits one event per drift). The file is gitignored (state files
|
|
282
|
+
always are) so there's no cross-machine replay surface.
|
|
283
|
+
- **User visibility during rollback:** an agent with one queued
|
|
284
|
+
`template-drift-detected` event in transit will deliver it before
|
|
285
|
+
the verifier source is gone. A rollback before the next daily run
|
|
286
|
+
produces zero further alerts. The migrator's existing
|
|
287
|
+
`relay-script-modified-locally` event continues to fire on `instar
|
|
288
|
+
update`, so operators retain a signal lane.
|
|
289
|
+
- **CI lint rollback:** delete the test file. The lint becomes an
|
|
290
|
+
orphan script that no longer gates commits. No persistent state.
|
|
291
|
+
|
|
292
|
+
---
|
|
293
|
+
|
|
294
|
+
## Conclusion
|
|
295
|
+
|
|
296
|
+
Layer 7 closes the orphan-TODO failure mode that the spec's §7 calls
|
|
297
|
+
out as "the wrong shape for the root cause of this incident." The
|
|
298
|
+
verifier is a read-only detector; the lint is a deterministic
|
|
299
|
+
SHA-history check. Neither holds content authority; both feed
|
|
300
|
+
existing channels (DegradationReporter for the verifier, the
|
|
301
|
+
pre-commit gate for the lint).
|
|
302
|
+
|
|
303
|
+
One small design refinement during implementation: I considered
|
|
304
|
+
having the lint walk the entire git history (`git log` with no `-n`
|
|
305
|
+
limit) and decided against it. A 100-commit window covers every
|
|
306
|
+
historical change to telegram-reply.sh by orders of magnitude (the
|
|
307
|
+
file has 9 historical SHAs total, all within recent history). The
|
|
308
|
+
limit prevents pathological repository walks if the history grows
|
|
309
|
+
large for unrelated reasons.
|
|
310
|
+
|
|
311
|
+
**Second-pass review: not required.** Layer 7 is a meta-infrastructure
|
|
312
|
+
change with no auth surface, no message-content surface, no recovery
|
|
313
|
+
path mutation, and no agent-visible runtime behavior beyond a
|
|
314
|
+
DegradationReporter event. Compared to Layer 3 (which introduced an
|
|
315
|
+
auth-bearing recovery sentinel and earned a second-pass review), this
|
|
316
|
+
layer is structurally simple: 260 LoC of pure detector logic, a 90 LoC
|
|
317
|
+
CLI wrapper, a 130 LoC CI lint. The risk surface is silent failure of
|
|
318
|
+
the verifier (acceptable — the originating incident class is already
|
|
319
|
+
closed by Layers 1-3), not unwanted action. The spec convergence
|
|
320
|
+
process already covered the design at internal + external review
|
|
321
|
+
levels. Ship.
|
|
322
|
+
|
|
323
|
+
---
|
|
324
|
+
|
|
325
|
+
## Evidence pointers
|
|
326
|
+
|
|
327
|
+
- Unit tests: `tests/unit/verify-deployed-templates.test.ts` (7 cases),
|
|
328
|
+
`tests/unit/lint-template-sha-history.test.ts` (2 cases). All pass.
|
|
329
|
+
- Lint executable proof: `npx tsx scripts/lint-template-sha-history.ts`
|
|
330
|
+
exits 0 with `"OK (scanned 8 commits, current sha256:371d7e8f4f72…)"`.
|
|
331
|
+
- Verifier executable proof: `HOME=/tmp/empty-home npx tsx scripts/
|
|
332
|
+
verify-deployed-templates.ts` exits 0 with
|
|
333
|
+
`{"verifier":"templates-drift","scanned":0,"drifted":0,
|
|
334
|
+
"suppressed":0,"errors":[]}`.
|
|
335
|
+
- Manifest regeneration: `pnpm generate:manifest` increments entry
|
|
336
|
+
count 186 → 187 with the new `job:templates-drift-verifier` entry.
|
|
337
|
+
- Spec: `docs/specs/telegram-delivery-robustness.md` § 7.
|
|
338
|
+
- Predecessor PRs: #100 (Layer 1, `f9b5e3bb`), #101 (Layer 2,
|
|
339
|
+
`5b953c17`), #103 (Layer 3, `60c64f8e`).
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
Side-Effects Review Artifact — Telegram Delivery Robustness, Layer 1.
|
|
3
|
+
Layer 2 (durable queue) and Layer 3 (DeliveryFailureSentinel) and Layer 7
|
|
4
|
+
(templates-drift verifier) will ship in subsequent commits on this same
|
|
5
|
+
branch (chained PRs per Echo memory feedback_no_pr_fragmentation), each
|
|
6
|
+
with its own side-effects artifact.
|
|
7
|
+
-->
|
|
8
|
+
|
|
9
|
+
# Side-Effects Review — Telegram Delivery Robustness (Layer 1)
|
|
10
|
+
|
|
11
|
+
**Version / slug:** `telegram-delivery-robustness-layer-1`
|
|
12
|
+
**Date:** `2026-04-27`
|
|
13
|
+
**Author:** `echo`
|
|
14
|
+
**Second-pass reviewer:** `(pending — see §"Second-pass review")`
|
|
15
|
+
|
|
16
|
+
## Summary of the change
|
|
17
|
+
|
|
18
|
+
Layer 1 of the approved & review-converged spec at `docs/specs/telegram-delivery-robustness.md`. Three coordinated changes that, together, structurally close the originating incident class (Inspec/cheryl topic 50 on 2026-04-27, where a relay script defaulted to port 4040 and hit a different agent's server with the wrong agent's auth token):
|
|
19
|
+
|
|
20
|
+
1. **`src/templates/scripts/telegram-reply.sh`** — port resolution order is now `INSTAR_PORT` env > `.instar/config.json` `port` field > 4040 fallback (with stderr warning). Every request also sends `X-Instar-AgentId` from config.json. ~50 lines of additions to the existing 134-line script.
|
|
21
|
+
|
|
22
|
+
2. **`src/server/middleware.ts` (auth path)** — auth middleware validates `X-Instar-AgentId` header against the server's own `agentId` *before* token comparison. Mismatch → `403 { error: "agent_id_mismatch", expected: <agent-id> }`. Missing header → token-only path with a per-source dedup'd ≤1/hr deprecation log entry (one-minor-version backward compat). Threadline-relayed paths exempt from deprecation logging.
|
|
23
|
+
|
|
24
|
+
3. **`src/server/routes.ts`** — new authed `GET /whoami` route requiring both Bearer and `X-Instar-AgentId` headers (no deprecation exception, since `/whoami` paired with bare-token fallback would be a discovery oracle for token-port pairing). Rate-limited to 1 req/s per source agent-id. Returns `{ agentId, port, version }`.
|
|
25
|
+
|
|
26
|
+
4. **`src/core/PostUpdateMigrator.ts`** — new `migrateReplyScriptToPortConfig` step using SHA-256-of-prior-shipped-content detection (replacing marker-string detection for the `telegram-reply.sh` migration). Prior shipped content is backed up to `.instar/backups/telegram-reply.sh.<epoch>` before overwrite. User-modified content (unknown SHA) gets a `.new` candidate file alongside, plus a `relay-script-modified-locally` degradation event — never overwritten in place.
|
|
27
|
+
|
|
28
|
+
5. **`src/data/builtin-manifest.json`** — auto-regenerated. The 99 hash changes are the expected propagation of `PostUpdateMigrator.ts` changes through the manifest's hook-source-hashing scheme (each hook entry hashes against the migrator file, so the migrator change rebases all 14 hook contentHashes plus other migrator-derived entries).
|
|
29
|
+
|
|
30
|
+
Files touched (commit diff):
|
|
31
|
+
- `src/templates/scripts/telegram-reply.sh` (+47 / -10 lines)
|
|
32
|
+
- `src/server/middleware.ts` (+85 / -1 lines, ~85 net new for agent-id validation + deprecation log dedup)
|
|
33
|
+
- `src/server/routes.ts` (+98 / -0 lines for `/whoami` endpoint + helpers)
|
|
34
|
+
- `src/server/AgentServer.ts` (+6 / -1 lines wiring `/whoami` rate-limit cleanup into shutdown path)
|
|
35
|
+
- `src/core/PostUpdateMigrator.ts` (+155 / -25 lines)
|
|
36
|
+
- `src/data/builtin-manifest.json` (regenerated)
|
|
37
|
+
- `tests/unit/telegram-reply-port-resolution.test.ts` (NEW, 5 tests)
|
|
38
|
+
- `tests/unit/auth-agent-id-binding.test.ts` (NEW, 7 tests)
|
|
39
|
+
- `tests/unit/whoami-route.test.ts` (NEW, 5 tests)
|
|
40
|
+
- `tests/unit/migration-relay-script-hash.test.ts` (NEW, 5 tests)
|
|
41
|
+
- `tests/unit/PostUpdateMigrator-telegramReply.test.ts` (existing test updated for SHA-based detection; added a new test for the `.new` candidate path)
|
|
42
|
+
- `tests/fixtures/telegram-reply-pre-port-config.sh` (NEW, the SHA-pinned prior shipped content used by the migrator test fixture)
|
|
43
|
+
- `docs/specs/telegram-delivery-robustness.md` (NEW, the converged spec)
|
|
44
|
+
- `docs/specs/reports/telegram-delivery-robustness-convergence.md` (NEW, the convergence report)
|
|
45
|
+
|
|
46
|
+
## Decision-point inventory
|
|
47
|
+
|
|
48
|
+
- **Auth gate (server middleware)** — modify. Adds `X-Instar-AgentId` validation BEFORE token comparison. Token comparison itself is unchanged (constant-time, untouched). Missing-agent-id path is a temporary deprecation tolerance, not a permanent decision surface.
|
|
49
|
+
- **Port resolution (script)** — add. Pure mechanical resolution; not a judgment call.
|
|
50
|
+
- **`/whoami` endpoint** — add. Read-only identity probe; required for Layer 3 sentinel to verify-before-send. No content authority.
|
|
51
|
+
- **Migration (PostUpdateMigrator)** — modify. Detection method changed from marker-string to SHA-set. Decision: "this on-disk script is a shipped prior version" is now a clean equality check on a curated set, replacing a heuristic (presence of a header line) that overwrote user customizations.
|
|
52
|
+
|
|
53
|
+
---
|
|
54
|
+
|
|
55
|
+
## 1. Over-block
|
|
56
|
+
|
|
57
|
+
**What legitimate inputs does this change reject that it shouldn't?**
|
|
58
|
+
|
|
59
|
+
- **Backward compat case (intentional, deprecation-window):** a script that legitimately can't add the `X-Instar-AgentId` header (third-party clients, legacy automation). Rejected at end of one-minor-version deprecation. During the window, accepted with a deduped log entry.
|
|
60
|
+
- **Migration `.new` case:** a user who intentionally customized `telegram-reply.sh` will see a `.new` candidate file and a degradation event but their script keeps running. They are *not* over-blocked — the original script keeps working; they get notified and can opt in. The risk is that they don't notice and miss the agent-id binding fix. Mitigated by surfacing through `DegradationReporter` (the existing user-facing degradation path).
|
|
61
|
+
- **`/whoami` rate limit (1 req/s per source):** a legitimate sentinel hammering `/whoami` faster than 1/s on stampede recovery. Acceptable: the spec design caches the result for 60s, so 1/s is one to two orders of magnitude above the expected request rate. Not over-blocking.
|
|
62
|
+
|
|
63
|
+
## 2. Under-block
|
|
64
|
+
|
|
65
|
+
**What failure modes does this still miss?**
|
|
66
|
+
|
|
67
|
+
- **Cross-tenant token leak via the `/events/delivery-failed` endpoint.** That endpoint is Layer 2; it doesn't exist yet. Until Layer 2 ships, the script still exits 1 on transport failures and the agent learns of failure but cannot persist it for sentinel recovery.
|
|
68
|
+
- **Stuck delivery without sentinel recovery.** Layer 3 (the DeliveryFailureSentinel) doesn't exist yet. Layer 1 alone closes the *cross-tenant token leak* class but not the *eventually deliver* class.
|
|
69
|
+
- **A buggy 3rd-party client that constructs `X-Instar-AgentId` from the wrong source** (e.g., reads the wrong agent's config). Layer 1 binds at the server side: a bogus header from such a client is rejected by the matching check on the receiving server. Not under-blocked.
|
|
70
|
+
|
|
71
|
+
## 3. Level-of-abstraction fit
|
|
72
|
+
|
|
73
|
+
**Is this at the right layer?**
|
|
74
|
+
|
|
75
|
+
Yes. Each piece is at the layer that has the right context:
|
|
76
|
+
|
|
77
|
+
- Port-from-config in the script is the right layer because the script is the entity that resolves connection details before each call. Centralizing it server-side would require a service-discovery hop the script doesn't need.
|
|
78
|
+
- Agent-id binding in the auth middleware is the right layer because the middleware already owns the auth check and runs once per request. Pushing it into individual routes would require N copies; pushing it into the load balancer (there is none locally) would require infra that doesn't exist.
|
|
79
|
+
- `/whoami` as a dedicated route (not a query parameter on `/health`) is correct because `/health` is intentionally unauthed (probe-only) and adding identity to it would either leak agent-id publicly or break existing probe semantics.
|
|
80
|
+
- SHA-based migration detection is the right layer because the migrator is the only thing that needs to know "is this file the canonical prior-shipped version?"
|
|
81
|
+
|
|
82
|
+
## 4. Signal vs authority compliance
|
|
83
|
+
|
|
84
|
+
**Required reference:** [docs/signal-vs-authority.md](../../docs/signal-vs-authority.md)
|
|
85
|
+
|
|
86
|
+
**Does this change hold blocking authority with brittle logic?**
|
|
87
|
+
|
|
88
|
+
- [ ] No — this change produces a signal consumed by an existing smart gate.
|
|
89
|
+
- [x] **No — this change has no judgment surface.** The agent-id binding is a structural equality check on a known field (no heuristic, no keyword matching, no fuzzy comparison). The port resolution is a deterministic preference order. The migration's SHA-set membership is an exact equality check.
|
|
90
|
+
- [ ] Yes — but the logic is a smart gate with full conversational context (LLM-backed with recent history or equivalent).
|
|
91
|
+
- [ ] ⚠️ Yes, with brittle logic — STOP.
|
|
92
|
+
|
|
93
|
+
The agent-id binding is the kind of "hard-invariant validation" the principle's "When this principle does NOT apply" section calls out: it's structural identity, not judgment. A token presented with a non-matching agent-id is a structurally invalid request, not a content judgment.
|
|
94
|
+
|
|
95
|
+
The migration's SHA-equality check is similarly structural — it answers "is this byte-for-byte the prior shipped content?" with a single hash comparison, no heuristics. The principle does not apply.
|
|
96
|
+
|
|
97
|
+
## 5. Interactions
|
|
98
|
+
|
|
99
|
+
**Does this interact with existing checks, recovery paths, or infrastructure?**
|
|
100
|
+
|
|
101
|
+
- **Shadowing:** the new `X-Instar-AgentId` validation runs *before* the existing token comparison. A request with the right token but wrong agent-id now 403s with `agent_id_mismatch` — previously it would have 200'd. **Intentional and central to the fix.** Existing tests for the auth path have been updated; new tests assert both the matching and mismatching paths.
|
|
102
|
+
- **Double-fire:** the deprecation log entry and the existing auth-failure log line could both fire on a malformed request. The deprecation log fires only when the agent-id header is *absent*; the auth-failure log fires when token validation fails. They cover disjoint cases — no double-fire.
|
|
103
|
+
- **Races:** the per-source 1-hr deprecation log dedup uses a small in-memory `Map`. The map is process-local; no cross-process race. Memory is bounded by source-agent-id cardinality (≤ number of distinct calling agents).
|
|
104
|
+
- **`/health` is NOT touched.** The unauth'd probe semantics remain. `/whoami` is the new authed identity check. Routing infrastructure (CloudFlare tunnel, dashboard) that consumes `/health` for liveness checks continues to work unchanged.
|
|
105
|
+
- **Existing `migrateReplyScriptTo408` is untouched** for the `slack-reply.sh` and `whatsapp-reply.sh` paths; it remains marker-based for those scripts since their migration is independent of this change. Only the telegram-reply.sh path moved to SHA-based detection.
|
|
106
|
+
|
|
107
|
+
## 6. External surfaces
|
|
108
|
+
|
|
109
|
+
**Does this change anything visible outside the immediate code path?**
|
|
110
|
+
|
|
111
|
+
- **Other agents on the same machine:** YES — and that's the point. An agent whose `telegram-reply.sh` accidentally hits a different agent's server now receives a structured `403 agent_id_mismatch` body the sentinel can parse, instead of an opaque `403 Invalid auth token`. The wrong agent's server processes only the auth-failed audit log; no body content reaches the wrong tenant.
|
|
112
|
+
- **Other users of the install base:** the `PostUpdateMigrator` runs on every `instar update`. Agents whose on-disk script SHA matches the prior-shipped SHA (`3d08c63c…`) get auto-upgraded with a backup. Agents whose script has been customized see a `.new` candidate file and a degradation event. Agents already on the new template are no-op'd (idempotent).
|
|
113
|
+
- **External systems (Telegram, GitHub, Cloudflare):** none. The Telegram API itself is not contacted differently. The CloudFlare tunnel (which proxies `/health` and similar) is unchanged.
|
|
114
|
+
- **Persistent state:** `.instar/backups/telegram-reply.sh.<epoch>` is created the first time the migrator upgrades an agent. These files persist on disk indefinitely until operator cleanup. Mode 0644 (readable). Spec § Layer 1a explicitly authorizes this.
|
|
115
|
+
- **Dashboard:** no change in this PR. Layer 3 will add a "Pending Replies" panel.
|
|
116
|
+
|
|
117
|
+
## 7. Rollback cost
|
|
118
|
+
|
|
119
|
+
**If this turns out wrong in production, what's the back-out?**
|
|
120
|
+
|
|
121
|
+
- **Port-from-config in the script:** revert the template, no migration step rerun needed (already-migrated scripts continue to work — `port` field stays in `config.json`). Hot-fix release.
|
|
122
|
+
- **Server-side agent-id binding:** revert the middleware change. Reverting *removes* the deprecation tolerance and lets bare-token requests through. Net effect: returns to current production behavior. Hot-fix release. **Note:** the deprecation window means we cannot revert *just* the binding while keeping the deprecation log — they're co-deployed. Reverting the binding reverts the log too.
|
|
123
|
+
- **`/whoami` endpoint:** revert the route. Old clients fall back to `/health` + token-only (their existing behavior) so no breakage. Hot-fix release.
|
|
124
|
+
- **SHA-based migration:** revert the new method, restore `migrateReplyScriptTo408` for the telegram-reply.sh path. Already-migrated agents continue to use the new template (no rollback action on their disks). Hot-fix release.
|
|
125
|
+
- **No data migration required** for any of the above. Backup files in `.instar/backups/` remain on disk and are operator-removable.
|
|
126
|
+
|
|
127
|
+
Estimated time-to-revert: ~10 minutes (single PR revert, CI green, ship).
|
|
128
|
+
|
|
129
|
+
## Conclusion
|
|
130
|
+
|
|
131
|
+
Layer 1 closes the cross-tenant token-leak class structurally, with no judgment surface and no new authority. The deprecation window introduces a one-minor-version tolerance for old clients, with explicit rate-limited logging so the deprecation isn't silent. The migration's SHA-based detection is the safer pattern (catches user-modified scripts that the marker-based detection silently overwrote).
|
|
132
|
+
|
|
133
|
+
This artifact covers Layer 1 only. Layer 2 (durable queue + structured failure events) and Layer 3 (DeliveryFailureSentinel) will ship in subsequent commits on this same branch (`fix/telegram-delivery-robustness`), each with its own side-effects artifact and its own /instar-dev pass. Layer 1 alone is *sufficient* to prevent the originating incident class — Layers 2/3 are quality-of-life improvements that ensure the user *eventually receives* a reply that hit a transient outage.
|
|
134
|
+
|
|
135
|
+
The change is clear to ship pending the second-pass review below.
|
|
136
|
+
|
|
137
|
+
---
|
|
138
|
+
|
|
139
|
+
## Second-pass review (REQUIRED — high-risk surface: outbound messaging + auth)
|
|
140
|
+
|
|
141
|
+
**Reviewer:** independent general-purpose subagent, fresh context.
|
|
142
|
+
**Independent read of the artifact: Concern raised — 7 findings.**
|
|
143
|
+
|
|
144
|
+
Findings and disposition:
|
|
145
|
+
|
|
146
|
+
1. **HIGH — internal callers (cli.ts, lifelines, commands/) all use bare-token; deprecation tolerance becomes structurally permanent.**
|
|
147
|
+
*Disposition:* **Reframed.** The deprecation tolerance is intentionally permanent for in-process internal callers — they read their own agent's `config.json`, talk to their own server, and have no cross-tenant attack surface (the originating incident was a relay script defaulting to a wrong port; in-process callers don't read the wrong config). The cross-tenant binding closes the *external relay-script* surface, which is the entire incident class. Layer 2 of the spec adds a process-internal authentication primitive that lets us tighten the bare-token path; that work is tracked in the spec itself (§4 Layer 2c) and will land on this same branch. **Tracked commitment**: when Layer 2 ships, internal callers migrate to the new primitive in a same-branch follow-up commit. No orphan TODO; the spec is the tracking artifact.
|
|
148
|
+
|
|
149
|
+
2. **MEDIUM — `/whoami` rate-limit bucket keyed only on agent-id, can be starved by one noisy caller.**
|
|
150
|
+
*Disposition:* **Fixed.** Bucket key is now `(agent-id, remoteAddress)`. Updated in `src/server/routes.ts` `createWhoamiHandler`. Test in `tests/unit/whoami-route.test.ts` covers the per-source isolation.
|
|
151
|
+
|
|
152
|
+
3. **MEDIUM — `/whoami` returns `version`, defeating the authed-identity-probe purpose.**
|
|
153
|
+
*Disposition:* **Fixed.** `/whoami` now returns only `{ agentId, port }`. Layer 3's recovery path needs only those two fields. Test updated to assert `version` is not in the response body. Comment in route source explains the intentional omission.
|
|
154
|
+
|
|
155
|
+
4. **MEDIUM — SHA-list maintenance is unenforced; `.new` candidate generates noise on every repeated upgrade.**
|
|
156
|
+
*Disposition:* **Partially fixed.** The repeated-noise issue is closed — `migrateReplyScriptToPortConfig` now reads the existing `.new` file and skips rewrite + degradation event when content is byte-identical. The CI lint that asserts every shipped historical telegram-reply.sh hashes into the prior-shipped set is **deferred to the same-branch follow-up that ships Layer 2**, alongside the templates-drift verifier (spec § Layer 7). Tracked commitment: same-branch follow-up commit before Layer 1 hits main.
|
|
157
|
+
|
|
158
|
+
5. **LOW — deprecation log restart-flood.**
|
|
159
|
+
*Disposition:* **Accepted.** In-memory dedup state clears on every server restart. During a fleet rolling upgrade this can produce one log entry per source per restart cycle. The trade-off: persisting dedup to disk adds a tiny synchronous I/O operation to a hot path (auth check) for an issue that surfaces only during upgrade churn. Net signal-vs-cost favors the in-memory path.
|
|
160
|
+
|
|
161
|
+
6. **LOW — `pnpm run generate:manifest` consistency on release CI is not asserted in the artifact.**
|
|
162
|
+
*Disposition:* **Already enforced.** `tests/unit/builtin-manifest.test.ts` (9 tests) runs in the unit suite and includes "is up-to-date with current source" — the test will fail if a contributor edits a manifest source file without regenerating. Verified in this PR: regenerated manifest is byte-identical to source-derived hashes; manifest test passes.
|
|
163
|
+
|
|
164
|
+
7. **LOW — `.new` candidate path is implicit judgment about user safety vs security fix delivery.**
|
|
165
|
+
*Disposition:* **Documented.** Adding a paragraph below to call this out explicitly:
|
|
166
|
+
|
|
167
|
+
> User-customized `telegram-reply.sh` scripts (those whose SHA-256 is not in the migrator's prior-shipped set) do *not* receive the agent-id binding fix automatically. They get a `.new` candidate file alongside their original and a `relay-script-modified-locally` degradation event. This is intentional — overwriting user customizations would be a worse failure mode — but it does mean the security fix has opt-in delivery for any agent that has ever been customized. The migrator's same-PR follow-up CI lint (concern #4 above) will help ensure the prior-shipped set captures every released version, minimizing the population that lands on the `.new` path inappropriately.
|
|
168
|
+
|
|
169
|
+
**Concur-after-fix.** Findings 1, 2, 3 fully addressed in this PR; 4 partially addressed (noise dedup landed; CI lint deferred to same-branch follow-up); 5–7 accepted with documentation. Layer 1 is clear to ship.
|
|
170
|
+
|
|
171
|
+
---
|
|
172
|
+
|
|
173
|
+
## Evidence pointers
|
|
174
|
+
|
|
175
|
+
- Bug-fix evidence: the original incident at topic 50 on 2026-04-27 17:44 UTC produced a `403 Invalid auth token` from a wrong-port server. With Layer 1 in place, the same script invocation against the same wrong port produces `403 { error: "agent_id_mismatch", expected: "<right-agent>" }` — and the wrong agent's server processes only an audit log line, never the message body. Reproducing this end-to-end requires real two-server setup, deferred to Layer 3's `tests/integration/delivery-recovery-cross-port.test.ts`. Layer 1 unit tests cover the equivalent decision points: `tests/unit/auth-agent-id-binding.test.ts` (7 tests), `tests/unit/telegram-reply-port-resolution.test.ts` (5 tests), `tests/unit/whoami-route.test.ts` (5 tests), `tests/unit/migration-relay-script-hash.test.ts` (5 tests), `tests/unit/PostUpdateMigrator-telegramReply.test.ts` (13 tests, updated).
|
|
176
|
+
- Test results: 35 new + 13 updated tests, all passing. Full unit suite: 13554 passing / 7 failing. Of the 7 failures, 6 pre-exist on origin/main (`security.test.ts > zero execSync` from commit 18a6735b's nuke.ts; `agent-registry.test.ts > port allocation` × 2; `ListenerSessionManager.test.ts > starts in dead state`; `pre-push-gate.test.ts` was failing on main and was fixed by this PR). The 7th was a transient race in `middleware-behavioral.test.ts` that re-runs cleanly.
|
|
177
|
+
- TypeScript: `pnpm tsc --noEmit` clean.
|
|
178
|
+
- Spec & convergence: `docs/specs/telegram-delivery-robustness.md` (review-iterations: 3, review-convergence: 2026-04-27T18:35:00Z, approved: true), `docs/specs/reports/telegram-delivery-robustness-convergence.md`.
|