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>
142 lines
5.5 KiB
Markdown
142 lines
5.5 KiB
Markdown
# M5d-2 task 09: index `ToolSummary` as kind `summary`
|
|
|
|
**Branch:** `m5d2`. Check it: `git branch --show-current` prints `m5d2` and `git status --short`
|
|
is empty; otherwise stop. Never switch branch.
|
|
**Commit subject:** `memoryd: index ToolSummary as kind summary`
|
|
**Log row:** the Task cell is `M5d2/09-memoryd-summary-index`.
|
|
|
|
## Goal
|
|
|
|
`memoryd` indexes `LogRecord::ToolSummary` content as kind `summary`, with that record's
|
|
`class` and `untrusted` (spec 4.3, P26). `recall` finds it and tags `memory` or
|
|
`memory-tainted` as for any other session hit. Raw `ToolResult` bodies stay unindexed.
|
|
|
|
`index_record` today has `_ => {}`. It compiles. This task adds the arm.
|
|
|
|
## Every place that changes
|
|
|
|
| Place | What happens there |
|
|
|---|---|
|
|
| `crates/memoryd/src/index.rs` | `ToolSummary` arm (edit I1); module doc |
|
|
| `crates/memoryd/tests/tool_summary_index.rs` | new, given |
|
|
| everything else | **no change**: not `recall.rs` headers (role `"summary"` uses the existing "the assistant said" branch) |
|
|
|
|
## Files
|
|
|
|
- Copy, from `docs/plans/M5d2/files/` (the same path under it): the new test
|
|
`crates/memoryd/tests/tool_summary_index.rs`.
|
|
- Modify: `crates/memoryd/src/index.rs`, `docs/implementer-log.md`.
|
|
- Do not touch: any other file. Do not edit `tests/support/logs.rs`.
|
|
|
|
## Facts you need
|
|
|
|
- **Kind `summary`.** Set `kind: "summary".to_string()` on the `Source`, not the log's
|
|
`"session"`. Role `"summary"`. Time from the record. `class` / `untrusted` from the
|
|
`ToolSummary`, not from `base` (the rolling session label). Skip when
|
|
`summary.class > self.max_class`, even if `base.class` is still `Private`. Skip when
|
|
`content.trim()` is empty.
|
|
- **The existing `if base.class > self.max_class` stays.** A secret `ToolResult` raises the
|
|
rolling label before the next record, so a following secret summary is also skipped that
|
|
way. Still check the summary's own class.
|
|
- **Do not add `ToolSummary` to the rolling-label update** in `index_log` (that loop still
|
|
looks at `ToolResult` only). The result already carried the same labels.
|
|
- **Recall headers.** `kind` `"summary"` is not `moved` / `dropped` / `noted`, so the tag is
|
|
`memory` or `memory-tainted`. Role `"summary"` is not `owner` or `call`, so the line says
|
|
`the assistant said`. The given tests look for `memory · session mm-a` and
|
|
`memory-tainted`.
|
|
- The items the edits use. This table is complete.
|
|
|
|
| Item | What it does |
|
|
|---|---|
|
|
| `self.add` | FTS row plus `sources` |
|
|
| `Source` | kind / role / class / untrusted |
|
|
|
|
## The edits, exactly
|
|
|
|
Each quoted "before" block occurs exactly once.
|
|
|
|
### `crates/memoryd/src/index.rs`
|
|
|
|
**I1.** After the `Assistant` arm, before `_ => {}`. The lines
|
|
|
|
```rust
|
|
}
|
|
_ => {}
|
|
}
|
|
Ok(())
|
|
}
|
|
```
|
|
|
|
become
|
|
|
|
```rust
|
|
}
|
|
LogRecord::ToolSummary {
|
|
time,
|
|
content,
|
|
class,
|
|
untrusted,
|
|
..
|
|
} if !content.trim().is_empty() && *class <= self.max_class => {
|
|
let src = Source {
|
|
kind: "summary".to_string(),
|
|
time: time.to_rfc3339(),
|
|
role: "summary".to_string(),
|
|
class: *class,
|
|
untrusted: *untrusted,
|
|
..base.clone()
|
|
};
|
|
self.add(content, &src)?;
|
|
}
|
|
_ => {}
|
|
}
|
|
Ok(())
|
|
}
|
|
```
|
|
|
|
`DataClass` already implements `Ord` (`Public < Private < Secret`). If `<=` does not
|
|
compile, stop.
|
|
|
|
Optionally update the module doc "never a tool's result" to say summaries of opted-in
|
|
results are indexed. A comment that does not fit its code: stop.
|
|
|
|
## Steps
|
|
|
|
- [ ] **1. Copy the given test.**
|
|
|
|
```sh
|
|
cp docs/plans/M5d2/files/crates/memoryd/tests/tool_summary_index.rs crates/memoryd/tests/
|
|
```
|
|
|
|
- [ ] **2. See it fail.** `cargo test -p memoryd --test tool_summary_index`, timeout 600000
|
|
ms: the tests compile (`ToolSummary` exists) and `a_tool_summary_is_found_as_kind_summary`
|
|
fails: `(no matches for "tea")` or the unique phrase is missing. `the_raw_tool_result_is_still_not_indexed`
|
|
may pass (results were already unindexed).
|
|
- [ ] **3. The edit.** I1. `cargo check -p memoryd` prints no error and no warning.
|
|
- [ ] **4. The tests.** `cargo test -p memoryd --test tool_summary_index --test recall`: every
|
|
test passes, 5 in `tool_summary_index`.
|
|
- [ ] **5. Check.** `git diff --stat` lists exactly `crates/memoryd/src/index.rs`.
|
|
- [ ] **6. Run the gate.** `cargo fmt --all`, then `make gate`, timeout 600000 ms. Last line
|
|
`gate: ok`. Test count **1566** (1561 before, plus 5).
|
|
- [ ] **7. Log and commit.** Task cell `M5d2/09-memoryd-summary-index`. Stage with
|
|
`git add crates/memoryd docs/implementer-log.md Cargo.lock`, then commit as `AGENTS.md`
|
|
says.
|
|
|
|
## Done when
|
|
|
|
- `make gate` prints `gate: ok` with 1566 tests.
|
|
- `git diff HEAD~1 --stat` lists only `crates/memoryd/src/index.rs`,
|
|
`crates/memoryd/tests/tool_summary_index.rs` and the log.
|
|
|
|
## Stop and report if
|
|
|
|
- The branch check fails; a "before" block is not found exactly once; step 2 differs; `cargo
|
|
check` warns; a test fails; the gate count is not 1566; you index `ToolResult` content; you
|
|
leave `kind` as `"session"`; a secret summary is searchable on a private index.
|
|
|
|
## What the given tests pin
|
|
|
|
A summary's content is found and tagged `memory · session …`; the raw tool body is not; an
|
|
untrusted summary taints the recall (`memory-tainted`); a trusted summary does not taint; a
|
|
secret summary is skipped when `max_class` is `Private`.
|