Commit Graph
183 Commits
Author SHA1 Message Date
kyleandClaude Opus 5.5 b426ca1958 Specify and plan M3b: the runner and the tools
A draft spec for the owner's review and 13 offline tasks with their given
tests: shared tool arguments and host rules in proto, the sealed fetch
target (M3a finding 14), the toolkit tools and SOCKS5 egress proxy, and
brokerd's [runner], podman argument lists, runtime and proxy lifecycle. Each
task's tests were run against a reference at that task's end state (560 to
638 tests, clippy clean); the reference is not in the repository. Adds the
runner-unavailable runbook entry and tip T23 (ETXTBSY in script tests).

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-22 22:29:27 -07:00
kyleandClaude Opus 5.5 d988edac4a Implementer log: record which model did each M3a task; repair the rows
Models from the owner: Ornith for tasks 01 to 18, Ornith then Grok 4.6 for
19, Grok 4.6 for 20 to 22. Future and late dates set to the commit dates;
notes pasted into the wrong rows moved back; every row has eight cells.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-22 22:01:14 -07:00
kyleandClaude Opus 5.5 aafd9f930e Merge m3a: brokerd's decision path (M3a)
Tasks 01 to 22, the review, and task 23 (the review fixes, with a second,
independent review of them). The one conflict, docs/implementer-lessons.md,
had the same T18 and T19 on both sides; m3a's T20 to T22 follow them.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-22 21:55:11 -07:00
kyleandClaude Opus 5.5 f0b39a4766 Record the second review of task 23 and the findings first left out
The review table gains findings 16 to 20, which the two review agents
reported and the first write-up dropped. The independent review of the fix
commits, and what was changed for it, is recorded; task 23's claims about
its tests are corrected. The spec and decisions record the day-long cap, the
ttl_ms bound, the socket-directory rule and the listener's retry.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-22 21:54:28 -07:00
kyleandClaude Opus 5.5 e08deb39a6 brokerd: recover a torn line in place, real dates only, bounded ttl, EMFILE
From the independent review of task 23. A torn last line followed by an empty
later file had its recovery written into the later file, which broke the
chain for good; the line is now ended in its own file. The log-name rule
takes months 01 to 12 and days 01 to 31 only. [approvals] ttl_ms is limited
to a day, the longest loopd waits after a pending frame. Running out of file
descriptors or memory pauses the listener instead of stopping brokerd (the
errors the previous fix skipped do not occur on Linux). args.rs's doc fixed.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-22 21:48:24 -07:00
kyleandClaude Opus 5.5 ba369f82ba brokerd: refuse / and a symbolic link as a socket's directory
brokerd makes a socket's directory 0700. With a socket directly in / it would
chmod /, and through a symbolic link it would change the link's target. Both
are now refused at start with #brokerd-start-failed. Without the fix the link
case started and served, with the shared directory made private.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-22 21:44:29 -07:00
kyleandClaude Opus 5.5 b1afcd5734 Record task 23: the M3a review fixes, done by the design model
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-22 21:12:22 -07:00
kyleandClaude Opus 5.5 f6841f1155 Record straylight's new slot layout: four slots over one 262144-token pool
loopd's self-test caught the change (context per slot 131072 -> 262144,
slots 2 -> 4). The device tests keep the expectation in one constant, and
the M3a script matches it; verify-device passes 6 of 6 and the M3a device
check passes. The inference contract notes which M0 findings rest on the old
layout and need re-measuring.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-22 21:11:23 -07:00
kyleandClaude Opus 5.5 6af89f7c60 brokerd: runbook pointers for startup failures, no thread panics, args_os
M3a review findings 3, 5 (the cast), 6, 7 (brokerd), 11. A config, directory
or socket failure at start now ends with docs/runbook.md#brokerd-start-failed,
and losing a listener with #brokerd-listener-lost; both entries are new.
Threads start through thread::Builder, so a refused thread is reported
instead of silently killing a listener; an aborted connection no longer stops
the daemon. brokerd reads args_os and keeps the config path as a path. The
"requester went away" result is recorded at the time it happens.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-22 21:07:59 -07:00
kyleandClaude Opus 5 22a26aad45 Review M3a: accept with fifteen findings; record the server change
Two medium findings in the audit writer (a startup panic on a record-less
log file, and a log-name filter that disagrees with bxctl's), one in the
missing runbook pointers for startup failures, and twelve low ones. Lessons
I14 and T21, T22; two new AGENTS rules; m3a's T18 renumbered to T20 so
master's T18 and T19 survive the merge.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-22 20:48:43 -07:00
kyle ffbff501d6 Record Grok 4.6 as the model for M3a tasks 20-22
Implemented-By: Grok 4.6
2026-09-22 20:25:50 -07:00
kyle 2249f7fd91 Add the end-to-end test: loopd against the real brokerd binary
Implemented-By: Grok 4.6
2026-09-22 20:25:40 -07:00
kyle 1828048564 Check that every runbook pointer has an entry
Implemented-By: Grok 4.6
2026-09-22 20:25:40 -07:00
kyle f1f17a171f Show and answer approvals in bxctl chat
Implemented-By: Grok 4.6
2026-09-22 20:25:40 -07:00
kyleandClaude Opus 5.5 0a9df81fe4 Record the resolution of the M3a "fsync stall": a macOS socket rule
The handoff and the two stopped rows blamed an environment fsync stall.
The cause was macOS refusing socket options after the peer closes, in
loopd and in the brokerd test client. The handoff now opens with the
resolution, the log gets a review note (the stopped rows are kept as
written), and the lessons gain I13 (measure what you blame, and name
the machine) and T18 (the gate must pass on Talos and on the Mac).

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-22 18:35:30 -07:00
kyleandClaude Opus 5.5 d7009dc488 brokerd tests: read the final frame after the handler closes, on macOS
The test client set its read timeout before every frame. On macOS that
fails with EINVAL once the handler has sent its final frame and closed,
so every admin test that reads a second frame failed there (40 runs of
40 at 2408e2c). The frame is already buffered, so the client now takes
that one refusal as the peer having closed and reads it. The plan's copy
changes with it.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-22 18:28:18 -07:00
kyle d21baa2954 Debug collection: hold_open fix, grants.rs refactor, and DEBUG-HANDOFF findings
Debug collection commit for the brokerd admin-test hang investigation (M3a
task 19). Contains:

- crates/brokerd/src/broker.rs: hold_open helper (HOLD_OPEN = 2s read-timeout
  loop) applied after forbid and after the final send in broker::handle
- crates/brokerd/src/admin.rs: hold_open applied after forbid and after the
  final send in admin::handle
- crates/brokerd/src/grants.rs: check_tool_constraints refactor (match guard
  instead of nested if)
- docs/M3a/DEBUG-HANDOFF.md: investigation results added (310 runs, zero
  hangs reproduced; stalled fsync cannot be fixed without dropping durability)

The implementer log row was committed separately (a6d81d9).

Implemented-By: OpenCode session (model recorded in docs/implementer-log.md)
2026-09-22 15:39:20 -07:00
kyle a6d81d941b DEBUG-HANDOFF.md: confirm brokerd admin fsync stall is environment-level
Investigated the brokerd admin test hang described in docs/M3a/DEBUG-HANDOFF.md.
The hold_open fix is already implemented and eliminates the EINVAL. 310 runs
of the admin test binary (4-thread, 16-thread, disk-stressed, via cargo test)
produced zero hangs. The ~7-12% fsync stall cannot be reproduced in this
environment. Per AGENTS.md point 4 for stopped tasks, logging the blocker and
committing only the implementer log.

Implemented-By: OpenCode session (model recorded in docs/implementer-log.md)
2026-09-22 13:41:13 -07:00
kyle 2408e2c622 Add bxctl audit verify
Implemented-By: OpenCode session (model recorded in docs/implementer-log.md)
2026-09-21 01:35:08 -07:00
kyle 56e5363109 Stop: bxctl audit verify not wired in main.rs (task M3a/19)
Implemented-By: OpenCode session (model recorded in docs/implementer-log.md)
2026-09-21 00:20:15 -07:00
kyle 2d94067b52 Add bxctl approvals, approve, refuse and grants check
Implemented-By: OpenCode session (model recorded in docs/implementer-log.md)
2026-09-20 23:25:05 -07:00
kyle 469be2c0a1 Add BrokerPort: loopd asks brokerd for every tool call
Implemented-By: OpenCode session (model recorded in docs/implementer-log.md)
2026-09-20 19:40:35 -07:00
kyle 1ceaa36b9b Give loopd's tool port approvals, its own clock and plain denials
Implemented-By: OpenCode session (model recorded in docs/implementer-log.md)
2026-09-20 17:43:05 -07:00
kyle 3ecaef3c8b Add brokerd serve: startup, both sockets, and the expiry thread
Implemented-By: OpenCode session (model recorded in docs/implementer-log.md)
2026-09-20 17:24:57 -07:00
kyle d250678355 Handle approvals, refusals and grant checks on admin.sock
Implemented-By: OpenCode session (model recorded in docs/implementer-log.md)
2026-09-20 13:54:01 -07:00
kyle e68e626cd7 Handle a tool request from decision to answer
Implemented-By: OpenCode session (model recorded in docs/implementer-log.md)
2026-09-20 12:59:42 -07:00
kyle cff22ce579 Add the ledger: the audit writer and session state behind one lock
Implemented-By: OpenCode session (model recorded in docs/implementer-log.md)
2026-09-20 03:30:37 -07:00
kyle caf8fd6eca Add the table of pending approvals
Implemented-By: OpenCode session (model recorded in docs/implementer-log.md)
2026-09-19 16:48:09 -07:00
kyle 57734ebb9a Replace the runner stub with the Runtime seam and RunSpec
Implemented-By: OpenCode session (model recorded in docs/implementer-log.md)
2026-09-19 16:43:56 -07:00
kyle ded7eb8c50 Add the audit writer with its startup check
Implemented-By: OpenCode session (model recorded in docs/implementer-log.md)
2026-09-19 16:32:37 -07:00
kyleandClaude Opus 5 ec4037abee Lessons from the first M3a run: references out of reach; per-task copies
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-19 12:08:37 -07:00
kyleandClaude Opus 5 e7f0d84d02 Note how the first M3a run went: task 03 copied from the reference
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-19 12:08:25 -07:00
kyleandClaude Opus 5 ed8cf49540 M3a task 01: copy a strict.rs of its own
The strict.rs in files/ is the merged one and walks task 02's new wire
fixtures, so task 01's gate could not pass; the first run stopped on it.
Task 01 now copies area A's version, checked to give 3 and 5 passed at
task 01's end state.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-19 12:07:59 -07:00
kyle 726ce1f766 Keep each session's taint and untrusted flag in a file
Implemented-By: OpenCode session (model recorded in docs/implementer-log.md)
2026-09-19 03:08:46 -07:00
kyle e1e6c7a338 Decide tool calls against grants, taint and time
Implemented decide and redecide in crates/brokerd/src/policy.rs:
SessionState, Label, Denial, private Matched, and Decision/Ask (private
fields, Debug only, nine getters each) with the Outcome enum. decide
rejects an unknown tool (args not parsed) and malformed arguments before
matching, then runs the M1-M5 matching pass in id order and returns
Allowed/Ask/Denied by the winner's mode; redecide re-runs matching now
and rebuilds the Decision from the Ask. Seven doctests (six compile_fail,
one compiling) guard the two facts. policy 7, policy_matching 10,
policy_redecide 7, policy_property 4, doc 7 all pass; make gate ok.

Implemented-By: OpenCode session (model recorded in docs/implementer-log.md)
2026-09-19 03:05:01 -07:00
kyle e2ab29aa15 Load grant files, failing closed on any invalid file
crates/brokerd/src/grants.rs reads grants/*.toml into a GrantSet: load reports every problem in every file and returns either a complete valid set or the full problem list, never a partial one; from_grants sorts by id and collects every rule-2..9 problem; render prints each problem then the runbook pointer. All 17 grants tests pass; make gate prints gate: ok.

Implemented-By: OpenCode session (model recorded in docs/implementer-log.md)
2026-09-19 02:50:26 -07:00
kyle 9150effc8e Add typed tool arguments and the form checks for paths, hosts and URLs
Implemented brokerd::args: a pure module (no I/O, no clock) that parses tool
arguments into a typed ToolArgs and checks the form of paths, hosts and URLs.
Four private deny_unknown_fields structs drive parse and canonical_json; path,
cwd and url are validated as written and never normalised. All 13 args tests
pass and make gate prints gate: ok.

Implemented-By: OpenCode session (model recorded in docs/implementer-log.md)
2026-09-19 02:37:31 -07:00
kyle 5502de1c90 Add brokerd's configuration
Implemented crates/brokerd/src/config.rs: typed Paths, Sockets, Approvals and
Config with serde(deny_unknown_fields, default) on every struct, hand-written
ConfigError (Read/Parse) with Display and std::error::Error, and the parse/load/
broker_socket/admin_socket/audit_dir/state_dir methods. Added serde, serde_json
and toml to crates/brokerd/Cargo.toml, registered pub mod config; in lib.rs,
added brokerd to the serde and serde_json Used-by cells in docs/dependencies.md,
and copied the given test and six fixtures byte-identical. 7 config tests pass;
make gate prints gate: ok.

Implemented-By: OpenCode session (model recorded in docs/implementer-log.md)
2026-09-19 02:24:15 -07:00
kyle d01b2ef2d9 Add the audit chain verifier
Implemented proto::ChainVerifier as a pure line-holding state machine:
each line is judged only once the next has arrived, so a Recovery record
can mark the line before it not-a-record. Adds ChainFailure, TornTail,
ChainReport, Location and ChainVerifier, wired through lib.rs and the
matching re-export in audit.rs. 13 chain tests pass; make gate prints
gate: ok.

Implemented-By: OpenCode session (model recorded in docs/implementer-log.md)
2026-09-19 02:19:45 -07:00
kyle e8568edf7e Add the admin messages, approval ids as numbers, and two turn events
Implemented-By: OpenCode session (model recorded in docs/implementer-log.md)
2026-09-19 00:28:46 -07:00
kyle c6395b16f4 Replace the audit record with chained audit events
Implemented-By: OpenCode session (model recorded in docs/implementer-log.md)
2026-09-19 00:22:25 -07:00
kyle cb5ecad4da M3a/01-proto-audit-types: stopped
Gate cannot pass: the task's strict.rs walks 28 wire fixtures but 16
(approvals/approve/refuse/ok/grants_report/turn_event_* and friends) do not
exist on the m3a branch and are created by task 02. The audit types were
implemented exactly as specified and records passes; only the unrelated
wire-envelope test blocks the gate. Committed only this log row.

Implemented-By: OpenCode session (model recorded in docs/implementer-log.md)
2026-09-19 00:10:43 -07:00
kyleandClaude Opus 5 0703306e19 Record that the M3a plan is ready, and how it was checked
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-18 23:45:43 -07:00
kyleandClaude Opus 5 e3f37da232 Hand over the M3a plan: 22 tasks, their files, and the check record
Task files, the files they copy in (byte-identical to the reference on
m3a-ref), each area's check record, and a README with the per-task
table of what each check exposed. The handoff note is done with.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-18 23:45:43 -07:00
kyleandClaude Opus 5 69f0a0a218 M3a spec: fold in area E's findings; runbook and egress to match
Every request is recorded, unreadable state is recorded as secret, a
refusal that cannot be recorded is an error, and the other cases the
brokerd reference settled. The audit-unavailable and
broker-state-damaged entries name the new messages; egress lists the
development calls to straylight.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-18 23:40:02 -07:00
kyleandClaude Opus 5 43f5b8abc6 M3a spec: fold in the defects the plan's checks found in areas A to D
DecisionRecord's empty struct variants, the verifier's report fields and
region rule, the startup fallback, the IPv4 host rule, Denial, BrokerPort
deadlines and envelope id, the runbook anchor rule, bxctl's --say/--json
and escaping. Recorded in docs/decisions.md; the array-form question is
left open.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-18 23:09:32 -07:00
kyleandClaude Fable 5.1 b39dac3f71 Hand off the half-built M3a plan
Areas A to D (audit, policy side, loopd, bxctl) are written on branches
in ~/src/boxmaker-ref-a to -d; area E (broker and approval handoff) is
not started. HANDOFF.md records each area's result, the contract
conflicts between them, the spec defects they found and the remaining
steps in order.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-18 23:00:21 -07:00
kyleandClaude Fable 5.1 66fa143524 M3a spec: a ledger module and a two-process end-to-end test
Both came out of planning the tasks. The three locked steps need a home
that is neither the connection handler nor the pending table. The
one-process end-to-end test would have made loopd dev-depend on
brokerd, which the crate-dependency gate forbids.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-18 22:36:55 -07:00
kyleandClaude Fable 5.1 1008dce351 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>
2026-09-18 22:28:53 -07:00
kyleandClaude Fable 5.1 0ee375dd03 Record the open M4 decision on approvals too long for one post
Settled: what is being approved is never truncated. Leading option for
Mattermost is a thread of numbered chunks approved on the last post.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-18 22:23:54 -07:00