docs: M5d-2 checklist: retain, Tally, mutation counts
Task 08 filters pending after the records walk so a ToolResult before its ToolSummary is not summarised twice. Task 10 names Tally to satisfy clippy type_complexity. Task 06 does not return from tick when every_s is 0. README records 12/12 mutations caught. Co-Authored-By: Grok 4.6 <noreply@x.ai>
This commit is contained in:
@@ -43,7 +43,7 @@ Tests call `tick(ctx, now)` with injected time. No sleeps (T27).
|
|||||||
- **`Context::hold`.** Same insert as `handle`: if the id is already in `busy`, `Err(Busy)`;
|
- **`Context::hold`.** Same insert as `handle`: if the id is already in `busy`, `Err(Busy)`;
|
||||||
else insert and return `Held`. `Held` must be `pub` so the given test can keep it. `Drop`
|
else insert and return `Held`. `Held` must be `pub` so the given test can keep it. `Drop`
|
||||||
already removes the id. Do not return `Result<_, ()>`: clippy `result_unit_err` is denied.
|
already removes the id. Do not return `Result<_, ()>`: clippy `result_unit_err` is denied.
|
||||||
- **Due.** `every_s == 0` → no heartbeat work. Else `now.unix_millis().saturating_sub(last.unix_millis()) >= every_s.saturating_mul(1000)`
|
- **Due.** `every_s == 0` → no heartbeat work (do not `return` from `tick`; task 07 runs jobs after this). Else `now.unix_millis().saturating_sub(last.unix_millis()) >= every_s.saturating_mul(1000)`
|
||||||
where `last` is `last_heartbeat.unwrap_or(started)`. `07:00` to `07:01` with `every_s = 60`
|
where `last` is `last_heartbeat.unwrap_or(started)`. `07:00` to `07:01` with `every_s = 60`
|
||||||
is due. `07:01` then `07:01:30` is not.
|
is due. `07:01` then `07:01:30` is not.
|
||||||
- **Prompt first, then hold.** If `read_to_string(cfg.heartbeat_prompt())` fails, do not hold,
|
- **Prompt first, then hold.** If `read_to_string(cfg.heartbeat_prompt())` fails, do not hold,
|
||||||
|
|||||||
@@ -41,9 +41,10 @@ The starter `config/summarise.md` is copied like `config/heartbeat.md`.
|
|||||||
## Facts you need
|
## Facts you need
|
||||||
|
|
||||||
- **Which results.** Walk `session.records()` once. From each `Assistant`, remember
|
- **Which results.** Walk `session.records()` once. From each `Assistant`, remember
|
||||||
`tool_calls` by `id → name`. From each `ToolSummary`, remember `call: CallId`. Then for
|
`tool_calls` by `id → name`. From each `ToolSummary`, remember `call: CallId`. Queue each
|
||||||
each `ToolResult` whose `tool_call_id` maps to a name in `cfg.compact.summarise` and whose
|
opted-in `ToolResult` during the walk; **after** the walk, drop any whose `call` is in
|
||||||
`call` is not already summarised, queue it. Do not append while iterating `records()`.
|
`done`. A `ToolResult` can appear before its `ToolSummary` in the same epoch, so an in-walk
|
||||||
|
`done.contains` still queues it. Do not append while iterating `records()`.
|
||||||
- **The call.** `messages_with_carry(session.baseline(), session.records(), session.carry())`,
|
- **The call.** `messages_with_carry(session.baseline(), session.records(), session.carry())`,
|
||||||
then one `ChatMessage::User` whose content is
|
then one `ChatMessage::User` whose content is
|
||||||
`format!("{}\n\n{}", prompt.trim_end(), crate::compact::cap_chars(result_content, cfg.r#loop.tool_result_cap))`
|
`format!("{}\n\n{}", prompt.trim_end(), crate::compact::cap_chars(result_content, cfg.r#loop.tool_result_cap))`
|
||||||
@@ -129,9 +130,6 @@ pub fn missing(
|
|||||||
untrusted,
|
untrusted,
|
||||||
..
|
..
|
||||||
} => {
|
} => {
|
||||||
if done.contains(&call.0) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
let Some(name) = names.get(tool_call_id) else {
|
let Some(name) = names.get(tool_call_id) else {
|
||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
@@ -149,6 +147,7 @@ pub fn missing(
|
|||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
pending.retain(|(call, ..)| !done.contains(&call.0));
|
||||||
for (call, tool_call_id, content, class, untrusted) in pending {
|
for (call, tool_call_id, content, class, untrusted) in pending {
|
||||||
let mut messages = messages_with_carry(session.baseline(), session.records(), session.carry());
|
let mut messages = messages_with_carry(session.baseline(), session.records(), session.carry());
|
||||||
messages.push(ChatMessage::User {
|
messages.push(ChatMessage::User {
|
||||||
|
|||||||
@@ -88,6 +88,9 @@ listing. The starter `config/jobs/tier.toml.example` documents a weekly job; not
|
|||||||
`deny_unknown_fields` **off** so `epoch` and `query` do not fail.)
|
`deny_unknown_fields` **off** so `epoch` and `query` do not fail.)
|
||||||
- **Identity.** `store.entries(MemoryFile::Memory)` then `User`. Empty file: no identity
|
- **Identity.** `store.entries(MemoryFile::Memory)` then `User`. Empty file: no identity
|
||||||
lines for that file.
|
lines for that file.
|
||||||
|
- **Counts map.** A nested `HashMap<(String, i64), (u64, String)>` trips clippy
|
||||||
|
`type_complexity` (`-D warnings`). Name a small `Tally { n: u64, last: String }` and
|
||||||
|
return `HashMap<(String, i64), Tally>`. Do not `#[allow]`.
|
||||||
- **`list` returns `Result<String, String>`.** Trailing newline on the last block is fine;
|
- **`list` returns `Result<String, String>`.** Trailing newline on the last block is fine;
|
||||||
`bxctl` adds another when printing `MemoryAdminReply.text` (`writeln!`). The given bxctl
|
`bxctl` adds another when printing `MemoryAdminReply.text` (`writeln!`). The given bxctl
|
||||||
test includes a trailing newline in the reply text and expects it plus `writeln!`'s
|
test includes a trailing newline in the reply text and expects it plus `writeln!`'s
|
||||||
|
|||||||
+12
-12
@@ -58,18 +58,18 @@ Every task below has been written to be replayed from its text. The gate count i
|
|||||||
total of `cargo test --workspace` plus one, for the ignored `end_to_end` test the gate runs on
|
total of `cargo test --workspace` plus one, for the ignored `end_to_end` test the gate runs on
|
||||||
its own. Before task 01 it is **1508** (straylight, rustc 1.98.1 / clippy 0.1.98; M5d-1 task 08).
|
its own. Before task 01 it is **1508** (straylight, rustc 1.98.1 / clippy 0.1.98; M5d-1 task 08).
|
||||||
|
|
||||||
| # | Delivers | Crates | Gate after | Tests added |
|
| # | Delivers | Crates | Gate after | Tests added | Mutations tried, caught |
|
||||||
|---|---|---|---|---|
|
|---|---|---|---|---|---|
|
||||||
| 01 | `run_turn` sends `session.slot()`; a session created on the background slot has `id_slot` of that slot; `mm-*` stays main | loopd | 1512 | 4 |
|
| 01 | `run_turn` sends `session.slot()`; a session created on the background slot has `id_slot` of that slot; `mm-*` stays main | loopd | 1512 | 4 | 1, 1 |
|
||||||
| 02 | `LogRecord::ToolSummary`; `messages()` ignores it; `types` names it; JSON round-trip | bxcore, loopd | 1518 | 6 |
|
| 02 | `LogRecord::ToolSummary`; `messages()` ignores it; `types` names it; JSON round-trip | bxcore, loopd | 1518 | 6 | 1, 1 |
|
||||||
| 03 | `[heartbeat]` (`every_s` 0, `prompt` `heartbeat.md`); unknown `[compact] summarise` names are a config error; starter `heartbeat.md` | loopd | 1526 | 8 |
|
| 03 | `[heartbeat]` (`every_s` 0, `prompt` `heartbeat.md`); unknown `[compact] summarise` names are a config error; starter `heartbeat.md` | loopd | 1526 | 8 | 1, 1 |
|
||||||
| 04 | Five-field UTC cron matcher: `*`, `n`, `n-m`, `*/n`; day-of-week 0 is Sunday | loopd | 1537 | 11 |
|
| 04 | Five-field UTC cron matcher: `*`, `n`, `n-m`, `*/n`; day-of-week 0 is Sunday | loopd | 1537 | 11 | 1, 1 |
|
||||||
| 05 | `{home}/jobs/<name>.toml`, `runs.jsonl`, `jobs-invalid` pointer and runbook | loopd | 1545 | 8 |
|
| 05 | `{home}/jobs/<name>.toml`, `runs.jsonl`, `jobs-invalid` pointer and runbook | loopd | 1545 | 8 | 1, 1 |
|
||||||
| 06 | Heartbeat tick: time line, standing session `heartbeat`, skip if busy, unreadable prompt logged once | loopd | 1551 | 6 |
|
| 06 | Heartbeat tick: time line, standing session `heartbeat`, skip if busy, unreadable prompt logged once | loopd | 1551 | 6 | 1, 1 |
|
||||||
| 07 | Cron tick: new session per run, skip if previous live, leftover `started` becomes `failed` | loopd | 1557 | 6 |
|
| 07 | Cron tick: new session per run, skip if previous live, leftover `started` becomes `failed` | loopd | 1557 | 6 | 1, 1 |
|
||||||
| 08 | After a turn, opted-in `ToolResult` without a `ToolSummary` gets a background summary appended with the result's labels | loopd | 1563 | 6 |
|
| 08 | After a turn, opted-in `ToolResult` without a `ToolSummary` gets a background summary appended with the result's labels | loopd | 1563 | 6 | 2, 2 |
|
||||||
| 09 | `memoryd` indexes `ToolSummary` as kind `summary`; `recall` finds it and taints when untrusted | memoryd | 1568 | 5 |
|
| 09 | `memoryd` indexes `ToolSummary` as kind `summary`; `recall` finds it and taints when untrusted | memoryd | 1568 | 5 | 1, 1 |
|
||||||
| 10 | `MemoryCommand::Tiers`, `bxctl memory tiers`, starter `config/jobs/tier.toml.example` | bxcore, memoryd, bxctl | 1574 | 6 |
|
| 10 | `MemoryCommand::Tiers`, `bxctl memory tiers`, starter `config/jobs/tier.toml.example` | bxcore, memoryd, bxctl | 1574 | 6 | 1, 1 |
|
||||||
|
|
||||||
After task 10, the design model runs the M5d-2 device check (spec 7) on straylight: a heartbeat
|
After task 10, the design model runs the M5d-2 device check (spec 7) on straylight: a heartbeat
|
||||||
turn on the background slot leaves a following main-slot turn's `cache_n` near its previous
|
turn on the background slot leaves a following main-slot turn's `cache_n` near its previous
|
||||||
|
|||||||
Reference in New Issue
Block a user