A batch carries the Mattermost user id of each message; the turn's speaker
is the username of the one user who wrote all of it (Client::username,
kept in a map on the event loop), and None for two or more people or a
failed lookup. The turn's text is unchanged.
Checks: reference replayed from the task text on a fresh ref-02 worktree
with its own build dir, byte-identical; make gate ok with 1148 tests
(1138 + 10); /tmp unchanged around both gate runs; 21 mutations, all
caught; new tests stressed 40 times under load, no failure; every before
block found once at ref 02; no chat-template tags.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The owner's hosts (titan, talos) run 1.98.1; nixos-26.05's Rust is
1.95.0, so builds and lints differed by host. The flake gains a second
input, oxalica's rust-overlay (following our nixpkgs, so host configs
can still follow theirs), and both the package build and the dev shell
use its stable 1.98.1 with clippy and rustfmt. The workspace's
rust-version rises to 1.98 to match; AGENTS.md, docs/dependencies.md
and the M5c-1 plan follow.
Checked on straylight: nix build gives all seven binaries; the dev
shell has rustc, cargo and clippy 1.98.1, rustfmt 1.9.0, cargo-deny
0.19.6; make gate in it passes with 1122 tests, as on titan.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
loopd copies the Turn's speaker onto the User record it logs, as it
came (not checked, not neutralised), and never into a request; after a
finished turn it sends SessionUpdated with the turn's number, the count
of User records in the session's log (Session::turns), so the first
turn is 1, a failed turn that was logged counts, and the count goes on
after a reopen or a restart. Failed turns are still not told.
Given: speaker_turn.rs (8 tests) and new versions of loopd's memory.rs,
turn_broker.rs, end_to_end.rs and support/turn.rs (run_turn gains
speaker, MemorySource::updated gains turn). Task 01 now copies
memory.rs-task01, its own version.
Checks: the reference passes make gate with 1138 tests (1130 + 8); the
task replayed from its text on a fresh ref-01 worktree with its own
target is byte-identical to the reference and passes the gate; /tmp
unchanged around both gate runs; 15 one-line mutations (speaker not
logged or dropped by the channel or neutralised, speaker in the request
at log time or at replay, turn 0-based or +1, counting Assistant
records, all records or only speakers' turns, a global or per-process
counter, told before logging or on failure, MemoryPort sending 0) all
caught; speaker_turn run 60 times under load, no failure; no
chat-template tag in the plan or given files; task lines within 100
characters but tables.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Task 01 changes bxcore's wire and log types for M5c-1: Turn.speaker and
LogRecord::User.speaker (optional, skipped when None, so old frames and logs
keep their bytes), SessionUpdated.turn (required, refused when missing), and
the new SessionState / SessionStateReply messages. The other crates only
construct the new fields (speaker: None, turn: 0) and brokerd's kind() names
the two new kinds; later tasks give them values. 20 given files.
Checks, against a reference at 7b40686 with its own build directory:
- every "before" block found exactly once at 7b40686 (and at master, which
changed no crate since);
- step 2's failures as the task names them: two strict tests, fifteen test
targets with E0559/E0560/E0432/E0599 only;
- make gate: gate: ok, 1130 tests (1122 + 8); /tmp unchanged around it;
- replay from the task text in a fresh worktree of 7b40686 with its own
target/: crates/ byte-identical to the reference, gate ok, 1130; removed;
- 23 mutations: 21 caught; the two that drop `default` from an Option
field cannot change behaviour (serde reads a missing Option as None);
- no chat-template tag whole in the task or the given files; lines over
100 characters only in tables, fixtures and verbatim strings.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
29 request/response pairs, each request exactly as roncho 1.0.0's
blocking client sends it, recorded in a throwaway workspace
(boxmaker-plan-probe) created for it and deleted afterwards; no other
workspace was touched. For the fake Honcho server of task 10. Found:
creation is get-or-create (201, then 200); adding messages to a missing
session creates it; a 422 echoes the whole input; a deleted conclusion
answers 204 with an empty body, and 404 the second time.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>