Skip to content

feat(operability): structured server diagnostics behind the generic 503 - #577

Open
seonghobae wants to merge 3 commits into
mainfrom
fix/global-ask-session-storage-adapter
Open

feat(operability): structured server diagnostics behind the generic 503#577
seonghobae wants to merge 3 commits into
mainfrom
fix/global-ask-session-storage-adapter

Conversation

@seonghobae

@seonghobae seonghobae commented Aug 24, 2026

Copy link
Copy Markdown
Contributor

Implements #361 for the /api/ask boundary.

Customer boundary unchanged

Every failure path still returns the same generic 503 — no exception text, provider trace, or prompt/response content reaches the caller. The old f-string detail (Ask Agent is unavailable: {exc}) leaked raw exception text and is gone.

Operator diagnosability restored

Three classified catch paths in /api/ask:

Exception Classification Log event
HttpClientError, OSError known provider/transport fault warning orchestrator_provider_unavailable (operation, correlation id, exception class; message deliberately excluded)
KeyError, ValueError evidence-object contract break error orchestrator_internal_fault with stack trace
Exception unexpected defect same internal-fault diagnostic

New backend/app/operability.py documents the forbidden-field contract: no prompt text, model output, bearer tokens, provider keys, tenant PII, or post bodies in any record. Alerting keys on event_type so pager load separates provider-down from our-bug.

Tests

tests/test_operability.py (5 cases, no live stack needed): event shapes, correlation-id uniqueness, stack-trace attachment for internal faults, forbidden-field guarantee.


Open in Devin Review

