Repository navigation
Description
What to build
Deepen retained Harness completion so a change to Muse's Session log rules or OpenCode's export rules stays within its Harness adapter. Session recording should consume one completion report without knowing which Harness supplies retained Models.
Preserve final assistant text, usage summaries, Model attribution and progress, failure causes, safeguard refusals, and interruption. This is an internal refactor sized for one session.
Acceptance criteria
- Generic Harness Interpretation no longer imports Muse/OpenCode, stores a concrete retained-source enum, or selects their retained-record policies. Each Harness adapter supplies its retained implementation through an internal seam.
- Session recording displays completion progress from the report without matching on the chosen Harness. Retained Model progress keeps its current text, order, and multiplicity; stream-only Harnesses gain no completion Model lines.
- Muse preserves stream facts when records are unavailable or unreadable. A readable record replaces Models and usage, including an authoritative empty Model set, but replaces final text only when present. Unrelated session and sub-agent records remain excluded.
- OpenCode performs no export without a session id. An unavailable/unreadable export preserves stream facts; a readable export replaces final text, Models, and summary even when empty. An exported failure fails a zero-exit session and preserves an existing stream diagnostic.
- Execution errors retain precedence; ordinary failures retain available completion reporting; safeguard refusals stay sticky. Interruption before/during retained completion returns
interrupted, suppresses the report, and preserves the stream Model checkpoint. - Recording's captured owning Command, metadata format, attribution fallbacks, warning-only evidence writes, and child inheritance remain compatible.
- Muse's minimal Model check remains stream-only; OpenCode's check retains export reconciliation and interruption behavior. Release summaries and Resumes retain their existing interpretation behavior.
- Preserve the existing interface tests and extend them for completion Model progress and absence of duplicate live progress. Update fixture construction and delete tests made redundant by interface coverage; do not assert internal adapter calls.
- Before delivering the implementation, run formatting, clippy across all targets with warnings denied, and the full Rust suite.
Blocked by
None (can start immediately).
Decisions
The settled design tree has retained-completion ownership at its root. Its children are the seam, retained authority, lifecycle ordering, and caller reporting; these determine construction, compatibility, and testing. Three rounds settle every branch below. No Day shift decision remains.
Round 1: ownership and seam
- Concentrate retained policy inside the Harness module. Its adapter owns live decoding already, but generic Interpretation selects Muse/OpenCode reconciliation and Session recording separately selects their Model progress. Absorbing this caller knowledge gives locality in a recent hot spot. Limit the work to this leakage, preserving product behavior.
- Keep Interpretation's existing external interface. Callers still condense lines, obtain observed Models, and finish into a report and outcome; captured checks keep their validation entry point. Add one Harness-private retained completion interface, with an optional owned boxed adapter that reconciles completed facts and returns an error. Require Send because Interpretation moves into the transcript reader. Muse records and OpenCode exports are two real adapters, so the internal seam is justified. Stream-only interpretation uses absence, without a no-op adapter or concrete Harness enum.
Round 2: implementation and reporting
- Place each implementation beside its retained reader. Muse captures its optional data root; OpenCode captures its Worktree path. Each adapter owns lookup, authoritative replacement, and completion Model progress. Reuse existing readers and subprocess controls. Owned paths preserve the worker lifetime without borrowing a checkout.
- Preserve differing authority rules. Muse replaces usage and Models but only replaces final text when present. OpenCode's readable export is authoritative even without text or Models and promotes exported failure while preferring a stream diagnostic. Unavailable sources remain optional. Existing interface tests demonstrate these actual Harness differences; a normalized policy would lose them.
- Keep lifecycle and error precedence in generic Interpretation. Complete after the process owner waits/stops the child and joins its workers. Check interruption before completion and after reconciliation; seed the report with observed stream Models before reconciliation; apply sticky safeguard refusal as today; retain execution-error precedence over reconciliation/turn errors. Ordinary errors can carry reports; interruption cannot. This keeps cross-Harness policy in one place and protects attribution recovery.
- Carry ordered completion progress in the report. Add a completion-progress collection distinct from Models, warnings, and summary. The retained adapter supplies the existing
Model: ...lines from the final report's Models, including fallback stream Models when retained records are unavailable. Recording keeps evidence, then prints completion progress, warnings, and elapsed-time summary in their current order. Other adapters leave completion progress empty. Recording keeps Choice for process control and attribution metadata, without selecting retained reporting rules. Captured checks and release summaries continue to ignore report progress.
Round 3: construction, compatibility, and testing
- Default construction to stream-only; adapters attach retained completion. Muse sessions/summaries attach record completion, while its paid minimal Model check deliberately does not. OpenCode sessions/summaries/checks attach export completion. Resumes use the same construction as their first session. This preserves existing choices without exposing retained paths or policies to Session callers.
- Preserve Recording's two-stage evidence persistence. The reader checkpoints consumed stream Models before supervision can suppress recovered state. A present completion report replaces that checkpoint even with empty Models; an absent report leaves it untouched. Captured Command ownership and existing metadata formats remain intact because this change concerns completion ownership, not attribution semantics.
- Use the existing interface as the test surface. Retain adapter-created Interpretation tests with isolated Muse records and a fake OpenCode executable, Recording tests for conflicting/empty evidence and interrupted checkpoints, and CLI scenarios for text authority, exported failures, fallback, usage, Model checks, and Resumes. Extend report/progress assertions to verify retained Model order, empty sets, and no duplicate stream-only progress. Update the synthetic stream/retained fixture to obtain retained completion from Harness-owned fixture construction rather than recreate an enum in generic tests. Assert observable text, reports, progress, attribution, and failures, not internal adapter calls. This gives leverage across recording, captured checks, and summaries without fixing the implementation topology in tests.
- Deliver one standalone Ticket with no domain-document changes. One internal seam and two existing adapters fit one fresh context window; no independent migration stages or new domain concept are needed. CONTEXT.md's Harness, Session log, and Run notification definitions remain accurate. ADRs 0001 and 0013 remain respected; this reversible implementation choice requires no new ADR. No CONTEXT.md or ADR edit belongs to this Ticket.
Baseline verification on main at 4fd3f719b111ba5d7aa6a3d5eba6ddfa66a23517:
cargo test --bin thirdshift harness::interpretation_tests: 19 passed.cargo test --bin thirdshift session::recording::tests: 11 passed.cargo test --test muse_sessions --test opencode_sessions: 26 passed.
These 56 passing tests verify the current contracts, not a completed implementation.
Architecture review
Strength: Strong · Dependencies: local-substitutable
Files: src/harness/interpretation.rs, src/harness/muse.rs, src/harness/muse/log.rs, src/harness/opencode.rs, src/harness/opencode/export.rs, src/session/recording.rs, src/harness/interpretation_tests.rs, src/session/recording/tests.rs, tests/muse_sessions.rs, tests/opencode_sessions.rs
Before
flowchart LR
S[Session recording] --> I[Harness Interpretation]
I -. Muse policy .-> M[Muse retained completion]
I -. OpenCode policy .-> O[OpenCode retained completion]
S -. Model progress rules .-> M
S -. Model progress rules .-> O
classDef leak stroke:#dc2626,stroke-width:2px;
class S,I leak
After
flowchart LR
S[Session recording] -->|Completion report| I[Harness Interpretation]
subgraph H[Harness adapters]
M[Muse retained completion]
O[OpenCode retained completion]
end
I -->|Internal completion seam| M
I -->|Internal completion seam| O
classDef deep stroke-width:3px;
class H,I deep
Problem: Retained completion policy leaks across the Harness seam into generic Interpretation and Session recording, spreading one Session log implementation across three modules.
Solution: Deepen Harness interpretation by placing retained authority and completion progress behind its existing interface, with each adapter owning its retained implementation.
Wins
- Locality: retained policy stays together
- Leverage: recording consumes one report
- Interface stays the test surface
- Two adapters justify the seam
Deletion test: Removing the shallow Harness selections concentrates complexity in retained adapters instead of moving it to callers; depth comes from absorbing those caller rules behind the existing interface.
Selection: Highest-ranked uncovered Strong candidate: concrete leakage, two real adapters, existing behavior tests, and a whole design settled from code and domain docs. No open issue proposes this deepening; completed #630 and #640 address adjacent recording and live-evidence work. No ADR conflicts.
Activity