Row 82 round 2, owner Rocko, candidate manifest dbf36e92 on 876f1ffe.
Approved by Filbert (27650); Sage's gate green 02:05-02:09Z.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
140 lines
6.6 KiB
JavaScript
140 lines
6.6 KiB
JavaScript
// scripts/mosaic-task.mjs list and show read through this package. These
|
|
// spawn the real script against a seeded data root and a scratch config.
|
|
import { test } from "node:test";
|
|
import assert from "node:assert/strict";
|
|
import fs from "node:fs";
|
|
import path from "node:path";
|
|
import { spawnSync } from "node:child_process";
|
|
import { fileURLToPath } from "node:url";
|
|
import { RESULT, scratch, write } from "./helpers.mjs";
|
|
|
|
const ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..", "..", "..");
|
|
const A = "r-20260101T000000Z-aaaaaa";
|
|
const B = "r-20260101T000100Z-bbbbbb";
|
|
|
|
function task(t, dataRoot, ...args) {
|
|
const config = path.join(path.dirname(dataRoot), "config.json");
|
|
write(config, { configVersion: 1, environment: "development", dataRoot, execution: { backend: "docker", provider: "zai", model: "m" } });
|
|
const env = { ...process.env, MOSAIC_CONFIG: config };
|
|
delete env.NODE_TEST_CONTEXT;
|
|
const proc = spawnSync(process.execPath, [path.join(ROOT, "scripts", "mosaic-task.mjs"), ...args], { cwd: ROOT, env, encoding: "utf8" });
|
|
return { status: proc.status, stdout: proc.stdout, stderr: proc.stderr };
|
|
}
|
|
|
|
test("list prints each run in the established format", (t) => {
|
|
const { dataRoot } = scratch(t);
|
|
write(path.join(dataRoot, "runs", A, "result.json"), { ...RESULT, workspace: "ws1", session: "s1" });
|
|
write(path.join(dataRoot, "runs", B, "task.json"), { id: "t" });
|
|
const out = task(t, dataRoot, "list");
|
|
assert.equal(out.status, 0, out.stderr);
|
|
assert.equal(out.stdout,
|
|
`${A} succeeded task=t-one ws=ws1 session=s1\n` +
|
|
`${B} unknown task=- ws=- session=-\n`);
|
|
});
|
|
|
|
test("list prints a damaged result.json as unknown and keeps listing the runs after it", (t) => {
|
|
const { dataRoot } = scratch(t);
|
|
const M = "r-20260101T000050Z-mmmmmm";
|
|
write(path.join(dataRoot, "runs", A, "result.json"), { ...RESULT, workspace: "ws1", session: "s1" });
|
|
write(path.join(dataRoot, "runs", M, "result.json"), {});
|
|
write(path.join(dataRoot, "runs", B, "result.json"), { ...RESULT, taskId: "t-two", workspace: ":run" });
|
|
const out = task(t, dataRoot, "list");
|
|
assert.equal(out.status, 0, out.stderr);
|
|
assert.equal(out.stdout,
|
|
`${A} succeeded task=t-one ws=ws1 session=s1\n` +
|
|
`${M} unknown task=- ws=- session=-\n` +
|
|
`${B} succeeded task=t-two ws=:run session=-\n`);
|
|
});
|
|
|
|
test("list prints each result field that isn't a string as unknown or -", (t) => {
|
|
const { dataRoot } = scratch(t);
|
|
const runs = [
|
|
["r-20260101T000000Z-status", { status: 5 }, "unknown task=t-one ws=- session=-"],
|
|
["r-20260101T000001Z-taskid", { taskId: null }, "succeeded task=- ws=- session=-"],
|
|
["r-20260101T000002Z-worksp", { workspace: 7 }, "succeeded task=t-one ws=- session=-"],
|
|
["r-20260101T000003Z-sessin", { session: { name: "s1" } }, "succeeded task=t-one ws=- session=-"],
|
|
];
|
|
for (const [runId, damage] of runs) write(path.join(dataRoot, "runs", runId, "result.json"), { ...RESULT, ...damage });
|
|
const out = task(t, dataRoot, "list");
|
|
assert.equal(out.status, 0, out.stderr);
|
|
assert.equal(out.stdout, runs.map(([runId, , line]) => `${runId} ${line}\n`).join(""));
|
|
});
|
|
|
|
test("show prints the run in the established format", (t) => {
|
|
const { dataRoot } = scratch(t);
|
|
const dir = path.join(dataRoot, "runs", A);
|
|
write(path.join(dir, "result.json"), { ...RESULT, missionId: "m", tools: ["read"], expectedExact: "hi" });
|
|
write(path.join(dir, "mission.json"), { id: "m", objective: "obj" });
|
|
const out = task(t, dataRoot, "show", A);
|
|
assert.equal(out.status, 0, out.stderr);
|
|
assert.equal(out.stdout, [
|
|
`run: ${A}`,
|
|
"status: succeeded",
|
|
"task: t-one",
|
|
"mission: m",
|
|
"tools: read",
|
|
"adapter: (see config) provider=zai model=m",
|
|
'request: "hi"',
|
|
'response: "hi"',
|
|
'expected: "hi"',
|
|
"timing: 2026-01-01T00:00:00.000Z -> 2026-01-01T00:00:01.000Z (1000 ms)",
|
|
"exit: 0",
|
|
"mission snapshot: m - obj",
|
|
`artifacts: ${fs.readdirSync(dir).join(", ")}`,
|
|
"",
|
|
].join("\n"));
|
|
});
|
|
|
|
test("show of a missing run and an invalid id exit 4 as before", (t) => {
|
|
const { dataRoot } = scratch(t);
|
|
const missing = task(t, dataRoot, "show", A);
|
|
assert.equal(missing.status, 4);
|
|
assert.equal(missing.stderr, `mosaic-task: run not found: ${A} (under ${path.join(dataRoot, "runs")})\n`);
|
|
const invalid = task(t, dataRoot, "show", "../x");
|
|
assert.equal(invalid.status, 4);
|
|
assert.equal(invalid.stderr, 'mosaic-task: invalid run id: "../x" (expected r-<id>)\n');
|
|
});
|
|
|
|
test("list and show refuse a runs directory linked out of the data root", (t) => {
|
|
const { dataRoot, outside } = scratch(t);
|
|
write(path.join(outside, A, "result.json"), RESULT);
|
|
fs.symlinkSync(outside, path.join(dataRoot, "runs"));
|
|
for (const args of [["list"], ["show", A]]) {
|
|
const out = task(t, dataRoot, ...args);
|
|
assert.equal(out.status, 4, args.join(" "));
|
|
assert.equal(out.stdout, "");
|
|
assert.match(out.stderr, /^mosaic-task: .*runs resolves outside the data root/);
|
|
}
|
|
});
|
|
|
|
test("show refuses a run linked out of the data root; list reports it unknown", (t) => {
|
|
const { dataRoot, outside } = scratch(t);
|
|
write(path.join(outside, "result.json"), RESULT);
|
|
fs.mkdirSync(path.join(dataRoot, "runs"));
|
|
fs.symlinkSync(outside, path.join(dataRoot, "runs", A));
|
|
const show = task(t, dataRoot, "show", A);
|
|
assert.equal(show.status, 4);
|
|
assert.equal(show.stdout, "");
|
|
assert.match(show.stderr, /resolves outside the data root/);
|
|
const list = task(t, dataRoot, "list");
|
|
assert.equal(list.status, 0, list.stderr);
|
|
assert.equal(list.stdout, `${A} unknown task=- ws=- session=-\n`);
|
|
});
|
|
|
|
test("list shows an r- name that isn't a valid run id, as before", (t) => {
|
|
const { dataRoot } = scratch(t);
|
|
write(path.join(dataRoot, "runs", "r-.bad", "result.json"), RESULT);
|
|
const out = task(t, dataRoot, "list");
|
|
assert.equal(out.status, 0, out.stderr);
|
|
assert.equal(out.stdout, "r-.bad succeeded task=t-one ws=- session=-\n");
|
|
});
|
|
|
|
test("show refuses an invalid id before reading the config", (t) => {
|
|
const { dir } = scratch(t);
|
|
const env = { ...process.env, MOSAIC_CONFIG: path.join(dir, "missing.json") };
|
|
delete env.NODE_TEST_CONTEXT;
|
|
const proc = spawnSync(process.execPath, [path.join(ROOT, "scripts", "mosaic-task.mjs"), "show", "../x"], { cwd: ROOT, env, encoding: "utf8" });
|
|
assert.equal(proc.status, 4, proc.stderr);
|
|
assert.equal(proc.stderr, 'mosaic-task: invalid run id: "../x" (expected r-<id>)\n');
|
|
});
|