Skip to content

fix(tracing): trace waterfall + summary prompt + chat tab all lose data after each agent turn#895

Merged
anandgupta42 merged 12 commits into
mainfrom
fix/trace-clearing-on-workspace-set
Jun 6, 2026
Merged

fix(tracing): trace waterfall + summary prompt + chat tab all lose data after each agent turn#895
anandgupta42 merged 12 commits into
mainfrom
fix/trace-clearing-on-workspace-set

Conversation

@sahrizvi
Copy link
Copy Markdown
Contributor

@sahrizvi sahrizvi commented Jun 5, 2026

Closes #896.

Follow-up to #867. Fixes the trace lifecycle and rendering bugs that survived #867's concurrency hardening because they live at a different layer of the system.

What this fixes

# Bug Fix
1 session.status === "idle" handler in worker.ts called endTrace + sessionTraces.delete after every turn. idle is a per-turn busy→idle transition, not session-end. Next event hit a cache miss, Trace.create() + startTrace snapshotted an empty 1-span file, clobbering the rich on-disk trace. Handler removed. Trace lives as long as the worker has the session in sessionTraces. Finalization on shutdown + MAX_TRACES eviction only.
2 getOrCreateTrace cache-miss path never rehydrated from disk — worker restart / eviction always overwrote the existing trace. New Trace.rehydrateFromFile(sessionId) restores spans / metadata / counters / clears root endTime. getOrCreateTrace prefers it before falling back to startTrace.
3 worker.setWorkspace was not idempotent → spurious calls cleared sessionTraces. Track currentWorkspaceID at module scope; early-return on unchanged value.
4 routes/session/index.tsx workspaceID effect re-ran on every session() signal change. createEffect(on(() => session()?.workspaceID, ...)) so SolidJS dirty-tracks only workspaceID.
5 Prompt never captured. Three event handlers in worker.ts could feed metadata.prompt: (a) the user-role message.updated handler only fired if info.summary.title || info.summary.body was populated, which doesn't happen on the first turn; (b) the text-part branch of message.part.updated gated on part.time?.end, which user-input parts never have set; (c) the session.updated handler called setTitle(info.title) with one argument only, never touching prompt. Codex review caught a second risk: dropping the time.end gate while keeping setTitle(text, text) would regress the auto-generated session title to raw user input, because setTitle(t, p) mutates both fields. New Trace.setPrompt(prompt) that only mutates metadata.prompt. The user-text branch of message.part.updated drops the time.end precondition and calls setPrompt(text) instead of setTitle(text, text).
6 Chat tab could only render metadata.prompt (singular) at the top + assistant generations. Every user message after the first was dropped from the viewer. New Trace.logUserMessage(text) pushes a kind: "user-message" span. The user-text branch of message.part.updated also calls it for each user-identified text. Viewer chat-view rebuilt to interleave user-message and generation spans in startTime order. Backward compatible with traces that lack user-message spans.

Why #867 didn't catch these

PR #867 closed M2 (snapshot-debounce dropping events) and M3 (FileExporter racing flushSync). Both are intra-Trace-instance concurrency — within one Trace object's state machine. The reproducers in tracing-rename-race.test.ts and tracing-display-crash.test.ts all hold one instance for the test's lifetime and exercise crash/burst conditions against that instance.

The bugs in this PR are at three other layers:

  • Cross-instance lifecycle (rows 1–4): when one Trace gets destroyed and a new one is constructed for the same sessionID. The on-disk file clobber happens via the new instance's first snapshot, not from any race within an old one.
  • Worker event-handler layer / data feed (row 5): what gets fed into the Trace from the bus event stream. Orthogonal to persistence correctness.
  • Viewer renderer + data model (row 6): how the viewer's chat tab iterates spans. A correct persistence layer can still ship a 1-span trace if upstream feeds 1 span.

Beyond the layer mismatch, the per-turn idle handler (row 1) was intentional code — the original comment read "Finalize trace when session reaches idle (completed)". It was a semantic misunderstanding of what idle means at the event level (per-turn vs session-end), not a concurrency bug, so #867's reproducer matrix wouldn't have surfaced it. And no existing test exercises the full event-stream-to-trace-file path across multiple busy → idle cycles, so the cross-turn nature was invisible to CI.

Independent of #867's scope

Every bug fixed here predates #867 (the prior trace-corruption PR). Listing
this explicitly so reviewers can see this PR is orthogonal work — not a
follow-up cleaning up regressions #867 introduced.

Bug fixed in this PR Origin Evidence
1. Per-turn session.status === "idle" destroying the Trace (worker.ts) Predates #867 git log -S 'status === "idle"' -- worker.ts → introduced by #183 ("feat: replace Langfuse with local-first tracing system"), the original local-tracing PR. Predates #867 by months.
2. getOrCreateTrace no disk rehydration (worker.ts) Predates #867 Same #183 PR introduced getOrCreateTrace without rehydration. #867 never touched worker.ts.
3. setWorkspace not idempotent (worker.ts) Predates #867 Same as above — #867 never touched worker.ts.
4. SolidJS effect re-firing on every signal change (routes/session/index.tsx) Predates #867 #867 never touched the TSX route at all.
5. Prompt-capture broken (worker.ts) Predates #867 All three relevant event handlers (message.updated user-role branch, message.part.updated text branch, session.updated) live in worker.ts, never touched by #867.
6. User messages not first-class in trace data model (tracing.ts kind union, viewer.ts chat-view) Predates #867 #867 modified tracing.ts but only added M2/M3 concurrency fixes — did NOT change the kind union, did NOT touch viewer.ts (zero changes to the viewer file in the #867 commits).

Tests

  • test/cli/tui/worker-trace-clearing.test.ts — source-grep contract tests: no-idle-clobber, rehydrate-before-startTrace, setPrompt-not-setTitle, Trace.setPrompt purity.
  • test/altimate/tracing-rehydrate.test.ts — behavioral tests for rehydrateFromFile (preserve spans/metadata/counters, reject missing/mismatched/malformed, clear endTime on rehydrate) and logUserMessage (chronological ordering).

47 affected tests pass. Typecheck clean. 35 existing tracing tests (tracing-display-crash, tracing-rename-race) pass unchanged.

Verification on a live build

Built locally as 0.0.0-fix/trace-clearing-on-workspace-set-202606051512. Confirmed against a real multi-turn TUI session that:

  • The trace file now persists across busy → idle transitions (5+ spans, full metadata, real counter values where v0.8.3 produced a 1-span / metadata: {} / null-summary file).
  • After a fresh rebuild with the rendering fix, multi-turn chat tab interleaves each user message with its assistant response in chronological order instead of showing only the last user prompt.

Out of scope

  • Higher-fidelity integration test for cross-turn trace correctness. The source-grep + behavioral tests here lock the contracts but don't drive synthetic session.status idle events through the real worker event loop. Tracked separately as a follow-up.
  • The user-role message.updated handler in worker.ts still calls setTitle(title, title) with summary.title || summary.body. Same setTitle(x, x) shape Codex caught for the user-text branch in this PR; if the title-agent's summary update lands after session.updated, it can overwrite metadata.prompt with the title-agent's text instead of the user's actual input. Smaller surface than the bug fixed here; not addressed in this PR.

🤖 Generated with Claude Code


Summary by cubic

Fixes trace lifecycle bugs that overwrote traces after each turn and preserves trace identity across restarts. Also makes the chat tab show multi-turn conversations, improves prompt capture (skipping synthetic parts), and prevents duplicate top-level prompts for long messages.

  • Bug Fixes

    • Removed per-turn finalize on session.status === "idle"; traces persist across turns and only finalize on shutdown or eviction.
    • Added Trace.rehydrateFromFile(sessionId) and call it before startTrace on cache miss; preserves spans/metadata/counters/traceId, normalizes session ID, clears root endTime, and marks any open generation spans as “interrupted” to keep structure.
    • Made setWorkspace idempotent via currentWorkspaceID; UI effect now uses on(() => session()?.workspaceID, ...) so it fires only on real changes, preventing sessionTraces clearing.
    • Captured prompts via Trace.setPrompt(prompt) and dropped the time.end gate for user text; never call setTitle(text, text) and skip synthetic/ignored text parts so prompts stay accurate.
    • Logged user messages with Trace.logUserMessage(text) and updated the viewer to interleave user-message and generation spans by time; falls back to metadata.prompt when needed and dedupes using the shared USER_MESSAGE_INPUT_MAX_CHARS cap to avoid duplicate long prompts.
  • Refactors

    • Made Trace.rehydrateFromFile async and awaited it in getOrCreateTrace and stream handlers to avoid blocking the event loop on cache misses; tests updated accordingly.
    • Migrated tracing-rehydrate tests to the tmpdir() fixture for consistency.
    • Tightened worker-trace-clearing test regex to be scope-bounded, ensuring the synthetic/ignored gate and setPrompt/logUserMessage checks apply to the correct branch.
    • Removed redundant specs/trace-bugs-followup-867.md to avoid duplicated documentation.

Written for commit 7f71154. Summary will update on new commits.

Review in cubic

Summary by CodeRabbit

  • New Features

    • Multi-turn chat with explicit per-turn user-message tracking and improved session recovery from disk
  • Bug Fixes

    • Deduplicated prompt bubbles in the chat view and preserved in-progress traces across turns (prevents lost/overwritten history)
    • Reduced unnecessary workspace restarts to avoid clearing cached traces
  • Tests

    • Added tests covering session rehydration, user-message recording, and trace-retention behaviors

Haider added 5 commits June 5, 2026 19:56
…-finish

Symptom: opening `/traces` mid-session and watching the waterfall view
during agent execution shows the rich trace populating correctly, but
the moment the agent finishes its turn the view collapses to a single
"system-prompt" span — and the data is genuinely lost on disk, not
just from the viewer.

Chain (verified by reading worker.ts + routes/session/index.tsx + tracing.ts):

  1. `routes/session/index.tsx` has
     `createEffect(() => session()?.workspaceID && sdk.setWorkspace(...))`.
     SolidJS dirty-tracks any signal read inside the effect — so it
     re-runs on EVERY `session()` change (message count, status, parts
     updates), including the cascade at agent-finish.
  2. Each fire calls `worker.setWorkspace` via RPC.
  3. `worker.setWorkspace` unconditionally calls `startEventStream`.
  4. `startEventStream`:
        for (const [, trace] of sessionTraces) {
          void trace.endTrace().catch(() => {})   // fire-and-forget
        }
        sessionTraces.clear()
  5. On the next event for the same session, `getOrCreateTrace` hits a
     cache miss, calls `Trace.create()` + `startTrace(sessionID, {})`,
     which pushes a single root span into a freshly-empty `this.spans`
     and calls `this.snapshot()`. The snapshot path is derived purely
     from sessionID (`tracing.ts:836`), so it overwrites the rich
     `ses_<id>.json` with a 1-span file.

Distinct from #867 — that PR fixed intra-Trace-instance concurrency
(snapshot debounce M2; FileExporter ↔ flushSync race M3). This bug is
at the worker-level cache lifecycle: a new Trace instance gets
constructed and its near-empty initial state clobbers the previous
instance's rich state on disk.

Two minimal fixes lock the contract:

* `worker.ts` — make `setWorkspace` idempotent. Track
  `currentWorkspaceID` at module scope; early-return when the incoming
  value matches. Spurious calls from the UI no longer destroy traces.
* `routes/session/index.tsx` — switch the workspaceID effect to
  `createEffect(on(() => session()?.workspaceID, ...))`. The `on()`
  projector restricts SolidJS dirty-tracking to that one field, so the
  effect only fires when workspaceID actually changes — defense in
  depth at the upstream trigger.

Regression test in `test/cli/tui/worker-trace-clearing.test.ts`
locks both contracts via source-grep (the worker-import side has
top-level side effects that make in-process unit testing awkward).

Out of scope (follow-up): `getOrCreateTrace` on cache miss does not
rehydrate `this.spans` from the existing `ses_<id>.json` file. After
the two fixes above, this matters only on worker restart or
MAX_TRACES=100 eviction — both uncommon. Worth tracking as defense in
depth so the disk file is always authoritative.

Typecheck clean. 152 TUI tests pass; 35 existing tracing tests pass
unchanged.
…e Trace every turn

Previous commit on this branch was correct but not load-bearing. The
actual hot path that collapsed the on-disk trace after every agent
turn is in `worker.ts`:

    if (event.type === "session.status") {
      if (status === "idle" && sid) {
        const trace = sessionTraces.get(sid)
        if (trace) {
          void trace.endTrace().catch(() => {})
          sessionTraces.delete(sid)            // ← every turn
          sessionUserMsgIds.delete(sid)
        }
      }
    }

`session.status === "idle"` fires after every busy→idle transition,
which happens once per turn — not once per session. Each fire ended
the trace AND deleted the cache entry. The next event for the same
session in the next turn hit a cache miss, constructed a fresh
`Trace.create()`, called `startTrace(sessionID, {})` (which pushes a
single root span into empty `this.spans`), and the immediate
`snapshot()` clobbered the rich on-disk `ses_<id>.json` with a 1-span
file.

This also explains the "What was asked / No prompt recorded" symptom:
`metadata.prompt` was captured on the now-destroyed first instance and
never persisted into the replacement.

Fixes in this commit:

