A record of a review, kept as it stood; what it found is fixed in protocol-v1.md or listed there under Open.
The maintainer asked for "a high quality document and code review" (f68898def7). Five reviewers read v1 at 485bbd7e69: the documents alone, as an outside implementer would; the node against the rules; the tools against their documents; security; and the code's clarity. Codex reviewed ca02aaad5d0e and 7c019867e397. This page lists what they found: what is fixed, and what is left, so the next agent can take it up.
Fixed
| Check-in | What |
|---|---|
| ca02aaad5d | create's form missing from the web page; every tool, field and operation description rewritten as plain sentences; the context's pre-v1 node (a server-code) removed |
| 7c019867e3 | The critical finding: a run's paths could reach the release root and replace the program the hook runs. Also edits of posts acted on; signals misread as limits; TERM misread as a stop; a lost run's program left running; the run's lock emptied by a second watcher; a deleted sender freezing a run; limits overflowing after started; a run's user and checkout unchecked before the disk; a session's input unbounded; create's pattern fetched for anyone |
| 19e85669d2 | --user on the command line taken from create; dry runs hiding the node's act; a written run's hash lost when the act failed; run's refusals and reasons; status naming no offer; inherited capabilities left out; the relay's bound miscounted |
| 1a607da3ae | Runs written whole, the runner pages gone (HISTORY.md decision 42): protocol item 6, create reading only an admin's or setup's version of the served repository's own pattern page, and the environment a program starts in |
| 07858e8c8b | A run's password on fossil clone's command line, readable in /proc: the URL now reaches fossil on its standard input |
Left in the code
- Two people start one manual run at once (failure case 8). The node's
decision and the hand-off to a watcher are not one step. A second
runin that window may answer that it handed the run on; the second watcher then writes nothing. The protocol's promise holds, onestartedand one program, but the second tool's answer is not "refused". Fix: the node takes the run's lock under its own lock before handing it on, and passes it to the watcher (src/ocx/hook.cr,hand; src/ocx/watcher.cr,watch). - Workspaces are never removed: one clone per run, under the release
root's
agents. - Each round reads every OCX message in the repository, with its text. It is cheap today, and grows with the repository.
- Clarity, from the code review:
- names from before v1:
Said#record,records_namedandWriteStop'srecord(a thread or ticket: useWhere);Template(a runner's page); "agents" for the workspaces' root;Catalog; "unit" and "task" in src/ocx/sandbox.cr; "login" where Fossil says user, in identifiers; - repeats:
Fossil::Place.new(File.dirname(r), home, repository: r), 30 times; two bubblewrap planners and three types of limits; fenced JSON found three ways; - docs/crystal.md's rules:
Session.startandSandbox.startstart children withoutclear_env; tuples of one type returned and read by position.
- names from before v1:
- Code only specs call:
Releases.accept,Staging.release,Messages.read,Commands.names. - Documents that predate v1: ARCHITECTURE.md (a node daemon, a live stream), docs/design/events.json, and PLAN.md's table of what is missing.
Left in the protocol: the maintainer's to decide
- The receipt service. A node on a clone, and a reader there, must ask
the server who sent an artifact (section 8), but its request, answer and
authentication are not specified. Its answer gives the receipt's number,
not the row number that orders artifacts within one receipt (section 1).
So no other project can build a node on a clone, and a reader on a clone
cannot reproduce the order (codex; the documents' review).
Answered by HISTORY.md decision 43: the node signs in through Fossil's
login page, and
receiptanswers each artifact's row number too. - A run's user across nodes. The server's node sets a fresh password on
a run's user each time; a node on another host holding that user's
password then loses it. "One run at a time for each
user" holds within one node only. Either a run's user belongs to one node, or a page such asnode/NAMElists each node's run users (codex; the documents' review). Answered by decision 43: a run user works for the node of the first run that named it, and every other node refuses it. - Recovery. Section 1 says every open request "is found again after any
failure", and section 4 that no run is left open; both rest on the
deliberate check. It is not specified when that check runs or what it
reads. A stop the hook missed, for a program still running, is acted on
by nothing (codex; the documents' review). Answered: section 10 says it
runs at the node's start and whenever its administrator runs it again
(
hook --node USER), reads every run for the node from the repository, and ends a running program whose stop it finds. - A
civerdict counts when "theuserof the run it names" wrote it. Anyone may write a run naming themselves; require that run to have astartedthat counts (the documents' review). Answered: the verdicts page requires it. - A check-in's branch is "as the node first reads it" in section 6 and "the branch the check-in's own manifest names" on the verdicts page. Fossil's manifests name a branch only at its first check-in. Answered: both say the branch tag Fossil's timeline shows, as the node reads it.
- Pattern pages.
createfetchesrun/NAMEwithout signing in, and any user holding check-in may push a new version. An admin's nextcreatethen writes the edited run.createcould read only the newest version a user holding admin or setup sent, as a node readssandbox/NAME. Answered by HISTORY.md decision 42:createreads the served repository's own pattern page so, and runs are written whole, so no node readssandbox/NAMEany more. - What the standard leaves unsaid:
- a table of each message's fields (
budget's limit); - the environment a program starts in: answered by decision 42, in section 5;
- OCX's own tools named where any node's would do.
- a table of each message's fields (
How a node came to be named by a user
Before 1a88c92b77 (2026-10-12), a run named its node by the repository's
server-code. Two consistency reviews of the protocol (docs/battery/defs, 16r
and 17r) found that a report must count only when its node's own user sent
it, or anyone who may post could forge one. That user is then the node's
identity readers can check by receipt, so the node is named by it: its node
user. HISTORY.md decisions 37 and 38 build on this. The context's node, a
server-code, was the last of the old naming, and ca02aaad5d removed it.