Repository navigation
refactor(native-chat): structured chat failures always reach the diagnostics log - #24312
Conversation
The structured chat runtime took an optional onError callback that the desktop never passed, so a late dispatch settlement, an unanswered-dispatch release, a journal event-sink write and a provider lifecycle delivery that failed were dropped with no trace. Other host failures went to scattered console.warn calls, which reach nothing in a packaged desktop build. The runtime and host now take one required logger (warn/error with a scope and fields). The production logger writes each entry as a failed span to <userData>/logs/main.trace.ndjson, which the diagnostic bundle collects, and to the console (stderr under a supervised headless host). The runtime and the host wrap it so a logger that throws never fails what it reports, and the install refuses without one. Sites that deliberately kept a recovery-capsule error out of the log still log no error object.
… and give orcad its trace file The delivery loop, idle sweep, queued-message drain, lease renewer, event sink, conversation map and provider start/exit settlement each took an internal error callback that the host mapped onto the logger. They now take the logger itself and log under their own scope. The event sink keeps one onFailed hook, which decides whether to stop the provider, not whether to report. The dead-generation settlement returns its failure so each caller logs it under its own scope. orcad now installs the desktop's local trace sink under its own data root, so a headless host's chat failures reach <data-root>/logs/main.trace.ndjson as well as stderr. Also passes the logger in the test fixtures the first commit missed, which tc:node caught.
…chat-errors-logged # Conflicts: # src/main/native-chat/agent-session-wire/structured-agent-session-host-mutations.ts # src/main/native-chat/agent-session-wire/structured-agent-session-host.ts # src/main/native-chat/agent-session-wire/structured-agent-session-prompt-cancel.test.ts
… file, and record their causes - The production structured-chat logger writes a repeated failure (same level, scope, session, message and error text) once per 5 minutes, carrying how many repeats it swallowed; the tracked set is capped at 256. - Trace entries now carry the error's code (and SQLite errcode) and up to three causes by name and message. - A chat read whose conversation will not open is logged through the host's logger (open-for-read), and so are the runtime's chat-tab bookkeeping failures that already hold the host. - orcad writes its own orcad.trace.ndjson, closes it after every quit handler, and flushes it on process exit; a trace file that cannot be opened leaves tracing off instead of stopping the app or orcad. - Tests: the desktop wiring test proves the logger reaches the trace sink, and the privacy tests read every level the logger received.
…mpt failures through the host's logger
… writes The repeat suppression keyed on the message and the error's text, so two refusals with the same code but different causes, a plain error and a refusal of one code, or two object-valued errors shared a key and the second was swallowed for five minutes. The key is now the entry's whole written content (fields, code, errcode, refusal reason, cause chain, a stable rendering of a non-error value) plus the error's name and message; a refusal's reason is also written.
…owing, not Reflect.get
Review status: ready for review (head 3a54c6d)The problem. Some structured-chat failures that the app deliberately carries on past were thrown away on desktop. Examples: a late reply that could not be saved, provider events the chat history refused, a provider start or exit that could not be delivered, and an unreadable old chat-records file. The chat runtime only reported them through optional callbacks, and the desktop never passed those callbacks. A few failures went to What changes for you. Nothing in the UI. These failures are now written to the diagnostics trace file, Fixed during review (each with tests, plus an ablation that turns the test red):
Deferred (P3, not fixing here):
Verified:
Not verified:
|
|
|
Navigate logical layers of code changes, visualize relationships, and explore their blast radius. 📝 WalkthroughWalkthroughThe change introduces structured agent-session logging with scoped warnings and errors, repeat suppression, bounded error serialization, and non-throwing logger wrappers. Agent-session runtime, journal, delivery, queue, status, restart, and settlement paths now use injected loggers instead of callback or console reporting. Tests provide logger fixtures and assert structured entries. Orcad now writes and flushes a dedicated trace file during runtime shutdown. Priority: ⬇️ Low Merge Risk: 🔵 Low · up to Failure logging is now centralized and structured. Raw non-Error failure values could land in local diagnostics, which is a small privacy concern worth tightening before or soon after merge. Security Architecture ReviewSecurity architecture risk: 🔵 Low · up to Failure logging improves troubleshooting, but arbitrary error values can carry private content into console output. Trace files have redaction and restricted file permissions. No new remote access or privilege expansion was established, and actual sensitive-payload reachability remains uncertain. Retained concerns
Security review detailsSecurity Blast Radius
Security Findings and Attack Paths
Trust Boundaries and Controls
Resilience and Maintainability Implications
Hardening Proposals
🚥 Pre-merge checks | ✅ 4 | ❓ 1❌ Failed checks (1 inconclusive)
✅ Passed checks (4 passed)
Full details: Docstring CoverageExplanation Docstring coverage is 35.29% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 34 functions across 50 files. (171 skipped: 1 unsupported, 170 over the file limit.) ✨ Finishing Touches 💡 1📝 Generate docstrings 💡
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 |
There was a problem hiding this comment.
🧹 Nitpick comments (1)
src/main/native-chat/agent-session-wire/structured-agent-session-logger.ts (1)
114-116: 🔒 Security & Privacy | 🛡️ Detected with Advanced Tier | 🔵 Trivial | ⚡ Quick winSensitive Data Exposure
Exploitability: Difficult
CWE: CWE-532 — Insertion of Sensitive Information into Log FileSanitize non-Error values in both trace attributes and console output.
errorAttributesstores every non-Errorvalue aserror, and the tracer writes span attributes to the local diagnostic trace. The console path also prints the originalfieldsobject. Changing onlyerrorAttributeswould leave the same value in console diagnostics.Reduce non-Error values to their type, plus
codewhen it is a string or number. Remove the rawerrorfield from the console payload. Update the test that expects{ code: 'busy', attempt: 1 }.Proposed change
@@ - print( - `[agent-session] ${scope}: ${message}`, - suppressed > 0 ? { ...fields, suppressed } : fields - ) + const printFields = { scope, ...rest, ...errorAttributes(error) } + print( + `[agent-session] ${scope}: ${message}`, + suppressed > 0 ? { ...printFields, suppressed } : printFields + ) @@ if (!(error instanceof Error)) { - return { error } + if (typeof error !== 'object' || error === null) { + return { error: String(error) } + } + const code = codeValue('code' in error ? (error as { code?: unknown }).code : undefined) + return { error: '[non-error value]', ...(code !== undefined ? { errorCode: code } : {}) } }
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Advanced
Run ID: 03445c40-392b-445e-9037-33b4f6fa23a0
📒 Files selected for processing (221)
docs/reference/orcad-operations.mdsrc/main/agent-hooks/first-work-branch-rename.test.tssrc/main/claude/claude-api-retry-idle-sweep.test.tssrc/main/claude/claude-api-retry-row.test.tssrc/main/claude/claude-background-wake-retention.test.tssrc/main/claude/claude-context-usage-restart.test.tssrc/main/claude/claude-context-usage-unloaded-turn.test.tssrc/main/claude/claude-stream-json-connection.test.tssrc/main/claude/claude-structured-journal-translation-background-tasks.test.tssrc/main/claude/claude-structured-journal-translation.test.tssrc/main/claude/claude-structured-provider-fallback.test.tssrc/main/claude/claude-structured-session-reading-control.test.tssrc/main/claude/claude-subagent-resume-after-restart.test.tssrc/main/claude/claude-subagent-roster.test.tssrc/main/codex/codex-provider-retry-idle-sweep.test.tssrc/main/codex/codex-structured-journal-goal-resume.test.tssrc/main/codex/codex-structured-journal-goal-revision.test.tssrc/main/codex/codex-structured-journal-subagent-readers.test.tssrc/main/codex/codex-structured-journal-translation-settlement.test.tssrc/main/codex/codex-structured-journal-translation-turn-lifecycle.test.tssrc/main/codex/codex-structured-journal-translation.test.tssrc/main/codex/codex-structured-journal-turn-settles-once-journal.test.tssrc/main/codex/codex-structured-question-order.test.tssrc/main/native-chat/agent-session-journal/journal-open-failure.test.tssrc/main/native-chat/agent-session-journal/journal-open-failure.tssrc/main/native-chat/agent-session-journal/journal-per-session-import.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-accept-then-deliver.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-acquisition-options.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-adopted-import.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-agent-start.tssrc/main/native-chat/agent-session-wire/structured-agent-session-append-delivery.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-at-rest-commands.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-attach-flow.tssrc/main/native-chat/agent-session-wire/structured-agent-session-attach-orchestration.tssrc/main/native-chat/agent-session-wire/structured-agent-session-attach-test-conversation.tssrc/main/native-chat/agent-session-wire/structured-agent-session-background-task-channel.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-chat-stop.tssrc/main/native-chat/agent-session-wire/structured-agent-session-claude-compact-stop.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-claude-echo-working.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-claude-option-queue.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-claude-queued-stop.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-claude-root-exit.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-claude-stop-ends-session.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-close-verdict.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-codex-stop-row.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-conversation-close.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-conversation-lifetime.tssrc/main/native-chat/agent-session-wire/structured-agent-session-conversation-open.tssrc/main/native-chat/agent-session-wire/structured-agent-session-conversation-stop.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-conversations.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-conversations.tssrc/main/native-chat/agent-session-wire/structured-agent-session-crash-mid-start.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-crash-turn-end.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-dead-generation-settlement.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-dead-generation-settlement.tssrc/main/native-chat/agent-session-wire/structured-agent-session-delivery-loop.tssrc/main/native-chat/agent-session-wire/structured-agent-session-event-recovery.tssrc/main/native-chat/agent-session-wire/structured-agent-session-event-sink-queue.tssrc/main/native-chat/agent-session-wire/structured-agent-session-event-sink.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-event-sink.tssrc/main/native-chat/agent-session-wire/structured-agent-session-eviction.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-eviction.tssrc/main/native-chat/agent-session-wire/structured-agent-session-failed-create-owner-verdict.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-failed-create-sink-release.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-forget-status.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-grouped-prompt.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-host-delivery.tssrc/main/native-chat/agent-session-wire/structured-agent-session-host-lifetime.tssrc/main/native-chat/agent-session-wire/structured-agent-session-host-runtime-state.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-host-runtime-state.tssrc/main/native-chat/agent-session-wire/structured-agent-session-host-tabs.tssrc/main/native-chat/agent-session-wire/structured-agent-session-host-teardown.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-host-teardown.tssrc/main/native-chat/agent-session-wire/structured-agent-session-host-test-abandon.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-host-test-harness.tssrc/main/native-chat/agent-session-wire/structured-agent-session-host-types.tssrc/main/native-chat/agent-session-wire/structured-agent-session-host.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-host.tssrc/main/native-chat/agent-session-wire/structured-agent-session-idle-sweep.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-idle-sweep.tssrc/main/native-chat/agent-session-wire/structured-agent-session-import-mismatch.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-journal-corruption.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-late-settlement.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-lease-renewer.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-lease-renewer.tssrc/main/native-chat/agent-session-wire/structured-agent-session-legacy-handoff-record.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-log-repeats.tssrc/main/native-chat/agent-session-wire/structured-agent-session-logger-test-support.tssrc/main/native-chat/agent-session-wire/structured-agent-session-logger.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-logger.tssrc/main/native-chat/agent-session-wire/structured-agent-session-main-agent-working-agreement.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-mutation-admission.tssrc/main/native-chat/agent-session-wire/structured-agent-session-mutation-context.tssrc/main/native-chat/agent-session-wire/structured-agent-session-operation-settlement.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-operation-settlement.tssrc/main/native-chat/agent-session-wire/structured-agent-session-operation-start-refusal.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-option-settlement.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-options-read.tssrc/main/native-chat/agent-session-wire/structured-agent-session-owed-work-release.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-pre-spawn-first-answer.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-processless-reservation.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-prompt-cancel.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-provider-child-record.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-provider-restore.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-provider-started.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-provider-started.tssrc/main/native-chat/agent-session-wire/structured-agent-session-queued-message-rig.test-fixture.tssrc/main/native-chat/agent-session-wire/structured-agent-session-queued-messages.tssrc/main/native-chat/agent-session-wire/structured-agent-session-queued-mutations.tssrc/main/native-chat/agent-session-wire/structured-agent-session-queued-pause.tssrc/main/native-chat/agent-session-wire/structured-agent-session-queued-stop.tssrc/main/native-chat/agent-session-wire/structured-agent-session-queued-wiring.tssrc/main/native-chat/agent-session-wire/structured-agent-session-read-restore.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-readable-restorer.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-recovered-turn-clock.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-recovery-exits.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-refusal-retry.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-resolved-append.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-rest-test-rig.tssrc/main/native-chat/agent-session-wire/structured-agent-session-restart-cap.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-restart-continuation.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-restart-continuation.tssrc/main/native-chat/agent-session-wire/structured-agent-session-restart-failure-ledger.tssrc/main/native-chat/agent-session-wire/structured-agent-session-restart-interruption-test-harness.tssrc/main/native-chat/agent-session-wire/structured-agent-session-restart-offer-records.tssrc/main/native-chat/agent-session-wire/structured-agent-session-restart-offer-withdrawal.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-restart-offer-withdrawal.tssrc/main/native-chat/agent-session-wire/structured-agent-session-restart-ownership.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-restart-reconcile.tssrc/main/native-chat/agent-session-wire/structured-agent-session-restart-restore.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-restart-resume-host.tssrc/main/native-chat/agent-session-wire/structured-agent-session-restart-resume-wiring.tssrc/main/native-chat/agent-session-wire/structured-agent-session-restart-status-publication.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-restart-teardown.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-restore-without-import.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-reveal.tssrc/main/native-chat/agent-session-wire/structured-agent-session-rewind-at-rest.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-rewind.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-rewind.tssrc/main/native-chat/agent-session-wire/structured-agent-session-send-block.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-send-idempotency.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-send-open-stale-turn.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-send-preparation.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-send-preparation.tssrc/main/native-chat/agent-session-wire/structured-agent-session-send-restarts-failed-start.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-settled-attach-retry.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-start-failure-writer.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-startup-failure-exit.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-startup-reconcile-failure.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-status-feed-child-work.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-status-feed-child.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-status-feed-children.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-status-feed-clock.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-status-feed.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-status-feed.tssrc/main/native-chat/agent-session-wire/structured-agent-session-status-reentry.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-subagent-recency.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-subscribers.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-surface-lifetime.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-thread-goal.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-turns.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-turns.tssrc/main/native-chat/agent-session-wire/structured-agent-session-unexpected-exit.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-unexpected-exit.tssrc/main/native-chat/agent-session-wire/structured-agent-session-view-start-after-failed-start.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-wedged-profile-migration.test.tssrc/main/native-chat/agent-session-wire/structured-conversation-command.test.tssrc/main/native-chat/agent-session-wire/structured-conversation-command.tssrc/main/native-chat/agent-session-wire/structured-rewind-recovery.tssrc/main/observability/index.tssrc/main/observability/logs-directory.tssrc/main/orcad/orcad-entry.tssrc/main/orcad/orcad-observability.test.tssrc/main/orcad/orcad-observability.tssrc/main/runtime/agent-session-legacy-record-import.test.tssrc/main/runtime/claude-structured-session-integration.test.tssrc/main/runtime/orca-runtime-close-structured-agent-session-tab.tssrc/main/runtime/orca-runtime-get-worktree-ps.tssrc/main/runtime/orca-runtime-restore-structured-agent-session-tabs-once.tssrc/main/runtime/orca-runtime-structured-status-sink-wiring.test.tssrc/main/runtime/rpc/methods/agent-launch-structured-prompt.test.tssrc/main/runtime/rpc/methods/agent-launch-structured-prompt.tssrc/main/runtime/rpc/methods/structured-agent-session-adoption-replay.test.tssrc/main/runtime/rpc/methods/structured-agent-session-at-rest.test.tssrc/main/runtime/rpc/methods/structured-agent-session-create-tab-publication.test.tssrc/main/runtime/rpc/methods/structured-agent-session-create.tssrc/main/runtime/rpc/methods/structured-agent-session-hold.test.tssrc/main/runtime/rpc/methods/structured-agent-session-precommit-refusal.test.tssrc/main/runtime/rpc/methods/structured-agent-session-rpc.test-fixture.tssrc/main/runtime/rpc/methods/structured-chat-tab-table.test.tssrc/main/runtime/runtime-worktree-agent-rows-verdict.test.tssrc/main/runtime/runtime-worktree-structured-agent-rows-liveness.test.tssrc/main/runtime/structured-agent-session-close.test.tssrc/main/runtime/structured-agent-session-close.tssrc/main/runtime/structured-agent-session-codex-turn-end-settlement.test.tssrc/main/runtime/structured-agent-session-dispatch-followups.tssrc/main/runtime/structured-agent-session-failure-logging.test.tssrc/main/runtime/structured-agent-session-host-refusal.test.tssrc/main/runtime/structured-agent-session-install-failure.test.tssrc/main/runtime/structured-agent-session-integration.test.tssrc/main/runtime/structured-agent-session-journal-open.tssrc/main/runtime/structured-agent-session-lifecycle-delivery.tssrc/main/runtime/structured-agent-session-record-import-install.test.tssrc/main/runtime/structured-agent-session-runtime-exit.test.tssrc/main/runtime/structured-agent-session-runtime.test.tssrc/main/runtime/structured-agent-session-runtime.tssrc/main/runtime/structured-agent-session-spawn-token-descendants.test.tssrc/main/runtime/structured-agent-session-startup-reconcile.test.tssrc/main/runtime/structured-agent-session-startup-tab-restore.test.tssrc/main/runtime/structured-agent-session-tab-index-seed.tssrc/main/runtime/structured-chat-coordinator-mail.test.tssrc/main/runtime/structured-child-records-switch.test.tssrc/main/runtime/structured-claude-pending-rewind.test.tssrc/main/runtime/structured-claude-scripted-runtime-test-support.tssrc/main/runtime/structured-codex-child-work-runtime.test.tssrc/main/runtime/structured-codex-session-rpc-test-harness.tssrc/main/runtime/structured-session-worktree-teardown.tstests/e2e/codex-child-approval-activity-row.unit.test.tstests/e2e/cross-version-wire/cross-version-agent-session-wire.unit.test.tstests/e2e/structured-agent-session-read-owner.unit.test.tstests/e2e/structured-chat-owner-status-activation.unit.test.ts
Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 5 remain after this review.
There was a problem hiding this comment.
ℹ️ Minor suggestions only — one comment typo and one small status-surface edge case.
Reviewed changes
- Optional failure callbacks become a required
logger. The structured chat runtime and host now take one required logger (warn/error, each carrying ascope);onError,onEventSinkError,onLeaseReconcileFailure,onLegacyRecordImportReportandonNoteFailedare gone, and every site — plus the host's scatteredconsole.warns — reports under its own scope. - Production logger writes failed
agentSession.<scope>spans.createStructuredAgentSessionLogger()records the span with level, message, session id, the error's code/errcode/refusal reason and a depth-capped cause chain, then mirrors to the console; reporting is wrapped so a throw can never escape into the operation it reports. - Repeat suppression. A stable key over everything the entry writes swallows identical repeats for 5 minutes, carrying the swallowed count, bounded at 256 tracked entries.
orcadgets its own trace file and fail-soft install.<data-root>/logs/orcad.trace.ndjson, installed before the runtime, closed after every quit handler and flushed onexit; an unopenable logs folder now warns and leaves tracing off instead of failing startup.- Privacy kept on recovery-payload paths. Recovery-capsule, restart-offer and note failures log scope/session id only, and the restart-teardown tests now inspect every recorded entry, not just the console.
I read the whole diff and ran the new structured-agent-session-logger (7), structured-agent-session-failure-logging (11) and orcad-observability (4) suites; all 22 pass. The repeat-suppression boundary/eviction cases and the install-without-logger guard are pinned by tests that would fail if the behavior regressed.
ℹ️ Nitpicks
initObservabilitysetsconsent.localFileEnabledbefore callinginstallLocalSink; when the sink cannot be opened,getDiagnosticsStatus()still reports local-file tracing as enabled (src/main/observability/index.ts:142-165) even though no sink is active. Harmless today — the tracer's active sink is unset, so nothing writes — but the diagnostics status surface would claim tracing is on when it is off.
DeepSeek Flash (free via Pullfrog for OSS) | 𝕏
| // Its own file because the bindings carry real decisions — which caller key the continuation sends | ||
| // under, that the verdict comes from the settlement waiter rather than the send result, and where a | ||
| // failed journal note is reported — and those belong next to the collaborator that consumes them | ||
| // under, that the verdict comes from the settlement waiter rather than the send result, — and those belong next to the collaborator that consumes them |
There was a problem hiding this comment.
Stray comma before the em dash, and this line is much longer than the surrounding comment. Reflowing it keeps the file's comment rhythm.
| // under, that the verdict comes from the settlement waiter rather than the send result, — and those belong next to the collaborator that consumes them | |
| // under, that the verdict comes from the settlement waiter rather than the send result — and those | |
| // belong next to the collaborator that consumes them |
…op-keeps-steered-card #24312 gave the structured chat host one required logger. Its logging of the stored queue pause went with code this branch replaced: the Stop-event write failure (runRecordedStop, including a throw before the append) now logs through the context's logger under stop-queued-bookkeeping, step "event row", and the restart-pause adoption logs under queue-pause-adoption.
…rt-failure-on-message Brings in main's native-chat Stop work (#24333 owed stop retried by the next message, #24072 queue pause derived from Stop/Resume rows, #24334, #24437) and #24312 (structured chat failures go through the host logger). Conflicts, each keeping main's behaviour and this branch's design: - queued-message-pause-table.ts: deleted, as #24072 did. Its "a returned card holds the queue only when it was not a failed start" rule (queuedCardHoldsQueue) is ported into main's queued-message-pause.ts (nextSendableQueuedCard and resumableQueuePause); the drain's pick in queued-messages.ts takes main's pause-aware nextSendableQueuedCard. New test pins it. - delivery-loop: main's wind-down wait (#24333) goes into this branch's prepare step: a held owed stop records its waiting row and stops; a start refused because the previous exit is unverifiable waits the same way instead of being recorded as a failed start. onError becomes main's logger, including the deps type (now in delivery-loop-deps.ts). The retry-wake booking moved to structured-agent-session-start-retry-wakes.ts to stay under max-lines. - dead-generation settlement: main's { ok, error } result with this branch's unprovenStart (the delivery loop writes a failed start); unexpected-exit and host-lifetime pass unprovenStart and log through main's logger. - agent-start, attach-flow: main's logger calls; this branch's startPending preparation and at-rest create. - conversation-lifetime, provider-child, host, host-delivery: main's finishOwedWindDown and endedAt with this branch's comments and startFailureRecorded; conversation delivery now takes the attach context (one line in host.ts, which was over max-lines). - restart-continuation: both imports; the handed-over/verdict reading moved to structured-agent-session-continuation-verdict.ts for max-lines. - tests: main's logger added to this branch's hosts and attach inputs; the provider-start log expectation uses main's logger line.

