Login
Check-in [8cac96ce10]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Nothing schedules run-work on the server or from a hook: the server's node, the hook's rounds and decisions, the backoffice start after an ended and poll go, and the after-receive hook is Fossil's own git export

Intent: the maintainer's "go" (2026-10-26) on the design page "How a post reaches an agent", check-in 3 of the 4 of its build plan (Facts, Daemon, Remove, Docs). That page has the public server keep the record and nothing more: "When new posts or check-ins arrive, Fossil stores them. OCX runs nothing then, and OCX never writes on the server"; "One Fossil hook remains: Fossil's own fossil git export, which keeps the git mirror current. It is not OCX code"; and among what OCX never does, "Run anything on the public server when something arrives". The rules this check-in serves are the maintainer's: no hook schedules run-work; the git mirror is Fossil's own after-receive hook running Fossil's own fossil git export; OCX's read-only CGI pages stay on the server; a restart may only cause a pull and an evaluation and must never start a run twice; nothing missed, nothing given twice; and "I'm happy to throw away code that we can do without". The case the maintainer asked to settle stays true with the server's node gone: a run addressed to this node that ended long ago, before the daemon, with no run file, does not start again, as its ended, which OCX's read-only receipt page says the node user sent, counts as done; an ended whose card names the node but which another user sent does not.

