Skip to content

fix(quota): show "not in plan" instead of misleading 100%, map code 2056 (#173)#174

Closed
kapelame wants to merge 2 commits into
mainfrom
fix/cli-173-quota-not-in-plan
Closed

fix(quota): show "not in plan" instead of misleading 100%, map code 2056 (#173)#174
kapelame wants to merge 2 commits into
mainfrom
fix/cli-173-quota-not-in-plan

Conversation

@kapelame

@kapelame kapelame commented Jun 8, 2026

Copy link
Copy Markdown
Collaborator

What

Fixes #173mmx quota show reports a video quota of 100% while mmx video generate is rejected with code 2056, a self-contradiction.

Root cause

When a Token Plan does not bundle a model, the server returns that model's quota row as 0/0 with remaining_percent: 100, marked current_interval_status: 3 / current_weekly_status: 3. The table trusted remaining_percent and rendered a misleading 100%, even though the model is unusable (generate → 2056).

status is the only reliable discriminator: legitimate time-based in-plan rows are also 0/0, but report status: 1. A count-based heuristic (total==0) would wrongly flag those.

Changes (this PR's own commit)

  • src/output/quota-table.ts — when current_interval_status / current_weekly_status is 3, render not in plan / 不在当前套餐中 instead of a bar + percent.
  • src/errors/api.ts — fold code 2056 into the existing 1028 || 1030 quota branch → QUOTA exit code + check-usage / upgrade hint (matches how same-class codes are already grouped).
  • Tests for both paths.

⚠️ Depends on #168

This builds on #168 (feat(quota): align types with coding-plan API, show boost multiplier), which adds the current_*_status fields to QuotaModelRemain. My commit only consumes them.

Because #168 is on a fork, GitHub won't let me target it as the base, so this PR is opened against main and currently contains #168's commit as well (it sits directly on main). Once #168 merges, this PR's diff collapses to just my 4-file change automatically — no rebase needed. Please merge #168 first.

My change alone (vs the #168 tip):

 src/errors/api.ts               |  4 ++--
 src/output/quota-table.ts       | 18 ++++++++++++++++--
 test/errors/api.test.ts         | 13 +++++++++++++
 test/output/quota-table.test.ts | 31 +++++++++++++++++++++++++++++++
 4 files changed, 62 insertions(+), 4 deletions(-)

Verification

  • bun test — 359 pass / 0 fail
  • tsc --noEmit clean; eslint clean on touched files
  • Live-checked against a real Token Plan account: the server does return current_*_status (=1 for in-plan rows), and video generate debits quota normally for an in-plan model — confirming the fix is inert for users whose plan includes the model.

Rendered result for a no-video plan:

| 视频    剩余 不在当前套餐中     周剩余 不在当前套餐中     重置 6h 0m   |

(the in-plan 通用 row still shows its real percent)

raylanlin and others added 2 commits June 2, 2026 01:01
- types: add 4 optional fields (interval_status, weekly_status, boost_permille x 2)
- render: prepend 'xN' to model name when boost_permille > 1000
- tests: add 2 cases (with boost, without boost)

PR #166 missed these fields. status is not separately rendered since
percent already conveys the state (1=partial, 3=full). boost informs
the user about their 2x subscription multiplier.
…056 (#173)

A Token Plan that does not bundle a model (e.g. video) makes the server
return that model's row as 0/0 with remaining_percent=100, marked
current_*_status=3. The table trusted the percent and rendered a
misleading "100%", while `video generate` was rejected by the server with
code 2056 — a contradiction reported in #173.

- quota-table: when current_interval_status / current_weekly_status is 3,
  render "not in plan" / "不在当前套餐中" instead of the bar+percent.
  Status is the only reliable signal: in-plan time-based rows are also
  0/0 but report status=1.
- errors/api: fold code 2056 into the existing quota branch so the user
  gets a QUOTA exit code with a check-usage / upgrade hint.

Builds on #168, which already added the current_*_status fields to
QuotaModelRemain; this change consumes them.
@github-actions

github-actions Bot commented Jun 8, 2026

Copy link
Copy Markdown

dummy

@github-actions

github-actions Bot commented Jun 8, 2026

Copy link
Copy Markdown

AI Review — #${PR_NUMBER}

Summary: Handles two UX issues with the quota table display: (1) models not bundled in a plan show misleading 100% bars for 0/0 counts, now replaced with an explicit "not in plan" label; (2) models with a boost multiplier display the ×N tag. Also adds error code 2056 to the quota-exhausted path.


Checks

Command Result Note
bun run typecheck ✅ Pass No TS errors
bun test ✅ Pass 359 pass, 0 fail
bun run lint 🛑 2 errors, 12 warnings Pre-existing — none in PRchanged files

Note on lint: The 2 errors (mockDeviceCodeFlow unused in test/auth/oauth.test.ts, ImageSaveOptions unused in test/sdk/image.test.ts) and all 12 warnings are in files unchanged by this PR. The files this PR modifies (src/errors/api.ts, src/output/quota-table.ts, src/types/api.ts, and their tests) are lint-clean.


Changes by file

src/errors/api.ts — Adds apiCode === 2056 to the quotaexhausted branch alongside 1028/1030. Correct.

src/types/api.ts — Adds current_interval_status, current_weekly_status, interval_boost_permille, weekly_boost_permille to QuotaModelRemain. These are optional and additive — backward-compatible with existing API responses. Correct.

src/output/quota-table.ts — Two additions:

  • Boost multiplier tag (×N when boost_permille > 1000) appended to model display name. Logic: boost > 1000 means boost/1000 > 1, so the multiplier is only shown when above base (i.e., the server sends values like 2000 = ×2). Correct.
  • status === STATUS_NOT_IN_PLAN (3) path renders "not in plan" label instead of the misleading 100% bar for 0/0 rows. The status parameter is correctly threaded through from API response to renderMetric. Correct.

test/errors/api.test.ts — Adds test for 2056 → QUOTA exit code with upgrade hint. Well-covered.

test/output/quota-table.test.ts — Three new test cases covering boost display (with/without), and the "not in plan" status-3 rendering. All use inline console.log capture which is the established pattern in this file.


No blocking issues

The PR is focused, type-safe, and well-tested. No CLI-breaking changes.


Approve

@kapelame

kapelame commented Jun 8, 2026

Copy link
Copy Markdown
Collaborator Author

Closing for now — superseded by a cleaner approach. The quota endpoint fix is split out as #175 (independent of the rendering change). Will re-open the rendering fix (not-in-plan / 2056) on a clean base once #168's status fields land in main, to avoid carrying #168's commit in this PR.

@kapelame kapelame closed this Jun 8, 2026
@kapelame kapelame deleted the fix/cli-173-quota-not-in-plan branch June 8, 2026 12:04
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.

mmx quota show reports 100% remaining for video, but mmx video generate rejects with 0/0 used

2 participants