Decide where reference implementations are still written

From M3a: a full reference for the audit chain and the approval
handoff, the property test's oracle for policy, and compiling
skeletons for everything else. Each plan records what its checks
exposed, and that record decides what the next milestone gets.
Tip T17; the spec's handover section says which check each module has.

Also restores three / examples that an editing tool had decoded
to a plain slash.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
2026-09-18 22:28:53 -07:00
co-authored by Claude Fable 5.1
parent 0ee375dd03
commit 1008dce351
3 changed files with 22 additions and 8 deletions
+19 -7
View File
@@ -582,7 +582,7 @@ An unknown or already answered `approval` is `error` `no_such_approval`.
`PendingApproval.arguments` is not the string `loopd` sent. It is the parsed arguments serialised
again by `serde_json` from the typed value in `args`, fields in the order of section 3's table.
The owner approves what policy matched: in the raw string `"/etc"` and `"/etc"` look
The owner approves what policy matched: in the raw string `"\u002fetc"` and `"/etc"` look
different and mean the same, and the re-serialised form shows both as `/etc`. The audit log keeps
the raw string.
@@ -746,8 +746,8 @@ Every message for such a state ends with `see docs/runbook.md#<anchor>`. A gate
## 12. Testing
Tests and fixtures are given to the implementer and checked against a reference implementation
first, as in M2.
Tests and fixtures are given to the implementer. How each was checked first (a reference
implementation, the oracle, or a compiling skeleton) is in section 15.
- **Policy tables.** Every row of every table in section 3 is a case, plus: mode precedence among
three matching grants; the reason order when one candidate is expired and another has too much
@@ -814,7 +814,7 @@ first, as in M2.
arrives after `expires` but within `timeout_ms` of it (delivered). The turn loop with
`approval_pending` and `tool_denied`.
- **`bxctl`.** `approvals` output with an argument full of escape sequences and one with U+202E,
U+200B and U+2066; `/etc` in the request shown as `/etc`; `approve`, `refuse`,
U+200B and U+2066; `\u002fetc` in the request shown as `/etc`; `approve`, `refuse`,
`grants check` and `audit verify` against fakes and fixture directories. `chat` against a fake
`loopd` and a fake `brokerd`: when the event says `read_file` and `brokerd`'s entry says `shell`,
the block says `shell`;
@@ -873,6 +873,18 @@ accepts only allowlisted host names refuses other hosts and IP literals.
## 15. How the work is handed over
As in M2: small closed tasks with given tests, driven by `tools/run-plan.sh`, reviewed once after
the last M3a task. The reference implementation lives in a git worktree at `~/src/boxmaker-ref`
on an unpushed branch, not in `/tmp`. No task mixes policy with plumbing. Every task that adds a
fail-closed path lists its exits and its runbook anchor (tips T14 and T16).
the last M3a task. No task mixes policy with plumbing. Every task that adds a fail-closed path
lists its exits and its runbook anchor (tips T14 and T16).
What changes from M2 is how the given tests are checked before they are handed over (decision of
2026-09-18, tip T17):
| Check | Used for | What it proves |
|---|---|---|
| Reference implementation | `proto::audit` (the verifier), `brokerd::audit` (the writer and startup), `brokerd::approvals` | The tests pass, and the spec can be implemented as written. It also generates the tampering fixtures, whose hashes must be real. |
| Oracle | `brokerd::policy`, `args`, `grants` | The property test carries its own naive second implementation. |
| Skeleton | Everything else | The given tests compile against the task's signatures with `todo!()` bodies. |
The reference and the skeletons live in a git worktree at `~/src/boxmaker-ref` on an unpushed
branch, not in `/tmp`. The plan's README records, for each task, which check it had and what that
check exposed.