Commit Graph
65 Commits
Author SHA1 Message Date
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 a75a5453e9 bxctl: escape error details, time out on admin.sock, AdminError::Io
M3a review findings 9, 10, 12, 13. A retrying error and every error detail
can carry the inference server's body, so they are escaped like model text.
Admin requests wait at most 30 s, so a stuck brokerd cannot hang bxctl or a
chat turn. A failed write is AdminError::Io and stops handle_pending instead
of being answered with another write. The usage line says what audit verify
checks.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-22 21:09:53 -07:00
kyleandClaude Opus 5.5 70d582acf5 BrokerPort: cap the wait after a pending frame at a day
M3a review finding 8. The wait was expires plus the timeout with no bound,
and the "expiry too far away" guard could not fire, so a far expiry (which
brokerd produces when now + ttl_ms does not fit) parked a turn for ever.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-22 21:08:48 -07:00
kyleandClaude Opus 5.5 33994d0dc6 loopd, bxctl, inferproxy: read args_os instead of panicking
M3a review finding 7, for the other three roles. loopd keeps its config path
as a path; bxctl and inferproxy take text arguments and answer one that is
not UTF-8 with their usage.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-22 21:07:59 -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.5 eed0a221ca Audit writer: open a record-less log, share the log-name rule, keep the lock file
M3a review findings 1, 2, 4 and part of 5. One empty log file made brokerd
panic at startup (files[len - 2]); it now opens as an empty log. brokerd's
name check tested one month digit, so a file bxctl ignored could become
brokerd's latest file; both now use proto::is_audit_log_name. Writer no
longer unlinks audit/.lock, which opened a two-writer window. No unwrap in
short_check.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-22 21:05:13 -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 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 57dc7899a9 brokerd: close the connection after the final frame again
hold_open (d21baa2) kept each connection open for up to two seconds
after its final frame, reading and dropping anything the peer sent, to
hide a test client that set a read timeout after the handler had closed.
On macOS that call fails with EINVAL; the clients now allow for it
(00a85c1, d7009dc), so the handler goes back to closing at once.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-22 18:32:31 -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
kyleandClaude Opus 5.5 00a85c124d loopd: read on a socket whose peer closed, instead of failing on macOS
macOS refuses every socket option with EINVAL once the peer has closed
(XNU sosetoptlock, bsd/kern/uipc_socket.c), even with unread data still
buffered. loopd set a read timeout before each read, so on macOS every
frame or response that arrived just before the peer closed was lost:
BrokerPort reported the broker unavailable with "os error 22", and the
llama client failed the same way. Twelve loopd test binaries failed on
macOS; Linux never refuses, so the gate on Talos did not see it.

Both places now go through socket::set_read_timeout, which on Apple
targets takes that one refusal as success: a socket shut in both
directions returns its data or the end at once and cannot block. A
zero timeout is still an error.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-22 18:27:31 -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 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 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
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 c060c80c7e Fix four review findings: busy release, poison recovery, core.md errors, chat loop
Implemented-By: OpenCode session (model recorded in docs/implementer-log.md)
2026-09-18 21:06:58 -07:00
kyle 34951084cc Extend on-device verification to the agent loop
Implemented-By: OpenCode session (model recorded in docs/implementer-log.md)
2026-09-18 20:38:56 -07:00
kyle 06cda69509 Add bxctl chat
Implemented-By: OpenCode session (model recorded in docs/implementer-log.md)
2026-09-18 20:24:26 -07:00
kyle eb8fc5f920 Add the loopd serve command
Implemented-By: OpenCode session (model recorded in docs/implementer-log.md)
2026-09-18 19:50:32 -07:00
kyle 8bc835f623 Add the channel server on loop.sock
Implemented-By: OpenCode session (model recorded in docs/implementer-log.md)
2026-09-18 19:43:12 -07:00
kyle 9063cf958e Add the turn loop with its limits
Implemented-By: OpenCode session (model recorded in docs/implementer-log.md)
2026-09-18 19:14:52 -07:00
kyle 9704a64507 Add the session store: baseline file and append-only log
Implemented-By: OpenCode session (model recorded in docs/implementer-log.md)
2026-09-18 18:42:00 -07:00
kyle b152ba3cd3 Add the baseline and the log replay function
Implemented-By: OpenCode session (model recorded in docs/implementer-log.md)
2026-09-18 18:31:33 -07:00
kyle fd7ade9689 Add the tool port, registry, dispatch and the fake tools
Implemented-By: OpenCode session (model recorded in docs/implementer-log.md)
2026-09-18 18:12:45 -07:00
kyle ec5d887daa Add the paths, channel, loop and baseline config tables
Implemented-By: OpenCode session (model recorded in docs/implementer-log.md)
2026-09-18 17:36:20 -07:00
kyle 06298d6a8e Add the channel messages and the usage record to proto
Implemented-By: OpenCode session (model recorded in docs/implementer-log.md)
2026-09-18 17:30:51 -07:00
kyle 0f5213a466 Return chunked body data as soon as it is available
Implemented-By: OpenCode session (model recorded in docs/implementer-log.md)
2026-09-18 16:15:22 -07:00
kyle 1faa38be44 Close the client side when the upstream closes, in inferproxy
Implemented-By: OpenCode session (model recorded in docs/implementer-log.md)
2026-09-18 16:07:45 -07:00
kyle ad7bce88a4 Add on-device verification for the inference path
Implemented-By: OpenCode session (model recorded in docs/implementer-log.md)
2026-09-18 15:32:20 -07:00
kyle f1d880568f Add the startup self-test and the loopd selftest command
Implemented-By: OpenCode session (model recorded in docs/implementer-log.md)
2026-09-18 15:28:37 -07:00
kyle 59cf89e7ba Add the per-slot gate and chat_with_retry
Implemented SlotGate (one request in flight per server slot, FIFO queue,
bounded) and chat_with_retry (retry only server-gone errors, jittered
backoff within a window and attempt budget). chat acquires the gate and
maps GateFull to Busy; Client gained a gate field.

Implemented-By: OpenCode session (model recorded in docs/implementer-log.md)
2026-09-18 14:45:45 -07:00
kyle a07c341cbb Add the thinking cap to Client::chat
Implemented-By: OpenCode session (model recorded in docs/implementer-log.md)
2026-09-18 14:06:11 -07:00
kyle 60557a0634 Add Client::chat with the first-byte wait, liveness and error mapping
Implemented-By: OpenCode session (model recorded in docs/implementer-log.md)
2026-09-18 13:37:01 -07:00
kyle 3663a1e4d5 Add props, slots, tokenize and the cache-loss check to the llama client
Implemented-By: OpenCode session (model recorded in docs/implementer-log.md)
2026-09-18 03:39:05 -07:00