Skip to content

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

Closed
luvs01 wants to merge 4 commits into
lidge-jun:devfrom
luvs01:agent/quota-expiry-range
Closed

fix(gui): keep the capacity panel when a credit expiry cannot be formatted#2950
luvs01 wants to merge 4 commits into
lidge-jun:devfrom
luvs01:agent/quota-expiry-range

Conversation

@luvs01

@luvs01 luvs01 commented Aug 29, 2026

Copy link
Copy Markdown
Contributor

Stacked on #2951, which carries the wire-layer half. Until it lands, the diff here also
shows its two files; the GUI change under review is the four gui/ files plus the
screenshot asset. I will rebase onto dev once #2951 merges.

Summary

An unrepresentable credit expiry aborted rendering of the provider capacity panel. Omit the
affected line instead of handing the value to a formatter.

The defect

Intl.DateTimeFormat.format() throws a RangeError on a time value outside ±8.64e15 ms
rather than rendering an approximation. ProviderCapacityQuota formatted expiresAt and
nextRecoveryAt directly:

}).format(new Date(value > 10_000_000_000 ? value : value * 1000));

So a provider reporting a bogus expiry did not produce a wrong date. It produced a render
fault: server-side rendering aborts with "date value is not finite in DateTimeFormat
format()", taking the credit balance, the recovery rows, and the aggregate view with it.
One malformed field from one provider removes the whole panel.

The fix

Two layers, because each is reachable without the other:

Layer File Why it needs its own guard
Normalization gui/src/provider-workspace/report.ts Persisted reports predate the wire-side guard
Render gui/src/components/provider-workspace/ProviderCapacityQuota.tsx Also covers nextRecoveryAt, which formats on the same path

The component resolves to null and omits the line rather than formatting it.
Representable timestamps, seconds inference, and every other credit figure are unchanged.

UI change

Left is current dev, right is this branch. The top row is a provider reporting
expiresAt: 1e20; the bottom row is an ordinary representable expiry, which is unaffected.

Provider capacity panel before and after

Verification

Based on dev@47b8d164366b9db9e4331b2bb8b542db22766910 with #2951 applied.

  • Bun 1.4.0-canary.1: bun test tests in gui/ → full suite, 0 failures.
  • bun x tsc -b clean in gui/.
  • Red-proven: with the two guards reverted, the new GUI test fails with the real
    RangeError: date value is not finite in DateTimeFormat format() raised from
    renderToStringImpl — the render fault itself, not an assertion. The screenshot above is
    that same server render, captured before and after the change.
  • The repository-wide suite was intentionally not duplicated locally; hosted CI remains the
    full-matrix check.

Review readiness checklist

This PR stays in draft until every box below is ticked. Tick all four boxes once the requirements are met:

  • All CI tests are green on my local testing.

  • I pushed my PR to the latest dev commit.

  • I resolved all correct Codex and CodeRabbit findings.

  • My PR is ready for review.

Summary by CodeRabbit

  • Bug Fixes

    • Prevented invalid or out-of-range timestamps from causing quota and capacity views to fail.
    • Capacity balances and billing-period details now remain visible when expiry or recovery dates are unusable.
    • Preserved quota usage information when reset dates are missing or invalid.
    • Omitted only malformed date fields while retaining other valid quota data.
  • Tests

    • Added coverage for invalid expiry, reset, and subscription period timestamps.

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Aug 29, 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-29T23:42:32.356124Z bcbc3ad Draft marked ready
ℹ️ 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 Aug 29, 2026
@github-actions

Copy link
Copy Markdown
Contributor

Deterministic PR hygiene checks passed.

@coderabbitai

coderabbitai Bot commented Aug 29, 2026

Copy link
Copy Markdown
Contributor

Review 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: Pro Plus

Run ID: 8e1b7e5d-3dbe-4d92-94f4-c138d294530f

📥 Commits

Reviewing files that changed from the base of the PR and between 35ef304 and 79b5eab.

⛔ Files ignored due to path filters (1)
  • assets/pr2950-capacity-expiry.png is excluded by !**/*.png
📒 Files selected for processing (2)
  • src/providers/quota.ts
  • tests/provider-quota.test.ts

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


📝 Walkthrough

Walkthrough

Quota timestamp handling now rejects unrepresentable dates at wire and report boundaries. The xAI credits parser preserves usable weekly data when reset timestamps are missing or invalid. The capacity panel skips invalid date rows. Regression tests cover these cases.

Changes

Quota timestamp handling

Layer / File(s) Summary
Wire timestamp validation
src/providers/quota-wire.ts, tests/command-code-quota.test.ts
epochMillis now rejects out-of-range dates. The quota test verifies that invalid period ends are omitted while valid credit and window data remains available.
xAI credits normalization
src/providers/quota.ts, tests/provider-quota.test.ts
parseXaiCreditsResponse now preserves the weekly window when period.end is absent or invalid. It defaults percent to 0 and omits invalid resetAt values.
Report expiry normalization
gui/src/provider-workspace/report.ts, gui/tests/provider-capacity.test.ts
dateTimestamp validates timestamps before parsing credit expiry values. The normalization test verifies that an invalid expiresAt value is removed.
GUI date rendering guards
gui/src/components/provider-workspace/ProviderCapacityQuota.tsx, gui/tests/provider-capacity-credits.test.tsx
asDate, formatRecoveryAt, and formatPeriodEnd now handle unrepresentable dates without throwing. The component test verifies that the credit balance remains visible while the invalid billing-period line is omitted.

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

Merge Risk: ⚪ Minimal · up to 79b5e

The change keeps provider capacity data visible when an invalid expiry is supplied and preserves the existing 0% default for omitted usage; no actionable merge-blocking risk remains after normal checks and review.

Suggested reviewers: ingwannu, lidge-jun

🚥 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 6 functions across 8 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 describes the primary change: preventing the GUI capacity panel from failing when a credit expiry timestamp cannot be formatted. It is concise, specific, and directly related to the …
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.
Full details: Title check

Explanation

The title clearly describes the primary change: preventing the GUI capacity panel from failing when a credit expiry timestamp cannot be formatted. It is concise, specific, and directly related to the changeset.

  • Fix all pre-merge checks with AI
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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

github-actions Bot commented Aug 29, 2026

Copy link
Copy Markdown
Contributor

⏳ DRAFT

  • review readiness checklist open (0/4 boxes ticked).

What to do

  • Tick all four boxes in the PR description once you're done (currently 0/4).

Review readiness checklist

  • ⬜ All CI tests are green on my local testing.
  • ⬜ I pushed my PR to the latest dev commit.
  • ⬜ I resolved all correct Codex and CodeRabbit findings.
  • ⬜ My PR is ready for review.

0/4 boxes ticked.

This PR stays in draft until every box above is ticked.

@github-actions
github-actions Bot marked this pull request as draft August 29, 2026 23:07
@luvs01
luvs01 marked this pull request as ready for review August 29, 2026 23:07
@github-actions
github-actions Bot marked this pull request as draft August 29, 2026 23:08
@lidge-jun

Copy link
Copy Markdown
Owner

리뷰 · 우선순위 71 / 80

이 PR은 지금 dev HEAD 47b8d1643 (#2946, Codex 무덤 가드를 자격 증명이 남은 무덤으로 따로 증명) 바로 위에서, 제공자가 보낸 만료 시각이 날짜 포맷터가 그릴 수 없는 값일 때 용량 패널 전체가 깨지던 버그를 고친다. 작성자는 @luvs01 이다. 갈래는 dev 이고 라벨은 bug 다. 손대는 파일은 src/providers/quota-wire.ts, gui/src/provider-workspace/report.ts, gui/src/components/provider-workspace/ProviderCapacityQuota.tsx, 그리고 세 테스트(tests/command-code-quota.test.ts, gui/tests/provider-capacity.test.ts, gui/tests/provider-capacity-credits.test.tsx)다. 더하기 104줄·빼기 16줄이다. 미리보기 배포는 계획에 없고, types.ts/config.ts 분할과도 안 겹친다. 패키지 버전은 2.36.0 이고 이번 패치는 버전을 안 올린다.

쉽게 말하면 이렇다. 지금 HEAD의 epochMillis(src/providers/quota-wire.ts 31–34행)는 유한한 양수만 통과시킨다. 그런데 유한한 숫자라고 해서 날짜로 그릴 수 있는 건 아니다. ECMAScript 시간 값은 대략 ±8.64e15 밀리초 안에만 있고, 그 밖은 Intl.DateTimeFormat.format()이 RangeError를 던진다. 잘못된 날짜가 나오는 게 아니라, 그리는 자체가 실패한다. GUI에서는 그 예외가 용량 패널 렌더를 통째로 중단시킨다. 크레딧 잔액, 회복 행, 합산 보기까지 한 제공자의 한 필드 때문에 같이 사라진다. 그래서 이 고침은 표시를 예쁘게 만드는 일이 아니라, 패널이 살아남게 하는 일이다.

고침은 세 층이다. 와이어(quota-wire.ts)에서는 표현 못 하는 값을 undefined로 돌려 새 리포트에 안 넣는다. 정규화(report.tsdateTimestamp)는 예전에 캐시에 남은 나쁜 만료값을 다시 걸러 낸다. 컴포넌트(ProviderCapacityQuota.tsx)는 asDatenull이면 그 줄을 아예 안 그린다. nextRecoveryAt도 같은 포맷 경로를 쓰므로 렌더 가드가 그 경로까지 막는다. 초/밀리초 추정(10_000_000_000 기준)과 0·음수 센티널 처리는 그대로다. 검증도 층마다 있다. 와이어만 빼면 Command Code 테스트가 실패하고, 컴포넌트·정규화만 빼면 GUI 테스트가 실제 RangeError로 실패한다고 적혀 있다. 빨간 증명까지 맞춰 둔 편이다.

지금 dev 방향과도 맞는다. 최근 HEAD는 Codex 계정·무덤 가드(#2946), 실패한 exec 래퍼 정규화(#2945), Copilot vision 카탈로그(#2943/#2944), 그리고 그 앞의 할당량 drain 라우팅(#2845)처럼 제공자·할당량 쪽을 다듬고 있다. 이 PR은 그 흐름 안의 좁은 렌더 구멍만 막는다. 와이어 계약이나 제공자 파서 모양을 바꾸지 않는다. 독립 버그 픽스라서 큰 갈래와 겹치지 않고, 닫을 이유도 없다.

라인 59–72 (ProviderCapacityQuota.tsx) - formatRecoveryAt/formatPeriodEndnull을 반환할 수 있게 바뀌었고, 호출부도 periodEnd !== nullrecoveryAt !== null로 줄을 생략한다. 의도는 맞다. 다만 asDate가 컴포넌트 안에만 있어서, 같은 초/밀리초 추정 상수가 와이어·정규화·렌더에 세 번 반복된다. 이번 범위 밖이지만 나중에 한곳으로 모으면 어긋날 위험이 줄어든다.

경로 gui/src/provider-workspace/report.ts · dateTimestamp - creditsExpiresAtdateTimestamp로 거르고, capacityWindownextRecoveryAt은 여전히 finite만 쓴다. 렌더 가드가 막아주니 패널 붕괴는 막히지만, 캐시에 남은 나쁜 nextRecoveryAt은 정규화 단계에서 안 빠진다. 의도된 비대칭인지, 정규화에도 같은 가드를 넣을지 한 번만 정해 두면 좋다.

경로 src/providers/quota-wire.ts · epochMillis - 표현 못 하는 값을 undefined로 돌리는 판정은 Number.isFinite(new Date(milliseconds).getTime())다. 경계값 ±8.64e15는 그대로 통과하고, 그 밖만 버린다. 초 단위로 들어온 정상 만료(예: 1771077734)는 밀리초로 바뀐 뒤 통과한다. 동작은 PR 본문 측정과 맞다.

경로 tests/command-code-quota.test.ts - currentPeriodEnd: 1e20이 리포트의 creditsUsd.expiresAt에 안 실리는지만 본다. GUI 쪽은 잔액은 보이고 "Billing period ends" 문구는 없어야 한다고 본다. 두 층이 서로 다른 실패 모드를 잡고 있어서 회귀 울타리가 탄탄하다.

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

  • nextRecoveryAtreport.ts 정규화에서도 dateTimestamp로 걸러 세 층을 맞출지, 렌더 가드만으로 충분한지
  • 초/밀리초 추정 상수와 "표현 가능한 날짜" 판정을 공용 헬퍼로 올릴지, 이번엔 중복을 두고 갈지
  • CI 전체 행렬이 아직 안 보였다면 초록 확인 후 바로 머지할지, 아니면 로컬 검증만으로 충분하다고 볼지

너의 추천
머지 쪽으로 간다. 결함은 실제 패널 붕괴이고, 고침은 표현 못 하는 값만 바꾸며, 와이어·캐시·렌더를 각각 막았고 테스트로 빨간 증명까지 있다. types/config 분할과도 무관하다. 머지 전에 nextRecoveryAt을 정규화에도 넣을지 한 줄만 정하고(안 넣어도 렌더가 막아주니 필수는 아님), CI가 초록이면 dev에 바로 넣으면 된다.

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

luvs01 added 2 commits August 30, 2026 08:16
`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.
@luvs01
luvs01 force-pushed the agent/quota-expiry-range branch from 35ef304 to e7f5995 Compare August 29, 2026 23:18
@luvs01 luvs01 changed the title fix(quota): drop expiry timestamps that no date formatter can render fix(gui): keep the capacity panel when a credit expiry cannot be formatted Aug 29, 2026
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/.
@luvs01
luvs01 marked this pull request as ready for review August 29, 2026 23:40
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

Copy link
Copy Markdown
Owner

Carried to #2965 and merged there, with your three commits cherry-picked so authorship is preserved.

Reopened as a maintainer PR because the repair commit I pushed here reset the review-readiness checklist and returned this PR to draft. That checklist is your attestation, bound to an exact head, so it is not mine to tick for you.

The repair: rejecting an unrenderable timestamp at the wire boundary is right, but parseXaiCreditsResponse returned null whenever the reset was unrenderable, discarding a valid creditUsagePercent 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 validated independently of the reset. A second commit hoisted asDate to module scope, because React Doctor runs with blocking: warning and flagged it.

Thanks for the fix.

@lidge-jun lidge-jun closed this Aug 30, 2026
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