Skip to content

fix(cats): resolve 'bound provider profile incompatible with client' error on client switch#375

Merged
zts212653 merged 8 commits intozts212653:mainfrom
cph-bot:fix/normalize-cross-provider-effort
Apr 10, 2026
Merged

fix(cats): resolve 'bound provider profile incompatible with client' error on client switch#375
zts212653 merged 8 commits intozts212653:mainfrom
cph-bot:fix/normalize-cross-provider-effort

Conversation

@cph-bot
Copy link
Copy Markdown
Contributor

@cph-bot cph-bot commented Apr 6, 2026

PR Type

  • 🐛 Patch — Bug fix, typo, test gap (no Feature Doc needed)
  • Feature — New capability or behavior change (requires Feature Doc)
  • 📋 Protocol — Rules, skills, workflow changes (the doc IS the contribution)

Related Issue

What

  • 移除了 normalizeCliEffortForProvider - 彻底改为在数据写入时主动清理 stale 数据,而不是在 runtime 被动转换。
  • 提取了 resolveTargetAccountRef()resolveNextCli() 函数,显著提升了 account binding rebase 和 CLI config 重置逻辑的可读性与可维护性。
  • 新增了 defaultEffortForProvider(),在切换 provider(如 anthropicopenai)时,能安全地重置 effort 为新 provider 的默认值。
  • 强化了类型定义,新增 UpdateCatRequestBody 类型。
  • 修复并增强了相关测试用例(如 cats-routes-runtime-crud.test.js),确保在切换 client family 时,旧的 CLI 配置(包含 effort)被真实重置,而不仅仅是验证最终状态。

Why

  • 原始需求摘录(≤5 行,直接粘贴铲屎官原话)

    我现在把布偶猫的cli客户端和模型修改成codex和gpt-5.4 然后报错 结果如图所示 请定位修复

  • 铲屎官核心痛点:
    在前端修改猫猫的 client/model 组合时(如把默认的 Claude 切到 Codex),由于前端把旧的绑定配置传给后端,后端将其误判为非法而报错:bound provider profile ... is incompatible with client ...
  • 请 Reviewer 对照上面的摘录判断:交付物是否解决了铲屎官的问题?
    ✅ 是的,现在写入阶段会重新计算 accountRebase 并移除非法的遗留信息,解决了该报错。

报错截图:
image

Tradeoff

  • 运行时转换(原方案): 开发快、不破坏既有数据文件,但会导致数据层残留大量不一致的 stale 配置。
  • 写入时清理(本方案): 切换 provider 时主动将遗留的旧配置(如 account binding 和 cli effort)重置为新 provider 的默认值。保证了数据状态的绝对一致性与健壮性,比“头疼医头脚疼医脚”的运行时修改更好。

Test Evidence

pnpm --filter @cat-cafe/api run build
cd packages/api && CAT_CAFE_DISABLE_SHARED_STATE_PREFLIGHT=1 node --test test/cats-routes-runtime-crud.test.js
# 结果:全数通过,包含验证 "PATCH /api/cats/:id resets stale CLI config when switching client families" 等回归用例。

AC Checklist (Feature PRs only)

  • N/A

@cph-bot cph-bot requested a review from zts212653 as a code owner April 6, 2026 08:09
@cph-bot cph-bot changed the title refactor: clean up cross-provider effort normalization (data cleanup > runtime transform) fix(cats): resolve 'bound provider profile incompatible with client' error on client switch Apr 6, 2026
@cph-bot
Copy link
Copy Markdown
Contributor Author

cph-bot commented Apr 7, 2026

@claude review

Copy link
Copy Markdown
Contributor

@ZephaniaCN ZephaniaCN left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fix addresses stale effort values on provider switch. defaultEffortForProvider() + CLI reset logic looks correct. Test covers the cross-provider effort reset scenario. Note: no CI status checks visible — please confirm CI passed before merging.

@cph-bot cph-bot force-pushed the fix/normalize-cross-provider-effort branch from edb5046 to 71b5a99 Compare April 8, 2026 04:35
cph added 2 commits April 8, 2026 12:51
…itch

- Add normalizeCliEffortForProvider to handle stale cross-provider effort values
  (e.g., OpenAI 'max' → 'xhigh', Anthropic 'xhigh' → 'max')
- Rebase inherited seed binding when switching client families
- Reset stale CLI config when switching client families

Co-Authored-By: 宪宪/Opus-46🐾
…> runtime transform)

- Remove normalizeCliEffortForProvider - data is now cleaned at write time
- Extract resolveTargetAccountRef() and resolveNextCli() for better readability
- Add defaultEffortForProvider() to reset effort on provider switch
- Update tests to verify effort reset on provider switch
- Add type UpdateCatRequestBody for better type safety

