# Runtime Objects — Interstitial Contextual Messaging (P1-07, #30) ## Summary Runtime objects are the observable plan/action/result state of a Rune turn, carried as typed, stable-id data on the operator's response envelope and projected into the TUI's **work pane**. They are the same events the chat log already narrates; the work pane is the operational index, the log remains the narrative record (**two-view principle**). No chain-of-thought ever rides a runtime object: only what was actually admitted, run, observed, verified, or concluded. ## Object set (`src/rune/tool_protocol.py`) All objects are frozen dataclasses with `to_dict()` / `from_dict()` round-trips and ISO-UTC `ts`. The pre-existing `ToolRequest` / `ToolEvent` got the same round-trip surface and are part of the set. | Object | id field | Meaning | | --- | --- | --- | | `MemoryQuery` | `query_id` | One context-broker memory-selection pass: `admitted` (`{block_name: tokens}`), `dropped` (`[{name, tokens}]`), `memory_tokens`. | | `Observation` | `observation_id` | Observable runtime event: `kind` (`tool_result` / `approval` / `compaction` / `degraded` / `note`), one-line `summary`, bounded `detail` (<=300 chars). | | `VerificationResult` | `verification_id` | Objective verification of a task outcome: `method` (`exit_code` / `test` / `diff` / `manual` / `none`), `passed`, bounded `evidence`. Never self-report. | | `Outcome` | `outcome_id` | Final classified task outcome: `status` (`completed` / `failed` / `superseded` / `cancelled`), `verification_id` link ("" when none), `degraded`. | ## Emission points (`src/rune/rune_operator.py`) Inside `_execute_on_model`'s tier loop, on the final response path (before `_finalize_runtime_response`): 1. **MemoryQuery** — one per broker `assemble`, built from `_last_trace` (admitted blocks → `{name: tokens}`, non-admitted blocks → dropped). 2. **Observations** — one per broker compaction event (`kind=compaction`, summary carries the `tokens_before -> tokens_after` delta) and one per degraded subsystem name (`kind=degraded`, summary `subsystem unavailable: `). 3. **VerificationResult + Outcome** — emitted when the turn finishes without a pending approval. Method rule: `exit_code` when a `run_command` tool event completed successfully, `test` when `run_tests` completed, otherwise no VerificationResult is emitted at all (`method=none` is never claimed). `passed` = final response success AND no failed tool event. The Outcome's status is back-filled from the final task transition in `send_task` (`completed` / `failed`), and the verification link is set iff the verification passed **and** the task completed. Emission is degrade-not-crash: a failure to build runtime objects records a `runtime_objects` subsystem failure (tier 2) and never fails the turn. The objects flow to the TUI as dicts via the additive `runtime_objects` field on `OperatorResponse` (`_response_envelope` uses `asdict`, so the key survives automatically; default `[]` keeps pre-broker failure paths clean). ## Work pane (`src/rune/rune_tui.py`) `WorkPane(Vertical)` is the third column in `#channels` (`id="work-pane"`, collapsible via Ctrl+3). CSS: `.work-pane { width: 1fr; border-left: solid $secondary; }`. - **Data methods are headless-testable**: `add_object(obj)` / `update_object(obj)` (in-place by id, no duplicates) / `object_count()`; `render()` builds the display. Tests exercise the unmounted instance. - Sections render newest-first: Outcomes, Verification, Observations, Memory queries, Tool calls. Each line: kind glyph + stable id + one-line summary (+ bounded detail). - Tool calls keep their existing `ToolCallWidget` in the chat log AND get a one-line mirror in the pane (the pane is the operational index; the log keeps the interaction). - Visibility policy: hidden on the chat channel, visible on task; Ctrl+3 toggles the expansion. `_consume_runtime_objects` feeds the pane from every response envelope (including approval resumes), degrade-not-crash. ## #33 handoff `Outcome` is the OutcomeLedger's future record shape. This stage ships the typed object and its rendering only; ledger wiring (persisting outcomes) is the #33 dependency that adopts this shape. `VerificationResult` is the Verifier strategy's typed claim; the verifier itself is also #33 — until then the operator derives it from observable tool results (never self-report).