Merge pull request #115 from PR0M3TH3AN/codex/enforce-memory-interaction-in-run-contract

Codex-generated pull request
This commit is contained in:
thePR0M3TH3AN authored and GitHub committed 2026-02-14 17:05:58 -05:00
commit 4dbef6bf01
4 files changed
+186 -14

No files matched your search

+111
View File
@@ -85,6 +85,43 @@ async function readJson(filePath, fallback) {
}
}
function normalizeStringList(value, fallback = []) {
if (!Array.isArray(value)) return fallback;
return value.filter((item) => typeof item === 'string' && item.trim()).map((item) => item.trim());
}
async function artifactExistsSince(filePath, sinceMs) {
if (!filePath) return false;
const resolved = path.isAbsolute(filePath)
? filePath
: path.resolve(process.cwd(), filePath);
try {
const stat = await fs.stat(resolved);
return stat.isFile() && stat.mtimeMs >= sinceMs;
} catch {
return false;
}
}
async function verifyMemoryStep({ name, markers, artifacts, outputText, sinceMs }) {
const markerMatched = markers.some((marker) => outputText.includes(marker));
let artifactMatched = false;
for (const artifact of artifacts) {
if (await artifactExistsSince(artifact, sinceMs)) {
artifactMatched = true;
break;
}
}
return {
name,
markerMatched,
artifactMatched,
complete: markerMatched || artifactMatched,
};
}
function parseFrontmatterAgent(markdown) {
const lines = markdown.split(/\r?\n/);
if (lines[0]?.trim() !== '---') return null;
@@ -135,6 +172,9 @@ async function getSchedulerConfig(cadence, { isInteractive }) {
const scheduler = cfg.scheduler || {};
const handoffCommand = scheduler.handoffCommandByCadence?.[cadence] || null;
const missingHandoffCommandForMode = !isInteractive && !handoffCommand;
const memoryPolicyRaw = scheduler.memoryPolicyByCadence?.[cadence] || {};
const mode = memoryPolicyRaw.mode === 'required' ? 'required' : 'optional';
return {
firstPrompt: scheduler.firstPromptByCadence?.[cadence] || null,
handoffCommand,
@@ -142,6 +182,19 @@ async function getSchedulerConfig(cadence, { isInteractive }) {
validationCommands: Array.isArray(scheduler.validationCommandsByCadence?.[cadence])
? scheduler.validationCommandsByCadence[cadence].filter((cmd) => typeof cmd === 'string' && cmd.trim())
: ['npm', 'run', 'lint'],
memoryPolicy: {
mode,
retrieveCommand: typeof memoryPolicyRaw.retrieveCommand === 'string' && memoryPolicyRaw.retrieveCommand.trim()
? memoryPolicyRaw.retrieveCommand.trim()
: null,
storeCommand: typeof memoryPolicyRaw.storeCommand === 'string' && memoryPolicyRaw.storeCommand.trim()
? memoryPolicyRaw.storeCommand.trim()
: null,
retrieveSuccessMarkers: normalizeStringList(memoryPolicyRaw.retrieveSuccessMarkers, ['MEMORY_RETRIEVED']),
storeSuccessMarkers: normalizeStringList(memoryPolicyRaw.storeSuccessMarkers, ['MEMORY_STORED']),
retrieveArtifacts: normalizeStringList(memoryPolicyRaw.retrieveArtifacts),
storeArtifacts: normalizeStringList(memoryPolicyRaw.storeArtifacts),
},
};
}
@@ -257,10 +310,25 @@ async function main() {
const promptPath = path.resolve(process.cwd(), 'src/prompts', cadence, `${selectedAgent}.md`);
const runArtifactSince = new Date().toISOString();
const runStartMs = Date.parse(runArtifactSince);
const outputChunks = [];
if (schedulerConfig.memoryPolicy.retrieveCommand) {
const retrieveResult = await runCommand('bash', ['-lc', schedulerConfig.memoryPolicy.retrieveCommand], {
env: { AGENT_PLATFORM: platform, SCHEDULER_AGENT: selectedAgent, SCHEDULER_CADENCE: cadence, SCHEDULER_PROMPT_PATH: promptPath },
});
outputChunks.push(retrieveResult.stdout, retrieveResult.stderr);
if (retrieveResult.code !== 0) {
await writeLog({ cadence, agent: selectedAgent, status: 'failed', reason: 'Memory retrieval command failed', detail: schedulerConfig.memoryPolicy.retrieveCommand });
process.exit(retrieveResult.code);
}
}
if (schedulerConfig.handoffCommand) {
const handoff = await runCommand('bash', ['-lc', schedulerConfig.handoffCommand], {
env: { AGENT_PLATFORM: platform, SCHEDULER_AGENT: selectedAgent, SCHEDULER_CADENCE: cadence, SCHEDULER_PROMPT_PATH: promptPath },
});
outputChunks.push(handoff.stdout, handoff.stderr);
if (handoff.code !== 0) {
await writeLog({ cadence, agent: selectedAgent, status: 'failed', reason: 'Prompt/handoff execution failed', detail: 'Handoff callback failed.' });
process.exit(handoff.code);
@@ -273,6 +341,49 @@ async function main() {
process.exit(1);
}
if (schedulerConfig.memoryPolicy.storeCommand) {
const storeResult = await runCommand('bash', ['-lc', schedulerConfig.memoryPolicy.storeCommand], {
env: { AGENT_PLATFORM: platform, SCHEDULER_AGENT: selectedAgent, SCHEDULER_CADENCE: cadence, SCHEDULER_PROMPT_PATH: promptPath },
});
outputChunks.push(storeResult.stdout, storeResult.stderr);
if (storeResult.code !== 0) {
await writeLog({ cadence, agent: selectedAgent, status: 'failed', reason: 'Memory storage command failed', detail: schedulerConfig.memoryPolicy.storeCommand });
process.exit(storeResult.code);
}
}
const memoryOutput = outputChunks.join('\n');
const retrieveCheck = await verifyMemoryStep({
name: 'retrieve',
markers: schedulerConfig.memoryPolicy.retrieveSuccessMarkers,
artifacts: schedulerConfig.memoryPolicy.retrieveArtifacts,
outputText: memoryOutput,
sinceMs: runStartMs,
});
const storeCheck = await verifyMemoryStep({
name: 'store',
markers: schedulerConfig.memoryPolicy.storeSuccessMarkers,
artifacts: schedulerConfig.memoryPolicy.storeArtifacts,
outputText: memoryOutput,
sinceMs: runStartMs,
});
const missingSteps = [retrieveCheck, storeCheck].filter((step) => !step.complete).map((step) => step.name);
if (missingSteps.length && schedulerConfig.memoryPolicy.mode === 'required') {
await writeLog({
cadence,
agent: selectedAgent,
status: 'failed',
reason: 'Required memory steps not verified',
detail: `Missing evidence for: ${missingSteps.join(', ')}`,
});
process.exit(1);
}
if (missingSteps.length) {
console.warn(`[scheduler] Optional memory evidence missing for ${missingSteps.join(', ')}.`);
}
const artifactCheck = await runCommand('node', [
'scripts/agent/verify-run-artifacts.mjs',
'--since',
+26 -6
View File
@@ -50,15 +50,25 @@ MUST 3: Run these commands in this order:
AGENT_PLATFORM=<platform> npm run lock:lock -- --agent <agent-name> --cadence daily
Exit 0 = lock acquired, proceed. Exit 3 = race lost, go back to step 3.
6) Execute selected prompt from src/prompts/daily/
7) Run repository checks (for example: npm run lint)
7) Run required memory workflow for this cadence:
- Before execution, run the retrieval command if configured:
`scheduler.memoryPolicyByCadence.daily.retrieveCommand`
- After execution, run the storage command if configured:
`scheduler.memoryPolicyByCadence.daily.storeCommand`
- Emit or collect verifiable evidence for both steps using configured markers/artifacts.
8) Validate memory evidence:
- Confirm retrieval evidence exists (marker and/or artifact file).
- Confirm storage evidence exists (marker and/or artifact file).
- If `scheduler.memoryPolicyByCadence.daily.mode` is `required`, fail the run if either check is missing.
9) Run repository checks (for example: npm run lint)
- If any validation command exits non-zero, do not call `lock:complete`.
- Instead, write `_failed.md` with the failing command and reason, then stop.
8) Publish completion before writing `_completed.md` (only after step 7 passes):
10) Publish completion before writing `_completed.md` (only after step 9 passes):
AGENT_PLATFORM=<platform> npm run lock:complete -- --agent <agent-name> --cadence daily
(Equivalent command allowed: torch-lock complete --agent <agent-name> --cadence daily)
- Exit 0: continue.
- Exit non-zero: fail the run, write `_failed.md` with a clear completion-publish failure reason and retry guidance, then stop.
9) Only after step 8 succeeds, write final task log (`_completed.md` for success). For any failure in step 7 or step 8, write `_failed.md`, then stop.
11) Only after step 10 succeeds, write final task log (`_completed.md` for success). For any failure in step 9 or step 10, write `_failed.md`, then stop.
Worked example (required order):
- `AGENT_PLATFORM=codex npm run lock:lock -- --agent content-audit-agent --cadence daily`
@@ -122,15 +132,25 @@ MUST 3: Run these commands in this order:
AGENT_PLATFORM=<platform> npm run lock:lock -- --agent <agent-name> --cadence weekly
Exit 0 = lock acquired, proceed. Exit 3 = race lost, go back to step 3.
6) Execute selected prompt from src/prompts/weekly/
7) Run repository checks (for example: npm run lint)
7) Run required memory workflow for this cadence:
- Before execution, run the retrieval command if configured:
`scheduler.memoryPolicyByCadence.weekly.retrieveCommand`
- After execution, run the storage command if configured:
`scheduler.memoryPolicyByCadence.weekly.storeCommand`
- Emit or collect verifiable evidence for both steps using configured markers/artifacts.
8) Validate memory evidence:
- Confirm retrieval evidence exists (marker and/or artifact file).
- Confirm storage evidence exists (marker and/or artifact file).
- If `scheduler.memoryPolicyByCadence.weekly.mode` is `required`, fail the run if either check is missing.
9) Run repository checks (for example: npm run lint)
- If any validation command exits non-zero, do not call `lock:complete`.
- Instead, write `_failed.md` with the failing command and reason, then stop.
8) Publish completion before writing `_completed.md` (only after step 7 passes):
10) Publish completion before writing `_completed.md` (only after step 9 passes):
AGENT_PLATFORM=<platform> npm run lock:complete -- --agent <agent-name> --cadence weekly
(Equivalent command allowed: torch-lock complete --agent <agent-name> --cadence weekly)
- Exit 0: continue.
- Exit non-zero: fail the run, write `_failed.md` with a clear completion-publish failure reason and retry guidance, then stop.
9) Only after step 8 succeeds, write final task log (`_completed.md` for success). For any failure in step 7 or step 8, write `_failed.md`, then stop.
11) Only after step 10 succeeds, write final task log (`_completed.md` for success). For any failure in step 9 or step 10, write `_failed.md`, then stop.
Worked example (required order):
- `AGENT_PLATFORM=codex npm run lock:lock -- --agent bug-reproducer-agent --cadence weekly`
+21 -8
View File
@@ -30,7 +30,13 @@ Every agent prompt invoked by the schedulers (daily/weekly) MUST enforce this co
3. **Capture reusable failures and unresolved issues**:
- Record reusable failures in `docs/agent-handoffs/incidents/`
- Record active unresolved reproducible items in `KNOWN_ISSUES.md`
4. **Publish lock completion only after validation passes and before writing success logs**:
4. **Execute memory retrieval before implementation begins**:
- 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
5. **Store memory after implementation and before completion publish**:
- Run configured memory storage workflow after prompt execution (for example via `scheduler.memoryPolicyByCadence.<cadence>.storeCommand`)
- Persist summary/decision memory and emit verifiable markers/artifacts
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
- If any validation command exits non-zero, do **not** call `lock:complete`; write `_failed.md` with the validation failure reason and stop
- Only after completion publish succeeds may the agent write final `*_completed.md` log files
@@ -125,12 +131,19 @@ Every agent prompt invoked by the schedulers (daily/weekly) MUST enforce this co
8. Execute `<prompt_dir>/<prompt-file>` end-to-end.
9. Run repository checks (for example: `npm run lint`).
9. Confirm memory contract completion:
- 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).
- If `scheduler.memoryPolicyByCadence.<cadence>.mode = required`, missing evidence is a hard failure.
- If mode is `optional`, log warning context and continue.
10. Run repository checks (for example: `npm run lint`).
- If any validation command exits non-zero: **fail the run immediately**, write `_failed.md` with the failing command and reason, and stop.
- When step 9 fails, step 10 MUST NOT be executed (`lock:complete` is forbidden until validation passes).
- When step 10 fails, step 11 MUST NOT be executed (`lock:complete` is forbidden until validation passes).
10. Publish completion before writing final success log:
11. Publish completion before writing final success log:
```bash
AGENT_PLATFORM=<platform> \
@@ -139,15 +152,15 @@ Every agent prompt invoked by the schedulers (daily/weekly) MUST enforce this co
(Equivalent invocation is allowed: `torch-lock complete --agent <agent-name> --cadence <cadence>`.)
- Exit `0`: completion published successfully; continue to step 11.
- Exit `0`: completion published successfully; continue to step 12.
- Exit non-zero: **fail the run**, write `_failed.md` with a clear reason that completion publish failed and retry guidance (for example: `Retry npm run lock:complete -- --agent <agent-name> --cadence <cadence> after verifying relay connectivity`), then stop.
11. Create final task log only after step 10 succeeds:
12. Create final task log only after step 11 succeeds:
- `_completed.md` MUST be created only after completion publish succeeds.
- `_failed.md` is required when step 9 or step 10 fails, and should include the failure reason and next retry action.
- `_failed.md` is required when step 10 or step 11 fails, and should include the failure reason and next retry action.
12. Commit and push.
13. Commit and push.
Worked post-task example (MUST order):
+28
View File
@@ -17,6 +17,34 @@
"firstPromptByCadence": {
"daily": "scheduler-update-agent",
"weekly": "bug-reproducer-agent"
},
"memoryPolicyByCadence": {
"daily": {
"mode": "optional",
"retrieveCommand": null,
"storeCommand": null,
"retrieveSuccessMarkers": [
"MEMORY_RETRIEVED"
],
"storeSuccessMarkers": [
"MEMORY_STORED"
],
"retrieveArtifacts": [],
"storeArtifacts": []
},
"weekly": {
"mode": "optional",
"retrieveCommand": null,
"storeCommand": null,
"retrieveSuccessMarkers": [
"MEMORY_RETRIEVED"
],
"storeSuccessMarkers": [
"MEMORY_STORED"
],
"retrieveArtifacts": [],
"storeArtifacts": []
}
}
}
}