Skip to content

fix(kiro): keep unreported cache counters unknown instead of zero (#4546) - #4588

Merged
lidge-jun merged 1 commit into
devfrom
codex/260914-kiro-cache-unknown
Sep 14, 2026
Merged

lidge-jun merged 1 commit into
devfrom
codex/260914-kiro-cache-unknown

Conversation

@lidge-jun

@lidge-jun lidge-jun commented Sep 14, 2026

Copy link
Copy Markdown
Owner

Summary

Kiro coerced an absent cacheReadInputTokens or cacheWriteInputTokens to 0 and then recorded it as a measured value, so a turn where the provider reported nothing about caching was indistinguishable from a turn that missed the cache entirely.

That distinction is the one needed to tell whether a routing change preserved a prompt cache. It is also the only place this happened: OcxUsage omits cache fields it has no reading for, and cacheHitRate is null when unobserved, so every other path already keeps unknown as unknown. #4546 had to be diagnosed from a token bill rather than a dashboard, and this is one of the reasons the dashboard could not have shown it.

Absence is now unknown. A malformed counter is still a malformed event — only a missing key is unknown — and an unreported counter still contributes nothing to inputTokens, which is a different statement from claiming it was measured as zero.

The wire contract is unchanged. responsesUsage in src/bridge.ts still emits cached_tokens with its zero default, which is deliberate and load-bearing: strict Responses clients deserialize input_tokens_details as a required field, and omitting it turns a successful turn into a hard exit after response.completed. This changes what OpenCodex records, not what it sends.

Follow-on to #4580, from the same plan unit devlog/_plan/260914_cost_guard_stabilization/ (see 080_codex_cache_reinforcement.md).

Verification

  • No local suite, typecheck, install or build was run, by explicit instruction. Hosted CI at the exact final head SHA of this branch is the only proof.
  • Two regression tests in tests/providers/kiro/kiro-stream.test.ts: a tokenUsage payload with no cache keys leaves all three cache fields absent while inputTokens stays correct, and a negative cacheReadInputTokens still throws. The existing "authoritative metadata token usage overrides estimates and preserves cache splits" case, which reports cache fields explicitly, is unchanged and still asserts exact values.

Checklist

  • Scope stays focused and avoids unrelated cleanup.
  • Docs or release notes were updated when needed.
  • Security-sensitive changes were reviewed for secrets, auth, and unsafe defaults.

Summary by CodeRabbit

  • Bug Fixes
    • Usage reporting now distinguishes between cache-token counts that are unavailable and counts that are confirmed as zero.
    • Input-token totals remain accurate when cache counters are not provided.
    • Invalid token usage values, including negative cache counts, are now rejected instead of being accepted silently.

)

Kiro coerced an absent cacheReadInputTokens or cacheWriteInputTokens to 0 and then recorded it as a measured value. Every other usage path omits what it has no reading for, and cacheHitRate is null when unobserved, so this was the one place a silent provider looked like a total cache miss - the exact signal needed to tell whether a routing change preserved the prompt cache. Absence is now unknown; a malformed counter is still a malformed event, and the bridge wire still emits its zero default for strict clients.
@lidge-jun
lidge-jun requested a review from Ingwannu as a code owner September 14, 2026 05:47
@github-actions

Copy link
Copy Markdown
Contributor

Deterministic PR hygiene checks passed.

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Sep 14, 2026

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review Completed 2026-09-14T05:51:08.431185Z e9b5e10 PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@github-actions github-actions Bot added the bug Something isn't working label Sep 14, 2026
@coderabbitai

coderabbitai Bot commented Sep 14, 2026

Copy link
Copy Markdown
Contributor

Review Change StackReview Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Advanced

Run ID: a2ce926f-fa90-4fa8-8546-3493536e5b7d

📥 Commits

Reviewing files that changed from the base of the PR and between 8c7f014 and e9b5e10.

📒 Files selected for processing (2)
  • src/adapters/kiro-events.ts
  • tests/providers/kiro/kiro-stream.test.ts

Included review availability: Your plan provides up to 10 included reviews per hour; 3 remain after this review.


📝 Walkthrough

Walkthrough

The Kiro adapter now preserves absent cache-token counters as unknown. It still rejects malformed reported counters. New stream tests cover both behaviors.

Changes

Kiro token usage

Layer / File(s) Summary
Optional cache counter parsing
src/adapters/kiro-events.ts
optionalTokenCount returns undefined for absent counters and validates reported values. parseTokenUsage uses nullish coalescing for inputTokens and emits cache fields only when reported.
Token usage validation tests
tests/providers/kiro/kiro-stream.test.ts
Tests verify that omitted cache counters remain absent and that a negative cacheReadInputTokens value causes parseKiroEvent to throw.

Priority: ⬇️ Low

Estimated code review effort: 2 (Simple) | ~15 minutes

Change: Bug fix

Merge Risk: ⚪ Minimal · up to e9b5e

The change preserves unknown cache usage, validates reported counters, and maintains the existing bridge output contract.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 33.33% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 3 functions across 2 files. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the main change: Kiro now keeps unreported cache counters unknown instead of treating them as zero.
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.
  • Fix all pre-merge checks with AI
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch codex/260914-kiro-cache-unknown

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.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: e9b5e10cc2

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +94 to +95
const cacheRead = optionalTokenCount(eventType, usage, "cacheReadInputTokens");
const cacheWrite = optionalTokenCount(eventType, usage, "cacheWriteInputTokens");

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Synchronize the owned adapter documentation

This changes src/adapters/kiro-events.ts's usage-event contract from measured zeroes to omitted cache counters, but the commit leaves every structure document mapped to src/adapters/ unchanged. That leaves the repository's architecture source of truth without the new Kiro telemetry invariant; update the applicable owned documentation and its coverage reference in the same change.

AGENTS.md reference: src/AGENTS.md:L11-L11

Useful? React with 👍 / 👎.

@lidge-jun

Copy link
Copy Markdown
Owner Author

리뷰 · 우선순위 68 / 80

지금 dev(HEAD 8c7f01451, #4580 직후)는 cost-guard L1으로 pool.cacheAffinity가 기본 ON이고, bound thread가 prompt cache를 지키도록 계정 바인딩을 잡습니다. #4546이 남긴 진단 구멍 중 하나가 측정값과 미관측을 구분하지 못하는 대시보드입니다. OcxUsage는 읽은 값이 없으면 cache 필드를 빼고, cacheHitRate도 미관측이면 null인데, Kiro만 src/adapters/kiro-events.tsparseTokenUsage에서 tokenCount(..., "cacheReadInputTokens"|"cacheWriteInputTokens", false)로 없는 키를 0으로 채운 뒤 cachedInputTokens / cacheReadInputTokens / cacheCreationInputTokens에 찍습니다. 라우팅이 캐시를 지켰는지, 아예 망가뜨렸는지가 같은 「캐시 0」으로 보입니다. 청구서만 보고 #4546을 진단해야 했던 이유 중 하나입니다. src/bridge.tsresponsesUsagecached_tokens에 0 기본값을 넣는 것과는 층이 다릅니다. 와이어는 strict Responses 클라이언트가 input_tokens_details를 필수로 받기 때문에 의도적으로 0을 내고, 이 버그는 OpenCodex가 기록하는 값 쪽입니다.

이 PR(codex/260914-kiro-cache-unknown)은 그 한 곳만 고칩니다. optionalTokenCount를 두고 키가 없으면 undefined를 돌려, OcxUsage에 cache 필드를 아예 넣지 않습니다. inputTokens 합산만 (cacheRead ?? 0) + (cacheWrite ?? 0)으로 「미보고는 합에 기여하지 않음」을 유지하고, 「측정된 0」이라고 주장하지는 않습니다. 음수·비정수 같은 잘못된 값은 예전처럼 malformed로 터집니다. 테스트는 tests/providers/kiro/kiro-stream.test.ts에 캐시 키 없음 → 세 필드 모두 absent + inputTokens 유지, 음수 cacheReadInputTokens → throw 두 건을 추가했고, 캐시를 명시해 주는 기존 케이스는 그대로입니다. devlog/_plan/260914_cost_guard_stabilization/의 080 보강 축 follow-on으로 #4580과 같은 레인입니다. types/config 스플릿에 통째로 무효화되는 PR이 아닙니다. 범위가 작고 지금 dev 방향과 바로 맞습니다.

라인 - optionalTokenCountobj[key] === undefined만 미관측으로 보고, nulltokenCount(..., true)로 넘겨 malformed가 됩니다. 같은 파일의 optionalBooleanundefined || null을 둘 다 미관측으로 둡니다. Kiro 와이어가 cache 카운터에 null을 넣을 일이 거의 없다면 괜찮지만, 패턴을 맞추려면 null도 unknown으로 두는지 한 줄로 정해 두는 편이 읽기 쉽습니다.

경로/심볼 - inputTokens = uncached + (cacheRead ?? 0) + (cacheWrite ?? 0)은 주석대로 「합산 기여 없음」이지 「측정 0」이 아닙니다. 대시보드·로그가 inputTokens만 보고 cache 필드를 안 보면, 미관측 턴도 숫자상으로는 캐시 없는 턴과 같아 보일 수 있습니다. 소비자 쪽에서 cachedInputTokens in usage / cacheHitRate === null을 쓰는지 한 번만 확인하면 이 수정의 의미가 살아납니다.

경로/심볼 - Verification이 로컬 스위트·타입체크·install을 안 돌렸다고 명시합니다. 이 시각 기준 hygiene/changes/gates/docker/keyring/api usage/storage 등은 초록이고, test 샤드·macos·npm-global macos는 pending입니다. 머지 증거는 이 헤드 SHA의 호스트 CI 전부 초록뿐입니다. 회귀 핀은 위 두 테스트에 있습니다.

메인테이너의 판단이 필요한 지점

너의 추천
호스트 CI가 test/macos까지 전부 초록이면 squash merge into dev. null 처리는 지금 그대로(malformed) 둬도 되고, 맞추고 싶으면 optionalBoolean과 같이 unknown으로 한 줄만 고치면 됩니다. types/config·bridge 와이어(cached_tokens 0 기본값)는 건드리지 말 것. 우선순위 중상: #4580 직후 cost-guard 진단 축을 막는 작은 핀이고, #4546 재발을 대시보드에서도 볼 수 있게 만듭니다.

이 댓글은 grok-bot이 작성했습니다

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant