Skip to content

fix(auth): don't demote Pro/Trial tier to 'free' after each chat call#44

Merged
dwgx merged 1 commit into
dwgx:masterfrom
aict666:fix/preserve-authoritative-tier
Apr 24, 2026
Merged

fix(auth): don't demote Pro/Trial tier to 'free' after each chat call#44
dwgx merged 1 commit into
dwgx:masterfrom
aict666:fix/preserve-authoritative-tier

Conversation

@aict666
Copy link
Copy Markdown
Contributor

@aict666 aict666 commented Apr 24, 2026

Problem

After any successful /v1/chat/completions call, the dashboard shows the
account tier as FREE even for Pro / 14-day Trial accounts (e.g. screenshot
where planName is Trial but the tier badge renders FREE).

Root cause

handlers/chat.js calls updateCapability(apiKey, modelKey, true, 'success')
after every successful request. updateCapability then runs
inferTier(account.capabilities) unconditionally and writes the result
back to account.tier.

inferTier only recognises claude-opus-4.6 / claude-sonnet-4.6 as Pro
evidence. If a Pro or Trial account calls a non-premium model such as
gemini-2.5-flash or gpt-4o-mini, inferTier sees ok=true on that model
and returns 'free', overwriting the authoritative tier that
GetUserStatus / refreshCredits had set.

probeAccount already works around this with a manual
account.tier = status.tierName restore at the end (see the existing
comment: "updateCapability rewrites tier via inferTier, so restore it
afterwards"
), but the chat handler path has no such restore, so every real
API call silently demotes the tier.

Fix

Skip the inferTier fallback in updateCapability when an authoritative
tier source is present:

  • userStatusLastFetched > 0GetUserStatus has returned a real tier
  • tierManual === true — user has manually pinned the tier in the dashboard

The fallback still runs for brand-new accounts that have never been probed,
so tier inference for those accounts is unchanged.

Test

  1. Add a Trial account, run the 15-min refresh / probe → tier shows pro.
  2. Send a chat request to gemini-2.5-flash (any non-premium model).
  3. Before: tier flips to free in accounts.json and in the dashboard.
    After: tier remains pro.

updateCapability() ran inferTier() unconditionally after every request,
which overwrites the authoritative tier set by GetUserStatus /
refreshCredits. When a Pro or 14-day Trial account called a non-premium
model such as gemini-2.5-flash or gpt-4o-mini, inferTier() saw only that
ok=true and returned 'free', so the dashboard showed the account as FREE
right after a successful request.

probeAccount() already worked around this by restoring status.tierName
at the end, but the chat handler path (handlers/chat.js) had no such
restore, so every real API call silently demoted the tier.

Skip the inferTier() fallback when an authoritative source is present
(userStatusLastFetched > 0, or tierManual=true). The fallback still runs
for brand-new accounts that have never been probed.
@dwgx dwgx merged commit 20dea9e into dwgx:master Apr 24, 2026
@dwgx
Copy link
Copy Markdown
Owner

dwgx commented Apr 24, 2026

已合并。修复了 chat 路径每次调用后 inferTier 把 Pro/Trial 降级为 free 的问题——根因抓得很准。感谢 @aict666 🎯

