Problem
The Sessions tab replays a session turn by turn, but file changes surface only as files_touched aggregates (ops letters, ±line counts) and the bounded file_change.diff text inside per-execution events. The store already keeps the real thing: crates/stella-store/src/work_journal.rs maintains a bare git repo at ~/.stella/work/<workspace-id>.git with the workspace attached as a work tree, committing per session onto refs/stella/<session>/head and marking every turn end as refs/stella/<session>/turn/<n> (WorkJournal::mark_turn). read_at_turn/blob_at_turn are documented as having writers but no consumer — a byte-exact per-turn diff source going unread.
Build
Decide the boundary first: the observatory reads .stella-rooted artifacts and spawns nothing. Reading a bare git repo means either (a) shelling out to git (a new subprocess surface — needs an explicit ruling like #615's), or (b) linking a pure-Rust object reader (gitoxide is heavy; a minimal loose-object+pack reader is nontrivial), or (c) teaching stella-store's WorkJournal to serve diffs and exposing them via a small CLI-side precomputation the observatory reads. Whichever is chosen, the route shape is /api/session-turn-diff?id=<session>&turn=<n> returning unified hunks (stella-diff shapes them once the two file versions are in hand — it is already a dependency).
Verify
Witness: a seeded work journal with two turn refs where one file changed between them produces hunks naming the changed lines; a missing work journal degrades to an empty payload.
Constraints
- The observatory is read-only and loopback-only; whatever reads the repo must not lock or mutate it while a live session commits.
run_id/execution_id/session_id join rules per AGENTS.md glossary.
Refs the Sessions tab work and #1511.
Problem
The Sessions tab replays a session turn by turn, but file changes surface only as
files_touchedaggregates (ops letters, ±line counts) and the boundedfile_change.difftext inside per-execution events. The store already keeps the real thing:crates/stella-store/src/work_journal.rsmaintains a bare git repo at~/.stella/work/<workspace-id>.gitwith the workspace attached as a work tree, committing per session ontorefs/stella/<session>/headand marking every turn end asrefs/stella/<session>/turn/<n>(WorkJournal::mark_turn).read_at_turn/blob_at_turnare documented as having writers but no consumer — a byte-exact per-turn diff source going unread.Build
Decide the boundary first: the observatory reads
.stella-rooted artifacts and spawns nothing. Reading a bare git repo means either (a) shelling out togit(a new subprocess surface — needs an explicit ruling like #615's), or (b) linking a pure-Rust object reader (gitoxide is heavy; a minimal loose-object+pack reader is nontrivial), or (c) teachingstella-store's WorkJournal to serve diffs and exposing them via a small CLI-side precomputation the observatory reads. Whichever is chosen, the route shape is/api/session-turn-diff?id=<session>&turn=<n>returning unified hunks (stella-diffshapes them once the two file versions are in hand — it is already a dependency).Verify
Witness: a seeded work journal with two turn refs where one file changed between them produces hunks naming the changed lines; a missing work journal degrades to an empty payload.
Constraints
run_id/execution_id/session_idjoin rules per AGENTS.md glossary.Refs the Sessions tab work and #1511.