ELI5
When something behind a native chat goes wrong in a way the app deliberately carries on past (a late reply from the agent could not be saved, provider events could not be written to the chat history, a provider start or exit could not be delivered), the desktop app threw the error away. Nobody could find out afterwards what happened. Now every one of those failures is written to the app's diagnostics log file, so it can be found after the fact. A failure that keeps repeating is written once every five minutes with a count, so it cannot crowd everything else out of that file.
What Changed
The problem. The structured chat runtime took an optional
onError({ scope, error })callback. The desktop app (and the headlessorcadhost, which builds the runtime through the sameOrcaRuntimeServicecall) never passed one, so these failures were silently dropped: a late dispatch settlement, releasing sends an idle provider never answered, provider events the chat journal would not take, provider start/exit events the host could not take, and about a dozen more routed through the host's optionalonEventSinkError. A couple of scopes had ad-hocconsole.warnfallbacks (#23964), and the chat host had 38 more scatteredconsole.warncalls. In a packaged desktop build the main process has no console to read, so those reached nobody either.What is different for the user. Nothing visible in the UI. Failures the app carries on past now land in
<userData>/logs/main.trace.ndjson(on macOS~/Library/Application Support/Orca/logs/main.trace.ndjson), the file the "share diagnostics" bundle already collects. Each entry is a failed span namedagentSession.<scope>(for exampleagentSession.late-settlement) with the session id, a one-line message, and the error with its stack, its code (errorCode, plus SQLite'serrorErrcode), a refusal's reason (refusalReason) and up to three causes by name and message (errorCause). The headlessorcadhost now keeps its own trace file,<data-root>/logs/orcad.trace.ndjson(default~/.orca/logs/), with every trace span it emits (git commands, worktree paths, terminal spawns, structured-chat failures and the rest; documented indocs/reference/orcad-operations.md), and prints each chat entry to stderr, which its service manager captures. The local file is skipped whenORCA_DIAGNOSTICS_DISABLED=1or in CI, same as every other trace. A logs folder that cannot be opened (permissions, a read-only mount) now leaves tracing off with one warning instead of stopping the desktop app ororcadfrom starting.Mechanism.
logger(warn/error, each with a message and fields that always carry ascope). The optionalonError,onEventSinkError,onLeaseReconcileFailure,onLegacyRecordImportReportandonNoteFailedcallbacks are gone; every site that used them, and everyconsole.warnin the host (src/main/native-chat/agent-session-wire/), reports through the logger under its own scope.onFailed, which is not reporting: it is how the host decides to stop a provider whose journal failed. The dead-generation settlement returns its failure instead of reporting it, so each caller logs it under its own scope (and a closing chat keeps it as the thrown error's cause).open-for-read) now reports through the host's logger, as its write twin already did. So do the callers outside the host that already hold it: chat-tab bookkeeping on open, close, restore and tab-index seed, a failed close's tab restore, a removed workspace's tab drop, a created chat's tab publication, and a created chat's launch prompt.createStructuredAgentSessionLogger()is the production logger: a failed span in the local trace sink plus the console.OrcaRuntimeServicepasses it, so desktop andorcadboth get it. It writes a repeated entry at most once per 5 minutes, carryingsuppressed: <count>of the repeats it swallowed; it tracks at most 256 such entries. An entry repeats only when everything it would write is the same: level, scope, message, every field, and the error's name, message, code, refusal reason and cause chain (a value that is not an error is compared by its contents). Swallowed repeats are counted on the next write of that entry; if the failure stops, that count is never written. Test loggers record everything.orcadinstalls the same local trace sink as the desktop at startup under its own file name (src/main/orcad/orcad-observability.ts), closes it last in its cleanup (after every quit handler), and flushes it on process exit, so a 15-second shutdown deadline, a failed start or an uncaught exception keeps what was buffered.console.warnand returns. This keeps fix(native-chat): a failed startup chat-lease save no longer puts the app into "Session restore failed" #23964's guarantee and makes it hold everywhere, not only for the lease reconcile.@ts-nocheckfile, the install refuses without a logger, the same way it already refuses without a Claude auth policy. A wiring test pins that the runtime passes a logger that reaches the trace sink.Differences from the common pattern
Where this differs from the common pattern. Each item is Intended (kept, with why) or Temporary (with the follow-up that removes it).
structured-agent-session-restart-teardown.test.ts,structured-agent-session-restart-ownership.test.ts) pin that these errors can carry a chat's private recovery payload; they now check every level the logger received, not only the console.console.warn/console.erroronly, because none of them holds the host. Follow-up: give the journal database the host's logger, and pass it to the orchestration and session-environment callers.src/main/native-chat/agent-session-journal/):journal-database.ts:218,journal-per-session-import.ts:255,journal-per-session-source.ts:136,journal-queued-messages.ts:309,journal-restart-reconciliation.ts:104,journal-row-writer.ts:86.structured-agent-session-tab-retirement.ts:77,structured-session-child-identity-env.ts:89,rpc/methods/structured-agent-session-precommit-refusal.ts:60(a create refused before the host committed anything).rpc/methods/orchestration-structured-worker-session.ts:193and:349,orchestration/structured-mailbox-pointer-host.ts:73,orchestration/structured-session-mail-target.ts:121,orca-runtime-get-pty-record-for-pane-key.ts:216.native-chat/wsl-transcript-fs-gate.ts:260.orcad's trace stays on that host; the desktop's share-diagnostics bundle does not collect it. Failures of a chat whose execution host is a remoteorcadare in that host's<data-root>/logs/orcad.trace.ndjson, reachable over SSH only. Follow-up: serve the host's trace over the runtime RPC so the desktop bundle includes it for paired hosts.Why
The common pattern is one logger for every reported failure, never a per-failure callback, with log lines kept in a local file as well as the console. A per-scope optional callback is what caused this bug: forgetting to pass it compiles fine and drops the failure silently. A required dependency cannot be forgotten. Writing into the existing trace sink, rather than a new log file, means no new file to rotate, redact or collect; the diagnostic bundle and its redactor already handle it. The error's cause chain is written out, as is common when serializing errors.
Linked Issue
Found while building #23964.
Visual Proof
N/A: no UI change. The change is what gets written to the diagnostics log file.
Testing
src/main/runtime/structured-agent-session-failure-logging.test.ts(new): a scoped failure from each previously dropped path (late settlement, unanswered dispatch, provider start/exit delivery, journal event sink) reaches an injected logger; a logger that throws never throws out; the production logger writes a failedagentSession.<scope>span to the trace sink; the install refuses without a logger and hands the host a guarded one. The delivery loop, idle sweep and queued-message drain each log a failed step under their scope.structured-agent-session-logger.test.ts(new): 30 repeats on a 10-second timer write one entry, and the next after the window carriessuppressed: 29; different sessions, scopes, levels, messages and errors are never merged, including two refusals with one code and different causes, one message under another error name, and two different non-error values; the tracked set is bounded; an entry carries the error's code, SQLite errcode and a depth-capped cause chain, with no cause's own fields.orca-runtime-structured-status-sink-wiring.test.ts: the logger the runtime hands the host writes anagentSession.<scope>failed span into an installed trace sink (a logger that writes nowhere fails it).src/main/orcad/orcad-observability.test.ts(new):orcadwrites<data-root>/logs/orcad.trace.ndjson(and nomain.trace.ndjson), flushes buffered lines on process exit, still starts with tracing off when its logs folder cannot be opened, installs before the runtime and closes after every quit handler.journal-open-failure.test.ts,structured-agent-session-restore-without-import.test.ts: a chat read whose journal will not open logsopen-for-readwith the session id, once per failure.orcadsink install and entry wiring, its file name, exit flush and close order, the fail-soft install, and a payload logged at error level each turns its test red. The workspace-removal tab drop has no test.orcadand observability unit tests).tsconfig.node.json) passes.<userData>/agent-sessions/agent-sessions.jsonwas made unreadable (chmod 000). This build wrote the failure tomain.trace.ndjson;origin/main(9ed7b39) wrote noagentSessionline there and only printed a console warning. Both builds otherwise started and rendered normally. Redacted entry from this build (stack shortened):{"type":"effect-span","name":"agentSession.legacy-record-import","durationMs":0,"attributes":{"level":"warn","message":"importing the chat records file did not complete","outcome":"unavailable","errorCause":["Error: EACCES: permission denied, open '~/<profile>/agent-sessions/agent-sessions.json'"]},"events":[],"exit":{"_tag":"Failure","cause":"Error: agent_session_store_corrupt\n at … ensureStructuredAgentSessionHost …"}}Not checked by hand: a failure during a live chat (for example the chat history refusing provider events), which needs a running agent; the unit tests above cover those paths.
I manually tested these changes locally
Automated tests added/updated, or explained why not below
Review
Agent skill upstream boundary
docs/reference/agent-skill-sharing-upstream-boundary.mdand copies or mechanically translates no upstream skill-installer source, tests, fixtures, registry entries, path tables, comments, or documentation.Notes
No wire change: the logger is host-internal, so mixed client and host versions are unaffected. SSH: the execution host logs its own failures to its own file; nothing new crosses the wire. Volume: status-sink and observer failures that previously printed to an unread console now also add spans to the rotated trace file, at most one per repeated failure per 5 minutes.
orcadnow records the same span families as the desktop, up to 100 MB on each host.Checklist
N/Awith reasonpnpm lint,pnpm typecheck,pnpm test, andpnpm buildpass (or CI will cover; local preferred)