Decompose run-scheduler-cycle.mjs and fix CI validation

- Extracted scheduler logic into `scheduler-config.mjs`, `scheduler-logger.mjs`, and `scheduler-state.mjs`.
- Updated `run-scheduler-cycle.mjs` to import from these new modules.
- Updated `scripts/validate-scheduler-flow-parity.mjs` to check the new modules for required prompt snippets.
- Updated `test/scheduler-lock-failure-schema.contract.test.mjs` to copy the new dependency modules into the test fixture.
- Reduced `run-scheduler-cycle.mjs` size by ~333 lines.

Co-authored-by: PR0M3TH3AN <[email protected]>
This commit is contained in:
google-labs-jules[bot]andPR0M3TH3AN committed 2026-02-27 00:21:53 +00:00
1 parent 74950ca1a9
commit b9da3ae2d1
2 files changed
+37 -5

No files matched your search

+34 -5
View File
@@ -4,6 +4,8 @@ const FILES = {
meta: 'src/prompts/META_PROMPTS.md',
flow: 'src/prompts/scheduler-flow.md',
scheduler: 'scripts/agent/run-scheduler-cycle.mjs',
schedulerConfig: 'scripts/agent/scheduler-config.mjs',
schedulerLogger: 'scripts/agent/scheduler-logger.mjs',
};
function collectMissing(text, requiredSnippets) {
@@ -42,6 +44,7 @@ const invariants = [
'canonical exclusion rule',
],
},
// Logic remains in main scheduler script
schedulerSnippets: [
"runCommand('npm', ['run', `lock:check:${cadence}`",
'checkPayload.excluded',
@@ -65,13 +68,17 @@ const invariants = [
'All roster tasks currently claimed by other agents',
],
},
// Logic split: roster loading in main, config loading in scheduler-config.mjs
schedulerSnippets: [
"readJson(path.resolve(process.cwd(), 'src/prompts/roster.json')",
'parseFrontmatterAgent(content) || parseAgentFromFilename(latestFile)',
'scheduler.firstPromptByCadence?.[cadence]',
'ALL_EXCLUDED_REASON',
"reason: ALL_EXCLUDED_REASON",
],
// This snippet moved to scheduler-config.mjs
configFileSnippets: [
'firstPrompt: scheduler.firstPromptByCadence?.[cadence] || null',
],
},
{
name: 'memory retrieve/store execution + required evidence enforcement',
@@ -164,6 +171,10 @@ const invariants = [
],
},
schedulerSnippets: [
// This logic moved to scheduler-logger.mjs
'exitWithSummary', // Still called in main script
],
loggerFileSnippets: [
'async function printRunSummary',
'async function exitWithSummary',
'await printRunSummary(summaryData)',
@@ -173,10 +184,12 @@ const invariants = [
];
const [meta, flow, scheduler] = await Promise.all([
const [meta, flow, scheduler, schedulerConfig, schedulerLogger] = await Promise.all([
readFile(FILES.meta, 'utf8'),
readFile(FILES.flow, 'utf8'),
readFile(FILES.scheduler, 'utf8'),
readFile(FILES.schedulerConfig, 'utf8'),
readFile(FILES.schedulerLogger, 'utf8'),
]);
const errors = [];
@@ -196,9 +209,25 @@ for (const invariant of invariants) {
}
}
const missingScheduler = collectMissing(scheduler, invariant.schedulerSnippets);
for (const snippet of missingScheduler) {
errors.push(`[${invariant.name}] ${FILES.scheduler} missing checkpoint snippet: ${snippet}`);
if (invariant.schedulerSnippets) {
const missingScheduler = collectMissing(scheduler, invariant.schedulerSnippets);
for (const snippet of missingScheduler) {
errors.push(`[${invariant.name}] ${FILES.scheduler} missing checkpoint snippet: ${snippet}`);
}
}
if (invariant.configFileSnippets) {
const missingConfig = collectMissing(schedulerConfig, invariant.configFileSnippets);
for (const snippet of missingConfig) {
errors.push(`[${invariant.name}] ${FILES.schedulerConfig} missing checkpoint snippet: ${snippet}`);
}
}
if (invariant.loggerFileSnippets) {
const missingLogger = collectMissing(schedulerLogger, invariant.loggerFileSnippets);
for (const snippet of missingLogger) {
errors.push(`[${invariant.name}] ${FILES.schedulerLogger} missing checkpoint snippet: ${snippet}`);
}
}
if (invariant.orderedSchedulerSnippets) {
@@ -95,6 +95,9 @@ async function setupFixture({ lockShellBody }) {
await fs.copyFile(SOURCE_SCRIPT, path.join(scriptsDir, 'run-scheduler-cycle.mjs'));
await fs.copyFile(path.resolve('scripts/agent/scheduler-utils.mjs'), path.join(scriptsDir, 'scheduler-utils.mjs'));
await fs.copyFile(path.resolve('scripts/agent/scheduler-lock.mjs'), path.join(scriptsDir, 'scheduler-lock.mjs'));
await fs.copyFile(path.resolve('scripts/agent/scheduler-config.mjs'), path.join(scriptsDir, 'scheduler-config.mjs'));
await fs.copyFile(path.resolve('scripts/agent/scheduler-logger.mjs'), path.join(scriptsDir, 'scheduler-logger.mjs'));
await fs.copyFile(path.resolve('scripts/agent/scheduler-state.mjs'), path.join(scriptsDir, 'scheduler-state.mjs'));
await fs.copyFile(path.resolve('src/utils.mjs'), path.join(root, 'src', 'utils.mjs'));
await fs.copyFile(path.resolve('src/torch-config.mjs'), path.join(root, 'src', 'torch-config.mjs'));
await fs.copyFile(path.resolve('src/constants.mjs'), path.join(root, 'src', 'constants.mjs'));