Skip to content

feat(2.5.H): reasoning rendering, live-turn feedback & actionable error taxonomy (EA6)#67

Merged
cemililik merged 14 commits into
developmentfrom
feat/2.5.h-reasoning-render
Jul 7, 2026
Merged

feat(2.5.H): reasoning rendering, live-turn feedback & actionable error taxonomy (EA6)#67
cemililik merged 14 commits into
developmentfrom
feat/2.5.h-reasoning-render

Conversation

@cemililik

Copy link
Copy Markdown
Contributor

Phase 2.5.H — Reasoning rendering, live-turn feedback & actionable error taxonomy

The additive 2.5.H lane. Makes the reasoning the @relavium/llm seam already carries (ADR-0030) visible in the chat TUI, gives every in-flight turn live latency + honest truncation + failover attribution, and turns each failed-turn ErrorCode into an actionable, session-survives recovery hint. The @relavium/llm seam is not modified; the engine change is one additive event.

Behind EA6 — a new dual-envelope agent:reasoning stream event that amends ADR-0036 (the event substrate) via an append-only note. No new top-level ADR (pre-authorized by the roadmap 2.5.H section + the EA appendix).

Base: development (= the pre-2.5.H tip 20027fc), so this PR is exactly the 14 2.5.H commits.

Delivered (4 steps, each with an opus → Sonnet review round)