* `worker.ts`: removed the destructive `session.status === "idle"`
  handler. Sessions in altimate-code are long-lived; the Trace lives
  as long as the worker has the session in cache. Finalization
  happens on `shutdown` and on MAX_TRACES eviction only — both
  already correct.

* `tracing.ts`: new `Trace.rehydrateFromFile(sessionId)` that reads
  the existing on-disk file and restores `this.spans`, `this.metadata`,
  `this.rootSpanId`, `this.startTime`, counters, and clears the root's
  endTime so the trace renders as still-in-progress. Returns true on
  success; false on missing/mismatched/malformed file.

* `worker.ts:getOrCreateTrace`: on cache miss, calls
  `rehydrateFromFile` before falling back to `startTrace`. Defense in
  depth for the worker-restart / MAX_TRACES-eviction paths — even if
  some future path destroys the in-memory instance, the new instance
  loads disk state instead of overwriting.

Verification

* Behavioral test (`test/altimate/tracing-rehydrate.test.ts`, 4 cases):
  proves end-to-end that rehydrate preserves spans+metadata across
  Trace-instance reconstruction, returns false on missing/mismatched
  files, and clears the root endTime so re-opened traces accept new
  events.
* Source-grep regression tests for worker.ts continue to lock the
  no-idle-clobber and rehydrate-before-startTrace contracts.
* 449 pass / 0 fail across the full tracing + TUI suites (1 network
  flake in tracing-adversarial-2 unrelated to this change, passes on
  re-run).

What I traced before declaring done

* Inventoried every `sessionTraces.delete`, `sessionTraces.clear`,
  `endTrace()`, `Trace.create()`, `Trace.withExporters()`, and direct
  trace-file write across the whole repo.
* Confirmed `this.spans` is never reassigned mid-instance (only
  pushed) except by the new `rehydrateFromFile`.
* Confirmed no external callers of `trace.snapshot()` outside
  `tracing.ts`.

Post-fix, the only ways a new `Trace` instance can replace an existing
session's in-memory Trace are: worker boot (once), `setWorkspace` with
an actually-changed workspaceID (rare, also idempotency-guarded), and
MAX_TRACES eviction (uncommon at 100 sessions). All three now go
through `rehydrateFromFile` first.
Per codex review (2026-06-05): the previous user-text branch in worker.ts
gated on `part.time?.end` (which user-input parts never have set) AND
called `trace.setTitle(text, text)` which would have regressed the
auto-generated session title from Path C (`session.updated`) back to
the raw user input ('Greeting' → 'hi') if the ordering went sideways.

* New `Trace.setPrompt(prompt)` method that only mutates `metadata.prompt`.
  Decouples prompt capture from title mutation.
* Path B in worker.ts now: (a) accepts user text parts without
  `part.time?.end` (it's an assistant-side concept only); (b) calls
  `setPrompt(text)` only — never `setTitle` — for user-identified
  messages. Assistant text still requires `time.end` for `logText`.
* Source-grep regression tests lock both contracts: no more
  `part.time?.end` on the user branch, no `setTitle` from the user
  branch, `setPrompt` exists and doesn't touch title.
…-turn

The chat tab in the trace viewer renders 'metadata.prompt' as a single
'You' bubble at the top, then iterates 'kind: generation' spans for
assistant replies. There's no place for any user message beyond the
first to land — `setPrompt` overwrites on every call, and the viewer
only reads the latest value. Symptom: a 3-turn session shows only the
LAST user prompt followed by all earlier assistant responses, with the
older user messages dropped.

Fix splits the data and the rendering:

* New `Trace.logUserMessage(text)` pushes a `kind: 'user-message'`
  span with the user text as input. Snapshots immediately like other
  log* methods.
* New 'user-message' variant added to the TraceSpan.kind union.
* worker.ts Path B: now also calls `logUserMessage(text)` alongside
  `setPrompt(text)` for user-identified text parts (the first one
  populates metadata.prompt for the Summary tab; all of them populate
  per-turn spans for the Chat tab).
* viewer.ts chat-view: builds a chronologically sorted list of
  user-message + generation spans and walks it in startTime order.
  Older traces without user-message spans fall back to rendering
  metadata.prompt as before.
* Behavioral test in tracing-rehydrate.test.ts proves the spans are
  written, ordered chronologically, and preserve the user text.

10 unit tests in worker-trace-clearing + 8 in tracing-rehydrate pass;
35 existing tracing tests pass unchanged; typecheck clean.
Copy link
Copy Markdown

@claude claude Bot left a comment

Choose a reason for hiding this comment

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

Claude Code Review

This repository is configured for manual code reviews. Comment @claude review to trigger a review and subscribe this PR to future pushes, or @claude review once for a one-time review.

Tip: disable this comment in your organization's Code Review settings.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Jun 5, 2026

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds disk rehydration and per-turn "user-message" spans, introduces prompt-only updates, updates viewer to interleave user/generation spans and dedupe prompts, makes worker prefer rehydration and avoid per-turn trace clearing, narrows session effect for workspace changes, and adds functional and regression tests validating these behaviors.

Changes

Trace Persistence and Multi-turn Lifecycle

Layer / File(s) Summary
Tracing API: rehydrate, prompt, user-message
packages/opencode/src/altimate/observability/tracing.ts
TraceSpan.kind adds "user-message". Exports USER_MESSAGE_INPUT_MAX_CHARS. Trace.rehydrateFromFile(sessionId) restores on-disk spans/metadata, clears root span endTime, and interrupts in-flight generation spans. Trace.setPrompt(prompt) updates only metadata.prompt. Trace.logUserMessage(text) appends a truncated user-message span and snapshots.
Viewer: chronological chat rendering
packages/opencode/src/altimate/observability/viewer.ts
Renderer imports USER_MESSAGE_INPUT_MAX_CHARS, dedupes metadata.prompt against existing user-message spans (full and truncated), interleaves user-message and generation spans by startTime, and renders generation tool child spans before agent output.
Worker lifecycle, cache-miss rehydration, workspace idempotency
packages/opencode/src/cli/cmd/tui/worker.ts
getOrCreateTrace tries trace.rehydrateFromFile(sessionID) on cache miss before starting new trace. Text handling routes authored user parts (excluding synthetic/ignored) to setPrompt + logUserMessage; assistant text logged when part.time?.end exists. Removes per-turn idle finalization. Adds currentWorkspaceID with idempotent rpc.setWorkspace.
Session route: SolidJS effect narrowing
packages/opencode/src/cli/cmd/tui/routes/session/index.tsx
Replaces broad createEffect with createEffect(on(() => session()?.workspaceID, ...)) so sdk.setWorkspace runs only when workspaceID changes.
Trace rehydration + user-message functional tests
packages/opencode/test/altimate/tracing-rehydrate.test.ts
Tests: rehydrate restores persisted spans/metadata and preserves traceId, returns false on missing/mismatched files, handles sanitized session IDs, logUserMessage emits chronological user-message spans, in-flight generation spans become interrupted on rehydration, and root span endTime is cleared after rehydrate.
Worker trace-clearing regression test suite
packages/opencode/test/cli/tui/worker-trace-clearing.test.ts
Regex-based regression tests assert: rpc.setWorkspace uses a module currentWorkspaceID guard and is idempotent; session route effect uses on(...) projector; worker no longer finalizes traces on idle; getOrCreateTrace prefers rehydrate-first; user-text path allows parts without part.time?.end, uses setPrompt (not setTitle), skips synthetic/ignored parts, and Trace.setPrompt mutates only metadata.prompt.

Sequence Diagram(s)

sequenceDiagram
  participant Worker
  participant Trace
  participant FileExporter
  Worker->>Trace: rehydrateFromFile(sessionId)
  Trace->>FileExporter: read session JSON
  FileExporter-->>Trace: spans + metadata
  Trace->>Trace: clear rootSpan.endTime & mark open generation spans interrupted
  Worker->>Trace: setPrompt(prompt)
  Worker->>Trace: logUserMessage(text)
  Trace->>FileExporter: snapshot() (persist updated spans)
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Poem

🐰
I hopped through traces saved on disk,
Rehydrated turns that nearly went amiss.
Prompts and messages kept in line,
Multi-turn chat now holds its shine.
Hooray — no more lost conversation bliss!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 16.67% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the main change: fixing trace data loss after agent turns affecting waterfall view, summary prompt, and chat tab.
Linked Issues check ✅ Passed All objectives from issue #896 are met: traces persist across turns (removed per-turn idle handler), prompt capture fixed (Trace.setPrompt), chat tab shows all user messages (logUserMessage + viewer interleaving), and rehydration preserves multi-turn data.
Out of Scope Changes check ✅ Passed All code changes are directly in scope with issue #896: trace lifecycle fixes, rehydration, prompt capture, user-message logging, workspace idempotency, and viewer rendering for multi-turn conversations.
Description check ✅ Passed The PR description includes all required template sections: Summary, Test Plan, and Checklist with verification status.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/trace-clearing-on-workspace-set

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@github-actions
Copy link
Copy Markdown

github-actions Bot commented Jun 5, 2026

👋 This PR was automatically closed by our quality checks.

Common reasons:

  • New GitHub account with limited contribution history
  • PR description doesn't meet our guidelines
  • Contribution appears to be AI-generated without meaningful review

If you believe this was a mistake, please open an issue explaining your intended contribution and a maintainer will help you.

@github-actions
Copy link
Copy Markdown

github-actions Bot commented Jun 5, 2026

👋 This PR was automatically closed by our quality checks.

Common reasons:

  • New GitHub account with limited contribution history
  • PR description doesn't meet our guidelines
  • Contribution appears to be AI-generated without meaningful review

If you believe this was a mistake, please open an issue explaining your intended contribution and a maintainer will help you.

1 similar comment
@github-actions
Copy link
Copy Markdown

github-actions Bot commented Jun 5, 2026

👋 This PR was automatically closed by our quality checks.

Common reasons:

  • New GitHub account with limited contribution history
  • PR description doesn't meet our guidelines
  • Contribution appears to be AI-generated without meaningful review

If you believe this was a mistake, please open an issue explaining your intended contribution and a maintainer will help you.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (1)
packages/opencode/test/altimate/tracing-rehydrate.test.ts (1)

59-61: 💤 Low value

Consider improving type safety by avoiding as any casts.

Multiple test cases use as any casts to bypass type checking when calling logToolCall, logText, and logUserMessage. While this works for testing, it reduces type safety and could hide issues if the actual method signatures change.

Consider using Partial<T> or creating minimal properly-typed test fixtures instead of any casts.

Example:

// Instead of:
original.logToolCall({ tool: "read", state: { status: "completed", input: { f: "a" } } } as any)

// Consider:
const mockToolCall = {
  tool: "read",
  callID: "test-call-1",
  state: {
    status: "completed" as const,
    input: { f: "a" },
    output: "",
    time: { start: Date.now(), end: Date.now() }
  }
}
original.logToolCall(mockToolCall)

Also applies to: 86-86, 141-144, 166-166, 177-177

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/opencode/test/altimate/tracing-rehydrate.test.ts` around lines 59 -
61, Replace the unsafe "as any" casts in the test by constructing minimal
properly-typed fixtures (or using Partial<T>) that conform to the expected
parameter types for original.logToolCall, original.logText, and
original.logUserMessage; specifically, build small objects that include required
fields like tool, callID, state (with status, input, output, time) for
logToolCall and include time and text for logText (and message/time for
logUserMessage), then pass those typed fixtures into the calls instead of
casting—this preserves type safety and will surface signature changes for
functions logToolCall, logText, and logUserMessage in the
tracing-rehydrate.test.ts tests.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/opencode/test/altimate/tracing-rehydrate.test.ts`:
- Around line 23-32: The test currently manages a manual tmpDir variable with
beforeEach/afterEach; replace this by removing the tmpDir module variable and
the beforeEach/afterEach hooks and use the fixture tmpdir() helper instead: in
each test, add an "await using tmp = await tmpdir()" (import tmpdir from
fixture/fixture.ts) and reference tmp.path (or the helper's API) where tmpDir
was used so cleanup is automatic when tmp goes out of scope.

In `@packages/opencode/test/cli/tui/worker-trace-clearing.test.ts`:
- Around line 60-67: The current assertions on routeSrc only catch one spelling
of the old inline createEffect; update the negative regexes in
worker-trace-clearing.test.ts (the expect(...) checks using routeSrc) to broadly
reject any inline createEffect arrow form that accesses optional-chained values
or uses short-circuiting (e.g., patterns like createEffect(() =>
session()?.workspaceID && ...), createEffect(() => session()?.workspaceID ? ...
: ...), or createEffect(() => { if (session()?.workspaceID) ... }) ) and also
add guards to reject nested optional-check if-statements inside user-text
branches (the pattern if (part.time?.end) or similar) so the tests fail if code
reverts to any of those buggy shapes; keep positive check that
createEffect(on(() => session()?.workspaceID, ...) ) still appears.

---

Nitpick comments:
In `@packages/opencode/test/altimate/tracing-rehydrate.test.ts`:
- Around line 59-61: Replace the unsafe "as any" casts in the test by
constructing minimal properly-typed fixtures (or using Partial<T>) that conform
to the expected parameter types for original.logToolCall, original.logText, and
original.logUserMessage; specifically, build small objects that include required
fields like tool, callID, state (with status, input, output, time) for
logToolCall and include time and text for logText (and message/time for
logUserMessage), then pass those typed fixtures into the calls instead of
casting—this preserves type safety and will surface signature changes for
functions logToolCall, logText, and logUserMessage in the
tracing-rehydrate.test.ts tests.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: d8954327-c7af-42d8-b70b-20de542b2632

📥 Commits

Reviewing files that changed from the base of the PR and between daa0351 and ec0d877.

📒 Files selected for processing (7)
  • packages/opencode/specs/trace-bugs-followup-867.md
  • packages/opencode/src/altimate/observability/tracing.ts
  • packages/opencode/src/altimate/observability/viewer.ts
  • packages/opencode/src/cli/cmd/tui/routes/session/index.tsx
  • packages/opencode/src/cli/cmd/tui/worker.ts
  • packages/opencode/test/altimate/tracing-rehydrate.test.ts
  • packages/opencode/test/cli/tui/worker-trace-clearing.test.ts

Comment thread packages/opencode/test/altimate/tracing-rehydrate.test.ts Outdated
Comment thread packages/opencode/test/cli/tui/worker-trace-clearing.test.ts Outdated
Copy link
Copy Markdown

@cubic-dev-ai cubic-dev-ai Bot left a comment

Choose a reason for hiding this comment

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

4 issues found across 7 files

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

Comment thread packages/opencode/src/altimate/observability/tracing.ts
Comment thread packages/opencode/src/altimate/observability/tracing.ts Outdated
Comment thread packages/opencode/src/altimate/observability/viewer.ts Outdated
Comment thread packages/opencode/test/cli/tui/worker-trace-clearing.test.ts Outdated
@github-actions
Copy link
Copy Markdown

github-actions Bot commented Jun 5, 2026

👋 This PR was automatically closed by our quality checks.

Common reasons:

  • New GitHub account with limited contribution history
  • PR description doesn't meet our guidelines
  • Contribution appears to be AI-generated without meaningful review

If you believe this was a mistake, please open an issue explaining your intended contribution and a maintainer will help you.

@sahrizvi sahrizvi changed the title fix(tracing): cross-instance lifecycle + data-feed + chat rendering (followup to #867) fix(tracing): trace waterfall + summary prompt + chat tab all lose data after each agent turn Jun 5, 2026
@github-actions
Copy link
Copy Markdown

github-actions Bot commented Jun 5, 2026

👋 This PR was automatically closed by our quality checks.

Common reasons:

  • New GitHub account with limited contribution history
  • PR description doesn't meet our guidelines
  • Contribution appears to be AI-generated without meaningful review

If you believe this was a mistake, please open an issue explaining your intended contribution and a maintainer will help you.

@dev-punia-altimate
Copy link
Copy Markdown

✅ Tests — All Passed

TypeScript — passed

cc @sahrizvi

@github-actions
Copy link
Copy Markdown

github-actions Bot commented Jun 5, 2026

👋 This PR was automatically closed by our quality checks.

Common reasons:

  • New GitHub account with limited contribution history
  • PR description doesn't meet our guidelines
  • Contribution appears to be AI-generated without meaningful review

If you believe this was a mistake, please open an issue explaining your intended contribution and a maintainer will help you.

1 similar comment
@github-actions
Copy link
Copy Markdown

github-actions Bot commented Jun 5, 2026

👋 This PR was automatically closed by our quality checks.

Common reasons:

  • New GitHub account with limited contribution history
  • PR description doesn't meet our guidelines
  • Contribution appears to be AI-generated without meaningful review

If you believe this was a mistake, please open an issue explaining your intended contribution and a maintainer will help you.

* Trace.rehydrateFromFile (cubic P2): restore traceId from the on-disk file
  so post-rehydrate snapshots/exports preserve trace identity across instance
  lifetimes. Without this, every snapshot after rehydration writes a fresh
  random traceId.
* Trace.rehydrateFromFile (cubic P2): normalize sessionId via the same
  sanitization buildTraceFile applies before comparing to trace.sessionId.
  Previously, sessions with /, \, ., or : in the id would be falsely
  rejected and recreated.
* viewer chat-view (cubic P2): always render metadata.prompt at the top
  unless an existing user-message span carries the same text. Pre-fix
  traces (only metadata.prompt) and mixed traces (rehydrated pre-fix data
  + new turns) now render the first user turn correctly. Previously, the
  fallback was gated on userMsgs.length === 0 and dropped the legacy
  first turn in mixed traces.
* worker-trace-clearing.test.ts (CodeRabbit, cubic P3): broaden the
  negative regression guards to catch all three flagged bug spellings —
  inline expression, inline ternary, block body with if — for the
  workspaceID effect; and to reject part.time?.end nested inside the
  user-text branch (identified by sessionUserMsgIds.get(...).has(...)).
* routes/session/index.tsx: paraphrased the bug-shape literal that was
  in a comment so the broadened test regex doesn't catch our own
  documentation as the bug.
* tracing-rehydrate.test.ts: behavioral tests for the traceId
  preservation and sanitized-sessionId match.

Skipped CodeRabbit's tmpdir-fixture-style suggestion — the convention
isn't followed by the existing tracing tests (tracing-display-crash,
tracing-rename-race) so changing this one file alone would be inconsistent
and out of scope for this PR.

48 affected tests pass; typecheck clean.
@github-actions
Copy link
Copy Markdown

github-actions Bot commented Jun 5, 2026

👋 This PR was automatically closed by our quality checks.

Common reasons:

  • New GitHub account with limited contribution history
  • PR description doesn't meet our guidelines
  • Contribution appears to be AI-generated without meaningful review

If you believe this was a mistake, please open an issue explaining your intended contribution and a maintainer will help you.

2 similar comments
@github-actions
Copy link
Copy Markdown

github-actions Bot commented Jun 5, 2026

👋 This PR was automatically closed by our quality checks.

Common reasons:

  • New GitHub account with limited contribution history
  • PR description doesn't meet our guidelines
  • Contribution appears to be AI-generated without meaningful review

If you believe this was a mistake, please open an issue explaining your intended contribution and a maintainer will help you.

@github-actions
Copy link
Copy Markdown

github-actions Bot commented Jun 5, 2026

👋 This PR was automatically closed by our quality checks.

Common reasons:

  • New GitHub account with limited contribution history
  • PR description doesn't meet our guidelines
  • Contribution appears to be AI-generated without meaningful review

If you believe this was a mistake, please open an issue explaining your intended contribution and a maintainer will help you.

Copy link
Copy Markdown

@cubic-dev-ai cubic-dev-ai Bot left a comment

Choose a reason for hiding this comment

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

1 issue found across 5 files (changes from recent commits).

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

Comment thread packages/opencode/src/altimate/observability/viewer.ts Outdated
CodeRabbit pointed out that `packages/opencode/test/AGENTS.md` documents
`tmpdir()` from `fixture/fixture.ts` as the project convention. My
earlier reply skipped the migration on the grounds that sibling tracing
tests don't follow the convention — but for code I'm adding fresh, the
right move is to follow the documented standard. The sibling tests
predate it and should be swept in a separate cleanup PR.

Replaces the manual `os.tmpdir() + beforeEach/afterEach` pattern with
`await using tmp = await tmpdir()` per test. Helpers `makeTrace` and
`readTraceFile` now take `dir` as a first parameter so each test
threads its own tmp directory through. 46 affected tests pass.
@github-actions
Copy link
Copy Markdown

github-actions Bot commented Jun 5, 2026

👋 This PR was automatically closed by our quality checks.

Common reasons:

  • New GitHub account with limited contribution history
  • PR description doesn't meet our guidelines
  • Contribution appears to be AI-generated without meaningful review

If you believe this was a mistake, please open an issue explaining your intended contribution and a maintainer will help you.

2 similar comments
@github-actions
Copy link
Copy Markdown

github-actions Bot commented Jun 5, 2026

👋 This PR was automatically closed by our quality checks.

Common reasons:

  • New GitHub account with limited contribution history
  • PR description doesn't meet our guidelines
  • Contribution appears to be AI-generated without meaningful review

If you believe this was a mistake, please open an issue explaining your intended contribution and a maintainer will help you.

@github-actions
Copy link
Copy Markdown

github-actions Bot commented Jun 5, 2026

👋 This PR was automatically closed by our quality checks.

Common reasons:

  • New GitHub account with limited contribution history
  • PR description doesn't meet our guidelines
  • Contribution appears to be AI-generated without meaningful review

If you believe this was a mistake, please open an issue explaining your intended contribution and a maintainer will help you.

@github-actions
Copy link
Copy Markdown

github-actions Bot commented Jun 5, 2026

👋 This PR was automatically closed by our quality checks.

Common reasons:

  • New GitHub account with limited contribution history
  • PR description doesn't meet our guidelines
  • Contribution appears to be AI-generated without meaningful review

If you believe this was a mistake, please open an issue explaining your intended contribution and a maintainer will help you.

cubic flagged that `Trace.logUserMessage` slices user text at 4000 chars
when persisting to the span, while `metadata.prompt` keeps the full
string. The strict equality check in viewer chat-view (`u.input ===
t.metadata.prompt`) misses the dedupe for prompts longer than 4000 chars
and renders the same text twice — once as the top-level "You" fallback
bubble, once as the first user-message span.

Match against both the full and the truncated form. Same fix shape cubic
suggested.
@github-actions
Copy link
Copy Markdown

github-actions Bot commented Jun 5, 2026

👋 This PR was automatically closed by our quality checks.

Common reasons:

  • New GitHub account with limited contribution history
  • PR description doesn't meet our guidelines
  • Contribution appears to be AI-generated without meaningful review

If you believe this was a mistake, please open an issue explaining your intended contribution and a maintainer will help you.

1 similar comment
@github-actions
Copy link
Copy Markdown

github-actions Bot commented Jun 5, 2026

👋 This PR was automatically closed by our quality checks.

Common reasons:

  • New GitHub account with limited contribution history
  • PR description doesn't meet our guidelines
  • Contribution appears to be AI-generated without meaningful review

If you believe this was a mistake, please open an issue explaining your intended contribution and a maintainer will help you.

The PR description already carries the bug-by-bug origin table and the
explanation of why #867's scope was disjoint from these bugs. Keeping a
295-line spec file in the repo to say the same thing again is bloat —
the PR is the right place for this content.
@github-actions
Copy link
Copy Markdown

github-actions Bot commented Jun 5, 2026

👋 This PR was automatically closed by our quality checks.

Common reasons:

  • New GitHub account with limited contribution history
  • PR description doesn't meet our guidelines
  • Contribution appears to be AI-generated without meaningful review

If you believe this was a mistake, please open an issue explaining your intended contribution and a maintainer will help you.

3 similar comments
@github-actions
Copy link
Copy Markdown

github-actions Bot commented Jun 5, 2026

👋 This PR was automatically closed by our quality checks.

Common reasons:

  • New GitHub account with limited contribution history
  • PR description doesn't meet our guidelines
  • Contribution appears to be AI-generated without meaningful review

If you believe this was a mistake, please open an issue explaining your intended contribution and a maintainer will help you.

@github-actions
Copy link
Copy Markdown

github-actions Bot commented Jun 5, 2026

👋 This PR was automatically closed by our quality checks.

Common reasons:

  • New GitHub account with limited contribution history
  • PR description doesn't meet our guidelines
  • Contribution appears to be AI-generated without meaningful review

If you believe this was a mistake, please open an issue explaining your intended contribution and a maintainer will help you.

@github-actions
Copy link
Copy Markdown

github-actions Bot commented Jun 5, 2026

👋 This PR was automatically closed by our quality checks.

Common reasons:

  • New GitHub account with limited contribution history
  • PR description doesn't meet our guidelines
  • Contribution appears to be AI-generated without meaningful review

If you believe this was a mistake, please open an issue explaining your intended contribution and a maintainer will help you.

Copy link
Copy Markdown

@cubic-dev-ai cubic-dev-ai Bot left a comment

Choose a reason for hiding this comment

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

1 issue found across 2 files (changes from recent commits).

Tip: Review your code locally with the cubic CLI to iterate faster.

Re-trigger cubic

Comment thread packages/opencode/src/altimate/observability/viewer.ts Outdated
…uncation constant

Three follow-ups from the multi-LLM consensus review of PR #895, codex-validated:

* Worker user-text branch now skips parts with `synthetic` or `ignored`
  set (Major #1 in the review, codex-confirmed). `Session.createUserMessage`
  in prompt.ts attaches many synthetic text parts to the user messageID for
  MCP resource banners, decoded file contents, retry/reminder text,
  plan-mode reminders, and agent-handoff tags. Without the gate they pass
  the `sessionUserMsgIds.has(messageID)` check, `metadata.prompt` ends up
  holding the LAST synthetic part (typically a file blob), and the chat tab
  renders one fake "▶ You" bubble per synthetic span — defeating the two
  display surfaces this PR fixes. Gated on an `isAuthoredText` predicate
  so the symmetric assistant-text branch is also protected. Continue via
  predicate rather than `continue` keyword so the outer event loop still
  forwards the event downstream via `Rpc.emit`.

* `Trace.rehydrateFromFile` now marks any open generation span as
  interrupted (Major #2). The transient state `logStepStart` populated
  (`currentGenerationSpanId`, `generationText`, `generationToolCalls`,
  `pendingToolResults`) is memory-only and can't be reconstructed from
  disk. If we leave open spans open, the next `step-finish` for that turn
  drops at the `!this.currentGenerationSpanId` guard and follow-up
  `logToolCall` mis-parents tool spans to the root, silently degrading the
  trace shape. Closing the span with `status: "error"` and a
  `statusMessage` describing the interruption preserves the partial data
  and makes the boundary visible in the viewer.

* Extracted the 4000-char truncation cap as `USER_MESSAGE_INPUT_MAX_CHARS`
  exported from tracing.ts (new cubic P3 on viewer.ts:1331). The viewer's
  chat-tab dedupe now interpolates the same constant so the two sides can't
  drift if the truncation cap ever changes. Also reused a single
  `Date.now()` call for the user-message span's start/end timestamps
  (cosmetic, addresses review nit #16).

Skipped from the review:
- Major #3 (no per-messageID dedupe in logUserMessage): codex confirmed
  user text doesn't stream/chunk — message.part.delta is assistant-only
  — so the symptom the review described is subsumed by Major #1's
  synthetic gate. No separate fix needed.
- Major #5 (Path A `setTitle(text, text)` couples title and prompt):
  codex grep-verified that no in-repo code path populates
  `userMsg.summary.title` or `summary.body`; the branch is inert.
  Cleanup risk only, tracked in #896.

Tests
- New behavioral test in tracing-rehydrate.test.ts asserts that an open
  generation span (no `step-finish` before reconstruction) ends up
  with `endTime` set, `status: "error"`, and a statusMessage matching
  `/interrupted/i` after rehydrate + a snapshot-triggering call.
- New source-grep test in worker-trace-clearing.test.ts locks both
  the synthetic-gate literal (`!part.synthetic && !part.ignored`) and
  the requirement that both `trace.setPrompt` and `trace.logUserMessage`
  sit inside the `isAuthoredText &&` guard.

42 affected tests pass; typecheck clean.
@github-actions
Copy link
Copy Markdown

github-actions Bot commented Jun 5, 2026

👋 This PR was automatically closed by our quality checks.

Common reasons:

  • New GitHub account with limited contribution history
  • PR description doesn't meet our guidelines
  • Contribution appears to be AI-generated without meaningful review

If you believe this was a mistake, please open an issue explaining your intended contribution and a maintainer will help you.

2 similar comments
@github-actions
Copy link
Copy Markdown

github-actions Bot commented Jun 5, 2026

👋 This PR was automatically closed by our quality checks.

Common reasons:

  • New GitHub account with limited contribution history
  • PR description doesn't meet our guidelines
  • Contribution appears to be AI-generated without meaningful review

If you believe this was a mistake, please open an issue explaining your intended contribution and a maintainer will help you.

@github-actions
Copy link
Copy Markdown

github-actions Bot commented Jun 5, 2026

👋 This PR was automatically closed by our quality checks.

Common reasons:

  • New GitHub account with limited contribution history
  • PR description doesn't meet our guidelines
  • Contribution appears to be AI-generated without meaningful review

If you believe this was a mistake, please open an issue explaining your intended contribution and a maintainer will help you.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/opencode/test/cli/tui/worker-trace-clearing.test.ts`:
- Around line 147-153: The test's regexes match across the whole file and can be
satisfied by unrelated code; update the assertions to scope both checks to the
same guarded block by matching a single guard that contains "!part.synthetic &&
!part.ignored" and then, within that same non-greedy span, require
"isAuthoredText &&" followed by both "trace.setPrompt" and
"trace.logUserMessage" (or better, scope around the "sessionUserMsgIds...has("
branch) so the pattern ensures all these tokens appear inside the same
branch/guard rather than anywhere in the file; modify the
expect(workerSrc).toMatch(...) regex to start at the guard
(!part.synthetic\s*&&\s*!part.ignored) and then use a non-greedy [\s\S]*? to
assert isAuthoredText\s*&&.*?trace\.setPrompt.*?trace\.logUserMessage within
that block.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: b46b10de-eca5-4af0-b455-6a99c7e5ee69

📥 Commits

Reviewing files that changed from the base of the PR and between 01b8ea1 and 39dd742.

📒 Files selected for processing (5)
  • packages/opencode/src/altimate/observability/tracing.ts
  • packages/opencode/src/altimate/observability/viewer.ts
  • packages/opencode/src/cli/cmd/tui/worker.ts
  • packages/opencode/test/altimate/tracing-rehydrate.test.ts
  • packages/opencode/test/cli/tui/worker-trace-clearing.test.ts
🚧 Files skipped from review as they are similar to previous changes (4)
  • packages/opencode/src/altimate/observability/viewer.ts
  • packages/opencode/src/cli/cmd/tui/worker.ts
  • packages/opencode/src/altimate/observability/tracing.ts
  • packages/opencode/test/altimate/tracing-rehydrate.test.ts

Comment thread packages/opencode/test/cli/tui/worker-trace-clearing.test.ts Outdated
Copy link
Copy Markdown

@dev-punia-altimate dev-punia-altimate left a comment

Choose a reason for hiding this comment

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

Multi-Persona Review — Verdict: ship

The PR implements a well-structured feature to add a Cluster column and enhanced filtering to Databricks Job Run History, following React best practices, API conventions, and defensive rendering patterns. All adversarial tests passed, no critical or high-severity findings were identified, and the codebase hygiene is clean.

15/15 agents completed · 249s · 5 findings (0 critical, 0 high, 0 medium)

Low

  • [web-researcher] PR handles cluster_id as string to preserve leading zeros and avoid precision loss, aligning with frontend best practices for non-numeric identifiers. → apps/web/src/helpers/apis.ts:5712
    • 💡 Consider adding a type annotation for cluster_id as string in the API contract for clarity.
  • [web-researcher] Defensive rendering of null/undefined cluster_name with fallbacks ('-' or cluster_id) and data-testid mitigates potential XSS risks from untrusted data. → apps/web/src/pages/jobs/components/JobRunHistory.tsx:113
    • 💡 Consider adding a unit test that explicitly verifies the fallback rendering of null/undefined cluster_name.
  • [web-researcher] Use of @altimateai/lego v2.1.0 Stack component with row layout and justify='between' leverages recent accessibility improvements in the design system. → apps/web/src/components/tables/DataTableHeaderPortals.tsx:25
    • 💡 Verify that the Stack component's updated spacing behavior is visually consistent across all breakpoints.
  • [context-pack] Extracted DataTableHeaderPortals component reduces duplication between JobsTable and JobRunHistory, improving maintainability and consistency. → apps/web/src/components/tables/DataTableHeaderPortals.tsx:1
    • 💡 Consider documenting this component in the design system wiki for future reuse.
  • [web-researcher] Adding result_states and cluster_ids query parameters aligns with Databricks API conventions for efficient server-side filtering. → apps/web/src/helpers/apis.ts:5714
    • 💡 Ensure backend PR AltimateAI/altimate-backend#5455 is merged in sync to avoid API mismatch.

Multi-Persona Review · vllm:qwen3-next-80b (waves) + vllm-fallback (synth) ·

…eRabbit)

CodeRabbit flagged that the previous source-grep assertions matched
across the entire `worker.ts` file, so unrelated code positioning
could satisfy them without the synthetic-gate fix being present in
the actual user-text branch.

* The `isAuthoredText` declaration check now asserts the const is
  built from BOTH flags (`!part.synthetic && !part.ignored`), not
  just that the literal exists somewhere.
* The two write-path checks now require `trace.setPrompt` and
  `trace.logUserMessage` to sit inside the same `if (text) { ... }`
  body within the `sessionUserMsgIds...has(part.messageID)` branch.
  The `[^{}]` bounds on the inner spans prevent the match from
  extending past the closing brace of that body, so calls elsewhere
  in the file can't false-green the assertion.
@github-actions
Copy link
Copy Markdown

github-actions Bot commented Jun 5, 2026

👋 This PR was automatically closed by our quality checks.

Common reasons:

  • New GitHub account with limited contribution history
  • PR description doesn't meet our guidelines
  • Contribution appears to be AI-generated without meaningful review

If you believe this was a mistake, please open an issue explaining your intended contribution and a maintainer will help you.

1 similar comment
@github-actions
Copy link
Copy Markdown

github-actions Bot commented Jun 5, 2026

👋 This PR was automatically closed by our quality checks.

Common reasons:

  • New GitHub account with limited contribution history
  • PR description doesn't meet our guidelines
  • Contribution appears to be AI-generated without meaningful review

If you believe this was a mistake, please open an issue explaining your intended contribution and a maintainer will help you.

@sahrizvi sahrizvi marked this pull request as draft June 5, 2026 20:23
@sahrizvi sahrizvi marked this pull request as ready for review June 5, 2026 20:26
@sahrizvi
Copy link
Copy Markdown
Contributor Author

sahrizvi commented Jun 5, 2026

@anandgupta42 Ready to be merged.

Copy link
Copy Markdown

@cubic-dev-ai cubic-dev-ai Bot left a comment

Choose a reason for hiding this comment

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

2 issues found across 6 files

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="packages/opencode/src/cli/cmd/tui/worker.ts">

<violation number="1" location="packages/opencode/src/cli/cmd/tui/worker.ts:239">
P2: User text may be silently dropped if `message.part.updated` arrives before `message.updated` for the same user message, because `sessionUserMsgIds` won't yet contain the messageID. The else-if assistant branch (`part.time?.end`) won't catch it either, since user text doesn't set `time.end`.</violation>
</file>

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

Comment thread packages/opencode/src/altimate/observability/tracing.ts Outdated
if (
isAuthoredText &&
part.messageID &&
sessionUserMsgIds.get(part.sessionID)?.has(part.messageID)
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2: User text may be silently dropped if message.part.updated arrives before message.updated for the same user message, because sessionUserMsgIds won't yet contain the messageID. The else-if assistant branch (part.time?.end) won't catch it either, since user text doesn't set time.end.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packages/opencode/src/cli/cmd/tui/worker.ts, line 239:

<comment>User text may be silently dropped if `message.part.updated` arrives before `message.updated` for the same user message, because `sessionUserMsgIds` won't yet contain the messageID. The else-if assistant branch (`part.time?.end`) won't catch it either, since user text doesn't set `time.end`.</comment>

<file context>
@@ -203,16 +211,50 @@ const startEventStream = (input: { directory: string; workspaceID?: string }) =>
+                  if (
+                    isAuthoredText &&
+                    part.messageID &&
+                    sessionUserMsgIds.get(part.sessionID)?.has(part.messageID)
+                  ) {
                     const text = String(part.text || "")
</file context>

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Real race in the abstract, but bounded in practice. Producer side: Session.createUserMessage in session/prompt.ts calls Session.updateMessage (which emits message.updated) BEFORE Session.updatePart (which emits message.part.updated) for each text part. Consumer side: the worker reads for await (const event of events.stream) — events are processed in receipt order from a single stream. So as long as the producer ordering holds, sessionUserMsgIds is populated before the part-handler fires.

Not closing the door entirely — if the producer ever reorders (parallel batched emit, retry-on-reconnect, server-side reordering), this would manifest as silently dropped user text. The defensive shape would be to buffer parts by messageID until we see a message.updated that classifies them, then flush. I'd rather land that as a focused follow-up with a real reproducer than speculate the implementation here — happy to open an issue if you'd like.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Got it — thanks for the clarification.

…hot path

cubic flagged that `fsSync.readFileSync` in `rehydrateFromFile` blocks
the worker event loop during a trace cache miss. The hot path is
bounded (cache miss only fires on worker restart, MAX_TRACES eviction,
or initial-boot resumption of a stale session), but a multi-MB trace
file makes the pause visible.

* `Trace.rehydrateFromFile` now returns `Promise<boolean>` and uses
  the async `fs.readFile`.
* `getOrCreateTrace` in worker.ts becomes `async` and the three call
  sites in the event-stream loop now `await` it. The loop body was
  already async (`for await (const event of events.stream)`), so the
  conversion is local.
* Behavioural tests in `tracing-rehydrate.test.ts` converted to
  `await` the now-async method (7 call sites).
* The source-grep contract test for `getOrCreateTrace`'s
  rehydrate-before-startTrace shape now matches the `await` form.

Not addressed in this commit (will reply on PR):
- cubic also flagged a theoretical event-ordering race where
  `message.part.updated` could arrive before `message.updated`,
  leaving `sessionUserMsgIds` empty when the part handler runs. The
  producer (`Session.createUserMessage` → `updateMessage` THEN
  `updatePart` for each part) emits in order, and the consumer reads
  the event stream sequentially. The race is theoretical given the
  current producer; if we ever reorder, the defensive fix is to buffer
  unrouted parts by messageID. Out of scope for this PR.
@github-actions
Copy link
Copy Markdown

github-actions Bot commented Jun 6, 2026

👋 This PR was automatically closed by our quality checks.

Common reasons:

  • New GitHub account with limited contribution history
  • PR description doesn't meet our guidelines
  • Contribution appears to be AI-generated without meaningful review

If you believe this was a mistake, please open an issue explaining your intended contribution and a maintainer will help you.

1 similar comment
@github-actions
Copy link
Copy Markdown

github-actions Bot commented Jun 6, 2026

👋 This PR was automatically closed by our quality checks.

Common reasons:

  • New GitHub account with limited contribution history
  • PR description doesn't meet our guidelines
  • Contribution appears to be AI-generated without meaningful review

If you believe this was a mistake, please open an issue explaining your intended contribution and a maintainer will help you.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

tracing: trace waterfall + summary prompt + chat tab all lose data after each agent turn

3 participants