Files
boxmaker/docs/plans/M5d2/09-memoryd-summary-index.md
T
kyleandGrok 4.6 df987c3058 docs: M5d-2 checklist: given-test lifetimes and cron AND
session_slot and the scheduler tests held a temporary JSON Value across
statements (E0716). Cron now pins DOM and DOW as AND, which the given tests
had not. Gate counts from task 04 on move up by one.

Co-Authored-By: Grok 4.6 <noreply@x.ai>
2026-10-03 01:31:07 -07:00

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 **1568** (1563 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 1568 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 1568; 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`.