feat: 接通实现核验修复到正向运行采纳
任务书16第二块:角色分派与每调用轻量检查,提交及代码原子记账,按次数核验修复且耗尽不跑,串行正式运行及恢复引用指标,采纳含null统一公开。451项免费测试通过,全新上下文独立审阅未发现问题;真实研究验收仍待进行。
This commit is contained in:
@@ -1,9 +1,16 @@
|
||||
import assert from "node:assert/strict";
|
||||
import { spawnSync } from "node:child_process";
|
||||
import { cpSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs";
|
||||
import { cpSync, mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs";
|
||||
import { tmpdir } from "node:os";
|
||||
import { join } from "node:path";
|
||||
import { test, type TestContext } from "node:test";
|
||||
import { lightChecker } from "../src/flow/task-code.ts";
|
||||
import { recover } from "../src/flow/recover.ts";
|
||||
import { containerName, freshDir, runPaths } from "../src/flow/paths.ts";
|
||||
import type { Study } from "../src/flow/study.ts";
|
||||
import { Board, protocolMetrics, type FrozenProtocol } from "../src/materials/index.ts";
|
||||
import { loadTask, formalRun as runDefinition, prepareRun } from "../src/tasks/index.ts";
|
||||
import { runBalance } from "../src/rules/index.ts";
|
||||
import { runStudy } from "../src/flow/index.ts";
|
||||
import { Ledger } from "../src/ledger/index.ts";
|
||||
import { Runner } from "../src/runner/index.ts";
|
||||
@@ -76,3 +83,67 @@ test("docker run 没启动:写结果\"没启动\"后停下,原因带 Docker
|
||||
assert.match((ending as { reason: string }).reason, /运行 base-1 没有启动.*unknown or invalid runtime name: inforsi-test-no-such-runtime/);
|
||||
assert.deepEqual(ledgerKinds(dir), ["config", "code", "runPlanned", "runResult", "event"]);
|
||||
});
|
||||
|
||||
|
||||
/** 不派模型,只接真实任务镜像、账本和运行器,检查 flow 的两处 Docker 接线。 */
|
||||
async function runtimeStudy(t: TestContext, suffix: string): Promise<Study> {
|
||||
const dir = tempDir(t);
|
||||
const id = studyId(t, suffix);
|
||||
const task = loadTask(TASK_DIR);
|
||||
const runner = new Runner(null);
|
||||
const image = await runner.buildImage(task.dir, `inforsi-${id}`);
|
||||
const ledger = Ledger.open(join(dir, "ledger.sqlite"));
|
||||
t.after(() => ledger.close());
|
||||
return { dir, task, runner, ledger, stop: new AbortController().signal,
|
||||
frozen: { config: { ...fullConfig(), studyId: id, lightChecks: { maxCount: 1, seconds: 7 } }, facts: task.facts, image, seed: 1 } } as Study;
|
||||
}
|
||||
|
||||
test("flow 轻量检查:每次调用各自限次和限时,真实 Docker 只检查当前目录,不登记正式运行", { timeout: 120_000 }, async (t) => {
|
||||
const s = await runtimeStudy(t, "light");
|
||||
const work = join(s.dir, "work");
|
||||
mkdirSync(work);
|
||||
writeFileSync(join(work, "initial.py"), "raise RuntimeError('不应执行候选代码')\ndef run_packing():\n pass\n");
|
||||
for (const call of ["first-call", "second-call"]) {
|
||||
freshDir(join(s.dir, "calls", call));
|
||||
const check = lightChecker(s, call, work);
|
||||
const result = JSON.parse(await check());
|
||||
assert.deepEqual(result, { used: 1, maxCount: 1, seconds: 7, result: { passed: true } });
|
||||
assert.match(await check(), /已用完(上限 1 次)/);
|
||||
assert.equal(await s.runner.status(containerName(s.frozen.config.studyId, `${call}-check-1`)), "absent");
|
||||
}
|
||||
assert.deepEqual(s.ledger.records(), []);
|
||||
});
|
||||
|
||||
test("正向恢复:接上原容器不重跑,补启动只扣一次,引用指标沿用原登记缺失作废规则", { timeout: 120_000 }, async (t) => {
|
||||
const s = await runtimeStudy(t, "forward-recover");
|
||||
const metric = { id: "old-c.required", meaning: "必测量", unit: "次", direction: "maximize" as const, howMeasured: "原登记定义", missing: "invalidateRun" as const };
|
||||
const original: FrozenProtocol = { round: 0, baseline: "base", proposals: [], factors: [], safeguards: [], metrics: { defined: [metric], reused: [] }, clauses: [], body: "登记" };
|
||||
const current: FrozenProtocol = { ...original, round: 1, metrics: { defined: [], reused: [metric.id] } };
|
||||
s.ledger.append("protocol", { candidate: "old-c", protocol: original });
|
||||
s.ledger.append("protocol", { candidate: "r1-c1", protocol: current });
|
||||
const board = new Board(s.ledger.records());
|
||||
const run = "forward-1";
|
||||
const paths = runPaths(s.dir, run);
|
||||
const definition = runDefinition(s.task, s.frozen.image, "1");
|
||||
s.ledger.append("runPlanned", { run, purpose: "forward", round: 1, object: "r1-c1", definition });
|
||||
freshDir(paths.base);
|
||||
prepareRun(s.task, s.task.baselineDir, freshDir(paths.run), protocolMetrics(board, current));
|
||||
const name = containerName(s.frozen.config.studyId, run);
|
||||
t.after(() => { const result = docker(["rm", "-f", name]); if (result.status !== 0 && !result.stderr.includes("No such container")) throw new Error(result.stderr); });
|
||||
assert.deepEqual(await s.runner.start(name, definition, paths.run), { started: true });
|
||||
// 中断点:容器已启动,账本还没写 runStarted。恢复不调用 formalRun,而是找到原容器等它。
|
||||
assert.equal(await recover(s), null);
|
||||
const records = s.ledger.records();
|
||||
assert.equal(records.filter((r) => r.kind === "runPlanned").length, 1);
|
||||
assert.equal(records.filter((r) => r.kind === "runStarted").length, 1);
|
||||
assert.equal(records.filter((r) => r.kind === "runResult").length, 1);
|
||||
const result = records.find((r) => r.kind === "runResult")!;
|
||||
if (result.kind !== "runResult") throw new Error("缺运行结果");
|
||||
assert.equal(result.content.judged!.verdict, "invalid");
|
||||
assert.match(result.content.judged!.verdictReason, /old-c.required/);
|
||||
assert.equal(result.content.judged!.metrics[metric.id]!.status, "unmeasured");
|
||||
assert.deepEqual(runBalance(13, new Board(records).runStates()), { charged: 1, reserved: 0, balance: 12 });
|
||||
assert.equal(await s.runner.status(name), "absent");
|
||||
assert.equal(await recover(s), null);
|
||||
assert.equal(s.ledger.records().length, records.length);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user