runs: list survives a damaged run record (#1551)

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]>
This commit is contained in:
2026-10-11 21:13:56 -05:00
co-authored by Claude Opus 5.5
parent 0e6c944bd9
commit 0a9692aebd
3 changed files with 40 additions and 7 deletions
+5 -1
View File
@@ -72,7 +72,10 @@ printed them.
`list` and `show` print exactly what they printed before this package
existed, for any data root with no link out of it, no run document that
is JSON but not an object, and no unreadable directory.
is JSON but not an object, no `result.json` with a field of the wrong
type (a `status` or `taskId` that isn't a string, or a `workspace` or
`session` that is neither a string nor `null`), and no unreadable
directory.
`agents/rocko/work/queue-56/byte-check.sh` checks that byte for byte
against a seeded data root. Where those conditions don't hold, the
output changes on purpose:
@@ -82,6 +85,7 @@ output changes on purpose:
| run directory or `result.json` linked out | read through the link | `list`: `unknown`; `show`: refuses (run directory) or `result.json: (missing or unreadable)` |
| `runs/` linked out | read through the link | `list` and `show` refuse, exit 4 |
| `result.json` is `5` or `[]` | `list` crashed; `show` printed `undefined` fields | `unknown`; `(missing or unreadable)` |
| `result.json` is an object whose `status` or `taskId` isn't a string, or whose `workspace` or `session` is neither a string nor `null` (`{}`, a numeric `status`, a `null` `taskId`) | `list` crashed on a `status` or `taskId` that isn't a string, hiding every run after it, and printed a `workspace` or `session` that is neither a string nor `null` through `String` | `list`: `unknown` for the status, `-` for each other field, and every later run still lists; `show` as before |
| `task.json` or `mission.json` is JSON but not an object | `show` printed its snapshot line | snapshot line omitted |
| run is a regular file | `show` crashed | `run not found`, exit 4 |
| `runs/` unreadable | `list` printed nothing | refuses, exit 4 |
+28
View File
@@ -32,6 +32,34 @@ test("list prints each run in the established format", (t) => {
`${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);
+7 -6
View File
@@ -470,18 +470,19 @@ function readRuns(read) {
function listRuns() {
const resolved = loadConfig();
for (const { runId, result } of readRuns(() => listRunRecords(resolved.dataRoot))) {
// An incomplete or unreadable run record (result null) reports as unknown.
// An incomplete or unreadable run record (result null) reports as unknown,
// and so does each field of a damaged one that isn't a string.
let status = "unknown";
let taskId = "-";
let workspace = "-";
let session = "-";
if (result) {
status = result.status;
taskId = result.taskId;
workspace = result.workspace ?? "-";
session = result.session ?? "-";
if (typeof result.status === "string") status = result.status;
if (typeof result.taskId === "string") taskId = result.taskId;
if (typeof result.workspace === "string") workspace = result.workspace;
if (typeof result.session === "string") session = result.session;
}
process.stdout.write(`${runId} ${status.padEnd(9)} task=${taskId.padEnd(18)} ws=${String(workspace).padEnd(10)} session=${session}\n`);
process.stdout.write(`${runId} ${status.padEnd(9)} task=${taskId.padEnd(18)} ws=${workspace.padEnd(10)} session=${session}\n`);
}
}