Follow-up commit: legacy-namespace migration tooling (ADR 0157 / #372)

scripts/migrate_legacy_namespace.py + 8 tests: deterministic, dry-run-by-default rewrite of stored post_project_mention.ontology_iri values from the deprecated repository-case namespace to the canonical lowercase one. Fails closed on unrecognized namespaces; provenance columns untouched.

Summary by CodeRabbit

  • 개선 사항
    • 외부 서비스 또는 전송 장애 발생 시 보다 안정적으로 처리하며, 민감한 오류 세부 정보 대신 안내 메시지를 제공합니다.
    • 장애 유형을 구분해 기록하여 문제 원인 파악과 복구가 쉬워졌습니다.
    • 기존 네임스페이스 데이터를 표준 형식으로 안전하게 정리할 수 있는 마이그레이션 도구를 추가했습니다.
    • 변경 전 결과를 확인하는 미리보기 모드와, 검증된 항목만 일괄 적용하는 기능을 제공합니다.

Global Ask hid every failure behind a stable 503 (correct customer
boundary) but the cause never reached structured telemetry, and the
f-string leaked raw exception text to callers.

Split the ask handler into three classified paths, all returning the
same generic 503:
- HttpClientError/OSError -> known provider/transport fault; warning
  event orchestrator_provider_unavailable with operation code,
  correlation id, exception class; message deliberately not logged.
- KeyError/ValueError -> evidence-object contract break; error event
  orchestrator_internal_fault with stack trace attached.
- broad Exception -> unexpected defect; same internal-fault diagnostic
  so a programming regression cannot degrade into an opaque
  availability incident. Chaining is preserved on every path.

backend/app/operability.py documents the forbidden-field contract (no
prompt text, model output, bearer tokens, provider keys, tenant PII, or
post bodies in any record); alerting keys on event_type so pager load
separates provider-down from our-bug (issue #361). Unit tests cover
both event shapes, uniqueness of correlation ids, and the forbidden-
field guarantee without needing a live stack.
@coderabbitai

coderabbitai Bot commented Aug 24, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

Next included review available in 43 minutes.

View limit details

Limit details: You’ve used the included review currently available.

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

Learn how review limits work.

Review configuration:

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: e3f4c91d-c7fd-427e-b10f-cebe25fd197e

📥 Commits

Reviewing files that changed from the base of the PR and between 0ead98e and aaaec14.

📒 Files selected for processing (3)
  • backend/app/main.py
  • backend/app/operability.py
  • tests/test_operability.py
📝 Walkthrough

Walkthrough

오케스트레이터 오류를 구조화해 기록하고 클라이언트 응답에서 예외 세부 내용을 제거합니다. PostgreSQL 레거시 네임스페이스를 canonical 형식으로 변환하는 안전한 마이그레이션 CLI와 테스트를 추가합니다.

Changes

오케스트레이터 오류 처리

Layer / File(s) Summary
구조화된 오류 로거 구현
backend/app/operability.py
공급자 장애와 내부 결함을 별도 이벤트로 기록합니다. 작업 코드, 예외 클래스, 상관관계 ID를 기록합니다. 내부 결함에는 traceback을 포함하고 예외 메시지는 기록하지 않습니다.
Global Ask Agent 오류 흐름
backend/app/main.py, tests/test_operability.py
예외 유형별 로깅을 연결합니다. 클라이언트에는 일반화된 503 메시지를 반환합니다. 로그 레벨, 필드, 상관관계 ID 고유성, 민감한 텍스트 비노출을 검증합니다.

레거시 네임스페이스 마이그레이션

Layer / File(s) Summary
네임스페이스 마이그레이션 CLI
scripts/migrate_legacy_namespace.py
레거시 IRI를 canonical IRI로 변환합니다. 기본 dry-run은 쓰기 없이 보고합니다. --apply는 단일 트랜잭션으로 갱신하며, 알 수 없는 네임스페이스와 동시 변경을 검증합니다.
마이그레이션 동작 검증
tests/test_migrate_legacy_namespace.py
매핑, fragment 보존, dry-run, apply, 알 수 없는 네임스페이스, no-op 및 업데이트 인자를 검증합니다.

Estimated code review effort: 4 (Complex) | ~45 minutes

Merge Risk: 🟠 High · up to 0ead9

The current change may expose different internal failure details through the 503 response and may leak sensitive exception text into diagnostic logs, potentially including prompt or credential-related data. Merge should wait until every failure path uses the same generic response and logged tracebacks are sanitized.

Sequence Diagram(s)

sequenceDiagram
  participant GlobalAskAgent
  participant OperabilityLogger
  participant Client

  GlobalAskAgent->>OperabilityLogger: 오류 유형별 구조화된 이벤트 기록
  OperabilityLogger-->>GlobalAskAgent: correlation_id 반환
  GlobalAskAgent-->>Client: 일반화된 503 응답 반환
Loading
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed Docstring check was indeterminate for this PR — some files could not be analyzed in time. Not blocking.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed 제목은 /api/ask의 구조화된 서버 진단과 일반화된 503 응답이라는 주요 변경 사항을 정확하고 간결하게 설명합니다.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/global-ask-session-storage-adapter

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

❤️ Share

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

devin-ai-integration[bot]

This comment was marked as resolved.

ADR 0157 keeps the lowercase ontology namespace canonical and demoted
the repository-case spelling to deprecated compatibility status, but
rows written before the decision can still carry legacy IRIs in
post_project_mention.ontology_iri -- and RDF consumers treat the two
spellings as different resources.

scripts/migrate_legacy_namespace.py scans, prints every planned
rewrite, refuses unrecognized namespaces (fail closed rather than
bulk-mangle a third spelling), and only writes under --apply inside
one transaction guarded by the exact old IRI so a concurrent edit
aborts instead of double-applying. Provenance columns (extraction
method, confidence, evidence) are never touched per ADR 0157's
do-not-silently-rewrite rule.

Dry run is the default. 8 unit tests cover canonicalize mapping,
dry-run reporting, selective apply, fail-closed behavior, and the
clean-database no-op.
coderabbitai[bot]

This comment was marked as resolved.

@seonghobae
seonghobae enabled auto-merge August 24, 2026 09:12
…backs

Python renders a traceback's final line as 'ExceptionType: message', so
exc_info=exc violated the module's own forbidden-field contract: parsing
exceptions from orchestrator responses can embed provider payload or
prompt fragments, and those landed in the log. Re-emit through a
_MessageRedacted carrier that keeps the original __traceback__ (the
raise-site frames stay diagnosable) while its text is a fixed redaction
notice; the real class name is retained in the structured
exception_class field.

Also unify the three /api/ask 503 detail strings into one generic
message so callers cannot probe which internal classifier fired; the
provider-vs-contract-vs-defect distinction lives only in server-side
event_type (devin/coderabbit review threads on PR #577). Drop the
docstring's nonexistent include_message option.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant