Verdict-Review Surface / Interactive TUI (Phase 4)
Status: spec. Created 2026-06-22 from docs/BUILD-PLAN.md Phase 4.
Truss’s moat is “review proofs, not transcripts.” That moat is only realized if a
human can actually look at the proofs and act on them quickly. Phases 1–3 built the
signed evidence (durable journal, N-reviewer panel, verdict bundles, diff-aware
review, governed memory + verified playbooks) and the read surface for it
(LedgerReader + truss ledger list|show|get|verdict|export|recall with stable
--json). Phase 4 builds the human-facing review and sign-off surface on top of
that read API.
North-star “done when”
Matt can approve or reject a real Truss task from the verdict view — seeing the definition-of-done clauses, the independent evidence, the reviewer panel result, the diff, and the ledger chain/head status — without reading the full transcript, and his decision becomes part of the signed chain.
Design decisions
-
In-repo interactive TUI first, external front-ends via the JSON seam. We build a
ratatui/crosstermTUI insidetruss-clias the first concrete surface because it is self-contained, testable, and hits the “done when” directly. The external ClawTerm/Warp front end consumes the same stable--jsonread surface (already shipped) plus the same core write primitives — we are not building a bespoke protocol. The TUI is a presentation/controller overLedgerReaderandStore; it never becomes the provenance substrate. -
Provenance discipline (the load-bearing rule). Provenance-capturing = core. Stream-consuming = plugin/CLI.
- The human decision (approve / reject / needs-changes) is provenance → it lives in
core as a new signed journal entry (
human_review) on the same hash chain, verified byverify_chain. - The screens, tabs, scroll position, note input, and layout are presentation → they live in the CLI/TUI and are never written to the ledger.
- The human decision (approve / reject / needs-changes) is provenance → it lives in
core as a new signed journal entry (
-
Human sign-off attests to a head hash. A
human_reviewentry records the decision, an optional note, the reviewer’s signing key id, and the session head hash it is attesting to at decision time. If later entries change the head, the sign-off is still cryptographically pinned to exactly the state the human reviewed — you can prove what was approved, and detect approve-then-mutate. -
No fake authority. A
human_reviewdecision is recorded and signed, but it does not silently overwrite the machineVerdict. The verdict bundle shows both: the independent machine verdict (panel + checks) and the human sign-off. They are distinct trust signals; the UI presents them side by side. (Default-to-fail is unchanged: absence of a human approval is not an approval.) -
TUI state is not durable. Underlying runs are durable (journal authoritative); the review window is not. Don’t engineer UI state into the ledger.
Milestones (one PR + one ADR section each)
VR-1 — signed human-review primitive (core + non-interactive CLI). FOUNDATION.
- New journal entry kind
human_review { decision: Approved|Rejected|NeedsChanges, note: Option<String>, attested_head_hash: String, reviewer_key_id: String }, signed and chained like every other entry;verify_chaincovers it (incl. tamper tests). - Non-interactive CLI first (scriptable, testable without a terminal):
truss review approve|reject|needs-changes <session> [--note ...] [--json]. LedgerReadergains read access to human-review entries; verdict bundle +truss ledger verdictrender the human sign-off alongside the machine verdict.- Honest boundary: this is the trust primitive; no TUI yet. ADR 0034.
VR-2 — read-only interactive TUI (truss review / truss tui).
ratatui+crossterm, feature-gated (tui) so headless/CI builds stay lean.- Screens, all backed by
LedgerReader: (1) list of recent/active contracts with machine verdict + human-review status; (2) verdict bundle detail — DoD clauses, clause evidence, self-validation evidence, reviewer panel majority + per-reviewer verdicts, diff summary, budget; (3) ledger chain view with head hash + verify status; (4) transcript drill-down (not the default view). - Pure consumer; no writes. Hermetic render tests over a fixture DB (ratatui
TestBackend).
VR-3 — actions in the TUI.
- Wire approve / reject / needs-changes keybindings (
a/r/n) to the VR-1 signed primitive. - Add confirmation + note capture; the note is persisted only as the core
human_review.notepayload. - Add suspended-run signal control (
s) by routing throughStore::add_signal, plus a resume command control (x) that points back to the existing durable runner (truss --resume <session> --db <db>). The TUI does not duplicate provider/tool setup or create a second resume engine. - Everything routes through core (
Store); no UI-side provenance.
VR-4 — approval gates. SHIPPED.
- High-risk tool calls or spend over a configurable threshold suspend the durable
run pending a human
human_reviewdecision (reuses the suspend/signal substrate). - Configurable (Directive 1): gate policy global→agent→contract; default off.
- Honest no: don’t gate everything; gate is opt-in and policy-driven.
- Release/block semantics (ADR 0037): approved
human_reviewentries release the pending gate by queueing the existing approval-gate signal; rejected and needs-changes entries stay signed in the chain but keep the run suspended. A raw signal without the signed approval does not release the gate.
Lens (per BUILD-PLAN discipline)
- Verification / crypto: human decision is a signed, chained, head-pinned entry (yes for the decision; the TUI rendering itself is not provenance).
- Pause / resume: underlying runs are durable; VR-3 can deliver pending signals and
points to the existing resume command; VR-4 gates ride the existing suspend/signal
substrate; UI window state is presentation, not durable. Approval gates are
signed
suspendedledger entries waiting on an approval signal that only an approvedhuman_reviewdecision can release. - Honest no: the TUI does not replace the machine verdict, does not invent a
protocol (reuses
--json), and does not store layout/scroll in the ledger.
Reuse map (what already exists — do not rebuild)
truss_core::ledger::LedgerReaderand its view structs (verdict bundle, evidence, panel result, verify report, export bundle).truss ledger list|show|get|verdict|export|recall+ stable--json.identity::Signer(sign the human-review entry),Store/verify_chain(chain it), suspend/signal substrate (VR-3/VR-4),docs/ux-presentation-principles.md(proof-legibility principles to carry into the screens).approval::ApprovalGatePolicymirrors the existing layered-config pattern: global defaults, per-agent overrides, then per-contract overrides.