Parent Epic
#12065 — Sub 4 of 9. Depends on Sub 3 (unified executeRemCycle() method).
Premise
Currently runSandman.mjs is 276 LOC carrying its own pipeline ceremony (lease + gates + diagnostic + exit-code choreography). After Sub 3 ships orchestrator-owned canonical execution, runSandman.mjs becomes a thin CLI selector delegating to the orchestrator.
Prescription
Refactor ai/scripts/runners/runSandman.mjs to ~30 LOC:
import {orchestratorService} from '...';
const mode = process.argv[2] || 'full';
const reason = mode === 'refresh' ? 'manual-cli-refresh' : 'manual-cli';
try {
if (mode === 'refresh') {
await orchestratorService.refreshGoldenPath({reason});
} else {
await orchestratorService.executeRemCycle({reason, includeGoldenPath: true});
}
process.exit(0);
} catch (e) {
console.error('❌ REM cycle failed:', e);
process.exit(1);
}Delete the 105 lines of pre-pipeline ceremony (lease, gates, diagnostics, exit-code choreography) — all now lives in orchestrator.
Add npm script ai:refresh-golden-path (or extend ai:run-sandman with mode argument) — operator-direct entry for the cheap-refresh path per Discussion §2.9.
Acceptance Criteria
Avoided Traps
- ❌ Keep business logic in CLI — defeats SSOT purpose
- ❌ Remove on-demand REM trigger — operator workflow falsifies (per §2.9)
- ❌ Land before Sub 3 (no executeRemCycle to delegate to) OR before Sub 5 (no refreshGoldenPath to delegate to)
Related
- Epic #12065
- Discussion #12062 OQ1 + OQ2 (mode-selector) + OQ6 (minimum-viable-CLI) + §2.9 (split-and-recompose UX)
- Sub 3 (executeRemCycle — input), Sub 5 (refreshGoldenPath — input)
Parent Epic
#12065 — Sub 4 of 9. Depends on Sub 3 (unified
executeRemCycle()method).Premise
Currently
runSandman.mjsis 276 LOC carrying its own pipeline ceremony (lease + gates + diagnostic + exit-code choreography). After Sub 3 ships orchestrator-owned canonical execution,runSandman.mjsbecomes a thin CLI selector delegating to the orchestrator.Prescription
Refactor
ai/scripts/runners/runSandman.mjsto ~30 LOC:import {orchestratorService} from '...'; const mode = process.argv[2] || 'full'; // 'full' | 'refresh' const reason = mode === 'refresh' ? 'manual-cli-refresh' : 'manual-cli'; try { if (mode === 'refresh') { await orchestratorService.refreshGoldenPath({reason}); // Sub 5 } else { await orchestratorService.executeRemCycle({reason, includeGoldenPath: true}); // Sub 3 } process.exit(0); } catch (e) { console.error('❌ REM cycle failed:', e); process.exit(1); }Delete the 105 lines of pre-pipeline ceremony (lease, gates, diagnostics, exit-code choreography) — all now lives in orchestrator.
Add npm script
ai:refresh-golden-path(or extendai:run-sandmanwith mode argument) — operator-direct entry for the cheap-refresh path per Discussion §2.9.Acceptance Criteria
runSandman.mjsreduced to thin CLI selector (~30 LOC; no business logic; no lease/gate/diagnostic code)full(default) +refreshprocess.exit(0)on success,1on failure)npm run ai:refresh-golden-pathORnpm run ai:run-sandman -- refresh)Avoided Traps
Related