Expression: the hook's node goes. src/ocx/hook.cr keeps only Hook::COMMAND, "%F git export --if-mirrored -R %R", the command Fossil 2.27's `fossil all git export` runs (allrepo.c 265; %F and %R, hook.c 95-96; --if-mirrored, export.c 1860; the export's write transaction, export.c 1460, with the backoffice running one hook at a time, so no lock of OCX's), OURS (that command and any old ocx2-hook command), State, Backoffice, Registered and Standing (state, command, others, backoffice, chat_user from chat-timeline-user); Hook.run, its export and answer, check, act, the watcher's hand-on, Run, Acted, the release root's ocx2-hook link and its log go, and with them EntryPoint::Hook (src/ocx/entry.cr, src/ocx/command.cr), whose identification of the served repository now reads its hooks for Hook::COMMAND alone. src/ocx/commands/hook.cr: `hook` takes no root and no login, installs Hook::COMMAND once, replacing any ocx2-hook command and leaving other hooks alone; `unhook` removes both; CheckServing, CheckNodeLogin, CheckRuns and PlaceHook go. src/ocx/node.cr loses round, check, mend, decide, give, listed?, own? and Round, keeping the decisions and deliveries the daemon and each watcher read, with ROOT/node, made 0700, as Node::DIRECTORY; src/ocx/node/view.cr always reads every message, up to a completion number, its read by tags (hold_tagged, listed, tag_untagged) gone, Node.untagged moved into src/ocx/commands/tag_messages.cr, and View is generic over its server's and host's types; src/ocx/decisions.cr counts a report only when the receipt page says the node user sent it (Held#own goes) and passwords is an Array(String); src/ocx/care.cr loses polling and stop_program; src/ocx/server.cr's Here keeps only its reads, for status and audit, while post, password and published are Server::Writer's, which Asked is and the watcher, Launch.steps and Node.verdict hold by type (src/ocx/server/pages.cr, src/ocx/launch.cr, src/ocx/node/sharing.cr), send_left and Asked.from going; src/ocx/fossil/message_tags.cr loses said_tagged_open, said_tagged_about and OpenRuns, src/ocx/fossil/repository.cr start_backoffice, src/ocx/fossil/forum.cr index_stored_posts, src/ocx/fossil/said.cr last_receipt and received_after, src/ocx/fossil.cr the re-entrant turn only the mend took, src/ocx/writes.cr act_at_once and ActOnRun, and src/ocx/commands/create.cr and src/ocx/commands/stop.cr their acted output, the write's chat message waking the daemon; a run must name its node. poll goes (src/ocx/commands/poll.cr deleted, its SignIn, CloneServer and PrepareClone already in src/ocx/commands/daemon.cr, which now places no hook link). src/ocx/watcher.cr: `following` goes, a run that waited being handed by a later daemon round, which the ended's chat message or the chat poll's timeout wakes; Watcher.hand starts ROOT/current/ocx2, resolved at each start, as `watch RUN SERVER CREDENTIALS --repository CLONE [--by-hand]`; every watcher works at completion numbers, Completion.latest (src/ocx/completion.cr) refusing a clone with no server-code or no complete pull yet, so the no-completion mode that posted at once under the node's lock goes from src/ocx/watcher.cr, src/ocx/watcher/reports.cr, src/ocx/watcher/process.cr and src/ocx/watcher/giving.cr, and taken is written before started is posted, as a comment there now says why. src/ocx/commands/watch.cr, new, `watch`, the command line alone, needing setup on the clone, whose default user is the node user and its admin. src/ocx/commands/run.cr moves `run` to the node's machine: `run RUN NODES --repository CLONE` reads the clone's entry in the nodes file, finds and decides the run by hand with the server's receipts up to the clone's completion number (FindRun and ReadCompletion, src/ocx/served.cr) and hands it to `watch --by-hand`. src/ocx/commands/status.cr and src/ocx/commands/console.cr, with src/ocx/console_page.cr and src/ocx/console_text.cr: on the served repository, the record's runs for every node user a run an admin or setup sent names, with no care; given the nodes file and --repository CLONE, the clone's runs up to its completion number with their care and processes, signed in as a logged check, and status's offer (node user, server-code, the limits it enforces); status shows the hook's standing and the daemon's last round from ROOT/node/daemon.log, read by Logged.last (src/ocx/log.cr, was Hook.last, also read by src/ocx/imports.cr). src/ocx/imports_detached.cr, src/ocx/commands/import.cr, src/ocx/commands/import_operations.cr (Hook::COMMAND), src/ocx/commands/attach.cr, src/ocx/commands/audit.cr, src/ocx/daemon.cr, src/ocx/fossil/pulls.cr, src/ocx/mirror.cr, src/ocx/session.cr, src/ocx/workspaces.cr (Workspaces.agents, which only the hook called, goes) and src/ocx/commands.cr follow. Specs: spec/ocx/remote_node_spec.cr is deleted, its behaviors in the daemon's specs, its verdict and share example in spec/ocx/daemon_spec.cr and its refusals in spec/ocx/daemon_refusals_spec.cr; spec/support/local_server.cr, new, a Server::Writer whose post writes straight into a fixture's repository as the node user, so in-process watchers stay fast, each spec giving by writing a completion number the watcher's own Giving reads; Node.round and Node.check in the other specs become a watcher's answers or its giving at a written completion number. Data: docs/design/modules.json and modules.md (commands/poll.cr goes, commands/watch.cr comes, the purposes rewritten), docs/survey/functionality.json ("Log a hook run" and "Be a node on another host" go; the export takes Fossil's own hook), docs/design/facts.json ("chat for timeline events", chat-timeline-user, read by src/ocx/hook.cr), docs/interfaces.md, SCENARIOS.md and docs/backlog.md (the plan's three open points). Every file within 400 lines (precept C1, File Boundedness); nothing added to docs/precepts/exceptions.json; spec/coverage/ratchet.json keeps "missed": [].

Review: Codex (codex-cli 0.162.1, gpt-6.1-sol at high reasoning, in its workspace-write sandbox, which blocks sockets, so it ran only the specs that serve nothing; the reviewer ran every spec, network ones included, and the coverage ratchet after each pass) wrote every line, in seven runs (codex-build-15.log to -21.log beside the build plan); the reviewer's only tree edits are fossil add and fossil rm of the files it made and deleted. Pass 1 stopped with "Selected model is at capacity" after its first large edit, and was resumed in the same session. Review 1, 548 examples, 3 failures (one, spec/guards/outlived_spec.cr's "refutes a fossil program left naming a fixture that is gone", fails by itself on the parent check-in too, twice in two runs, and passed in later runs here), coverage 6704 of 6732: 13 findings: the CLI parser let a required argument take a global flag's place, so `send_runs alice --user stone` refused alice (restored, `watch` and `run` taking bare words, the regression pinned); the daemon setup example and the talk scenario expecting what is gone; 28 statements no spec ran, most of them the refusals remote_node_spec had shown (moved to spec/ocx/daemon_refusals_spec.cr, Workspaces.agents deleted); the no-completion mode, which only the server's node and poll used (removed, and the spec harness's second giving loop and reopened Watcher.watch with it); `run` deciding past the last complete pull (bounded, with spec/ocx/daemon_reads_spec.cr); `.as(Server::Writer)` casts and a Here#post that only refused (post moved to Writer, View generic); watch and run needing nothing while overriding changes? and refusal (now setup, overrides gone); module comments and modules.json purposes cut to a line, stale wording about this release's hook, the spec names that still named the hook; a second copy of a decision's note in console; unrelated fixture changes (reverted); status signing in outside the log; Logged.last's example in the hook's spec. Review 2, 554 examples, 1 failure, coverage 6714 of 6721: `run`'s dry run refused for want of a completion number, which hid attach's; a clone read's ended run; Watcher.hand's check for a missing program, which the daemon and run, themselves that program, never meet (deleted); an unused assignment in watch. Review 3: 554 examples, 0 failures, the ratchet holding. Gemma (gemma4:31b) read the change's sources in four parts and its main specs in a fifth, then the changed parts three more times, after passes 4, 5 and 6 (scratchpad gemma-remove-server-runs-a to -h). Held: create's help sent a person to status for a clone's server-code, which status no longer showed, and Node::ENFORCES was read nowhere; status on the node's machine shows the node's offer again (pass 4). Misread, a clarity finding, the code changed and asked again: Asked#arguments taken as missing watch's flags (its comment says they are watch's SERVER and CREDENTIALS words); View's "only a view holding a Writer can post" taken as unenforced (it says the compiler refuses it); Giving's server-code taken as possibly nil (it says Watcher.watch refuses first, and Completion.latest names a clone with no server-code apart from one with no complete pull) (pass 4); taken read as written after started is posted, so a killed watcher could launch twice (the order was right; a comment now says why it matters) (pass 5); run's and watch's examples read as naming a root (they name the nodes and credentials files) (pass 6). Wrong: a Giving made with no completion number, a post's wait on a clone never pulled, `run` reading past its bound, a release root whose current link is not updated (each refused or bounded before it); Here naming no sender for a local write (it reads the local receipt's user); started_here? turning another clone's started into lost (it answers nothing, as that clone may hold the process); status with a nodes file and no root failing with a type error (it refuses, saying so); console falling back when its sign-in fails (an explicit nodes file is refused); `hook` replacing any export hook (only its own command and old ocx2-hook commands); the imports directory made without its parent's mode (Dir.mkdir_p applies it to each); audit losing a report Held#own counted (own never read the receipt page; the local receipt's user is the sender); the share example reading a local checkout (AtHost.place is the served repository); Giving made from a view of Here (Watcher.watch takes a Writer, Giving a view with a host); a post's wait unbounded with the daemon down (the retry is the next complete pull, by design S3, which the service manager's restart brings); run's NODES not taken from the command line (it is its second bare word); run's of_clone? call read as passing its block wrongly (the fix it gives is the line as written); DecideRun's completion not a field (it is a getter). Not in this check-in: the documents that describe what was removed (USAGE, protocol v1, GLOSSARY, HISTORY decision 125; check-in 4), and protocol v1's refusal row 11.

Demonstrates: spec/ocx/daemon_spec.cr (a run that waited for its user's other run is handed by a later round once that run has ended, with no state written by the watcher that waited; a build's verdict pushed once to the named remote and checked on the receipt page, a share only with y, the default remote left as it was; the round's watch command line; a run ended before the daemon by lab-1 settled and one with mallory's forged ended handed, unchanged), spec/ocx/daemon_reads_spec.cr (run and watch refused before a complete pull; mid-pull reports hidden from run, status and console; a run present mid-pull not found), spec/ocx/daemon_refusals_spec.cr (insecure or decorated URLs, unreadable or shared credentials, an unreachable server, receipt answers malformed, oversized, failed or refused, a bad login, a missing run password, a verdict unsent or received from another user), spec/ocx/daemon_pages_spec.cr, spec/ocx/watch_spec.cr (the current release's watch command with its words, following an accept; the node directory 0700; watch needing a root and a clone; a run answered through Fossil's pages; withheld from CGI and MCP), spec/ocx/hook_spec.cr (Fossil's own git export installed once, replacing ocx2-hook, other hooks left; run by Fossil's backoffice after a sync, bringing the export up to date; backoffice standing and the chat user; refusals, a dry run and the entry points), spec/ocx/run_spec.cr (a manual run decided with receipts and handed to watch --by-hand; served status for every node user an admin's run names, never reading server locks as care; a clone's care, processes and offer with its nodes file; the daemon's last round; stop writing as its caller), spec/ocx/run_states_spec.cr, spec/ocx/run_pages_spec.cr, spec/ocx/giving_spec.cr, spec/ocx/completion_spec.cr, spec/ocx/command_spec.cr (send_runs alice --user stone keeping stone as the acting user), spec/ocx/node_spec.cr, spec/ocx/watcher_spec.cr, spec/ocx/turned_away_spec.cr, spec/ocx/decisions_spec.cr, spec/ocx/console_spec.cr, spec/ocx/create_spec.cr, spec/ocx/dry_run_spec.cr, spec/ocx/asked_spec.cr, spec/ocx/attach_spec.cr, spec/ocx/care_spec.cr, spec/ocx/elements_spec.cr, spec/ocx/ending_spec.cr, spec/ocx/ends_spec.cr, spec/ocx/export_spec.cr, spec/ocx/harness_spec.cr, spec/ocx/import_spec.cr, spec/ocx/imports_detached_spec.cr, spec/ocx/logins_spec.cr, spec/ocx/mcp_spec.cr, spec/ocx/message_tags_spec.cr, spec/ocx/program_spec.cr, spec/ocx/release_bounds_spec.cr, spec/ocx/steps_spec.cr, spec/ocx/terminal_spec.cr, spec/ocx/writers_spec.cr, spec/scenarios/audit_spec.cr, spec/scenarios/build_spec.cr, spec/scenarios/ci_spec.cr, spec/scenarios/question_spec.cr and spec/scenarios/talk_spec.cr, with spec/support/local_server.cr, spec/support/at_host.cr, spec/support/daemon_node.cr, spec/support/fixture.cr and spec/support/stand_in_fossil.cr; spec/guards/external_programs_spec.cr (src/ocx/session.cr starting a run's watcher or session) and spec/guards/outlived_spec.cr (the fixture server's backoffice alone) follow; the sources src/ocx/hook.cr, src/ocx/commands/hook.cr, src/ocx/commands/watch.cr, src/ocx/commands/run.cr, src/ocx/commands/status.cr, src/ocx/commands/console.cr, src/ocx/console_page.cr, src/ocx/console_text.cr, src/ocx/watcher.cr, src/ocx/watcher/reports.cr, src/ocx/watcher/giving.cr, src/ocx/watcher/process.cr, src/ocx/completion.cr, src/ocx/daemon.cr, src/ocx/commands/daemon.cr, src/ocx/node.cr, src/ocx/node/view.cr, src/ocx/node/sharing.cr, src/ocx/decisions.cr, src/ocx/care.cr, src/ocx/server.cr, src/ocx/server/pages.cr, src/ocx/launch.cr, src/ocx/served.cr, src/ocx/entry.cr, src/ocx/command.cr, src/ocx/commands.cr, src/ocx/commands/create.cr, src/ocx/commands/stop.cr, src/ocx/writes.cr, src/ocx/fossil.cr, src/ocx/fossil/forum.cr, src/ocx/fossil/message_tags.cr, src/ocx/fossil/pulls.cr, src/ocx/fossil/repository.cr, src/ocx/fossil/said.cr, src/ocx/log.cr, src/ocx/imports.cr, src/ocx/imports_detached.cr, src/ocx/commands/import.cr, src/ocx/commands/import_operations.cr, src/ocx/commands/tag_messages.cr, src/ocx/commands/attach.cr, src/ocx/commands/audit.cr, src/ocx/mirror.cr, src/ocx/session.cr and src/ocx/workspaces.cr; spec/guards/size_spec.cr, spec/guards/causation_spec.cr, spec/guards/survey_spec.cr, spec/guards/interfaces_spec.cr, spec/guards/derivation_spec.cr and spec/guards/sourcing_spec.cr hold them. crystal run ci.cr green: 555 examples, 0 failures.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QVpmCsBwVF3d4zhMHHDAxs

Downloads: Tarball | ZIP archive
Timelines: family | ancestors | descendants | both | agent-tools
Files: files | file ages | folders
SHA3-256: 8cac96ce1018ad882ae79e06c6e573c181366fe062fc97bf17c2007596eeb9e6
User & Date: opus-ocx2 2026-10-26 12:31:00.441
Context
2026-10-26
13:54
The documents say how a post reaches an agent: the approved page in the tree, USAGE and protocol v1 without the hook's node or poll, and decision 125 in the maintainer's words

Intent: the maintainer's "go" (2026-10-26, at the terminal) on the design page "How a post reaches an agent", check-in 4 of the 4 of its build plan (Facts, Daemon, Remove, Docs), which a4cceed157, ef83839803 and 8cac96ce10 built in code. This check-in makes the documents say what that code does, so a reader learns the design from the tree and not from code that is gone: one daemon per agent machine, a watcher per run, Fossil's own git export as the only hook, nothing run on the public server when something arrives. It records the decision in the maintainer's own words, "go", and, from the same day at the terminal, "A simple design is FAR more important to me than something that saves a few seconds in response." and "I'm happy to throw away code that we can do without." The rules it serves are the maintainer's: no hook schedules run-work; the git mirror is Fossil's own after-receive hook running Fossil's own fossil git export; OCX's read-only CGI pages stay on the server; a restart may only cause a pull and an evaluation and must never start a run twice; nothing missed, nothing given twice. The case the maintainer asked to settle is now stated in protocol v1 itself (docs/protocol-v1.md, section 10): a run with no state file whose ended OCX's receipt page says this node user sent counts as done, so no watcher takes it, however long ago it ended; an ended another user sent, whatever its user card says, does not count.

Expression: docs/how-a-post-reaches-an-agent.md, new, is the approved page word for word (byte for byte the text Gemma checked); knowledge-map.json names it once (kind guide, area Protocol v1, answering "How does a post reach an agent?") and docs/knowledge-map.md is regenerated; README.md's "How is it put together?" is two sentences linking it. USAGE.md: the Tools table gains "Run a node" (daemon NODES) and "Watch one run on a node" (watch RUN SERVER CREDENTIALS --repository CLONE [--by-hand]), loses "Be a node on another host", and the unbuilt live stream is "See a run live" with no CLI or MCP name claimed (its name is open in docs/backlog.md), so `watch` names only the built watcher; "Start a manual run by hand" is `run RUN NODES --repository CLONE` on the agent machine, setup on the clone, refusing a run its node leaves waiting; "Write a run" says a run must name its node and how a password reaches a user create made; create and stop answer no act at once; "Install or remove the hook" says hook installs %F git export --if-mirrored -R %R, that after accepting this release `ocx2 --repository REPO hook` must be run once on each served repository whose hook still runs ROOT/ocx2-hook (the old link now starts the command line, which does not take its words, and nothing is exported until then), and what chat-timeline-user does (Fossil 2.27, chat.c 133-143); "Run a node" (Fossil 2.27, bubblewrap, GNU timeout, register and approve, goC4w with i for verdicts and y for shares, ROOT/node/nodes.json, the service unit with Restart=always, RestartSec=10, StartLimitIntervalSec=0 and KillMode=process, daemon --dry-run, moving from hook --login NAME) replaces "Add a node on another host"; the status and console paragraphs say what they read. docs/protocol-v1.md: "What it is for" has one daemon per machine woken by Fossil's chat and reports posted through Fossil's pages; section 4 keeps each run's state and each clone's completion number (each NEW TERM, needs approval); section 9's "only what arrives", "known senders first" and "told when held back" (each session's watcher, for its own session); section 10's closing paragraph (the daemon reads every message at each start, the run states, the settled case); section 11 row 11 (a verdict asked of a node user lacking Check-In); section 13 "node user" for "the node's login". docs/protocol-v1-fossil.md sections 1, 2, 3 and 5, docs/protocol-v1-failures.md (cases 1 to 36 keep their numbers and what their specs show; cases 37 to 41 are the design page's failure table), docs/protocol-v1-tools.md (run, stop, daemon, watch, hook, status, console), docs/protocol-v1-verdicts.md and docs/protocol-v1-examples.md (node user), ARCHITECTURE.md (its points and drawing: the person posting, the daemon, the watcher, the run user's own clone), GLOSSARY.md (Agent machine, Daemon, Node user, Run state and Completion number added, the last two NEW TERM, needs approval; Node, Watcher, Hook, Manual run, Delivery and Clone, the key rewritten; Poll and The node's login removed), PLAN.md, SCENARIOS.md, docs/fossil.md ("Hooks"), docs/refresher.md (questions 2, 3, 4 and 6 and their answers), docs/remote-agents.md (a secret is set on the node's clone), docs/parity-v1.md, docs/backlog.md (items the removal settled or made false), docs/interfaces.md (the rows naming the mend, the console's JSON, a run user's password), docs/design/modules.json with docs/design/modules.md regenerated, and docs/survey/functionality.json (console's reads) follow. HISTORY.md decision 125 quotes only the maintainer, marks the rest as the agent's words, names what it changes of decisions 37, 39, 84, 87, 103, 108, 121 and 122, and records the build plan's eight choices as the agent's, not decisions; KEEP.md has one line under decision 39, marked as the agent's words, touching no quote. Every Markdown file is within 400 lines (precept C1, File Boundedness), docs/interfaces.md keeps every contract pinned (precept C7, Pinned Interfaces), nothing is added to docs/precepts/exceptions.json, and no src/ or spec/ file changes. Records (the older decisions, docs/slices*.md, docs/review-v1*.md) stay as they stood. Not done here: the plan's Fossil tech-note of Gemma's answers, recorded in this comment instead.

Review: Codex (codex-cli 0.162.1, gpt-6.1-sol at high reasoning, in its workspace-write sandbox, which blocks sockets) wrote every line, in six runs, codex-build-22.log to -27.log beside the build plan; the reviewer's only tree edits are the fossil add of docs/how-a-post-reaches-an-agent.md and this comment. Review 1 (19 findings): decision 125 broke HISTORY.md's one-line form and named the plan's S1 to S8; KEEP.md's new line was not marked as the agent's words; USAGE.md said Fossil suppresses chat messages from chat-timeline-user (chat.c 133-143 says they come from that user and are read as wiki markup), said this release has no ocx2-hook program (the old link starts the command line), and told an administrator to supply a password create never shows; status's form differed between two sections; "node machine" against the approved page's "agent machine"; "login" for the node user in protocol v1 sections 3, 8, 10 and 13, GLOSSARY.md, ARCHITECTURE.md, parity and failures; "recovery" and other undefined shorthand; protocol v1 lacked the settled case; section 4 lost "nothing a reader of the record depends on"; "known senders first" and case 24 against giving.cr, and "the current code" in a definition; "the check" in case 36; the GLOSSARY watcher entry dropped what is still true (decisions 103, 108 and 122, the launch chain); ARCHITECTURE.md's drawing dropped the person posting and the run user's own sync; backlog items made false (the mend, "the server's node"); parity's daemon row; link text "how". Review 2 (6): removing the blank line before protocol v1's first table made Fossil render it as a paragraph (fossil test-markdown-render), and unrelated protocol v1 and USAGE sentences were cut to save lines (restored, room taken from the added text); docs/interfaces.md and docs/survey/functionality.json still described the deleted mend and the console's "this host's node". Review 3 (4): the console's JSON field (nodes, not node), a run user's password and "the node's check" in docs/interfaces.md, and "a node's login" in protocol-v1-verdicts and -examples. The reviewer ran every guard, network ones included, after passes 1 and 4 (spec/guards: 109 examples; spec/guards/outlived_spec.cr's "refutes a fossil program left naming a fixture that is gone" failed alone, as it has on the parent check-ins, and is no document's). Gemma (gemma4:31b) read the change in five parts, then again after passes 5 and 6 (scratchpad gemma-run-work-docs-a to -e, -a2 to -e2, -a3 to -d3). Held, fixed in pass 5: GLOSSARY.md defined no "agent machine"; "every node an administrator named" beside "every node user an administrator's run names"; the secret's "node clone" and "node's clone". Misread, a clarity finding, the words changed and asked again: the console row's "which shows runs only with its nodes file", the run-work row's "a confirmed ended" (pass 5); run's "needs setup", read as on the server, run's "waiting run", read as one waiting for a person, and "the clone rule", defined nowhere (pass 6). Wrong (50 of the 58 findings, many raised again in a later read, each checked against the code or the documents): the approved page's "for each request that may run, start a watcher", "one Fossil hook remains" and "it is not OCX code" (word for word by design; protocol v1 and USAGE say a refusal, stop or lost is handed too, and the hook is Fossil's own command, which `hook` installs); NODES read as a JSON argument, and the served secret form and the CGI write tools read as gone (the reviewer's intent text was loose at first: NODES is a file, and the write tools remain, as the documents and the backlog say); protocol v1 section 13's "Instead of" column read as a definition (outside the diff's context; asked with the header, Gemma read it right, scratchpad gemma-run-work-docs-section13.txt); "login" asked for in place of "node user" (Fossil's word is user); goC4w, i and y "missing" from section 5 (stated two lines on); run "not checking" the node user and clone, and not refusing an unapproved one (run.cr refuses another node or clone, and its sign-in refuses an unapproved user); "pulls first" missing (stated above it); the hook "only runs" the export (--if-mirrored is that command); `taken`, the watcher, goC4w and "completion number" used before definition (protocol v1 section 4 and GLOSSARY.md define them, and USAGE.md sends its reader to GLOSSARY.md first); docs/fossil.md's link to how-a-post-reaches-an-agent.md (relative to docs/, and documents_spec resolves it); case 21's run written into the clone (it has no server receipt and allows nothing); status reading ROOT/node/daemon.log and listing open runs, and console's "Runs: none known here" (the code does each); the watcher reading its credentials file and putting each delivery in the inbox (it does both); the receipt page asked about the node's own reports (it is, so a forged ended counts for nothing); a build's verdict written as the node user (i is for verdicts); HISTORY.md and the backlog read as contradicting (one states the rule, the other its known exception, decision 124); the live stream's row (its status says missing); and requests to list again what a linked page lists, or to repeat a consequence already said. Gemma, given only docs/how-a-post-reaches-an-agent.md and the approved page's 15 questions (thinking off), answered all 15 right, as on the wiki page: 1. Fossil stores the post and adds a short line to its chat page. 2. The daemon asks the server's `/chat-poll` page for chat lines newer than the last one seen. 3. The daemon checks if Fossil saved the server's address as the clone's remote; if not, it waits a few seconds and pulls again. 4. It identifies artifacts with a receipt number higher than the highest one it has already handled. 5. It asks the server's `receipt` page who sent the request. 6. A lock on a small file named for the run ensures only one watcher works on it, and a file that says "done" is never started again. 7. The daemon reads everything once more, but since run files track progress, nothing starts twice. 8. No OCX code runs on the public server when something arrives. 9. The agent writes its own answers as its own Fossil user. 10. It only causes one more pull. 11. No; people's posts come from their own clones or Fossil's own forum page. 12. It comes from Fossil's own `fossil git export` hook. 13. Nothing is lost or done twice because the daemon reads everything once more upon restart and run files prevent duplicate starts. 14. A pull arrives in several parts, so the clone might hold a request but not a later post that stops it. 15. The chat line is only a signal that something is new; the actual work is read from the repository.

Demonstrates: spec/guards/delineation_spec.cr (docs/how-a-post-reaches-an-agent.md named once in knowledge-map.json and reached from README.md), spec/guards/documents_spec.cr (every document renders, every link and anchor resolves, ARCHITECTURE.md's drawing among them), spec/guards/size_spec.cr (USAGE.md, docs/protocol-v1.md and docs/fossil.md at 400 lines), spec/guards/decisions_spec.cr (decision 125 cites the maintainer and a date), spec/guards/interfaces_spec.cr (docs/interfaces.md's rows and SCENARIOS.md's tools), spec/guards/survey_spec.cr (docs/survey/functionality.json, docs/survey/gaps.json exact), spec/guards/derivation_spec.cr and spec/guards/deliberation_spec.cr (docs/design/modules.md and docs/knowledge-map.md as spec/support/generate.cr writes them), spec/guards/entries_spec.cr (GLOSSARY.md defines each kind the code writes) and spec/ocx/examples_spec.cr (docs/protocol-v1-examples.md read as a node reads it) hold the documents README.md, KEEP.md, HISTORY.md, PLAN.md, ARCHITECTURE.md, GLOSSARY.md, USAGE.md, SCENARIOS.md, knowledge-map.json, docs/knowledge-map.md, docs/how-a-post-reaches-an-agent.md, docs/protocol-v1.md, docs/protocol-v1-fossil.md, docs/protocol-v1-failures.md, docs/protocol-v1-tools.md, docs/protocol-v1-verdicts.md, docs/protocol-v1-examples.md, docs/fossil.md, docs/interfaces.md, docs/backlog.md, docs/parity-v1.md, docs/refresher.md, docs/remote-agents.md, docs/design/modules.json, docs/design/modules.md and docs/survey/functionality.json. crystal run ci.cr green: 555 examples, 0 failures.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QVpmCsBwVF3d4zhMHHDAxs check-in: e92855a0e0 user: opus-ocx2 tags: agent-tools

12:31
Nothing schedules run-work on the server or from a hook: the server's node, the hook's rounds and decisions, the backoffice start after an ended and poll go, and the after-receive hook is Fossil's own git export

Intent: the maintainer's "go" (2026-10-26) on the design page "How a post reaches an agent", check-in 3 of the 4 of its build plan (Facts, Daemon, Remove, Docs). That page has the public server keep the record and nothing more: "When new posts or check-ins arrive, Fossil stores them. OCX runs nothing then, and OCX never writes on the server"; "One Fossil hook remains: Fossil's own fossil git export, which keeps the git mirror current. It is not OCX code"; and among what OCX never does, "Run anything on the public server when something arrives". The rules this check-in serves are the maintainer's: no hook schedules run-work; the git mirror is Fossil's own after-receive hook running Fossil's own fossil git export; OCX's read-only CGI pages stay on the server; a restart may only cause a pull and an evaluation and must never start a run twice; nothing missed, nothing given twice; and "I'm happy to throw away code that we can do without". The case the maintainer asked to settle stays true with the server's node gone: a run addressed to this node that ended long ago, before the daemon, with no run file, does not start again, as its ended, which OCX's read-only receipt page says the node user sent, counts as done; an ended whose card names the node but which another user sent does not.

Expression: the hook's node goes. src/ocx/hook.cr keeps only Hook::COMMAND, "%F git export --if-mirrored -R %R", the command Fossil 2.27's `fossil all git export` runs (allrepo.c 265; %F and %R, hook.c 95-96; --if-mirrored, export.c 1860; the export's write transaction, export.c 1460, with the backoffice running one hook at a time, so no lock of OCX's), OURS (that command and any old ocx2-hook command), State, Backoffice, Registered and Standing (state, command, others, backoffice, chat_user from chat-timeline-user); Hook.run, its export and answer, check, act, the watcher's hand-on, Run, Acted, the release root's ocx2-hook link and its log go, and with them EntryPoint::Hook (src/ocx/entry.cr, src/ocx/command.cr), whose identification of the served repository now reads its hooks for Hook::COMMAND alone. src/ocx/commands/hook.cr: `hook` takes no root and no login, installs Hook::COMMAND once, replacing any ocx2-hook command and leaving other hooks alone; `unhook` removes both; CheckServing, CheckNodeLogin, CheckRuns and PlaceHook go. src/ocx/node.cr loses round, check, mend, decide, give, listed?, own? and Round, keeping the decisions and deliveries the daemon and each watcher read, with ROOT/node, made 0700, as Node::DIRECTORY; src/ocx/node/view.cr always reads every message, up to a completion number, its read by tags (hold_tagged, listed, tag_untagged) gone, Node.untagged moved into src/ocx/commands/tag_messages.cr, and View is generic over its server's and host's types; src/ocx/decisions.cr counts a report only when the receipt page says the node user sent it (Held#own goes) and passwords is an Array(String); src/ocx/care.cr loses polling and stop_program; src/ocx/server.cr's Here keeps only its reads, for status and audit, while post, password and published are Server::Writer's, which Asked is and the watcher, Launch.steps and Node.verdict hold by type (src/ocx/server/pages.cr, src/ocx/launch.cr, src/ocx/node/sharing.cr), send_left and Asked.from going; src/ocx/fossil/message_tags.cr loses said_tagged_open, said_tagged_about and OpenRuns, src/ocx/fossil/repository.cr start_backoffice, src/ocx/fossil/forum.cr index_stored_posts, src/ocx/fossil/said.cr last_receipt and received_after, src/ocx/fossil.cr the re-entrant turn only the mend took, src/ocx/writes.cr act_at_once and ActOnRun, and src/ocx/commands/create.cr and src/ocx/commands/stop.cr their acted output, the write's chat message waking the daemon; a run must name its node. poll goes (src/ocx/commands/poll.cr deleted, its SignIn, CloneServer and PrepareClone already in src/ocx/commands/daemon.cr, which now places no hook link). src/ocx/watcher.cr: `following` goes, a run that waited being handed by a later daemon round, which the ended's chat message or the chat poll's timeout wakes; Watcher.hand starts ROOT/current/ocx2, resolved at each start, as `watch RUN SERVER CREDENTIALS --repository CLONE [--by-hand]`; every watcher works at completion numbers, Completion.latest (src/ocx/completion.cr) refusing a clone with no server-code or no complete pull yet, so the no-completion mode that posted at once under the node's lock goes from src/ocx/watcher.cr, src/ocx/watcher/reports.cr, src/ocx/watcher/process.cr and src/ocx/watcher/giving.cr, and taken is written before started is posted, as a comment there now says why. src/ocx/commands/watch.cr, new, `watch`, the command line alone, needing setup on the clone, whose default user is the node user and its admin. src/ocx/commands/run.cr moves `run` to the node's machine: `run RUN NODES --repository CLONE` reads the clone's entry in the nodes file, finds and decides the run by hand with the server's receipts up to the clone's completion number (FindRun and ReadCompletion, src/ocx/served.cr) and hands it to `watch --by-hand`. src/ocx/commands/status.cr and src/ocx/commands/console.cr, with src/ocx/console_page.cr and src/ocx/console_text.cr: on the served repository, the record's runs for every node user a run an admin or setup sent names, with no care; given the nodes file and --repository CLONE, the clone's runs up to its completion number with their care and processes, signed in as a logged check, and status's offer (node user, server-code, the limits it enforces); status shows the hook's standing and the daemon's last round from ROOT/node/daemon.log, read by Logged.last (src/ocx/log.cr, was Hook.last, also read by src/ocx/imports.cr). src/ocx/imports_detached.cr, src/ocx/commands/import.cr, src/ocx/commands/import_operations.cr (Hook::COMMAND), src/ocx/commands/attach.cr, src/ocx/commands/audit.cr, src/ocx/daemon.cr, src/ocx/fossil/pulls.cr, src/ocx/mirror.cr, src/ocx/session.cr, src/ocx/workspaces.cr (Workspaces.agents, which only the hook called, goes) and src/ocx/commands.cr follow. Specs: spec/ocx/remote_node_spec.cr is deleted, its behaviors in the daemon's specs, its verdict and share example in spec/ocx/daemon_spec.cr and its refusals in spec/ocx/daemon_refusals_spec.cr; spec/support/local_server.cr, new, a Server::Writer whose post writes straight into a fixture's repository as the node user, so in-process watchers stay fast, each spec giving by writing a completion number the watcher's own Giving reads; Node.round and Node.check in the other specs become a watcher's answers or its giving at a written completion number. Data: docs/design/modules.json and modules.md (commands/poll.cr goes, commands/watch.cr comes, the purposes rewritten), docs/survey/functionality.json ("Log a hook run" and "Be a node on another host" go; the export takes Fossil's own hook), docs/design/facts.json ("chat for timeline events", chat-timeline-user, read by src/ocx/hook.cr), docs/interfaces.md, SCENARIOS.md and docs/backlog.md (the plan's three open points). Every file within 400 lines (precept C1, File Boundedness); nothing added to docs/precepts/exceptions.json; spec/coverage/ratchet.json keeps "missed": [].

Review: Codex (codex-cli 0.162.1, gpt-6.1-sol at high reasoning, in its workspace-write sandbox, which blocks sockets, so it ran only the specs that serve nothing; the reviewer ran every spec, network ones included, and the coverage ratchet after each pass) wrote every line, in seven runs (codex-build-15.log to -21.log beside the build plan); the reviewer's only tree edits are fossil add and fossil rm of the files it made and deleted. Pass 1 stopped with "Selected model is at capacity" after its first large edit, and was resumed in the same session. Review 1, 548 examples, 3 failures (one, spec/guards/outlived_spec.cr's "refutes a fossil program left naming a fixture that is gone", fails by itself on the parent check-in too, twice in two runs, and passed in later runs here), coverage 6704 of 6732: 13 findings: the CLI parser let a required argument take a global flag's place, so `send_runs alice --user stone` refused alice (restored, `watch` and `run` taking bare words, the regression pinned); the daemon setup example and the talk scenario expecting what is gone; 28 statements no spec ran, most of them the refusals remote_node_spec had shown (moved to spec/ocx/daemon_refusals_spec.cr, Workspaces.agents deleted); the no-completion mode, which only the server's node and poll used (removed, and the spec harness's second giving loop and reopened Watcher.watch with it); `run` deciding past the last complete pull (bounded, with spec/ocx/daemon_reads_spec.cr); `.as(Server::Writer)` casts and a Here#post that only refused (post moved to Writer, View generic); watch and run needing nothing while overriding changes? and refusal (now setup, overrides gone); module comments and modules.json purposes cut to a line, stale wording about this release's hook, the spec names that still named the hook; a second copy of a decision's note in console; unrelated fixture changes (reverted); status signing in outside the log; Logged.last's example in the hook's spec. Review 2, 554 examples, 1 failure, coverage 6714 of 6721: `run`'s dry run refused for want of a completion number, which hid attach's; a clone read's ended run; Watcher.hand's check for a missing program, which the daemon and run, themselves that program, never meet (deleted); an unused assignment in watch. Review 3: 554 examples, 0 failures, the ratchet holding. Gemma (gemma4:31b) read the change's sources in four parts and its main specs in a fifth, then the changed parts three more times, after passes 4, 5 and 6 (scratchpad gemma-remove-server-runs-a to -h). Held: create's help sent a person to status for a clone's server-code, which status no longer showed, and Node::ENFORCES was read nowhere; status on the node's machine shows the node's offer again (pass 4). Misread, a clarity finding, the code changed and asked again: Asked#arguments taken as missing watch's flags (its comment says they are watch's SERVER and CREDENTIALS words); View's "only a view holding a Writer can post" taken as unenforced (it says the compiler refuses it); Giving's server-code taken as possibly nil (it says Watcher.watch refuses first, and Completion.latest names a clone with no server-code apart from one with no complete pull) (pass 4); taken read as written after started is posted, so a killed watcher could launch twice (the order was right; a comment now says why it matters) (pass 5); run's and watch's examples read as naming a root (they name the nodes and credentials files) (pass 6). Wrong: a Giving made with no completion number, a post's wait on a clone never pulled, `run` reading past its bound, a release root whose current link is not updated (each refused or bounded before it); Here naming no sender for a local write (it reads the local receipt's user); started_here? turning another clone's started into lost (it answers nothing, as that clone may hold the process); status with a nodes file and no root failing with a type error (it refuses, saying so); console falling back when its sign-in fails (an explicit nodes file is refused); `hook` replacing any export hook (only its own command and old ocx2-hook commands); the imports directory made without its parent's mode (Dir.mkdir_p applies it to each); audit losing a report Held#own counted (own never read the receipt page; the local receipt's user is the sender); the share example reading a local checkout (AtHost.place is the served repository); Giving made from a view of Here (Watcher.watch takes a Writer, Giving a view with a host); a post's wait unbounded with the daemon down (the retry is the next complete pull, by design S3, which the service manager's restart brings); run's NODES not taken from the command line (it is its second bare word); run's of_clone? call read as passing its block wrongly (the fix it gives is the line as written); DecideRun's completion not a field (it is a getter). Not in this check-in: the documents that describe what was removed (USAGE, protocol v1, GLOSSARY, HISTORY decision 125; check-in 4), and protocol v1's refusal row 11.

Demonstrates: spec/ocx/daemon_spec.cr (a run that waited for its user's other run is handed by a later round once that run has ended, with no state written by the watcher that waited; a build's verdict pushed once to the named remote and checked on the receipt page, a share only with y, the default remote left as it was; the round's watch command line; a run ended before the daemon by lab-1 settled and one with mallory's forged ended handed, unchanged), spec/ocx/daemon_reads_spec.cr (run and watch refused before a complete pull; mid-pull reports hidden from run, status and console; a run present mid-pull not found), spec/ocx/daemon_refusals_spec.cr (insecure or decorated URLs, unreadable or shared credentials, an unreachable server, receipt answers malformed, oversized, failed or refused, a bad login, a missing run password, a verdict unsent or received from another user), spec/ocx/daemon_pages_spec.cr, spec/ocx/watch_spec.cr (the current release's watch command with its words, following an accept; the node directory 0700; watch needing a root and a clone; a run answered through Fossil's pages; withheld from CGI and MCP), spec/ocx/hook_spec.cr (Fossil's own git export installed once, replacing ocx2-hook, other hooks left; run by Fossil's backoffice after a sync, bringing the export up to date; backoffice standing and the chat user; refusals, a dry run and the entry points), spec/ocx/run_spec.cr (a manual run decided with receipts and handed to watch --by-hand; served status for every node user an admin's run names, never reading server locks as care; a clone's care, processes and offer with its nodes file; the daemon's last round; stop writing as its caller), spec/ocx/run_states_spec.cr, spec/ocx/run_pages_spec.cr, spec/ocx/giving_spec.cr, spec/ocx/completion_spec.cr, spec/ocx/command_spec.cr (send_runs alice --user stone keeping stone as the acting user), spec/ocx/node_spec.cr, spec/ocx/watcher_spec.cr, spec/ocx/turned_away_spec.cr, spec/ocx/decisions_spec.cr, spec/ocx/console_spec.cr, spec/ocx/create_spec.cr, spec/ocx/dry_run_spec.cr, spec/ocx/asked_spec.cr, spec/ocx/attach_spec.cr, spec/ocx/care_spec.cr, spec/ocx/elements_spec.cr, spec/ocx/ending_spec.cr, spec/ocx/ends_spec.cr, spec/ocx/export_spec.cr, spec/ocx/harness_spec.cr, spec/ocx/import_spec.cr, spec/ocx/imports_detached_spec.cr, spec/ocx/logins_spec.cr, spec/ocx/mcp_spec.cr, spec/ocx/message_tags_spec.cr, spec/ocx/program_spec.cr, spec/ocx/release_bounds_spec.cr, spec/ocx/steps_spec.cr, spec/ocx/terminal_spec.cr, spec/ocx/writers_spec.cr, spec/scenarios/audit_spec.cr, spec/scenarios/build_spec.cr, spec/scenarios/ci_spec.cr, spec/scenarios/question_spec.cr and spec/scenarios/talk_spec.cr, with spec/support/local_server.cr, spec/support/at_host.cr, spec/support/daemon_node.cr, spec/support/fixture.cr and spec/support/stand_in_fossil.cr; spec/guards/external_programs_spec.cr (src/ocx/session.cr starting a run's watcher or session) and spec/guards/outlived_spec.cr (the fixture server's backoffice alone) follow; the sources src/ocx/hook.cr, src/ocx/commands/hook.cr, src/ocx/commands/watch.cr, src/ocx/commands/run.cr, src/ocx/commands/status.cr, src/ocx/commands/console.cr, src/ocx/console_page.cr, src/ocx/console_text.cr, src/ocx/watcher.cr, src/ocx/watcher/reports.cr, src/ocx/watcher/giving.cr, src/ocx/watcher/process.cr, src/ocx/completion.cr, src/ocx/daemon.cr, src/ocx/commands/daemon.cr, src/ocx/node.cr, src/ocx/node/view.cr, src/ocx/node/sharing.cr, src/ocx/decisions.cr, src/ocx/care.cr, src/ocx/server.cr, src/ocx/server/pages.cr, src/ocx/launch.cr, src/ocx/served.cr, src/ocx/entry.cr, src/ocx/command.cr, src/ocx/commands.cr, src/ocx/commands/create.cr, src/ocx/commands/stop.cr, src/ocx/writes.cr, src/ocx/fossil.cr, src/ocx/fossil/forum.cr, src/ocx/fossil/message_tags.cr, src/ocx/fossil/pulls.cr, src/ocx/fossil/repository.cr, src/ocx/fossil/said.cr, src/ocx/log.cr, src/ocx/imports.cr, src/ocx/imports_detached.cr, src/ocx/commands/import.cr, src/ocx/commands/import_operations.cr, src/ocx/commands/tag_messages.cr, src/ocx/commands/attach.cr, src/ocx/commands/audit.cr, src/ocx/mirror.cr, src/ocx/session.cr and src/ocx/workspaces.cr; spec/guards/size_spec.cr, spec/guards/causation_spec.cr, spec/guards/survey_spec.cr, spec/guards/interfaces_spec.cr, spec/guards/derivation_spec.cr and spec/guards/sourcing_spec.cr hold them. crystal run ci.cr green: 555 examples, 0 failures.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QVpmCsBwVF3d4zhMHHDAxs check-in: 8cac96ce10 user: opus-ocx2 tags: agent-tools

08:34
One daemon per machine pulls each clone whole on each chat message and hands each open run to a watcher, which keeps the run's state under its lock, posts through Fossil's pages and gives each new post once

Intent: the maintainer's "go" (2026-10-26) on the design page "How a post reaches an agent", check-in 2 of the 4 of its build plan (Facts, Daemon, Remove, Docs). That page has one program on each agent machine, the daemon, do for each clone "over and over" its five steps, Wait, Pull, Find what is new, Decide and Remember, deciding nothing "until the pull is done"; and a watcher for each run that "takes a lock on a small file named for the run", "posts "started", starts the agent in a sandbox, and gives the agent each new post in the run's thread, once", and, when the agent finishes, "posts "ended". The file then says "done", so the run never starts again." The rule this check-in serves is the page's "A restart is safe. A restarted daemon reads everything once more; each run's file still says what already happened, so nothing starts twice", with its "Nothing is missed" and "Nothing runs twice", and the maintainer's rules that a restart may only cause a pull and an evaluation and must never start a run twice, and that OCX never writes as a person. The case the maintainer asked to settle: a run addressed to this node that ended before the daemon, with no run file, does not start again, as its ended, which OCX's read-only receipt page says the node user sent, counts as done; an ended whose card names the node but which another user sent does not.

Expression: src/ocx/daemon.cr, Daemon::Served#round: `fossil remote off`, then `fossil pull ocx-server`, killed past 10 minutes, complete only when Fossil saved the default remote again (Incomplete otherwise, and the daemon exits for its service manager to start again, which pulls first); the clone's highest blob.rcvid written by rename as its completion number, ROOT/node/completed/SERVER-CODE; on the first round every message read up to it, after that what arrived since the last number handled, which starts at 0 in each process, so a restart reads everything once; then, under the node's lock, each run for the node user and clone not settled: its state done, settled; its lock held, skipped; otherwise Decisions.decide with senders from the receipt page, Nothing settled (so a run that ended before the daemon starts no watcher), Wait kept, and anything else handed to a watcher, again at each round until settled, a run handed twice taking one watcher by its lock; Daemon::Served#wait holds /chat-poll at the highest id answered before the last complete pull; Daemon.serve runs one fiber per clone and returns once the release root's current link names another release; one JSON line per round in ROOT/node/daemon.log. src/ocx/commands/daemon.cr, `ocx2 daemon NODES`, withheld from the web page and MCP: one daemon per machine (ROOT/node/daemon.lock, taken without waiting, never in a dry run); poll's joined moved here, an entry whose login is not approved yet passed over and named (Unapproved, src/ocx/commands/register.cr); SignIn refuses a node user holding admin or setup, lacking g, o, C, 4 or w, or whose ticket changes a moderator holds; PrepareClone, logged, names the node user as the clone's default user (Fossil's pull needs it after remote off, docs/fossil.md, "What the daemon relies on") and the remote ocx-server from the default. src/ocx/fossil/pulls.cr: name_remote, pull_whole, highest_receipt, said_between, checkins_between, push_to and sync_unversioned_to, the last two leaving the default remote alone; src/ocx/fossil.cr's private run gains a bound that kills fossil past it and reads no exit status (the one Process call stays one, precept I7, Single Process Site); src/ocx/fossil/said.cr's said and said_in read up to a completion number. src/ocx/server/pages.cr: Server#post, Here writing into its repository as before, Asked posting through /forume2 or /tktedit (csrf, same-origin Referer, mutype=Markdown) and raising Unposted without Fossil's redirect to the stored post; Asked#wake and Asked#held. src/ocx/completion.cr: Completion.write and read, and Completion::Watch, an inotify descriptor per waiter on the completed directory (docs/linux.md). src/ocx/watcher/state.cr: taken, ending and done beside the run's lock, written by rename and fsync only under it, a state that does not read counting as taken. src/ocx/watcher.cr and src/ocx/watcher/reports.cr: on taking the run's lock the words the earlier watcher left are kept, and ended (Node.end_left) where the run is answered lost; done, nothing; ending, the held ended posted, then done; taken, lost; no state, decided as before, Nothing writing done; taken written right before started is posted, the program launched only once Fossil redirected to the stored started; a post with no redirect, on a clone with completion numbers, waits for the next one on a watch of its own and counts as made when the same text, replying to the same post, sent by the node user, is there (Fossil 2.27 stores a forum post without its last newline), and a stop that counts meanwhile makes it post ended stopped and never launch; with no completion numbers (the server's own repository, or a clone poll pulls) a post raises at once, and decisions and posts that cannot wait keep the node's lock as before; the watcher starts in a stated environment holding the account's home (precept C6, Explicit Arguments). src/ocx/watcher/giving.cr: on a clone the watcher gives each new post in its run's thread and each check-in once, in the server's order, at each completion number, never what came before its started, replies for its own session to a person's post it held back naming the filter, ends the program for a stop that counts, and tries a receipt-page failure again at the next number without ending the run. src/ocx/watcher/process.cr holds the launching code moved out of watcher.cr, unchanged but for Time.utc in place of Time.monotonic, as docs/crystal.md has OCX time a run. src/ocx/node.cr: Node.round gives nothing and tags nothing on a clone; the node user's own ended, received from the server, counts as on the server's own repository; src/ocx/node/view.cr reads every message on a clone, up to a completion number, and holds only what the server has received; src/ocx/decisions.cr refuses a run asking a verdict when the node user lacks i; verdicts push with `fossil push --once ocx-server` (src/ocx/server.cr) and shares with `fossil uv sync ocx-server` (src/ocx/node/sharing.cr); Logins::ASKED becomes goC4w (src/ocx/commands/logins.cr), and poll names its remote too (src/ocx/commands/poll.cr), so poll and the hook's node keep working until check-in 3; src/ocx/care.cr, src/ocx/hook.cr, src/ocx/commands.cr and src/ocx/fossil/scratch.cr follow. docs/design/modules.json and modules.md, docs/survey/functionality.json ("Run a node: the daemon"), docs/interfaces.md (the row check-in 1 left, precept C7, Pinned Interfaces) and docs/linux.md (inotify). Every file within 400 lines (precept C1, File Boundedness).

Review: Codex (codex-cli 0.162.1, gpt-6.1-sol at high reasoning, in its workspace-write sandbox, which blocks sockets, so it ran only the specs that serve nothing; the reviewer ran every spec after each pass) wrote every line, in seven passes (codex-build-8.log to -14.log beside the build plan); the reviewer's only tree edit is `fossil add` of the new files. Review 1, 30 findings: of the new specs 4 of 26 failed, and of the old ones 8 failed and remote_node_spec hung, its watcher waiting for a completion number no daemon writes; Fossil stores a post without its last newline, so a stored started was posted twice; Node.round's clone line, the tool list, the dry run's daemon sample, the node user's letters (goC4w, as posting through pages needs) and poll's remote; unnamed limits; handed runs settled for ever, so a run whose watcher waited was missed; lock tries outside the node's lock in the round and in the watcher's decision, which can fail a take; the decision and started on the server's node no longer in one hold, letting a started follow a round's look past a stop; end_left after the lock's words were replaced, ending nothing; giving replying to every post before the run, using another rule for whom it never tells, stopping the run on one receipt failure, reading every check-in ever received, and sharing one inotify descriptor with a post's retry; an equal later reply taken as already posted; the watcher's home; the verdict row's letters; matching an error's text for an unapproved login; comments; the interfaces row; watchers logging into daemon.log; giving's spec copying the repository file instead of pulling. Review 2, 533 examples, 1 failure, 1 error, and watcher_spec and turned_away_spec hung, spec/support/held_watcher.cr overriding the old signatures; 10 findings, among them comments citing the build plan, which is not in the tree, setup writes outside the log (now PrepareClone), and the 2.23 floor claimed for commands pinned on 2.27. Pass 3 ended "Selected model is at capacity" before its report; the reviewer checked its changes. Review 3, 548 examples, 1 failure: a dry run's log, as Registration asks nothing in one. Gemma (gemma4:31b) read the change after pass 4 four times, whole and in three parts, and the changed parts again after passes 5 and 6 (scratchpad gemma-run-daemon-1, -a, -b, -c, -a2, -b2, -b3). Held: a bounded fossil whose wait raises would leave the wait after its KILL unbounded; the fiber now sends what it raised (pass 5). Misread, a clarity finding, the code changed and asked again: a run that waits taken as keeping its lock; `unchecked` taken as letting a pull that exited 0 count (the flag is gone: a bounded run never reads its exit status); the lock's words kept past the block taken as a race; the clone's own-ended check's removal taken as letting another user's ended count, twice (comments now say each, passes 5 and 6). Wrong: SignIn comparing against ASKED's text (it tests each letter with allows?); poll's home nil (Context#home is a String); an empty ask asking the server (it asks nothing); taken to be undone after a failed started (a watcher dying between taken and ending ends its run lost, by the design page's rule, so an unconfirmed started never launches twice); the OOM killer stopping one fiber; a named remote's name taken for a URL; said's bound bypassed by a join (both are inner joins on blob); the old take_run line read from the diff as current; Run#process nil (it is not nilable, and row 2 refuses a run that does not read); recovered not ending what the lock names (it does); write_state failing silently (it raises Refused); the watcher's bound a stale number (it is the newest complete pull). The third read's delivery point cites `counted` as not shown, as its body is outside the diff; the comment beside the check says what it checks. The gate then broke the coverage ratchet: 27 statements of the new code never ran (7075 of 7102); pass 7 added specs that run them (a serve of two clones, one failing, raising that failure once the other's wake is closed; a check-in given to a session; a held ending Fossil had already stored, not posted again; a ticket run's reports through /tktedit; a receipt failure while a post is retried; a giving closed while its reply waits; a completion number and a state that cannot be written) and removed what cannot run (the daemon's refusal fallback for the withheld entry points, a check for an end of file inotify never gives, two repeated checks), and coverage reached 7093 of 7093. Gemma read the changes made after review 2 once more: that a daemon whose pull keeps failing restarts in a tight loop is wrong: its service manager starts it again 10 s later, and a pull raising on its exit status would end the daemon the same way. Not in this check-in: removing the hook's node and poll (check-in 3), and protocol v1's new refusal row 11 and the documents that describe them (check-in 4).

Demonstrates: spec/ocx/daemon_spec.cr, spec/ocx/daemon_pages_spec.cr and spec/ocx/daemon_setup_spec.cr (an incomplete pull writes no completion number and hands nothing; the completion number after each complete pull and each run for its node user and clone handed, again while its lock is free, skipped while held; a done run handed by no restart; a run whose ended lab-1 posted settled with no watcher while mallory's forged ended is handed; a wake within 5 s of a post; a pull after an empty answer brings an approved run; a return once the root serves another release; refusals of admin, setup, a missing C, 4 or w and moderated tickets; the clone made, prepared and named once approved, an unapproved entry named, a dry run changing nothing; a second daemon refused at once; a verdict refused without i; a serve of two clones raising the first failure; a completion number that cannot be written refused), spec/ocx/run_states_spec.cr and spec/ocx/run_pages_spec.cr (states read, unreadable as taken; taken ended lost and ending posted unchanged, then done; done for an ended the node user sent, none for a forged one; what an old lock names ended for taken and for a lost decision, not for done; a held ending already stored finished without a second post; a state that cannot be written refused, the previous stage kept; taken before started, a launch only after the stored started, a retry at the next completion number posting none twice; a stopped ended and no launch for a stop before the redirect, or for one the first giving reads after a stored started; /forume2 and /tktedit with mutype; a ticket run's reports through /tktedit; an unconfirmed ticket change refused), spec/ocx/giving_spec.cr (each new post once in the server's order through real pulls, nothing before started, a reply naming the filter, none to another run's user, a receipt failure retried, the node user's own ended given, equal replies kept apart, a check-in on a branch the session hears given once, a stop from mallory ignored and stone's obeyed, a giving joined while its held-back reply waits), spec/ocx/pulls_spec.cr, spec/ocx/completion_spec.cr and spec/ocx/server_pages_spec.cr, with spec/support/daemon_node.cr, spec/support/pages_proxy.cr and spec/support/fossil_pull.cr; spec/ocx/remote_node_spec.cr, spec/ocx/logins_spec.cr, spec/ocx/ends_spec.cr, spec/ocx/dry_run_spec.cr, spec/ocx/command_spec.cr, spec/ocx/turned_away_spec.cr and spec/support/held_watcher.cr follow the change; the sources src/ocx/daemon.cr, src/ocx/commands/daemon.cr, src/ocx/completion.cr, src/ocx/fossil/pulls.cr, src/ocx/server/pages.cr, src/ocx/watcher/state.cr, src/ocx/watcher/reports.cr, src/ocx/watcher/giving.cr, src/ocx/watcher/process.cr, src/ocx/watcher.cr, src/ocx/node.cr, src/ocx/node/view.cr, src/ocx/node/sharing.cr, src/ocx/decisions.cr, src/ocx/care.cr, src/ocx/server.cr, src/ocx/fossil.cr, src/ocx/fossil/said.cr, src/ocx/fossil/scratch.cr, src/ocx/commands/poll.cr, src/ocx/commands/logins.cr, src/ocx/commands/register.cr, src/ocx/commands.cr and src/ocx/hook.cr; spec/guards/size_spec.cr, spec/guards/measure_spec.cr, spec/guards/causation_spec.cr, spec/guards/external_programs_spec.cr, spec/guards/survey_spec.cr and spec/guards/interfaces_spec.cr hold them. crystal run ci.cr green: 566 examples, 0 failures.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QVpmCsBwVF3d4zhMHHDAxs check-in: ef83839803 user: opus-ocx2 tags: agent-tools

Changes
Unified Diff Side-by-Side Diff Patch
Changes to SCENARIOS.md.
Changes to docs/backlog.md.
Changes to docs/design/facts.json.
Changes to docs/design/modules.json.
Changes to docs/design/modules.md.
Changes to docs/interfaces.md.
Changes to docs/survey/functionality.json.
Changes to spec/guards/external_programs_spec.cr.
Changes to spec/guards/outlived_spec.cr.
Changes to spec/ocx/asked_spec.cr.
Changes to spec/ocx/attach_spec.cr.
Changes to spec/ocx/care_spec.cr.
Changes to spec/ocx/command_spec.cr.
Changes to spec/ocx/completion_spec.cr.
Changes to spec/ocx/console_spec.cr.
Changes to spec/ocx/create_spec.cr.
Changes to spec/ocx/daemon_pages_spec.cr.
Added spec/ocx/daemon_reads_spec.cr.
Added spec/ocx/daemon_refusals_spec.cr.
Changes to spec/ocx/daemon_spec.cr.
Changes to spec/ocx/decisions_spec.cr.
Changes to spec/ocx/dry_run_spec.cr.
Changes to spec/ocx/elements_spec.cr.
Changes to spec/ocx/ending_spec.cr.
Changes to spec/ocx/ends_spec.cr.
Changes to spec/ocx/export_spec.cr.
Changes to spec/ocx/giving_spec.cr.
Changes to spec/ocx/harness_spec.cr.
Changes to spec/ocx/hook_spec.cr.
Changes to spec/ocx/import_spec.cr.
Changes to spec/ocx/imports_detached_spec.cr.
Changes to spec/ocx/logins_spec.cr.
Changes to spec/ocx/mcp_spec.cr.
Changes to spec/ocx/message_tags_spec.cr.
Changes to spec/ocx/node_spec.cr.
Changes to spec/ocx/program_spec.cr.
Changes to spec/ocx/release_bounds_spec.cr.
Deleted spec/ocx/remote_node_spec.cr.
Changes to spec/ocx/run_pages_spec.cr.
Changes to spec/ocx/run_spec.cr.
Changes to spec/ocx/run_states_spec.cr.
Changes to spec/ocx/steps_spec.cr.
Changes to spec/ocx/terminal_spec.cr.
Changes to spec/ocx/turned_away_spec.cr.
Added spec/ocx/watch_spec.cr.
Changes to spec/ocx/watcher_spec.cr.
Changes to spec/ocx/writers_spec.cr.
Changes to spec/scenarios/audit_spec.cr.
Changes to spec/scenarios/build_spec.cr.
Changes to spec/scenarios/ci_spec.cr.
Changes to spec/scenarios/question_spec.cr.
Changes to spec/scenarios/talk_spec.cr.
Changes to spec/support/at_host.cr.
Changes to spec/support/daemon_node.cr.
Changes to spec/support/fixture.cr.
Added spec/support/local_server.cr.
Changes to spec/support/stand_in_fossil.cr.
Changes to src/ocx/care.cr.
Changes to src/ocx/command.cr.
Changes to src/ocx/commands.cr.
Changes to src/ocx/commands/attach.cr.
Changes to src/ocx/commands/audit.cr.
Changes to src/ocx/commands/console.cr.
Changes to src/ocx/commands/create.cr.
Changes to src/ocx/commands/daemon.cr.
Changes to src/ocx/commands/hook.cr.
Changes to src/ocx/commands/import.cr.
Changes to src/ocx/commands/import_operations.cr.
Deleted src/ocx/commands/poll.cr.
Changes to src/ocx/commands/run.cr.
Changes to src/ocx/commands/status.cr.
Changes to src/ocx/commands/stop.cr.
Changes to src/ocx/commands/tag_messages.cr.
Added src/ocx/commands/watch.cr.
Changes to src/ocx/completion.cr.
Changes to src/ocx/console_page.cr.
Changes to src/ocx/console_text.cr.
Changes to src/ocx/daemon.cr.
Changes to src/ocx/decisions.cr.
Changes to src/ocx/entry.cr.
Changes to src/ocx/fossil.cr.
Changes to src/ocx/fossil/forum.cr.
Changes to src/ocx/fossil/message_tags.cr.
Changes to src/ocx/fossil/pulls.cr.
Changes to src/ocx/fossil/repository.cr.
Changes to src/ocx/fossil/said.cr.
Changes to src/ocx/hook.cr.
Changes to src/ocx/imports.cr.
Changes to src/ocx/imports_detached.cr.
Changes to src/ocx/launch.cr.
Changes to src/ocx/log.cr.
Changes to src/ocx/mirror.cr.
Changes to src/ocx/node.cr.
Changes to src/ocx/node/sharing.cr.
Changes to src/ocx/node/view.cr.
Changes to src/ocx/served.cr.
Changes to src/ocx/server.cr.
Changes to src/ocx/server/pages.cr.
Changes to src/ocx/session.cr.
Changes to src/ocx/watcher.cr.
Changes to src/ocx/watcher/giving.cr.
Changes to src/ocx/watcher/process.cr.
Changes to src/ocx/watcher/reports.cr.
Changes to src/ocx/workspaces.cr.
Changes to src/ocx/writes.cr.