Skip to content

fix(coverage): unblock org-wide OpenCode approval + docs(gaps) corrections - #1438

Closed
seonghobae wants to merge 69 commits into
mainfrom
claude/noema-contextualwisdomlab-commercialization-afow1j
Closed

fix(coverage): unblock org-wide OpenCode approval + docs(gaps) corrections#1438
seonghobae wants to merge 69 commits into
mainfrom
claude/noema-contextualwisdomlab-commercialization-afow1j

Conversation

@seonghobae

@seonghobae seonghobae commented Aug 30, 2026

Copy link
Copy Markdown
Contributor

Summary

Exact current identity and evidence

  • exact head: 18987a7191f070fdcb134d5feb96a07442c39a98
  • protected base: main@1ff8268255b061461d9d49b4cab4febf9a8e7bfa
  • current delta remains six files: .gitignore, CHANGELOG.md, docs/product-technical-gap-baseline.md, scripts/ci/contextual_orchestrator_review_sidecar.sh, and two sidecar tests.
  • scripts/ci/pingora_edge_policy.py is not in the current diff. The earlier coverage-fix narrative below is historical and must not be treated as this PR's current source delta.
  • current-head generated Security Scan, SAST, CodeQL, Python Security, OSV, SBOM, secret, Scorecard, readiness quality, and Strix changed-path quality workflows are terminal success.
  • exact-current-head required OpenCode, Noema, and Strix review/scan evidence is absent. The previous required runs belong to historical head 50febfe7a9bd74c8c33d1eef6526a33f116f5c2f and cannot satisfy this head.
  • historical Strix run 33331290092 attempt 1 verified 50febfe7, passed discovery/health/gateway preflight, then timed out after 5400 seconds and emitted STRIX_PROVIDER_UNAVAILABLE without an authoritative scan result; attempt 2 was cancelled during provisioning. This is provider/infrastructure evidence recorded on fix(ci): gate Strix's orchestrator/free access on live diversity evidence #1437, not a source finding or current-head pass.
  • current non-outdated unresolved threads: 0; exact-current-head formal approval: absent.

Original summary (docs correction + sidecar tail widening — unchanged):

  1. Docs correction (docs/product-technical-gap-baseline.md): the "2026-08-30 post-chore(fuzz): remove dead duplicate fuzz target #1486/fix(coverage): unblock org-wide OpenCode approval + docs(gaps) corrections #1438 wake" entry misdiagnosed the incident on two counts, found by a 7-agent investigation:
    • Bytez can never populate orchestrator/free regardless of its HTTP status (_parse_bytez never sets is_free) — its logged HTTP 500 changed nothing about the outcome.
    • The request_failed status=413 line is the sidecar's own unconditional offline self-test, not a live ZDR-catalog prefetch that "fell back" to anything.
    • This branch's own follow-up "correction" entry has itself been revised to defer to main's much more thorough "sidecar-preflight outage: consolidated evidence" entry as the authoritative root cause, rather than presenting this branch's own generic "two call sites, no retry" theory as confirmed for this specific incident (that mechanism is still real, just not what caused this one — see ContextualWisdomLab/contextual-orchestrator#923).
  2. SIDECAR_STDERR_TAIL_LINES: widens the sidecar's failure-path stderr tail from a fixed 20 lines to a named constant (60), complementary to (not overlapping with) main's new preflight-evidence log line — so discovery-error diagnostics can't be silently truncated alongside it.

Also includes the original §5.1 next-increment-list refresh (#1297 already merged; #1345/#1326 closed unmerged), the naruon-Noema role-clarification entry, and a CodeRabbit 10-star/rate-limit gap entry, all from earlier in this branch's history.

Verification

  • PYTHONPATH=. python -m coverage run -m pytest tests -q → 1897 passed, 1 skipped, 21 subtests, coverage TOTAL 100%.
  • python -m interrogate → 100.0%.
  • bash -n scripts/ci/contextual_orchestrator_review_sidecar.sh → syntax OK.
  • PYTHONPATH=. python -m pytest tests/test_product_technical_gap_baseline.py -q → 5 passed (doc contract markers intact).
  • PYTHONPATH=. python -m pytest tests/test_pingora_edge_policy.py -q → 61 passed.

Related

  • ContextualWisdomLab/contextual-orchestrator#923 — companion discovery-side retry fix (independent resilience improvement, not the fix for this specific incident).
  • ContextualWisdomLab/naruon#1486 — the PR whose CI run first surfaced this incident.
  • ContextualWisdomLab/.github#1398 — the owner's own in-flight, more extensive coverage-evidence/Python-lock work; this PR's dead-code fix is narrowly scoped and orthogonal to it.

Summary by CodeRabbit

  • 개선 사항

    • 오케스트레이터 사이드카가 초기화·상태 확인 실패 시 더 많은 진단 로그를 표시합니다.
    • 제공자 패밀리별 후보 상한을 확대했습니다.
  • 버그 수정

    • 커버리지 검사에서 발생하던 도달 불가능한 코드 관련 실패를 해결했습니다.
    • 잘못된 시도 횟수 값(예: "00", "0000")을 올바르게 거부합니다.
  • 문서

    • 기술적 격차 기준선과 후속 작업 상태를 최신 내용으로 갱신했습니다.
  • 테스트

    • 확장된 진단 로그와 잘못된 입력값 검증을 확인하는 테스트를 추가했습니다.

…ma increment

#1297 was already merged and #1345/#1326 were closed unmerged, but all
three were still listed as pending candidates for this loop's next pass.
Replace with current state and record this pass's actual increment:
ContextualWisdomLab/naruon#1486 adds a check_calendar_conflict tool to
naruon's noema-general-agent, reusing the existing deterministic conflict
policy instead of a second one, and clarifies that naruon's Noema and
this repo's central review-bot Noema are separate agents sharing only a
name.
@coderabbitai

coderabbitai Bot commented Aug 30, 2026

Copy link
Copy Markdown

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 7f4e6c61-24ed-4d56-96e4-e60877a2dde0

📥 Commits

Reviewing files that changed from the base of the PR and between 50febfe and 8a843c4.

📒 Files selected for processing (1)
  • docs/product-technical-gap-baseline.md
🚧 Files skipped from review as they are similar to previous changes (1)
  • docs/product-technical-gap-baseline.md

Included review availability: Your plan provides up to 1 included review per hour; 0 remain after this review.


📝 Walkthrough

Walkthrough

Sidecar의 stderr 진단 출력 한도를 20줄에서 60줄로 확장했습니다. Provider-family별 catalog 후보 상한을 4에서 8로 변경했습니다. 선행 0이 포함된 잘못된 재시도 설정을 거부하고 관련 테스트와 운영 문서를 갱신했습니다.

Changes

Sidecar 진단 및 운영 기록

Layer / File(s) Summary
Sidecar 진단 출력 및 preflight 검증
scripts/ci/contextual_orchestrator_review_sidecar.sh, tests/test_contextual_orchestrator_review_sidecar_contract.py, tests/test_contextual_orchestrator_review_runtime_preflight.py
Sidecar가 세 진단 경로에서 SIDECAR_STDERR_TAIL_LINES=60을 사용합니다. Provider-family별 catalog 후보 상한을 8로 변경했습니다. 선행 0이 포함된 잘못된 REVIEW_PREFLIGHT_GATEWAY_MAX_ATTEMPTS 값을 거부합니다. 계약 테스트가 변경된 동작을 검증합니다.
사건 분석 및 후속 작업 기록
CHANGELOG.md, docs/product-technical-gap-baseline.md
Coverage 수정, preflight 원인, 리뷰 트리거 조건, 관련 PR 상태와 후속 작업을 기록했습니다.
저장소 제외 규칙
.gitignore
.claude/ 디렉터리를 Git 무시 규칙에 추가했습니다.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Merge Risk: 🔵 Low · up to 8a843

The change mainly improves failure diagnostics and documentation, but the sidecar still has a configuration edge case where leading-zero zero values can disable retries through an immediate failure; the PR is mergeable with explicit owner awareness and follow-up.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 5 functions across 3 files. (1 skipped: 1 …
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 제목의 docs(gaps) corrections 부분은 gap-baseline과 CHANGELOG 수정이라는 주요 변경을 정확히 설명합니다. 그러나 현재 diff에 scripts/ci/pingora_edge_policy.py 변경이 없으므로 coverageunblock org-wide OpenCode approval 표현은 변경 범위를 …
Full details: Docstring Coverage

Explanation

Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 5 functions across 3 files. (1 skipped: 1 unsupported.)

Full details: Title check

Explanation

제목의 docs(gaps) corrections 부분은 gap-baseline과 CHANGELOG 수정이라는 주요 변경을 정확히 설명합니다. 그러나 현재 diff에 scripts/ci/pingora_edge_policy.py 변경이 없으므로 coverageunblock org-wide OpenCode approval 표현은 변경 범위를 완전히 반영하지 않습니다.

✨ Finishing Touches 💡 1
🛠️ Fix failing CI checks 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch claude/noema-contextualwisdomlab-commercialization-afow1j

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.

Copy link
Copy Markdown
Contributor Author

opencode-review is currently failing because there is no APPROVED/CHANGES_REQUESTED review from opencode-agent at the current head yet (##[error]No APPROVED or CHANGES_REQUESTED from opencode-agent on the current head...). This is the required-check gate correctly failing closed while it waits for the separate async OpenCode dispatch to post a current-head verdict — expected for a freshly-pushed head, not a defect in this PR's diff (docs-only change to docs/product-technical-gap-baseline.md and CHANGELOG.md). No action needed; it clears once the dispatch posts, and the central queue scanner (scan-pr-queue, seen success on this same head) retries it. Keeping this PR watched.


Generated by Claude Code

naruon#1486 confirms the current sidecar pin (30c6d716...) actually
reaches a hosted PR-target run, but still fails closed with a new
signature: a non-fatal 413 on ZDR-catalog prefetch (falls back to a
live feed) followed by bytez discovery returning HTTP 500, which empties
the orchestrator/free pool the same way the already-tracked structural
gap describes. Also confirms opencode-review's gate correctly fails
closed awaiting the async dispatch verdict on fresh heads (naruon#1486,
.github#1438) — expected, not a defect.

Copy link
Copy Markdown
Contributor Author

noema-review is also failing on this PR's current head with the identical signature already documented on ContextualWisdomLab/naruon#1486 (and in docs/product-technical-gap-baseline.md): sidecar vendors the current pin 30c6d716… fine, a ZDR-catalog prefetch gets 413 request_too_large and falls back to a live OpenRouter feed (non-fatal), then the sidecar exits before /healthz — same central orchestrator/free-pool-exhaustion class, not caused by this PR's docs-only diff. Not duplicating the full write-up here; see the naruon PR and the gap baseline for details. I'm actively investigating a real fix for the underlying single-provider fragility rather than just continuing to log it — will report back here and on the gap baseline once that lands.


Generated by Claude Code

claude added 2 commits August 30, 2026 11:14
…tail

The review sidecar's live warm-up preflight already records a bounded
error_type/http_status per rejected route, but only into a JSON
artifact -- not the CI job's visible console log. That made a real
fail-closed incident impossible to diagnose as transient or not
without downloading the artifact separately, and led directly to a
misdiagnosis this pass corrects in docs/product-technical-gap-baseline.md.

Add _log_preflight_rejections (mirrors the existing _log_discovery_errors
visibility fix), a matching sanitizer allowlist entry, and widen the
failure-path stderr tail from a fixed 20 lines to a named
SIDECAR_STDERR_TAIL_LINES=60 so discovery errors plus preflight
rejections plus summary lines can no longer silently truncate.

Companion to ContextualWisdomLab/contextual-orchestrator#923, which
fixes the analogous single-shot discovery fetch. This repo's own
completion-warm-up-probe call site is deliberately left single-shot;
see that PR's description for the latency/amplification risk that
ruled out retrying it blind.
Adversarial re-investigation (triggered by direct feedback that a
single provider erroring should never fail-close org-wide review CI)
found the "2026-08-30 post-#1486/#1438 wake" entry misdiagnosed the
incident on two counts: Bytez can never populate orchestrator/free
regardless of HTTP status (_parse_bytez never sets is_free), and the
413 line is the sidecar's own unconditional self-test, not a live
ZDR-prefetch fallback -- also present in two earlier entries, flagged
here rather than hand-edited there. The actual terminating message was
"review sidecar preflight failed" (a live warm-up-probe rejection),
not the "no eligible models" path those entries claimed.

Records the real root cause (two single-shot HTTP call sites with no
retry) and the fix that follows: contextual-orchestrator#923 (discovery
retry) and this repo's own #1438 (preflight-rejection visibility +
wider stderr tail). Updates §5.1 to track both to merge.
@seonghobae seonghobae changed the title docs(gaps): refresh stale §5.1 next-increment list, record naruon Noema increment fix(sidecar): surface preflight-rejection detail; correct gap-baseline bytez misattribution Aug 30, 2026
main advanced with the owner's own parallel investigation into the
same sidecar-preflight incident this branch was fixing, with far more
precise evidence than this branch's own analysis had (actual hosted-run
preflight/discovery artifacts, not just log-pattern reading). The real
root cause turned out to be contextual_orchestrator_review_policy.py's
family_cap selecting the same alphabetically-first candidates every
run -- 2 of which are permanently-retired NVIDIA model ids returning
HTTP 404 forever, not a transient failure -- plus a too-tight gateway
smoke-test timeout and a max_tokens/probe-budget desync. All three are
already fixed on main (family_cap 4->8, gateway timeout 30s->120s,
max_tokens 16->4096).

Conflict resolution:
- CHANGELOG.md / docs/product-technical-gap-baseline.md: kept both
  sides' entries; revised this branch's own "correction" entry to
  defer to main's much more thorough "sidecar-preflight outage:
  consolidated evidence" entry as the authoritative root cause and
  fix, rather than presenting this branch's own generic
  "two call sites, no retry" theory as confirmed. That mechanism is
  still real (kept, reframed as independent/complementary), just not
  what caused this specific incident.
- scripts/ci/contextual_orchestrator_review_sidecar.sh: kept main's new
  preflight-report console dump and this branch's
  SIDECAR_STDERR_TAIL_LINES threading -- complementary, not
  overlapping.

Deliberate follow-up simplification in the same commit: dropped this
branch's own _log_preflight_rejections (launcher.py), its sanitizer
allowlist entry, and its tests -- main's own
`log "sidecar preflight route evidence: ..."` fix already surfaces the
same already-bounded-safe preflight_report JSON to the console,
achieving the same operator-visibility goal more directly. Keeping
both would have been duplicate code solving the same problem twice.

Full suite: 1897 passed, 1 skipped, 21 subtests; coverage 100% on all
touched files (pre-existing pingora_edge_policy.py:274 gap, owned by
#1398, unaffected); interrogate 100%; bash -n clean.
@seonghobae seonghobae changed the title fix(sidecar): surface preflight-rejection detail; correct gap-baseline bytez misattribution docs(gaps): correct bytez/413 misattribution; widen sidecar failure-log tail Aug 30, 2026
@seonghobae
seonghobae marked this pull request as ready for review August 30, 2026 11:28

@devin-ai-integration devin-ai-integration Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note

This report is out of date. Scroll down for Devin Review's latest report on this PR.

✅ Devin Review: No Issues Found

Devin Review analyzed this PR and found no bugs or issues to report.

Devin Review

claude added 2 commits August 30, 2026 11:30
…ixes

Summarizes the wakeup that found main had advanced with the owner's
own deeper investigation into the same bytez/preflight incident,
reconciled this branch's three open PRs against it (merged current
main/develop into each, dropped the now-redundant preflight-visibility
fix, marked all three ready for review), and explicitly defers
.github#1347's merge conflict to a dedicated next pass given it
overlaps a file main has independently hardened for SSRF.
… finding

naruon#1486 and contextual-orchestrator#923 both hit a PR-governance
metadata-gate block that looked like a blocking CodeRabbit finding but was
actually CodeRabbit's own "approval pending, not reviewed yet" state -- every
ContextualWisdomLab repo is below CodeRabbit's 10-GitHub-star automatic-review
threshold, so it never reviews a new commit without an explicit
@coderabbitai review trigger. Triggered both PRs manually; documents the
structural gap and a deferred central-automation candidate fix.

Copy link
Copy Markdown
Contributor Author

@coderabbitai review


Generated by Claude Code

devin-ai-integration[bot]

This comment was marked as resolved.

claude added 2 commits August 30, 2026 11:53
Devin review on #1438 flagged two real issues in the CodeRabbit gap-baseline
entry: bare naruon#1486/contextual-orchestrator#923 references don't create
durable cross-repo links (missing the org prefix), and the claim that "every
org PR" is affected outran the evidence (only 4 repos were actually checked).
Both fixed.

Copy link
Copy Markdown
Contributor Author

opencode-review is failing on the current head (ef311a0) with ##[error]No APPROVED or CHANGES_REQUESTED from opencode-agent on the current head... — the same documented, expected wait-state already noted on ContextualWisdomLab/naruon#1486 and ContextualWisdomLab/contextual-orchestrator#923: the gate correctly fails closed until the separate async OpenCode dispatch posts a current-head verdict. Not a defect in this PR's diff. No action needed; will clear once the dispatch posts and the central queue scanner retries it.


_Generated by Claude Code


Generated by Claude Code

coderabbitai[bot]

This comment was marked as resolved.

… a fix

CodeRabbit correctly flagged that "already fixed"/"resolves" overstates the
4->8 family-cap raise: it reduces the odds of the same retired/timed-out
candidates being selected every run, but doesn't guarantee against it, and
hosted-run confirmation of the fix is still pending. Softened both the
changelog bullet and the gap-baseline correction entry to "mitigates ...
hosted confirmation remains pending".
@coderabbitai

coderabbitai Bot commented Aug 30, 2026

Copy link
Copy Markdown

@seonghobae, I will review the changes in #1438.

⚠️ Action not completed

Review rate limited.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@opencode-agent opencode-agent Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

OpenCode reviewed the current-head product diff. Coverage is a separate gate.

Changed files

  • CHANGELOG.md — repository behavior
  • docs/product-technical-gap-baseline.md — operator or user guidance
  • scripts/ci/contextual_orchestrator_review_sidecar.sh — review and security gate shell path
  • tests/test_contextual_orchestrator_review_sidecar_contract.py — regression suite

Changed behavior

flowchart LR
  PR["PR changed files"] --> Evidence["OpenCode bounded evidence"]
  Evidence --> S1["Repository file: CHANGELOG.md"]
  S1 --> I1["repository behavior"]
  I1 --> R1["Review risk: Repository file: CHANGELOG.md"]
  R1 --> V1["required checks"]
  Evidence --> S2["Docs: product-technical-gap-baseline.md"]
  S2 --> I2["operator or user guidance"]
  I2 --> R2["Review risk: Docs: product-technical-gap-baseline.md"]
  R2 --> V2["docs review"]
  Evidence --> S3["CI script: contextual_orchestrator_review_sidecar.sh"]
  S3 --> I3["review and security gate shell path"]
  I3 --> R3["Review risk: CI script: contextual_orchestrator_review_sidecar.sh"]
  R3 --> V3["bash -n plus Strix self-test"]
  Evidence --> S4["Test: test_contextual_orchestrator_review_sidecar_contract.py"]
  S4 --> I4["regression suite"]
  I4 --> R4["Review risk: Test: test_contextual_orchestrator_review_sidecar_contract.py"]
  R4 --> V4["targeted test run"]
Loading

Findings

No source-backed product finding is synthesized from the coverage gate. A coverage miss belongs in the status comment.

  • Head SHA: c11b68c2e3cb4d14099c0925f4239c1ae13dc674
  • Workflow run: 33310753001
  • Workflow attempt: 1
  • Coverage gate: failure

Review outcome

Coverage is a gate, not the review. This body reviews the changed product files.

Changed-File Evidence Map

flowchart LR
  PR["PR changed files"] --> Evidence["OpenCode bounded evidence"]
  Evidence --> S1["Repository file: CHANGELOG.md"]
  S1 --> I1["repository behavior"]
  I1 --> R1["Review risk: Repository file: CHANGELOG.md"]
  R1 --> V1["required checks"]
  Evidence --> S2["Docs: product-technical-gap-baseline.md"]
  S2 --> I2["operator or user guidance"]
  I2 --> R2["Review risk: Docs: product-technical-gap-baseline.md"]
  R2 --> V2["docs review"]
  Evidence --> S3["CI script: contextual_orchestrator_review_sidecar.sh"]
  S3 --> I3["review and security gate shell path"]
  I3 --> R3["Review risk: CI script: contextual_orchestrator_review_sidecar.sh"]
  R3 --> V3["bash -n plus Strix self-test"]
  Evidence --> S4["Test: test_contextual_orchestrator_review_sidecar_contract.py"]
  S4 --> I4["regression suite"]
  I4 --> R4["Review risk: Test: test_contextual_orchestrator_review_sidecar_contract.py"]
  R4 --> V4["targeted test run"]
Loading

@opencode-agent

opencode-agent Bot commented Aug 30, 2026

Copy link
Copy Markdown
Contributor

OpenCode Review Overview

Coverage evidence did not pass, so approval is blocked. The formal pull-request review is the source-backed diff review, not this status comment.

claude added 2 commits August 30, 2026 12:22
_load_changed_files's post-loop PolicyError at the end of the pagination
loop can never execute: 31 full 100-item pages would push the file count
past 3,000 during page 31's own iteration (30 full pages = exactly 3,000),
tripping the len(files) > 3_000 raise inside the loop before the outer
range(1, 32) can ever exhaust without an early return or that inner raise.

This dead line has been silently failing this repo's org-wide
coverage-evidence gate (fail_under=100 on scripts/ci) for every PR reviewed
through the central OpenCode/Noema/Strix dispatcher -- confirmed via live
Actions logs on multiple unrelated PRs (.github#1161, #1438) all showing
"Coverage failure: total of 99 is less than fail-under=100" at this exact
line, which in turn blocks opencode-agent from ever posting an APPROVED
verdict anywhere in the org. Marked pragma: no cover with a justification,
matching this repo's existing convention for provably-unreachable
defensive code (see other pragma: no cover sites in scripts/ci/*.py).

Verified: full suite 1897 passed, 1 skipped, 21 subtests; coverage TOTAL
100% (9966/9966 statements, 3926/3926 branches); interrogate 100%.
Consolidates a 5-agent investigation into why opencode-agent had not posted
a verdict on any of the three tracked PRs: naruon#1486 is stuck on a stale
scheduler thread-count snapshot, contextual-orchestrator#923 is missing a
cross-repo dispatch credential in its scheduler run, and .github#1438's
dispatch ran but was blocked by the pingora_edge_policy.py coverage bug
fixed in the preceding commit. Also records hosted-run confirmation that
the earlier family_cap sidecar mitigation is now working (3/3 post-fix
runs clean), while flagging a separate, still-open "healthz passes then
completion request hangs" signature on the same commit.
@seonghobae seonghobae changed the title docs(gaps): correct bytez/413 misattribution; widen sidecar failure-log tail fix(coverage): unblock org-wide OpenCode approval + docs(gaps) corrections Aug 30, 2026
devin-ai-integration[bot]

This comment was marked as resolved.

devin-ai-integration[bot]

This comment was marked as resolved.

claude added 4 commits August 31, 2026 23:31
…e-scoping fixes

Documents this pass's three genuine bugs (project-graph-projection
workspace mismatch, import_fixtures.py duplicate-check missing
workspace filter, bootstrap_db.py missing second legacy constraint
name) and the repeat/no-registry-exists finding, plus the
false-negative test lesson from the duplicate-check assertion.
…h-quarantine fix, two reasoned deferrals)

Documents the fix for base64 quarantine payloads leaking into hybrid
search, and the reasoning behind deferring TicketTask workspace
scoping (real gap, separate increment) and skipping a real-Postgres
smoke test for the reparse path (no lock/constraint semantics a mock
would hide).
…he 20 hidden real-Postgres test bugs it masked

naruon#1486's Devin finding about 0001's fresh-install migration crash
led to installing a local PostgreSQL to verify it -- which revealed
naruon's CI backend job has no Postgres service at all, so every
@pytest.mark.postgres test has always silently skipped in CI. Fixed
the critical migration bug plus 19 hidden workspace_id/ORM-default
test gaps (naruon commit b9b02dd0); records the still-open follow-up
of actually wiring a Postgres service into naruon's CI.
…ace fixes and two CodeRabbit verifications

Documents two more Devin findings fixed on naruon (RESULT_PENDING
cursor starvation in NewsdomRecognitionWorker, unlocked reparse-intent
TOCTOU race), plus two CodeRabbit findings verified: one correctly
deferred (pre-existing raw-SQL migration pattern, out of scope), one
confirmed a false positive (workspace mismatch that the query never
actually reads).
@seonghobae

Copy link
Copy Markdown
Contributor Author

Contextual-Orchestrator와 관계한 것들을 같이 손보든 어쩌든 해결하세요. Bypass merge 필요하면 가능 (chicken and eggs 상황이라면) + NVIDIA NIM 만 쓰는 건 허용하지 않아요. Contextual-Orchestrator를 쓰세요. Timeout은 적어도 3시간으로 잡으세요. 120초 같은 건 당황스럽군요. Strix가 6시간 이상 동작해서 취약점 잡는 것도 본 일이 있습니다. Opencode와 Noema 는 Coderabbitai 및 Devin 수준으로 실제로 리뷰를 하게 하시오. Strix도 보안 리뷰를 꼼꼼하게 하도록 하시오. 특히 보안 리뷰는 전체 코드로 수행하는 것입니다. Contextual-Orchestrator는 실시간으로 빠르면서 능력이 좋은 모델에 요청을 보내어 시간을 당기시오. @opencode-agent 라고 부르면 호출되는 기능도 인터넷 가이드에는 /oc 라고 나와있기 때문에 이 점도 확인해 보는 게 좋겠습니다.

…ling

The org's standing directive requires central Strix/OpenCode/Noema scans
to get at least a 3-hour floor (observed real runs go well past that).
Strix's own budget was 150-minute process / 155-minute total (obfuscated
via budget_suffix, per contract, so the literal env var names never
appear in workflow logs), bounded by a 170-minute step and 200-minute
job -- 155 minutes falls short of the 3-hour floor.

Raise process/total/step/job proportionally to the actual maximum job
execution time GitHub-hosted runners allow (6 hours): job 200->360
(the platform ceiling itself), step 170->330, total budget 9300->18900s
(315 min), process budget 9000->18600s (310 min) -- preserving the
original buffer ratios between each layer. Update the matching
scripts/ci/test_strix_quick_gate.sh contract assertions in lockstep.

Also records this investigation, plus the contextual-orchestrator
single-tool-call-limit failover fix (ContextualWisdomLab/contextual-orchestrator#986)
and confirmation that Strix already scans the full codebase and the
@opencode-agent mention convention is already correct, in
docs/product-technical-gap-baseline.md.
scripts/ci/noema_review_gate.py's call_llm sent its actual review-
completion request to the contextual-orchestrator gateway with a bare
urllib timeout=120 and no retry of its own -- unlike the sidecar's own
preflight self-check (ADR-0005, deliberately kept at 120s with its own
bounded retry), this call had no fallback at all.

Live reproduction today (naruon#1486, job 99690488248): the gateway's
own routing pool rejected 11 of 12 candidates (mostly TimeoutError, two
retired-model 404s, one 429) and picked its one remaining "ready" agent;
that agent's real completion for a full PR diff ran past 120s with
nothing to fall back to, failing the entire required review check with
TimeoutError.

Replace the bare literal with a named
NOEMA_LLM_REQUEST_TIMEOUT_SECONDS = 10800 (3h, matching the org's
standing at-least-3-hour floor for central Strix/OpenCode/Noema review
latency), and update the tests that pinned the old 120s value.

Also fixes 3 pre-existing test failures inherited from origin/main
(commit a3f9f9b, #1531): that commit
changed opencode-review-dispatch.yml's validate-pr-metadata step from
exact-matching head_sha to warn-and-proceed on a head-only advance, but
did not update the two tests that pin the workflow's exact git blob SHA
(test_pr_review_autofix_nvidia_nim_contract.py,
test_opencode_rust_coverage_toolchain_contract.py) or the assertion in
test_opencode_agent_contract.py that still looked for the old
exact-match line -- main itself was red on these three tests.
origin/main reverted a3f9f9b (commit 7b1a028, #1540, no rationale
given) right after this branch merged it and adapted
test_pr_review_autofix_nvidia_nim_contract.py's REVIEW_DISPATCH_BLOB_SHA
and test_opencode_agent_contract.py's metadata-step assertion to match
its new warn-and-proceed behavior. Restore both to their original
exact-match values now that opencode-review-dispatch.yml itself is back
to its pre-a3f9f9b6 content (blob 2aa245e).

Copy link
Copy Markdown
Contributor Author

요청하신 7개 항목을 각각 실제 코드/워크플로 추적으로 조사했습니다. 추측이 아니라 확인한 것만 아래에 남깁니다.

1) Contextual-Orchestrator 관련 수정

수정 완료 — contextual-orchestrator#986.

naruon#1486의 Strix 스캔에서 실제로 관측된 문제: 일부 NVIDIA NIM 호스팅 모델(vision 지원 Llama 계열)이 tool call을 두 번 이상 요청하는 턴을 거부하는데, 이 거부가 invalid_request_error라는 일반 에러 코드로 감싸져 있고 모델 고유의 "this model only supports single tool-calls at once" 문장이 더 긴 agent-prefixed 메시지 안에 묻혀 있었습니다. 기존 _is_passthrough_failover_error가 이를 인식하지 못해 다음 capability-matched agent로 넘어가지 않고 스캔 전체가 중단됐습니다.

기존 _is_provider_tool_description_limit_error와 같은 모양으로 _is_single_tool_call_limit_error()를 추가하고 failover 판단에 연결했습니다. 새 회귀 테스트로 수정 전 진짜 RED(ProviderUpstreamError로 전체 실패) → 수정 후 GREEN을 확인했고, 전체 스위트는 2824 passed / 1 skipped(무관한 사전 존재 fast_mlsirm optional-dependency 갭 1건 제외 — 이 diff와 무관, 별도 후속 필요)입니다.

2) NVIDIA NIM 단독 사용 금지 → Contextual-Orchestrator 사용

중앙 리뷰 파이프라인은 이미 pr-review-autofix.ymlscripts/ci/contextual_orchestrator_review_sidecar.sh 경로로 contextual-orchestrator 게이트웨이를 거치도록 배선되어 있음을 코드로 직접 확인했습니다 — NIM에 직접 요청을 보내지 않습니다. 위 1번 수정은 그 게이트웨이 내부에서 특정 NIM 모델 하나의 결함이 전체 요청을 죽이지 않고 다른 provider로 정상 failover하도록 만드는 것이라, "NIM만 의존하지 않는다"는 요청의 실질을 한 단계 더 강화합니다.

3) Timeout을 최소 3시간으로

수정 완료. strix.yml의 실제 예산(설명 주석은 "150분 process / 155분 total budget"이라 말했고, budget_suffix="TIME""OUT" 문자열 결합으로 GitHub 로그에 리터럴 env var 이름이 노출되지 않게 난독화된 채로 실제 그 값이 배선되어 있음을 scripts/ci/test_strix_quick_gate.sh 계약으로 재확인)이 155분(2h35m)으로, 요청하신 "최소 3시간" 바닥에 못 미쳤습니다.

GitHub-hosted runner(ubuntu-latest)는 job 실행시간이 플랫폼 자체에서 6시간(360분)으로 하드 캡되어 있어 — timeout-minutes를 얼마로 설정하든 그 이상은 실행되지 않습니다 — 그 한도까지 기존 여유시간 비율을 유지하며 전부 상향했습니다:

항목 이전 이후
job timeout-minutes 200 360(플랫폼 최댓값)
step timeout-minutes 170 330
내부 total budget 9300초(155분) 18900초(315분)
내부 process budget 9000초(150분) 18600초(310분)

내부 실질 스캔 예산이 315분(5h15m)이 되어 "최소 3시간"을 여유 있게 충족하고, 단일 GitHub-hosted job이 물리적으로 도달 가능한 최댓값(6시간)에 근접합니다. 관측하셨다는 "6시간 이상"이 정확히 이 워크플로/러너였는지는 확인할 방법이 없었습니다 — self-hosted runner였거나 로컬 실행이었을 가능성이 있어 보입니다. 알려주시면 그 경로를 정확히 다시 추적하겠습니다.

그런데 "120초"는 이 조사 도중 실제로 잡았습니다. naruon#1486noema-review 필수 체크가 방금 이 코멘트를 작성하는 중에 실패했고, job 로그를 보니 정확히 그 원인이었습니다: scripts/ci/noema_review_gate.py(call_llm)가 contextual-orchestrator 게이트웨이에 실제 리뷰 완료 요청을 보낼 때 urllib.requesttimeout=120을 하드코딩해 두고 있었고, 재시도 로직이 전혀 없었습니다. 이번 실행에서는 게이트웨이의 preflight 확률이 12개 후보 중 11개를 거부(대부분 TimeoutError, 일부는 영구 은퇴된 모델의 404, 하나는 429)하고 남은 1개(meta/llama-3.2-11b-vision-instruct)만 "ready"로 판정했는데, 실제 PR diff 전체를 다루는 무거운 완료 요청이 그 120초 안에 끝나지 못해 TimeoutError: timed out으로 전체 필수 체크가 실패했습니다. (같은 파일의 sidecar preflight 자체 점검용 120초는 ADR-0005로 의도적으로 고정된 별개의 값이고 자체 재시도가 있어 손대지 않았습니다 — 이번에 고친 것은 재시도가 전혀 없던 실제 리뷰 완료 호출 쪽입니다.) 이 하드코딩된 timeout=120을 이름 있는 상수 NOEMA_LLM_REQUEST_TIMEOUT_SECONDS = 10800(정확히 요청하신 "최소 3시간")으로 올리고 대응 테스트도 갱신했습니다 — 이 diff의 일부로 포함되어 있습니다. 다만 이 스크립트는 OpenCode의 풀/재시도/failover 체계에 비해 단일 호출·무재시도 구조라는 점 자체가 4번 항목("Noema를 CodeRabbit/Devin 수준으로")과도 연결되는 구조적 격차로 보이며, 재시도 로직 추가는 이번 패스 범위를 넘어서 별도로 남겨두었습니다.

4) OpenCode/Noema를 CodeRabbit/Devin 수준으로

결론 유보, 후속 필요. 현재 예산 체계(위에서 본 3h15m~5h25m)는 결코 얕지 않지만, "CodeRabbit/Devin 수준의 실제 리뷰 깊이"는 예산 크기가 아니라 프롬프트·평가 기준·산출물 품질의 문제라 이번 패스의 코드 추적만으로는 결론 낼 수 없었습니다. 실제 PR에서 나온 리뷰 산출물을 CodeRabbit/Devin의 산출물과 나란히 비교하는 별도 품질 평가 트랙이 필요하다고 보고, docs/product-technical-gap-baseline.md에 후속 항목으로 남겼습니다.

5) Strix 전체 코드 보안 리뷰

이미 올바르게 구현되어 있음(수정 불필요). STRIX_TARGET_PATH__PR_SCOPE__ sentinel은 스캔 범위가 아니라 "PR 이벤트에서는 신뢰 가능한 base checkout이 아니라 격리된 PR-head 임시 스코프에서 읽어라"는 격리 경로 선택 플래그이고, scripts/ci/strix_quick_gate.sh가 이를 TARGET_PATH="$REPO_ROOT"(레포 전체)로 해석합니다. Strix는 이미 diff-only가 아니라 전체 코드베이스를 스캔합니다.

6) Contextual-Orchestrator가 빠르고 능력 좋은 모델로 라우팅

부분 확인, 후속 필요. model_discovery.py의 모델 랭킹(select_cheapest_discovered_agent 등)은 발견된 모델을 가격으로만 랭크하고, 지연시간(latency)이나 처리 능력은 랭킹 기준에 없습니다. 1번 수정은 "느리거나 결함 있는 모델에 걸려 멈추지 않고 다음 모델로 넘어간다"는 점에서는 도움이 되지만, "가장 빠른 모델을 우선 선택한다"는 명시적 최적화는 아직 없습니다. 관측된 응답 지연을 랭킹에 반영하는 별도 증분이 필요하다고 보고 gap-baseline에 남겼습니다.

7) @opencode-agent 호출 규칙

이미 정확함(수정 불필요). scripts/ci/agent_mention_router.pyAGENT_NAMES["opencode-agent"]@opencode-agent를 정확히 매칭하는 정규식입니다. /oc는 업스트림 OpenCode 프로젝트 자체의 일반 문서에 나오는 무관한 명령어로, 이 조직의 커스텀 멘션 컨벤션과는 별개입니다.


전체 경위는 docs/product-technical-gap-baseline.md의 2026-09-01 신규 섹션에 근거·PR 링크와 함께 기록했습니다.


Generated by Claude Code

devin-ai-integration[bot]

This comment was marked as resolved.

1. strix.yml's retry-reserve check silently disabled every retry: raising
   process_budget_seconds to 18600 without raising the wrapper's own
   strix_gate_deadline (still 9600) made retry_reserve_seconds
   (process_budget_seconds + backoff) exceed the deadline unconditionally,
   so a transient provider outage that used to recover on attempt 2 would
   now fail closed on attempt 1 every time. Raise strix_gate_deadline to
   19200 (same 600s buffer under the new 330-minute step, proportional to
   the original ratio) and add a regression test
   (test_retry_deadline_reserves_room_for_at_least_one_retry) asserting
   the live numbers -- not synthetic ones -- keep a retry reachable.

2. noema_review_gate.py's call_llm can recurse once for a validator-
   rejected repair; two independent NOEMA_LLM_REQUEST_TIMEOUT_SECONDS
   (10800s) calls would total 21600s -- exactly the 6h GitHub-hosted job
   execution ceiling, leaving no room for sidecar provisioning or cleanup
   and turning a fast failure into a reliable 6h one. Add a shared
   NOEMA_LLM_TOTAL_BUDGET_SECONDS (19800s) deadline threaded through the
   repair recursion; each call's own request timeout is now capped to
   whatever remains of it. New test
   (test_call_llm_repair_call_shares_the_total_budget_deadline) proves
   the repair call's timeout shrinks when the first call has already
   consumed most of the shared budget.

3. strix.yml's timeout comment misattributed the 3-hour floor to the
   standing operating directive; that directive only accepts scans over
   two hours per model. The 3-hour floor came from the repo owner's later
   comment on #1438 -- corrected the citation.

All three found by Devin Review on #1438.
devin-ai-integration[bot]

This comment was marked as resolved.

1. noema_review_gate.py's timeout comment carried the same misattribution
   as strix.yml's -- fixed there but missed here -- crediting the 3-hour
   floor to the standing operating directive (which only accepts scans
   over two hours per model) instead of the owner's later comment on
   #1438. Corrected the citation.

2. call_llm clamped an expired shared deadline to a 1-second timeout
   instead of stopping, so a late validator-rejected repair would still
   open a network request and burn through the job's already-exhausted
   reserved cleanup time. Raise TimeoutError immediately when the shared
   budget is gone, per Devin's suggested fix. New test
   (test_call_llm_raises_instead_of_sending_a_request_on_an_expired_budget)
   proves no request is sent once the deadline has passed -- verified
   genuine RED (the old clamp let a 1-second request through) before GREEN.

3. strix.yml's retry-loop comment still named the old 200-minute job
   budget after the job became 360 minutes, and did not make clear that
   the 3-attempt retry cap is conditional on an early failure rather than
   a guarantee of three full-budget attempts. Updated the comment with
   both corrections.

All three found by Devin Review's second pass on
#1438.
devin-ai-integration[bot]

This comment was marked as resolved.

Devin Review (#1438) noted call_llm's repair
call reuses the same absolute deadline, so validation and response
processing time between the initial call and its repair also count
against the shared budget -- not just network time. That is intended:
the deadline is a hard wall-clock ceiling regardless of where the time
goes. Documented the intent inline so it reads as deliberate.
…alwisdomlab-commercialization-afow1j

Reconciles this branch's fix for noema_review_gate.py's hardcoded 120s
timeout (NOEMA_LLM_REQUEST_TIMEOUT_SECONDS=10800 + shared
NOEMA_LLM_TOTAL_BUDGET_SECONDS=19800 deadline across the initial call
and its one possible repair call) with main's independent fix for the
exact same bug (PR #1507, NOEMA_LLM_TIMEOUT_SECONDS=14400 flat), plus
main's several other genuine, unrelated hardening fixes in the same
file: fail-closed handling of malformed/deeply-nested LLM JSON,
UnicodeDecodeError safety, and skipping the repair-retry request when
the PR head has moved (new expected_head parameter and
StaleHeadDuringRepairRetryError).

Kept main's JSON-crash and stale-head logic entirely intact, and kept
this branch's shared-deadline design for the timeout itself: a flat
4-hour constant applied independently to both the initial and repair
calls could sum past the 6-hour GitHub-hosted job execution ceiling,
which the shared budget already accounts for. Removed the now-unused
NOEMA_LLM_TIMEOUT_SECONDS constant and updated its references.

Fixed 3 additional breaks the merge surfaced in this branch's own
tests: two calls to call_llm missing the newly-required expected_head
argument, and one test asserting a stale literal 14400 timeout value.
Full suite: 2211 passed, 1 skipped, coverage 100%, interrogate 100%.
devin-ai-integration[bot]

This comment was marked as resolved.

…gressions found while fixing it

Devin's claim (test_stacked_pr_workflow_contract.py never collected by
app-ci.yml's backend-scoped pytest) verified real by reading the actual
workflow files. Fixed in naruon db97962c. While fixing it, also found
a4e01191's stacked-PR trigger change had broken 2 pre-existing contract
tests in the same file (stale release/**-branch-list assertions) — also
fixed in the same commit.
…icit job timeout, detect a dead sidecar on every attempt

Three Devin Review findings against the prior timeout/deadline fix, all
verified real:

1. noema_review_gate.py::call_llm relied solely on urllib's timeout=
   argument, which bounds per-socket-operation inactivity, not the
   request's total wall-clock duration. A response trickling at least
   one byte before each such window elapses could keep the shared
   5.5-hour budget unenforced indefinitely. The network call now runs
   on a daemon thread; call_llm enforces the real deadline via
   Thread.join(timeout=remaining_budget), so a trickling connection is
   preempted at the actual budget boundary regardless of how the far
   end paces its response.

2. The noema-review job carried no explicit timeout-minutes, leaving
   the relationship between its 5.5-hour LLM budget and GitHub's
   implicit 360-minute default unauditable. Made it explicit.

3. contextual_orchestrator_review_sidecar.sh's gateway-preflight retry
   loop only checked whether the sidecar process had died on the last
   configured attempt, so a sidecar that died on attempt 1 still burned
   the remaining attempts (each up to 120s) before detection -- the
   original incident this branch exists for shows all 3 attempts took
   roughly the full 120s each. Moved the dead-sidecar check to run
   immediately after any failed attempt.

Each fix verified genuine RED against the pre-fix code/tests before
being restored to GREEN. Full suite: 2214 passed, 1 skipped, 21
subtests, coverage 100%, interrogate 100%.
devin-ai-integration[bot]

This comment was marked as resolved.

Devin Review found a real regression in the prior daemon-thread deadline
fix (e186203): call_llm joined the request thread with
timeout=remaining_budget (the full shared 5.5h budget) instead of
timeout=request_timeout (this call's own cap, already min()'d against
the shared budget). A single trickling response could then consume the
entire shared budget, leaving nothing for a validator-rejected repair
call -- exactly the failure NOEMA_LLM_REQUEST_TIMEOUT_SECONDS was
introduced to prevent. Fixed to join on request_timeout, matching
Devin's suggested one-line change. Also corrected a stale comment
claiming the noema-review job has no explicit timeout-minutes (this PR
already added one in e186203).

Verified genuine RED (a 0.05s per-request cap was ignored while 10s of
shared budget remained, letting a 0.3s trickle complete normally) before
the fix, GREEN after. Full suite: 2215 passed, 1 skipped, 21 subtests,
coverage 100%, interrogate 100%.
…estrator#986, root-caused to unmerged .github#1438 fix

contextual-orchestrator#986's required noema-review check crashed with an
uncaught JSONDecodeError -- traced to the trusted noema_review_gate.py
still fetched from .github's main branch, which lacks the malformed-JSON
repair-retry fix already sitting in this PR. Not that PR's own fault;
commented there with the root cause and re-ran the job once. Reinforces
that merging this PR fixes the same crash for every sibling repo, not
just this one.
@seonghobae

Copy link
Copy Markdown
Contributor Author

Closing as a stale mixed branch after current-main audit. Exact head e6ec629 is BEHIND main@44a3c740, deletes/regresses scheduler coverage evidence added by #1541/#1548, and carries absolute inference/job wall-clock deadlines that conflict with the accepted unbounded Contextual Orchestrator review policy and #1546. The small stderr-tail diagnostic is not sufficient reason to preserve or merge the unsafe branch; no predecessor check/review evidence is transferable. No commits from this branch were pushed or merged by this audit.

@seonghobae seonghobae closed this Sep 1, 2026
seonghobae added a commit that referenced this pull request Sep 1, 2026
* fix(noema): fail closed on a transport error instead of crashing the required check

Live incident on ContextualWisdomLab/naruon#1486: call_llm's
opener.open(request) sat outside the surrounding try/except, which only
guarded the JSON-decode/validation steps after a successful response. A
genuine HTTP 502 from the completion request therefore crashed the
whole required noema-review check with an unhandled traceback instead
of getting the same one-time repair-retry the malformed-verdict path
already has.

Widened the try to also cover the request itself, and added
urllib.error.URLError alongside RuntimeError to the existing
repair-retry except clause. A transient transport failure now gets one
retry, then fails closed with a clean RuntimeError on a second failure
-- exactly like a malformed verdict already does.

Verified genuine RED (the exact HTTPError: Bad Gateway reproduced
uncaught) before the fix, GREEN after. Full suite: 2248 passed, 1
skipped, 21 subtests. Confirmed the repo's 99% (11 stmt/7 branch)
coverage gap is pre-existing on main in
pr_review_fix_scheduler.py/pr_review_merge_scheduler.py, unrelated to
this two-file diff -- verified identically present before this change
too.

Narrowly scoped: nothing here touches the wall-clock-deadline design
that #1438 was closed over, or the
in-progress #1546 reconciliation (already checked -- #1546's call_llm
has this exact same unguarded line).

* fix(noema): normalize http.client.HTTPException/OSError into the transport-error retry too

Devin Review on #1566 correctly found that the round-1 transport-error fix
(RuntimeError, urllib.error.URLError) still missed http.client.IncompleteRead
-- raised by response.read() on a truncated body -- since it is neither a
RuntimeError nor a URLError. The repo owner independently confirmed the same
gap and specified the fix: widen to the bounded transport/read exception
families (URLError, http.client.HTTPException including
IncompleteRead/RemoteDisconnected, and raw OSError transport failures such as
a bare socket timeout reaching opener.open() before urllib wraps it) without
swallowing JSON/validator/programming errors, and add RED->GREEN regressions
for a truncated-body success-after-retry, a repeated-failure case, and at
least one timeout/disconnect family exercising a distinct exception path.

Widened the except clause to (RuntimeError, urllib.error.URLError,
http.client.HTTPException, OSError) and simplified the repair-retry re-raise
to "re-raise as-is only when it's already our own RuntimeError; otherwise
wrap in a clean RuntimeError" -- generalizes the fail-closed contract to any
transport exception type rather than needing another isinstance branch added
per exception class.

Three genuinely distinct exception paths each get their own RED->GREEN
success-after-retry and repeated-failure pair, none transferred from another
case as substitute proof:
- test_call_llm_repairs_once_after_a_truncated_response_then_succeeds /
  test_call_llm_fails_closed_after_a_repeated_truncated_response
  (http.client.IncompleteRead from response.read())
- test_call_llm_repairs_once_after_a_socket_timeout_then_succeeds /
  test_call_llm_fails_closed_after_a_repeated_socket_timeout
  (raw TimeoutError from opener.open() itself, never wrapped as URLError)

Full suite: 2252 passed, 1 skipped, 21 subtests. noema_review_gate.py itself
at 100% line/branch coverage; 100% docstring coverage. Repo-wide coverage
remains the same pre-existing 99% (11 stmt/7 branch gap in
pr_review_fix_scheduler.py/pr_review_merge_scheduler.py) confirmed unrelated
to this diff in the prior commit on this branch.

Updated docs/product-technical-gap-baseline.md with the full root
cause/owner/status writeup for this incident (naruon#1486), including the
round-1 and round-2 fixes and the unrelated SIGPIPE test flake found and
fixed separately while verifying this change.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Y6UJHYbfbGdHfYPjgbVhAr

* fix(noema): track retry state independently of the exception's text

Devin Review on #1566 found a fourth, distinct bug: gating the
retry-vs-fail-closed decision on repair_error's truthiness conflated "is
this the second attempt" with "does the caught exception have display
text". Several transport exceptions (a bare OSError()/TimeoutError(), or
an http.client.HTTPException raised with no message) all stringify to
'', so an empty-message failure on the first attempt left repair_error
falsy on the recursive call too -- the retry-state signal was lost, and
call_llm would retry unboundedly (each recursive call another live
gateway request) instead of failing closed after one attempt, eventually
crashing on an uncaught RecursionError once the call stack was exhausted.

Added an explicit is_retry: bool = False parameter that tracks retry
state independently of the exception's text. It (not repair_error) now
gates both the prompt-injection branch -- falling back to a generic
message when repair_error is empty -- and the except clause's
retry-vs-fail-closed decision, and is threaded through as is_retry=True
on the recursive call.

Verified genuine RED with a bounded-recursion regression test
(test_call_llm_fails_closed_after_a_repeated_empty_message_transport_error,
which raises a diagnostic AssertionError if call_llm retries more than
once instead of letting it recurse to CPython's own limit) before this
fix, GREEN after -- paired with
test_call_llm_repairs_once_after_an_empty_message_transport_error_then_succeeds
for the happy-path case.

Full suite: 2254 passed, 1 skipped, 21 subtests. noema_review_gate.py
still at 100% line/branch coverage; 100% docstring coverage. Repo-wide
99% remains the same pre-existing gap tracked by #1567, unrelated to
this diff.

Updated docs/product-technical-gap-baseline.md and CHANGELOG.md with
this fourth fix round.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Y6UJHYbfbGdHfYPjgbVhAr

---------

Co-authored-by: Claude <noreply@anthropic.com>
seonghobae added a commit that referenced this pull request Sep 2, 2026
…aims

CodeRabbit on PR #1661:

1. The hash-lock-freshness verification step's `while IFS= read -r
   line; do ... done < requirements-opencode-review-ci.txt` silently
   skips the final line if the file doesn't end with a trailing
   newline -- `read` returns failure at EOF even though it populated
   `$line`, so the loop body never runs for that last pin. Fixed with
   the standard `|| [[ -n ${line:-} ]]` idiom. Verified locally against
   CodeRabbit's own repro (a requirements file with no trailing
   newline and a deliberately-stale lock): without the fix the mismatch
   goes undetected, with it the check correctly fails.

2. "then both fire -- and only one survives the shared concurrency
   group" overstated cancel-in-progress: false's actual behavior --
   it keeps one running job protected plus one replaceable pending
   job, not a strict single survivor. Corrected in both the doctoring
   doc and its gap-baseline mirror.

3. "most PRs eventually get through, per the #1438/#1176 evidence"
   drew an organization-wide majority claim from two examples with no
   stated denominator or sampling methodology. Softened to "some PRs"
   with an explicit note that this record doesn't have the basis for
   a "most" claim.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
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.

2 participants