Build a custom machine
Testing
On your computer. ownbox run <folder> runs the machine once against a local Ownbox with sample data.
It waits for each job, asks its Morning Review part and each tool that takes no argument, and says yes to its first
five proposals. Then it prints what the machine declared, what happened, what it would have done, what the Ownbox
refused, and what it logged. Nothing leaves your computer. The local Ownbox makes the Ownbox's own checks, with the
same refusals by the same codes. It reads the machine's own fixtures/box.json (at most 256 KB) instead of its sample
when the folder has one. It exits non-zero when a job or an answer failed.
Its pages, on your computer. ownbox preview <folder> opens the machine's page in your browser, drawn by the
Ownbox's own renderer on the local Ownbox's sample data: its figures and lists, its settings form, and Run now. Each
page and each change is checked as the Ownbox checks it, and refused in the Ownbox's words. Change the code and reload
the page: the preview starts the machine again with the new code, its settings kept. It listens on 127.0.0.1 only and
reaches nothing outside your computer; Ctrl-C stops it.
Its own test. Every machine carries test_<slug>.py, which checks its own files and never imports the Ownbox's
code.
The Ownbox's check. Each build is checked before it runs: machine: 2, the permissions, the packages, the slug,
the imports, that every file compiles, and that it uses only calls a custom machine can make. Every finding names its
fix.
The dry runs. Before the owner is asked to approve anything, the draft runs twice, never both at once. Each run lasts at most 90 seconds and asks at most five of its tools and five of its pages.
- The data run reads the owner's real data and reaches nothing: a fetch is refused
dry_run, every send, spend and proposal is answered{"dry": true}, and what it saves is thrown away. - The fetch run reaches only the hosts the owner tapped for the test, GET only, ten fetches in all unless the tap
allows more (at most 50), and reads a made-up sample business instead of theirs. A host not tapped is refused
not_tapped. A machine with nofetch:hosts skips the fetch run.
Either way the AI answers at most ten times a run. A run is clean when nothing failed and no call was refused but by
the test's own holds (dry_run, dry_run_limit); only a build whose runs are clean, or skipped, can be approved. What
it would have done is the log you read before the next try.