claude-code-session-manager 0.98.0 → 0.100.0

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 (431) hide show
  1. package/README.md +3 -3
  2. package/bin/cli.cjs +16 -4
  3. package/bin/node-floor.cjs +41 -0
  4. package/dist/assets/{DataModel-DCEgMTjH.js → DataModel-HdR0AxFq.js} +1 -1
  5. package/dist/assets/{History-Bfdoywlh.js → History-Dr4Jr_5z.js} +2 -2
  6. package/dist/assets/{Hooks-CKDJjTJV.js → Hooks-NhrvH3JP.js} +3 -3
  7. package/dist/assets/{Library-7akfgy67.js → Library-Dv_EtIMr.js} +1 -1
  8. package/dist/assets/{MarkdownEditor-DDesiqet.js → MarkdownEditor-DTKDWV_n.js} +1 -1
  9. package/dist/assets/{McpServers-D4lZtXof.js → McpServers-M034G9B3.js} +2 -2
  10. package/dist/assets/{Memory-CeI8G1w5.js → Memory-DzF1B4gx.js} +6 -6
  11. package/dist/assets/{Permissions-BGleLja4.js → Permissions-DrgbSGWl.js} +3 -3
  12. package/dist/assets/{Plugins-P4eCXy_S.js → Plugins-Bd3ef35w.js} +2 -2
  13. package/dist/assets/{ProvenanceBadge-BFczzI1B.js → ProvenanceBadge-DcBHT1Iy.js} +1 -1
  14. package/dist/assets/{SaveBar-l9jnEMES.js → SaveBar-rimJem-Y.js} +1 -1
  15. package/dist/assets/Scheduler-DjgFJl2w.js +16 -0
  16. package/dist/assets/{ScopeSwitcher-CjJi8ST5.js → ScopeSwitcher-CnAzTBrl.js} +1 -1
  17. package/dist/assets/Settings-Dc1F_sSg.js +3 -0
  18. package/dist/assets/{SkillReferenceGraph-CjbO01Sg.js → SkillReferenceGraph-B9aZDecM.js} +1 -1
  19. package/dist/assets/{Skills-BxZ9_fCR.js → Skills-DRXd18gu.js} +2 -2
  20. package/dist/assets/{SystemPrompt-D8vfFb8b.js → SystemPrompt-ahy5-Fwe.js} +1 -1
  21. package/dist/assets/{TagLibrary-2vzUo7YL.js → TagLibrary-C_tToDeL.js} +1 -1
  22. package/dist/assets/{TiptapBody-B8ZfbK90.js → TiptapBody-DvdefS6K.js} +1 -1
  23. package/dist/assets/{Toggle-BbW4nGGf.js → Toggle-6Jl5Njc6.js} +1 -1
  24. package/dist/assets/{index-CKH5Uxik.css → index-Bta-hwud.css} +1 -1
  25. package/dist/assets/{index-Cd98Q1lD.js → index-vx8O73l8.js} +497 -502
  26. package/dist/assets/{settingsSchema-IhUfucCF.js → settingsSchema-D6iRguNV.js} +1 -1
  27. package/dist/index.html +2 -2
  28. package/package.json +25 -29
  29. package/plugins/CLAUDE.md +6 -6
  30. package/plugins/session-manager-dev/skills/builder/4-manual/SKILL.md +21 -19
  31. package/plugins/session-manager-dev/skills/builder/SKILL.md +3 -3
  32. package/plugins/session-manager-dev/skills/develop/SKILL.md +254 -510
  33. package/plugins/session-manager-dev/skills/develop/standards.md +17 -22
  34. package/scripts/README.md +3 -11
  35. package/scripts/audit-ops-hygiene.cjs +3 -3
  36. package/scripts/hooks/lib/guard-prd-writes-policy.cjs +1 -1
  37. package/scripts/hooks/lib/guard-self-schedule-policy.cjs +1 -1
  38. package/scripts/mint-epic.cjs +2 -3
  39. package/scripts/scheduler-mcp-server.cjs +36 -7
  40. package/src/main/agentLibrary.cjs +22 -2
  41. package/src/main/build-info.json +4 -4
  42. package/src/main/config.cjs +41 -38
  43. package/src/main/docEdit.cjs +4 -1
  44. package/src/main/files.cjs +2 -5
  45. package/src/main/health.cjs +1 -1
  46. package/src/main/index.cjs +23 -10
  47. package/src/main/ipcSchemas.cjs +28 -35
  48. package/src/main/lib/agentPersonaSchema.cjs +13 -2
  49. package/src/main/lib/atomicFs.cjs +116 -0
  50. package/src/main/lib/branchSweep.cjs +13 -12
  51. package/src/main/lib/buildTarget.cjs +3 -3
  52. package/src/main/lib/claudeCliCaps.cjs +129 -0
  53. package/src/main/lib/credentials.cjs +2 -4
  54. package/src/main/lib/crossProjectFeedback.cjs +3 -3
  55. package/src/main/lib/cwdClassify.cjs +15 -3
  56. package/src/main/lib/definitionOfDone.cjs +207 -125
  57. package/src/main/lib/dodDrainHook.cjs +11 -5
  58. package/src/main/lib/epicMint.cjs +2 -4
  59. package/src/main/lib/epicStatusMirror.cjs +8 -10
  60. package/src/main/lib/epicWorktreeProjectConfig.cjs +2 -4
  61. package/src/main/lib/gateAuthority.cjs +96 -0
  62. package/src/main/lib/gitExec.cjs +69 -0
  63. package/src/main/lib/gitWorktree.cjs +656 -92
  64. package/src/main/lib/instanceLock.cjs +5 -8
  65. package/src/main/lib/launchFailure.cjs +2 -3
  66. package/src/main/lib/macroLibrary.cjs +386 -0
  67. package/src/main/lib/mcpToolCatalog.cjs +26 -17
  68. package/src/main/lib/needsReviewLedger.cjs +1 -1
  69. package/src/main/lib/opsErrorLog.cjs +11 -1
  70. package/src/main/lib/opsOwnership.cjs +0 -5
  71. package/src/main/lib/pidAlive.cjs +32 -0
  72. package/src/main/lib/prdCreate.cjs +121 -12
  73. package/src/main/lib/prdDisposition.cjs +2 -2
  74. package/src/main/lib/prdGateFiles.cjs +284 -0
  75. package/src/main/lib/prdLocations.cjs +61 -0
  76. package/src/main/lib/prdMigration.cjs +2 -3
  77. package/src/main/lib/prdSizing.cjs +2 -1
  78. package/src/main/lib/promptSessionSchema.cjs +10 -2
  79. package/src/main/lib/rcaReport.cjs +4 -6
  80. package/src/main/lib/reaperHelpers.cjs +8 -1
  81. package/src/main/lib/reservationExpiry.cjs +6 -1
  82. package/src/main/lib/reviewNotice.cjs +263 -0
  83. package/src/main/lib/runClaudeP.cjs +4 -1
  84. package/src/main/lib/schedulerPaths.cjs +22 -2
  85. package/src/main/lib/sessionSlots.cjs +2 -4
  86. package/src/main/lib/shippedPersonaSeeds.cjs +179 -0
  87. package/src/main/lib/timeoutShim.cjs +123 -0
  88. package/src/main/lib/timeoutShimScript.cjs +275 -0
  89. package/src/main/lib/upgradeDrain.cjs +4 -10
  90. package/src/main/lib/watchdogHelpers.cjs +12 -25
  91. package/src/main/lib/workTypeLibrary.cjs +7 -1
  92. package/src/main/promptSessionEvents.cjs +37 -13
  93. package/src/main/scheduler.cjs +910 -198
  94. package/src/main/seedAgentPersonas.cjs +278 -23
  95. package/src/main/supervisor.cjs +4 -1
  96. package/src/main/templates/PRD_AUTHORING.md +126 -406
  97. package/src/preload/__tests__/preload-surface.test.cjs +68 -0
  98. package/src/preload/api.d.ts +41 -94
  99. package/src/preload/index.cjs +14 -9
  100. package/src/seed/agents/architect.md +1 -0
  101. package/src/seed/agents/dev-lead.md +17 -18
  102. package/src/seed/agents/project-home-builder.md +1 -0
  103. package/src/seed/agents/validator.md +10 -4
  104. package/dist/assets/HostBilko-CDVHE0hT.js +0 -1
  105. package/dist/assets/Scheduler-C_phpeUS.js +0 -16
  106. package/dist/assets/Settings-BIwZ3FGQ.js +0 -3
  107. package/src/main/__tests__/activeIndexMerge.test.cjs +0 -235
  108. package/src/main/__tests__/agentEffortResolve.test.cjs +0 -117
  109. package/src/main/__tests__/agentLibrary.test.cjs +0 -276
  110. package/src/main/__tests__/agentModelResolve.test.cjs +0 -311
  111. package/src/main/__tests__/agentOverlayWrite.test.cjs +0 -95
  112. package/src/main/__tests__/bilkoHost-deriveSlug.test.cjs +0 -26
  113. package/src/main/__tests__/bilkoHost-integration.test.cjs +0 -118
  114. package/src/main/__tests__/bilkoHostCore.test.cjs +0 -72
  115. package/src/main/__tests__/broadcastCoalescer.test.cjs +0 -122
  116. package/src/main/__tests__/chat-cancel-terminal.test.cjs +0 -120
  117. package/src/main/__tests__/chat-dead-channels.test.cjs +0 -63
  118. package/src/main/__tests__/chat-exit-close-race.test.cjs +0 -146
  119. package/src/main/__tests__/chat-mcp-consent-notice.test.cjs +0 -139
  120. package/src/main/__tests__/chat-preamble-anchors.test.cjs +0 -100
  121. package/src/main/__tests__/chat-queue.test.cjs +0 -97
  122. package/src/main/__tests__/chat-stop-signal.test.cjs +0 -89
  123. package/src/main/__tests__/chatRunner-epic-worktree-execcwd.test.cjs +0 -125
  124. package/src/main/__tests__/chatRunner-session-flag-retry.test.cjs +0 -252
  125. package/src/main/__tests__/classifyPromptTicket.test.cjs +0 -101
  126. package/src/main/__tests__/classifyTranscriptLine.test.cjs +0 -201
  127. package/src/main/__tests__/computeDepHistorySatisfaction.test.cjs +0 -66
  128. package/src/main/__tests__/config-readText-bounded.test.cjs +0 -84
  129. package/src/main/__tests__/configWriteBoundaryOwners.test.cjs +0 -59
  130. package/src/main/__tests__/crossProjectFeedback.test.cjs +0 -334
  131. package/src/main/__tests__/crossProjectFeedbackRoutes.test.cjs +0 -161
  132. package/src/main/__tests__/dep-orphan-archive-health.test.cjs +0 -77
  133. package/src/main/__tests__/develop-skill-failure-modes.test.cjs +0 -70
  134. package/src/main/__tests__/docEdit.test.cjs +0 -244
  135. package/src/main/__tests__/dod-batchkey.test.cjs +0 -183
  136. package/src/main/__tests__/dod-drain-hook.test.cjs +0 -302
  137. package/src/main/__tests__/dod-report.test.cjs +0 -304
  138. package/src/main/__tests__/dod-reverify.test.cjs +0 -285
  139. package/src/main/__tests__/epicContextDigest.test.cjs +0 -174
  140. package/src/main/__tests__/epicMint.test.cjs +0 -332
  141. package/src/main/__tests__/epicMintTelemetryTap.test.cjs +0 -64
  142. package/src/main/__tests__/epicStatusMirror.test.cjs +0 -110
  143. package/src/main/__tests__/epicValidationHook.test.cjs +0 -291
  144. package/src/main/__tests__/exchanges.test.cjs +0 -122
  145. package/src/main/__tests__/exchangesPromptId.test.cjs +0 -61
  146. package/src/main/__tests__/extractJson.test.cjs +0 -51
  147. package/src/main/__tests__/files-reject-credentials.test.cjs +0 -40
  148. package/src/main/__tests__/fixtures/1218-fo-01-move-scripts-lib-into-src-main-lib.log +0 -556
  149. package/src/main/__tests__/flatPrdTickSweep.test.cjs +0 -110
  150. package/src/main/__tests__/health-build-freshness.test.cjs +0 -39
  151. package/src/main/__tests__/health-claude-md-budget.test.cjs +0 -57
  152. package/src/main/__tests__/health-credentials.test.cjs +0 -81
  153. package/src/main/__tests__/health-delegation-chain.test.cjs +0 -124
  154. package/src/main/__tests__/health-per-project-stall.test.cjs +0 -84
  155. package/src/main/__tests__/health-prd-migration.test.cjs +0 -37
  156. package/src/main/__tests__/health-queue-dispatch.test.cjs +0 -135
  157. package/src/main/__tests__/health-starve-escalation.test.cjs +0 -94
  158. package/src/main/__tests__/health-tick-liveness.test.cjs +0 -179
  159. package/src/main/__tests__/health-usage-poller.test.cjs +0 -144
  160. package/src/main/__tests__/health-worktree-cap-blocked.test.cjs +0 -65
  161. package/src/main/__tests__/heapSnapshot.test.cjs +0 -121
  162. package/src/main/__tests__/historyAggregatorIntraday.test.cjs +0 -313
  163. package/src/main/__tests__/historyDashboard.test.cjs +0 -163
  164. package/src/main/__tests__/historyRollup.test.cjs +0 -333
  165. package/src/main/__tests__/intradayRefresh.test.cjs +0 -39
  166. package/src/main/__tests__/ipcSchemas-dependsOn.test.cjs +0 -39
  167. package/src/main/__tests__/kg-augment.test.cjs +0 -195
  168. package/src/main/__tests__/loadGateDetailTick.test.cjs +0 -31
  169. package/src/main/__tests__/machineProfile.test.cjs +0 -152
  170. package/src/main/__tests__/mcpStatus.test.cjs +0 -61
  171. package/src/main/__tests__/memoryAggregate.test.cjs +0 -109
  172. package/src/main/__tests__/memoryStale.test.cjs +0 -88
  173. package/src/main/__tests__/needsReviewLedger.test.cjs +0 -162
  174. package/src/main/__tests__/openExternalApp-spawn-error.test.cjs +0 -25
  175. package/src/main/__tests__/opsErrorLog.test.cjs +0 -109
  176. package/src/main/__tests__/opsErrorLogTelemetryTap.test.cjs +0 -173
  177. package/src/main/__tests__/personaMerge.test.cjs +0 -169
  178. package/src/main/__tests__/planValidator.test.cjs +0 -125
  179. package/src/main/__tests__/pollLoop-dispatch-on-failure.test.cjs +0 -176
  180. package/src/main/__tests__/prd-group-allocator.test.cjs +0 -119
  181. package/src/main/__tests__/prdAdminRouteParity.test.cjs +0 -70
  182. package/src/main/__tests__/prdAdminRoutes.test.cjs +0 -718
  183. package/src/main/__tests__/prdAgentType.test.cjs +0 -103
  184. package/src/main/__tests__/prdAuthoringSeed.test.cjs +0 -39
  185. package/src/main/__tests__/prdCreate.test.cjs +0 -979
  186. package/src/main/__tests__/prdCreateAdoption.test.cjs +0 -205
  187. package/src/main/__tests__/prdCreateDisposition.test.cjs +0 -201
  188. package/src/main/__tests__/prdCreatePlanId.test.cjs +0 -132
  189. package/src/main/__tests__/prdFrontmatterAgentType.test.cjs +0 -117
  190. package/src/main/__tests__/prdFrontmatterDependsOn.test.cjs +0 -136
  191. package/src/main/__tests__/prdFrontmatterDisposition.test.cjs +0 -125
  192. package/src/main/__tests__/prdFrontmatterQuietMachine.test.cjs +0 -108
  193. package/src/main/__tests__/prdLocations.test.cjs +0 -195
  194. package/src/main/__tests__/prdLocationsArchived.test.cjs +0 -201
  195. package/src/main/__tests__/prdMigration.test.cjs +0 -349
  196. package/src/main/__tests__/prdMigrationLegacyAdopt.test.cjs +0 -91
  197. package/src/main/__tests__/prdParserHighWater.test.cjs +0 -74
  198. package/src/main/__tests__/prdParserSourcePromptId.test.cjs +0 -65
  199. package/src/main/__tests__/prdSetDisposition.test.cjs +0 -222
  200. package/src/main/__tests__/prdSizing.test.cjs +0 -106
  201. package/src/main/__tests__/prdSourcePromptIdBackfill.test.cjs +0 -118
  202. package/src/main/__tests__/prdUpdateDependsOn.test.cjs +0 -160
  203. package/src/main/__tests__/proc-role-env.test.cjs +0 -125
  204. package/src/main/__tests__/procname-claude-spawn-sites.test.cjs +0 -304
  205. package/src/main/__tests__/procname-sm-processes.test.cjs +0 -127
  206. package/src/main/__tests__/projectHomeAdminRoutes.test.cjs +0 -177
  207. package/src/main/__tests__/projectPages.test.cjs +0 -137
  208. package/src/main/__tests__/promptSessionEvents.test.cjs +0 -234
  209. package/src/main/__tests__/promptSessionSchema.test.cjs +0 -101
  210. package/src/main/__tests__/promptSessionTranscript.test.cjs +0 -0
  211. package/src/main/__tests__/promptSessionsCreateEpicHandler.test.cjs +0 -159
  212. package/src/main/__tests__/pty-epic-worktree-spawn-cwd.test.cjs +0 -282
  213. package/src/main/__tests__/pty-session-open-telemetry.test.cjs +0 -96
  214. package/src/main/__tests__/pty-write-result.test.cjs +0 -46
  215. package/src/main/__tests__/queue-health-verdict.test.cjs +0 -170
  216. package/src/main/__tests__/queue-starvation-dispatch-driver.test.cjs +0 -286
  217. package/src/main/__tests__/queue-starvation-per-project.test.cjs +0 -147
  218. package/src/main/__tests__/queueHistory.test.cjs +0 -355
  219. package/src/main/__tests__/queueOps-interactive-ac-lint.test.cjs +0 -65
  220. package/src/main/__tests__/queueOpsArchiveDestination.test.cjs +0 -65
  221. package/src/main/__tests__/queueOpsAutoArchive.test.cjs +0 -211
  222. package/src/main/__tests__/rateLimitPollerStreak.test.cjs +0 -128
  223. package/src/main/__tests__/rcaReport.test.cjs +0 -266
  224. package/src/main/__tests__/reconcileFlatPrdSweep.test.cjs +0 -119
  225. package/src/main/__tests__/reconcileTiming.test.cjs +0 -135
  226. package/src/main/__tests__/runLogRetention.test.cjs +0 -489
  227. package/src/main/__tests__/runVerify-atomic-verdicts.test.cjs +0 -26
  228. package/src/main/__tests__/runVerify-blocked-by-foreign-wip.test.cjs +0 -58
  229. package/src/main/__tests__/runVerify-landed-commit-outranks.test.cjs +0 -191
  230. package/src/main/__tests__/runVerify-policy-denial.test.cjs +0 -89
  231. package/src/main/__tests__/runVerify-transcript-commit-evidence.test.cjs +0 -225
  232. package/src/main/__tests__/runVerify.test.cjs +0 -1784
  233. package/src/main/__tests__/scheduleJobSchema.test.cjs +0 -127
  234. package/src/main/__tests__/scheduleJobStatusDrift.test.cjs +0 -65
  235. package/src/main/__tests__/scheduleJobTransitions.test.cjs +0 -277
  236. package/src/main/__tests__/scheduleJobTransitionsGrep.test.cjs +0 -59
  237. package/src/main/__tests__/scheduleJobTransitionsTelemetryTap.test.cjs +0 -72
  238. package/src/main/__tests__/scheduler-admin-routes.test.cjs +0 -199
  239. package/src/main/__tests__/scheduler-adopted-run-supervision.test.cjs +0 -143
  240. package/src/main/__tests__/scheduler-already-satisfied-on-main.test.cjs +0 -105
  241. package/src/main/__tests__/scheduler-archive-completed-prd.test.cjs +0 -102
  242. package/src/main/__tests__/scheduler-archived-twin-guard.test.cjs +0 -155
  243. package/src/main/__tests__/scheduler-autofix-outcome.test.cjs +0 -188
  244. package/src/main/__tests__/scheduler-autofix-select.test.cjs +0 -439
  245. package/src/main/__tests__/scheduler-autopromote.test.cjs +0 -51
  246. package/src/main/__tests__/scheduler-bash-timeout-env.test.cjs +0 -101
  247. package/src/main/__tests__/scheduler-blocked-by-foreign-wip.test.cjs +0 -107
  248. package/src/main/__tests__/scheduler-boot-orphans.test.cjs +0 -153
  249. package/src/main/__tests__/scheduler-broadcast-reconcile.test.cjs +0 -121
  250. package/src/main/__tests__/scheduler-clear-queue-history.test.cjs +0 -134
  251. package/src/main/__tests__/scheduler-commit-guard-noop.test.cjs +0 -244
  252. package/src/main/__tests__/scheduler-committed-in-window.test.cjs +0 -182
  253. package/src/main/__tests__/scheduler-cross-project-batch.test.cjs +0 -43
  254. package/src/main/__tests__/scheduler-default-eligible-heal.test.cjs +0 -168
  255. package/src/main/__tests__/scheduler-dispatch-loop.test.cjs +0 -58
  256. package/src/main/__tests__/scheduler-effective-concurrency.test.cjs +0 -81
  257. package/src/main/__tests__/scheduler-epic-digest.test.cjs +0 -227
  258. package/src/main/__tests__/scheduler-failed-autoreset.test.cjs +0 -121
  259. package/src/main/__tests__/scheduler-finalize-dispatch-guards.test.cjs +0 -229
  260. package/src/main/__tests__/scheduler-find-prd-dir.test.cjs +0 -75
  261. package/src/main/__tests__/scheduler-fix-plan-path.test.cjs +0 -119
  262. package/src/main/__tests__/scheduler-force-tick-outcome.test.cjs +0 -46
  263. package/src/main/__tests__/scheduler-foreign-wip-manifest.test.cjs +0 -78
  264. package/src/main/__tests__/scheduler-gate-shadow.test.cjs +0 -119
  265. package/src/main/__tests__/scheduler-guard-verdict-autoresolve.test.cjs +0 -390
  266. package/src/main/__tests__/scheduler-heal-refusal.test.cjs +0 -61
  267. package/src/main/__tests__/scheduler-heartbeat-payload.test.cjs +0 -80
  268. package/src/main/__tests__/scheduler-inplace-salvage.test.cjs +0 -323
  269. package/src/main/__tests__/scheduler-integration-failure-stamp.test.cjs +0 -41
  270. package/src/main/__tests__/scheduler-investigation-clean-skip.test.cjs +0 -63
  271. package/src/main/__tests__/scheduler-investigation-prompt.test.cjs +0 -123
  272. package/src/main/__tests__/scheduler-job-budget.test.cjs +0 -172
  273. package/src/main/__tests__/scheduler-job-overrun.test.cjs +0 -175
  274. package/src/main/__tests__/scheduler-launch-failure.test.cjs +0 -199
  275. package/src/main/__tests__/scheduler-leftover-fields.test.cjs +0 -52
  276. package/src/main/__tests__/scheduler-leftover-quarantine.test.cjs +0 -199
  277. package/src/main/__tests__/scheduler-looks-done.test.cjs +0 -537
  278. package/src/main/__tests__/scheduler-manual-pause.test.cjs +0 -118
  279. package/src/main/__tests__/scheduler-mechanical-recovery.test.cjs +0 -245
  280. package/src/main/__tests__/scheduler-meta-code-sha.test.cjs +0 -46
  281. package/src/main/__tests__/scheduler-mutate-reentrancy.test.cjs +0 -117
  282. package/src/main/__tests__/scheduler-needs-review-autoresolve.test.cjs +0 -197
  283. package/src/main/__tests__/scheduler-never-stop.test.cjs +0 -157
  284. package/src/main/__tests__/scheduler-no-dead-end-status.test.cjs +0 -152
  285. package/src/main/__tests__/scheduler-no-orphan-run-dir.test.cjs +0 -81
  286. package/src/main/__tests__/scheduler-notify-originating-tab-transcript.test.cjs +0 -87
  287. package/src/main/__tests__/scheduler-notify-originating-tab.test.cjs +0 -343
  288. package/src/main/__tests__/scheduler-periodic-reverify-guard.test.cjs +0 -217
  289. package/src/main/__tests__/scheduler-porcelain-rename.test.cjs +0 -164
  290. package/src/main/__tests__/scheduler-prd-missing-skip.test.cjs +0 -161
  291. package/src/main/__tests__/scheduler-prd-persona-spawn.test.cjs +0 -178
  292. package/src/main/__tests__/scheduler-quarantine-autoresolve.test.cjs +0 -165
  293. package/src/main/__tests__/scheduler-quiet-machine-lease.test.cjs +0 -257
  294. package/src/main/__tests__/scheduler-rate-limit-cooldown-freshness.test.cjs +0 -123
  295. package/src/main/__tests__/scheduler-rate-limit-pause.test.cjs +0 -152
  296. package/src/main/__tests__/scheduler-rate-limit-spin-guard.test.cjs +0 -156
  297. package/src/main/__tests__/scheduler-reap-dead-running-jobs.test.cjs +0 -754
  298. package/src/main/__tests__/scheduler-reaper-helpers-basics.test.cjs +0 -87
  299. package/src/main/__tests__/scheduler-reconcile-cwd-preserve.test.cjs +0 -100
  300. package/src/main/__tests__/scheduler-reconcile-history-backfill.test.cjs +0 -105
  301. package/src/main/__tests__/scheduler-reconcile-invalid-repair.test.cjs +0 -203
  302. package/src/main/__tests__/scheduler-reconcile-quarantine.test.cjs +0 -247
  303. package/src/main/__tests__/scheduler-reset-job-fields-guard.test.cjs +0 -77
  304. package/src/main/__tests__/scheduler-resume-recovery.test.cjs +0 -254
  305. package/src/main/__tests__/scheduler-shard-quarantine.test.cjs +0 -115
  306. package/src/main/__tests__/scheduler-shared-tree-guard.test.cjs +0 -380
  307. package/src/main/__tests__/scheduler-sigterm-commit.test.cjs +0 -43
  308. package/src/main/__tests__/scheduler-stall-per-project.test.cjs +0 -126
  309. package/src/main/__tests__/scheduler-starve-escalation.test.cjs +0 -154
  310. package/src/main/__tests__/scheduler-stranded-autofix-park.test.cjs +0 -252
  311. package/src/main/__tests__/scheduler-stranded-investigation.test.cjs +0 -185
  312. package/src/main/__tests__/scheduler-stuck-failed-escalation.test.cjs +0 -136
  313. package/src/main/__tests__/scheduler-supervisor-record.test.cjs +0 -81
  314. package/src/main/__tests__/scheduler-tick-cancel-token.test.cjs +0 -54
  315. package/src/main/__tests__/scheduler-tick-wedge.test.cjs +0 -172
  316. package/src/main/__tests__/scheduler-transient-failure.test.cjs +0 -141
  317. package/src/main/__tests__/scheduler-unreadable-queue-guard.test.cjs +0 -62
  318. package/src/main/__tests__/scheduler-utilization-hold.test.cjs +0 -89
  319. package/src/main/__tests__/scheduler-verify-prd-path.test.cjs +0 -109
  320. package/src/main/__tests__/scheduler-worktree-cap-defer.test.cjs +0 -234
  321. package/src/main/__tests__/scheduler-worktree-exec-cwd.test.cjs +0 -120
  322. package/src/main/__tests__/scheduler-writeprd-epic-rollback.test.cjs +0 -105
  323. package/src/main/__tests__/schedulerBatchRootBlocker.test.cjs +0 -117
  324. package/src/main/__tests__/schedulerStateSidecarRestore.test.cjs +0 -110
  325. package/src/main/__tests__/seedAgentPersonas.test.cjs +0 -184
  326. package/src/main/__tests__/seedSchedulerMcp.test.cjs +0 -211
  327. package/src/main/__tests__/seedStatus.test.cjs +0 -100
  328. package/src/main/__tests__/seedValidatorPersona.test.cjs +0 -116
  329. package/src/main/__tests__/stop-signal-anchor.test.cjs +0 -75
  330. package/src/main/__tests__/telemetryClient.test.cjs +0 -1055
  331. package/src/main/__tests__/telemetryContract.test.cjs +0 -930
  332. package/src/main/__tests__/telemetrySettings.test.cjs +0 -210
  333. package/src/main/__tests__/transcripts-batch-flush.test.cjs +0 -249
  334. package/src/main/__tests__/transcripts-doFlush-array.test.cjs +0 -124
  335. package/src/main/__tests__/transcripts-paged-reads.test.cjs +0 -241
  336. package/src/main/__tests__/transcripts-worktree-epic-path.test.cjs +0 -154
  337. package/src/main/__tests__/transcriptsUsageFor.test.cjs +0 -206
  338. package/src/main/__tests__/uniquePrdNumbers.test.cjs +0 -153
  339. package/src/main/__tests__/usageSingleFlight.test.cjs +0 -169
  340. package/src/main/__tests__/validationSentinels.test.cjs +0 -84
  341. package/src/main/__tests__/workTypeLibrary.test.cjs +0 -89
  342. package/src/main/bilkoHost.cjs +0 -314
  343. package/src/main/bilkoHostCore.cjs +0 -89
  344. package/src/main/lib/__tests__/active-sessions.test.cjs +0 -251
  345. package/src/main/lib/__tests__/activeIndexRebuild.test.cjs +0 -179
  346. package/src/main/lib/__tests__/agentPersonaSchema.test.cjs +0 -67
  347. package/src/main/lib/__tests__/auditLog.test.cjs +0 -38
  348. package/src/main/lib/__tests__/bootSelfHeal.test.cjs +0 -107
  349. package/src/main/lib/__tests__/branchSweep.test.cjs +0 -164
  350. package/src/main/lib/__tests__/buildIdentity.test.cjs +0 -121
  351. package/src/main/lib/__tests__/buildTarget.test.cjs +0 -52
  352. package/src/main/lib/__tests__/childWithLog.test.cjs +0 -321
  353. package/src/main/lib/__tests__/coldBootPromptSessionsWrite.test.cjs +0 -87
  354. package/src/main/lib/__tests__/crashTelemetry.test.cjs +0 -103
  355. package/src/main/lib/__tests__/credentials-futile-refresh.test.cjs +0 -115
  356. package/src/main/lib/__tests__/cwdClassify.test.cjs +0 -111
  357. package/src/main/lib/__tests__/definitionOfDoneSequence.test.cjs +0 -95
  358. package/src/main/lib/__tests__/delegationReadiness.test.cjs +0 -1175
  359. package/src/main/lib/__tests__/dispatchLoop.test.cjs +0 -63
  360. package/src/main/lib/__tests__/effectiveModelInfo.test.cjs +0 -244
  361. package/src/main/lib/__tests__/ephemeralCwd.test.cjs +0 -91
  362. package/src/main/lib/__tests__/epicDelegationStats.test.cjs +0 -137
  363. package/src/main/lib/__tests__/epicSpawnCwd.test.cjs +0 -283
  364. package/src/main/lib/__tests__/epicSpawnPlan.test.cjs +0 -196
  365. package/src/main/lib/__tests__/epicTranscriptPath.test.cjs +0 -163
  366. package/src/main/lib/__tests__/epicWorktreeBoot.test.cjs +0 -136
  367. package/src/main/lib/__tests__/epicWorktreeMerge.test.cjs +0 -130
  368. package/src/main/lib/__tests__/epicWorktreeMint.test.cjs +0 -117
  369. package/src/main/lib/__tests__/epicWorktreeProjectConfig.test.cjs +0 -137
  370. package/src/main/lib/__tests__/fixChainDepth.test.cjs +0 -40
  371. package/src/main/lib/__tests__/fixtures/204-mercury-steam-horse.log.txt +0 -13
  372. package/src/main/lib/__tests__/fixtures/scheduler-machine.json.corrupt-1789147548 +0 -34
  373. package/src/main/lib/__tests__/gateFixtures.json +0 -20
  374. package/src/main/lib/__tests__/gitCacheBound.test.cjs +0 -69
  375. package/src/main/lib/__tests__/gitWorktree.test.cjs +0 -1478
  376. package/src/main/lib/__tests__/gitWorktreeSalvage.test.cjs +0 -107
  377. package/src/main/lib/__tests__/gitWorktreeSalvageDelta.test.cjs +0 -153
  378. package/src/main/lib/__tests__/guardShims.test.cjs +0 -158
  379. package/src/main/lib/__tests__/importReferences.spec.cjs +0 -56
  380. package/src/main/lib/__tests__/instanceLock.test.cjs +0 -173
  381. package/src/main/lib/__tests__/jobSupervisorRecord.test.cjs +0 -78
  382. package/src/main/lib/__tests__/jobWorktree.test.cjs +0 -199
  383. package/src/main/lib/__tests__/jobWorktreeBootLive.test.cjs +0 -82
  384. package/src/main/lib/__tests__/landedSinceRun.test.cjs +0 -133
  385. package/src/main/lib/__tests__/launchFailure.test.cjs +0 -220
  386. package/src/main/lib/__tests__/loadGate.test.cjs +0 -303
  387. package/src/main/lib/__tests__/localAdminHttp.test.cjs +0 -214
  388. package/src/main/lib/__tests__/loopDelay.test.cjs +0 -68
  389. package/src/main/lib/__tests__/mcpToolCatalog.test.cjs +0 -107
  390. package/src/main/lib/__tests__/modelCatalog.test.cjs +0 -202
  391. package/src/main/lib/__tests__/opsOwnership.test.cjs +0 -113
  392. package/src/main/lib/__tests__/opsRootAbsoluteCwd.test.cjs +0 -328
  393. package/src/main/lib/__tests__/opsRootNestedWrite.test.cjs +0 -51
  394. package/src/main/lib/__tests__/opsRootResolve.test.cjs +0 -149
  395. package/src/main/lib/__tests__/prdDeclaredPaths.test.cjs +0 -82
  396. package/src/main/lib/__tests__/prdDisposition.test.cjs +0 -224
  397. package/src/main/lib/__tests__/procIdentity.test.cjs +0 -119
  398. package/src/main/lib/__tests__/procName.test.cjs +0 -92
  399. package/src/main/lib/__tests__/projectBriefCore.test.cjs +0 -216
  400. package/src/main/lib/__tests__/projectRootResolve.test.cjs +0 -148
  401. package/src/main/lib/__tests__/queueHealth.test.cjs +0 -58
  402. package/src/main/lib/__tests__/queueStoreAtomicWrite.test.cjs +0 -88
  403. package/src/main/lib/__tests__/queueStoreMachineStateRecovery.test.cjs +0 -190
  404. package/src/main/lib/__tests__/quietMachineLease.test.cjs +0 -39
  405. package/src/main/lib/__tests__/rateLimitWindow.test.cjs +0 -88
  406. package/src/main/lib/__tests__/reaperHelpers.test.cjs +0 -577
  407. package/src/main/lib/__tests__/schedulerBatchDepends.test.cjs +0 -312
  408. package/src/main/lib/__tests__/schedulerBatchFairness.test.cjs +0 -213
  409. package/src/main/lib/__tests__/schedulerBatchLaunchHold.test.cjs +0 -125
  410. package/src/main/lib/__tests__/schedulerBatchProjectCap.test.cjs +0 -127
  411. package/src/main/lib/__tests__/schedulerBatchQuietMachine.test.cjs +0 -109
  412. package/src/main/lib/__tests__/schedulerMcpServerHeadlessRefusal.test.cjs +0 -71
  413. package/src/main/lib/__tests__/schedulerMcpServerHelp.test.cjs +0 -216
  414. package/src/main/lib/__tests__/schedulerMcpServerProjectHome.test.cjs +0 -183
  415. package/src/main/lib/__tests__/schedulerPaths.test.cjs +0 -226
  416. package/src/main/lib/__tests__/schedulerPathsWorktree.test.cjs +0 -133
  417. package/src/main/lib/__tests__/schedulerRuntimeState.test.cjs +0 -56
  418. package/src/main/lib/__tests__/sessionSlots.test.cjs +0 -144
  419. package/src/main/lib/__tests__/telemetryBacklog.test.cjs +0 -626
  420. package/src/main/lib/__tests__/telemetryBoot.test.cjs +0 -134
  421. package/src/main/lib/__tests__/telemetryConsent.test.cjs +0 -136
  422. package/src/main/lib/__tests__/telemetryCounters.test.cjs +0 -57
  423. package/src/main/lib/__tests__/telemetryCountersMetadataColumn.test.cjs +0 -98
  424. package/src/main/lib/__tests__/terminalRunOutcome.test.cjs +0 -200
  425. package/src/main/lib/__tests__/toolUseClassify.test.cjs +0 -53
  426. package/src/main/lib/__tests__/updateCheck.test.cjs +0 -63
  427. package/src/main/lib/__tests__/upgradeDrain.test.cjs +0 -130
  428. package/src/main/lib/__tests__/usageCircuit.test.cjs +0 -354
  429. package/src/main/lib/__tests__/watchdog-helpers.test.cjs +0 -441
  430. package/src/main/lib/__tests__/watchdog-relaunch.test.cjs +0 -266
  431. package/src/main/lib/kgExchangePairing.cjs +0 -75
