Skip to content

fix: post-release audit — hook safety, polling resilience, cache merge, env warnings#77

Merged
ComBba merged 1 commit into
masterfrom
fix/post-release-audit
Feb 25, 2026
Merged

fix: post-release audit — hook safety, polling resilience, cache merge, env warnings#77
ComBba merged 1 commit into
masterfrom
fix/post-release-audit

Conversation

@ComBba
Copy link
Copy Markdown
Contributor

@ComBba ComBba commented Feb 25, 2026

Summary

Post-release hardening pass addressing 9 issues identified by deep codebase audit (5× Explore agents + Oracle architecture review). All fixes are minimal, targeted, and backwards-compatible.

Changes

P0 — Critical

# File Fix
1 src/plugin.ts Wrapped 4 unprotected hook handlers (event, tool.execute.before/after, experimental.text.complete) in try/catch — unhandled exceptions crashed host CLI

P1 — High

# File Fix
2 src/polling-manager.ts Moved authResolver() call inside try block — was unguarded outside
3 src/polling-manager.ts Added .catch() to both tick().then() chains — rejected tick killed polling permanently
4 src/usage-aggregator.ts fromJSON() now merges via upsertSample() instead of wiping in-memory data
5 src/runtime/coexistence.ts Wrapped promptClient dispatch in try/catch

P2 — Medium

# File Fix
7 src/plugin.ts Added warnInvalidEnv() helper — logs warnings for invalid env var values instead of silent null
8 docs/CONFIG_DEFAULTS.md Fixed stale "toast-only" reference → "prompt+publisher"
9 src/plugin.ts Added JSDoc to MAX_SESSION_ENTRIES explaining the 200-entry cap

P3 — Low

# File Fix
12 src/disk-cache.ts Added module-level saveCounter to tmpPath — prevents concurrent write collision within same process

Verification

  • ✅ 332 tests pass (npm run test)
  • ✅ Typecheck clean (npm run typecheck)
  • ✅ Build clean (npm run build)
  • 7 files changed, +217 / −167 lines

Not in Scope (Future)

Oracle identified additional architectural items deferred to future PRs:

  • plugin.ts SRP extraction (session store, renderer, cache coordinator)
  • Per-session reducer serialization (promise queue)
  • Unbounded per-session collections cap
  • Multi-instance disk cache file locking
  • LRU pruning for pruneMap
  • over200k cost rate activation
  • Output strip regex tightening

Summary by CodeRabbit

릴리스 노트

  • 버그 수정

    • 환경 변수 검증 및 오류 처리 개선으로 플러그인 안정성 증대
    • 사용량 샘플 병합 동작으로 데이터 보존 기능 강화
    • 폴링 및 프롬프트 발생 중 오류 처리 추가로 시스템 복원력 개선
  • 문서

    • 기본 설정값 업데이트: 공존 모드 및 사용량 프롬프트 간격 설정 변경

…e, env warnings

P0: Wrap all plugin hook handlers (event, experimental.text.complete,
tool.execute.before/after) in try/catch to prevent host CLI crashes.

P1: Fix polling-manager — move authResolver inside try block, add
.catch() to tick().then() chains to prevent silent polling death.

P1: Change usage-aggregator fromJSON to merge (upsert) instead of
replace, preventing early in-memory samples from being lost on
cache load.

P1: Wrap coexistence promptClient call in try/catch to isolate
prompt channel errors from propagating to plugin hooks.

P2: Add console.warn for invalid env var values with valid options.
P2: Fix CONFIG_DEFAULTS.md toast remnant (toast-only → prompt+publisher).
P2: Add clarifying JSDoc to MAX_SESSION_ENTRIES constant.
P3: Use per-save unique tmp paths in disk-cache to prevent concurrent
write collisions.
@gemini-code-assist
Copy link
Copy Markdown

Warning

You have reached your daily quota limit. Please wait up to 24 hours and I will start processing your requests again!

@chatgpt-codex-connector
Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.
To continue using code reviews, add credits to your account and enable them for code reviews in your settings.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Feb 25, 2026

Walkthrough

다양한 모듈에 환경 변수 검증, 에러 처리 개선, 동시 저장 충돌 감소 로직이 추가되었습니다. 또한 설정 기본값이 업데이트되고, 사용량 샘플 병합 방식이 교체에서 업서트로 변경되었습니다.

Changes

Cohort / File(s) Summary
Configuration & Documentation
docs/CONFIG_DEFAULTS.md
Emission Defaults의 Coexistence mode를 toast-only에서 prompt+publisher로 변경, Usage prompt interval 기본값 10000ms 추가.
Disk Cache Optimization
src/disk-cache.ts
모듈 레벨 saveCounter 도입으로 동시 저장 시 고유 임시 파일명 생성, 경로 충돌 위험 감소.
Plugin Error Handling & Validation
src/plugin.ts
환경 변수 검증 로직 추가(warnInvalidEnv 헬퍼), 주요 핸들러들(event, experimental.text.complete, tool.execute.*)에 try/catch 블록 추가로 예외 방지.
Polling Resilience
src/polling-manager.ts
인증 및 토큰 처리에 try/catch 추가, 에러 발생 시에도 폴링이 계속되도록 보장, 지수 백오프 동작 유지.
Coexistence Prompt Safety
src/runtime/coexistence.ts
프롬프트 emission 경로에 try/catch 추가, 프롬프트 클라이언트 에러가 전체 플로우에 영향을 주지 않도록 격리.
Usage Sample Merging
src/usage-aggregator.ts, tests/usage-aggregator.test.ts
fromJSON 메서드의 동작을 교체에서 업서트로 변경, 기존 샘플과 새로운 샘플을 병합하도록 수정 및 테스트 업데이트.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

🐰 Whiskers twitch with joy profound,
Error handlers wrap around,
Samples merge, no clash in sight,
Concurrent saves dance just right!
Robustness blooms, resilience bright! ✨

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 25.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main changes: hook safety, polling resilience, cache merge, and env warnings match the actual file modifications across plugin.ts, polling-manager.ts, disk-cache.ts, and configuration.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch fix/post-release-audit

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 and usage tips.

@ComBba ComBba merged commit d2d4fbc into master Feb 25, 2026
2 of 3 checks passed
@ComBba ComBba deleted the fix/post-release-audit branch February 25, 2026 07:56
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (3)
tests/usage-aggregator.test.ts (1)

426-451: 병합 테스트에 “동일 messageID 갱신” 케이스를 한 줄 더 추가하면 회귀 방지가 더 탄탄해집니다.

현재 테스트는 “신규 추가” 경로를 잘 검증합니다. 같은 messageID 입력 시 값이 덮어써지는 경로까지 포함하면 upsert 의미를 완전히 고정할 수 있습니다.

테스트 보강 예시
   aggregator.fromJSON(newSamples)
+  aggregator.fromJSON([{ ...newSamples[0], cost: 0.07 }])

   const samples = aggregator.allSamples()
   expect(samples).toHaveLength(2)
   expect(samples.map((s) => s.messageID).sort()).toEqual(["new_msg", "old_msg"])
+  expect(samples.find((s) => s.messageID === "new_msg")?.cost).toBe(0.07)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/usage-aggregator.test.ts` around lines 426 - 451, Add one more case to
the "fromJSON merges samples with existing (upsert behavior)" test that verifies
an incoming sample with the same messageID updates the existing sample: after
calling aggregator.addSample(oldSample) and then aggregator.fromJSON with a new
sample that has messageID "old_msg" but different fields (e.g., updated
completedMs, contextUsedTokens, cost), assert that aggregator.allSamples() still
has the same length but that the sample with messageID "old_msg" reflects the
updated fields (use messageID lookup or find on samples array). This ensures
aggregator.fromJSON upserts existing entries rather than only appending new
ones.
src/plugin.ts (2)

520-521: 세션 상한 주석에 실제 상한값을 함께 명시하면 더 명확합니다.

주석에 현재 상한 숫자(예: 50)를 같이 넣어두면, 운영/튜닝 시 maxStateEntries와의 차이를 더 빠르게 파악할 수 있습니다.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/plugin.ts` around lines 520 - 521, Update the comment for the constant
MAX_SESSION_ENTRIES to explicitly include its numeric value (50) and clarify it
is distinct from config.maxStateEntries; e.g., modify the docstring above
MAX_SESSION_ENTRIES so it reads something like "Maximum concurrent sessions
tracked (50). Distinct from config.maxStateEntries (reducer history depth)." to
make the hard limit obvious during tuning/operations.

835-918: 훅 무중단 전략은 좋지만, 완전 무음 catch에는 최소 디버그 로그 경로를 두는 편이 운영 추적에 유리합니다.

지금 구조는 안정성 목적에 부합합니다. 다만 모든 예외를 완전히 삼키면 현장 장애 분석이 어려워집니다. 기본은 무음 유지, 디버그 플래그에서만 로그를 남기는 방식이 균형이 좋습니다.

경량 디버그 로깅 예시
+function reportHookError(scope: string, error: unknown): void {
+  if (process.env.OPENCODE_STATUS_HUD_DEBUG === "1") {
+    console.warn(`[opencode-status-hud] ${scope} hook failed`, error)
+  }
+}
...
-      } catch {
-        // Plugin hooks must never throw — silently ignore errors
+      } catch (error) {
+        reportHookError("event", error)
       }
...
-      } catch {
-        // Plugin hooks must never throw — silently ignore errors
+      } catch (error) {
+        reportHookError("experimental.text.complete", error)
       }

Also applies to: 948-1009, 1013-1026, 1030-1044

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/plugin.ts` around lines 835 - 918, The try/catch currently swallows all
errors silently; change the final catch to capture the error (catch (err)) and,
while keeping silent by default, emit a debug-level log when a debug flag is
enabled (use the existing runtimeConfig for a debug/verbose flag check).
Specifically, inside the catch block reference the error and call a debug logger
(e.g., ctx.logger?.debug(...) or console.debug(...)) only when
runtimeConfig.debug (or similar) is true so normal operation stays silent but
failures are visible when debugging; update the same pattern for the other hook
blocks noted (lines marked 948-1009, 1013-1026, 1030-1044) to use the same
conditional logging approach.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@src/plugin.ts`:
- Around line 520-521: Update the comment for the constant MAX_SESSION_ENTRIES
to explicitly include its numeric value (50) and clarify it is distinct from
config.maxStateEntries; e.g., modify the docstring above MAX_SESSION_ENTRIES so
it reads something like "Maximum concurrent sessions tracked (50). Distinct from
config.maxStateEntries (reducer history depth)." to make the hard limit obvious
during tuning/operations.
- Around line 835-918: The try/catch currently swallows all errors silently;
change the final catch to capture the error (catch (err)) and, while keeping
silent by default, emit a debug-level log when a debug flag is enabled (use the
existing runtimeConfig for a debug/verbose flag check). Specifically, inside the
catch block reference the error and call a debug logger (e.g.,
ctx.logger?.debug(...) or console.debug(...)) only when runtimeConfig.debug (or
similar) is true so normal operation stays silent but failures are visible when
debugging; update the same pattern for the other hook blocks noted (lines marked
948-1009, 1013-1026, 1030-1044) to use the same conditional logging approach.

In `@tests/usage-aggregator.test.ts`:
- Around line 426-451: Add one more case to the "fromJSON merges samples with
existing (upsert behavior)" test that verifies an incoming sample with the same
messageID updates the existing sample: after calling
aggregator.addSample(oldSample) and then aggregator.fromJSON with a new sample
that has messageID "old_msg" but different fields (e.g., updated completedMs,
contextUsedTokens, cost), assert that aggregator.allSamples() still has the same
length but that the sample with messageID "old_msg" reflects the updated fields
(use messageID lookup or find on samples array). This ensures
aggregator.fromJSON upserts existing entries rather than only appending new
ones.

ℹ️ Review info

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 507d18d and 7342106.

📒 Files selected for processing (7)
  • docs/CONFIG_DEFAULTS.md
  • src/disk-cache.ts
  • src/plugin.ts
  • src/polling-manager.ts
  • src/runtime/coexistence.ts
  • src/usage-aggregator.ts
  • tests/usage-aggregator.test.ts

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