mirror of
https://github.com/PR0M3TH3AN/TORCH.git
synced 2026-10-27 07:51:52 +00:00
Align scheduler tables with roster and add drift check
This commit is contained in:
1 parent
f27929746e
commit
5b0cf980e9
4 files changed
+142
-17
No files matched your search
+3
-2
@@ -27,7 +27,7 @@
|
|||||||
"README.md"
|
"README.md"
|
||||||
],
|
],
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"test": "node --test test/*.test.mjs tests/*.test.js",
|
"test": "npm run validate:scheduler && node --test test/*.test.mjs tests/*.test.js",
|
||||||
"lock:check:daily": "node bin/torch-lock.mjs check --cadence daily",
|
"lock:check:daily": "node bin/torch-lock.mjs check --cadence daily",
|
||||||
"lock:check:weekly": "node bin/torch-lock.mjs check --cadence weekly",
|
"lock:check:weekly": "node bin/torch-lock.mjs check --cadence weekly",
|
||||||
"lock:list": "node bin/torch-lock.mjs list",
|
"lock:list": "node bin/torch-lock.mjs list",
|
||||||
@@ -35,7 +35,8 @@
|
|||||||
"dashboard:serve": "node bin/torch-lock.mjs dashboard",
|
"dashboard:serve": "node bin/torch-lock.mjs dashboard",
|
||||||
"build": "node build.mjs",
|
"build": "node build.mjs",
|
||||||
"lint": "eslint .",
|
"lint": "eslint .",
|
||||||
"lock:complete": "node bin/torch-lock.mjs complete"
|
"lock:complete": "node bin/torch-lock.mjs complete",
|
||||||
|
"validate:scheduler": "node scripts/validate-scheduler-roster.mjs"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"nostr-tools": "2.19.4",
|
"nostr-tools": "2.19.4",
|
||||||
|
|||||||
@@ -0,0 +1,122 @@
|
|||||||
|
import { readdir, readFile } from 'node:fs/promises';
|
||||||
|
|
||||||
|
const CONFIG = {
|
||||||
|
daily: {
|
||||||
|
schedulerFile: 'src/prompts/daily-scheduler.md',
|
||||||
|
promptDir: 'src/prompts/daily',
|
||||||
|
},
|
||||||
|
weekly: {
|
||||||
|
schedulerFile: 'src/prompts/weekly-scheduler.md',
|
||||||
|
promptDir: 'src/prompts/weekly',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
function parseTableRows(markdown, schedulerFile) {
|
||||||
|
const rows = [];
|
||||||
|
for (const line of markdown.split('\n')) {
|
||||||
|
const match = line.match(/^\|\s*(\d+)\s*\|\s*([^|]+?)\s*\|\s*`([^`]+)`\s*\|\s*$/);
|
||||||
|
if (!match) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
rows.push({
|
||||||
|
index: Number(match[1]),
|
||||||
|
agent: match[2].trim(),
|
||||||
|
promptFile: match[3].trim(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rows.length === 0) {
|
||||||
|
throw new Error(`No scheduler table rows found in ${schedulerFile}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
return rows;
|
||||||
|
}
|
||||||
|
|
||||||
|
function diffLists(expected, actual) {
|
||||||
|
return {
|
||||||
|
missing: expected.filter((item) => !actual.includes(item)),
|
||||||
|
extra: actual.filter((item) => !expected.includes(item)),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function validateScheduler(cadence, roster, rows, promptFiles) {
|
||||||
|
const errors = [];
|
||||||
|
|
||||||
|
if (rows.length !== roster.length) {
|
||||||
|
errors.push(
|
||||||
|
`[${cadence}] row count mismatch: roster has ${roster.length}, table has ${rows.length}`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let i = 0; i < rows.length; i += 1) {
|
||||||
|
const row = rows[i];
|
||||||
|
const expectedIndex = i + 1;
|
||||||
|
if (row.index !== expectedIndex) {
|
||||||
|
errors.push(`[${cadence}] row ${i + 1} has index ${row.index}, expected ${expectedIndex}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const expectedAgent = roster[i];
|
||||||
|
if (expectedAgent && row.agent !== expectedAgent) {
|
||||||
|
errors.push(
|
||||||
|
`[${cadence}] row ${i + 1} agent mismatch: table has "${row.agent}", roster expects "${expectedAgent}"`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const expectedPromptFile = `${row.agent}.md`;
|
||||||
|
if (row.promptFile !== expectedPromptFile) {
|
||||||
|
errors.push(
|
||||||
|
`[${cadence}] row ${i + 1} prompt file mismatch: table has "${row.promptFile}", expected "${expectedPromptFile}"`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const tableAgents = rows.map((row) => row.agent);
|
||||||
|
const rosterVsTable = diffLists(roster, tableAgents);
|
||||||
|
if (rosterVsTable.missing.length > 0 || rosterVsTable.extra.length > 0) {
|
||||||
|
errors.push(
|
||||||
|
`[${cadence}] roster/table mismatch: missing in table [${rosterVsTable.missing.join(', ')}], extra in table [${rosterVsTable.extra.join(', ')}]`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const rosterPromptFiles = roster.map((agent) => `${agent}.md`);
|
||||||
|
const filesVsRoster = diffLists(rosterPromptFiles, promptFiles);
|
||||||
|
if (filesVsRoster.missing.length > 0 || filesVsRoster.extra.length > 0) {
|
||||||
|
errors.push(
|
||||||
|
`[${cadence}] roster/files mismatch: missing files [${filesVsRoster.missing.join(', ')}], extra files [${filesVsRoster.extra.join(', ')}]`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const filesVsTable = diffLists(promptFiles, rows.map((row) => row.promptFile));
|
||||||
|
if (filesVsTable.missing.length > 0 || filesVsTable.extra.length > 0) {
|
||||||
|
errors.push(
|
||||||
|
`[${cadence}] table/files mismatch: missing in table [${filesVsTable.missing.join(', ')}], extra in table [${filesVsTable.extra.join(', ')}]`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return errors;
|
||||||
|
}
|
||||||
|
|
||||||
|
const roster = JSON.parse(await readFile('src/prompts/roster.json', 'utf8'));
|
||||||
|
|
||||||
|
const allErrors = [];
|
||||||
|
|
||||||
|
for (const [cadence, cfg] of Object.entries(CONFIG)) {
|
||||||
|
const schedulerMd = await readFile(cfg.schedulerFile, 'utf8');
|
||||||
|
const rows = parseTableRows(schedulerMd, cfg.schedulerFile);
|
||||||
|
const promptFiles = (await readdir(cfg.promptDir))
|
||||||
|
.filter((filename) => filename.endsWith('.md'))
|
||||||
|
.sort((a, b) => a.localeCompare(b));
|
||||||
|
|
||||||
|
allErrors.push(...validateScheduler(cadence, roster[cadence] ?? [], rows, promptFiles));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (allErrors.length > 0) {
|
||||||
|
console.error('Scheduler/roster drift detected:');
|
||||||
|
for (const error of allErrors) {
|
||||||
|
console.error(`- ${error}`);
|
||||||
|
}
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('Scheduler tables, roster, and prompt filenames are in sync.');
|
||||||
@@ -28,9 +28,9 @@ Canonical roster source: `src/prompts/roster.json` (`daily` key).
|
|||||||
| 11 | innerhtml-migration-agent | `innerhtml-migration-agent.md` |
|
| 11 | innerhtml-migration-agent | `innerhtml-migration-agent.md` |
|
||||||
| 12 | known-issues-agent | `known-issues-agent.md` |
|
| 12 | known-issues-agent | `known-issues-agent.md` |
|
||||||
| 13 | load-test-agent | `load-test-agent.md` |
|
| 13 | load-test-agent | `load-test-agent.md` |
|
||||||
| 14 | onboarding-audit-agent | `onboarding-audit-agent.md` |
|
| 14 | log-fixer-agent | `log-fixer-agent.md` |
|
||||||
| 15 | perf-agent | `perf-agent.md` |
|
| 15 | onboarding-audit-agent | `onboarding-audit-agent.md` |
|
||||||
| 16 | prompt-curator-agent | `prompt-curator-agent.md` |
|
| 16 | perf-agent | `perf-agent.md` |
|
||||||
| 17 | protocol-research-agent | `protocol-research-agent.md` |
|
| 17 | protocol-research-agent | `protocol-research-agent.md` |
|
||||||
| 18 | scheduler-update-agent | `scheduler-update-agent.md` |
|
| 18 | scheduler-update-agent | `scheduler-update-agent.md` |
|
||||||
| 19 | style-agent | `style-agent.md` |
|
| 19 | style-agent | `style-agent.md` |
|
||||||
|
|||||||
@@ -18,17 +18,19 @@ Canonical roster source: `src/prompts/roster.json` (`weekly` key).
|
|||||||
| 1 | bug-reproducer-agent | `bug-reproducer-agent.md` |
|
| 1 | bug-reproducer-agent | `bug-reproducer-agent.md` |
|
||||||
| 2 | changelog-agent | `changelog-agent.md` |
|
| 2 | changelog-agent | `changelog-agent.md` |
|
||||||
| 3 | dead-code-agent | `dead-code-agent.md` |
|
| 3 | dead-code-agent | `dead-code-agent.md` |
|
||||||
| 4 | event-schema-agent | `event-schema-agent.md` |
|
| 4 | feature-proposer-agent | `feature-proposer-agent.md` |
|
||||||
| 5 | frontend-console-debug-agent | `frontend-console-debug-agent.md` |
|
| 5 | frontend-console-debug-agent | `frontend-console-debug-agent.md` |
|
||||||
| 6 | fuzz-agent | `fuzz-agent.md` |
|
| 6 | fuzz-agent | `fuzz-agent.md` |
|
||||||
| 7 | interop-agent | `interop-agent.md` |
|
| 7 | perf-deepdive-agent | `perf-deepdive-agent.md` |
|
||||||
| 8 | perf-deepdive-agent | `perf-deepdive-agent.md` |
|
| 8 | perf-optimization-agent | `perf-optimization-agent.md` |
|
||||||
| 9 | perf-optimization-agent | `perf-optimization-agent.md` |
|
| 9 | pr-review-agent | `pr-review-agent.md` |
|
||||||
| 10 | pr-review-agent | `pr-review-agent.md` |
|
| 10 | prompt-maintenance-agent | `prompt-maintenance-agent.md` |
|
||||||
| 11 | race-condition-agent | `race-condition-agent.md` |
|
| 11 | prompt-safety-agent | `prompt-safety-agent.md` |
|
||||||
| 12 | refactor-agent | `refactor-agent.md` |
|
| 12 | race-condition-agent | `race-condition-agent.md` |
|
||||||
| 13 | repo-fit-agent | `repo-fit-agent.md` |
|
| 13 | refactor-agent | `refactor-agent.md` |
|
||||||
| 14 | smoke-agent | `smoke-agent.md` |
|
| 14 | repo-fit-agent | `repo-fit-agent.md` |
|
||||||
| 15 | telemetry-agent | `telemetry-agent.md` |
|
| 15 | smoke-agent | `smoke-agent.md` |
|
||||||
| 16 | test-coverage-agent | `test-coverage-agent.md` |
|
| 16 | telemetry-agent | `telemetry-agent.md` |
|
||||||
| 17 | weekly-synthesis-agent | `weekly-synthesis-agent.md` |
|
| 17 | test-coverage-agent | `test-coverage-agent.md` |
|
||||||
|
| 18 | ui-ux-agent | `ui-ux-agent.md` |
|
||||||
|
| 19 | weekly-synthesis-agent | `weekly-synthesis-agent.md` |
|
||||||
Reference in new issue
Block a user