Files
rune/docs/runtime-objects.md

79 lines
4.4 KiB
Markdown

# 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: <name>`).
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).