@@ -1,115 +0,0 @@
1
- /**
2
- * scheduler-shard-quarantine.test.cjs — a torn per-project queue shard
3
- * quarantines THAT project only. tickQueue keeps dispatching the healthy
4
- * project, never scans/mints rows for the torn project's PRDs, never touches
5
- * the torn file, and health names the quarantined cwd (non-GREEN).
6
- *
7
- * Everything runs under a temp HOME; the stub `claude` writes a marker into
8
- * its own cwd so the test can prove where a spawn did (not) happen.
9
- *
10
- * Run: timeout 120 npx vitest run src/main/__tests__/scheduler-shard-quarantine.test.cjs
11
- */
12
-
13
- 'use strict';
14
-
15
- import { test, expect, beforeAll, afterAll } from 'vitest';
16
- const fs = require('node:fs');
17
- const os = require('node:os');
18
- const path = require('node:path');
19
- const claudeStub = require('../../../tests/helpers/claudeStub.cjs');
20
-
21
- let tmpHome;
22
- let originalHome;
23
- let originalWt;
24
- let scheduler;
25
-
26
- function registerActiveProject(cwd) {
27
- const slugDir = path.join(tmpHome, '.claude', 'projects', `fake-project-slug-${path.basename(cwd)}`);
28
- fs.mkdirSync(slugDir, { recursive: true });
29
- fs.writeFileSync(path.join(slugDir, 'transcript.jsonl'), JSON.stringify({ cwd }) + '\n');
30
- }
31
-
32
- function makeProject(name) {
33
- const cwd = path.join(tmpHome, 'Projects', name);
34
- const stateDir = path.join(cwd, 'session-manager-operations', 'scheduler', 'state');
35
- const prdsDir = path.join(cwd, 'session-manager-operations', 'scheduler', 'epics', 'fixture-epic', 'prds');
36
- fs.mkdirSync(stateDir, { recursive: true });
37
- fs.mkdirSync(prdsDir, { recursive: true });
38
- registerActiveProject(cwd);
39
- return { cwd, prdsDir, queueFile: path.join(stateDir, 'queue.json') };
40
- }
41
-
42
- function writeClaudeStub() {
43
- return claudeStub.writeClaudeStub({ body: `
44
- require('fs').writeFileSync(require('path').join(process.cwd(), 'ran-here.marker'), 'yes');
45
- process.stdout.write(JSON.stringify({ type: 'result', subtype: 'success', result: 'ok\\nSCHEDULER_VERDICT: PASS' }) + '\\n');
46
- process.exit(0);
47
- ` });
48
- }
49
-
50
- beforeAll(() => {
51
- originalHome = process.env.HOME;
52
- originalWt = process.env.SM_JOB_WORKTREE_DISABLE;
53
- tmpHome = fs.mkdtempSync(path.join(os.tmpdir(), 'sm-shard-quarantine-'));
54
- process.env.HOME = tmpHome;
55
- process.env.SM_JOB_WORKTREE_DISABLE = '1';
56
- process.env.SM_AUTOFIX_DISABLE = '1';
57
- fs.mkdirSync(path.join(tmpHome, '.claude', 'session-manager'), { recursive: true });
58
- scheduler = require('../scheduler.cjs');
59
- });
60
-
61
- afterAll(() => {
62
- process.env.HOME = originalHome;
63
- if (originalWt === undefined) delete process.env.SM_JOB_WORKTREE_DISABLE;
64
- else process.env.SM_JOB_WORKTREE_DISABLE = originalWt;
65
- delete process.env.SM_AUTOFIX_DISABLE;
66
- delete process.env.SM_CLAUDE_BIN;
67
- fs.rmSync(tmpHome, { recursive: true, force: true });
68
- });
69
-
70
- test('tickQueue dispatches the healthy project while the torn project is skipped; health names it', async () => {
71
- const good = makeProject('good-proj');
72
- const torn = makeProject('torn-proj');
73
- const goodSlug = `9101-good-${process.pid}`;
74
- const tornSlug = `9102-torn-${process.pid}`;
75
- fs.writeFileSync(path.join(good.prdsDir, `${goodSlug}.md`), 'Healthy PRD.', 'utf8');
76
- fs.writeFileSync(path.join(torn.prdsDir, `${tornSlug}.md`), 'PRD in the torn project.', 'utf8');
77
- fs.writeFileSync(good.queueFile, JSON.stringify({
78
- jobs: [{ slug: goodSlug, title: 'good', status: 'pending', cwd: good.cwd, dependsOn: [], createdAt: new Date().toISOString() }],
79
- }));
80
- // A running row was in flight when the shard tore — must never become pending.
81
- const TORN = '{"jobs":[{"slug":"' + tornSlug + '","status":"running"}]}{"jobs":[{"slug":"';
82
- fs.writeFileSync(torn.queueFile, TORN);
83
- const before = fs.readFileSync(torn.queueFile);
84
- process.env.SM_CLAUDE_BIN = writeClaudeStub();
85
-
86
- const result = await scheduler.tickQueue({ bypassLoadGate: true });
87
- expect(result.reason).not.toBe('unreadable');
88
- expect(result.fired).toBe(true);
89
- // flagUnreadable (via tickQueue's readQueue) snapshots the torn shard beside itself.
90
- const snaps = fs.readdirSync(path.dirname(torn.queueFile)).filter((f) => f.startsWith('queue.json.corrupt-'));
91
- expect(snaps).toHaveLength(1);
92
-
93
- // 60s, not 20s: under npm run test:unit's full-suite parallel-worker load
94
- // this occasionally needed more than 20s for the real child-process
95
- // dispatch to land (PRD 1414 — confirmed flaky only inside the full suite,
96
- // never in isolation or under synthetic single-file CPU load). The
97
- // surrounding vitest test timeout below (120s) already budgets for this.
98
- await new Promise((resolve, reject) => {
99
- const t0 = Date.now();
100
- const poll = () => {
101
- if (fs.existsSync(path.join(good.cwd, 'ran-here.marker'))) return resolve();
102
- if (Date.now() - t0 > 60_000) return reject(new Error('healthy project never dispatched'));
103
- setTimeout(poll, 100);
104
- };
105
- poll();
106
- });
107
-
108
- expect(fs.existsSync(path.join(torn.cwd, 'ran-here.marker'))).toBe(false);
109
- expect(fs.readFileSync(torn.queueFile).equals(before)).toBe(true);
110
-
111
- const health = await require('../health.cjs').check({ skipTypecheck: true });
112
- expect(health.components.scheduler_queue.ok).toBe(false);
113
- expect(health.components.scheduler_queue.quarantinedCwds).toEqual([torn.cwd]);
114
- expect(health.issues.some((i) => i.includes(torn.cwd))).toBe(true);
115
- }, 120_000); // skipTypecheck: this asserts scheduler_queue only; tsc was the tens of seconds
@@ -1,380 +0,0 @@
1
- /**
2
- * scheduler-shared-tree-guard.test.cjs — the shared-tree stash guard added
3
- * for the 2026-09-01 social-signals-trader incident: a headless PRD executor
4
- * ran a blanket `git stash` in a working tree shared with a live trading
5
- * service, silently reverting an uncommitted operator config edit with no
6
- * error anywhere.
7
- *
8
- * evaluateSharedTreeGuard is the pure diff (no I/O); checkSharedTreeGuard is
9
- * the orchestrator that also restores a single unambiguous stash, using the
10
- * same module.exports spy pattern computeCommittedDuringRun/committedInWindow
11
- * use so the underlying git calls never actually run.
12
- *
13
- * Run: timeout 120 npx vitest run src/main/__tests__/scheduler-shared-tree-guard.test.cjs
14
- */
15
-
16
- 'use strict';
17
-
18
- import { test, expect, vi, afterEach } from 'vitest';
19
- const fs = require('node:fs');
20
- const scheduler = require('../scheduler.cjs');
21
- const { evaluateSharedTreeGuard, checkSharedTreeGuard } = scheduler;
22
-
23
- afterEach(() => {
24
- vi.restoreAllMocks();
25
- });
26
-
27
- test('evaluateSharedTreeGuard: no-op when nothing changed', () => {
28
- const result = evaluateSharedTreeGuard({
29
- stashBefore: ['aaa stash@{0} WIP on main: aaa old'],
30
- stashAfter: ['aaa stash@{0} WIP on main: aaa old'],
31
- dirtyBefore: ['data/spread_config.json'],
32
- dirtyAfter: ['data/spread_config.json'],
33
- pathsCommittedDuringRun: [],
34
- });
35
- expect(result.newStashes).toEqual([]);
36
- expect(result.reverted).toEqual([]);
37
- });
38
-
39
- test('evaluateSharedTreeGuard: flags one new stash entry not present in the baseline', () => {
40
- const result = evaluateSharedTreeGuard({
41
- stashBefore: [],
42
- stashAfter: ['bbb stash@{0} WIP on fix/x: bbb f5ae98f'],
43
- dirtyBefore: [],
44
- dirtyAfter: [],
45
- pathsCommittedDuringRun: [],
46
- });
47
- expect(result.newStashes).toEqual([{ hash: 'bbb', ref: 'stash@{0}', subject: 'WIP on fix/x: bbb f5ae98f' }]);
48
- });
49
-
50
- test('evaluateSharedTreeGuard: two new stash entries both surface (caller decides ambiguity, not this function)', () => {
51
- const result = evaluateSharedTreeGuard({
52
- stashBefore: [],
53
- stashAfter: [
54
- 'bbb stash@{0} WIP on fix/x: bbb newest',
55
- 'ccc stash@{1} WIP on fix/x: ccc older',
56
- ],
57
- dirtyBefore: [],
58
- dirtyAfter: [],
59
- pathsCommittedDuringRun: [],
60
- });
61
- expect(result.newStashes).toHaveLength(2);
62
- expect(result.newStashes.map((e) => e.ref)).toEqual(['stash@{0}', 'stash@{1}']);
63
- });
64
-
65
- test('evaluateSharedTreeGuard: baseline-dirty path clean after the run with no commit to explain it is flagged reverted', () => {
66
- const result = evaluateSharedTreeGuard({
67
- stashBefore: [],
68
- stashAfter: [],
69
- dirtyBefore: ['data/spread_config.json'],
70
- dirtyAfter: [],
71
- pathsCommittedDuringRun: [],
72
- });
73
- expect(result.reverted).toEqual(['data/spread_config.json']);
74
- });
75
-
76
- test('evaluateSharedTreeGuard: baseline-dirty path clean after the run but touched by a commit made during the run is NOT flagged', () => {
77
- const result = evaluateSharedTreeGuard({
78
- stashBefore: [],
79
- stashAfter: [],
80
- dirtyBefore: ['src/foo.js'],
81
- dirtyAfter: [],
82
- pathsCommittedDuringRun: ['src/foo.js'],
83
- });
84
- expect(result.reverted).toEqual([]);
85
- });
86
-
87
- test('checkSharedTreeGuard: no-op when nothing changed returns null', async () => {
88
- vi.spyOn(scheduler, 'stashList').mockResolvedValue([]);
89
- vi.spyOn(scheduler, 'uncommittedChanges').mockResolvedValue([]);
90
- vi.spyOn(scheduler, 'gitHead').mockResolvedValue('sha1');
91
- vi.spyOn(scheduler, 'pathsChangedSince').mockResolvedValue([]);
92
- const restoreSpy = vi.spyOn(scheduler, 'restoreSpecificStash');
93
-
94
- const result = await checkSharedTreeGuard({
95
- cwd: '/repo',
96
- stashBaseline: [],
97
- dirtyBaseline: [],
98
- headBefore: 'sha1',
99
- slug: 'job-1',
100
- });
101
- expect(result).toBeNull();
102
- expect(restoreSpy).not.toHaveBeenCalled();
103
- });
104
-
105
- test('checkSharedTreeGuard: a single new stash is restored via apply+drop of that specific ref', async () => {
106
- vi.spyOn(scheduler, 'stashList').mockResolvedValue(['newhash stash@{0} WIP on main: f5ae98f']);
107
- vi.spyOn(scheduler, 'uncommittedChanges').mockResolvedValue([]);
108
- vi.spyOn(scheduler, 'gitHead').mockResolvedValue('sha1');
109
- vi.spyOn(scheduler, 'pathsChangedSince').mockResolvedValue([]);
110
- const restoreSpy = vi.spyOn(scheduler, 'restoreSpecificStash').mockResolvedValue({ ok: true });
111
-
112
- const result = await checkSharedTreeGuard({
113
- cwd: '/repo',
114
- stashBaseline: [],
115
- dirtyBaseline: [],
116
- headBefore: 'sha1',
117
- slug: 'job-1',
118
- });
119
- expect(restoreSpy).toHaveBeenCalledWith('/repo', 'stash@{0}');
120
- expect(result).toEqual({ restoredStash: 'stash@{0}' });
121
- });
122
-
123
- test('checkSharedTreeGuard: a baseline-dirty path stashed by the job and successfully restored is not ALSO flagged reverted', async () => {
124
- vi.spyOn(scheduler, 'stashList').mockResolvedValue(['newhash stash@{0} WIP on main: f5ae98f']);
125
- vi.spyOn(scheduler, 'gitHead').mockResolvedValue('sha1');
126
- vi.spyOn(scheduler, 'pathsChangedSince').mockResolvedValue([]);
127
- vi.spyOn(scheduler, 'restoreSpecificStash').mockResolvedValue({ ok: true });
128
- // uncommittedChanges is queried AFTER the restore attempt in the fixed
129
- // implementation — simulate the stashed file reappearing dirty once the
130
- // apply+drop succeeds (this is the exact 2026-09-01 incident shape: an
131
- // operator's pre-existing dirty file gets swept into the job's stash).
132
- vi.spyOn(scheduler, 'uncommittedChanges').mockResolvedValue(['data/spread_config.json']);
133
-
134
- const result = await checkSharedTreeGuard({
135
- cwd: '/repo',
136
- stashBaseline: [],
137
- dirtyBaseline: ['data/spread_config.json'],
138
- headBefore: 'sha1',
139
- slug: 'job-1',
140
- });
141
- expect(result).toEqual({ restoredStash: 'stash@{0}' });
142
- });
143
-
144
- test('checkSharedTreeGuard: two new stashes are reported, not restored (ambiguous)', async () => {
145
- vi.spyOn(scheduler, 'stashList').mockResolvedValue([
146
- 'aaa stash@{0} WIP on main: newest',
147
- 'bbb stash@{1} WIP on main: older',
148
- ]);
149
- vi.spyOn(scheduler, 'uncommittedChanges').mockResolvedValue([]);
150
- vi.spyOn(scheduler, 'gitHead').mockResolvedValue('sha1');
151
- vi.spyOn(scheduler, 'pathsChangedSince').mockResolvedValue([]);
152
- const restoreSpy = vi.spyOn(scheduler, 'restoreSpecificStash');
153
-
154
- const result = await checkSharedTreeGuard({
155
- cwd: '/repo',
156
- stashBaseline: [],
157
- dirtyBaseline: [],
158
- headBefore: 'sha1',
159
- slug: 'job-1',
160
- });
161
- expect(restoreSpy).not.toHaveBeenCalled();
162
- expect(result.ambiguousStashes).toEqual(['stash@{0}', 'stash@{1}']);
163
- expect(result.restoredStash).toBeUndefined();
164
- });
165
-
166
- test('checkSharedTreeGuard: a baseline-dirty path reverted with no stash and no commit is flagged reverted', async () => {
167
- vi.spyOn(scheduler, 'stashList').mockResolvedValue([]);
168
- vi.spyOn(scheduler, 'uncommittedChanges').mockResolvedValue([]);
169
- vi.spyOn(scheduler, 'gitHead').mockResolvedValue('sha1');
170
- vi.spyOn(scheduler, 'pathsChangedSince').mockResolvedValue([]);
171
-
172
- const result = await checkSharedTreeGuard({
173
- cwd: '/repo',
174
- stashBaseline: [],
175
- dirtyBaseline: ['data/spread_config.json'],
176
- headBefore: 'sha1',
177
- slug: 'job-1',
178
- });
179
- expect(result).toEqual({ reverted: ['data/spread_config.json'] });
180
- });
181
-
182
- test('checkSharedTreeGuard: a failed restore is reported as restoreFailed, entry left in place', async () => {
183
- vi.spyOn(scheduler, 'stashList').mockResolvedValue(['newhash stash@{0} WIP on main: f5ae98f']);
184
- vi.spyOn(scheduler, 'uncommittedChanges').mockResolvedValue([]);
185
- vi.spyOn(scheduler, 'gitHead').mockResolvedValue('sha1');
186
- vi.spyOn(scheduler, 'pathsChangedSince').mockResolvedValue([]);
187
- vi.spyOn(scheduler, 'restoreSpecificStash').mockResolvedValue({ ok: false, error: 'conflict applying stash' });
188
-
189
- const result = await checkSharedTreeGuard({
190
- cwd: '/repo',
191
- stashBaseline: [],
192
- dirtyBaseline: [],
193
- headBefore: 'sha1',
194
- slug: 'job-1',
195
- });
196
- expect(result.restoreFailed).toMatch(/stash@\{0\}.*conflict applying stash/);
197
- });
198
-
199
- test('checkSharedTreeGuard never throws when the underlying git calls reject', async () => {
200
- vi.spyOn(scheduler, 'stashList').mockRejectedValue(new Error('boom'));
201
- vi.spyOn(scheduler, 'uncommittedChanges').mockResolvedValue([]);
202
- vi.spyOn(scheduler, 'gitHead').mockResolvedValue('sha1');
203
- vi.spyOn(scheduler, 'pathsChangedSince').mockResolvedValue([]);
204
-
205
- const result = await checkSharedTreeGuard({
206
- cwd: '/repo',
207
- stashBaseline: [],
208
- dirtyBaseline: [],
209
- headBefore: 'sha1',
210
- slug: 'job-1',
211
- });
212
- expect(result).toBeNull();
213
- });
214
-
215
- // --- 2026-09-12 false-positive: an untracked path that merely became
216
- // IGNORED during the run (a .gitignore edit) is not a revert. See the
217
- // evaluateSharedTreeGuard doc comment for the full incident writeup. Each
218
- // test below is written to FAIL against the pre-fix implementation (which
219
- // computed `reverted = dirtyBefore - dirtyAfter - committed` with no
220
- // existence/tracked-status distinction at all) and PASS after it.
221
-
222
- test('evaluateSharedTreeGuard: an untracked path that disappears from git status but STILL EXISTS on disk is nowIgnored, not reverted', () => {
223
- // Pre-fix behavior: this path would land in `reverted` (dirtyBefore minus
224
- // dirtyAfter minus committed, no existence check at all) — FAILS pre-fix.
225
- const result = evaluateSharedTreeGuard({
226
- stashBefore: [],
227
- stashAfter: [],
228
- dirtyBefore: [{ code: '??', path: 'session-manager-operations/logs/errors-2026-09-12.jsonl' }],
229
- dirtyAfter: [],
230
- pathsCommittedDuringRun: ['.gitignore'],
231
- existsAfter: ['session-manager-operations/logs/errors-2026-09-12.jsonl'],
232
- });
233
- expect(result.reverted).toEqual([]);
234
- expect(result.nowIgnored).toEqual(['session-manager-operations/logs/errors-2026-09-12.jsonl']);
235
- });
236
-
237
- test('evaluateSharedTreeGuard: an untracked path that disappears from git status AND no longer exists on disk is still reverted', () => {
238
- // Proves the fix is not a blanket "stop reporting reverted": a genuinely
239
- // deleted untracked file (the guard's real purpose — catching a job that
240
- // discarded uncommitted work) must still surface. If the fix had simply
241
- // stopped reporting any untracked-and-missing path as reverted, this test
242
- // would fail (reverted would come back empty instead of containing the
243
- // path).
244
- const result = evaluateSharedTreeGuard({
245
- stashBefore: [],
246
- stashAfter: [],
247
- dirtyBefore: [{ code: '??', path: 'data/scratch.txt' }],
248
- dirtyAfter: [],
249
- pathsCommittedDuringRun: [],
250
- existsAfter: [], // file no longer exists on disk
251
- });
252
- expect(result.reverted).toEqual(['data/scratch.txt']);
253
- expect(result.nowIgnored).toEqual([]);
254
- });
255
-
256
- test('evaluateSharedTreeGuard: a TRACKED path clean after the run is still reverted even though it exists on disk', () => {
257
- // A tracked file leaving the dirty set means its content was restored to
258
- // HEAD — exactly the discard this guard exists to catch — regardless of
259
- // whether the file is still present. Pre-fix this already worked by
260
- // accident (no existence check existed at all); this test pins the
261
- // behavior now that existence checks exist for the untracked branch, so a
262
- // future change can't accidentally start trusting `existsAfter` for
263
- // tracked paths too.
264
- const result = evaluateSharedTreeGuard({
265
- stashBefore: [],
266
- stashAfter: [],
267
- dirtyBefore: [{ code: ' M', path: 'src/config.js' }],
268
- dirtyAfter: [],
269
- pathsCommittedDuringRun: [],
270
- existsAfter: ['src/config.js'], // file exists, but content was reset to HEAD
271
- });
272
- expect(result.reverted).toEqual(['src/config.js']);
273
- expect(result.nowIgnored).toEqual([]);
274
- });
275
-
276
- test('checkSharedTreeGuard end-to-end: the real 2026-09-12 incident shape — untracked logs path ignored by a committed .gitignore change, file still on disk — must NOT verdict shared_tree_reverted', async () => {
277
- // PRD 1181's exact shape: a bare `logs/` pattern lands in .gitignore during
278
- // the run (committed), eleven untracked log paths vanish from `git status`,
279
- // and the files are untouched on disk. Pre-fix, checkSharedTreeGuard's
280
- // `reverted` would contain this path (no existsAfter computation existed),
281
- // driving the caller's `verdict: 'shared_tree_reverted'` downgrade — FAILS
282
- // pre-fix.
283
- const logPath = 'session-manager-operations/logs/errors-2026-09-12.jsonl';
284
- vi.spyOn(scheduler, 'stashList').mockResolvedValue([]);
285
- vi.spyOn(scheduler, 'gitHead').mockResolvedValue('sha-after');
286
- vi.spyOn(scheduler, 'pathsChangedSince').mockResolvedValue(['.gitignore']);
287
- vi.spyOn(scheduler, 'uncommittedChanges').mockResolvedValue([]); // the log path no longer shows up at all
288
- // checkSharedTreeGuard's existence check runs concurrently via
289
- // fs.promises.access (fsp === fs.promises — same object) rather than
290
- // fs.existsSync, so a large untracked baseline doesn't block the event
291
- // loop with hundreds of synchronous stats back-to-back.
292
- vi.spyOn(fs.promises, 'access').mockImplementation((p) => (
293
- String(p).includes('errors-2026-09-12.jsonl') ? Promise.resolve() : Promise.reject(new Error('ENOENT'))
294
- ));
295
-
296
- const result = await checkSharedTreeGuard({
297
- cwd: '/repo',
298
- stashBaseline: [],
299
- dirtyBaseline: [{ code: '??', path: logPath }],
300
- headBefore: 'sha-before',
301
- slug: 'job-1181',
302
- });
303
-
304
- expect(result.reverted).toBeUndefined();
305
- expect(result.nowIgnored).toEqual([logPath]);
306
- });
307
-
308
- // --- landedCommit ground truth (2026-09-18, 1229-fo-03 false positive) ---
309
- // Real temp git fixture, never the live repo. Baseline-dirty path `cfg.txt`
310
- // goes clean with no commit covering it (the shape that makes the baseline
311
- // diff say "reverted"); only the landedCommit ancestry decides the verdict.
312
- const { execFileSync } = require('node:child_process');
313
- const os = require('node:os');
314
- const nodePath = require('node:path');
315
-
316
- function gitIn(dir, ...args) {
317
- return execFileSync('git', args, { cwd: dir, encoding: 'utf8' }).trim();
318
- }
319
-
320
- function fixtureRepo() {
321
- const dir = fs.mkdtempSync(nodePath.join(os.tmpdir(), 'shared-tree-landed-'));
322
- gitIn(dir, 'init', '-q');
323
- gitIn(dir, 'config', 'user.email', 't@example.com');
324
- gitIn(dir, 'config', 'user.name', 'T');
325
- fs.writeFileSync(nodePath.join(dir, 'cfg.txt'), 'base\n');
326
- gitIn(dir, 'add', '-A');
327
- gitIn(dir, 'commit', '-q', '-m', 'base');
328
- const base = gitIn(dir, 'rev-parse', 'HEAD');
329
- fs.writeFileSync(nodePath.join(dir, 'cfg.txt'), 'human wip\n'); // baseline-dirty
330
- return { dir, base };
331
- }
332
-
333
- function commitPath(dir, rel, msg) {
334
- fs.writeFileSync(nodePath.join(dir, rel), `${msg}\n`);
335
- gitIn(dir, 'add', rel);
336
- gitIn(dir, 'commit', '-q', '-m', msg);
337
- return gitIn(dir, 'rev-parse', 'HEAD');
338
- }
339
-
340
- test('checkSharedTreeGuard: landedCommit still an ancestor of HEAD plus an unrelated later commit is NOT reverted', async () => {
341
- const { dir, base } = fixtureRepo();
342
- const landed = commitPath(dir, 'job.txt', 'job work');
343
- gitIn(dir, 'checkout', '--', 'cfg.txt'); // baseline-dirty path goes clean, no commit covers it
344
- commitPath(dir, 'later.txt', 'unrelated human commit');
345
-
346
- const result = await checkSharedTreeGuard({
347
- cwd: dir, stashBaseline: [], dirtyBaseline: [{ code: ' M', path: 'cfg.txt' }],
348
- headBefore: base, slug: 'job-a', landedCommit: landed,
349
- });
350
- expect(result).toBeNull();
351
- });
352
-
353
- test('checkSharedTreeGuard: landedCommit absent from history still parks as reverted', async () => {
354
- const { dir, base } = fixtureRepo();
355
- const landed = commitPath(dir, 'job.txt', 'job work');
356
- gitIn(dir, 'reset', '-q', '--hard', base); // job commit discarded
357
- commitPath(dir, 'later.txt', 'unrelated human commit');
358
-
359
- const result = await checkSharedTreeGuard({
360
- cwd: dir, stashBaseline: [], dirtyBaseline: [{ code: ' M', path: 'cfg.txt' }],
361
- headBefore: base, slug: 'job-b', landedCommit: landed,
362
- });
363
- expect(result).toEqual({ reverted: ['cfg.txt'] });
364
- });
365
-
366
- test('checkSharedTreeGuard: no landedCommit at all still parks as reverted', async () => {
367
- const { dir, base } = fixtureRepo();
368
- gitIn(dir, 'checkout', '--', 'cfg.txt');
369
- const result = await checkSharedTreeGuard({
370
- cwd: dir, stashBaseline: [], dirtyBaseline: [{ code: ' M', path: 'cfg.txt' }],
371
- headBefore: base, slug: 'job-c', landedCommit: null,
372
- });
373
- expect(result).toEqual({ reverted: ['cfg.txt'] });
374
- });
375
-
376
- test('landedCommitIsAncestorOfHead: empty/unknown sha is false, never throws', async () => {
377
- const { dir } = fixtureRepo();
378
- expect(await scheduler.landedCommitIsAncestorOfHead(dir, '')).toBe(false);
379
- expect(await scheduler.landedCommitIsAncestorOfHead(dir, 'deadbeefdeadbeef')).toBe(false);
380
- });
@@ -1,43 +0,0 @@
1
- /**
2
- * scheduler-sigterm-commit.test.cjs — a run SIGTERM'd (exit 143) mid an
3
- * interactive/headless-incompatible AC step (xvfb Electron screenshot,
4
- * playwright electron.launch — see the 776/779 incidents, 2026-07-30) can
5
- * still have landed its deliverable commit before it died. classifySigtermWithCommit
6
- * decides whether that run should be routed to needs_review (commit found —
7
- * a human should verify the rest of the AC) instead of staying `failed`
8
- * forever, without ever silently auto-promoting to `completed`.
9
- *
10
- * Run: timeout 120 npx vitest run src/main/__tests__/scheduler-sigterm-commit.test.cjs
11
- */
12
-
13
- 'use strict';
14
-
15
- import { test, expect } from 'vitest';
16
- const { classifySigtermWithCommit } = require('../scheduler.cjs');
17
-
18
- test('classifySigtermWithCommit: exit 143 + commit found in window → needs_review', () => {
19
- const decision = classifySigtermWithCommit(143, true);
20
- expect(decision.status).toBe('needs_review');
21
- expect(decision.reason).toMatch(/SIGTERM/);
22
- expect(decision.reason).toMatch(/verify AC/i);
23
- });
24
-
25
- test('classifySigtermWithCommit: exit 143 + no commit found in window → still failed (regression check)', () => {
26
- const decision = classifySigtermWithCommit(143, false);
27
- expect(decision).toBeNull();
28
- });
29
-
30
- test('classifySigtermWithCommit: exit 1 (non-143 code) is unaffected even with a commit found', () => {
31
- const decision = classifySigtermWithCommit(1, true);
32
- expect(decision).toBeNull();
33
- });
34
-
35
- test('classifySigtermWithCommit: exit 137 (SIGKILL) is unaffected — scoped narrowly to 143', () => {
36
- const decision = classifySigtermWithCommit(137, true);
37
- expect(decision).toBeNull();
38
- });
39
-
40
- test('classifySigtermWithCommit: exit 0 is unaffected', () => {
41
- const decision = classifySigtermWithCommit(0, true);
42
- expect(decision).toBeNull();
43
- });
@@ -1,126 +0,0 @@
1
- /**
2
- * scheduler-stall-per-project.test.cjs — unit tests for computeStallSummary's
3
- * per-project `stalled` verdict and findStaleQuarantinedJobs' age-based
4
- * escalation.
5
- *
6
- * Covers the exact burrow-vs-others shape observed live: one project (burrow)
7
- * holds only quarantined rows (0 running, 0 pending) while another project
8
- * has running + pending work — the machine-wide `stalled` boolean reads
9
- * false (masking burrow), but burrow's own byProject entry must read true.
10
- *
11
- * Run: timeout 120 npx vitest run src/main/__tests__/scheduler-stall-per-project.test.cjs
12
- */
13
-
14
- 'use strict';
15
-
16
- // vitest, NOT node:test — this repo's suite is vitest-only (see CLAUDE.md:
17
- // "This repo does not use `node --test`"). A node:test file loads under
18
- // vitest as "No test suite found" and contributes zero tests, so the guard
19
- // silently doesn't exist. node:assert works fine inside a vitest run.
20
- import { test } from 'vitest';
21
- const assert = require('node:assert/strict');
22
- const { computeStallSummary, findStaleQuarantinedJobs, QUARANTINE_ESCALATE_MS } = require('../scheduler.cjs');
23
-
24
- test('computeStallSummary: burrow fully stalled (quarantined only) while another project is busy — machine-wide false, burrow true', () => {
25
- const state = {
26
- paused: null,
27
- jobs: [
28
- { slug: '821-a', cwd: '/home/bilko/Projects/burrow', status: 'quarantined' },
29
- { slug: '822-b', cwd: '/home/bilko/Projects/burrow', status: 'quarantined' },
30
- { slug: '823-c', cwd: '/home/bilko/Projects/burrow', status: 'quarantined' },
31
- { slug: '824-d', cwd: '/home/bilko/Projects/burrow', status: 'quarantined' },
32
- { slug: '900-e', cwd: '/home/bilko/Projects/other', status: 'running' },
33
- { slug: '901-f', cwd: '/home/bilko/Projects/other', status: 'pending' },
34
- ],
35
- invalidJobs: [],
36
- };
37
- const summary = computeStallSummary(state);
38
- assert.strictEqual(summary.stalled, false, 'machine-wide must NOT read stalled — other project is busy');
39
- assert.strictEqual(summary.byProject['/home/bilko/Projects/burrow'].stalled, true, 'burrow must read stalled on its own');
40
- assert.strictEqual(summary.byProject['/home/bilko/Projects/other'].stalled, false);
41
- });
42
-
43
- test('computeStallSummary: both projects busy — neither stalled', () => {
44
- const state = {
45
- paused: null,
46
- jobs: [
47
- { slug: 'a', cwd: '/p1', status: 'running' },
48
- { slug: 'b', cwd: '/p2', status: 'pending' },
49
- ],
50
- invalidJobs: [],
51
- };
52
- const summary = computeStallSummary(state);
53
- assert.strictEqual(summary.stalled, false);
54
- assert.strictEqual(summary.byProject['/p1'].stalled, false);
55
- assert.strictEqual(summary.byProject['/p2'].stalled, false);
56
- });
57
-
58
- test('computeStallSummary: both projects stalled — machine-wide AND both per-project read true', () => {
59
- const state = {
60
- paused: null,
61
- jobs: [
62
- { slug: 'a', cwd: '/p1', status: 'failed' },
63
- { slug: 'b', cwd: '/p2', status: 'needs_review' },
64
- ],
65
- invalidJobs: [],
66
- };
67
- const summary = computeStallSummary(state);
68
- assert.strictEqual(summary.stalled, true);
69
- assert.strictEqual(summary.byProject['/p1'].stalled, true);
70
- assert.strictEqual(summary.byProject['/p2'].stalled, true);
71
- });
72
-
73
- test('computeStallSummary: paused scheduler never reads stalled, machine-wide or per-project', () => {
74
- const state = {
75
- paused: { reason: 'rate_limit' },
76
- jobs: [{ slug: 'a', cwd: '/p1', status: 'quarantined' }],
77
- invalidJobs: [],
78
- };
79
- const summary = computeStallSummary(state);
80
- assert.strictEqual(summary.stalled, false);
81
- assert.strictEqual(summary.byProject['/p1'].stalled, false);
82
- });
83
-
84
- test('findStaleQuarantinedJobs: fires past threshold, not before', () => {
85
- const now = Date.parse('2026-08-08T12:00:00.000Z');
86
- const jobs = [
87
- {
88
- slug: 'fresh',
89
- cwd: '/p1',
90
- status: 'quarantined',
91
- statusHistory: [{ to: 'quarantined', at: new Date(now - 1 * 60 * 60_000).toISOString() }],
92
- },
93
- {
94
- slug: 'stale',
95
- cwd: '/p1',
96
- status: 'quarantined',
97
- statusHistory: [{ to: 'quarantined', at: new Date(now - 25 * 60 * 60_000).toISOString() }],
98
- },
99
- {
100
- slug: 'exactly-at-threshold',
101
- cwd: '/p1',
102
- status: 'quarantined',
103
- statusHistory: [{ to: 'quarantined', at: new Date(now - QUARANTINE_ESCALATE_MS).toISOString() }],
104
- },
105
- { slug: 'no-history', cwd: '/p1', status: 'quarantined' },
106
- { slug: 'not-quarantined', cwd: '/p1', status: 'pending' },
107
- ];
108
- const stale = findStaleQuarantinedJobs(jobs, now, QUARANTINE_ESCALATE_MS);
109
- const slugs = stale.map((s) => s.slug).sort();
110
- assert.deepStrictEqual(slugs, ['exactly-at-threshold', 'stale']);
111
- assert.strictEqual(stale.find((s) => s.slug === 'stale').cwd, '/p1');
112
- });
113
-
114
- test('computeStallSummary: a fully drained project (all completed) is idle, not stalled', () => {
115
- const state = {
116
- paused: null,
117
- jobs: [
118
- { slug: 'a', cwd: '/p1', status: 'completed' },
119
- { slug: 'b', cwd: '/p2', status: 'running' },
120
- ],
121
- invalidJobs: [],
122
- };
123
- const summary = computeStallSummary(state);
124
- assert.strictEqual(summary.byProject['/p1'].stalled, false);
125
- assert.strictEqual(computeStallSummary({ paused: null, jobs: [{ slug: 'a', cwd: '/p1', status: 'completed' }], invalidJobs: [] }).stalled, false);
126
- });