Add M2b plan: ten tasks, tests, recordings and the first system prompt
The tasks build the agent loop on M2a's client: channel messages and the usage record in proto, four config tables, the tool port and registry with find_tool and call_tool, the baseline and replay, the session store, the turn loop with its limits and the append-only property test, the channel server, loopd serve, bxctl chat, and the device checks including a four-turn conversation with a restart. Checked against a private reference implementation: the gate passes after every task in order, the new suites pass under CPU load, and the reference passes make verify-device on straylight with no cache loss. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,81 @@
|
||||
# M2b task 02: the M2b config tables
|
||||
|
||||
**Branch:** `m2b` (run `git switch m2b`; `git status --short` must be empty, otherwise stop)
|
||||
**Commit subject:** `Add the paths, channel, loop and baseline config tables`
|
||||
|
||||
## Goal
|
||||
|
||||
Four small config tables that the rest of M2b reads. All are optional, with defaults, and reject
|
||||
unknown keys like the existing ones.
|
||||
|
||||
```toml
|
||||
[paths]
|
||||
home = "/var/lib/boxmaker" # default: $BOXMAKER_HOME if set, else this
|
||||
|
||||
[channel]
|
||||
socket = "" # default empty, meaning <home>/run/loop/loop.sock
|
||||
|
||||
[loop]
|
||||
tool_iterations = 8 # completions with tool calls allowed in one turn
|
||||
repeat_detection = true # stop the same call made twice in a turn
|
||||
tool_result_cap = 16384 # bytes of a tool result that are kept
|
||||
|
||||
[baseline]
|
||||
system = "system.md" # the system prompt; relative to the config file's directory
|
||||
```
|
||||
|
||||
## Files
|
||||
|
||||
- Copy (replacing the old one): `crates/loopd/tests/config.rs`;
|
||||
new: `crates/loopd/tests/fixtures/config/m2b.toml`
|
||||
- Modify: `crates/loopd/src/config.rs`, `docs/implementer-log.md`
|
||||
|
||||
## Interfaces
|
||||
|
||||
Added to `Config` (all `pub`, all `#[serde(default)]`): `paths: Paths`, `channel: Channel`,
|
||||
`r#loop: Loop`, `baseline: Baseline`. The field is spelled `r#loop` because `loop` is a keyword;
|
||||
in TOML it is `[loop]`.
|
||||
|
||||
```rust
|
||||
pub struct Paths { pub home: PathBuf } // Default: $BOXMAKER_HOME or /var/lib/boxmaker
|
||||
pub struct Channel { pub socket: PathBuf } // Default: empty
|
||||
pub struct Loop { pub tool_iterations: u32, pub repeat_detection: bool, pub tool_result_cap: usize }
|
||||
pub struct Baseline { pub system: PathBuf } // Default: "system.md"
|
||||
|
||||
impl Config {
|
||||
/// The channel socket, with the default filled in.
|
||||
pub fn channel_socket(&self) -> PathBuf;
|
||||
}
|
||||
```
|
||||
|
||||
Derives: `Debug, Clone, PartialEq, Eq, Deserialize` and `#[serde(deny_unknown_fields, default)]`
|
||||
on all four, each with a hand-written `Default` (or derived, for `Channel`).
|
||||
|
||||
Rule: `Config::load` makes a relative `baseline.system` absolute by joining it to the config
|
||||
file's directory. `Config::parse` leaves it as it is, because it has no file to be relative to.
|
||||
|
||||
## Steps
|
||||
|
||||
- [ ] **1. Copy.**
|
||||
|
||||
```sh
|
||||
git switch m2b
|
||||
cp docs/plans/M2b/files/crates/loopd/tests/config.rs crates/loopd/tests/
|
||||
cp docs/plans/M2b/files/crates/loopd/tests/fixtures/config/m2b.toml crates/loopd/tests/fixtures/config/
|
||||
```
|
||||
|
||||
- [ ] **2. See the tests fail.** `cargo test -p loopd --test config`. Expected: it does not compile.
|
||||
- [ ] **3. Make the changes.** Run `cargo fmt --all`.
|
||||
- [ ] **4. See the tests pass.** `cargo test -p loopd --test config`. Expected: `9 passed`.
|
||||
- [ ] **5. Run the gate.** `make gate`. Expected last line: `gate: ok`.
|
||||
- [ ] **6. Log and commit.** `git add crates/loopd docs/implementer-log.md && git commit`
|
||||
|
||||
## Done when
|
||||
|
||||
- `cargo test -p loopd --test config` reports 9 passed; `make gate` prints `gate: ok`.
|
||||
- `grep -c deny_unknown_fields crates/loopd/src/config.rs` prints 10 (the six old structs and
|
||||
the four new ones).
|
||||
|
||||
## Stop and report if
|
||||
|
||||
- `r#loop` cannot be used as a field name with serde. (It can; `serde` strips the `r#`.)
|
||||
Reference in New Issue
Block a user