dwgx added a commit that referenced this pull request Apr 25, 2026
The Pages site at dwgx.github.io/WindsurfAPI/ had only 4 names listed
in the footer (dd373156, colin1112a, motto1, youfak). 8 contributors
were missing from the public site even though most of them landed
S+/S level fixes (aict666 #44/#51/#53/#54, baily-zhang #36/#45/#61,
smeinecke #43, abwuge #58).

Adds a dedicated `#contributors` section before the footer with one
card per contributor: avatar, GitHub link, weight badge (S+/S/A+/A/B+),
PR list, and a one-paragraph 繁體中文 description of what each fix
actually solved. Cards reuse the existing panel-card warm/coral
palette to fit the site's aesthetic.

Footer one-liner is also expanded to all 8 names ordered by weight,
with a "完整名單 ↑" anchor back to the new section.

CSS additions: contrib-grid, contrib-card, contrib-avatar,
contrib-weight + 5 weight-tier classes (-S-plus, -S, -A-plus, -A,
-B-plus). All gradient/hover behaviour matches the existing
panel-card styling.
@aict666 aict666 deleted the fix/preserve-authoritative-tier branch April 26, 2026 00:10
huanchen pushed a commit to huanchen/WindsurfAPI that referenced this pull request May 3, 2026
修复了一个实际影响用户体验的 tier 降级 bug。updateCapability 在每次 chat 后调 inferTier 会把 Pro/Trial 降为 free,现在有 userStatus 的账号跳过推断。感谢 @aict666 的精准定位。
huanchen pushed a commit to huanchen/WindsurfAPI that referenced this pull request May 3, 2026
The Pages site at dwgx.github.io/WindsurfAPI/ had only 4 names listed
in the footer (dd373156, colin1112a, motto1, youfak). 8 contributors
were missing from the public site even though most of them landed
S+/S level fixes (aict666 dwgx#44/dwgx#51/dwgx#53/dwgx#54, baily-zhang dwgx#36/dwgx#45/dwgx#61,
smeinecke dwgx#43, abwuge dwgx#58).

Adds a dedicated `#contributors` section before the footer with one
card per contributor: avatar, GitHub link, weight badge (S+/S/A+/A/B+),
PR list, and a one-paragraph 繁體中文 description of what each fix
actually solved. Cards reuse the existing panel-card warm/coral
palette to fit the site's aesthetic.

Footer one-liner is also expanded to all 8 names ordered by weight,
with a "完整名單 ↑" anchor back to the new section.

CSS additions: contrib-grid, contrib-card, contrib-avatar,
contrib-weight + 5 weight-tier classes (-S-plus, -S, -A-plus, -A,
-B-plus). All gradient/hover behaviour matches the existing
panel-card styling.
dwgx added a commit that referenced this pull request May 9, 2026
The Pages site at dwgx.github.io/WindsurfAPI/ had only 4 names listed
in the footer (dd373156, colin1112a, motto1, youfak). 8 contributors
were missing from the public site even though most of them landed
S+/S level fixes (aict666 #44/#51/#53/#54, baily-zhang #36/#45/#61,
smeinecke #43, abwuge #58).

Adds a dedicated `#contributors` section before the footer with one
card per contributor: avatar, GitHub link, weight badge (S+/S/A+/A/B+),
PR list, and a one-paragraph 繁體中文 description of what each fix
actually solved. Cards reuse the existing panel-card warm/coral
palette to fit the site's aesthetic.

Footer one-liner is also expanded to all 8 names ordered by weight,
with a "完整名單 ↑" anchor back to the new section.

CSS additions: contrib-grid, contrib-card, contrib-avatar,
contrib-weight + 5 weight-tier classes (-S-plus, -S, -A-plus, -A,
-B-plus). All gradient/hover behaviour matches the existing
panel-card styling.
MYMDO added a commit to MYMDO/WindsurfAPI that referenced this pull request May 14, 2026
Operational/navigation links updated to MYMDO/WindsurfAPI:
- package.json: homepage, repository.url, bugs.url
- install-ls.sh: OUR_RELEASE
- update.sh: RELEASE_URL
- docker-compose.yml: ghcr.io/mymdo/windsurf-api:latest (lowercased per GHCR)
- SECURITY.md: 2x security advisory URLs
- .github/ISSUE_TEMPLATE/config.yml: security advisory URL
- .github/workflows/release.yml: comment
- README.{md,en,ua,zh}.md: clone URLs, GitHub Pages catalog, Issues/PR CTAs
- docs/index.html: nav GitHub, hero CTA, deploy clone, contributors CTA, footer (GitHub/Releases/Issues/Security/READMEs/CONTRIBUTING)
- src/dashboard/index.html + index-sketch.html: Issue/PR CTA buttons, RELEASE_NOTES blob link

KEPT at dwgx (intentional):
- Historical PR references (PR dwgx#1, dwgx#13, dwgx#36, dwgx#43, dwgx#44, dwgx#45) — they exist only in dwgx/WindsurfAPI
- @dwgx profile link in footer (attribution)
- (c) 2026 dwgx (copyright attribution per MIT)
- package.json author field (original creator)
- bydwgx1337 brand strings in dashboard UI / server provider / version BRAND
- contributors.json (login + historical narrative)
- test fixtures and code comments referencing dwgx
- docs/releases/RELEASE_NOTES_*.md (historical archives)
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.

2 participants