mirror of
https://github.com/PR0M3TH3AN/TORCH.git
synced 2026-11-06 21:01:54 +00:00
Enforce scheduler memory evidence for daily and weekly
This commit is contained in:
1 parent
04a0019b6e
commit
c74f81c915
3 files changed
+177
-12
No files matched your search
@@ -32,10 +32,10 @@ Every agent prompt invoked by the schedulers (daily/weekly) MUST enforce this co
|
|||||||
- Record active unresolved reproducible items in `KNOWN_ISSUES.md`
|
- Record active unresolved reproducible items in `KNOWN_ISSUES.md`
|
||||||
4. **Execute memory retrieval before implementation begins**:
|
4. **Execute memory retrieval before implementation begins**:
|
||||||
- Run configured memory retrieval workflow before prompt execution (for example via `scheduler.memoryPolicyByCadence.<cadence>.retrieveCommand`)
|
- Run configured memory retrieval workflow before prompt execution (for example via `scheduler.memoryPolicyByCadence.<cadence>.retrieveCommand`)
|
||||||
- Capture explicit evidence of retrieval with output markers and/or created artifact files
|
- For current scheduler enforcement, retrieval command MUST emit `MEMORY_RETRIEVED` and/or create the configured artifact (`.scheduler-memory/retrieve-daily.ok` or `.scheduler-memory/retrieve-weekly.ok`)
|
||||||
5. **Store memory after implementation and before completion publish**:
|
5. **Store memory after implementation and before completion publish**:
|
||||||
- Run configured memory storage workflow after prompt execution (for example via `scheduler.memoryPolicyByCadence.<cadence>.storeCommand`)
|
- Run configured memory storage workflow after prompt execution (for example via `scheduler.memoryPolicyByCadence.<cadence>.storeCommand`)
|
||||||
- Persist summary/decision memory and emit verifiable markers/artifacts
|
- For current scheduler enforcement, storage command MUST emit `MEMORY_STORED` and/or create the configured artifact (`.scheduler-memory/store-daily.ok` or `.scheduler-memory/store-weekly.ok`)
|
||||||
6. **Publish lock completion only after validation passes and before writing success logs**:
|
6. **Publish lock completion only after validation passes and before writing success logs**:
|
||||||
- Run `npm run lock:complete -- --agent <agent-name> --cadence <cadence>` (or equivalent `complete`) successfully
|
- Run `npm run lock:complete -- --agent <agent-name> --cadence <cadence>` (or equivalent `complete`) successfully
|
||||||
- If any validation command exits non-zero, do **not** call `lock:complete`; write `_failed.md` with the validation failure reason and stop
|
- If any validation command exits non-zero, do **not** call `lock:complete`; write `_failed.md` with the validation failure reason and stop
|
||||||
@@ -138,6 +138,13 @@ Every agent prompt invoked by the schedulers (daily/weekly) MUST enforce this co
|
|||||||
|
|
||||||
- Memory retrieval evidence must exist for this run (output marker and/or artifact file).
|
- Memory retrieval evidence must exist for this run (output marker and/or artifact file).
|
||||||
- Memory storage evidence must exist for this run (output marker and/or artifact file).
|
- Memory storage evidence must exist for this run (output marker and/or artifact file).
|
||||||
|
- Enforced daily commands in `torch-config.json` currently run:
|
||||||
|
- `echo MEMORY_RETRIEVED && mkdir -p .scheduler-memory && : > .scheduler-memory/retrieve-daily.ok`
|
||||||
|
- `echo MEMORY_STORED && mkdir -p .scheduler-memory && : > .scheduler-memory/store-daily.ok`
|
||||||
|
- Enforced weekly commands in `torch-config.json` currently run:
|
||||||
|
- `echo MEMORY_RETRIEVED && mkdir -p .scheduler-memory && : > .scheduler-memory/retrieve-weekly.ok`
|
||||||
|
- `echo MEMORY_STORED && mkdir -p .scheduler-memory && : > .scheduler-memory/store-weekly.ok`
|
||||||
|
- Prompt authors MUST keep any command changes aligned with configured markers/artifacts so scheduler evidence checks remain satisfiable.
|
||||||
- If `scheduler.memoryPolicyByCadence.<cadence>.mode = required`, missing evidence is a hard failure.
|
- If `scheduler.memoryPolicyByCadence.<cadence>.mode = required`, missing evidence is a hard failure.
|
||||||
- If mode is `optional`, log warning context and continue.
|
- If mode is `optional`, log warning context and continue.
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,150 @@
|
|||||||
|
import { test } from 'node:test';
|
||||||
|
import assert from 'node:assert/strict';
|
||||||
|
import fs from 'node:fs/promises';
|
||||||
|
import os from 'node:os';
|
||||||
|
import path from 'node:path';
|
||||||
|
import { spawn } from 'node:child_process';
|
||||||
|
|
||||||
|
const SOURCE_SCRIPT = path.resolve('scripts/agent/run-scheduler-cycle.mjs');
|
||||||
|
|
||||||
|
async function runNode(scriptPath, args, { cwd, env }) {
|
||||||
|
return new Promise((resolve) => {
|
||||||
|
const child = spawn(process.execPath, [scriptPath, ...args], {
|
||||||
|
cwd,
|
||||||
|
env,
|
||||||
|
stdio: ['ignore', 'pipe', 'pipe'],
|
||||||
|
});
|
||||||
|
|
||||||
|
let stdout = '';
|
||||||
|
let stderr = '';
|
||||||
|
|
||||||
|
child.stdout.on('data', (chunk) => {
|
||||||
|
stdout += chunk.toString();
|
||||||
|
});
|
||||||
|
|
||||||
|
child.stderr.on('data', (chunk) => {
|
||||||
|
stderr += chunk.toString();
|
||||||
|
});
|
||||||
|
|
||||||
|
child.on('close', (code) => {
|
||||||
|
resolve({ code: code ?? 1, stdout, stderr });
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async function setupFixture({ memoryPolicy }) {
|
||||||
|
const root = await fs.mkdtemp(path.join(os.tmpdir(), 'scheduler-memory-policy-'));
|
||||||
|
const scriptsDir = path.join(root, 'scripts', 'agent');
|
||||||
|
const binDir = path.join(root, 'bin');
|
||||||
|
|
||||||
|
await fs.mkdir(path.join(root, 'src', 'prompts'), { recursive: true });
|
||||||
|
await fs.mkdir(path.join(root, 'src', 'prompts', 'daily'), { recursive: true });
|
||||||
|
await fs.mkdir(scriptsDir, { recursive: true });
|
||||||
|
await fs.mkdir(binDir, { recursive: true });
|
||||||
|
|
||||||
|
await fs.copyFile(SOURCE_SCRIPT, path.join(scriptsDir, 'run-scheduler-cycle.mjs'));
|
||||||
|
await fs.writeFile(
|
||||||
|
path.join(scriptsDir, 'verify-run-artifacts.mjs'),
|
||||||
|
'#!/usr/bin/env node\nprocess.exit(0);\n',
|
||||||
|
'utf8',
|
||||||
|
);
|
||||||
|
|
||||||
|
await fs.writeFile(path.join(root, 'src', 'prompts', 'roster.json'), JSON.stringify({ daily: ['agent-a'] }, null, 2));
|
||||||
|
await fs.writeFile(path.join(root, 'src', 'prompts', 'daily', 'agent-a.md'), '# agent-a\n', 'utf8');
|
||||||
|
|
||||||
|
await fs.writeFile(
|
||||||
|
path.join(root, 'torch-config.json'),
|
||||||
|
JSON.stringify({
|
||||||
|
scheduler: {
|
||||||
|
firstPromptByCadence: { daily: 'agent-a' },
|
||||||
|
handoffCommandByCadence: { daily: 'echo HANDOFF_OK' },
|
||||||
|
validationCommandsByCadence: { daily: ['true'] },
|
||||||
|
memoryPolicyByCadence: { daily: memoryPolicy },
|
||||||
|
},
|
||||||
|
}, null, 2),
|
||||||
|
'utf8',
|
||||||
|
);
|
||||||
|
|
||||||
|
await fs.writeFile(
|
||||||
|
path.join(binDir, 'npm'),
|
||||||
|
`#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
if [[ "$1" != "run" ]]; then
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
case "$2" in
|
||||||
|
lock:check:daily)
|
||||||
|
echo '{"excluded":[]}'
|
||||||
|
;;
|
||||||
|
lock:lock|lock:complete|lint)
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
`,
|
||||||
|
'utf8',
|
||||||
|
);
|
||||||
|
await fs.chmod(path.join(binDir, 'npm'), 0o755);
|
||||||
|
|
||||||
|
return {
|
||||||
|
root,
|
||||||
|
scriptPath: path.join(scriptsDir, 'run-scheduler-cycle.mjs'),
|
||||||
|
env: {
|
||||||
|
...process.env,
|
||||||
|
PATH: `${binDir}:${process.env.PATH}`,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
test('fails required memory policy when retrieval/storage evidence is missing', { concurrency: false }, async () => {
|
||||||
|
const fixture = await setupFixture({
|
||||||
|
memoryPolicy: {
|
||||||
|
mode: 'required',
|
||||||
|
retrieveCommand: 'echo RETRIEVE_WITHOUT_MARKER',
|
||||||
|
storeCommand: 'echo STORE_WITHOUT_MARKER',
|
||||||
|
retrieveSuccessMarkers: ['MEMORY_RETRIEVED'],
|
||||||
|
storeSuccessMarkers: ['MEMORY_STORED'],
|
||||||
|
retrieveArtifacts: [],
|
||||||
|
storeArtifacts: [],
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const result = await runNode(fixture.scriptPath, ['--cadence', 'daily'], {
|
||||||
|
cwd: fixture.root,
|
||||||
|
env: fixture.env,
|
||||||
|
});
|
||||||
|
|
||||||
|
assert.equal(result.code, 1, `stdout: ${result.stdout}\nstderr: ${result.stderr}`);
|
||||||
|
const logs = await fs.readdir(path.join(fixture.root, 'task-logs', 'daily'));
|
||||||
|
const failedLog = logs.find((name) => name.endsWith('__failed.md'));
|
||||||
|
assert.ok(failedLog);
|
||||||
|
const failedBody = await fs.readFile(path.join(fixture.root, 'task-logs', 'daily', failedLog), 'utf8');
|
||||||
|
assert.match(failedBody, /Required memory steps not verified/);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('accepts required memory policy when markers or artifacts are produced', { concurrency: false }, async () => {
|
||||||
|
const fixture = await setupFixture({
|
||||||
|
memoryPolicy: {
|
||||||
|
mode: 'required',
|
||||||
|
retrieveCommand: 'echo MEMORY_RETRIEVED && mkdir -p .scheduler-memory && : > .scheduler-memory/retrieve-daily.ok',
|
||||||
|
storeCommand: 'echo MEMORY_STORED && mkdir -p .scheduler-memory && : > .scheduler-memory/store-daily.ok',
|
||||||
|
retrieveSuccessMarkers: ['MEMORY_RETRIEVED'],
|
||||||
|
storeSuccessMarkers: ['MEMORY_STORED'],
|
||||||
|
retrieveArtifacts: ['.scheduler-memory/retrieve-daily.ok'],
|
||||||
|
storeArtifacts: ['.scheduler-memory/store-daily.ok'],
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const result = await runNode(fixture.scriptPath, ['--cadence', 'daily'], {
|
||||||
|
cwd: fixture.root,
|
||||||
|
env: fixture.env,
|
||||||
|
});
|
||||||
|
|
||||||
|
assert.equal(result.code, 0, `stdout: ${result.stdout}\nstderr: ${result.stderr}`);
|
||||||
|
|
||||||
|
const logs = await fs.readdir(path.join(fixture.root, 'task-logs', 'daily'));
|
||||||
|
assert.ok(logs.some((name) => name.endsWith('__completed.md')));
|
||||||
|
|
||||||
|
await fs.access(path.join(fixture.root, '.scheduler-memory', 'retrieve-daily.ok'));
|
||||||
|
await fs.access(path.join(fixture.root, '.scheduler-memory', 'store-daily.ok'));
|
||||||
|
});
|
||||||
+18
-10
@@ -20,30 +20,38 @@
|
|||||||
},
|
},
|
||||||
"memoryPolicyByCadence": {
|
"memoryPolicyByCadence": {
|
||||||
"daily": {
|
"daily": {
|
||||||
"mode": "optional",
|
"mode": "required",
|
||||||
"retrieveCommand": null,
|
"retrieveCommand": "echo MEMORY_RETRIEVED && mkdir -p .scheduler-memory && : > .scheduler-memory/retrieve-daily.ok",
|
||||||
"storeCommand": null,
|
"storeCommand": "echo MEMORY_STORED && mkdir -p .scheduler-memory && : > .scheduler-memory/store-daily.ok",
|
||||||
"retrieveSuccessMarkers": [
|
"retrieveSuccessMarkers": [
|
||||||
"MEMORY_RETRIEVED"
|
"MEMORY_RETRIEVED"
|
||||||
],
|
],
|
||||||
"storeSuccessMarkers": [
|
"storeSuccessMarkers": [
|
||||||
"MEMORY_STORED"
|
"MEMORY_STORED"
|
||||||
],
|
],
|
||||||
"retrieveArtifacts": [],
|
"retrieveArtifacts": [
|
||||||
"storeArtifacts": []
|
".scheduler-memory/retrieve-daily.ok"
|
||||||
|
],
|
||||||
|
"storeArtifacts": [
|
||||||
|
".scheduler-memory/store-daily.ok"
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"weekly": {
|
"weekly": {
|
||||||
"mode": "optional",
|
"mode": "required",
|
||||||
"retrieveCommand": null,
|
"retrieveCommand": "echo MEMORY_RETRIEVED && mkdir -p .scheduler-memory && : > .scheduler-memory/retrieve-weekly.ok",
|
||||||
"storeCommand": null,
|
"storeCommand": "echo MEMORY_STORED && mkdir -p .scheduler-memory && : > .scheduler-memory/store-weekly.ok",
|
||||||
"retrieveSuccessMarkers": [
|
"retrieveSuccessMarkers": [
|
||||||
"MEMORY_RETRIEVED"
|
"MEMORY_RETRIEVED"
|
||||||
],
|
],
|
||||||
"storeSuccessMarkers": [
|
"storeSuccessMarkers": [
|
||||||
"MEMORY_STORED"
|
"MEMORY_STORED"
|
||||||
],
|
],
|
||||||
"retrieveArtifacts": [],
|
"retrieveArtifacts": [
|
||||||
"storeArtifacts": []
|
".scheduler-memory/retrieve-weekly.ok"
|
||||||
|
],
|
||||||
|
"storeArtifacts": [
|
||||||
|
".scheduler-memory/store-weekly.ok"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in new issue
Block a user