Skip to content

fix(quota): keep the capacity panel when a credit expiry cannot be formatted - #2965

Merged
lidge-jun merged 5 commits into
devfrom
codex/carry-2950-quota-expiry
Aug 30, 2026
Merged

fix(quota): keep the capacity panel when a credit expiry cannot be formatted#2965
lidge-jun merged 5 commits into
devfrom
codex/carry-2950-quota-expiry

Conversation

@lidge-jun

Copy link
Copy Markdown
Owner

Summary

Carries #2950 by @luvs01, plus one repair commit. A credit expiry timestamp that no date formatter can
render used to take the whole capacity panel down with it.

This also carries #2951 in full: commit 6fcd39ac0 — the src/providers/quota-wire.ts change and its
tests/command-code-quota.test.ts case — is the same commit object in both branches, so #2951 is
superseded by this rather than in conflict with it.

Opened as a maintainer PR because pushing the repair to the contributor branch reset its
review-readiness checklist and returned it to draft; that attestation belongs to the author. The
cherry-pick preserves @luvs01's authorship.

Carries #2950 and supersedes #2951. Close both as carried once this lands.

capacity panel before and after

The repair

Rejecting an unrenderable timestamp at the wire boundary is right, but parseXaiCreditsResponse in
src/providers/quota.ts returned null whenever the reset was unrenderable — discarding a perfectly
valid creditUsagePercent along with it. That silently degraded the preferred xAI weekly meter to the
legacy monthly one, or removed the xAI quota report entirely when the fallback also failed.

The percent is now parsed and validated independently of the reset, and the reset is included only
when it is defined and renderable.

Verification

Based on dev@dca16949b.

  • bun test tests/provider-quota.test.ts tests/command-code-quota.test.ts121 pass, 0 fail
  • cd gui && bun test tests/provider-capacity-credits.test.tsx tests/provider-capacity.test.ts11 pass, 0 fail
  • bun x tsc --noEmit → clean

The new xAI case uses a weekly period whose end is 1e20 and asserts the percent survives without a
reset timestamp.

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.

luvs01 and others added 4 commits August 30, 2026 11:24
`epochMillis` accepted any finite number, but finite is not the same as
representable. ECMAScript caps time values at ±8.64e15 ms, and
`Intl.DateTimeFormat.format()` throws a RangeError past that rather than
rendering an approximation.

So a provider reporting a bogus expiry did not produce a wrong date; it produced
a value that faults every consumer that formats it. Measured against the current
code, 1e20 and 1e16 both yield "date value is not finite in DateTimeFormat
format()", while 8.64e15 remains representable.

Resolve an unrepresentable value to undefined so it never enters a report.
Seconds inference, the zero/negative sentinel handling, and every representable
timestamp are unchanged.
…atted

`Intl.DateTimeFormat.format()` throws a RangeError on a time value outside
±8.64e15 ms rather than rendering an approximation. The capacity panel formatted
`expiresAt` and `nextRecoveryAt` directly, so one unrepresentable timestamp did
not merely show a wrong date — it aborted rendering and removed the credit
balance, the recovery rows, and the aggregate view along with it.

The wire-side guard stops such a value entering a fresh report, but persisted
reports predate it and the component is reachable without that path. Guard both
layers here: normalization drops the field, and the component omits the line
instead of formatting it.

Representable timestamps and seconds inference are unchanged.
Server-rendered comparison of the provider capacity panel when a provider
reports an expiry outside the representable date range, following the
repository's existing convention of committing PR screenshots under assets/.
An unrenderable weekly reset timestamp caused the credits parser to discard an otherwise valid usage percentage. Validate the percentage independently and omit only the invalid reset timestamp so the preferred weekly meter remains available.
@lidge-jun
lidge-jun requested a review from Ingwannu as a code owner August 30, 2026 02:25
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Aug 30, 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-08-30T02:28:42.982564Z 397958e 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.

@coderabbitai

coderabbitai Bot commented Aug 30, 2026

Copy link
Copy Markdown
Contributor

Warning

Review limit reached

Next included review available in 12 minutes.

View limit details

Limit details: You’ve used all 10 included reviews 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: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 31420ee2-71fb-43c4-9030-6d81f673f275

📥 Commits

Reviewing files that changed from the base of the PR and between dca1694 and 181d25f.

⛔ Files ignored due to path filters (1)
  • assets/pr2950-capacity-expiry.png is excluded by !**/*.png
📒 Files selected for processing (8)
  • gui/src/components/provider-workspace/ProviderCapacityQuota.tsx
  • gui/src/provider-workspace/report.ts
  • gui/tests/provider-capacity-credits.test.tsx
  • gui/tests/provider-capacity.test.ts
  • src/providers/quota-wire.ts
  • src/providers/quota.ts
  • tests/command-code-quota.test.ts
  • tests/provider-quota.test.ts

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.

@github-actions

Copy link
Copy Markdown
Contributor

Deterministic PR hygiene checks passed.

@github-actions github-actions Bot added the bug Something isn't working label Aug 30, 2026

@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: 397958e488

ℹ️ 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 thread src/providers/quota.ts
Comment on lines +1163 to +1165
return {
percent,
...(resetAt !== undefined ? { resetAt } : {}),

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Fall back when the weekly response has no usable meter

When xAI returns a weekly period but both end is missing or unrenderable and creditUsagePercent is omitted, this unconditional return now produces { percent: 0 }, so fetchXaiQuota treats the weekly probe as successful and never calls the legacy monthly endpoint. A truncated or malformed response that previously activated the fallback will therefore falsely display 0% weekly usage and hide usable monthly quota. Preserve an explicit valid percentage when only the reset is bad, but return null when neither an explicit percentage nor a valid reset exists, with a focused regression case.

AGENTS.md reference: src/AGENTS.md:L15-L17

Useful? React with 👍 / 👎.

@lidge-jun

Copy link
Copy Markdown
Owner Author

리뷰 · 우선순위 72 / 80

설명

이 PR은 크레딧 만료 시각(expiry)이 날짜로 그릴 수 없을 때, 용량(capacity) 패널 전체가 같이 죽던 버그를 고칩니다. 지금 dev(HEAD dca16949b)에서는 gui/src/components/provider-workspace/ProviderCapacityQuota.tsxIntl.DateTimeFormat.format()에 바로 넘기고, src/providers/quota-wire.tsepochMillis는 유한한 숫자면 그대로 밀리초로만 바꿉니다. ECMAScript 날짜 범위(대략 ±8.64e15 ms)를 넘는 값이 오면 format()RangeError를 던지고, 한 필드 때문에 패널 전체가 렌더 실패합니다. 제공자 API나 예전에 캐시에 남은 이상한 만료값이 그 경로로 들어올 수 있습니다.

고치는 층이 세 겹입니다. 첫째, quota-wire.tsepochMillisnew Date(...).getTime()이 유한한지까지 보고, 날짜로 못 쓰는 값은 undefined로 버립니다. 둘째, GUI report.tsdateTimestamp를 두어 캐시에서 읽은 보고서도 같은 기준으로 expiresAt을 깎습니다(와이어 가드가 생기기 전에 저장된 값 대비). 셋째, ProviderCapacityQuota.tsxasDate / formatRecoveryAt / formatPeriodEnd가 그리기 직전에 한 번 더 막아, 못 그리는 줄만 숨기고 잔액·퍼센트는 남깁니다.

메인테이너 수리 커밋이 핵심입니다. parseXaiCreditsResponse(src/providers/quota.ts)는 주간 기간의 endnormalizeResetAt에서 실패하면 예전에 null을 돌려, 멀쩡한 creditUsagePercent까지 함께 버렸습니다. HEAD의 반환 타입은 이미 resetAt?이고 fetchXaiWeeklyCreditsweeklyResetAt을 선택적으로 붙이는데, 파서 본문은 여전히 reset 없으면 null이었습니다. 이 PR은 퍼센트를 먼저 검증하고, reset은 있을 때만 붙입니다. 그래서 xAI 주간 미터가 레거시 월간으로 조용히 떨어지거나 보고서 자체가 사라지는 부작용을 막습니다.

기반은 dev@dca16949b이고, 기여자 @luvs01#2950(GUI 패널 방어)을 체리픽으로 실어 오며, #2951의 quota-wire/command-code-quota 커밋(6fcd39ac0)과 동일 객체를 포함해 #2951을 대체합니다. 기여자 브랜치에 수리를 직접 밀면 리뷰 체크리스트가 리셋되고 드래프트로 돌아가서, 메인테이너 PR로 연 경위가 본문에 적혀 있습니다. 테스트는 provider-quota·command-code-quota·GUI capacity/credits 쪽이 통과했다고 적혀 있고, 1e20 같은 못 그리는 시각으로 퍼센트·잔액이 남는지 회귀가 있습니다. types.ts/config.ts 분할과 충돌하지 않는 독립 쿼터/GUI 버그픽입니다.

라인 - 문제

src/providers/quota.ts parseXaiCreditsResponse - 예전에는 reset이 없으면 null(주간 미터 전체 실패)이었는데, 이제는 reset이 없고 percent도 생략이면 { percent: 0 }을 돌려 주간 0% 미터가 살아납니다. 의도된 수리이지만, “주간 미터 없음”과 “0%로 표시”의 의미가 바뀌니 병합 전에 한 번만 확인하면 좋습니다.

gui/.../ProviderCapacityQuota.tsx asDate와 gui/.../report.ts dateTimestamp, src/providers/quota-wire.ts epochMillis - 날짜로 쓸 수 있는지 검사가 세 곳에 같은 10_000_000_000 초/밀리초 휴리스틱과 함께 복제되어 있습니다. 방어는 맞지만, 나중에 기준이 바뀌면 한곳만 고치기 쉽습니다.

assets/pr2950-capacity-expiry.png - PR 설명용 before/after 스크린샷이 저장소 assets/에 들어갑니다. 문서·릴리스에 남길 자산이면 괜찮고, 리뷰용만이면 나중에 빼도 됩니다.

gui/.../ProviderCapacityQuota.tsx 복구(recovery) 줄 - nextRecoveryAt을 못 그리면 nextRecoveryPercent가 있어도 줄 전체를 숨깁니다. 만료 줄과 같은 “부분 생략” 정책이라 일관되지만, 퍼센트만 보여 달라는 UX가 있으면 따로 논의할 지점입니다.

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

  • 이 PR이 랜딩한 뒤 fix(gui): keep the capacity panel when a credit expiry cannot be formatted #2950(드래프트)과 #2951을 landed-via-maintainer로 닫을지(본문이 그렇게 요청함).
  • xAI에서 reset만 깨졌을 때 주간 0%를 보여줄지, 예전처럼 주간 미터를 아예 숨길지.
  • assets/에 스크린샷을 남길지, PR 본문 첨부만으로 둘지.
  • 날짜 가드 헬퍼를 quota-wire 한곳으로 모을지, 지금처럼 와이어·캐시·렌더 삼중 방어를 유지할지.

너의 추천

dev에 병합하세요. 패널 크래시를 막고, #2950/#2951을 한 브랜치로 정리하며, xAI 퍼센트 유실 수리까지 들어 있습니다. 랜딩 직후 #2950·#2951에 Landed via #2965 at <commit> 댓글과 landed-via-maintainer 라벨을 달고 닫으면 열린 PR 수가 깔끔해집니다. 스크린샷 자산과 헬퍼 통합은 후속 정리로 미뤄도 됩니다.

이 댓글은 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.

2 participants