Skip to content

chatd debug logs: deferred review items from PR stack #24137

@ThomasK33

Description

@ThomasK33

Tracking: chatd Debug Logs — Deferred Review Items

This issue tracks deferred review items from the chatd debug logs PR stack (#23913#23921) that mafredri flagged as needing a tracking artifact.

PR #23914 — Types, Context, Model Normalization

  • normalizeToolResultOutput test coverage: 7/8 type-switch arms untested including nil guards, error-to-string conversion, media placeholder formatting, and default JSON fallback
  • GenerateObject test coverage: unique paths (normalizeObjectCall, normalizeObjectResponse, nil guard, structured_output metadata) have 0% test coverage
  • Unconsumed stream safety net: an unconsumed stream wrapper never calls finalize, leaving step permanently in_progress once real recorder lands. Consider context.AfterFunc or runtime.SetFinalizer
  • stepHandle.finish synchronization: add sync.Once to stepHandle.finish itself or serialize through holder mutex to prevent data race when recorder inherits the pattern

PR #23915 — Recorder, Transport, Redaction

  • Transport test coverage: additional test scenarios for fail-closed RedactJSONSecrets, non-JSON response body handling
  • Recorder test coverage: additional test scenarios flagged in review (specific gaps addressed: TestNextStepNumber_Concurrent cleanup, step counter tests, nil-safety tests)

PR #23916 — Service, Summary, Aggregation

  • FinalizeStale uses time.Now() directly: Resolved — quartz.Clock injected via WithClock option; FinalizeStale, heartbeat tickers, and stepHandle.finish all use s.clock.Now()
  • Reasoning tokens aggregation test: Resolved — ReasoningTokensSummedAcrossSteps and ZeroReasoningTokensOmitsField tests added with updateTestStepWithFullUsage helper
  • nullJSON typed nils: nullJSON maps both nil and typed nils to NullRawMessage{Valid: false} — intentional for write-once-finalize pattern, not a correctness issue
  • for {} loop iteration cap: Resolved — maxCreateStepRetries = 10 cap and ctx.Err() check between iterations
  • F25: TouchStep uses full UpdateChatDebugRun: Resolved — added dedicated TouchChatDebugRunUpdatedAt SQL query that only bumps updated_at
  • F27: TOCTOU race in CreateStep finalization guard: Resolved — added AND run.finished_at IS NULL to InsertChatDebugStep WHERE clause; sql.ErrNoRows mapped to errRunFinalized
  • F18: stepHandle.generation dead code: Resolved — removed field and increment
  • F22: Priority guard blocks same-priority retries: Resolved — changed <= to <
  • F24: extractEndpointLabel deserializes full Attempt: Resolved — attemptLabel minimal projection struct
  • F26: Em-dash characters in comments: Resolved — replaced with standard punctuation
  • F28: errRunFinalized guard test coverage: Resolved — TestService_CreateStep_RejectsFinalizedRun added
  • F29: time.Now() in recorder.go: Resolved — replaced with h.svc.clock.Now()
  • F30: truncateRunes duplicates util/strings.Truncate: Resolved — replaced with stringutil.Truncate
  • expectUpdateStep shallow JSON assertions: model tests check .Valid flags but not JSON content; needs provider-specific fixture data
  • Non-stream heartbeat for Generate/GenerateObject: Resolved -- added launchHeartbeat calls in both Generate and GenerateObject to keep the step alive during blocking provider calls

PR #23917 — Chat Lifecycle Wiring

  • Unconditional NewService call: Resolved — chatd now initializes the
    debug service lazily through a factory and only materializes it on demand
  • processChat/finishActiveChat interleaving: Resolved — finish-time
    status publishing now re-reads the chat state and suppresses stale final
    updates after a newer write wins
  • newDebugModel nil guard: Resolved — debug model wrapping now routes
    through guarded debug-service accessors instead of assuming the service is
    always present
  • quickgen debug model wrapping: Resolved — quickgen now shares a helper
    that wraps the model before run creation and finalizes with a bounded,
    uncancelled context
  • chatd.go:4215 deferred cleanup: Resolved — edit/archive debug cleanup
    now uses retrying best-effort cleanup with bounded timeouts plus the existing
    stale-finalization safety net
  • chatd.go:1311 deferred item: Resolved — startup stale-finalization
    now reuses the existing debug service instead of eagerly constructing one
  • chatd.go:1918 deferred item: Resolved — active-chat finalization now
    avoids publishing stale terminal state after newer control-path updates
  • quickgen.go:784 deferred item: Resolved — quickgen debug lifecycle
  • Edit cleanup race (Codex P2): Resolved — DeleteChatDebugDataAfterMessageID
    now accepts a started_before timestamp so retried cleanup does not delete
    runs created by a replacement turn that raced ahead of the retry window
  • Startup stale-finalization gating (Codex P3): Resolved — startup now uses
    debugService() (forces lazy init) instead of existingDebugService() so
    stale debug rows from a previous crash are finalized even when no request
    has triggered initialization yet
    setup is centralized so title and push-summary generation share the same
    guarded create/finalize flow

PR #23918 — HTTP Handlers, API Docs

  • Handler test coverage: getChatDebugRuns, getChatDebugRun, getChatDebugLoggingEnabled, putChatDebugLoggingEnabled need test coverage
  • ChatDebugEvent zero consumers: type defined but unused in Go/TS — wire or remove
  • Naming inconsistency: debug_logs_enabled_override vs debug_logging_enabled naming mismatch
  • ChatDebugSettings / UpdateChatDebugLoggingRequest type sharing: DebugLoggingOverrideSet only meaningful for user endpoint
  • NullableBool.MarshalJSON wire format: produces object instead of null for unset state
  • Debug runs list pagination: SQL LIMIT 100 with no pagination or truncation signal

PR #23919 — Frontend API, Panel Utils

  • debugPanelUtils.test.ts test coverage: 1 test for 15 exported coercion functions across 1146 lines

PR #23920 — Debug Panel Components, Settings

  • Errored runs poll indefinitely: errored status missing from ERROR_STATUSES, causing infinite 5s polling
  • state.data typed as unknown: debugQueries.ts:35 should be properly typed
  • tool_choice bare String() on unknown: DebugStepCard.tsx:178 uses unsafe cast
  • Unbounded response.content rendering: DebugStepCard.tsx:346 has no content limit
  • NaN-unsafe sort: DebugPanel.tsx:23 sort comparator
  • Dead branch: DebugRunList.tsx:16 dead code
  • Tab-ID duplication: AgentChatPageView.tsx:317

PR #23913 — Database Schema, SDK Types

  • Three-tier toggle integration test: site/user/chat enablement resolution has no integration test
  • UpdateChatDebugStep operation updatable: defense was acknowledged, no ticket

PR #23921 — Storybook Stories

  • Section comment cleanup: "Existing stories" / "New stories" reflect development timeline, not semantic grouping

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions