docs: M5d-1 and M5d-2 implementation plans for Ornith
Eight closed tasks for epochs and compaction, then ten for the scheduler, ToolSummary, and tiers. Given tests first. Gate 1456 → 1507 → 1572. Co-Authored-By: Grok 4.6 <noreply@x.ai>
This commit is contained in:
@@ -0,0 +1,209 @@
|
||||
# M5d-1 task 01: `[compact]` on `loopd.toml`
|
||||
|
||||
**Branch:** `m5d1`. Check it: `git branch --show-current` prints `m5d1` and `git status --short`
|
||||
is empty; otherwise stop. Never switch branch.
|
||||
**Commit subject:** `loopd: [compact] threshold, summary_chars and summarise`
|
||||
**Log row:** the Task cell is `M5d1/01-loopd-compact-config`.
|
||||
|
||||
## Goal
|
||||
|
||||
M5d-1 compact after a turn whose last `Usage` is at or above a fraction of `expect.n_ctx` (spec
|
||||
3.3, 5). This task adds only the `[compact]` table so later tasks can read it:
|
||||
|
||||
- `threshold` (float, default `0.85`)
|
||||
- `summary_chars` (default `4000`)
|
||||
- `summarise` (list of tool names, default `["http_fetch"]`)
|
||||
|
||||
Nothing in this task uses the values. `summarise` is stored so a spec-complete `loopd.toml`
|
||||
loads; M5d-2 reads it. Unknown keys in `[compact]` are errors, as in every table we define.
|
||||
|
||||
`Config::compact_prompt` is `compact.md` beside `[baseline] system` (the same directory join
|
||||
`load` already does for `system.md`). The starter file is copied in task 05.
|
||||
|
||||
## Every place that changes
|
||||
|
||||
This is the complete list.
|
||||
|
||||
| Place | What happens there |
|
||||
|---|---|
|
||||
| `crates/loopd/src/config.rs` | `Compact`; `Config.compact`; `Config::compact_prompt` (edits C1 to C3) |
|
||||
| `crates/loopd/tests/config_compact.rs` | new, given |
|
||||
| everything else | **no change**: not `session.rs`, not the existing `config.rs` tests or fixtures |
|
||||
|
||||
## Files
|
||||
|
||||
- Copy, from `docs/plans/M5d1/files/` (the same path under it): the new test
|
||||
`crates/loopd/tests/config_compact.rs`.
|
||||
- Modify: `crates/loopd/src/config.rs`, `docs/implementer-log.md`.
|
||||
- Do not touch: any other file.
|
||||
|
||||
## Facts you need
|
||||
|
||||
- **`Config` already has `#[serde(default)]` on optional tables** (`sampling`, `limits`, `paths`,
|
||||
`channel`, `loop`, `baseline`, `broker`, `memory`). `[compact]` is the same: missing means
|
||||
`Compact::default()`.
|
||||
- **`threshold` is `f64`.** `Sampling.temperature` is already `f64` on `Config`, so `PartialEq`
|
||||
on `Config` still compiles. Do not add a range check: the spec does not name one.
|
||||
- **`summarise` default.** `vec!["http_fetch".to_string()]`. An explicit `summarise = []` is
|
||||
allowed and is empty. Unknown names are not checked here (M5d-2).
|
||||
- **`compact_prompt`.** `self.baseline.system.with_file_name("compact.md")`. After `load`,
|
||||
`baseline.system` is already joined to the config file's directory, so the prompt follows it
|
||||
into a subdirectory when `system` does (`prompts/agent.md` → `prompts/compact.md`).
|
||||
- The items the edits use. This table is complete; `serde` is already a dependency of `loopd`.
|
||||
|
||||
| Item | What it does |
|
||||
|---|---|
|
||||
| `#[serde(deny_unknown_fields, default)]` | on `Compact`: missing table uses `Default`; unknown keys error |
|
||||
| `Path::with_file_name` | `compact.md` beside `system.md` |
|
||||
| `Vec<String>` | `summarise` |
|
||||
|
||||
## The edits, exactly
|
||||
|
||||
Nothing else in this file changes. Each quoted "before" block occurs exactly once in its file
|
||||
when its turn comes (make them in order). Keep the fields in the order shown.
|
||||
|
||||
### `crates/loopd/src/config.rs`
|
||||
|
||||
**C1.** After the `Memory` struct (the lines)
|
||||
|
||||
```rust
|
||||
pub struct Memory {
|
||||
pub socket: std::path::PathBuf,
|
||||
}
|
||||
```
|
||||
|
||||
become
|
||||
|
||||
```rust
|
||||
pub struct Memory {
|
||||
pub socket: std::path::PathBuf,
|
||||
}
|
||||
|
||||
/// `[compact]`: when a session starts a new epoch, and how long a summary may be (M5d spec,
|
||||
/// section 5). `summarise` is stored here and unused until M5d-2.
|
||||
#[derive(Debug, Clone, PartialEq, Deserialize)]
|
||||
#[serde(deny_unknown_fields, default)]
|
||||
pub struct Compact {
|
||||
pub threshold: f64,
|
||||
pub summary_chars: usize,
|
||||
pub summarise: Vec<String>,
|
||||
}
|
||||
|
||||
impl Default for Compact {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
threshold: 0.85,
|
||||
summary_chars: 4_000,
|
||||
summarise: vec!["http_fetch".to_string()],
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**C2.** The lines
|
||||
|
||||
```rust
|
||||
#[serde(default)]
|
||||
pub memory: Memory,
|
||||
}
|
||||
```
|
||||
|
||||
become
|
||||
|
||||
```rust
|
||||
#[serde(default)]
|
||||
pub memory: Memory,
|
||||
#[serde(default)]
|
||||
pub compact: Compact,
|
||||
}
|
||||
```
|
||||
|
||||
**C3.** After `channel_socket` (the lines)
|
||||
|
||||
```rust
|
||||
pub fn channel_socket(&self) -> std::path::PathBuf {
|
||||
if self.channel.socket.as_os_str().is_empty() {
|
||||
self.paths.home.join("run/loop/loop.sock")
|
||||
} else {
|
||||
self.channel.socket.clone()
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
become
|
||||
|
||||
```rust
|
||||
pub fn channel_socket(&self) -> std::path::PathBuf {
|
||||
if self.channel.socket.as_os_str().is_empty() {
|
||||
self.paths.home.join("run/loop/loop.sock")
|
||||
} else {
|
||||
self.channel.socket.clone()
|
||||
}
|
||||
}
|
||||
|
||||
/// `compact.md` beside the system prompt: the summary call's last user message.
|
||||
pub fn compact_prompt(&self) -> std::path::PathBuf {
|
||||
self.baseline.system.with_file_name("compact.md")
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Steps
|
||||
|
||||
- [ ] **1. Copy the given test.** From the repository root, one command:
|
||||
|
||||
```sh
|
||||
cp docs/plans/M5d1/files/crates/loopd/tests/config_compact.rs crates/loopd/tests/
|
||||
```
|
||||
|
||||
Then `git status --short` lists one new file, `crates/loopd/tests/config_compact.rs`.
|
||||
- [ ] **2. See it fail.** `cargo build --tests --keep-going -p loopd`, with a shell timeout of
|
||||
600000 ms: one test target, `config_compact`, does not compile, with `E0609` (`no field
|
||||
\`compact\` on type \`Config\``) and `E0599` (`no method named \`compact_prompt\`` /
|
||||
`no variant or associated item named \`default\` for \`Compact\``). Every other target
|
||||
compiles.
|
||||
- [ ] **3. The edits.** Make edits C1 to C3, in order. `cargo check -p loopd` prints no error and
|
||||
no warning.
|
||||
- [ ] **4. The tests.** `cargo test -p loopd --test config_compact --test config`: every test
|
||||
passes, 8 in `config_compact` and the others as before.
|
||||
- [ ] **5. Check.** `git diff --stat` lists exactly `crates/loopd/src/config.rs`.
|
||||
- [ ] **6. Run the gate.** `cargo fmt --all`, then `make gate`, with a shell timeout of 600000 ms.
|
||||
Expected last line: `gate: ok`. The test count is **1464** after this task, 1456 before it
|
||||
(1455 passed in `cargo test --workspace`, plus 1), and the 8 new ones are the tests of
|
||||
`config_compact.rs`. To count, add up the `N passed` of every `test result:` line the gate's
|
||||
`cargo test --workspace` printed, and add 1. Never run the gate again only to count.
|
||||
- [ ] **7. Log and commit.** Add your row to `docs/implementer-log.md`; its Task cell is
|
||||
`M5d1/01-loopd-compact-config`. Stage with
|
||||
`git add crates/loopd docs/implementer-log.md Cargo.lock`, then commit as `AGENTS.md` says.
|
||||
`Cargo.lock` does not change in this task; the `git add` is harmless.
|
||||
|
||||
## Done when
|
||||
|
||||
- `make gate` prints `gate: ok` with 1464 tests.
|
||||
- `git diff HEAD~1 --stat` lists only `crates/loopd/src/config.rs`,
|
||||
`crates/loopd/tests/config_compact.rs` and `docs/implementer-log.md`.
|
||||
|
||||
## Stop and report if
|
||||
|
||||
- The branch check at the top fails.
|
||||
- A "before" block is not in its file exactly as shown when its turn comes, or is there more
|
||||
than once.
|
||||
- Step 2 shows a different result: another target failing, or other errors.
|
||||
- `cargo check` in step 3 prints an error or a warning. Quote it, and stop.
|
||||
- A test fails in step 4. Do not change the test: stop, and give the failing tests' names and
|
||||
their messages.
|
||||
- The fix seems to need a change anywhere else: a fixture, `config.rs` tests, a range check on
|
||||
`threshold`. It does not; stop and say why you think so.
|
||||
- A test outside `config_compact.rs` fails in the gate: check once whether it fails without your
|
||||
change (`git stash -u`, run it, `git stash pop`), then stop and report both results.
|
||||
- The gate passes with a count other than 1464.
|
||||
- A comment in an edit does not fit the code under it. Quote it and stop.
|
||||
|
||||
## What the given tests pin
|
||||
|
||||
Each of these changes to the finished code makes at least one given test fail: the default
|
||||
threshold moved; `summary_chars` default moved; `summarise` default emptied or given another
|
||||
name; unknown keys accepted; a misspelt `summary_char` accepted; a partial table wiping the
|
||||
other defaults; `compact_prompt` using `home` or the config file's name instead of `system.md`'s
|
||||
directory; `Compact::default` disagreeing with a missing table.
|
||||
Reference in New Issue
Block a user