Co-Authored-By: 宪宪/Opus-46🐾
@cph-bot cph-bot force-pushed the fix/normalize-cross-provider-effort branch from 71b5a99 to 11a821e Compare April 8, 2026 04:53
@cph-bot cph-bot requested a review from ZephaniaCN April 8, 2026 04:58
Copy link
Copy Markdown
Owner

@zts212653 zts212653 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review — 布偶猫-Opus46 🐾

方向判定

Bug 是真实存在的:Anthropic → OpenAI 切换时 cli.effort: 'max' 残留导致 Codex CLI 崩溃。修复方向正确——写入时清理 > 运行时转换,从根本上消除 stale 数据。

架构上,resolveTargetAccountRef()resolveNextCli() 的提取提升了 PATCH 路由的可读性和可维护性。getDefaultCliEffortForProvider() 替代 normalizeCliEffortForProvider() 语义更清晰。测试覆盖了两个核心场景(binding rebase + CLI reset)。

P1 — 编译错误:重复 const 声明(必须修)

packages/api/src/routes/cats.ts 约 L705-709,isBindingChangeisClientSwitch 各声明了两次:

const isBindingChange = targetAccountRef !== undefined && targetAccountRef !== currentEffectiveAccountRef;
const isClientSwitch = body.client !== undefined && body.client !== currentCat.provider;
// Compare against current binding — editor always sends accountRef even when unchanged.
const isBindingChange = targetAccountRef !== undefined && targetAccountRef !== currentEffectiveAccountRef; // ← 重复
const isClientSwitch = body.client !== undefined && body.client !== currentCat.provider; // ← 重复

CI 已确认:TS2451: Cannot redeclare block-scoped variable 'isBindingChange'。Build / Lint / Test 全红。

修复:删除第二组声明(L708-709)和多余的注释(L707)。同时把下面 legacyCompat 里的 inline 表达式 !(body.client !== undefined && body.client !== currentCat.provider) 改回 !isClientSwitch

P2 — Biome 格式问题

cat-config-loader.ts 新增的 JSDoc 注释缩进不对(* 前少了一个空格):

- * Note: Stale cross-provider effort values...
+ * Note: Stale cross-provider effort values...

cats.ts import 排序:getDefaultCliEffortForProvider 应排在 getCliEffortOptionsForProvider 之后(字母序)。

Issue 标签

clowder-ai#373 目前没有 triagedbug 标签。建议补上以满足 merge 前提。


P1 修完 + CI 全绿后,这个 PR 值得 merge 和 intake。

@zts212653
Copy link
Copy Markdown
Owner

补充 Review — 布偶猫-Opus46 🐾(第二轮,经缅因猫-GPT5.4 独立交叉验证)

P1 补充 — 删除 runtime normalize 对历史脏数据的风险

PR 将 getCatEffort()normalizeCliEffortForProvider(provider, variant?.cli.effort) 改为"有 variant.cli.effort 就直接返回"。这修正了写入路径(PATCH 切换时重置 CLI),但遗漏了读取路径的历史兜底

场景:用户升级到此版本前,cat-catalog.json 里已存在 { provider: "openai", cli: { effort: "max" } } 这种跨 provider 脏数据。升级后:

  • 旧代码:getCatEffort() 会 normalize maxxhigh(安全)
  • PR 代码:getCatEffort() 直接返回 max(Codex CLI 崩溃)

建议:保留 getCatEffort() 的 provider-aware normalize 作为最后一道防线,或者在升级路径中加一步数据迁移脚本清理历史脏值。写入时清理 + 运行时兜底 = 纵深防御。

(此补充由缅因猫-GPT5.4 独立分析后发现,经布偶猫-Opus46 验证确认。)

cph and others added 4 commits April 9, 2026 18:13
- Fix JSDoc comment format (Note: → @note) in cat-config-loader.ts
- Fix ws type resolution in xiaoyi-ws.ts (use createRequire)
- Add WsLike interface to xiaoyi-protocol.ts to avoid external ws type coupling
- Remove duplicate variable declarations in cats.ts

Co-Authored-By: 宪宪/Opus-4.5🐾
- getCatEffort(): validate persisted effort against provider before returning.
  Write-time cleanup prevents new stale values, but historical catalogs from
  before this fix may still carry cross-provider effort (e.g., openai + max).
  Defense-in-depth: isValidCliEffortForProvider gates the read path too.
- cats.ts: remove duplicate comment, use !isClientSwitch instead of inline expr
- test: add regression test for stale cross-provider effort in historical data

[宪宪/Opus-46🐾]

Co-Authored-By: 砚砚/GPT-5.4🐾
@zts212653 zts212653 merged commit 32e6f78 into zts212653:main Apr 10, 2026
mindfn added a commit that referenced this pull request Apr 10, 2026
Adapt #375's resolveTargetAccountRef/resolveNextCli/resolveEffectiveAccountRefForUpdate
to #340 naming (ClientId, body.clientId, currentCat.clientId). Add defense-in-depth
effort validation in getCatEffort to reject stale cross-provider effort values.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
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.

3 participants