Task · CXO-0031

Attach structured upstream error diagnostics to conversation records

Description

Users can see the proxy error code on an enriched conversation but cannot inspect the upstream HTTP status and upstream error code preserved in request_logs. These distinguish authentication, capacity, quota and continuity failures while reviewing the affected conversation, without switching to an unrelated raw database dashboard. internal/enrich/postgres.go currently selects status, error_code and failure_phase only.

Read-only SQL on 2026-09-05 over request_logs.id <= 472100 (472,098 rows) found 75 non-null upstream_status_code values: 40 HTTP 404, 30 HTTP 401, four HTTP 503 and one HTTP 429. All 75 rows had an archive_request_id; none had a resp_-prefixed request_id. On these rows the upstream and proxy error codes agreed, but the HTTP status is additional evidence. Separately, 75 other rows had differing codes: 60 proxy stream_incomplete and 15 proxy codex_previous_response_stale, all retaining upstream previous_response_not_found and no upstream HTTP status. Across the full snapshot upstream_error_code was present in 469 rows, including 394 previous_response_not_found values. The existing bounded cached archive-ID join therefore matters for early-error enrichment. Recent IDs 462101..472100 had no such diagnostics, so historical population is not current universal coverage.

Scope is populated structured fields: upstream_status_code, upstream_error_code and upstream_transport. Do not bulk-export failure_detail, error_message, credentials, endpoint identifiers, client IPs or other freeform database content. failure_exception_type, bridge_stage and fallback fields were empty in the inspected snapshot and are not evidence-backed additions. Existing CXO-0001 owns enabling enrichment; CXO-0021 already owns the general status-disagreement view.

Acceptance Criteria

Definition of Done

Implementation Plan

Wave 2: commit root-owned seams first; frozen owned lanes implement with synthetic tests; integrate, just check, one corpus confidence gate and CodeRabbit; one push; watchtower-only deploy observation and m7kni proof; reconcile acceptance by evidence layer.

Implementation Notes

Clean main e8e97fd directly descends from c567894 and equals origin/main. CI 33988760737 and release-please 33988761017 succeeded. D8 holds; traces and agento11y remain disabled.

Final Summary

Wave 2 delivered at aca5e5de0bcd4ba6f5fd72dfaa6caef3a6c7fb71. Synthetic enrichment and sink tests cover differing codes, archive-only joins and absence; upstream diagnostics confined to turn body/response span. Live upstream error query returned empty: not observed in window, no historical SQL re-query. Postgres integration test skipped without DSN; runtime db_hit/cost movement verified. just check passed at that source SHA; CI 33993480890 success. Watchtower deployed that SHA healthy, restart count 0. Publish 33993481221 failed signing after successful manifest push; run-level publication completion remains open. The single D20 corpus gate was canceled (exit 143), so corpus confidence is not proven. Final tracker closeout is local under the one-push contract.

References

View the source file on GitHub