Files
TORCH/scripts/validate-scheduler-flow-parity.mjs
T
google-labs-jules[bot]andPR0M3TH3AN 754a1c2ce1 feat: support platform and model info in nostr lock events
This change enables agents to report their execution platform (e.g., Jules, Codex, Goose) and model (e.g., DeepSeek 3.2) in the Nostr lock events.

Key changes:
- Updated `torch-lock` CLI to accept `--platform` and `--model` arguments.
- Implemented `detectPlatform` utility to infer platform from environment variables if not provided.
- Updated `src/lib.mjs` to include these fields in the event content.
- Updated `scripts/agent/run-scheduler-cycle.mjs` to propagate `--model` and `AGENT_MODEL`.
- Updated `dashboard/index.html` to display the model information on the lock card.
- Fixed a regression in `scripts/validate-scheduler-flow-parity.mjs` and `test/scheduler-ratchet.test.mjs` caused by argument string matching.
- Deleted `repro_test.mjs` temporary file.

Co-authored-by: PR0M3TH3AN <[email protected]>
2026-02-15 20:18:59 +00:00

204 lines
6.4 KiB
JavaScript

import { readFile } from 'node:fs/promises';
const FILES = {
meta: 'src/prompts/META_PROMPTS.md',
flow: 'src/prompts/scheduler-flow.md',
scheduler: 'scripts/agent/run-scheduler-cycle.mjs',
};
function collectMissing(text, requiredSnippets) {
return requiredSnippets.filter((snippet) => !text.includes(snippet));
}
function ensureOrdered(text, snippets) {
const positions = [];
for (const snippet of snippets) {
const idx = text.indexOf(snippet);
if (idx === -1) {
return { ok: false, missing: snippet };
}
positions.push(idx);
}
for (let i = 1; i < positions.length; i += 1) {
if (positions[i] < positions[i - 1]) {
return { ok: false, outOfOrder: [snippets[i - 1], snippets[i]] };
}
}
return { ok: true };
}
const invariants = [
{
name: 'lock check + exclusion fallback',
promptSnippets: {
meta: [
'Run preflight to get the exclusion set:',
'Use `excluded` from the JSON output as the canonical exclusion set.',
'fallback to the union of `locked`, `paused`, and `completed`',
],
flow: [
'canonical exclusion rule',
],
},
schedulerSnippets: [
"runCommand('npm', ['run', `lock:check:${cadence}`",
'checkPayload.excluded',
'checkPayload.locked',
'checkPayload.paused',
'checkPayload.completed',
],
},
{
name: 'roster selection source + all-excluded stop',
promptSnippets: {
meta: [
'Read roster from src/prompts/roster.json',
'scheduler.firstPromptByCadence.daily',
'scheduler.firstPromptByCadence.weekly',
'All roster tasks currently claimed by other agents',
],
flow: [
'Roster source: `src/prompts/roster.json`',
'Read `scheduler.firstPromptByCadence.<cadence>` from `torch-config.json` if present.',
'All roster tasks currently claimed by other agents',
],
},
schedulerSnippets: [
"readJson(path.resolve(process.cwd(), 'src/prompts/roster.json')",
'parseFrontmatterAgent(content) || parseAgentFromFilename(latestFile)',
'scheduler.firstPromptByCadence?.[cadence]',
'ALL_EXCLUDED_REASON',
"reason: ALL_EXCLUDED_REASON",
],
},
{
name: 'memory retrieve/store execution + required evidence enforcement',
promptSnippets: {
meta: [
'Run required memory workflow for this cadence:',
'Validate memory evidence:',
'fail the run if either check is missing',
],
flow: [
'Confirm memory contract completion:',
'Memory retrieval evidence must exist for this run',
'Memory storage evidence must exist for this run',
'mode = required`, missing evidence is a hard failure',
],
},
schedulerSnippets: [
'schedulerConfig.memoryPolicy.retrieveCommand',
'schedulerConfig.memoryPolicy.storeCommand',
"name: 'retrieve'",
"name: 'store'",
"schedulerConfig.memoryPolicy.mode === 'required'",
"reason: 'Required memory steps not verified'",
],
},
{
name: 'artifact verification checkpoint',
promptSnippets: {
flow: [
'Verify required run artifacts for the current run window.',
'verify-run-artifacts.mjs --since <run-start-iso> --check-failure-notes',
'If artifact verification exits non-zero: write `_failed.md` and stop.',
],
},
schedulerSnippets: [
"runCommand('node', [",
"'scripts/agent/verify-run-artifacts.mjs'",
"'--check-failure-notes'",
"reason: 'Missing required run artifacts'",
],
},
{
name: 'failure stop conditions + completion ordering',
promptSnippets: {
meta: [
'If any validation command exits non-zero, do not call `lock:complete`',
'Publish completion before writing `_completed.md`',
'Only after step 10 succeeds, write final task log (`_completed.md`',
],
flow: [
'step 12 MUST NOT be executed (`lock:complete` is forbidden until validation passes)',
'Publish completion before writing final success log:',
'`_completed.md` MUST be created only after completion publish succeeds.',
'backend_category',
'lock_command',
'lock_stderr_excerpt',
],
},
schedulerSnippets: [
"reason: 'Validation failed'",
'const completeResult = await runCommand(',
"['run', 'lock:complete'",
"status: 'completed'",
'Completion publish failed. Retry npm run lock:complete',
"reason: 'Lock backend error'",
'classifyLockBackendError',
'backend_category',
'lock_command',
'lock_stderr_excerpt',
'lock_stdout_excerpt',
],
orderedSchedulerSnippets: [
"reason: 'Validation failed'",
'const completeResult = await runCommand(',
"status: 'completed'",
],
},
];
const [meta, flow, scheduler] = await Promise.all([
readFile(FILES.meta, 'utf8'),
readFile(FILES.flow, 'utf8'),
readFile(FILES.scheduler, 'utf8'),
]);
const errors = [];
for (const invariant of invariants) {
if (invariant.promptSnippets?.meta) {
const missingMeta = collectMissing(meta, invariant.promptSnippets.meta);
for (const snippet of missingMeta) {
errors.push(`[${invariant.name}] ${FILES.meta} missing snippet: ${snippet}`);
}
}
if (invariant.promptSnippets?.flow) {
const missingFlow = collectMissing(flow, invariant.promptSnippets.flow);
for (const snippet of missingFlow) {
errors.push(`[${invariant.name}] ${FILES.flow} missing snippet: ${snippet}`);
}
}
const missingScheduler = collectMissing(scheduler, invariant.schedulerSnippets);
for (const snippet of missingScheduler) {
errors.push(`[${invariant.name}] ${FILES.scheduler} missing checkpoint snippet: ${snippet}`);
}
if (invariant.orderedSchedulerSnippets) {
const order = ensureOrdered(scheduler, invariant.orderedSchedulerSnippets);
if (!order.ok && order.missing) {
errors.push(`[${invariant.name}] ${FILES.scheduler} missing ordered snippet: ${order.missing}`);
} else if (!order.ok && order.outOfOrder) {
errors.push(
`[${invariant.name}] ${FILES.scheduler} ordering drift: "${order.outOfOrder[0]}" must appear before "${order.outOfOrder[1]}"`,
);
}
}
}
if (errors.length > 0) {
console.error('Scheduler flow parity drift detected:');
for (const error of errors) {
console.error(`- ${error}`);
}
process.exit(1);
}
console.log('Scheduler flow parity validated for prompts and scheduler implementation.');