Reject incomplete autonomous cycles

This commit is contained in:
Theodore Song
2026-08-21 17:13:24 -04:00
parent 83e4ea8203
commit 6e6477a4e3
6 changed files with 22 additions and 16 deletions
+9 -4
View File
@@ -24,7 +24,7 @@ function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
export function validateRuntimeSnapshot(snapshot, expectedBuild = 0) {
export function validateRuntimeSnapshot(snapshot, expectedBuild = 0, { allowIncomplete = false } = {}) {
if (!snapshot || typeof snapshot !== "object" || !snapshot.items || typeof snapshot.items !== "object") {
throw new Error("Autonomous export is not a state snapshot");
}
@@ -47,7 +47,12 @@ export function validateRuntimeSnapshot(snapshot, expectedBuild = 0) {
if (expectedBuild && Number(snapshot.build_version) !== Number(expectedBuild)) {
throw new Error(`Expected Build ${expectedBuild}, received Build ${snapshot.build_version}`);
}
if ((suggestions.suggestions || []).length > 300) throw new Error("Runtime suggestion snapshot exceeds the 300-item public limit");
const suggestionCount = (suggestions.suggestions || []).length;
if (suggestionCount > 300) throw new Error("Runtime suggestion snapshot exceeds the 300-item public limit");
if (!allowIncomplete && suggestionCount === 0) throw new Error("Runtime cycle produced no live suggestions");
if (!allowIncomplete && Object.values(agents.agents).some(agent => !agent?.lastDecision)) {
throw new Error("Runtime cycle did not produce a decision for every agent");
}
const bytes = Buffer.byteLength(JSON.stringify(snapshot));
if (bytes > MAX_STATE_BYTES) throw new Error(`Runtime snapshot is ${bytes} bytes; limit is ${MAX_STATE_BYTES}`);
return { snapshot, bytes, agents, suggestions };
@@ -123,10 +128,10 @@ async function main() {
const branch = process.env.RUNTIME_BRANCH || "runtime-state";
const pathname = process.env.RUNTIME_STATE_PATH || "runtime/state.json";
const arenaUrl = (process.env.ARENA_URL || "https://polymarket-site-eta.vercel.app").replace(/\/$/, "");
const expectedBuild = Number(required("EXPECTED_BUILD", "88"));
const expectedBuild = Number(required("EXPECTED_BUILD", "89"));
await ensureRuntimeBranch(repository, branch);
const prior = await readRuntimeFile(repository, branch, pathname);
if (prior.snapshot) validateRuntimeSnapshot(prior.snapshot);
if (prior.snapshot) validateRuntimeSnapshot(prior.snapshot, 0, { allowIncomplete: true });
const browser = await chromium.launch({ headless: true });
try {
+5 -4
View File
@@ -8,7 +8,7 @@ const workflow = fs.readFileSync(new URL("../.github/workflows/autonomous-cycle.
const runner = fs.readFileSync(new URL("./run-autonomous-cycle.mjs", import.meta.url), "utf8");
const build = Number(index.match(/const BUILD_VERSION = (\d+);/)?.[1]);
assert.equal(build, 88);
assert.equal(build, 89);
assert.deepEqual([...ALLOWED_RUNTIME_KEYS].sort(), ["pma_agents_v2", "pma_suggestions_v5"]);
assert.match(index, /function collectPublicRuntimeItems\(\)/);
assert.match(index, /const PUBLIC_RUNTIME_KEYS=Object\.freeze\(\[AGENTS_KEY,SUG_KEY\]\)/);
@@ -19,11 +19,11 @@ assert.match(api, /runtime-state\/runtime\/state\.json/);
assert.match(api, /sanitizeGithubRuntimeState/);
assert.match(workflow, /cron: "7 \* \* \* \*"/);
assert.match(workflow, /contents: write/);
assert.match(workflow, /EXPECTED_BUILD: "88"/);
assert.match(workflow, /EXPECTED_BUILD: "89"/);
assert.match(runner, /MAX_STATE_BYTES = 900_000/);
const agentIds = ["value", "momentum", "favorite", "longshot", "diversifier", "catalyst", "reversal", "breakout", "tailalpha", "conviction"];
const agents = Object.fromEntries(agentIds.map(id => [id, { cash: 10000, positions: [] }]));
const agents = Object.fromEntries(agentIds.map(id => [id, { cash: 10000, positions: [], lastDecision: { mode: "test" } }]));
const snapshot = {
schema_version: 1,
build_version: build,
@@ -31,11 +31,12 @@ const snapshot = {
last_cycle_hour: "2026-08-21T20|v59",
items: {
pma_agents_v2: JSON.stringify({ seeded: true, last_cycle_hour: "2026-08-21T20|v59", agents }),
pma_suggestions_v5: JSON.stringify({ suggestions: [] }),
pma_suggestions_v5: JSON.stringify({ suggestions: [{ market_id: "test" }] }),
},
};
assert.equal(validateRuntimeSnapshot(snapshot, build).agents.seeded, true);
assert.throws(() => validateRuntimeSnapshot({ ...snapshot, items: { ...snapshot.items, pma_paper_accounts_v1: "{}" } }, build), /unexpected keys/);
assert.throws(() => validateRuntimeSnapshot({ ...snapshot, build_version: build - 1 }, build), /Expected Build/);
assert.throws(() => validateRuntimeSnapshot({ ...snapshot, items: { ...snapshot.items, pma_suggestions_v5: JSON.stringify({ suggestions: [] }) } }, build), /no live suggestions/);
console.log(`autonomous runtime verified for Build ${build}`);