claude-code-session-manager 0.97.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.
- package/README.md +3 -3
- package/bin/cli.cjs +16 -4
- package/bin/node-floor.cjs +41 -0
- package/dist/assets/{DataModel-D93FoaOm.js → DataModel-HdR0AxFq.js} +1 -1
- package/dist/assets/{History-CXxxqNP1.js → History-Dr4Jr_5z.js} +2 -2
- package/dist/assets/{Hooks-CzeYFQjq.js → Hooks-NhrvH3JP.js} +3 -3
- package/dist/assets/{Library-D2zPkwOC.js → Library-Dv_EtIMr.js} +1 -1
- package/dist/assets/{MarkdownEditor-DbinP78A.js → MarkdownEditor-DTKDWV_n.js} +1 -1
- package/dist/assets/{McpServers-Bu_sVGLr.js → McpServers-M034G9B3.js} +2 -2
- package/dist/assets/{Memory-BgiI6LZ_.js → Memory-DzF1B4gx.js} +6 -6
- package/dist/assets/{Permissions-C1MMzZRm.js → Permissions-DrgbSGWl.js} +3 -3
- package/dist/assets/{Plugins-Dhu6wAZi.js → Plugins-Bd3ef35w.js} +2 -2
- package/dist/assets/{ProvenanceBadge-C3AcWKMG.js → ProvenanceBadge-DcBHT1Iy.js} +1 -1
- package/dist/assets/{SaveBar-plwYm0iO.js → SaveBar-rimJem-Y.js} +1 -1
- package/dist/assets/Scheduler-DjgFJl2w.js +16 -0
- package/dist/assets/{ScopeSwitcher-DFy0vv_o.js → ScopeSwitcher-CnAzTBrl.js} +1 -1
- package/dist/assets/Settings-Dc1F_sSg.js +3 -0
- package/dist/assets/{SkillReferenceGraph-DsI7hRPB.js → SkillReferenceGraph-B9aZDecM.js} +1 -1
- package/dist/assets/{Skills-3E748UfB.js → Skills-DRXd18gu.js} +2 -2
- package/dist/assets/{SystemPrompt-BqmfUJOd.js → SystemPrompt-ahy5-Fwe.js} +1 -1
- package/dist/assets/{TagLibrary-CPz6fO8Q.js → TagLibrary-C_tToDeL.js} +1 -1
- package/dist/assets/{TiptapBody-D9EoBQ1P.js → TiptapBody-DvdefS6K.js} +1 -1
- package/dist/assets/{Toggle-BHAmZNDn.js → Toggle-6Jl5Njc6.js} +1 -1
- package/dist/assets/{index-CKH5Uxik.css → index-Bta-hwud.css} +1 -1
- package/dist/assets/{index-tn5JIVPj.js → index-vx8O73l8.js} +497 -502
- package/dist/assets/{settingsSchema-Crqy_aNz.js → settingsSchema-D6iRguNV.js} +1 -1
- package/dist/index.html +2 -2
- package/package.json +26 -29
- package/plugins/CLAUDE.md +6 -6
- package/plugins/session-manager-dev/skills/builder/4-manual/SKILL.md +23 -19
- package/plugins/session-manager-dev/skills/builder/SKILL.md +3 -3
- package/plugins/session-manager-dev/skills/develop/SKILL.md +254 -510
- package/plugins/session-manager-dev/skills/develop/standards.md +17 -22
- package/scripts/README.md +3 -11
- package/scripts/audit-ops-hygiene.cjs +3 -3
- package/scripts/hooks/lib/guard-prd-writes-policy.cjs +1 -1
- package/scripts/hooks/lib/guard-self-schedule-policy.cjs +1 -1
- package/scripts/mint-epic.cjs +2 -3
- package/scripts/scheduler-mcp-server.cjs +36 -7
- package/src/main/agentLibrary.cjs +22 -2
- package/src/main/build-info.json +4 -4
- package/src/main/config.cjs +41 -38
- package/src/main/docEdit.cjs +4 -1
- package/src/main/files.cjs +2 -5
- package/src/main/health.cjs +1 -1
- package/src/main/index.cjs +23 -10
- package/src/main/ipcSchemas.cjs +28 -35
- package/src/main/lib/agentPersonaSchema.cjs +13 -2
- package/src/main/lib/atomicFs.cjs +116 -0
- package/src/main/lib/branchSweep.cjs +13 -12
- package/src/main/lib/buildTarget.cjs +3 -3
- package/src/main/lib/claudeCliCaps.cjs +129 -0
- package/src/main/lib/credentials.cjs +2 -4
- package/src/main/lib/crossProjectFeedback.cjs +3 -3
- package/src/main/lib/cwdClassify.cjs +15 -3
- package/src/main/lib/definitionOfDone.cjs +207 -125
- package/src/main/lib/dodDrainHook.cjs +11 -5
- package/src/main/lib/epicMint.cjs +2 -4
- package/src/main/lib/epicStatusMirror.cjs +8 -10
- package/src/main/lib/epicWorktreeProjectConfig.cjs +2 -4
- package/src/main/lib/gateAuthority.cjs +96 -0
- package/src/main/lib/gitExec.cjs +69 -0
- package/src/main/lib/gitWorktree.cjs +656 -92
- package/src/main/lib/instanceLock.cjs +5 -8
- package/src/main/lib/launchFailure.cjs +2 -3
- package/src/main/lib/macroLibrary.cjs +386 -0
- package/src/main/lib/mcpToolCatalog.cjs +26 -17
- package/src/main/lib/needsReviewLedger.cjs +1 -1
- package/src/main/lib/opsErrorLog.cjs +11 -1
- package/src/main/lib/opsOwnership.cjs +0 -5
- package/src/main/lib/pidAlive.cjs +32 -0
- package/src/main/lib/prdCreate.cjs +153 -19
- package/src/main/lib/prdDisposition.cjs +2 -2
- package/src/main/lib/prdGateFiles.cjs +284 -0
- package/src/main/lib/prdLocations.cjs +61 -0
- package/src/main/lib/prdMigration.cjs +2 -3
- package/src/main/lib/prdSizing.cjs +2 -1
- package/src/main/lib/promptSessionSchema.cjs +10 -2
- package/src/main/lib/rcaReport.cjs +4 -6
- package/src/main/lib/reaperHelpers.cjs +8 -1
- package/src/main/lib/reservationExpiry.cjs +6 -1
- package/src/main/lib/reviewNotice.cjs +263 -0
- package/src/main/lib/runClaudeP.cjs +4 -1
- package/src/main/lib/schedulerPaths.cjs +22 -2
- package/src/main/lib/sessionSlots.cjs +2 -4
- package/src/main/lib/shippedPersonaSeeds.cjs +179 -0
- package/src/main/lib/timeoutShim.cjs +123 -0
- package/src/main/lib/timeoutShimScript.cjs +275 -0
- package/src/main/lib/upgradeDrain.cjs +4 -10
- package/src/main/lib/watchdogHelpers.cjs +33 -30
- package/src/main/lib/workTypeLibrary.cjs +7 -1
- package/src/main/promptSessionEvents.cjs +37 -13
- package/src/main/queueOps.cjs +17 -6
- package/src/main/scheduler.cjs +975 -203
- package/src/main/seedAgentPersonas.cjs +278 -23
- package/src/main/supervisor.cjs +4 -1
- package/src/main/templates/PRD_AUTHORING.md +126 -406
- package/src/preload/__tests__/preload-surface.test.cjs +68 -0
- package/src/preload/api.d.ts +41 -94
- package/src/preload/index.cjs +14 -9
- package/src/seed/agents/architect.md +1 -0
- package/src/seed/agents/dev-lead.md +17 -18
- package/src/seed/agents/project-home-builder.md +1 -0
- package/src/seed/agents/validator.md +10 -4
- package/dist/assets/HostBilko-nESrTRIg.js +0 -1
- package/dist/assets/Scheduler-BVYTeh39.js +0 -16
- package/dist/assets/Settings-DIhGgdfs.js +0 -3
- package/src/main/__tests__/activeIndexMerge.test.cjs +0 -235
- package/src/main/__tests__/agentEffortResolve.test.cjs +0 -117
- package/src/main/__tests__/agentLibrary.test.cjs +0 -276
- package/src/main/__tests__/agentModelResolve.test.cjs +0 -311
- package/src/main/__tests__/agentOverlayWrite.test.cjs +0 -95
- package/src/main/__tests__/bilkoHost-deriveSlug.test.cjs +0 -26
- package/src/main/__tests__/bilkoHost-integration.test.cjs +0 -118
- package/src/main/__tests__/bilkoHostCore.test.cjs +0 -72
- package/src/main/__tests__/broadcastCoalescer.test.cjs +0 -122
- package/src/main/__tests__/chat-cancel-terminal.test.cjs +0 -120
- package/src/main/__tests__/chat-dead-channels.test.cjs +0 -63
- package/src/main/__tests__/chat-exit-close-race.test.cjs +0 -146
- package/src/main/__tests__/chat-mcp-consent-notice.test.cjs +0 -139
- package/src/main/__tests__/chat-preamble-anchors.test.cjs +0 -100
- package/src/main/__tests__/chat-queue.test.cjs +0 -97
- package/src/main/__tests__/chat-stop-signal.test.cjs +0 -89
- package/src/main/__tests__/chatRunner-epic-worktree-execcwd.test.cjs +0 -125
- package/src/main/__tests__/chatRunner-session-flag-retry.test.cjs +0 -252
- package/src/main/__tests__/classifyPromptTicket.test.cjs +0 -101
- package/src/main/__tests__/classifyTranscriptLine.test.cjs +0 -201
- package/src/main/__tests__/computeDepHistorySatisfaction.test.cjs +0 -66
- package/src/main/__tests__/config-readText-bounded.test.cjs +0 -84
- package/src/main/__tests__/configWriteBoundaryOwners.test.cjs +0 -59
- package/src/main/__tests__/crossProjectFeedback.test.cjs +0 -334
- package/src/main/__tests__/crossProjectFeedbackRoutes.test.cjs +0 -161
- package/src/main/__tests__/dep-orphan-archive-health.test.cjs +0 -77
- package/src/main/__tests__/develop-skill-failure-modes.test.cjs +0 -70
- package/src/main/__tests__/docEdit.test.cjs +0 -244
- package/src/main/__tests__/dod-batchkey.test.cjs +0 -183
- package/src/main/__tests__/dod-drain-hook.test.cjs +0 -302
- package/src/main/__tests__/dod-report.test.cjs +0 -304
- package/src/main/__tests__/dod-reverify.test.cjs +0 -285
- package/src/main/__tests__/epicContextDigest.test.cjs +0 -174
- package/src/main/__tests__/epicMint.test.cjs +0 -332
- package/src/main/__tests__/epicMintTelemetryTap.test.cjs +0 -64
- package/src/main/__tests__/epicStatusMirror.test.cjs +0 -110
- package/src/main/__tests__/epicValidationHook.test.cjs +0 -291
- package/src/main/__tests__/exchanges.test.cjs +0 -122
- package/src/main/__tests__/exchangesPromptId.test.cjs +0 -61
- package/src/main/__tests__/extractJson.test.cjs +0 -51
- package/src/main/__tests__/files-reject-credentials.test.cjs +0 -40
- package/src/main/__tests__/fixtures/1218-fo-01-move-scripts-lib-into-src-main-lib.log +0 -556
- package/src/main/__tests__/flatPrdTickSweep.test.cjs +0 -110
- package/src/main/__tests__/health-build-freshness.test.cjs +0 -39
- package/src/main/__tests__/health-claude-md-budget.test.cjs +0 -57
- package/src/main/__tests__/health-credentials.test.cjs +0 -81
- package/src/main/__tests__/health-delegation-chain.test.cjs +0 -124
- package/src/main/__tests__/health-per-project-stall.test.cjs +0 -84
- package/src/main/__tests__/health-prd-migration.test.cjs +0 -37
- package/src/main/__tests__/health-queue-dispatch.test.cjs +0 -135
- package/src/main/__tests__/health-starve-escalation.test.cjs +0 -94
- package/src/main/__tests__/health-tick-liveness.test.cjs +0 -179
- package/src/main/__tests__/health-usage-poller.test.cjs +0 -144
- package/src/main/__tests__/health-worktree-cap-blocked.test.cjs +0 -65
- package/src/main/__tests__/heapSnapshot.test.cjs +0 -121
- package/src/main/__tests__/historyAggregatorIntraday.test.cjs +0 -313
- package/src/main/__tests__/historyDashboard.test.cjs +0 -163
- package/src/main/__tests__/historyRollup.test.cjs +0 -333
- package/src/main/__tests__/intradayRefresh.test.cjs +0 -39
- package/src/main/__tests__/ipcSchemas-dependsOn.test.cjs +0 -39
- package/src/main/__tests__/kg-augment.test.cjs +0 -195
- package/src/main/__tests__/loadGateDetailTick.test.cjs +0 -31
- package/src/main/__tests__/machineProfile.test.cjs +0 -152
- package/src/main/__tests__/mcpStatus.test.cjs +0 -61
- package/src/main/__tests__/memoryAggregate.test.cjs +0 -109
- package/src/main/__tests__/memoryStale.test.cjs +0 -88
- package/src/main/__tests__/needsReviewLedger.test.cjs +0 -162
- package/src/main/__tests__/openExternalApp-spawn-error.test.cjs +0 -25
- package/src/main/__tests__/opsErrorLog.test.cjs +0 -109
- package/src/main/__tests__/opsErrorLogTelemetryTap.test.cjs +0 -173
- package/src/main/__tests__/personaMerge.test.cjs +0 -169
- package/src/main/__tests__/planValidator.test.cjs +0 -125
- package/src/main/__tests__/pollLoop-dispatch-on-failure.test.cjs +0 -176
- package/src/main/__tests__/prd-group-allocator.test.cjs +0 -119
- package/src/main/__tests__/prdAdminRouteParity.test.cjs +0 -70
- package/src/main/__tests__/prdAdminRoutes.test.cjs +0 -718
- package/src/main/__tests__/prdAgentType.test.cjs +0 -103
- package/src/main/__tests__/prdAuthoringSeed.test.cjs +0 -39
- package/src/main/__tests__/prdCreate.test.cjs +0 -979
- package/src/main/__tests__/prdCreateDisposition.test.cjs +0 -201
- package/src/main/__tests__/prdCreatePlanId.test.cjs +0 -132
- package/src/main/__tests__/prdFrontmatterAgentType.test.cjs +0 -117
- package/src/main/__tests__/prdFrontmatterDependsOn.test.cjs +0 -136
- package/src/main/__tests__/prdFrontmatterDisposition.test.cjs +0 -125
- package/src/main/__tests__/prdFrontmatterQuietMachine.test.cjs +0 -108
- package/src/main/__tests__/prdLocations.test.cjs +0 -195
- package/src/main/__tests__/prdLocationsArchived.test.cjs +0 -201
- package/src/main/__tests__/prdMigration.test.cjs +0 -349
- package/src/main/__tests__/prdMigrationLegacyAdopt.test.cjs +0 -91
- package/src/main/__tests__/prdParserHighWater.test.cjs +0 -74
- package/src/main/__tests__/prdParserSourcePromptId.test.cjs +0 -65
- package/src/main/__tests__/prdSetDisposition.test.cjs +0 -222
- package/src/main/__tests__/prdSizing.test.cjs +0 -106
- package/src/main/__tests__/prdSourcePromptIdBackfill.test.cjs +0 -118
- package/src/main/__tests__/prdUpdateDependsOn.test.cjs +0 -160
- package/src/main/__tests__/proc-role-env.test.cjs +0 -125
- package/src/main/__tests__/procname-claude-spawn-sites.test.cjs +0 -304
- package/src/main/__tests__/procname-sm-processes.test.cjs +0 -127
- package/src/main/__tests__/projectHomeAdminRoutes.test.cjs +0 -177
- package/src/main/__tests__/projectPages.test.cjs +0 -137
- package/src/main/__tests__/promptSessionEvents.test.cjs +0 -234
- package/src/main/__tests__/promptSessionSchema.test.cjs +0 -101
- package/src/main/__tests__/promptSessionTranscript.test.cjs +0 -0
- package/src/main/__tests__/promptSessionsCreateEpicHandler.test.cjs +0 -159
- package/src/main/__tests__/pty-epic-worktree-spawn-cwd.test.cjs +0 -282
- package/src/main/__tests__/pty-session-open-telemetry.test.cjs +0 -96
- package/src/main/__tests__/pty-write-result.test.cjs +0 -46
- package/src/main/__tests__/queue-health-verdict.test.cjs +0 -170
- package/src/main/__tests__/queue-starvation-dispatch-driver.test.cjs +0 -286
- package/src/main/__tests__/queue-starvation-per-project.test.cjs +0 -147
- package/src/main/__tests__/queueHistory.test.cjs +0 -355
- package/src/main/__tests__/queueOps-interactive-ac-lint.test.cjs +0 -65
- package/src/main/__tests__/queueOpsArchiveDestination.test.cjs +0 -65
- package/src/main/__tests__/queueOpsAutoArchive.test.cjs +0 -154
- package/src/main/__tests__/rateLimitPollerStreak.test.cjs +0 -128
- package/src/main/__tests__/rcaReport.test.cjs +0 -266
- package/src/main/__tests__/reconcileFlatPrdSweep.test.cjs +0 -119
- package/src/main/__tests__/reconcileTiming.test.cjs +0 -135
- package/src/main/__tests__/runLogRetention.test.cjs +0 -489
- package/src/main/__tests__/runVerify-atomic-verdicts.test.cjs +0 -26
- package/src/main/__tests__/runVerify-blocked-by-foreign-wip.test.cjs +0 -58
- package/src/main/__tests__/runVerify-landed-commit-outranks.test.cjs +0 -191
- package/src/main/__tests__/runVerify-policy-denial.test.cjs +0 -89
- package/src/main/__tests__/runVerify-transcript-commit-evidence.test.cjs +0 -225
- package/src/main/__tests__/runVerify.test.cjs +0 -1784
- package/src/main/__tests__/scheduleJobSchema.test.cjs +0 -127
- package/src/main/__tests__/scheduleJobStatusDrift.test.cjs +0 -65
- package/src/main/__tests__/scheduleJobTransitions.test.cjs +0 -277
- package/src/main/__tests__/scheduleJobTransitionsGrep.test.cjs +0 -59
- package/src/main/__tests__/scheduleJobTransitionsTelemetryTap.test.cjs +0 -72
- package/src/main/__tests__/scheduler-admin-routes.test.cjs +0 -199
- package/src/main/__tests__/scheduler-adopted-run-supervision.test.cjs +0 -143
- package/src/main/__tests__/scheduler-already-satisfied-on-main.test.cjs +0 -105
- package/src/main/__tests__/scheduler-archive-completed-prd.test.cjs +0 -102
- package/src/main/__tests__/scheduler-archived-twin-guard.test.cjs +0 -155
- package/src/main/__tests__/scheduler-autofix-outcome.test.cjs +0 -188
- package/src/main/__tests__/scheduler-autofix-select.test.cjs +0 -439
- package/src/main/__tests__/scheduler-autopromote.test.cjs +0 -51
- package/src/main/__tests__/scheduler-bash-timeout-env.test.cjs +0 -101
- package/src/main/__tests__/scheduler-blocked-by-foreign-wip.test.cjs +0 -107
- package/src/main/__tests__/scheduler-boot-orphans.test.cjs +0 -153
- package/src/main/__tests__/scheduler-broadcast-reconcile.test.cjs +0 -121
- package/src/main/__tests__/scheduler-clear-queue-history.test.cjs +0 -134
- package/src/main/__tests__/scheduler-commit-guard-noop.test.cjs +0 -244
- package/src/main/__tests__/scheduler-committed-in-window.test.cjs +0 -182
- package/src/main/__tests__/scheduler-cross-project-batch.test.cjs +0 -43
- package/src/main/__tests__/scheduler-default-eligible-heal.test.cjs +0 -168
- package/src/main/__tests__/scheduler-dispatch-loop.test.cjs +0 -58
- package/src/main/__tests__/scheduler-effective-concurrency.test.cjs +0 -81
- package/src/main/__tests__/scheduler-epic-digest.test.cjs +0 -227
- package/src/main/__tests__/scheduler-failed-autoreset.test.cjs +0 -121
- package/src/main/__tests__/scheduler-finalize-dispatch-guards.test.cjs +0 -229
- package/src/main/__tests__/scheduler-find-prd-dir.test.cjs +0 -75
- package/src/main/__tests__/scheduler-fix-plan-path.test.cjs +0 -119
- package/src/main/__tests__/scheduler-force-tick-outcome.test.cjs +0 -46
- package/src/main/__tests__/scheduler-foreign-wip-manifest.test.cjs +0 -78
- package/src/main/__tests__/scheduler-gate-shadow.test.cjs +0 -119
- package/src/main/__tests__/scheduler-guard-verdict-autoresolve.test.cjs +0 -390
- package/src/main/__tests__/scheduler-heal-refusal.test.cjs +0 -61
- package/src/main/__tests__/scheduler-heartbeat-payload.test.cjs +0 -80
- package/src/main/__tests__/scheduler-inplace-salvage.test.cjs +0 -323
- package/src/main/__tests__/scheduler-integration-failure-stamp.test.cjs +0 -41
- package/src/main/__tests__/scheduler-investigation-clean-skip.test.cjs +0 -63
- package/src/main/__tests__/scheduler-investigation-prompt.test.cjs +0 -123
- package/src/main/__tests__/scheduler-job-budget.test.cjs +0 -172
- package/src/main/__tests__/scheduler-job-overrun.test.cjs +0 -175
- package/src/main/__tests__/scheduler-launch-failure.test.cjs +0 -199
- package/src/main/__tests__/scheduler-leftover-fields.test.cjs +0 -52
- package/src/main/__tests__/scheduler-leftover-quarantine.test.cjs +0 -199
- package/src/main/__tests__/scheduler-looks-done.test.cjs +0 -537
- package/src/main/__tests__/scheduler-manual-pause.test.cjs +0 -118
- package/src/main/__tests__/scheduler-mechanical-recovery.test.cjs +0 -245
- package/src/main/__tests__/scheduler-meta-code-sha.test.cjs +0 -46
- package/src/main/__tests__/scheduler-needs-review-autoresolve.test.cjs +0 -197
- package/src/main/__tests__/scheduler-never-stop.test.cjs +0 -157
- package/src/main/__tests__/scheduler-no-dead-end-status.test.cjs +0 -152
- package/src/main/__tests__/scheduler-no-orphan-run-dir.test.cjs +0 -81
- package/src/main/__tests__/scheduler-notify-originating-tab-transcript.test.cjs +0 -87
- package/src/main/__tests__/scheduler-notify-originating-tab.test.cjs +0 -343
- package/src/main/__tests__/scheduler-periodic-reverify-guard.test.cjs +0 -217
- package/src/main/__tests__/scheduler-porcelain-rename.test.cjs +0 -164
- package/src/main/__tests__/scheduler-prd-missing-skip.test.cjs +0 -161
- package/src/main/__tests__/scheduler-prd-persona-spawn.test.cjs +0 -178
- package/src/main/__tests__/scheduler-quarantine-autoresolve.test.cjs +0 -165
- package/src/main/__tests__/scheduler-quiet-machine-lease.test.cjs +0 -257
- package/src/main/__tests__/scheduler-rate-limit-cooldown-freshness.test.cjs +0 -123
- package/src/main/__tests__/scheduler-rate-limit-pause.test.cjs +0 -152
- package/src/main/__tests__/scheduler-rate-limit-spin-guard.test.cjs +0 -156
- package/src/main/__tests__/scheduler-reap-dead-running-jobs.test.cjs +0 -754
- package/src/main/__tests__/scheduler-reaper-helpers-basics.test.cjs +0 -87
- package/src/main/__tests__/scheduler-reconcile-cwd-preserve.test.cjs +0 -100
- package/src/main/__tests__/scheduler-reconcile-history-backfill.test.cjs +0 -105
- package/src/main/__tests__/scheduler-reconcile-invalid-repair.test.cjs +0 -203
- package/src/main/__tests__/scheduler-reconcile-quarantine.test.cjs +0 -247
- package/src/main/__tests__/scheduler-reset-job-fields-guard.test.cjs +0 -77
- package/src/main/__tests__/scheduler-resume-recovery.test.cjs +0 -254
- package/src/main/__tests__/scheduler-shard-quarantine.test.cjs +0 -115
- package/src/main/__tests__/scheduler-shared-tree-guard.test.cjs +0 -380
- package/src/main/__tests__/scheduler-sigterm-commit.test.cjs +0 -43
- package/src/main/__tests__/scheduler-stall-per-project.test.cjs +0 -126
- package/src/main/__tests__/scheduler-starve-escalation.test.cjs +0 -154
- package/src/main/__tests__/scheduler-stranded-autofix-park.test.cjs +0 -252
- package/src/main/__tests__/scheduler-stranded-investigation.test.cjs +0 -185
- package/src/main/__tests__/scheduler-stuck-failed-escalation.test.cjs +0 -136
- package/src/main/__tests__/scheduler-supervisor-record.test.cjs +0 -81
- package/src/main/__tests__/scheduler-tick-cancel-token.test.cjs +0 -54
- package/src/main/__tests__/scheduler-tick-wedge.test.cjs +0 -172
- package/src/main/__tests__/scheduler-transient-failure.test.cjs +0 -141
- package/src/main/__tests__/scheduler-unreadable-queue-guard.test.cjs +0 -62
- package/src/main/__tests__/scheduler-utilization-hold.test.cjs +0 -89
- package/src/main/__tests__/scheduler-verify-prd-path.test.cjs +0 -109
- package/src/main/__tests__/scheduler-worktree-cap-defer.test.cjs +0 -234
- package/src/main/__tests__/scheduler-worktree-exec-cwd.test.cjs +0 -120
- package/src/main/__tests__/scheduler-writeprd-epic-rollback.test.cjs +0 -105
- package/src/main/__tests__/schedulerBatchRootBlocker.test.cjs +0 -117
- package/src/main/__tests__/schedulerStateSidecarRestore.test.cjs +0 -110
- package/src/main/__tests__/seedAgentPersonas.test.cjs +0 -184
- package/src/main/__tests__/seedSchedulerMcp.test.cjs +0 -211
- package/src/main/__tests__/seedStatus.test.cjs +0 -100
- package/src/main/__tests__/seedValidatorPersona.test.cjs +0 -116
- package/src/main/__tests__/stop-signal-anchor.test.cjs +0 -75
- package/src/main/__tests__/telemetryClient.test.cjs +0 -1055
- package/src/main/__tests__/telemetryContract.test.cjs +0 -930
- package/src/main/__tests__/telemetrySettings.test.cjs +0 -210
- package/src/main/__tests__/transcripts-batch-flush.test.cjs +0 -249
- package/src/main/__tests__/transcripts-doFlush-array.test.cjs +0 -124
- package/src/main/__tests__/transcripts-paged-reads.test.cjs +0 -241
- package/src/main/__tests__/transcripts-worktree-epic-path.test.cjs +0 -154
- package/src/main/__tests__/transcriptsUsageFor.test.cjs +0 -206
- package/src/main/__tests__/uniquePrdNumbers.test.cjs +0 -153
- package/src/main/__tests__/usageSingleFlight.test.cjs +0 -169
- package/src/main/__tests__/validationSentinels.test.cjs +0 -84
- package/src/main/__tests__/workTypeLibrary.test.cjs +0 -89
- package/src/main/bilkoHost.cjs +0 -314
- package/src/main/bilkoHostCore.cjs +0 -89
- package/src/main/lib/__tests__/active-sessions.test.cjs +0 -251
- package/src/main/lib/__tests__/activeIndexRebuild.test.cjs +0 -179
- package/src/main/lib/__tests__/agentPersonaSchema.test.cjs +0 -67
- package/src/main/lib/__tests__/auditLog.test.cjs +0 -38
- package/src/main/lib/__tests__/bootSelfHeal.test.cjs +0 -107
- package/src/main/lib/__tests__/branchSweep.test.cjs +0 -164
- package/src/main/lib/__tests__/buildIdentity.test.cjs +0 -121
- package/src/main/lib/__tests__/buildTarget.test.cjs +0 -52
- package/src/main/lib/__tests__/childWithLog.test.cjs +0 -321
- package/src/main/lib/__tests__/coldBootPromptSessionsWrite.test.cjs +0 -87
- package/src/main/lib/__tests__/crashTelemetry.test.cjs +0 -103
- package/src/main/lib/__tests__/credentials-futile-refresh.test.cjs +0 -115
- package/src/main/lib/__tests__/cwdClassify.test.cjs +0 -111
- package/src/main/lib/__tests__/definitionOfDoneSequence.test.cjs +0 -95
- package/src/main/lib/__tests__/delegationReadiness.test.cjs +0 -1175
- package/src/main/lib/__tests__/dispatchLoop.test.cjs +0 -63
- package/src/main/lib/__tests__/effectiveModelInfo.test.cjs +0 -244
- package/src/main/lib/__tests__/ephemeralCwd.test.cjs +0 -91
- package/src/main/lib/__tests__/epicDelegationStats.test.cjs +0 -137
- package/src/main/lib/__tests__/epicSpawnCwd.test.cjs +0 -283
- package/src/main/lib/__tests__/epicSpawnPlan.test.cjs +0 -196
- package/src/main/lib/__tests__/epicTranscriptPath.test.cjs +0 -163
- package/src/main/lib/__tests__/epicWorktreeBoot.test.cjs +0 -136
- package/src/main/lib/__tests__/epicWorktreeMerge.test.cjs +0 -130
- package/src/main/lib/__tests__/epicWorktreeMint.test.cjs +0 -117
- package/src/main/lib/__tests__/epicWorktreeProjectConfig.test.cjs +0 -137
- package/src/main/lib/__tests__/fixChainDepth.test.cjs +0 -40
- package/src/main/lib/__tests__/fixtures/204-mercury-steam-horse.log.txt +0 -13
- package/src/main/lib/__tests__/fixtures/scheduler-machine.json.corrupt-1789147548 +0 -34
- package/src/main/lib/__tests__/gateFixtures.json +0 -20
- package/src/main/lib/__tests__/gitCacheBound.test.cjs +0 -69
- package/src/main/lib/__tests__/gitWorktree.test.cjs +0 -1478
- package/src/main/lib/__tests__/gitWorktreeSalvage.test.cjs +0 -107
- package/src/main/lib/__tests__/gitWorktreeSalvageDelta.test.cjs +0 -153
- package/src/main/lib/__tests__/guardShims.test.cjs +0 -158
- package/src/main/lib/__tests__/importReferences.spec.cjs +0 -56
- package/src/main/lib/__tests__/instanceLock.test.cjs +0 -173
- package/src/main/lib/__tests__/jobSupervisorRecord.test.cjs +0 -78
- package/src/main/lib/__tests__/jobWorktree.test.cjs +0 -199
- package/src/main/lib/__tests__/jobWorktreeBootLive.test.cjs +0 -82
- package/src/main/lib/__tests__/landedSinceRun.test.cjs +0 -133
- package/src/main/lib/__tests__/launchFailure.test.cjs +0 -220
- package/src/main/lib/__tests__/loadGate.test.cjs +0 -303
- package/src/main/lib/__tests__/localAdminHttp.test.cjs +0 -214
- package/src/main/lib/__tests__/loopDelay.test.cjs +0 -68
- package/src/main/lib/__tests__/mcpToolCatalog.test.cjs +0 -107
- package/src/main/lib/__tests__/modelCatalog.test.cjs +0 -202
- package/src/main/lib/__tests__/opsOwnership.test.cjs +0 -113
- package/src/main/lib/__tests__/opsRootAbsoluteCwd.test.cjs +0 -328
- package/src/main/lib/__tests__/opsRootNestedWrite.test.cjs +0 -51
- package/src/main/lib/__tests__/opsRootResolve.test.cjs +0 -149
- package/src/main/lib/__tests__/prdDeclaredPaths.test.cjs +0 -82
- package/src/main/lib/__tests__/prdDisposition.test.cjs +0 -224
- package/src/main/lib/__tests__/procIdentity.test.cjs +0 -119
- package/src/main/lib/__tests__/procName.test.cjs +0 -92
- package/src/main/lib/__tests__/projectBriefCore.test.cjs +0 -216
- package/src/main/lib/__tests__/projectRootResolve.test.cjs +0 -148
- package/src/main/lib/__tests__/queueHealth.test.cjs +0 -58
- package/src/main/lib/__tests__/queueStoreAtomicWrite.test.cjs +0 -88
- package/src/main/lib/__tests__/queueStoreMachineStateRecovery.test.cjs +0 -190
- package/src/main/lib/__tests__/quietMachineLease.test.cjs +0 -39
- package/src/main/lib/__tests__/rateLimitWindow.test.cjs +0 -88
- package/src/main/lib/__tests__/reaperHelpers.test.cjs +0 -577
- package/src/main/lib/__tests__/schedulerBatchDepends.test.cjs +0 -312
- package/src/main/lib/__tests__/schedulerBatchFairness.test.cjs +0 -213
- package/src/main/lib/__tests__/schedulerBatchLaunchHold.test.cjs +0 -125
- package/src/main/lib/__tests__/schedulerBatchProjectCap.test.cjs +0 -127
- package/src/main/lib/__tests__/schedulerBatchQuietMachine.test.cjs +0 -109
- package/src/main/lib/__tests__/schedulerMcpServerHeadlessRefusal.test.cjs +0 -71
- package/src/main/lib/__tests__/schedulerMcpServerHelp.test.cjs +0 -216
- package/src/main/lib/__tests__/schedulerMcpServerProjectHome.test.cjs +0 -183
- package/src/main/lib/__tests__/schedulerPaths.test.cjs +0 -226
- package/src/main/lib/__tests__/schedulerPathsWorktree.test.cjs +0 -133
- package/src/main/lib/__tests__/schedulerRuntimeState.test.cjs +0 -56
- package/src/main/lib/__tests__/sessionSlots.test.cjs +0 -144
- package/src/main/lib/__tests__/telemetryBacklog.test.cjs +0 -626
- package/src/main/lib/__tests__/telemetryBoot.test.cjs +0 -134
- package/src/main/lib/__tests__/telemetryConsent.test.cjs +0 -136
- package/src/main/lib/__tests__/telemetryCounters.test.cjs +0 -57
- package/src/main/lib/__tests__/telemetryCountersMetadataColumn.test.cjs +0 -98
- package/src/main/lib/__tests__/terminalRunOutcome.test.cjs +0 -200
- package/src/main/lib/__tests__/toolUseClassify.test.cjs +0 -53
- package/src/main/lib/__tests__/updateCheck.test.cjs +0 -63
- package/src/main/lib/__tests__/upgradeDrain.test.cjs +0 -130
- package/src/main/lib/__tests__/usageCircuit.test.cjs +0 -354
- package/src/main/lib/__tests__/watchdog-helpers.test.cjs +0 -375
- package/src/main/lib/__tests__/watchdog-relaunch.test.cjs +0 -266
- package/src/main/lib/kgExchangePairing.cjs +0 -75
|
@@ -1,247 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* scheduler-reconcile-quarantine.test.cjs — PRD-authoring-lockdown provenance
|
|
3
|
-
* gate: reconcile() must never turn a discovered PRD with no `createdVia`
|
|
4
|
-
* frontmatter into a runnable 'pending' queue row. It quarantines it instead
|
|
5
|
-
* (a distinct, non-runnable status), logs a warning naming the file, and
|
|
6
|
-
* audits the event — then, once the file is stamped (the Scheduler tab's
|
|
7
|
-
* "adopt PRD" action / scheduler_update_prd, both routed through
|
|
8
|
-
* remote.updatePrd), promotes the row to 'pending' on the very next pass.
|
|
9
|
-
*
|
|
10
|
-
* Mirrors scheduler-reconcile-invalid-repair.test.cjs's HOME-isolation setup.
|
|
11
|
-
*
|
|
12
|
-
* Run: timeout 120 npx vitest run src/main/__tests__/scheduler-reconcile-quarantine.test.cjs
|
|
13
|
-
*/
|
|
14
|
-
|
|
15
|
-
'use strict';
|
|
16
|
-
|
|
17
|
-
import { test, expect, beforeAll, afterAll, afterEach, vi } from 'vitest';
|
|
18
|
-
const fs = require('node:fs');
|
|
19
|
-
const os = require('node:os');
|
|
20
|
-
const path = require('node:path');
|
|
21
|
-
|
|
22
|
-
let tmpHome;
|
|
23
|
-
let originalHome;
|
|
24
|
-
let scheduler;
|
|
25
|
-
let queueStore;
|
|
26
|
-
|
|
27
|
-
beforeAll(() => {
|
|
28
|
-
originalHome = process.env.HOME;
|
|
29
|
-
tmpHome = fs.mkdtempSync(path.join(os.tmpdir(), 'sm-reconcile-quarantine-home-'));
|
|
30
|
-
process.env.HOME = tmpHome;
|
|
31
|
-
|
|
32
|
-
scheduler = require('../scheduler.cjs');
|
|
33
|
-
queueStore = require('../lib/queueStore.cjs');
|
|
34
|
-
|
|
35
|
-
if (!scheduler.PRDS_DIR.startsWith(tmpHome)) {
|
|
36
|
-
throw new Error(`refusing to run: PRDS_DIR (${scheduler.PRDS_DIR}) is not under the temp HOME (${tmpHome})`);
|
|
37
|
-
}
|
|
38
|
-
});
|
|
39
|
-
|
|
40
|
-
afterAll(() => {
|
|
41
|
-
process.env.HOME = originalHome;
|
|
42
|
-
fs.rmSync(tmpHome, { recursive: true, force: true });
|
|
43
|
-
});
|
|
44
|
-
|
|
45
|
-
afterEach(() => {
|
|
46
|
-
vi.restoreAllMocks();
|
|
47
|
-
});
|
|
48
|
-
|
|
49
|
-
function registerActiveProject(cwd) {
|
|
50
|
-
const projectsDir = path.join(tmpHome, '.claude', 'projects');
|
|
51
|
-
const slugDir = path.join(projectsDir, `fake-project-slug-${path.basename(cwd)}`);
|
|
52
|
-
fs.mkdirSync(slugDir, { recursive: true });
|
|
53
|
-
fs.writeFileSync(path.join(slugDir, 'transcript.jsonl'), JSON.stringify({ cwd }) + '\n');
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
function makeFixtureProject(prefix) {
|
|
57
|
-
const cwd = fs.mkdtempSync(path.join(os.tmpdir(), prefix));
|
|
58
|
-
registerActiveProject(cwd);
|
|
59
|
-
const opsRoot = path.join(cwd, 'session-manager-operations');
|
|
60
|
-
// Epic-scoped, not the retired flat dir: a flat PRD with no live queue row
|
|
61
|
-
// gets swept into prds-archived/ by reconcile()'s own consolidation pass
|
|
62
|
-
// (see consolidateAllFlatPrds) BEFORE it's ever scanned as a discoverable
|
|
63
|
-
// PRD — exactly the scenario every test below needs to observe, so the
|
|
64
|
-
// flat layout would race the very thing under test.
|
|
65
|
-
const prdsDir = path.join(opsRoot, 'scheduler', 'epics', 'test-epic-1', 'prds');
|
|
66
|
-
const stateDir = path.join(opsRoot, 'scheduler', 'state');
|
|
67
|
-
fs.mkdirSync(prdsDir, { recursive: true });
|
|
68
|
-
fs.mkdirSync(stateDir, { recursive: true });
|
|
69
|
-
return { cwd, prdsDir, stateDir };
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
test('reconcile() quarantines a newly-discovered PRD with no createdVia provenance', async () => {
|
|
73
|
-
const { cwd, prdsDir, stateDir } = makeFixtureProject('sm-quarantine-new-');
|
|
74
|
-
try {
|
|
75
|
-
fs.writeFileSync(
|
|
76
|
-
path.join(prdsDir, '9001-hand-written.md'),
|
|
77
|
-
`---\ntitle: Hand-written PRD\ncwd: ${cwd}\nestimateMinutes: 15\n---\n\n# Goal\nDo the thing.\n`,
|
|
78
|
-
'utf8',
|
|
79
|
-
);
|
|
80
|
-
fs.writeFileSync(path.join(stateDir, 'queue.json'), JSON.stringify({ jobs: [] }, null, 2), 'utf8');
|
|
81
|
-
|
|
82
|
-
const warnSpy = vi.spyOn(console, 'warn').mockImplementation(() => {});
|
|
83
|
-
const { auditLogPath } = require('../lib/auditLog.cjs');
|
|
84
|
-
|
|
85
|
-
queueStore.bustCwdCache();
|
|
86
|
-
const state = { jobs: [], invalidJobs: [], paused: null };
|
|
87
|
-
await scheduler.reconcile(state);
|
|
88
|
-
|
|
89
|
-
const row = state.jobs.find((j) => j.slug === '9001-hand-written');
|
|
90
|
-
expect(row).toBeDefined();
|
|
91
|
-
expect(row.status).toBe('quarantined');
|
|
92
|
-
|
|
93
|
-
const warned = warnSpy.mock.calls.some((args) =>
|
|
94
|
-
String(args[0]).includes('quarantining unstamped PRD') && String(args[0]).includes('9001-hand-written'),
|
|
95
|
-
);
|
|
96
|
-
expect(warned).toBe(true);
|
|
97
|
-
|
|
98
|
-
const auditLines = fs.readFileSync(auditLogPath(), 'utf8').trim().split('\n').filter(Boolean).map((l) => JSON.parse(l));
|
|
99
|
-
expect(auditLines.some((rec) => rec.kind === 'prd_quarantined' && rec.slug === '9001-hand-written')).toBe(true);
|
|
100
|
-
} finally {
|
|
101
|
-
fs.rmSync(cwd, { recursive: true, force: true });
|
|
102
|
-
}
|
|
103
|
-
});
|
|
104
|
-
|
|
105
|
-
test('reconcile() queues a newly-discovered PRD stamped with createdVia as pending, not quarantined', async () => {
|
|
106
|
-
const { cwd, prdsDir, stateDir } = makeFixtureProject('sm-quarantine-stamped-');
|
|
107
|
-
try {
|
|
108
|
-
fs.writeFileSync(
|
|
109
|
-
path.join(prdsDir, '9002-api-written.md'),
|
|
110
|
-
`---\ntitle: API-written PRD\ncwd: ${cwd}\nestimateMinutes: 15\ncreatedVia: scheduler-api\nissuedAt: 2026-08-07T00:00:00.000Z\n---\n\n# Goal\nDo the thing.\n`,
|
|
111
|
-
'utf8',
|
|
112
|
-
);
|
|
113
|
-
fs.writeFileSync(path.join(stateDir, 'queue.json'), JSON.stringify({ jobs: [] }, null, 2), 'utf8');
|
|
114
|
-
|
|
115
|
-
queueStore.bustCwdCache();
|
|
116
|
-
const state = { jobs: [], invalidJobs: [], paused: null };
|
|
117
|
-
await scheduler.reconcile(state);
|
|
118
|
-
|
|
119
|
-
const row = state.jobs.find((j) => j.slug === '9002-api-written');
|
|
120
|
-
expect(row).toBeDefined();
|
|
121
|
-
expect(row.status).toBe('pending');
|
|
122
|
-
} finally {
|
|
123
|
-
fs.rmSync(cwd, { recursive: true, force: true });
|
|
124
|
-
}
|
|
125
|
-
});
|
|
126
|
-
|
|
127
|
-
test('reconcile() exempts a fix-plan PRD (NN-fix-*) from quarantine even with no createdVia', async () => {
|
|
128
|
-
const { cwd, prdsDir, stateDir } = makeFixtureProject('sm-quarantine-fixplan-');
|
|
129
|
-
try {
|
|
130
|
-
fs.writeFileSync(
|
|
131
|
-
path.join(prdsDir, '9003-fix-something.md'),
|
|
132
|
-
`---\ntitle: Fix something\ncwd: ${cwd}\nestimateMinutes: 15\n---\n\n# Goal\nHeal it.\n`,
|
|
133
|
-
'utf8',
|
|
134
|
-
);
|
|
135
|
-
fs.writeFileSync(path.join(stateDir, 'queue.json'), JSON.stringify({ jobs: [] }, null, 2), 'utf8');
|
|
136
|
-
|
|
137
|
-
queueStore.bustCwdCache();
|
|
138
|
-
const state = { jobs: [], invalidJobs: [], paused: null };
|
|
139
|
-
await scheduler.reconcile(state);
|
|
140
|
-
|
|
141
|
-
const row = state.jobs.find((j) => j.slug === '9003-fix-something');
|
|
142
|
-
expect(row).toBeDefined();
|
|
143
|
-
expect(row.status).toBe('pending');
|
|
144
|
-
} finally {
|
|
145
|
-
fs.rmSync(cwd, { recursive: true, force: true });
|
|
146
|
-
}
|
|
147
|
-
});
|
|
148
|
-
|
|
149
|
-
test('reconcile() does NOT stamp investigationDepth for a createdVia-stamped PRD whose slug merely starts with "fix-" (PRD 1126/1131 regression)', async () => {
|
|
150
|
-
const { cwd, prdsDir, stateDir } = makeFixtureProject('sm-quarantine-fake-fixplan-');
|
|
151
|
-
try {
|
|
152
|
-
// Mirrors PRD 1126: authored via scheduler_create_prd (createdVia stamped),
|
|
153
|
-
// slug happens to kebab-case into "fix-..." — must NOT be treated as a
|
|
154
|
-
// genuine scheduler-authored fix plan just because the name matches.
|
|
155
|
-
fs.writeFileSync(
|
|
156
|
-
path.join(prdsDir, '9005-fix-plan-death-reopens-parent.md'),
|
|
157
|
-
`---\ntitle: Fix plan death reopens parent\ncwd: ${cwd}\nestimateMinutes: 15\ncreatedVia: scheduler-api\nissuedAt: 2026-08-07T00:00:00.000Z\n---\n\n# Goal\nDo the thing.\n`,
|
|
158
|
-
'utf8',
|
|
159
|
-
);
|
|
160
|
-
fs.writeFileSync(path.join(stateDir, 'queue.json'), JSON.stringify({ jobs: [] }, null, 2), 'utf8');
|
|
161
|
-
|
|
162
|
-
queueStore.bustCwdCache();
|
|
163
|
-
const state = { jobs: [], invalidJobs: [], paused: null };
|
|
164
|
-
await scheduler.reconcile(state);
|
|
165
|
-
|
|
166
|
-
const row = state.jobs.find((j) => j.slug === '9005-fix-plan-death-reopens-parent');
|
|
167
|
-
expect(row).toBeDefined();
|
|
168
|
-
expect(row.status).toBe('pending');
|
|
169
|
-
expect(row.isFixPlan).toBe(false);
|
|
170
|
-
expect(row.investigationDepth).toBeUndefined();
|
|
171
|
-
} finally {
|
|
172
|
-
fs.rmSync(cwd, { recursive: true, force: true });
|
|
173
|
-
}
|
|
174
|
-
});
|
|
175
|
-
|
|
176
|
-
test('reconcile() stamps isFixPlan + investigationDepth for a genuine spawnInvestigation-authored fix plan (explicit isFixPlan:true, no createdVia)', async () => {
|
|
177
|
-
const { cwd, prdsDir, stateDir } = makeFixtureProject('sm-quarantine-genuine-fixplan-');
|
|
178
|
-
try {
|
|
179
|
-
fs.writeFileSync(
|
|
180
|
-
path.join(prdsDir, '9006-fix-something.md'),
|
|
181
|
-
`---\ntitle: Fix something\ncwd: ${cwd}\nestimateMinutes: 15\nisFixPlan: true\n---\n\n# Goal\nHeal it.\n`,
|
|
182
|
-
'utf8',
|
|
183
|
-
);
|
|
184
|
-
fs.writeFileSync(path.join(stateDir, 'queue.json'), JSON.stringify({ jobs: [] }, null, 2), 'utf8');
|
|
185
|
-
|
|
186
|
-
queueStore.bustCwdCache();
|
|
187
|
-
const state = { jobs: [], invalidJobs: [], paused: null };
|
|
188
|
-
await scheduler.reconcile(state);
|
|
189
|
-
|
|
190
|
-
const row = state.jobs.find((j) => j.slug === '9006-fix-something');
|
|
191
|
-
expect(row).toBeDefined();
|
|
192
|
-
expect(row.status).toBe('pending');
|
|
193
|
-
expect(row.isFixPlan).toBe(true);
|
|
194
|
-
expect(row.investigationDepth).toBe(2);
|
|
195
|
-
} finally {
|
|
196
|
-
fs.rmSync(cwd, { recursive: true, force: true });
|
|
197
|
-
}
|
|
198
|
-
});
|
|
199
|
-
|
|
200
|
-
test('reconcile() adopts a quarantined row to pending once its PRD file is stamped', async () => {
|
|
201
|
-
const { cwd, prdsDir, stateDir } = makeFixtureProject('sm-quarantine-adopt-');
|
|
202
|
-
try {
|
|
203
|
-
const prdPath = path.join(prdsDir, '9004-adopt-me.md');
|
|
204
|
-
fs.writeFileSync(
|
|
205
|
-
prdPath,
|
|
206
|
-
`---\ntitle: Adopt me\ncwd: ${cwd}\nestimateMinutes: 15\n---\n\n# Goal\nAdopt.\n`,
|
|
207
|
-
'utf8',
|
|
208
|
-
);
|
|
209
|
-
const quarantinedRow = {
|
|
210
|
-
slug: '9004-adopt-me',
|
|
211
|
-
title: 'Adopt me',
|
|
212
|
-
cwd,
|
|
213
|
-
status: 'quarantined',
|
|
214
|
-
runId: null,
|
|
215
|
-
startedAt: null,
|
|
216
|
-
finishedAt: null,
|
|
217
|
-
exitCode: null,
|
|
218
|
-
error: null,
|
|
219
|
-
};
|
|
220
|
-
fs.writeFileSync(path.join(stateDir, 'queue.json'), JSON.stringify({ jobs: [quarantinedRow] }, null, 2), 'utf8');
|
|
221
|
-
|
|
222
|
-
// Simulate the adopt action: stamp the file via the same update-prd
|
|
223
|
-
// logic the IPC handler/admin route call (parsePrdFile/serializePrdFile
|
|
224
|
-
// round-trip), rather than hand-writing raw text, to exercise the real
|
|
225
|
-
// round-trip path this feature depends on.
|
|
226
|
-
const { parsePrdFile, serializePrdFile } = require('../lib/prdFrontmatter.cjs');
|
|
227
|
-
const raw = fs.readFileSync(prdPath, 'utf8');
|
|
228
|
-
const { frontmatter: fm, body } = parsePrdFile(raw);
|
|
229
|
-
fm.createdVia = 'legacy-adopted';
|
|
230
|
-
fm.issuedAt = '2026-08-07T01:00:00.000Z';
|
|
231
|
-
fs.writeFileSync(prdPath, serializePrdFile(fm, body), 'utf8');
|
|
232
|
-
|
|
233
|
-
const { auditLogPath } = require('../lib/auditLog.cjs');
|
|
234
|
-
queueStore.bustCwdCache();
|
|
235
|
-
const state = { jobs: [quarantinedRow], invalidJobs: [], paused: null };
|
|
236
|
-
await scheduler.reconcile(state);
|
|
237
|
-
|
|
238
|
-
const row = state.jobs.find((j) => j.slug === '9004-adopt-me');
|
|
239
|
-
expect(row).toBeDefined();
|
|
240
|
-
expect(row.status).toBe('pending');
|
|
241
|
-
|
|
242
|
-
const auditLines = fs.readFileSync(auditLogPath(), 'utf8').trim().split('\n').filter(Boolean).map((l) => JSON.parse(l));
|
|
243
|
-
expect(auditLines.some((rec) => rec.kind === 'scheduler_prd_adopted' && rec.slug === '9004-adopt-me')).toBe(true);
|
|
244
|
-
} finally {
|
|
245
|
-
fs.rmSync(cwd, { recursive: true, force: true });
|
|
246
|
-
}
|
|
247
|
-
});
|
|
@@ -1,77 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* scheduler-reset-job-fields-guard.test.cjs — unit tests for resetJobFields'
|
|
3
|
-
* terminal-status guard.
|
|
4
|
-
*
|
|
5
|
-
* A 'completed' job already landed its deliverable — resetting it back to
|
|
6
|
-
* 'pending' re-fires the PRD and re-executes already-shipped work (the
|
|
7
|
-
* incident: PRD 812-workbench-review-nits-cleanup was reset and re-run this
|
|
8
|
-
* way, burning a full claude -p job + Opus investigation over a correct
|
|
9
|
-
* no-op). resetJobFields must refuse (no-op) on a 'completed' job unless
|
|
10
|
-
* opts.force is true, and must still reset normally for every non-terminal
|
|
11
|
-
* status (pending/running/failed/needs_review).
|
|
12
|
-
*
|
|
13
|
-
* Run: timeout 120 npx vitest run src/main/__tests__/scheduler-reset-job-fields-guard.test.cjs
|
|
14
|
-
*/
|
|
15
|
-
|
|
16
|
-
'use strict';
|
|
17
|
-
|
|
18
|
-
import { test, expect } from 'vitest';
|
|
19
|
-
const { resetJobFields } = require('../scheduler.cjs');
|
|
20
|
-
|
|
21
|
-
function makeJob(status, overrides = {}) {
|
|
22
|
-
return {
|
|
23
|
-
slug: 'test-slug',
|
|
24
|
-
status,
|
|
25
|
-
runId: 'run-123',
|
|
26
|
-
startedAt: '2026-07-31T00:00:00.000Z',
|
|
27
|
-
finishedAt: '2026-07-31T00:05:00.000Z',
|
|
28
|
-
exitCode: 0,
|
|
29
|
-
error: null,
|
|
30
|
-
runtime: { pid: 999 },
|
|
31
|
-
verifierVerdict: 'pass',
|
|
32
|
-
landedCommit: 'abc1234',
|
|
33
|
-
...overrides,
|
|
34
|
-
};
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
test('resetJobFields: refuses and does not mutate a completed job', () => {
|
|
38
|
-
const job = makeJob('completed');
|
|
39
|
-
const snapshot = { ...job };
|
|
40
|
-
const result = resetJobFields(job, 'some error');
|
|
41
|
-
expect(result).toBe(false);
|
|
42
|
-
expect(job).toEqual(snapshot);
|
|
43
|
-
});
|
|
44
|
-
|
|
45
|
-
test('resetJobFields: force:true overrides the guard on a completed job', () => {
|
|
46
|
-
const job = makeJob('completed');
|
|
47
|
-
const result = resetJobFields(job, 'forced reset', { force: true });
|
|
48
|
-
expect(result).toBe(true);
|
|
49
|
-
expect(job.status).toBe('pending');
|
|
50
|
-
expect(job.runId).toBeNull();
|
|
51
|
-
expect(job.startedAt).toBeNull();
|
|
52
|
-
expect(job.finishedAt).toBeNull();
|
|
53
|
-
expect(job.exitCode).toBeNull();
|
|
54
|
-
expect(job.error).toBe('forced reset');
|
|
55
|
-
expect(job.runtime).toBeUndefined();
|
|
56
|
-
expect(job.verifierVerdict).toBeUndefined();
|
|
57
|
-
// landedCommit must survive even a forced reset — it feeds the
|
|
58
|
-
// pass_no_commit_prior_run_verified exemption on a later re-run.
|
|
59
|
-
expect(job.landedCommit).toBe('abc1234');
|
|
60
|
-
});
|
|
61
|
-
|
|
62
|
-
for (const status of ['pending', 'running', 'failed', 'needs_review']) {
|
|
63
|
-
test(`resetJobFields: resets normally for non-terminal status '${status}'`, () => {
|
|
64
|
-
const job = makeJob(status);
|
|
65
|
-
const result = resetJobFields(job, 'retry reason');
|
|
66
|
-
expect(result).toBe(true);
|
|
67
|
-
expect(job.status).toBe('pending');
|
|
68
|
-
expect(job.runId).toBeNull();
|
|
69
|
-
expect(job.startedAt).toBeNull();
|
|
70
|
-
expect(job.finishedAt).toBeNull();
|
|
71
|
-
expect(job.exitCode).toBeNull();
|
|
72
|
-
expect(job.error).toBe('retry reason');
|
|
73
|
-
expect(job.runtime).toBeUndefined();
|
|
74
|
-
expect(job.verifierVerdict).toBeUndefined();
|
|
75
|
-
expect(job.landedCommit).toBe('abc1234');
|
|
76
|
-
});
|
|
77
|
-
}
|
|
@@ -1,254 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* scheduler-resume-recovery.test.cjs — PRD 1111: resume-first recovery for a
|
|
3
|
-
* job parked in needs_review with verdict 'uncommitted_changes'. Before this
|
|
4
|
-
* feature, every such job went straight to spawnInvestigation (a cold-read
|
|
5
|
-
* fix-plan PRD authored by a FRESH session with no memory of the run it's
|
|
6
|
-
* diagnosing). This suite covers selectResumeRecoveryTarget's eligibility
|
|
7
|
-
* table, the --resume vs --session-id argv split (buildClaudeSpawnArgs), the
|
|
8
|
-
* preamble builder, the one-attempt bound, the SM_RESUME_RECOVERY_DISABLE
|
|
9
|
-
* kill-switch, and the two skip-gates (spawnInvestigation, selectAutoFixTargets).
|
|
10
|
-
*
|
|
11
|
-
* Run: timeout 120 npx vitest run src/main/__tests__/scheduler-resume-recovery.test.cjs
|
|
12
|
-
*/
|
|
13
|
-
|
|
14
|
-
'use strict';
|
|
15
|
-
|
|
16
|
-
import { test, expect, afterEach } from 'vitest';
|
|
17
|
-
const {
|
|
18
|
-
selectResumeRecoveryTarget,
|
|
19
|
-
buildResumeRecoveryPreamble,
|
|
20
|
-
buildClaudeSpawnArgs,
|
|
21
|
-
selectAutoFixTargets,
|
|
22
|
-
spawnInvestigation,
|
|
23
|
-
} = require('../scheduler.cjs');
|
|
24
|
-
|
|
25
|
-
const savedDisable = process.env.SM_RESUME_RECOVERY_DISABLE;
|
|
26
|
-
afterEach(() => {
|
|
27
|
-
if (savedDisable === undefined) delete process.env.SM_RESUME_RECOVERY_DISABLE;
|
|
28
|
-
else process.env.SM_RESUME_RECOVERY_DISABLE = savedDisable;
|
|
29
|
-
});
|
|
30
|
-
|
|
31
|
-
function baseJob(overrides = {}) {
|
|
32
|
-
return {
|
|
33
|
-
slug: '900-example',
|
|
34
|
-
status: 'needs_review',
|
|
35
|
-
verifierVerdict: 'uncommitted_changes',
|
|
36
|
-
sessionId: 'sess-abc-123',
|
|
37
|
-
uncommittedPaths: ['src/foo.js', 'src/bar.js'],
|
|
38
|
-
...overrides,
|
|
39
|
-
};
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
// ---------- selectResumeRecoveryTarget eligibility table ----------
|
|
43
|
-
|
|
44
|
-
test('selectResumeRecoveryTarget: eligible shape returns a resume decision', () => {
|
|
45
|
-
const target = selectResumeRecoveryTarget(baseJob());
|
|
46
|
-
expect(target).toEqual({
|
|
47
|
-
slug: '900-example',
|
|
48
|
-
sessionId: 'sess-abc-123',
|
|
49
|
-
dirtyPaths: ['src/foo.js', 'src/bar.js'],
|
|
50
|
-
salvagePatch: null,
|
|
51
|
-
});
|
|
52
|
-
});
|
|
53
|
-
|
|
54
|
-
test('selectResumeRecoveryTarget: carries salvagePatch through when present on the row', () => {
|
|
55
|
-
const target = selectResumeRecoveryTarget(baseJob({ salvagePatch: '/tmp/runs/x/900-example.uncommitted.patch' }));
|
|
56
|
-
expect(target.salvagePatch).toBe('/tmp/runs/x/900-example.uncommitted.patch');
|
|
57
|
-
});
|
|
58
|
-
|
|
59
|
-
const notNeedsReviewStatuses = ['pending', 'running', 'investigating', 'completed', 'failed', 'skipped'];
|
|
60
|
-
for (const status of notNeedsReviewStatuses) {
|
|
61
|
-
test(`selectResumeRecoveryTarget: status=${status} → null`, () => {
|
|
62
|
-
expect(selectResumeRecoveryTarget(baseJob({ status }))).toBeNull();
|
|
63
|
-
});
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
const nonRecoverableVerdicts = [
|
|
67
|
-
'silent_no_op',
|
|
68
|
-
'pass_no_commit_already_shipped',
|
|
69
|
-
'pass_no_commit_prior_run_verified',
|
|
70
|
-
'transcript_errors',
|
|
71
|
-
'deps_unmet',
|
|
72
|
-
'halt',
|
|
73
|
-
'verify_unavailable',
|
|
74
|
-
'worktree_integration_failed',
|
|
75
|
-
'shared_tree_reverted',
|
|
76
|
-
undefined,
|
|
77
|
-
];
|
|
78
|
-
for (const verdict of nonRecoverableVerdicts) {
|
|
79
|
-
test(`selectResumeRecoveryTarget: verdict=${JSON.stringify(verdict)} → null`, () => {
|
|
80
|
-
expect(selectResumeRecoveryTarget(baseJob({ verifierVerdict: verdict }))).toBeNull();
|
|
81
|
-
});
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
test('selectResumeRecoveryTarget: missing sessionId → null', () => {
|
|
85
|
-
expect(selectResumeRecoveryTarget(baseJob({ sessionId: undefined }))).toBeNull();
|
|
86
|
-
});
|
|
87
|
-
|
|
88
|
-
test('selectResumeRecoveryTarget: empty-string sessionId → null', () => {
|
|
89
|
-
expect(selectResumeRecoveryTarget(baseJob({ sessionId: '' }))).toBeNull();
|
|
90
|
-
});
|
|
91
|
-
|
|
92
|
-
test('selectResumeRecoveryTarget: non-string sessionId → null', () => {
|
|
93
|
-
expect(selectResumeRecoveryTarget(baseJob({ sessionId: 12345 }))).toBeNull();
|
|
94
|
-
});
|
|
95
|
-
|
|
96
|
-
test('selectResumeRecoveryTarget: resumeRecoveryAttempted === true → null (bounded to one attempt)', () => {
|
|
97
|
-
expect(selectResumeRecoveryTarget(baseJob({ resumeRecoveryAttempted: true }))).toBeNull();
|
|
98
|
-
});
|
|
99
|
-
|
|
100
|
-
test('selectResumeRecoveryTarget: resumeRecoveryAttempted absent/false → still eligible', () => {
|
|
101
|
-
expect(selectResumeRecoveryTarget(baseJob({ resumeRecoveryAttempted: false }))).not.toBeNull();
|
|
102
|
-
expect(selectResumeRecoveryTarget(baseJob())).not.toBeNull();
|
|
103
|
-
});
|
|
104
|
-
|
|
105
|
-
test('selectResumeRecoveryTarget: no recorded dirty paths → null', () => {
|
|
106
|
-
expect(selectResumeRecoveryTarget(baseJob({ uncommittedPaths: [] }))).toBeNull();
|
|
107
|
-
expect(selectResumeRecoveryTarget(baseJob({ uncommittedPaths: undefined }))).toBeNull();
|
|
108
|
-
});
|
|
109
|
-
|
|
110
|
-
test('selectResumeRecoveryTarget: null/undefined job → null', () => {
|
|
111
|
-
expect(selectResumeRecoveryTarget(null)).toBeNull();
|
|
112
|
-
expect(selectResumeRecoveryTarget(undefined)).toBeNull();
|
|
113
|
-
});
|
|
114
|
-
|
|
115
|
-
test('selectResumeRecoveryTarget: SM_RESUME_RECOVERY_DISABLE=1 → null even for an otherwise-eligible job', () => {
|
|
116
|
-
process.env.SM_RESUME_RECOVERY_DISABLE = '1';
|
|
117
|
-
expect(selectResumeRecoveryTarget(baseJob())).toBeNull();
|
|
118
|
-
});
|
|
119
|
-
|
|
120
|
-
// ---------- --resume vs --session-id argv (buildClaudeSpawnArgs) ----------
|
|
121
|
-
|
|
122
|
-
test('buildClaudeSpawnArgs: resume=true passes --resume <sessionId>, never --session-id', () => {
|
|
123
|
-
const args = buildClaudeSpawnArgs({ prompt: 'preamble text', model: 'sonnet', sessionId: 'sess-abc-123', resume: true });
|
|
124
|
-
expect(args).toContain('--resume');
|
|
125
|
-
expect(args[args.indexOf('--resume') + 1]).toBe('sess-abc-123');
|
|
126
|
-
expect(args).not.toContain('--session-id');
|
|
127
|
-
});
|
|
128
|
-
|
|
129
|
-
test('buildClaudeSpawnArgs: resume=false passes --session-id <sessionId>, never --resume', () => {
|
|
130
|
-
const args = buildClaudeSpawnArgs({ prompt: 'prd body', model: 'sonnet', sessionId: 'sess-fresh-456', resume: false });
|
|
131
|
-
expect(args).toContain('--session-id');
|
|
132
|
-
expect(args[args.indexOf('--session-id') + 1]).toBe('sess-fresh-456');
|
|
133
|
-
expect(args).not.toContain('--resume');
|
|
134
|
-
});
|
|
135
|
-
|
|
136
|
-
test('buildClaudeSpawnArgs: --model is always explicitly pinned, both modes', () => {
|
|
137
|
-
for (const resume of [true, false]) {
|
|
138
|
-
const args = buildClaudeSpawnArgs({ prompt: 'x', model: 'sonnet', sessionId: 'sid', resume });
|
|
139
|
-
const modelIdx = args.indexOf('--model');
|
|
140
|
-
expect(modelIdx).toBeGreaterThanOrEqual(0);
|
|
141
|
-
expect(args[modelIdx + 1]).toBe('sonnet');
|
|
142
|
-
}
|
|
143
|
-
});
|
|
144
|
-
|
|
145
|
-
// ---------- preamble content (buildResumeRecoveryPreamble) ----------
|
|
146
|
-
|
|
147
|
-
test('buildResumeRecoveryPreamble: contains every recorded dirty path', () => {
|
|
148
|
-
const dirtyPaths = ['src/main/scheduler.cjs', 'session-manager-operations/scheduler/prds/900-example.md'];
|
|
149
|
-
const preamble = buildResumeRecoveryPreamble({ dirtyPaths, salvagePatch: null });
|
|
150
|
-
for (const p of dirtyPaths) {
|
|
151
|
-
expect(preamble).toContain(p);
|
|
152
|
-
}
|
|
153
|
-
});
|
|
154
|
-
|
|
155
|
-
test('buildResumeRecoveryPreamble: does NOT re-embed a PRD body passed in as an unrelated string', () => {
|
|
156
|
-
const prdBody = '# Goal\nSome long PRD body that must never appear in a resume preamble.\n## Acceptance criteria\n- [ ] thing';
|
|
157
|
-
const preamble = buildResumeRecoveryPreamble({ dirtyPaths: ['a.js'], salvagePatch: null });
|
|
158
|
-
expect(preamble).not.toContain(prdBody);
|
|
159
|
-
expect(preamble).not.toContain('Acceptance criteria');
|
|
160
|
-
});
|
|
161
|
-
|
|
162
|
-
test('buildResumeRecoveryPreamble: instructs verifying paths on disk, foreground gate, and commit', () => {
|
|
163
|
-
const preamble = buildResumeRecoveryPreamble({ dirtyPaths: ['a.js'], salvagePatch: null });
|
|
164
|
-
expect(preamble).toMatch(/verify/i);
|
|
165
|
-
expect(preamble).toMatch(/FOREGROUND/);
|
|
166
|
-
expect(preamble).toMatch(/commit/i);
|
|
167
|
-
});
|
|
168
|
-
|
|
169
|
-
test('buildResumeRecoveryPreamble: mentions the salvage patch path when present', () => {
|
|
170
|
-
const preamble = buildResumeRecoveryPreamble({ dirtyPaths: ['a.js'], salvagePatch: '/tmp/runs/x/900-example.uncommitted.patch' });
|
|
171
|
-
expect(preamble).toContain('/tmp/runs/x/900-example.uncommitted.patch');
|
|
172
|
-
});
|
|
173
|
-
|
|
174
|
-
// ---------- selectAutoFixTargets skips resume-eligible jobs ----------
|
|
175
|
-
|
|
176
|
-
test('selectAutoFixTargets: excludes a job selectResumeRecoveryTarget accepts', () => {
|
|
177
|
-
const job = baseJob({ runId: 'run-1' });
|
|
178
|
-
const targets = selectAutoFixTargets([job], {
|
|
179
|
-
fixSlugExists: () => false,
|
|
180
|
-
resolveJobRunId: () => job.runId,
|
|
181
|
-
});
|
|
182
|
-
expect(targets).toEqual([]);
|
|
183
|
-
});
|
|
184
|
-
|
|
185
|
-
test('selectAutoFixTargets: still selects a needs_review job that is NOT resume-eligible (different verdict)', () => {
|
|
186
|
-
const job = baseJob({ runId: 'run-1', verifierVerdict: 'transcript_errors' });
|
|
187
|
-
const targets = selectAutoFixTargets([job], {
|
|
188
|
-
fixSlugExists: () => false,
|
|
189
|
-
resolveJobRunId: () => job.runId,
|
|
190
|
-
});
|
|
191
|
-
expect(targets.map((t) => t.slug)).toEqual([job.slug]);
|
|
192
|
-
});
|
|
193
|
-
|
|
194
|
-
test('selectAutoFixTargets: a resume-recovery-exhausted job (resumeRecoveryAttempted=true) falls through to normal auto-fix eligibility', () => {
|
|
195
|
-
const job = baseJob({ runId: 'run-1', resumeRecoveryAttempted: true });
|
|
196
|
-
const targets = selectAutoFixTargets([job], {
|
|
197
|
-
fixSlugExists: () => false,
|
|
198
|
-
resolveJobRunId: () => job.runId,
|
|
199
|
-
});
|
|
200
|
-
expect(targets.map((t) => t.slug)).toEqual([job.slug]);
|
|
201
|
-
});
|
|
202
|
-
|
|
203
|
-
// ---------- resume-then-fail: never a dead end ----------
|
|
204
|
-
|
|
205
|
-
test('resume-then-fail: a job whose one resume attempt is spent falls through to the normal fix-plan path, not a dead end', () => {
|
|
206
|
-
// spawnResumeRecovery reuses spawnJob wholesale, so a resume run that
|
|
207
|
-
// itself re-parks in needs_review runs through the SAME finalize mutate as
|
|
208
|
-
// any other run — the only difference is resumeRecoveryAttempted is now
|
|
209
|
-
// true on the row (stamped atomically with the 'running' transition
|
|
210
|
-
// before the resume child ever spawned).
|
|
211
|
-
const jobAfterFailedResume = baseJob({ runId: 'run-2', resumeRecoveryAttempted: true });
|
|
212
|
-
// A second resume is refused...
|
|
213
|
-
expect(selectResumeRecoveryTarget(jobAfterFailedResume)).toBeNull();
|
|
214
|
-
// ...but the job is NOT stranded: it is offered for a fix-plan exactly
|
|
215
|
-
// like any other needs_review job, via the same gate spawnInvestigation's
|
|
216
|
-
// periodic caller (reverifyNeedsReview) consults.
|
|
217
|
-
const targets = selectAutoFixTargets([jobAfterFailedResume], {
|
|
218
|
-
fixSlugExists: () => false,
|
|
219
|
-
resolveJobRunId: () => jobAfterFailedResume.runId,
|
|
220
|
-
});
|
|
221
|
-
expect(targets.map((t) => t.slug)).toEqual([jobAfterFailedResume.slug]);
|
|
222
|
-
});
|
|
223
|
-
|
|
224
|
-
// ---------- spawnInvestigation's own resume-first guard ----------
|
|
225
|
-
|
|
226
|
-
test('spawnInvestigation: a resume-eligible job is skipped before any fix-plan work (returns deferred:false immediately)', async () => {
|
|
227
|
-
const job = baseJob();
|
|
228
|
-
// A resume-eligible job trips the guard before spawnInvestigation ever
|
|
229
|
-
// touches the filesystem for runDir/investigationDepth lookups, so a
|
|
230
|
-
// nonexistent runDir is safe to pass here — proves the guard runs first.
|
|
231
|
-
const result = await spawnInvestigation(job, '/nonexistent/run/dir/for/this/test');
|
|
232
|
-
expect(result).toEqual({ deferred: false });
|
|
233
|
-
});
|
|
234
|
-
|
|
235
|
-
test('spawnInvestigation: resume-recovery-exhausted job (resumeRecoveryAttempted=true) is NOT skipped by the resume guard', async () => {
|
|
236
|
-
// slug matches the fix-plan pattern + investigationDepth beyond the cap so
|
|
237
|
-
// the NEXT gate (isFixPlanBeyondDepthCap) trips deterministically and
|
|
238
|
-
// returns before any fs/spawn work — proving the resume guard was passed
|
|
239
|
-
// through, not that this particular job happens to be safe to fully run.
|
|
240
|
-
const job = baseJob({ slug: '01-fix-example', resumeRecoveryAttempted: true, investigationDepth: 99 });
|
|
241
|
-
const result = await spawnInvestigation(job, '/nonexistent/run/dir/for/this/test');
|
|
242
|
-
expect(result).toEqual({ deferred: false });
|
|
243
|
-
});
|
|
244
|
-
|
|
245
|
-
test('SM_RESUME_RECOVERY_DISABLE=1: spawnInvestigation is NOT skipped by the resume guard for an otherwise-eligible job', async () => {
|
|
246
|
-
process.env.SM_RESUME_RECOVERY_DISABLE = '1';
|
|
247
|
-
const job = baseJob({ slug: '01-fix-example', investigationDepth: 99 });
|
|
248
|
-
// With the kill-switch on, selectResumeRecoveryTarget returns null, so the
|
|
249
|
-
// resume guard never fires; the job falls through to the NEXT gate
|
|
250
|
-
// (isFixPlanBeyondDepthCap, tripped here via investigationDepth: 99) —
|
|
251
|
-
// proving today's pre-feature behaviour is restored exactly.
|
|
252
|
-
const result = await spawnInvestigation(job, '/nonexistent/run/dir/for/this/test');
|
|
253
|
-
expect(result).toEqual({ deferred: false });
|
|
254
|
-
});
|