Skip to content

Port upstream 0.63.0: StepFun credit plans (Credit label, no invented reset) - #710

Closed
Finesssee wants to merge 1 commit into
port/upstream-0.63.0from
port/micro-0.63.0-stepfun-credit-plan
Closed

Finesssee wants to merge 1 commit into
port/upstream-0.63.0from
port/micro-0.63.0-stepfun-credit-plan

Conversation

@Finesssee

Copy link
Copy Markdown
Collaborator

Summary

StepFun Token Plan (credit) payloads now produce a usable snapshot instead of failing with "Missing StepFun five-hour usage". Credit plans show a single primary lane labelled Credit, never get an invented reset date, and Coding Plan snapshots keep their 5-hour / Weekly labels and lanes.

Found by the 0.60.4-0.69.0 port gap audit (0.63.0 item #13).

Upstream reference

Ported / Deferred

Ported (rust/src/providers/stepfun/mod.rs only):

  • New fields plan_family, plan_credit_rate_limit (subscription_credit_left_rate, subscription_credit_reset_time, topup_credit_left_rate, credit_buckets[].credit_total/credit_residual), all names taken from the upstream decoder.
  • Credit-plan classification: no live rolling window (both reset times 0/absent) and a credit pool exists; plan_family == 2 only as tie-breaker.
  • Primary-only window: used = clamp((1 - left) * 100), left rate weighted from sound buckets (residual/total), else subscription rate, else top-up rate (never summed).
  • Zero/missing subscription_credit_reset_time stays unknown: no resets_at, no reset description, no window minutes. A real reset sets monthly window minutes via the existing RateWindow::monthly_window_minutes.
  • primary_label = "Credit" via the existing UsageSnapshot::primary_label; the Tauri bridge, tray and CLI already consume it. Coding Plan still requires the five-hour and weekly fields.

Left out:

  • Upstream returns a nil primary for a credit plan with no balance yet. Win's UsageSnapshot.primary is non-optional, so this shows an informational "No credit balance reported" primary (the same pattern used by Amp/Antigravity), not an error and not a quota percentage.
  • Upstream ProviderPaceCapability.monthlyWindowSentinelMinutes is replaced by the local calendar-month helper, matching how other monthly providers (Abacus) are handled.
  • Upstream expire_at / next_reset_at bucket fields are unused by upstream's snapshot and are not modelled.
  • Upstream login flow / descriptor label renames (5h Window): unrelated to this item.
  • No local StepFun doc exists, so no docs change.

Validation

  • cargo +1.98.0 fmt --all: clean
  • cargo +1.98.0 clippy --workspace --all-targets -- -D warnings: pass (both manifests)
  • cargo +1.98.0 test -p codexbar stepfun: 11 passed, 0 failed (8 new: coding-plan regression and missing-field error, credit with reset, no/zero reset, bucket weighting, unsound-bucket fallback, no-balance credit family, live window beats credit family)
  • Shared code untouched, so the full cargo test -p codexbar and frontend tests were not run.

Affected areas

Provider: StepFun. Tray/dashboard/CLI primary-lane label (Credit) and reset line.

UI proof

Pending: coordinator will capture CUA proof on a fresh build.

@coderabbitai

coderabbitai Bot commented Sep 30, 2026

Copy link
Copy Markdown

Important

Draft PR not reviewed

Draft PRs are not automatically reviewed by default.

  • Trigger a manual review

To automatically review draft PRs, update your CodeRabbit configuration:

reviews:
  auto_review:
    drafts: true

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.

@Finesssee

Finesssee commented Oct 1, 2026 •

Copy link
Copy Markdown
Collaborator Author

UI proof (browser-use)

Result: PASS on build b883c478713dbb74de21be163174b910c0c36997, the current PR head. There is one finding, and it comes from main, not this PR. Merge #720 before or together with this PR (see T9).

  • Tray panel: StepFun credit payloads render as one Credit lane. A real monthly reset shows "Resets in 30d 18h". A zero or missing reset shows no reset line and no pace. With no balance, the lane reads "No credit balance reported". Coding Plan payloads keep their 5-hour and Weekly lanes, including when a credit family id comes with live windows.
  • Settings > Providers: the StepFun detail pane shows plan "Mini", the 50% credit bar and the "Credit" lane toggle.
  • Finding (T9): a credit reset 31 days out makes the tray refresh StepFun in a loop on this base. This is the useProviders reset-timer overflow already fixed by Fix reset refresh timer for resets over 24.8 days away #720, which port/upstream-0.63.0 doesn't include yet.

At the maintainer's direction, this proof drove the app's WebView2 over CDP with the browser-use CLI instead of CUA. It used no keyboard, mouse or focus. Provider selection and refreshes were DOM element.click() calls on the panel's own StepFun tab and Refresh button, and the global shortcut was off in the kit settings.

Setup

  • Build: pnpm run tauri:build:debug in the worker worktree at b883c478. The exe was copied to the proof kit; its SHA-256 is 85a048d5…5f209fca, and the build emitted index-OTO_h_Fk.js (this PR doesn't change the frontend).
  • Proof-only patch: never committed, and reverted after the build.
    • A workspace Cargo.toml [patch.crates-io] dirs shim for an isolated home, plus the resulting Cargo.lock change.
    • A no-focus overlay, because this branch doesn't include Stop CodexBar from stealing focus #713. It changes only window focus.
    • A StepFun fixture hook in rust/src/providers/stepfun/mod.rs. It renames the keyring target, so the user's Credential Manager entry is never read. When CODEXBAR_PROOF_STEPFUN_FIXTURE names a folder, post_json reads rate-limit.json and plan-status.json from it instead of calling https://platform.stepfun.com. No request is sent, and TLS and URL validation are untouched.
    • The hook decodes each body with the PR's own response types. A <name>.status file takes the same 401/403 and non-success branches as the network path, so every value below comes from the PR's snapshot_from_response and credit_snapshot. Each served request is logged with its endpoint and token kind only, never the token.
  • Home and providers: USERPROFILE, HOME, APPDATA, LOCALAPPDATA and XDG_CONFIG_HOME pointed at a home inside the kit. CODEX_HOME, CLAUDE_CONFIG_DIR and GEMINI_HOME pointed at empty kit folders, and PATH was cut to the Windows system folders.
  • Token: STEPFUN_OASIS_TOKEN was a dummy placeholder. STEPFUN_TOKEN, STEPFUN_USERNAME and STEPFUN_PASSWORD were unset.
  • Settings: only StepFun was enabled. The theme was auto, the float bar was off and the global shortcut was empty.
  • Commands:
    • bash launch.sh trayPanel (CODEXBAR_PROOF_MODE=trayPanel) for S1 to S6, then bash launch.sh settings:providers.
    • Both set WEBVIEW2_ADDITIONAL_BROWSER_ARGUMENTS=--remote-debugging-port=9335 .... Checks ran as BU_CDP_URL=http://127.0.0.1:9335 BU_NAME=worker-710 BH_TAB_MARKER=0 browser-use.
    • Before each attach, curl /json/version showed Edg/154 WebView2, and the port 9335 listener was a WebView2 child of the kit exe.

Fixture scenarios

The payload shapes come from upstream v0.63.0's StepFunUsageFetcherTests.swift, StepFunCreditLabelProofTests.swift and docs/stepfun.md. Timestamps were moved into the future.

Scenario rate-limit body plan-status
S1 Coding Plan five_hour_usage_left_rate 0.7 and weekly_usage_left_rate 0.8, with live reset times "Plus"
S2 credit, monthly reset upstream's Mini-plan payload: plan_family 2, both rolling resets "0", subscription_credit_reset_time 2026-11-01, one bucket of 400,000,000 credits with 385,643,853 left "Mini"
S3 credit, zero reset plan_family 2, subscription_credit_left_rate 0.5, subscription_credit_reset_time "0" "Mini"
S4 top-up only plan_family 2, only topup_credit_left_rate 0.6 HTTP 500
S5 credit family, no balance rolling rates 0 with resets "0", plan_family 2, no plan_credit_rate_limit "Mini"
S6 live window wins live 5-hour (0.8 left) and weekly (0.6 left) windows, plus plan_family 2 and a full credit pool "Plus"

Results

# Assertion Result
T0 No real email or account from the host is visible. The app page was scanned before each screenshot, and no scan found an @ address or the host user name. accountEmail stayed null in every snapshot. PASS
T1 Dark under theme auto on both surfaces: prefers-color-scheme: dark, surface rgb(28, 28, 30), and text luminance 0.91. PASS
T2 S1 Coding Plan. Badge "Plus". "5-hour 30% used, Resets in 3h 56m" and "Weekly 20% used, Resets in 3d 18h". The snapshot has primaryLabel "5-hour" (300 min) and secondaryLabel "Weekly" (10080 min). PASS
T3 S2 credit with a monthly reset. Badge "Mini". One lane: "Credit 4% used, Resets in 30d 18h", with an on-pace budget row and no second lane. The snapshot has primaryLabel "Credit", usedPercent 3.589 (from the bucket balance, 1 - 385,643,853 / 400,000,000), windowMinutes 44640 and resetsAt 2026-11-01T00:00:00Z. PASS
T4 S3 credit with reset "0". "Credit 50% used", with no reset line and no pace row. The snapshot has resetsAt, resetDescription and windowMinutes all null, so no reset was invented. PASS
T5 S4 top-up only, with plan status HTTP 500. "Credit 40% used" from the top-up rate, with no reset. The usage survived the plan-status failure, and the badge fell back to "Oasis-Token" as before this PR. The card showed no error. PASS
T6 S5 no balance. The lane reads "Credit" and "No credit balance reported", with no bar. The snapshot primary is isInformational: true. There was no card error and no quota percentage. PASS
T7 S6 live window wins. Badge "Plus". "5-hour 20% used" and "Weekly 40% used" with their resets, and no Credit lane. The credit family id and pool don't override live windows. PASS
T8 Settings > Providers (S3). The StepFun detail pane shows Plan "Mini", Data Source "api", a 50% usage bar, and an "Options: Credit" lane toggle. The bar is labelled "Session" (see the first item under Not blocking). PASS
T9 Refresh loop with the S2 reset (finding from main). After the S2 refresh, the fixture log recorded 15,316 requests (7,658 refresh cycles) between 05:03:51.767Z and 05:07:30.490Z, peaking at 84 requests per second. A page-local setTimeout with the S2 delay (2,659,959,038 ms) fired after 0 ms. The loop stopped as soon as S3 removed the reset: 0 requests in the next 3 s. Single refreshes in S3 to S6 each sent one rate-limit and one plan-status request. Finding, fixed by #720
T10 The proof never took focus. The app page reported document.hasFocus() as false at every step. PASS

About T9:

  • Cause: useProviders arms window.setTimeout(refresh, nextReset - now + 1000). WebView2 fires any timer with a delay above 2^31-1 ms (24.8 days) at once, so a reset 31 days out runs the forced refresh_providers immediately. Each new snapshot re-arms the timer, so the loop repeats.
  • Scope: this is on main since 3b39f59 and reproduces for any provider. Fix reset refresh timer for resets over 24.8 days away #720 re-arms the timer in chunks of at most 2^31-1 ms, and its own proof covers a 30-day reset.
  • Why it matters for this PR: a StepFun credit plan with a monthly reset is now a new way to reach the bug, during the first few days after each monthly reset. Merge Fix reset refresh timer for resets over 24.8 days away #720 first or in the same release; release/v0.70.0 includes both.

Validation at b883c478

Run in the worker worktree on Rust 1.98.0. This PR doesn't change the frontend.

Command Result
cargo +1.98.0 fmt --all --check pass
cargo +1.98.0 clippy --workspace --all-targets -- -D warnings pass
cargo +1.98.0 test -p codexbar stepfun 11 passed
cargo +1.98.0 test -p codexbar 2168 + 1 passed, 0 failed, 1 ignored
cargo +1.98.0 test -p codexbar-desktop-tauri -- --skip bootstrap_payload_exposes_every_provider_variant 461 passed, 0 failed. The skipped test is the non-hermetic #684 test that #711 fixes.

Screenshots

All paths are under %LOCALAPPDATA%\Win-CodexBar\port-audit\proof\710\shots\.

File What it shows
710-tray-s1-coding-plan-overview.png S1 in the compact overview: 5-hour and Weekly lanes.
710-tray-s1-coding-plan-selected.png S1 with StepFun selected: both lanes with their reset lines.
710-tray-s2-credit-monthly.png S2: one "Credit" lane, 4% used, "Resets in 30d 18h".
710-tray-s3-credit-zero-reset.png S3: "Credit 50% used" with no reset line.
710-tray-s4-topup-only-plan-status-500.png S4: "Credit 40% used" with the "Oasis-Token" badge after plan status HTTP 500.
710-tray-s5-credit-no-balance.png S5: "Credit" with "No credit balance reported".
710-tray-s6-live-window-wins.png S6: 5-hour and Weekly lanes, no Credit lane.
710-settings-providers-stepfun-s3.png Settings > Providers: the StepFun detail pane.

The fixture request log for T9 is proof\710\storm-requests-s2.log.

Not blocking (already on main)

None of these come from this PR; its diff touches only rust/src/providers/stepfun/mod.rs.

@Finesssee

Copy link
Copy Markdown
Collaborator Author

Shipped in v0.70.0: this PR's head is included in main via #735 (merge commit 9d0a37a). Closing as integrated.

@Finesssee Finesssee closed this Oct 3, 2026
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.

1 participant