Repository navigation
feat: select and switch runtime per session prompt - #283
Conversation
Preserve prompt-bound runtime snapshots across live, queued, steer, and interrupt flows while keeping logical session creation runtime-unbound. Harden runtime projection across API, CLI, native tools, extensions, SDKs, and web state. Fix session-window routing hydration, provider auth availability, daemon shutdown readiness, and runtime rollback behavior. Record the completed deep review and real-user QA coverage for session creation, runtime transitions, and structured prompt failures.
|
Too many files changed for review. ( Bypass the limit by tagging |
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
WalkthroughThe change moves runtime selection from session creation to prompt dispatch, adds runtime lifecycle and persistence metadata, exposes nested runtime API payloads, adds native session tools, updates CLI and SDK contracts, and introduces web controls for runtime selection, prompt cancellation, and durable unbound sessions. ChangesSession runtime architecture
Estimated code review effort: 5 (Critical) | ~120 minutes Possibly related PRs
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches 💡 1📝 Generate docstrings 💡
🧪 Generate unit tests (beta)
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. Comment |
|
React Doctor found 1 new issue in 1 file · 1 error · score 84 / 100 (Needs work) · 0 fixed · vs Errors
Reviewed by React Doctor for commit |
There was a problem hiding this comment.
Actionable comments posted: 19
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (5)
internal/cli/session_list.go (1)
123-132: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick winAlign JSONL with the runtime-provider projection.
sessionListBundle()callswriteJSONLine(cmd, item)for JSONL, so it serializesSessionRecorddirectly while the displayed rows usesessionRuntimeProvider(item). TheRuntime.Effective.Providerprojection is only exposed in Table/JSON modes unless JSONL is built with the same projected value used by the row renderer.🤖 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 `@internal/cli/session_list.go` around lines 123 - 132, Update the JSONL serialization path in sessionListBundle so writeJSONLine receives a SessionRecord whose runtime provider matches sessionRuntimeProvider(item), including the Runtime.Effective.Provider projection. Preserve the existing displayed-row and other output-mode behavior while applying this projection specifically to JSONL output.internal/session/manager_input_dispatch.go (1)
89-100: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick winFailed prompt-request construction leaves the queue entry claimed forever.
Every other failure branch in this file (
handleQueuedInputDispatchError) releases or marks-failed the claimed entry and callsm.startNextQueuedInputPrompt(target)to keep the queue moving. WhennewQueuedInputPromptRequestfails (line 125-132),dispatchHumanQueuedInputjust returns (line 89-92) — the entry claimed viaClaimNextis never released, never marked failed, and the queue is never advanced. If this path is ever hit, the session's queued input pipeline stalls silently.🐛 Proposed fix
req, ok := m.newQueuedInputPromptRequest(session, target, entry) if !ok { + if releaseErr := m.inputQueue.Release(m.fallbackLifecycleContext(), target, entry.id); releaseErr != nil { + m.sessionLogger(session).Warn( + "session: release queued input failed", + "entry_id", entry.id, + "error", releaseErr, + ) + } + m.startNextQueuedInputPrompt(target) return }Also applies to: 115-142
🤖 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 `@internal/session/manager_input_dispatch.go` around lines 89 - 100, Update dispatchHumanQueuedInput so the !ok branch after newQueuedInputPromptRequest handles the claimed entry consistently with handleQueuedInputDispatchError: release or mark the entry failed as appropriate, then call m.startNextQueuedInputPrompt(target) before returning. Ensure failed prompt-request construction cannot leave the queue stalled.internal/api/udsapi/transport_parity_integration_test.go (1)
686-696: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick winDiscarded errors violate the "never discard errors with
_" guideline.
io.ReadAllandBody.Close()errors are silently dropped here, while theresumeResphandling a few lines below in the same test correctly checks both. As per coding guidelines, "Never discard errors with_in production code or tests; handle every error or provide a justification."🧹 Proposed fix
if stopResp.StatusCode != http.StatusNoContent { - body, _ := io.ReadAll(stopResp.Body) - _ = stopResp.Body.Close() + body, readErr := io.ReadAll(stopResp.Body) + closeErr := stopResp.Body.Close() + if readErr != nil { + t.Fatalf("read UDS stop response body error = %v", readErr) + } + if closeErr != nil { + t.Fatalf("close UDS stop response body error = %v", closeErr) + } t.Fatalf( "UDS stop session status = %d, want %d; body=%s", stopResp.StatusCode, http.StatusNoContent, string(body), ) } - _ = stopResp.Body.Close() + if err := stopResp.Body.Close(); err != nil { + t.Fatalf("close UDS stop response body error = %v", err) + }🤖 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 `@internal/api/udsapi/transport_parity_integration_test.go` around lines 686 - 696, Update the stopResp error-handling block in the UDS stop-session test to check and handle errors from io.ReadAll and stopResp.Body.Close instead of assigning them to _. Match the explicit error-checking pattern already used by the nearby resumeResp handling, while preserving the existing failure message and status validation.Source: Coding guidelines
internal/store/globaldb/sqlcgen/session_core.sql.go (1)
265-315: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick winRuntime fields can still be silently dropped by the network-only optimistic-concurrency guard.
UpsertSessionParamsis built from the in-memory session snapshot, so the mapper emits currentRuntime*values even whensession.NetworkSpecSnapshot()is a stale participation snapshot. SinceON CONFLICT ... WHEREcompares onlynetwork_spec_json/network_mode/network_channel/network_source, a runtime-status update can be gate-locked out whenever any network field has changed. Include the runtime fields in the concurrency guard where that intent applies, or split the upsert path so runtime lifecycle updates are not bypassed by stale network metadata.🤖 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 `@internal/store/globaldb/sqlcgen/session_core.sql.go` around lines 265 - 315, The session upsert’s optimistic-concurrency guard must not reject current runtime lifecycle updates because of stale network metadata. Update the conflict handling around UpsertSessionParams and its ON CONFLICT WHERE clause to include the relevant Runtime* fields in the comparison, or separate runtime lifecycle updates from the network-guarded path; preserve the existing network protections while ensuring runtime status and transition changes are applied.sdk/go/contracts/types_019_gen.go (1)
248-289: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick winDocument the SDK session status/runtime field changes.
Provideris no longer present on the generatedSessionStatus/SessionSummary, andACPSessionIDis now underSessionRuntimePayload; add an entry to the migration/upgrade notes for external Go SDK consumers, since the migration guide only covers general SDK incompatibility and provider name mapping.🤖 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 `@sdk/go/contracts/types_019_gen.go` around lines 248 - 289, Update the migration/upgrade notes for external Go SDK consumers to document that Provider was removed from SessionStatus and SessionSummary, while ACPSessionID is now accessed through SessionRuntimePayload. Add this alongside the existing SDK incompatibility and provider-name mapping guidance, without changing the generated types.
🧹 Nitpick comments (18)
internal/api/httpapi/httpapi_integration_test.go (1)
712-719: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winAdd
t.Parallel()to the new parallelizable subtests.
TestHTTPTaskRunLifecycleRoutesRoundTripand other lifecycle helpers already uset.Parallel()withnewIntegrationRuntime(t), indicating the harness supports concurrent subtests. Addt.Parallel()at the start of the closures for the new stream cursor, stop reason, and crash stop reason subtests to keep this package aligned with the default parallel pattern.🤖 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 `@internal/api/httpapi/httpapi_integration_test.go` around lines 712 - 719, Add t.Parallel() at the beginning of the closures for the new stream cursor, stop reason, and crash stop reason subtests, including the test invoking exerciseHTTPSessionStreamReconnectPreservesCursorWhenNoNewEventsExistYet. Keep each subtest’s existing body and helper calls unchanged.Source: Coding guidelines
internal/session/additional_test.go (1)
365-378: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winWrap the new unbound-runtime scenario in its own
t.Run("Should ...")subtest.This adds a new, distinct test case (runtime-bind failure propagation) appended inline to
TestPromptErrorPathsrather than as a subtest.As per path instructions, "MUST use t.Run("Should...") pattern for ALL test cases."
♻️ Suggested wrapping
- h = newHarness(t) - session = createSession(t, h) - session.markRuntimeUnbound(time.Now().UTC()) - if got := session.Info().RuntimeStatus; got != RuntimeStatusUnbound { - t.Fatalf("unbound session runtime status = %q, want %q", got, RuntimeStatusUnbound) - } - bindErr := errors.New("runtime bind unavailable") - h.driver.startHook = func(_ acp.StartOpts, _ int) (*fakeProcess, error) { - return nil, bindErr - } - if _, err := h.manager.Prompt(testutil.Context(t), session.ID, "bind-runtime"); !errors.Is(err, bindErr) { - t.Fatalf("Prompt(unbound) error = %v, want runtime bind failure", err) - } + t.Run("Should propagate runtime bind failure for an unbound session", func(t *testing.T) { + t.Parallel() + h := newHarness(t) + session := createSession(t, h) + session.markRuntimeUnbound(time.Now().UTC()) + if got := session.Info().RuntimeStatus; got != RuntimeStatusUnbound { + t.Fatalf("unbound session runtime status = %q, want %q", got, RuntimeStatusUnbound) + } + bindErr := errors.New("runtime bind unavailable") + h.driver.startHook = func(_ acp.StartOpts, _ int) (*fakeProcess, error) { + return nil, bindErr + } + if _, err := h.manager.Prompt(testutil.Context(t), session.ID, "bind-runtime"); !errors.Is(err, bindErr) { + t.Fatalf("Prompt(unbound) error = %v, want runtime bind failure", err) + } + })🤖 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 `@internal/session/additional_test.go` around lines 365 - 378, Wrap the unbound-runtime bind failure scenario in a dedicated t.Run subtest named with the required “Should ...” pattern within TestPromptErrorPaths. Keep the existing setup, startHook error injection, Prompt invocation, and assertion together inside that subtest.internal/session/manager_start.go (1)
52-55: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueError message is coupled to the helper's current single failure mode.
sessionStartSpecFromMetatoday can only fail on speed normalization, so "validate resume speed" is accurate — but the wording will misattribute any future failure added to the shared helper. Prefer a neutral prefix and let the wrapped error carry the specifics.♻️ Suggested wording
- spec, err := sessionStartSpecFromMeta(meta, &resolvedWorkspace, cwd) - if err != nil { - return sessionStartSpec{}, fmt.Errorf("session: validate resume speed for %q: %w", meta.ID, err) - } + spec, err := sessionStartSpecFromMeta(meta, &resolvedWorkspace, cwd) + if err != nil { + return sessionStartSpec{}, fmt.Errorf("session: build resume start spec for %q: %w", meta.ID, err) + }🤖 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 `@internal/session/manager_start.go` around lines 52 - 55, Update the error wrapping in the session-start flow around sessionStartSpecFromMeta to use a neutral description of the helper failure rather than specifically naming resume-speed validation, while preserving meta.ID context and the wrapped error.internal/session/manager_start_meta.go (1)
11-32: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick winTake the workspace by value to remove the nil-deref surface.
Line 32 dereferences
workspaceunconditionally. The only caller passes&resolvedWorkspace, so it is safe today, but this is a new shared helper and the pointer buys nothing here — the spec stores a copy anyway. Passing by value makes the nil case unrepresentable instead of requiring a guard.♻️ Proposed signature change
func sessionStartSpecFromMeta( meta store.SessionMeta, - workspace *workspacepkg.ResolvedWorkspace, + workspace workspacepkg.ResolvedWorkspace, cwd string, ) (sessionStartSpec, error) {- workspace: *workspace, + workspace: workspace,Caller in
internal/session/manager_start.go:- spec, err := sessionStartSpecFromMeta(meta, &resolvedWorkspace, cwd) + spec, err := sessionStartSpecFromMeta(meta, resolvedWorkspace, cwd)🤖 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 `@internal/session/manager_start_meta.go` around lines 11 - 32, Change sessionStartSpecFromMeta to accept workspacepkg.ResolvedWorkspace by value instead of a pointer, and update its caller in the session-start flow to pass resolvedWorkspace directly. Preserve the existing spec.workspace copy assignment while eliminating the unconditional pointer dereference.internal/session/manager_start_test.go (1)
161-192: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winAlso assert the rolled-back runtime state after a failed initial bind.
The subtest verifies the transcript stays empty but not the rollback invariant introduced by
restoreRuntimeBinding— the session should be back toRuntimeStatusUnboundwithRuntimeFailurepopulated, and the durable meta should agree. Without that, a regression that leaves the session stuck inbindingwould still pass.💚 Suggested additional assertions
if len(page.Entries) != 0 { t.Fatalf("TranscriptPage() entries = %#v, want empty", page.Entries) } + live, ok := h.manager.Get(created.ID) + if !ok { + t.Fatalf("Get(%q) did not find created session", created.ID) + } + info := live.Info() + if info.RuntimeStatus != RuntimeStatusUnbound || info.RuntimeFailure == "" { + t.Fatalf( + "runtime after failed bind = %q/%q, want unbound with failure detail", + info.RuntimeStatus, + info.RuntimeFailure, + ) + } + if meta := readMeta(t, live.MetaPath()); meta.RuntimeStatus != RuntimeStatusUnbound { + t.Fatalf("meta runtime status = %q, want %q", meta.RuntimeStatus, RuntimeStatusUnbound) + }🤖 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 `@internal/session/manager_start_test.go` around lines 161 - 192, Extend the “Should preserve an empty transcript when initial binding fails” test to assert the rollback state after SendPrompt returns startErr: the session must have RuntimeStatusUnbound with RuntimeFailure populated, and the durable metadata must report the same runtime state. Use the existing session/runtime inspection APIs and meta symbols used by restoreRuntimeBinding, while preserving the transcript and cleanup assertions.internal/session/manager_test.go (1)
4488-4492: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winAssert the fake driver did not stop the bound process.
proc.donedefault-case does not makeShutdown()async-stop behavior impossible:driver.Stop()incrementsstopCallsbefore calling the hook, so a buggy path can callStop()and return only after the hook/closure signals shutdown. Addif h.driver.stopCalls != 0 { t.Fatalf("driver stop calls = %d, want 0", h.driver.stopCalls) }alongside thedonecheck.🤖 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 `@internal/session/manager_test.go` around lines 4488 - 4492, Strengthen the Shutdown() async-stop assertion by checking the fake driver’s stopCalls counter alongside the proc.done check. In the relevant test, fail when h.driver.stopCalls is nonzero and report the observed count, ensuring the bound process was not stopped.internal/session/manager_prompt_event_storage.go (1)
67-71: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winDuplicate prompt-runtime fallback logic between
normalizeEventandenrichRecordedAgentEvent.Both functions perform the identical "clone snapshot, then fall back to
runtimeBindingSnapshot().selection" sequence. Extracting a shared helper would avoid the two call sites silently diverging on a future change.♻️ Proposed refactor
+func ensurePromptRuntime(event acp.AgentEvent, session *Session) acp.AgentEvent { + if session == nil || event.PromptRuntimeSnapshot() != nil { + return event + } + return event.WithPromptRuntime(promptRuntimeFromSelection(session.runtimeBindingSnapshot().selection)) +}Then in
normalizeEvent:- if normalized.PromptRuntimeSnapshot() == nil { - normalized = normalized.WithPromptRuntime( - promptRuntimeFromSelection(session.runtimeBindingSnapshot().selection), - ) - } + normalized = ensurePromptRuntime(normalized, session)And in
enrichRecordedAgentEvent:- enriched = enriched.WithPromptRuntime(event.PromptRuntimeSnapshot()) - if enriched.PromptRuntimeSnapshot() == nil { - enriched = enriched.WithPromptRuntime(promptRuntimeFromSelection(session.runtimeBindingSnapshot().selection)) - } + enriched = enriched.WithPromptRuntime(event.PromptRuntimeSnapshot()) + enriched = ensurePromptRuntime(enriched, session)Also applies to: 172-175
🤖 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 `@internal/session/manager_prompt_event_storage.go` around lines 67 - 71, Extract the duplicated prompt-runtime fallback sequence from normalizeEvent and enrichRecordedAgentEvent into a shared helper that preserves the existing snapshot check, cloning behavior, and runtimeBindingSnapshot().selection fallback. Replace both call sites with the helper so future changes apply consistently.internal/store/types_session.go (1)
59-70: 🗄️ Data Integrity & Integration | 🔵 Trivial | ⚡ Quick winConsider requiring
RuntimeFailurewhen status isfailed.
validateSessionRuntime(ininternal/store/session_runtime.go) enforces that afailedruntime status carries a non-emptySessionRuntimeTransition, but nothing enforces thatRuntimeFailure(the failure detail string) is also non-empty in that case. A session could persistRuntimeStatus: SessionRuntimeFailedwith an emptyRuntimeFailure, making the failure undiagnosable downstream (CLI/API/observe surfaces).If
RuntimeFailureis meant to always describe why binding failed, add that requirement alongside the existing transition check.♻️ Possible fix
func validateSessionRuntime(status SessionRuntimeStatus, transition SessionRuntimeTransition) error { ... if status == SessionRuntimeFailed && strings.TrimSpace(string(transition)) == "" { return fmt.Errorf("store: failed session runtime requires a transition strategy") } + return nil +}Note: this would need to thread
RuntimeFailureintovalidateSessionRuntime's signature (or a sibling check intypes_session.go), since it currently only receivesstatusandtransition.Also applies to: 111-116
🤖 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 `@internal/store/types_session.go` around lines 59 - 70, Update validateSessionRuntime and its callers to also receive RuntimeFailure, and require it to be non-empty whenever RuntimeStatus is SessionRuntimeFailed, alongside the existing transition validation. Preserve current validation for other statuses and ensure the Session struct validation path passes its RuntimeFailure value through.web/src/systems/network/mocks/fixtures.ts (1)
28-39: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueConsolidate the duplicate
sessionRuntimemock helper.
@/systems/session/mocks/fixtures.tsalready exports an equivalentsessionRuntime(provider, acpCaps?)helper, whileweb/src/systems/network/mocks/fixtures.tsre-implements it privately. Re-export or import a single shared helper so the runtime mock shape does not drift between fixtures.🤖 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 `@web/src/systems/network/mocks/fixtures.ts` around lines 28 - 39, Remove the private sessionRuntime implementation from the network mock fixtures and reuse the exported sessionRuntime helper from the session mock fixtures via import or re-export. Update references in the network fixtures to use that shared helper while preserving the existing provider and acpCaps behavior.internal/daemon/native_tools_test.go (1)
5589-5599: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winUnconditional
<-promptAcceptedhangs the suite when the prompt call fails early.If
session_promptis rejected before reachingSendPromptFn(schema/policy/workspace change),promptAcceptedis never closed and the test blocks until the package timeout instead of reporting the failure. Select over the call result as well.♻️ Fail fast instead of blocking
- <-promptAccepted - select { - case call := <-promptCalls: - t.Fatalf("Registry.Call(session_prompt) returned before its live stream closed: %#v", call) - default: - } + select { + case <-promptAccepted: + case call := <-promptCalls: + t.Fatalf("Registry.Call(session_prompt) returned before submission: %#v", call) + case <-time.After(10 * time.Second): + t.Fatal("Registry.Call(session_prompt) never reached SendPrompt") + } + select { + case call := <-promptCalls: + t.Fatalf("Registry.Call(session_prompt) returned before its live stream closed: %#v", call) + default: + }🤖 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 `@internal/daemon/native_tools_test.go` around lines 5589 - 5599, Update the test flow around promptAccepted and promptCalls so it does not unconditionally block on the acceptance signal. Select between promptCalls and promptAccepted, immediately fail the test with the returned error when Registry.Call(session_prompt) rejects before reaching SendPromptFn, and retain the existing live-stream closure assertion for successfully accepted prompts.web/src/components/assistant-ui/session-prompt-dispatch-store.ts (1)
47-52: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win
requestStartedsilently orphans an in-flight controller.If a second dispatch starts before the first completes, the previous
AbortControlleris dropped withoutabort(), so the first request keeps running and its laterrequestCompletedis discarded (controller mismatch). Consider aborting the superseded controller and bumpinggeneration, mirroringpendingCanceled.♻️ Abort the superseded controller
- requestStarted: (context, event) => ({ - ...context, - canceled: false, - controller: event.controller, - pending: true, - }), + requestStarted: (context, event, enqueue) => { + const previous = context.controller; + if (previous !== null && previous !== event.controller) { + enqueue.effect(() => previous.abort()); + } + return { + ...context, + canceled: false, + controller: event.controller, + generation: previous === null ? context.generation : context.generation + 1, + pending: true, + }; + },🤖 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 `@web/src/components/assistant-ui/session-prompt-dispatch-store.ts` around lines 47 - 52, Update requestStarted to abort any existing context.controller before replacing it with event.controller, and increment generation when superseding an in-flight request, mirroring pendingCanceled. Preserve the new request’s pending state and controller while ensuring the prior request is canceled and cannot leave stale work running.web/src/components/assistant-ui/hooks/use-session-composer-state.ts (1)
56-65: 🩺 Stability & Availability | 🔵 TrivialSynchronize draft updates with live composer text before applying persisted state.
composerDraftChangedis synchronous, so the current keystroke path doesn’t drop characters. But if draft persistence is made async/debounced later, this effect can apply a laggingdraftTextand overwrite the live input; keep the persisted draft out of thesetTextcall when it cannot stay in sync with the user’s current text.🤖 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 `@web/src/components/assistant-ui/hooks/use-session-composer-state.ts` around lines 56 - 65, Update the useLayoutEffect synchronization logic in the session composer state hook so persisted draftText is not passed to aui.composer().setText when it may be stale relative to the live composer text; validate or synchronize the current composer text before applying persisted state, while preserving the existing session hydration guard and normal draft restoration behavior.web/src/systems/session/hooks/use-session-prompt-runtime.ts (1)
18-20: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winReuse the exported
SessionRuntimeEffectivealias instead of re-deriving it.
web/src/systems/session/types.ts(line 15) now exports exactly this type; the inlineimport("../types")form duplicates it and will drift.♻️ Suggested change
-type SessionRuntimeEffective = NonNullable< - NonNullable<import("../types").SessionPayload["runtime"]>["effective"] ->; +import type { SessionRuntimeEffective } from "../types";(place the import with the other
../typesimports)🤖 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 `@web/src/systems/session/hooks/use-session-prompt-runtime.ts` around lines 18 - 20, Update the session prompt runtime type references to import and reuse the exported SessionRuntimeEffective alias from ../types alongside the existing type imports, then remove the locally re-derived alias definition.web/src/systems/session/hooks/use-session-create-dialog.ts (2)
114-118: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick winMissing agent aborts submit with no user feedback.
Unlike the participation and workspace-path branches, an empty
agentNamereturns silently and leavessubmitErroruntouched, so the dialog appears inert. Route it throughvalidationFailedfor consistency.🛠️ Suggested fix
- if (agentName.length === 0) return; + if (agentName.length === 0) { + store.trigger.validationFailed({ message: "Select an agent to start a session." }); + return; + }🤖 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 `@web/src/systems/session/hooks/use-session-create-dialog.ts` around lines 114 - 118, Update submit in use-session-create-dialog so an empty trimmed agentName calls validationFailed before returning, instead of silently returning. Preserve the existing validation flow and feedback behavior used by the participation and workspace-path checks.
96-97: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value
selectedAgentlookup no longer changes the result.
selectedAgent?.namecan only ever bedraft.agentName(the predicate matches on that name), so the fallback makes the lookup redundant now that first-agent defaulting is gone. Either drop the lookup or useselectedAgentfor validation (e.g. reject an agent that isn't inagentList).🤖 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 `@web/src/systems/session/hooks/use-session-create-dialog.ts` around lines 96 - 97, The selectedAgent lookup in the session creation dialog is redundant because its name always equals draft.agentName when found. Remove selectedAgent and derive selectedAgentName directly from draft.agentName, unless the flow needs to validate membership in agentList; do not retain the current no-op fallback.web/src/systems/session/hooks/__tests__/use-session-prompt-runtime.test.tsx (1)
43-50: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueType
authStatewith the payload's auth-state union.
authState: stringplus theas ProviderSummarycast lets invalid states compile, weakening the fixture as a contract check.♻️ Suggested typing
-function provider(name: string, authState: string): ProviderSummary { +function provider( + name: string, + authState: NonNullable<ProviderSummary["auth_status"]>["state"] +): ProviderSummary {🤖 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 `@web/src/systems/session/hooks/__tests__/use-session-prompt-runtime.test.tsx` around lines 43 - 50, Update the provider fixture helper’s authState parameter to use the payload’s auth-state union type rather than string, and remove the broad ProviderSummary cast so invalid states are rejected at compile time while preserving the existing fixture fields.web/src/systems/session/contexts/session-prompt-runtime-context.tsx (1)
22-29: 🚀 Performance & Scalability | 🔵 Trivial | 💤 Low value
inputis recreated each render, so the sync effect runs on every render.
sessionPromptRuntimeInputreturns a fresh object, so[input, store]never stays stable. Correctness is saved only bysameInputno-op inside the store. Memoizing on the primitive inputs keeps the effect a genuine external-system sync.♻️ Suggested memoization
- const input = sessionPromptRuntimeInput(session, canPrompt); + const input = useMemo(() => sessionPromptRuntimeInput(session, canPrompt), [session, canPrompt]);(add
useMemoto the React import)🤖 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 `@web/src/systems/session/contexts/session-prompt-runtime-context.tsx` around lines 22 - 29, Memoize the input created by sessionPromptRuntimeInput in the session prompt runtime context using useMemo, with its primitive source values as dependencies. Keep the existing store binding and inputUpdated effect unchanged so the effect only synchronizes when the underlying input values change.web/src/systems/session/hooks/__tests__/use-session-create-dialog.test.tsx (1)
227-229: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winOrdering assertion inside the
navigatemock can be swallowed.If this
expectthrows, the rejection is handled by the store's navigation execution path and the test may still pass. Assert ordering explicitly instead.♻️ Deterministic ordering assertion
- mockNavigate.mockImplementation(async () => { - expect(mockActivateWorkspace).toHaveBeenCalledWith(sessionInOtherWorkspace); - }); + mockNavigate.mockResolvedValue(undefined);and after
waitFor:expect(mockActivateWorkspace).toHaveBeenCalledWith(sessionInOtherWorkspace); expect(mockActivateWorkspace.mock.invocationCallOrder[0]).toBeLessThan( mockNavigate.mock.invocationCallOrder[0] );🤖 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 `@web/src/systems/session/hooks/__tests__/use-session-create-dialog.test.tsx` around lines 227 - 229, Move the activation assertion out of the mockNavigate implementation in the session creation dialog test so failures cannot be swallowed by the navigation execution path. After the existing waitFor, assert mockActivateWorkspace was called with sessionInOtherWorkspace and explicitly verify its first invocation order precedes mockNavigate’s first invocation using their invocationCallOrder values.
🤖 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 `@internal/api/contract/prompt_runtime_selection.go`:
- Around line 12-17: Update the runtime selection conversion to apply
strings.TrimSpace to payload.Provider, payload.Model, and the string-converted
payload.ReasoningEffort before assigning them to session.RuntimeSelection,
matching runtimeSelectionPayloadFromInfo and SessionPayloadFromStoreInfo while
leaving Speed unchanged.
In `@internal/api/core/handlers_test.go`:
- Around line 215-250: Add API-level tests alongside the session handler
coverage using performRequest and fixture.Engine for ACP NegotiationError and
provider-auth failures. Assert the HTTP response preserves each error’s
ErrorPayload.Diagnostic.code, evidence, and SuggestedCommand, including the
expected negotiation/provider-auth diagnostic values rather than only checking
the status.
In `@internal/extension/host_api_test.go`:
- Around line 532-670: Wrap the bodies of
TestHostAPIHandlerSessionReadsProjectNestedRuntime and
TestHostAPIHandlerSessionsPromptReturnsQueuedRuntimeAdmission in t.Run subtests
named with the required “Should ...” pattern. Keep t.Parallel and all existing
setup and assertions within the corresponding subtest, matching the repository’s
established test structure.
In `@internal/observe/reconcile.go`:
- Around line 153-178: Update the session projection in the reconcile path to
apply strings.TrimSpace to meta.Model, meta.ReasoningEffort, and
meta.RuntimeFailure, matching sessionInfoFromCatalog and
sessionInfoFromSandboxReconcileMeta while leaving the other field mappings
unchanged.
In `@internal/session/manager_managed_input_submit.go`:
- Around line 29-59: Extend managedInput and managedInputFromQueueEntry to
retain the queued runtime snapshot by adding and copying
store.SessionInputRuntime from entry.Runtime. Update managedInputPromptRequest
and the related dispatch path to forward this runtime data into prompt runtime
selection, preserving provider, model, reasoning effort, and speed for queued
and steered prompts.
In `@internal/session/manager_process_watchers.go`:
- Around line 5-14: The helper ensureProcessWatchContext requires processWatchMu
to protect its writes, but manager_defaults.go calls it without holding that
mutex. Rename it to ensureProcessWatchContextLocked and update every caller to
acquire processWatchMu before invoking it, or document the locking requirement
if preserving the existing name.
In `@internal/session/manager_prompt_runtime.go`:
- Around line 153-158: Update the rollback branch in the session lifecycle flow
around persistSessionLifecycleState to persist the restored binding using
runtimeCleanupContext() instead of the failing request ctx. Keep the existing
restoreRuntimeBinding, candidate shutdown, and joined-error behavior unchanged.
In `@internal/session/manager_prompt_submit.go`:
- Around line 42-52: Update GoalDispatchPrompt’s reject-if-busy flow so
turn.start is not left uncompensated when prompt admission fails with
ErrPromptInProgress. Move dispatchTurnStart until after successful slot
reacquisition, or emit the existing turn.end/hook-cancellation compensation
before returning the busy goal-draft result; preserve normal turn lifecycle
behavior for successful admissions.
In `@internal/session/manager_transition.go`:
- Around line 123-149: The catalog update path must persist runtime selection
state after non-register prompt-runtime binding. Update
sessionCatalogStateUpdate() and its caller in UpdateSessionState() to write
provider/model, reasoning effort, speed resolution, runtime status/transition,
and runtime failure, or replace that path with an equivalent full upsert using
the complete session data.
In `@internal/session/provider_lifecycle_test.go`:
- Around line 85-99: Protect the fakeDriver hook assignments in the test with
h.driver.mu, matching the mutex used when fakeDriver operations read stopHook
and startHook. Lock around each assignment, including the stopHook callback
setup before SendPrompt, and release the mutex immediately after assignment.
In `@internal/session/runtime.go`:
- Around line 62-66: Update NormalizeRuntimeSelection’s ReasoningEffort
validation branch to wrap the ValidateReasoningEffort error with
ErrInvalidRuntimeOverride using the requested dual-wrapping format, while
preserving the existing validation and early-return behavior.
In `@internal/session/session_test.go`:
- Around line 241-243: Extend the session fixture assertions in
internal/session/session_test.go at lines 241-243 and 286-286 to verify the
configured runtime metadata through Meta(), Info(), and ReadSessionMeta():
assert ready status, initial-bind transition, and ACP session ID for the first
fixture, and unbound status for the second. Keep these checks focused on the
existing state-management and projection tests.
In `@internal/store/meta_test.go`:
- Line 27: Update both metadata read-back tests in internal/store/meta_test.go
to explicitly compare readBack.RuntimeStatus with SessionRuntimeReady, alongside
the existing metadata assertions. Ensure the assertions validate the persisted
“ready” status for both fixtures and preserve outcome-based verification.
In `@internal/store/session_meta_types.go`:
- Around line 38-40: Update validateSessionRuntime or the SessionMeta read path
to normalize a missing or empty runtime_status from legacy session.json files to
the unbound runtime status before validation. Preserve validation of all
explicitly provided runtime status enum values.
In `@internal/tools/builtin/sessions.go`:
- Around line 127-133: Replace the positional `descriptors[1]` and
`descriptors[2]` mutations in `sessionDescriptors` with the same explicit
descriptor-construction pattern used by `sessionListDescriptor`, attaching each
output schema directly to its corresponding session tool. Ensure schemas remain
associated by tool identity rather than `sessionTools` ordering.
In `@sdk/go/contracts/types_011_gen.go`:
- Around line 10-37: Regenerate the Go SDK contracts so the stale
MemoryStoreParams and MessageAttachment types are removed, and update
HostAPIMemoryStoreContract to no longer reference them. Verify generated
declarations and related fields consistently reflect the intended contract
removal.
In `@web/src/systems/session/components/session-create-advanced-section.tsx`:
- Around line 49-67: Update WorkspaceCommandSelect to accept an accessibility
prop for the trigger, such as ariaLabelledby or triggerId, and pass the
corresponding FieldTitle id "session-create-workspace-label" from the session
create advanced section. Ensure the rendered workspace select trigger associates
with that label while preserving existing props and behavior.
In `@web/src/systems/session/mocks/__tests__/handlers.test.ts`:
- Around line 55-80: Update the createSession request in the session-create test
to remove the prompt field from the POST payload, while preserving agent_name,
workspace, headers, and the existing response assertions.
In `@web/src/systems/session/stores/session-prompt-runtime-store.ts`:
- Around line 84-102: Update sessionPromptRuntimeInput and remove the throwing
requireWorkspaceId path so missing or whitespace-only session.workspace_id
produces degraded input instead of an exception. Derive workspaceId only from
the valid outer session/workspace value, set canPrompt to false when no valid
workspace is available, and preserve normal prompting for valid workspaces;
defer adding an error boundary until this input path is safe.
---
Outside diff comments:
In `@internal/api/udsapi/transport_parity_integration_test.go`:
- Around line 686-696: Update the stopResp error-handling block in the UDS
stop-session test to check and handle errors from io.ReadAll and
stopResp.Body.Close instead of assigning them to _. Match the explicit
error-checking pattern already used by the nearby resumeResp handling, while
preserving the existing failure message and status validation.
In `@internal/cli/session_list.go`:
- Around line 123-132: Update the JSONL serialization path in sessionListBundle
so writeJSONLine receives a SessionRecord whose runtime provider matches
sessionRuntimeProvider(item), including the Runtime.Effective.Provider
projection. Preserve the existing displayed-row and other output-mode behavior
while applying this projection specifically to JSONL output.
In `@internal/session/manager_input_dispatch.go`:
- Around line 89-100: Update dispatchHumanQueuedInput so the !ok branch after
newQueuedInputPromptRequest handles the claimed entry consistently with
handleQueuedInputDispatchError: release or mark the entry failed as appropriate,
then call m.startNextQueuedInputPrompt(target) before returning. Ensure failed
prompt-request construction cannot leave the queue stalled.
In `@internal/store/globaldb/sqlcgen/session_core.sql.go`:
- Around line 265-315: The session upsert’s optimistic-concurrency guard must
not reject current runtime lifecycle updates because of stale network metadata.
Update the conflict handling around UpsertSessionParams and its ON CONFLICT
WHERE clause to include the relevant Runtime* fields in the comparison, or
separate runtime lifecycle updates from the network-guarded path; preserve the
existing network protections while ensuring runtime status and transition
changes are applied.
In `@sdk/go/contracts/types_019_gen.go`:
- Around line 248-289: Update the migration/upgrade notes for external Go SDK
consumers to document that Provider was removed from SessionStatus and
SessionSummary, while ACPSessionID is now accessed through
SessionRuntimePayload. Add this alongside the existing SDK incompatibility and
provider-name mapping guidance, without changing the generated types.
---
Nitpick comments:
In `@internal/api/httpapi/httpapi_integration_test.go`:
- Around line 712-719: Add t.Parallel() at the beginning of the closures for the
new stream cursor, stop reason, and crash stop reason subtests, including the
test invoking
exerciseHTTPSessionStreamReconnectPreservesCursorWhenNoNewEventsExistYet. Keep
each subtest’s existing body and helper calls unchanged.
In `@internal/daemon/native_tools_test.go`:
- Around line 5589-5599: Update the test flow around promptAccepted and
promptCalls so it does not unconditionally block on the acceptance signal.
Select between promptCalls and promptAccepted, immediately fail the test with
the returned error when Registry.Call(session_prompt) rejects before reaching
SendPromptFn, and retain the existing live-stream closure assertion for
successfully accepted prompts.
In `@internal/session/additional_test.go`:
- Around line 365-378: Wrap the unbound-runtime bind failure scenario in a
dedicated t.Run subtest named with the required “Should ...” pattern within
TestPromptErrorPaths. Keep the existing setup, startHook error injection, Prompt
invocation, and assertion together inside that subtest.
In `@internal/session/manager_prompt_event_storage.go`:
- Around line 67-71: Extract the duplicated prompt-runtime fallback sequence
from normalizeEvent and enrichRecordedAgentEvent into a shared helper that
preserves the existing snapshot check, cloning behavior, and
runtimeBindingSnapshot().selection fallback. Replace both call sites with the
helper so future changes apply consistently.
In `@internal/session/manager_start_meta.go`:
- Around line 11-32: Change sessionStartSpecFromMeta to accept
workspacepkg.ResolvedWorkspace by value instead of a pointer, and update its
caller in the session-start flow to pass resolvedWorkspace directly. Preserve
the existing spec.workspace copy assignment while eliminating the unconditional
pointer dereference.
In `@internal/session/manager_start_test.go`:
- Around line 161-192: Extend the “Should preserve an empty transcript when
initial binding fails” test to assert the rollback state after SendPrompt
returns startErr: the session must have RuntimeStatusUnbound with RuntimeFailure
populated, and the durable metadata must report the same runtime state. Use the
existing session/runtime inspection APIs and meta symbols used by
restoreRuntimeBinding, while preserving the transcript and cleanup assertions.
In `@internal/session/manager_start.go`:
- Around line 52-55: Update the error wrapping in the session-start flow around
sessionStartSpecFromMeta to use a neutral description of the helper failure
rather than specifically naming resume-speed validation, while preserving
meta.ID context and the wrapped error.
In `@internal/session/manager_test.go`:
- Around line 4488-4492: Strengthen the Shutdown() async-stop assertion by
checking the fake driver’s stopCalls counter alongside the proc.done check. In
the relevant test, fail when h.driver.stopCalls is nonzero and report the
observed count, ensuring the bound process was not stopped.
In `@internal/store/types_session.go`:
- Around line 59-70: Update validateSessionRuntime and its callers to also
receive RuntimeFailure, and require it to be non-empty whenever RuntimeStatus is
SessionRuntimeFailed, alongside the existing transition validation. Preserve
current validation for other statuses and ensure the Session struct validation
path passes its RuntimeFailure value through.
In `@web/src/components/assistant-ui/hooks/use-session-composer-state.ts`:
- Around line 56-65: Update the useLayoutEffect synchronization logic in the
session composer state hook so persisted draftText is not passed to
aui.composer().setText when it may be stale relative to the live composer text;
validate or synchronize the current composer text before applying persisted
state, while preserving the existing session hydration guard and normal draft
restoration behavior.
In `@web/src/components/assistant-ui/session-prompt-dispatch-store.ts`:
- Around line 47-52: Update requestStarted to abort any existing
context.controller before replacing it with event.controller, and increment
generation when superseding an in-flight request, mirroring pendingCanceled.
Preserve the new request’s pending state and controller while ensuring the prior
request is canceled and cannot leave stale work running.
In `@web/src/systems/network/mocks/fixtures.ts`:
- Around line 28-39: Remove the private sessionRuntime implementation from the
network mock fixtures and reuse the exported sessionRuntime helper from the
session mock fixtures via import or re-export. Update references in the network
fixtures to use that shared helper while preserving the existing provider and
acpCaps behavior.
In `@web/src/systems/session/contexts/session-prompt-runtime-context.tsx`:
- Around line 22-29: Memoize the input created by sessionPromptRuntimeInput in
the session prompt runtime context using useMemo, with its primitive source
values as dependencies. Keep the existing store binding and inputUpdated effect
unchanged so the effect only synchronizes when the underlying input values
change.
In `@web/src/systems/session/hooks/__tests__/use-session-create-dialog.test.tsx`:
- Around line 227-229: Move the activation assertion out of the mockNavigate
implementation in the session creation dialog test so failures cannot be
swallowed by the navigation execution path. After the existing waitFor, assert
mockActivateWorkspace was called with sessionInOtherWorkspace and explicitly
verify its first invocation order precedes mockNavigate’s first invocation using
their invocationCallOrder values.
In `@web/src/systems/session/hooks/__tests__/use-session-prompt-runtime.test.tsx`:
- Around line 43-50: Update the provider fixture helper’s authState parameter to
use the payload’s auth-state union type rather than string, and remove the broad
ProviderSummary cast so invalid states are rejected at compile time while
preserving the existing fixture fields.
In `@web/src/systems/session/hooks/use-session-create-dialog.ts`:
- Around line 114-118: Update submit in use-session-create-dialog so an empty
trimmed agentName calls validationFailed before returning, instead of silently
returning. Preserve the existing validation flow and feedback behavior used by
the participation and workspace-path checks.
- Around line 96-97: The selectedAgent lookup in the session creation dialog is
redundant because its name always equals draft.agentName when found. Remove
selectedAgent and derive selectedAgentName directly from draft.agentName, unless
the flow needs to validate membership in agentList; do not retain the current
no-op fallback.
In `@web/src/systems/session/hooks/use-session-prompt-runtime.ts`:
- Around line 18-20: Update the session prompt runtime type references to import
and reuse the exported SessionRuntimeEffective alias from ../types alongside the
existing type imports, then remove the locally re-derived alias definition.
🪄 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 remediation summaryCommit Correctness fixes
Web fixes
Findings verified as non-actionable
Validation
Compozy Impact Audit
All review threads are resolved. Fresh CI on |
There was a problem hiding this comment.
Actionable comments posted: 2
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
internal/store/session_runtime.go (1)
29-54: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick winAdd a test case for failed session runtime failure validation.
validateSessionRuntimerejectsSessionRuntimeFailedwhenfailureis empty, but there are no Go tests exercising this rule. Add a table-driven case forStatus: SessionRuntimeFailedwith an empty failure message.🤖 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 `@internal/store/session_runtime.go` around lines 29 - 54, Add a table-driven test case covering validateSessionRuntime with Status set to SessionRuntimeFailed and an empty failure message, asserting validation returns an error. Reuse the existing test structure and expected-error conventions, while providing a valid transition so the failure-message rule is specifically exercised.
🧹 Nitpick comments (6)
internal/store/store_helpers_test.go (1)
160-201: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winRun the added table cases in parallel.
These cases execute serially because the shared
t.Runbody does not callt.Parallel(). Add it there; the validation closures only read immutable fixtures.As per coding guidelines, “Go tests must use
Should …subtest names, default tot.Parallel.”🤖 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 `@internal/store/store_helpers_test.go` around lines 160 - 201, Add t.Parallel() to the shared t.Run body that executes these validation table cases, while preserving the existing “Should …” subtest names and validation behavior.Source: Coding guidelines
internal/store/globaldb/global_db_test.go (1)
998-1059: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winWrap this scenario in a
Should …subtest.The updated integration scenario runs directly in
TestGlobalDBRegisterUpdateAndListSessions; move its body intot.Run("Should persist runtime replacement fields", ...).As per path instructions, “MUST use t.Run("Should...") pattern for ALL test cases.”
🤖 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 `@internal/store/globaldb/global_db_test.go` around lines 998 - 1059, Wrap the runtime replacement persistence scenario in TestGlobalDBRegisterUpdateAndListSessions inside a t.Run subtest named "Should persist runtime replacement fields". Move the related setup, updates, ListSessions call, and assertions into that subtest while preserving their behavior and ensuring the required Should-prefixed pattern is used.Source: Path instructions
internal/session/manager_transition_test.go (1)
52-58: 🎯 Functional Correctness | 🔵 Trivial | 🏗️ Heavy liftExercise a bound runtime before asserting propagation.
createSessionis promptless/unbound, and the catalog was registered from the same info before stopping. This equality check still passes if the update omits runtime fields. Bind non-default provider/model/status data first and assert a non-nilSpeedResolutiontoo.As per path instructions, “MUST test meaningful business logic” and “Verify tests can fail when business logic changes.”
🤖 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 `@internal/session/manager_transition_test.go` around lines 52 - 58, Strengthen the propagation test around createSession and the stopping catalog by binding non-default provider, model, and runtime status data before issuing the stop request, rather than relying on the promptless unbound session. Extend the assertion to require a non-nil SpeedResolution and verify its propagated value, ensuring the test fails when runtime-field propagation is omitted.Source: Path instructions
web/src/components/assistant-ui/hooks/use-session-composer-state.ts (1)
57-66: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueLocal
composerTextshadows the state selector value.Line 59 declares
composerTextinside the effect while line 20 already binds acomposerTextfromuseAuiState. Renaming the local (e.g.currentComposerText) makes the hydration guard easier to read and avoids accidental use of the stale render-scoped value later.♻️ Suggested rename
- const composerText = aui.composer().getState().text; - if (sameSession && composerText !== hydratedDraftTextRef.current) { + const currentComposerText = aui.composer().getState().text; + if (sameSession && currentComposerText !== hydratedDraftTextRef.current) { return; }🤖 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 `@web/src/components/assistant-ui/hooks/use-session-composer-state.ts` around lines 57 - 66, Rename the local composer text variable inside the useLayoutEffect in useSessionComposerState, such as to currentComposerText, and update the sameSession hydration guard to use it; leave the composerText value returned by useAuiState unchanged.internal/api/httpapi/handlers_test.go (1)
2635-2638: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueDrop the redundant loop-variable copy.
Since Go 1.22 loop variables are per-iteration, so
testCase := testCaseis unnecessary.♻️ Suggested cleanup
for _, testCase := range testCases { - testCase := testCase t.Run(testCase.name, func(t *testing.T) {🤖 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 `@internal/api/httpapi/handlers_test.go` around lines 2635 - 2638, Remove the redundant testCase := testCase assignment in the testCases loop while keeping the parallel subtest structure and existing test behavior unchanged.internal/session/manager_prompt_event_storage.go (1)
74-80: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueClarify the snapshot materialization.
WithPromptRuntime(event.PromptRuntimeSnapshot())creates a new event with a cloned snapshot payload. If that cloning is intentional, add a short comment; otherwise this assignment can be omitted.🤖 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 `@internal/session/manager_prompt_event_storage.go` around lines 74 - 80, Clarify the intent of the initial assignment in promptRuntimeFallbackForEvent: if cloning event.PromptRuntimeSnapshot() via WithPromptRuntime is required, add a brief comment explaining the snapshot materialization; otherwise remove that assignment while preserving the existing nil-session and fallback behavior.
🤖 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 `@internal/store/meta_test.go`:
- Around line 64-66: Update the metadata tests in internal/store/meta_test.go at
lines 64-66 and 161-163: wrap the round-trip scenario in t.Run("Should persist
ready runtime status", ...) and wrap the concurrent-write scenario in a
corresponding descriptive “Should …” subtest, preserving each scenario’s
existing assertions and behavior.
In `@web/src/systems/session/hooks/__tests__/use-session-create-dialog.test.tsx`:
- Around line 244-247: Update the test around mockActivateWorkspace and
mockNavigate to explicitly assert that mockNavigate was called before comparing
invocationCallOrder, then retain the ordering assertion to verify activation
precedes navigation without an invocation-order fallback.
---
Outside diff comments:
In `@internal/store/session_runtime.go`:
- Around line 29-54: Add a table-driven test case covering
validateSessionRuntime with Status set to SessionRuntimeFailed and an empty
failure message, asserting validation returns an error. Reuse the existing test
structure and expected-error conventions, while providing a valid transition so
the failure-message rule is specifically exercised.
---
Nitpick comments:
In `@internal/api/httpapi/handlers_test.go`:
- Around line 2635-2638: Remove the redundant testCase := testCase assignment in
the testCases loop while keeping the parallel subtest structure and existing
test behavior unchanged.
In `@internal/session/manager_prompt_event_storage.go`:
- Around line 74-80: Clarify the intent of the initial assignment in
promptRuntimeFallbackForEvent: if cloning event.PromptRuntimeSnapshot() via
WithPromptRuntime is required, add a brief comment explaining the snapshot
materialization; otherwise remove that assignment while preserving the existing
nil-session and fallback behavior.
In `@internal/session/manager_transition_test.go`:
- Around line 52-58: Strengthen the propagation test around createSession and
the stopping catalog by binding non-default provider, model, and runtime status
data before issuing the stop request, rather than relying on the promptless
unbound session. Extend the assertion to require a non-nil SpeedResolution and
verify its propagated value, ensuring the test fails when runtime-field
propagation is omitted.
In `@internal/store/globaldb/global_db_test.go`:
- Around line 998-1059: Wrap the runtime replacement persistence scenario in
TestGlobalDBRegisterUpdateAndListSessions inside a t.Run subtest named "Should
persist runtime replacement fields". Move the related setup, updates,
ListSessions call, and assertions into that subtest while preserving their
behavior and ensuring the required Should-prefixed pattern is used.
In `@internal/store/store_helpers_test.go`:
- Around line 160-201: Add t.Parallel() to the shared t.Run body that executes
these validation table cases, while preserving the existing “Should …” subtest
names and validation behavior.
In `@web/src/components/assistant-ui/hooks/use-session-composer-state.ts`:
- Around line 57-66: Rename the local composer text variable inside the
useLayoutEffect in useSessionComposerState, such as to currentComposerText, and
update the sameSession hydration guard to use it; leave the composerText value
returned by useAuiState unchanged.
🪄 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: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro Plus
Run ID: e0ed0bfe-60f6-4613-86d4-b7ce53a362c7
📒 Files selected for processing (56)
internal/api/contract/contract_test.gointernal/api/contract/prompt_runtime_selection.gointernal/api/httpapi/handlers_test.gointernal/api/httpapi/httpapi_integration_test.gointernal/api/udsapi/transport_parity_integration_test.gointernal/daemon/native_tools_test.gointernal/extension/build_runner_unix_test.gointernal/extension/host_api_test.gointernal/observe/reconcile.gointernal/observe/reconcile_test.gointernal/session/additional_test.gointernal/session/manager_busy_input_test.gointernal/session/manager_defaults.gointernal/session/manager_input_dispatch.gointernal/session/manager_managed_input_submit.gointernal/session/manager_process_watchers.gointernal/session/manager_prompt_event_storage.gointernal/session/manager_prompt_runtime.gointernal/session/manager_prompt_submit.gointernal/session/manager_start.gointernal/session/manager_start_meta.gointernal/session/manager_start_test.gointernal/session/manager_test.gointernal/session/manager_transition.gointernal/session/manager_transition_test.gointernal/session/provider_lifecycle_test.gointernal/session/runtime.gointernal/session/session_test.gointernal/store/globaldb/global_db_runtime_metadata_cut.gointernal/store/globaldb/global_db_session.gointernal/store/globaldb/global_db_session_scan.gointernal/store/globaldb/global_db_test.gointernal/store/meta_test.gointernal/store/session_meta_types.gointernal/store/session_runtime.gointernal/store/store_helpers_test.gointernal/store/types_session.gointernal/tools/builtin/sessions.goweb/src/components/assistant-ui/__tests__/session-thread.test.tsxweb/src/components/assistant-ui/hooks/use-session-composer-state.tsweb/src/components/assistant-ui/session-prompt-dispatch-store.tsweb/src/systems/network/mocks/fixtures.tsweb/src/systems/session/components/__tests__/session-chat-runtime-provider.test.tsxweb/src/systems/session/components/session-create-advanced-section.tsxweb/src/systems/session/contexts/session-prompt-runtime-context.tsxweb/src/systems/session/hooks/__tests__/use-session-create-dialog.test.tsxweb/src/systems/session/hooks/__tests__/use-session-prompt-runtime.test.tsxweb/src/systems/session/hooks/use-session-create-dialog.tsweb/src/systems/session/hooks/use-session-prompt-runtime.tsweb/src/systems/session/mocks/__tests__/handlers.test.tsweb/src/systems/session/mocks/fixtures.tsweb/src/systems/session/mocks/index.tsweb/src/systems/session/stores/__tests__/session-prompt-runtime-store.test.tsweb/src/systems/session/stores/session-prompt-runtime-store.tsweb/src/systems/workspace/components/__tests__/workspace-command-select.test.tsxweb/src/systems/workspace/components/workspace-command-select.tsx
💤 Files with no reviewable changes (1)
- web/src/systems/session/mocks/tests/handlers.test.ts
🚧 Files skipped from review as they are similar to previous changes (1)
- web/src/systems/session/hooks/use-session-prompt-runtime.ts
| if readBack.RuntimeStatus != SessionRuntimeReady { | ||
| t.Fatalf("ReadSessionMeta().RuntimeStatus = %q, want %q", readBack.RuntimeStatus, SessionRuntimeReady) | ||
| } |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win
Use required Should … subtests for these metadata cases.
internal/store/meta_test.go#L64-L66: wrap the round-trip scenario int.Run("Should persist ready runtime status", ...).internal/store/meta_test.go#L161-L163: wrap the concurrent-write scenario in a correspondingShould …subtest.
As per coding guidelines, “Go tests must use Should … subtest names.”
📍 Affects 1 file
internal/store/meta_test.go#L64-L66(this comment)internal/store/meta_test.go#L161-L163
🤖 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 `@internal/store/meta_test.go` around lines 64 - 66, Update the metadata tests
in internal/store/meta_test.go at lines 64-66 and 161-163: wrap the round-trip
scenario in t.Run("Should persist ready runtime status", ...) and wrap the
concurrent-write scenario in a corresponding descriptive “Should …” subtest,
preserving each scenario’s existing assertions and behavior.
Source: Coding guidelines
| expect(mockActivateWorkspace).toHaveBeenCalledWith(sessionInOtherWorkspace); | ||
| expect(mockActivateWorkspace.mock.invocationCallOrder[0]).toBeLessThan( | ||
| mockNavigate.mock.invocationCallOrder[0] ?? Number.POSITIVE_INFINITY | ||
| ); |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
Ordering assertion can pass when navigate never ran.
The ?? Number.POSITIVE_INFINITY fallback makes the comparison succeed if mockNavigate was never invoked, so a regression that drops navigation entirely would not fail here. Assert the navigation call explicitly before comparing invocation order.
💚 Proposed fix
expect(mockActivateWorkspace).toHaveBeenCalledWith(sessionInOtherWorkspace);
+ expect(mockNavigate).toHaveBeenCalledTimes(1);
expect(mockActivateWorkspace.mock.invocationCallOrder[0]).toBeLessThan(
- mockNavigate.mock.invocationCallOrder[0] ?? Number.POSITIVE_INFINITY
+ mockNavigate.mock.invocationCallOrder[0]
);📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| expect(mockActivateWorkspace).toHaveBeenCalledWith(sessionInOtherWorkspace); | |
| expect(mockActivateWorkspace.mock.invocationCallOrder[0]).toBeLessThan( | |
| mockNavigate.mock.invocationCallOrder[0] ?? Number.POSITIVE_INFINITY | |
| ); | |
| expect(mockActivateWorkspace).toHaveBeenCalledWith(sessionInOtherWorkspace); | |
| expect(mockNavigate).toHaveBeenCalledTimes(1); | |
| expect(mockActivateWorkspace.mock.invocationCallOrder[0]).toBeLessThan( | |
| mockNavigate.mock.invocationCallOrder[0] | |
| ); |
🤖 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 `@web/src/systems/session/hooks/__tests__/use-session-create-dialog.test.tsx`
around lines 244 - 247, Update the test around mockActivateWorkspace and
mockNavigate to explicitly assert that mockNavigate was called before comparing
invocationCallOrder, then retain the ordering assertion to verify activation
precedes navigation without an invocation-order fallback.
Summary
Changes
Session runtime lifecycle
Prompt snapshots and transitions
Session creation and web UX
Structured and agent-managed surfaces
compozy__session_createto create promptless logical sessions.compozy__session_promptto accept the nested runtime selection used by the daemon.Runtime and persistence hardening
Research basis
.resources/synaraand.resources/opendesign..repoclone.rc.Breaking changes
session.runtimeprojection.Migrations and configuration
00029_schema.sqland00030_schema.sqland update the declarative schema, Atlas checksum, and generated sqlc code.config.tomlkeys or defaults changed.Release notes
Features
Bug fixes
QA
Final status: Behavioral PASS; the full engineering gate is current.
clean: trueand no surviving lab processes.Evidence:
Deep review
Compozy Impact Audit
compozy__session_createandcompozy__session_prompt, their descriptors, input/output schemas, digests, registry coverage, availability behavior, and capability gates.workspace_idremains propagated and covered through CLI, HTTP, UDS, core, store, web, SSE, cache, events, queues, and replay so session runtime data cannot cross workspace boundaries.skills/compozy/references/native-tools.mdandskills/compozy/references/runtime-operations.mdfor promptless creation and prompt-bound runtime selection.Test plan
make gate-full— PASS CURRENT for fingerprintcf66e95f4ff5db7b655fa80917d5d5087f0faf94.Summary by CodeRabbit
New Features
Bug Fixes