Step 1 — agent:reasoning (EA6) · @relavium/shared + @relavium/core + docs
A dual-envelope stream event (the reasoning counterpart of agent:token), emitted by the correlation-agnostic turn core per reasoning_delta chunk — pure host-emit. Added to the shared union + RUN_EVENT_TYPES (22→23) + the drift-pin; carried on both the run path (engine #nodeEmit, now made compile-exhaustive) and the session sink; never the ephemeral same-provider signature (ADR-0030). Amends ADR-0036 + updates sse-event-schema.md.

Step 2a — Live-turn feedback + elision + attribution · apps/cli (host-only)

  • Thinking… / Working… {elapsed}s · Esc to stop — a whole-second formatElapsed timer so a running turn is never a frozen spinner (works standalone and in the Home).
  • A visible elision marker when a bounded live buffer's head scrolls out — fixing the pre-existing silent head-drop, baked into the finalized transcript entry too (so scrollback shows it).
  • Per-attempt model attribution (via {model}) on a within-turn failover, from the accurate cost:updated.model.

Step 2b — Collapsible "thinking" panel · apps/cli
Reduces agent:reasoning into a per-turn buffer; a collapsible panel (default collapsed), toggled by /thinking and Ctrl+T (both surfaces, works mid-turn). The pre-token label reads "Thinking…" only while the model is plausibly reasoning (not while a tool executes).

Step 3 — Actionable error taxonomy · apps/cli
A static, secret-free per-ErrorCode recovery hint that makes "the session is still active" explicit — provider rate-limit / unavailability (retried + failover), provider_auth (check the key / unlock the keychain), a context-overflow message heuristic/compact·/trim, tool_failed (incl. an unreachable MCP server), budget / turn-cap / content-filter / internal. Rendered on the TUI (yellow, under the summary) + the plain chat driver; suppressed on the one-shot agent run (its session ends immediately); --json unchanged.

Design decisions (confirmed up front)

  • Reasoning toggle: /thinking slash + a Ctrl+T keybind (both surfaces).
  • Context-overflow detection: a message keyword heuristic (the roadmap's "secondary net"; 2.5.F auto-compaction is primary) — context/token-qualified markers, no bare "exceeds the maximum" / "token limit" (which a param-400 would false-match).
  • --json: agent:reasoning is part of the session stream (dual-envelope, like agent:token); consumers filter on type.

Security posture

  • The ephemeral signature (ADR-0030) never reaches the event, a log, or the transcript (traced end-to-end).
  • The error-hint provider message is read for the heuristic but never echoed — every hint is a static host string (tested with a secret-ish substring on both surfaces).
  • All model-produced text (reasoning body, tokens, model id) goes through the existing terminal sanitizers.
  • The @relavium/llm seam holds; packages/core stays platform-free; no new dependency.

Review cadence & fixes

Every step went through an aggressive, multi-dimensional opus review → fix → Sonnet review → fix. ~15 verified findings fixed, including:

  • HIGH (Step 1): the new event was silently dropped on the run path (#nodeEmit had no case) — fixed + an exhaustiveness guard so the next in-node event can't silently drop.
  • HIGH (Step 2a): the Home live-timer was frozen at 0s (a nowMs captured at the wrong component boundary) — the clock is now read per-frame in ChatRegion.
  • HIGH (Step 2a): the elision marker vanished once a turn landed in <Static> scrollback — now baked into the finalized entry.
  • HIGH (Step 3): the recovery hints leaked into the one-shot agent run plain output (where "session is still active" / /compact are false) — gated + suppressed.
  • HIGH (Step 3): an Opus-fix over-reach on tool_unavailable (an over-promised resend) — reverted to the no-blind-retry standard.
  • Plus hint-accuracy corrections (tool_failed retry claim, turn_limit dual-producer, internal correlation-id), a heuristic false-negative/false-positive tightening, and a drift-guard test derived from ERROR_CODES.

Deferred (tracked in deferred-tasks.md, none blocking)

  • A CLI render-layer (ink component) test harness — the React prop-plumbing / render-cadence layer is currently untestable by design (pure-logic testing); the Home-timer fix is verified by tracing + the type-shape, not a regression test.
  • Bound the expanded reasoning panel by rendered lines (not just chars).
  • Allow Ctrl+T / /thinking during a pending approval (deliberately fail-closed for now — the approval floor is security-sensitive).

CI / tests

pnpm turbo run lint typecheck test build24/24 tasks green; lint:fence-check, lint:engine-deps, format:check clean. New tests across @relavium/shared, @relavium/core, @relavium/db, and apps/cli (view-model, store, projection, key reducer, command registry, plain printer, agent-run).

Known pre-existing flake (NOT introduced here): apps/cli/src/engine/media-gc.test.ts ("sweeps a row-less CAS orphan") is non-deterministic and fails intermittently — it touches no file in this PR (media CAS, not events). Verified it fails 3/3 on the pre-2.5.H base commit 1598798. Worth a separate fix.

🤖 Generated with Claude Code

cemililik and others added 14 commits July 7, 2026 13:36
Add the reasoning ("thinking") counterpart of `agent:token`: a dual-envelope
`agent:reasoning` stream event the correlation-agnostic agent turn core emits
per `reasoning_delta` chunk. Pure host-emit — the @relavium/llm seam already
carries the reasoning chunks (ADR-0030); the turn core previously only
ACCUMULATED reasoning deltas with no event of their own. The seam and the
engine architecture are unchanged.

- @relavium/shared: AgentReasoningEventSchema + type, added to the RunEvent
  union, RUN_EVENT_TYPES (22→23), and the dualBase family; drift-pin matrix +
  dual-envelope test extended.
- @relavium/core: 'agent:reasoning' in InNodeEventType; foldReasoningChunk emits
  it (mirrors the agent:token emit) carrying text + active model, never the
  ephemeral same-provider signature (ADR-0030); the session sink carries it
  (not run-only, unlike agent:file_patch_proposed). Engine + sink tests.
- docs: sse-event-schema.md row + Selected-definition + session-stream notes;
  ADR-0036 append-only amendment note (EA6 amends the event substrate; no new
  top-level ADR — an additive event in the shared union).

Toolchain: lint + typecheck + test + build green (24 tasks); format:check clean;
seam-hold clean.

Refs: ADR-0036, phase-2.5-cli-consolidation.md (2.5.H, EA6)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ore throttle

Fix the review-caught gaps in the agent:reasoning (EA6) landing:

- BLOCKER: the engine's #nodeEmit run-path translation point switched on
  event.type with no default, so agent:reasoning (added to InNodeEventType) fell
  through and was SILENTLY DROPPED on the workflow-run path — the dual-envelope
  contract was only half-delivered (the session path emitted it, a run did not).
  Add the pass-through case AND an exhaustiveness guard (`const exhaustive: never`)
  so a future in-node event is a compile error here, never another silent drop.
  New engine.test.ts regression asserts it reaches the bus with runId.
- MEDIUM: agent:reasoning was missing from HIGH_FREQUENCY_EVENTS in chat-store +
  run-store, so each reasoning delta flushed an immediate repaint (a live thrash on
  the session path now — reasoning models emit many thinking tokens). Coalesce it
  like agent:token.
- LOW: add it to the db STREAMING_EVENT_TYPES firehose set (defensive; never
  persisted); broaden the agent-turn.ts model-attribution NOTE (both mid-stream
  events share the pre-content-failover edge) + the deferred-task entry; fix the
  stale "four dual events" enumerations (agent-session.ts, node-executor.ts,
  agent-runner.md).
- Tests: run-path bus assertion (would have caught the BLOCKER) + a redacted-block
  zero-emit test.

Toolchain: lint + typecheck + test + build green (media-gc flake passed on retry);
format:check clean.

Refs: ADR-0036, phase-2.5-cli-consolidation.md (2.5.H, EA6)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…+ doc consistency

Close the review-caught gaps (0 blocker/high; 2 medium + 1 low):

- MEDIUM: sse-event-schema.md had a self-contradictory paragraph — its first
  sentence listed the reused in-turn events WITHOUT agent:reasoning while a later
  sentence in the same paragraph included it. Add it to the first list so the
  canonical home is internally consistent.
- MEDIUM: agent:reasoning was the one HIGH_FREQUENCY_EVENTS member with no
  coalescing regression test in either store. Add a chat-store test (mirrors the
  cost:updated test) + extend the run-store family test — so dropping it from
  either set fails a test (the untested-drift class the BLOCKER post-mortem flags).
- LOW: run-history-store.test.ts claimed "ALL THREE excluded streaming types" but
  the set now has four; persist + assert the 4th (agent:reasoning) so the
  "fails on drift/misspelling" guarantee holds for it too.

Toolchain: shared/core/db/cli green (media-gc CAS-orphan flake confirmed
pre-existing + unrelated — non-deterministic across repeated isolated runs, touches
no event code); format:check clean.

Refs: ADR-0036, phase-2.5-cli-consolidation.md (2.5.H, EA6)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
… attribution

Additive `relavium chat` UX (host-only, no engine change):

- Live-turn timer: before the first token streams, the busy line shows
  `⠋ Working… {elapsed} · Esc to stop` (whole-second `formatElapsed`, floored so it
  doesn't jitter per frame) — a running turn never reads as a frozen bare spinner.
  `nowMs` is threaded to `ChatView` from both `ChatApp` (Date.now()) and the Home.
- Elision marker: the live token buffer already sliced its head at
  MAX_LIVE_TOKEN_CHARS but dropped it SILENTLY; now the view-model tracks
  `liveTokensTruncated` (reset with the buffer) and the render shows a leading `…`,
  so the scroll-out is visible. `appendBounded` reports the elision (reused by Step
  2b for reasoning).
- Per-attempt model attribution: the completed-turn summary shows `via {model}` when
  the committed model (from the accurate per-attempt `cost:updated.model`, EA2)
  differs from the bound model — a within-turn failover — and is omitted otherwise
  (the footer already shows the bound model), so a plain turn is unchanged.

Tests: view-model truncation-flag + reset + failover-attribution; formatElapsed;
formatTurnSummary `via {model}` + sanitization. lint/typecheck/test/build green;
format:check clean.

Refs: phase-2.5-cli-consolidation.md (2.5.H)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…-line tests

Fix the review-caught HIGH + close the coverage gap:

- HIGH: the live-turn timer was frozen at 0s in the bare-Home in-process chat.
  `nowMs` was computed once per RootApp render (which only re-renders on controller
  state changes), then handed to the per-frame ChatRegion as a frozen number — so
  during the pre-first-token wait the elapsed stuck at 0s (worse than no timer).
  Thread the clock as a FUNCTION into ChatRegion (which re-renders every frame while
  a turn streams, via its own store subscription) and read it there. Standalone
  `relavium chat` was already correct (ChatApp reads Date.now() in its own render).
- MEDIUM: the busy-line branch matrix was inline JSX with zero test coverage.
  Extract a pure `formatBusyLine({...}) → { text, dim }` into chat-projection.ts and
  unit-test every branch (compaction / shell / pre-token Working…+elapsed / streaming
  content + elision adjacency / sanitization). The render now only maps `dim` → <Text>.
- LOW: guard formatElapsed against a non-finite input (symmetry with spinnerFrame);
  document the last-cost:updated "committed model" engine-ordering dependency + add a
  multi-attempt attribution test (cost A → cost B → `via B`).

Deferred to 2b (holistic busy-region redesign for the reasoning panel): keeping a
compact abort hint visible during token streaming.

Toolchain: lint/typecheck/test/build green (media-gc CAS-orphan flake CONFIRMED
pre-existing — fails 3/3 on the pre-2.5.H base commit, touches no file in my diff);
format:check clean.

Refs: phase-2.5-cli-consolidation.md (2.5.H)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…+ test gaps

Close the review-caught HIGH + the smaller gaps:

- HIGH: the elision marker vanished the instant a turn completed. reduceTurnCompleted
  built the transcript entry from raw liveTokens (no `…`), and the live busy-line
  marker (formatBusyLine, in-flight only) never applied to it — so once the turn
  landed in ink <Static> (the terminal's PERMANENT scrollback) it rendered verbatim,
  reverting to the silent head-loss the feature exists to surface. Bake `…` into the
  FINALIZED display text when the final segment truncated (guarded on the RAW text so
  no spurious empty entry), fully reducer-testable. The DURABLE record (persister →
  resume/export) is untouched + full — only the bounded live echo is short.
- MEDIUM: formatElapsed's non-finite guard shipped untested — add NaN/Infinity → "0s".
- LOW: pin formatBusyLine's compaction-over-shell priority.
- MEDIUM (tracked, not silently deferred): the Home live-timer fix has no regression
  test — the CLI has no ink component-render harness by design (pure-logic testing).
  Filed as a deferred task (a render-layer harness is a first-of-its-kind devDep/ADR
  decision, out of 2.5.H scope) alongside the streaming-abort-hint follow-up.

Toolchain: lint/typecheck/test/build green (1560 CLI tests; media-gc CAS-orphan flake
pre-existing — fails 3/3 on the pre-2.5.H base commit); format:check clean.

Refs: phase-2.5-cli-consolidation.md (2.5.H), deferred-tasks.md

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…nking + Ctrl+T)

Render the streamed reasoning (agent:reasoning, EA6) in the chat TUI:

- View-model: fold agent:reasoning into a bounded `liveReasoning` buffer (+ its
  `liveReasoningTruncated` elision flag). Unlike liveTokens it is reset only per
  TURN (started/completed/cancelled), NOT per tool call, so the panel accumulates
  the whole turn's thinking across tool rounds.
- A collapsible "thinking" panel (pure `formatReasoningPanel`) — default COLLAPSED
  (a dim `✻ Reasoning · Ctrl+T show` header); expanded shows the sanitized reasoning
  body (newline-preserving) with a leading `…` elision marker. The busy line labels
  the pre-token phase "Thinking…" (vs "Working…") when reasoning is streaming.
- Toggle both ways (the maintainer's choice): a chat-only `/thinking` slash command
  (a new `toggleReasoning` ReplCommandContext capability, wired in chat.ts's replCtx,
  inert in the bare-Home ctx) + a `Ctrl+T` keybind (a new `toggle-reasoning`
  ChatKeyAction, decided before the running-swallow so it works mid-turn). Both flip
  the store's new `reasoningVisible` flag; wired in BOTH surfaces (chat + Home).
- Home parity: ChatRegion threads reasoningVisible; the controller routes Ctrl+T to
  the store toggle.

Docs: commands.md + chat-session.md (the `/thinking` command, the Ctrl+T keymap row,
and a "Reasoning & live-turn feedback" section). Tests: reasoning fold + per-turn
reset + cross-tool accumulation; store toggle; formatReasoningPanel + the Thinking…
label; the Ctrl+T key action; the Home integration; the /thinking→toggleReasoning
dispatch. lint/typecheck/test/build green (media-gc flake pre-existing); format clean.

Refs: phase-2.5-cli-consolidation.md (2.5.H, EA6)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Address the review-caught polish (all LOW; Opus verdict was "ship it"):

- The pre-token busy line read "Thinking… {elapsed}" even while a tool was
  executing (reasoning is turn-scoped and liveTokens resets on a tool call, so the
  empty-tokens gap during a tool round showed the thinking label). Now the label is
  "Thinking…" only when reasoning has streamed AND no tool call is unresolved — during
  a tool round it falls back to "Working…", so the timer never claims the model is
  thinking while a tool runs.
- Tests: a sticky-truncation-across-deltas test for liveReasoning; a `/thinking`
  end-to-end dispatch test (through the real chat command → replCtx.toggleReasoning →
  the shown/hidden notice) closing the one untested wiring link.
- Deferred (tracked, not silently): bound the expanded reasoning panel by rendered
  LINES not chars (live-region flicker on a short terminal); allow Ctrl+T/`/thinking`
  during a pending approval (deliberately left fail-closed — the approval floor is
  security-sensitive, ADR-0057).

Toolchain: lint/typecheck/test/build green (media-gc CAS-orphan flake pre-existing);
format:check clean.

Refs: phase-2.5-cli-consolidation.md (2.5.H), deferred-tasks.md

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…reasoningLabelActive

Close the two MEDIUMs (same root) + the doc LOW (Sonnet verdict: 0 blocker/high):

- The Opus-fix's "Thinking… only when no tool is executing" derivation lived inline
  in ChatView (untestable without an ink harness) and left formatBusyLine's
  `hasReasoning` param doc describing the PRE-fix semantics (the caller now passes the
  narrower tool-gated value). Extract a pure, exported `reasoningLabelActive(hasReasoning,
  liveToolCalls)` in chat-projection.ts, unit-tested with the resolved/unresolved/mixed/
  empty/no-reasoning cases; rename formatBusyLine's param to `reasoningActive` with an
  accurate doc. The inline glue is now a one-line call to the tested helper.
- Documented the LOW bound-interaction note (liveToolCalls is capped) on the helper.
- Docs: chat-session.md now notes the "Working…" fallback also applies while a tool
  call is unresolved (not only when there is no reasoning).

Left as-is (Sonnet LOW, deliberate/acceptable): the turn-sticky "Thinking…" heuristic
in the resolved-tool→compose gap (a reasonable approximation, not a defect); the
approval-gated toggle + line-bounded panel remain tracked in deferred-tasks.

Toolchain: lint/typecheck/test/build green (1577 CLI tests, no flake this run);
format:check clean.

Refs: phase-2.5-cli-consolidation.md (2.5.H)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…rvives)

A failed turn is never a terminal (only session:cancelled ends a session), so a
failure always leaves the REPL live. Beyond the closed ErrorCode, the chat now
renders a one-line, secret-free recovery hint for each operational class that names
the next step + makes "the session is still active" explicit — extending the "say so
plainly" philosophy from the 2.5.A capability gap to the transport/quota/limit
classes:

- provider_rate_limit / provider_unavailable → retried w/ backoff + failover, resend.
- provider_auth → check the key or UNLOCK the OS keychain (if locked mid-session).
- context-overflow → surfaces as `validation`; a keyword heuristic on the (never-
  displayed) provider message distinguishes it from a shape error and suggests
  /compact·/trim (the maintainer-chosen detection; a SECONDARY net — 2.5.F auto-
  compaction pre-empts most overflows).
- tool_failed (incl. an MCP-server timeout), budget_exceeded, run_timeout,
  turn_limit, content_filter, internal → each an actionable one-liner.

The hint is ALWAYS a static host string — the provider message is read only to pick
the hint (the overflow heuristic), NEVER echoed, so no provider text/secret reaches
the terminal (tested). Rendered on the interactive TUI (a yellow line under the
summary) + the plain non-TTY driver (under `[turn failed: <code>]`); --json stays the
structured stream. `cancelled` (user-initiated) / `sandbox_error` (not chat-reachable)
get no hint.

Docs: chat-session.md "Actionable error recovery" section. Tests: errorRecoveryHint
per class + the overflow heuristic + the no-echo security assertion; the plain-printer
hint (+ secret-free). lint/typecheck/test/build green; format + seam clean.

Refs: phase-2.5-cli-consolidation.md (2.5.H)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…+ drift-guard

Address the review-caught accuracy debt (0 HIGH; 4 MEDIUM, all one-line string
edits with real user impact; the no-echo security crux was verified clean):

- tool_failed: the hint over-claimed "retried within budget" (there is NO session-
  level tool retry) and told the user to "try again" — unsafe for the non-recoverable
  (side-effecting) failure that actually reaches a completed turn, and contradicting
  the summary line's own path/target framing. Reframed to complement the summary:
  "fix the path or target (or check the MCP server) and resend" (no blind retry).
- turn_limit: had TWO producers — the per-turn tool-call ceiling AND the session HARD
  round cap (agent-session.ts) — and "send another message" is re-blocked by the
  latter. Now covers both (`/clear` if the hard cap is hit).
- internal: pointed at a "correlation id from the logs" that the session path never
  produces (correlationId is WorkflowEngine-only, ADR-0036). Dropped that clause.
- context-overflow heuristic: added Anthropic's "…exceed context limit" phrasing
  (a real false-negative), and dropped the false-positive-prone bare "exceeds the
  maximum" / "token limit" markers (a param 400 like "temperature exceeds the maximum"
  would mis-suggest /compact). Added a false-positive-boundary test.
- run_timeout: dropped its hint — it is WorkflowEngine-only (a session-path provider
  timeout classifies as provider_unavailable), so it's as unreachable as sandbox_error
  was already excluded (consistent rationale).
- tool_unavailable: added a resend affordance for parity.
- Test drift-guard: derive the taxonomy check from `ERROR_CODES` (partitioned
  hint / no-hint / message-conditional), so a NEW ErrorCode forces a decision.

Docs: chat-session.md tool_failed bullet corrected. lint/typecheck/test/build green
(1582 CLI tests); format clean.

Refs: phase-2.5-cli-consolidation.md (2.5.H)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…l_unavailable

Close the two review-caught HIGHs + the docs/LOW gaps:

- HIGH: the session-continuity recovery hints leaked into `relavium agent run`'s
  PLAIN output — a one-shot that cancels its session in `finally` right after. So
  "the session is still active", `/compact`, resend (a REPL-only affordance) were all
  FALSE there. Gate the hint via `makePlainPrinter(io, recoveryHints = true)`: the
  chat REPL (`drivePlain`) keeps it (session survives); the one-shot `agent run`
  passes `false` → only `[turn failed: <code>]`. A plain-mode agent-run failed-turn
  test + a makePlainPrinter suppression test lock it.
- HIGH: my own step-3-Opus fix over-reached — `tool_unavailable`'s hint became
  "resend and the model will answer without it", an unconditional promise that
  re-fails identically (the capability arm isn't wired for the whole session; it's
  not a `/mode` toggle). Softened to the same no-blind-retry standard the sibling
  tool_failed fix set (rephrase to avoid it, or wire it + fresh session).
- MEDIUM/LOW: docs now enumerate tool_denied/tool_unavailable + the one-shot
  suppression; reorder tool_failed so "session is still active" isn't leading (parity
  with its 8 siblings); drop the dead `context_length` underscore marker (the
  heuristic reads the message, not the code); tighten the `cancelled` rationale (it's
  structurally unreachable — settles as `aborted` with no error); make `internal`'s
  tail concrete (`/doctor`, not a dangling "report it"); add a no-hint plain-printer
  test.

Toolchain: lint/typecheck/test/build green (1585 CLI tests); format clean.

Refs: phase-2.5-cli-consolidation.md (2.5.H)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…5-3 reached

Reconcile the canonical status surfaces now that 2.5.H (reasoning rendering +
live-turn feedback + the actionable error taxonomy, behind EA6 amending ADR-0036)
has landed across four opus+Sonnet-reviewed steps:

- phase-2.5-cli-consolidation.md: a ✅-Done status block on the 2.5.H workstream, the
  top-of-file status line, the milestone table (M2.5-3 reached with 2.5.E), and the
  EA6 "Required ADRs" note (landed).
- current.md + CLAUDE.md: the additive-lane mention updated to 2.5.H ✅ Done (detail
  in current.md per the one-canonical-home rule); the stale "2.5.H / I / J" triple is
  gone (2.5.I / J remain).

(The reference homes — sse-event-schema.md, chat-session.md, commands.md, ADR-0036's
append-only note, deferred-tasks.md — were updated in their own step commits.)

format:check + lint:fence-check clean.

Refs: phase-2.5-cli-consolidation.md (2.5.H, EA6), ADR-0036

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
… optional param

The full-repo lint gate flagged `message?: string | undefined` (the `?` already
implies `undefined`) — @typescript-eslint/no-duplicate-type-constituents. Simplify to
`message?: string`; behaviorally identical (a function-parameter optional, not an
exactOptionalPropertyTypes object property). lint/typecheck/test/build all green.

Refs: phase-2.5-cli-consolidation.md (2.5.H)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry @cemililik, your pull request is larger than the review limit of 150000 diff characters

@coderabbitai

coderabbitai Bot commented Jul 7, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: c4aef9a8-8860-4092-ac08-0462e7122105

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/2.5.h-reasoning-render

Comment @coderabbitai help to get the list of available commands.

@sonarqubecloud

sonarqubecloud Bot commented Jul 7, 2026

Copy link
Copy Markdown

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request implements Phase 2.5.H, introducing the agent:reasoning dual-envelope stream event to support live rendering of model reasoning. Key changes include a collapsible 'thinking' panel in the TUI (toggled via /thinking or Ctrl+T), live-turn feedback with an elapsed timer, visible elision markers for truncated buffers, and per-attempt model attribution for within-turn failovers. Additionally, it adds an actionable, secret-free error recovery hint system for failed turns (e.g., suggesting /compact or /trim on context overflows). I have no feedback to provide as there are no review comments.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

@cemililik
cemililik merged commit 9c62ae9 into development Jul 7, 2026
6 checks passed
cemililik added a commit that referenced this pull request Jul 7, 2026
2.5.H landed on main (PR #68, development→main). Add the workstream PR reference
(#67 — the 2.5.H feature PR to development, matching how 2.5.A–G cite their feature
PR; #68 is the dev→main release mechanism, like #66) to the 2.5.H status surfaces:
phase-2.5-cli-consolidation.md (top status + the 2.5.H block header + Status line),
current.md, and CLAUDE.md. Date-only; no other change.

format:check + lint:fence-check clean.

Refs: phase-2.5-cli-consolidation.md (2.5.H)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant