fix(usage): replace inline casts with typeof guards in TUI renderer#3318
fix(usage): replace inline casts with typeof guards in TUI renderer#3318oldschoola wants to merge 3 commits into
Conversation
roboomp
left a comment
There was a problem hiding this comment.
Rank: P1. Tight two-file fix and the unsafe casts are gone, but formatAccountLabel currently drops valid scoped fallbacks when metadata is "" or non-string.
One blocking inline finding on that fallback order; existing usage tests did not cover this TUI renderer edge. I attempted bun test packages/coding-agent/test/acp-builtins.test.ts -t usage, but this worktree failed before tests with missing ./tool-views.generated.js.
Thanks for the focused cleanup.
| const accountId = report.metadata?.accountId ?? limit.scope.accountId; | ||
| if (typeof accountId === "string" && accountId) return accountId; | ||
| const projectId = report.metadata?.projectId ?? limit.scope.projectId; |
There was a problem hiding this comment.
blocking: ?? limit.scope.accountId / ?? limit.scope.projectId runs before the type and empty-string guard, so invalid metadata suppresses a valid scoped fallback. Example: metadata.accountId === "" with limit.scope.accountId === "acct-1" makes line 1347 produce "", line 1348 reject it, and the renderer falls through to projectId/account N instead of acct-1. The PR body says empty metadata falls through to scope.accountId/scope.projectId; guard the metadata value first, then fall back to limit.scope.*.
|
Fixed in latest push. Empty-string metadata values now fall through to the scope fallback instead of suppressing it. |
|
Addressed blocking review in latest push ( The const metaAccountId = report.metadata?.accountId;
const accountId = typeof metaAccountId === string && metaAccountId ? metaAccountId : limit.scope.accountId; |
The TUI usage renderer (command-controller.ts) used 'as string |
undefined' inline casts to read email/accountId/projectId/planType
from UsageReport.metadata (Record<string, unknown>). These casts
fabricated the type without runtime validation, violating the
ts-no-inline-cast-access rule.
Replaced all casts with typeof guards. This also fixes a behavioral
edge case: empty-string metadata values ('') previously passed
through the ?? chain and were displayed as the account label.
With the typeof guard, empty strings are falsy and fall through to
the next fallback (scope.accountId, scope.projectId, or 'account N').
Affected functions:
- formatAccountLabel (limit + report identity resolution)
- formatUnlimitedReportLabel (report-only identity resolution)
- resetAccountLines label (saved-reset credits display)
- unlimitedReports tier (plan type suffix)
…metadata suppressing valid scoped fallback
Address blocking review: ?? limit.scope.accountId runs before the type and empty-string guard, so metadata.accountId='' suppresses a valid scoped fallback. Check metadata value for truthiness first, then fall back to limit.scope.*.
6d25917 to
44f26be
Compare
Problem
The TUI usage renderer (
command-controller.ts) usedas string | undefinedinline casts to reademail/accountId/projectId/planTypefromUsageReport.metadata(Record<string, unknown>). These casts fabricated the type without runtime validation, violating thets-no-inline-cast-accessproject rule.Changes
Replaced all inline casts with
typeofguards in 4 locations:formatAccountLabel— limit + report identity resolutionformatUnlimitedReportLabel— report-only identity resolutionresetAccountLineslabel — saved-reset credits displayunlimitedReportstier — plan type suffixBehavioral improvement
Empty-string metadata values (
"") previously passed through the??chain and were displayed as the account label. Withtypeofguards, empty strings are falsy and fall through to the next fallback (scope.accountId,scope.projectId, or"account N").This matches the pattern already used in the ACP path (
usage-report.ts:formatUsageReportAccount).Tests
bun checkpasses (all 16 packages)