New packages/runs reads run records, result.json, the release pointer
and the activation log without writing, pruning or following a link out
of the data root. mosaic-task.mjs list and show use it, so a malformed
result.json or a run that is a regular file no longer crashes them.
Deliberate deltas are listed in the README.
Rocko built it. Round 1 (ed3c5392) was approved with notes by Darkwing
(27115) and Filbert (27116); round 2 (2727198f, tests and wording only)
was approved by Darkwing (27123) and Filbert (27124). Sage's gate on
c9a25a47 plus the candidate: runs 41/0, queue 148/0, webui 22/0,
conversation 182/0 (181/1 in the full run on the K12 cgroup timing
test under load, 182/0 alone), control-board 124/0, every
scripts/test-*.sh 0 failed (task 98/0 with Docker, 26/0 without).
Co-Authored-By: Claude Opus 5.5 <[email protected]>
93 lines
5.1 KiB
Markdown
93 lines
5.1 KiB
Markdown
# Runs
|
|
|
|
Read-only readers for the run records under `<dataRoot>/runs/` and the
|
|
release state under `<dataRoot>/state/` (#1545). `scripts/mosaic-task.mjs
|
|
list` and `show` read through it, and so will the console's runs view.
|
|
This README covers what the code does and the limits it accepts.
|
|
|
|
```sh
|
|
node --test packages/runs/tests/
|
|
```
|
|
|
|
## What it reads
|
|
|
|
| Export | Returns |
|
|
|---|---|
|
|
| `listRunIds(dataRoot)` | every name under `runs/` that starts with `r-`, sorted, which is oldest first |
|
|
| `listRunRecords(dataRoot)` | `[{ runId, result }]` for those names; `result` is `null` for an incomplete or unreadable record |
|
|
| `readRunRecord(dataRoot, runId)` | `{ runId, result, task, mission, artifacts }`, or `null` when the run doesn't exist or isn't a directory |
|
|
| `readRunDocument(dataRoot, runId, name)` | `result.json`, `task.json` or `mission.json` from one run, or `null` |
|
|
| `readActivePointer(dataRoot)` | `state/active.json`, or `null` when no release has been activated |
|
|
| `readActivationLog(dataRoot, { last })` | `{ entries, malformed }` from `state/activation-log.jsonl`, oldest first |
|
|
| `isRunId(value)`, `RUN_ID_PATTERN` | the run id shape `mosaic-task.mjs` checks: `r-` then 1 to 64 of `[A-Za-z0-9._-]`, starting with a letter or digit |
|
|
|
|
The caller passes `dataRoot`; this package doesn't read the system
|
|
config. `artifacts` are names in directory order, as `show` has always
|
|
printed them.
|
|
|
|
## Limits
|
|
|
|
- **Nothing writes.** No reader creates, changes, prunes or locks
|
|
anything. Run records stay write-once evidence; pruning stays in
|
|
`mosaic-task.mjs prune`.
|
|
- **Nothing follows a link out of the data root.** The configured data
|
|
root is trusted as given, even when it is itself a link. Every path
|
|
below it is resolved, and one that resolves outside it is refused or
|
|
read as unreadable:
|
|
- `runs/` or `state/` resolving outside refuses with a `RunsError`;
|
|
- a run directory resolving outside: `readRunRecord` refuses, and
|
|
`listRunRecords` gives that run a `null` result;
|
|
- a run document resolving outside reads as `null`;
|
|
- `active.json` or `activation-log.jsonl` resolving outside refuses.
|
|
|
|
Only a path that exists can resolve. A link with nothing behind it reads
|
|
as missing wherever it points. A `state/` link out of the data root to a
|
|
path that doesn't exist reads as no release and an empty log, and a
|
|
`runs/` link like that lists nothing. A link that stays inside the data
|
|
root is followed.
|
|
- **Run documents are JSON objects or `null`.** A document that is
|
|
missing, unreadable, not JSON, or JSON but not an object (`null`, `5`,
|
|
`[]`) reads as `null`. Run records are never validated beyond that,
|
|
because older records carry older shapes.
|
|
- **The release pointer is strict.** `active.json` must be the version 1
|
|
shape `scripts/release.sh` writes: exactly `pointerVersion` 1 and
|
|
non-empty strings `release`, `imageTag` and `activatedAt`. Anything else
|
|
refuses with exit code 2 rather than being guessed at.
|
|
- **The activation log is read per line.** One bad line never refuses
|
|
the log. An entry needs string `at`, `event`, `release` and `imageTag`,
|
|
an optional string `note`, and no other keys. A line that isn't JSON,
|
|
or is JSON with another shape, is counted in `malformed` and skipped.
|
|
That is stricter than `release.sh rollback`, which skips only lines that
|
|
aren't JSON and would act on an entry with an extra key or a non-string
|
|
field. Blank lines aren't counted. `last` must be a positive integer and
|
|
keeps the newest entries.
|
|
- **Errors.** Every refusal is a `RunsError` with `exitCode` 2 (invalid
|
|
data) or 4 (a file or environment problem), matching
|
|
`mosaic-task.mjs`. A missing data root, `runs/` or `state/` file is not
|
|
an error. A path that can't be resolved for another reason (a link
|
|
loop, a permission error) or a directory that can't be read refuses
|
|
instead of reading as empty.
|
|
|
|
## How mosaic-task.mjs uses it
|
|
|
|
`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.
|
|
`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:
|
|
|
|
| Case | Before | Now |
|
|
|---|---|---|
|
|
| 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)` |
|
|
| `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 |
|
|
| run directory unreadable (mode 000) | `show` printed two lines, then crashed, exit 1 | refuses with EACCES, exit 4 |
|
|
| link loop or a permission error resolving a run | `run not found` | refuses with the error code, exit 4 |
|
|
|
|
`agents/rocko/work/queue-56/delta-check.sh` prints the before and after
|
|
for each case.
|