dsh-tap 0.20.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (121) hide show
  1. package/AGENTS.md +99 -0
  2. package/CHANGELOG.md +751 -0
  3. package/LICENSE +21 -0
  4. package/README.en.md +59 -0
  5. package/README.md +256 -0
  6. package/cordis.patch.yml +385 -0
  7. package/core/bridge.js +698 -0
  8. package/core/json-store.js +91 -0
  9. package/core/rotation.js +108 -0
  10. package/core/usage-meter.js +176 -0
  11. package/docs/diagnosis-cache-quota.md +181 -0
  12. package/docs/diagnosis-qoder-flash.md +67 -0
  13. package/docs/diagnosis-trae-3003.md +302 -0
  14. package/docs/goals/bridge-port-host-split.md +91 -0
  15. package/docs/goals/desktop-adaptation.md +106 -0
  16. package/docs/goals/qoder-cn-provider-design.md +308 -0
  17. package/docs/goals/settings-card-ux-redesign-plan.md +1680 -0
  18. package/docs/goals/settings-card-ux-redesign.md +162 -0
  19. package/docs/goals/trae-agent-v3.md +41 -0
  20. package/docs/goals/trae-work-cn-repair.md +44 -0
  21. package/docs/goals/v0.8-/351/242/235/345/272/246/345/217/257/350/247/201-/346/250/241/345/236/213/345/212/250/346/200/201/345/214/226-/345/244/232/346/234/215/345/212/241/345/225/206.md +85 -0
  22. package/docs/pitfalls.md +105 -0
  23. package/docs/reverse/trae-cloud-api.md +218 -0
  24. package/docs/reverse/trae-model-catalog.md +129 -0
  25. package/docs/reverse/traework-cn.md +520 -0
  26. package/docs/rules/STATE.md +198 -0
  27. package/docs/rules/content-moderation.md +54 -0
  28. package/docs/rules/dev-role-boundary.md +94 -0
  29. package/docs/rules/extra-providers.md +42 -0
  30. package/docs/rules/gateway-facts.md +91 -0
  31. package/docs/rules/oauth-handshake.md +76 -0
  32. package/docs/rules/prompt-cache.md +93 -0
  33. package/docs/rules/quota-signals.md +125 -0
  34. package/docs/rules/routing.md +84 -0
  35. package/docs/rules/templates/oauth-reverse-checklist.md +42 -0
  36. package/docs/rules/trae-surface.md +242 -0
  37. package/docs/rules/ua-validation.md +81 -0
  38. package/host-config.js +282 -0
  39. package/index.js +2306 -0
  40. package/lib/client.js +2893 -0
  41. package/local-scan.js +104 -0
  42. package/package.json +82 -0
  43. package/providers/ark/index.js +11 -0
  44. package/providers/bailian/index.js +10 -0
  45. package/providers/bigmodel/index.js +11 -0
  46. package/providers/codebuddy/agenttool.js +122 -0
  47. package/providers/codebuddy/catalog.js +227 -0
  48. package/providers/codebuddy/errors.js +44 -0
  49. package/providers/codebuddy/headers.js +36 -0
  50. package/providers/codebuddy/images.js +125 -0
  51. package/providers/codebuddy/index.js +123 -0
  52. package/providers/codebuddy/oauth.js +279 -0
  53. package/providers/deepseek/index.js +11 -0
  54. package/providers/moonshot/index.js +11 -0
  55. package/providers/openai-compat.js +177 -0
  56. package/providers/openrouter/index.js +27 -0
  57. package/providers/qoder/catalog.js +145 -0
  58. package/providers/qoder/cosy.js +419 -0
  59. package/providers/qoder/gateway.js +563 -0
  60. package/providers/qoder/index.js +116 -0
  61. package/providers/qoder/oauth.js +364 -0
  62. package/providers/qoder/qoder_auth.wasm +0 -0
  63. package/providers/qoder/quota.js +56 -0
  64. package/providers/qwen/index.js +15 -0
  65. package/providers/tool-pairing.js +129 -0
  66. package/providers/trae/catalog.js +103 -0
  67. package/providers/trae/errors.js +85 -0
  68. package/providers/trae/gateway.js +853 -0
  69. package/providers/trae/index.js +126 -0
  70. package/providers/trae/oauth.js +443 -0
  71. package/providers/trae/quota.js +75 -0
  72. package/providers/trae/remote.js +365 -0
  73. package/scripts/capture-cache.mjs +65 -0
  74. package/scripts/capture-traffic.mjs +83 -0
  75. package/scripts/hermes-probe-dev-role.mjs +263 -0
  76. package/scripts/measure-latency.mjs +253 -0
  77. package/scripts/probe-ark-thinking.mjs +298 -0
  78. package/scripts/probe-cache-decline.mjs +292 -0
  79. package/scripts/probe-cache-ttl.mjs +221 -0
  80. package/scripts/probe-cache.mjs +156 -0
  81. package/scripts/probe-codebuddy-efforts.mjs +355 -0
  82. package/scripts/probe-codebuddy-tier-wiring.mjs +244 -0
  83. package/scripts/probe-effort-gaps.mjs +133 -0
  84. package/scripts/probe-media.mjs +115 -0
  85. package/scripts/probe-moderation.mjs +159 -0
  86. package/scripts/probe-oauth.mjs +617 -0
  87. package/scripts/probe-qoder-attribution-arm8.mjs +92 -0
  88. package/scripts/probe-qoder-attribution-arm9.mjs +102 -0
  89. package/scripts/probe-qoder-attribution.mjs +266 -0
  90. package/scripts/probe-qoder-flash-confirm.mjs +94 -0
  91. package/scripts/probe-qoder-live.mjs +344 -0
  92. package/scripts/probe-qoder-matrix.mjs +274 -0
  93. package/scripts/probe-qoder-null-content.mjs +153 -0
  94. package/scripts/probe-qoder-pairing.mjs +308 -0
  95. package/scripts/probe-qoder-quota.mjs +162 -0
  96. package/scripts/probe-qoder-thinking-config.mjs +52 -0
  97. package/scripts/probe-qoder-thinking-efforts.mjs +269 -0
  98. package/scripts/probe-quota.mjs +136 -0
  99. package/scripts/probe-quota2.mjs +144 -0
  100. package/scripts/probe-routing.mjs +226 -0
  101. package/scripts/probe-trae-3003-diagnosis.mjs +139 -0
  102. package/scripts/probe-trae-agent-v3.mjs +399 -0
  103. package/scripts/probe-trae-efforts.mjs +149 -0
  104. package/scripts/probe-trae-live.mjs +147 -0
  105. package/scripts/probe-trae-max-effort.mjs +179 -0
  106. package/scripts/probe-trae-model-routing.mjs +381 -0
  107. package/scripts/probe-trae-thinking-scene.mjs +238 -0
  108. package/scripts/probe-trae-transport-outage.mjs +176 -0
  109. package/scripts/probe-ua.mjs +508 -0
  110. package/scripts/trae-model-catalog.mjs +632 -0
  111. package/scripts/verify-agents-md.mjs +45 -0
  112. package/scripts/verify-bridge.mjs +1041 -0
  113. package/scripts/verify-core-generic.mjs +302 -0
  114. package/scripts/verify-desktop-acceptance.mjs +184 -0
  115. package/scripts/verify-host-config.mjs +265 -0
  116. package/scripts/verify-models.mjs +390 -0
  117. package/scripts/verify-providers.mjs +255 -0
  118. package/scripts/verify-qoder-provider.mjs +1020 -0
  119. package/scripts/verify-rotation.mjs +308 -0
  120. package/scripts/verify-trae-model-catalog.mjs +284 -0
  121. package/scripts/verify-trae-provider.mjs +1451 -0
@@ -0,0 +1,91 @@
1
+ # 已验证的网关事实(2026-08 实测,勿凭记忆改)
2
+
3
+ > 本文是网关事实摘要总表(2026-08-29 自 AGENTS.md 同名章节逐字迁入)。逐字段裁判细节见同目录专题文件:routing.md / ua-validation.md / quota-signals.md / prompt-cache.md / content-moderation.md / dev-role-boundary.md / trae-surface.md / oauth-handshake.md / extra-providers.md;Trae 协议细节另见 docs/reverse/traework-cn.md + trae-cloud-api.md。新实测事实追加在本文即可——AGENTS.md 网关节 2026-09-26 起只留 5 条通则 + 本文指针,不再逐条加行(踩坑 #52)。
4
+
5
+ - `/v2/chat/completions`:**仅流式**(非流式报 `code 11101`);`reasoning_effort` 接受 low/medium/high/max,各模型思考量自适应非严格单调(逐模型档位表与 2026-09-22 复查见下方「CodeBuddy 思考强度事实」节)
6
+
7
+ - `/agenttool/v1/search`、`/agenttool/v1/webfetch`:专用搜索/抓取端点,`ck_` Key 直调可用;**UA 必须是 CLI 形态**(如 `CLI/unknown CodeBuddy/2.136.0`,`CodeBuddyCode/1.0` 被拒 12403)
8
+
9
+ - `/v3/config`:网关自有模型目录(官方 CLI 用),`x-api-key` 头认证(OAuth 用 Authorization),同 UA 要求;响应 `{code, data:{models, agents}}`
10
+
11
+ - `/v2/images/generations`:OpenAI 形态生图端点,`hunyuan-image-v3.0-art` 实测出图(\~22s/张,plain UA 即可,无需 CLI UA);`/v2/videos/generations`、`/v2/3d/generations` 路由存在但当前账号一律 14407 `route config not found`(无可用模型,官方 CLI 包内也无对应客户端调用)→ 视频/3D 不接入。证据:docs/probes/media-2026-08-17.json(`probe-media.mjs`)
12
+
13
+ - OAuth 设备流:`POST /v2/plugin/auth/state?platform=CLI`(三个 `X-No-*` 头)→ 浏览器打开 authUrl → 轮询 `GET /v2/plugin/auth/token?state=`(`11217`=未完成)→ `GET /v2/plugin/login/account`;刷新 `POST /v2/plugin/auth/token/refresh`(`X-Refresh-Token`)
14
+
15
+ - **额度信号盘点**(2026-08-18,`scripts/probe-quota.mjs`,证据 docs/probes/quota-2026-08-18.json):`GET /v2/accounts`(ck\_ Key 直调可用)返回账户元数据(type/enterprise/lastLogin,当前账户=lastLogin:true 条目);`POST /v2/billing/meter/get-dosage-notify`(官方 CLI BillingService 的低额告警源,ck\_ 可用)健康时返回空文案;chat 响应头无 quota 字段,计费只有每请求 `usage.credit` 自报。**数字剩余额度 API 已找到**(2026-08-19 G2,quota-signals.md R-Q7):控制台计费路径族 `/billing/meter/get-user-resource` 等接受 **OAuth Bearer**(两域名同构;`ck_` key 401 不进)——`POST {}` 返回资源包列表(`CapacityRemainPrecise`/`CycleCapacity*`/`TotalDosage`,数值剩余额度主源);`get-enterprise-user-usage`(`X-Enterprise-Id` 头)返回套餐 `credit/limitNum`;daily/request 用量明细需 `X-Enterprise-Id` 作用域(个人=`"personal"` 字面量)。详见 docs/rules/quota-signals.md §R-Q7
16
+
17
+ - **WorkBuddy 与 CodeBuddy 同账户体系**:`www.workbuddy.cn/v2/plugin/auth/state` 实测返回同形态 `{state, authUrl}`(同一设备流);官方 CLI product.json 的 `internalDomain` 互含 workbuddy.cn,认证 id 同为 `Tencent-Cloud.coding-copilot` → 额度账户级共享,无需单独通道
18
+
19
+ - 会话头体系(CLI 使用,v0.5.5 目标):`X-Conversation-ID / X-Session-ID / X-Conversation-Request-ID / X-Conversation-Message-ID / X-Agent-Type / X-Agent-Intent`
20
+
21
+ - dsh 内置"获取可用模型"对本网关**永远失效**(无 OpenAI `GET /models`,404)
22
+
23
+ - **提示缓存按内容寻址、自动生效,与头无关**(2026-08-17 对照实测):usage 每 chunk 带 `prompt_cache_hit_tokens/prompt_cache_miss_tokens/credit`;会话亲和三头与 `prompt_cache_key` 对命中**零影响**(2.6k/15.8k 两档 anon==session);命中粒度 128 token。**按模型分策略**:deepseek-v4-pro 缓存工作(阈值 ≤2684 tok),deepseek-v3 在 ≤16.3k tok 全部 0 命中——v3 无缓存折扣。credit 实测单价:v4-pro miss ≈0.26/1k tok、hit ≈1/24;v3 ≈0.03/1k。~~命中可用性在 15.8k 规模有网关内部波动~~(**2026-09-03 重判**:该"波动"来自经桥流量的逐分片解码损坏,非网关内部行为——docs/diagnosis-cache-decline.md §2.4)。详见 docs/diagnosis-cache-quota.md
24
+
25
+ - **缓存按模型分策略实测表**(2026-08-18,docs/probes/cache-models-2026-08-18.jsonl):v4-pro / v4-flash / kimi-k2.7 / hy3 有稳定跨请求前缀缓存(同 prompt 连发命中 95–100%,kimi 全量命中含尾部);**glm-5.1/5.2 缓存条目秒-分钟级失效**,连发同 prompt 出现 0→83%→83%→0 非单调(4 次综合命中率 ≈41%——"命中率只有 40 多"类现象多源于此,与链路无关);deepseek-v3 恒 0。**v4-flash 网关缓存本身稳定**:直连同 prompt 连发 24 发全 99.3%(ck_/OAuth 交错)、16k/32k 条目无刷新存活 600s、增长前缀+60s 空闲全命中(2026-09-03,probe-cache-decline.mjs);存量"40k+ 真实内容保留不稳/命中波动"**已重判为桥逐分片解码损坏出站前缀**(core/bridge.js `rawBody += c`,跨 TCP 分片的中文字符→3×U+FFFD 且位置逐请求随机——完整证据链与历史重释见 docs/diagnosis-cache-decline.md)。**桥对缓存的"透明"结论有边界**:2.6k 单分片体逐字节透明(存量),大体量中文体在分片切断多字节字符时**不透明**(该缺陷待修复,踩坑 #28)。dsh 每步注入的秒级时间戳只动尾部 ~19 tok(17.5k prompt 跨会话重发命中 99.9%,docs/probes/cache-dsh-path-2026-08-18.jsonl)
26
+
27
+ - **内容审核 developer 角色事件**(2026-08-18 16:24 UTC 起,0.7.4 已解):网关内容审核开始对**含** **`role:"developer"`** **消息**的 chat payload 一律 `finish_reason: content_filter`,仅改回 `system` 即放行。触发源在 pi-ai:openai-completions 序列化器对推理模型把 system prompt 写成 developer 角色(`useDeveloperRole = model.reasoning && compat.supportsDeveloperRole`,桥 URL 不在非标准名单 → true)——所以 dsh 会话全挂而官方 CLI/手写回放(手写一直是 `system`)全过,deepseek-v3 不受影响(非推理模型不发 developer)。**修复在桥**:chat 出站前把 `developer` 重写为 `system`(verify-bridge 第 9 节锁回归)。0.7.3 猜的"x-stainless 头组/序列化顺序"已被 OpenAI SDK 6.26.0 全保真回放证伪;教训:等价对比必须用 dump/抓包的真实字节,手写重建会抹掉差异字段。
28
+
29
+ ### TraeWork CN 通道事实(2026-08-23 实测,裁判 docs/reverse/trae-cloud-api.md)
30
+
31
+ - 聊天网关在 `trae-api-cn.mchost.guru`:`POST /api/agent/v3/llm_utils_chat`(工具型一次性聊天,dsh provider 的目标)与 `create_agent_task`(官方 agent 环);未认证一律 401 `{code:1001}`。api.trae.cn / api.trae.com.cn 上**没有** /api/agent/v3(404)
32
+
33
+ - OAuth 在 `api.trae.cn`:`POST /trae/api/v3/oauth/ExchangeToken`(AuthCode 模式换 token / RefreshToken 模式+DeviceProof 刷新,同一端点);假 ClientID → 400 code 10101 "Invalid client.",真 ClientID+假 AuthCode → 10101 "无效参数";错误信封火山系 ResponseMetadata.Error;旧路径 `/cloudide/api/v3/trae/oauth/ExchangeToken` 仍存活但请求体已演进
34
+
35
+ - 客户端 id:SOLO Lite 分支 `en1oxy7wnw8j9n`、TRAE 分支 `ono9krqynydwx5`;认证双头 `Authorization: Cloud-IDE-JWT <token>` + `x-cloudide-token`(+`X-User-Region: CN`)
36
+
37
+ - **llm\_utils\_chat 信封与 SSE 语法已带凭据联调打通**(2026-08-23/24 实测,证据 docs/probes/trae-chat-live-\*.json):请求体 `{messages[content 为 {type,text} 块数组——字符串 400/4001], model, function:"inline_chat"(必填,缺则 2001), request_id, session_id, stream:true}`;头需三头同 JWT(Authorization/X-Cloudide-Token/x-ide-token)+ `x-app-id`(固定 UUID `6eefa01c-…`,**≠OAuth client\_id**)+ 数字串 version-code('0.1.52' 判 missing,用 20260401);SSE=metadata/timing\_cost/output(response/reasoning\_content)/token\_usage(顶层计数)/done,解析器按累计快照前缀差分(createTraeStreamParser)。**tools 全链路已联调**(2026-08-24):请求 `function.parameters` 必须字符串化(Go string 型),响应 `tool_calls[].function_call` 键 + arguments 增量片段按 index 拼接、done 恒 stop 需映射为 OpenAI `tool_calls` 终结。**model 字段不被 inline\_chat 路由**——服务端恒走账户默认模型(实测 provider\_model\_name=kimi-k2.6,与请求值无关)
38
+
39
+ - **模型改派与其余限制**(trae-cloud-api.md §5.1,2026-08-24 终局探测矩阵 docs/probes/trae-model-routing\[234]-*):raw 面模型被* ***function 位钉死**——inline\_chat 只服务账户默认模型(非默认 model 名→3003 "all models failed",custom\_model 无效;早前曾静默改派 kimi-k2.6,服务端行为有时变);chat\_v3/solo\_agent\_lite 恒 seed-code-lite、solo\_work\_lite 恒 glm-5.2(任意 model 名都 200 但改派)。改派真值源=timing\_cost.provider\_model\_name,网关以 SSE 注释行披露且计量记真实模型。**唯一真实的模型选择 = remote 会话协议**(2026-10-05 起工具环场景另有 agent 面,见下条)(已落地:providers/trae/remote.js + 网关* *`traeChatTransport`* *设置——chat\_sessions + model\_name/manual 策略,model\_config 事件证实 glm-5.3/kimi-k2.6 真实路由;事件=plan\_item thought/reasoning 累计快照 + finish summary 兜底 + token\_usage + done;耗* ***work 额度池**;不支持 OpenAI tools——带 tools 请求 400 remote-no-tools;Free 账号 kimi-k3 触发 error 1005 套餐门)。**额度双池**:raw 耗 IDE 池(available\_endpoint=0)、remote 耗 work 池(=1)——`POST api.trae.cn/trae/api/v2/pay/ide_user_ent_usage`(req\_source 0/1/2,Cloud-IDE-JWT + x-device-* 头组)按 `entitlement_base_info.available_endpoint` 分池读数(实测 3 次 remote 会话 work 池 +9.4 credits)。限流 4011 紧(raw 面联调间隔 ≥20s;remote 面无 4011 但有排队);/api/ide/v1/chat 老端点 4023 拒现代模型名;get\_model\_list 两域名 404;GetUserInfo 昵称字段=ScreenName
40
+
41
+ - 官方本地 harness(:40005 axum,chat/start\_chat/subscribe\_events)**懒启动**且启动参数未知;其数据库加密;令牌不在 state.vscdb/凭据管理器任何可读位置——harness 驱动路线存档未采用(trae-cloud-api.md §3)
42
+
43
+ - **余额只读面(设置卡「余额」行,2026-09-26 P1 落地)**:`POST {traeAuthBaseURL}/trae/api/v2/pay/ide_user_ent_usage` 带 `{require_usage:true, req_source:0}` 一次返回全部资源包(`req_source:1` 只回 `available_endpoint=0` 子集);按 `available_endpoint` 分池(0=IDE/raw、1=work/remote),头组 = 网关头组 + 凭证三头。插件 `providers/trae/quota.js` 60s memoize、永不 throw;POST action `trae-quota` 消费,采样纪律 = 展开/收起边界各一次、不周期轮询、取不到显示「—」不编造
44
+ - **思考档位(`reasoning_effort`)方言:2026-10-04 起已出档(goal trae-work-cn-repair G3)**。目录(state.vscdb 缓存)逐模型声明 `reasoning_effort_config:{support_thinking, options, default_level}`(实测 11 模型带声明,拼写逐模型不同:`glm-5.3`/`kimi-k3` 等 = `["light","high","extra_high"]`,`glm-5.2` = `["high","extra_high"]`,`Doubao-Seed-*` = `["light","high"]`;旧字段 `reasoning_effort_options` 已全 null 废弃)。**官方线缆字段取证**(官方 bundle `@byted-icube/solo-lite/dist/551.*.mjs` + `ai-modules-chat`):remote 通道消息体的 `custom_model.reasoning_effort`(旧名 `reasoning_effort_level` 由版本门切换),取值来自逐模型档位存储 `AI.agent.model.reasoning_effort_level_by_agent_model_v2`。**探针定论**(`scripts/probe-trae-thinking-scene.mjs`,证据 docs/probes/trae-thinking-scene-*.json):remote 面 thinking 恒 enabled(`reasoning_content` 全臂在场)且 `custom_model.reasoning_effort` 8/8 臂 200 被接受、真模型路由(model_config=glm-5.3 确认);效果方向性 2 采样 = light/extra_high INCONCLUSIVE、high 单向高于基线(同 Qoder 族结论:**入口不报错 ≠ 有单调语义**,用户不应期待高档位思考更多)。**inline_chat 面终局**:`thinking:{type:enabled}` / `thinking_enable:true` / `scene_params` 内嵌 effort 三变体全被忽略——同一内层 400 `Invalid combination of reasoning_effort and thinking type: high + disabled`,thinking=disabled 由 scene 决定、客户端字段无法翻转。**出档形态**:`catalogToProfiles` 投影 `reasoningEfforts`(键 = 宿主枚举映射 light→low/high→high/extra_high→xhigh,值 = 目录声明拼写——宿主 schema 对 reasoningEfforts 键有固定枚举 `off|minimal|low|medium|high|xhigh|max`,原拼写做键会被整块拒收,踩坑 #66);镜像块 `compat.supportsReasoningEffort:true`;设置卡逐模型 select(`traeModelSetPrefs`,允许集 = 目录声明 ∪ 存量);网关 remote 出站注入(客户端带值优先、prefs 补默认;inline 传输不注入——该面 3003 不可用)。**max 上位档(2026-10-05)**:目录不声明 `max` 但 remote 面实测接受该拼写且产生比 extra_high 更多推理(glm-5.3 high 2788 < extra_high 3209 < max 4139 推理字符,方向一致,证据 docs/probes/trae-max-effort-*.json)——投影对声明了 extra_high 的模型追加 max 上位档(无 extra_high 的模型不加,不臆造未测路径)。复跑:`node scripts/probe-trae-thinking-scene.mjs` / `node scripts/probe-trae-max-effort.mjs`
45
+
46
+ - **agent 面(function=solo_work_lite,2026-10-05 探针落地为 `traeChatTransport:'agent'`,证据 docs/probes/trae-agent-v3-*.jsonl,8 臂 + function 名扫描)**:同一端点 `/api/agent/v3/llm_utils_chat` 的第二面——接受 OpenAI 风格 tools(parameters 序列化字符串)+ tool_choice=auto + **并行 tool_calls**(单事件多调用);历史 assistant.tool_calls 出站键必须是 **function_call**(OpenAI 的 function 键被 proto 层拒:2001 "required field Name is not set");role:tool 回传闭环正常(第二轮产出最终回答)。**限制如实标注**:模型位钉死(A6 臂 kimi-k2.6/DeepSeek-V4-Flash 的 timing_cost.provider_model_name 恒为 glm-5.2——改派照常诚实披露);reasoning_effort 字段被忽略(A5 臂与 A2 同形态,不虚标生效);E1 错模型名/E2 坏参数均被静默容忍(该面宽容,与 inline 面 3003 硬错相反)。function 名扫描:agent_chat/agent_v3/solo_agent_chat/agent/assistant_chat 均未注册(2001 "no function config found");chat 已注册但模型名不被路由(4023 "model is unknown"——与 2001 的区别是 chat 进入了模型路由层)。复跑:`node scripts/probe-trae-agent-v3.mjs [--fn solo_work_lite] [--sweep]`
47
+
48
+ - **vscdb 目录发现按平台分支(2026-10-04 G1)**:`discoverStateDbs()` 无参时 win32 直查 `os.homedir()/AppData/Roaming/{TRAE SOLO CN,TraeWork CN}/User/globalStorage/state.vscdb`,其余(WSL)扫 `/mnt/c/Users/*/…` 逐用户目录——此前写死 WSL 路径,Windows 桌面端(dsh desktop 原生进程)恒扫空,是设置卡「同步目录」报「未发现 state.vscdb」的根因(踩坑 #67)。显式传 usersRoot 时两平台同为逐用户扫描(fixture 测试用)
49
+
50
+ ### Qoder CN 通道事实(2026-09-22 实测,裁判 docs/goals/qoder-cn-provider-design.md + wiki/10-provider-qoder.md)
51
+
52
+ - **聊天信封三种失败形态**(翻译网关 error taxonomy,证据 docs/probes/qoder-chat-live-\*.json):a) 传输层非 2xx(401/429 透传、其余 502);b) `event:error` 帧(stackTrace);c) **带内失败帧**——HTTP 200 信封装业务错误对象:body 为 JSON 字符串、解析后**无 choices/usage、有 code/message**(实测形态 `{"code":"400","message":"[FAIL]node:oa_qwen-plus-main msg:Execution failed: null"}`,statusCodeValue:400)。网关按 c 识别上抛:流式错误 chunk+[DONE],非流式 502 `qoder_upstream_error`
53
+ - **未知模型 key 静默改派 auto**:请求臆造 key(如 `qmodel_38flash`)→ HTTP 200 正常应答,但响应 chunk `model` 恒 `"auto"` 且 billable:false(Qwen3.8-Flash 真实 key = `qfmodel`);响应 model 字段不可作路由证据,归因以请求侧 key + 计费旁证为准(踩坑 #37)
54
+ - **上游逐模型家族严格校验 tool 配对,且校验器把 `content` 为 null/缺键的消息当"不存在"**(2026-09-22 单变量差分实测,证据 docs/probes/qoder-null-content-1790041768628.json + qoder-matrix-1790023075879.json):同一条**结构合法**的工具环,只切 assistant.content 一个字段——`null`/缺键在 **dmodel/kmodel/mmodel 上 400**(信封 `{code:provider_error, message:"Error in upstream response", request_id, details:"…"}`,details 内层文案三家各一:`Messages with role 'tool' must be a response to a preceding message with 'tool_calls'` / `Invalid request: tool_call_id is not found` / `invalid params, tool result's tool id(call_…) not found (2013)`),`""` 与非空文本三家**全绿**;`role:"tool"` 自身 `content:null` 另报 `An assistant message with 'tool_calls' must be followed by tool messages responding to each 'tool_call_id'`。真孤儿(无前置 assistant)同样 400。容错家族 **auto/qmodel_38max/qmodel/gmodel 对以上全部坏体静默容忍**(多半回空正文)——**用它们验证"修复有效"等于没验证**(踩坑 #39 首版正是在 qmodel 上验的)。`event:error` 的 stackTrace 带阿里侧类名(`com.alibaba.force.ai.biz.nodes.BaseLargeModelRequestNode$RetryableSseListener`),可据此确认是上游节点回传而非 Qoder 自身校验
55
+ - **tool_call_id 与前置 id 不匹配、双 tool_calls 只回一个结果:qmodel 上不报错**(同一矩阵,**仅在容错家族验过**):容错面比 OpenAI 官方宽;严格家族未逐条复测,别把它当全家族事实引用
56
+ - **`role:"developer"` 被上游在反序列化阶段整请求拒绝**(2026-09-22 实测 dmodel:details 内层 `Failed to deserialize the JSON body...`;同体换 `role:"system"` 全绿):宿主 pi-ai 对 reasoning 模型会把 system prompt 序列化成 developer(docs/rules/dev-role-boundary.md 同族),故 Qoder 网关出站一律折叠 developer→system(同 codebuddy 桥策略,verify-qoder [18] 锁定案)
57
+ - **官方 Qoder CN 客户端为什么从不触发上述 400(本机取证,2026-09-22)**:`~/.qoder-cn/projects/**/*.jsonl` 105 份 transcript——`tool_use` 与 `tool_result` **孤儿 result 恒为 0**(个别会话计数不等时,缺的永远是「结果」而非「声明」,如 54 uses / 52 results);按 `message.id` 归并的 **879 个工具回合中 93.3% 带非空 thinking、52.8% 带非空 text,裸 tool_use(≈ `content:null`)仅 2.73%**;252 份 `qodercli.log` 的 `request_message_count` 一路涨到 **457 条**(官方同样在客户端重放全量历史、同样打 `agent_chat_generation`),而整个日志库里 `provider_error` / `Messages with role` **零命中**。即:差异不在端点、不在服务端校验器,而在**客户端历史构造纪律**(声明与结果成对落盘、工具回合几乎总带正文)
58
+ - **目录 context_config = 官方客户端的上下文长度档位**:条目带 `context_config`(变体名 → {token_count, is_default},实测 Qwen3.8-Max:200K 默认/400K/1M);本插件逐模型"上下文长度"调节以变体为选项(选中写镜像 contextWindow,未选回落默认档)
59
+ - **`Cosy-ClientType` 恒为 5**(2026-09-22 与官方 wasm 逐头 diff 定案):`QoderContext(machineId, cosyVersion, userInfo, clientMetadata)` 的第 4 参 `clientMetadata.client_type` 不影响该头——官方 wasm 对 `'qoder'`/`5`/缺省一律出 **`5`**,现网客户端线缆值也是 5。附带:wasm 恒设 `Cosy-Business-Product: cli`、`Cosy-Business-Type: agent`、`Cosy-Scene: assistant`、`Cosy-MachineType: 5`、`Login-Version: v2`。我方旧值 `'qoder'` 曾在出站头留下第三方指纹,已修为 5
60
+ - **模型路由由 `X-Model-Key` 头决定,不由 body.model**(2026-09-22 实测):`X-Model-Key: qfmodel` + body `model:"auto"` → 打到 Flash 的坏节点;`X-Model-Key: auto` + body `model:"qfmodel"` → 正常出正文。插件用 `prepareChat(..., {modelKey: model})` 生成该头,与官方一致
61
+ - **Qwen3.8-Flash(qfmodel)上游节点 `oa_qwen-plus-main` 故障**(2026-09-22,完整诊断 docs/diagnosis-qoder-flash.md):带内 `{"code":"400","message":"[FAIL]node:oa_qwen-plus-main msg:Execution failed: null"}`,**只被 qfmodel 指名**(同坏体在 qmodel/qmodel_38max/q37fmodel 正常)。客户端侧成因已穷举排除:模型 key(客户端日志自证 qfmodel)、body 字段、9 组 clientMetadata(用官方 `QoderContext` 原实现签)、`cosyVersion` 1.1.40→999.999.999、`context_window` 各值、tools/多轮/effort——错误一字不变。**时间线**:客户端 transcript 04:21:38 最后一次成功,13 秒后同一客户端 `output_tokens=0`;节点在 04:21:38–04:21:51 进入持久失败。插件侧只能如实上抛(`qoder_upstream_error`);复测 `node scripts/probe-qoder-flash-confirm.mjs`(恢复即翻绿)
62
+ - **客户端不读 `minimal_version`**(2026-09-22):目录条目里的 `minimal_version:{vsc:"999.999.999"}` 是死数据——官方客户端 bundle 里 `minimal_version`/`minimalVersion`/`999.999.999` 零命中,客户端照选照跑;服务端也无版本闸门(扫 `cosyVersion` 1.1.40→999.999.999 错误不变)
63
+ - **逐模型 billable 标志**(2026-09-22 官方 transcript 统计):qfmodel 帧 `billable:false`(免费预览档,烧多少都不计 credits)、dfmodel 帧 `billable:true`;插件侧裸请求所有模型均回 `billable:true`(但不落计数器,见下条归因)。"官方今天用了却没统计"的先查是不是用的免费档模型
64
+ - **用量记账两链路分离:配额计数实时且与形态无关,统计视图(热力图/汇总/明细)是延迟批处理且由归因链驱动**(2026-09-22 臂9 定论,证据 docs/probes/qoder-attribution-arm9-*.json):①**额度扣减**(`quota/usage` 的 `addOnQuota.used`)对**裸 OpenAI body 同样实时入账**(两发大输出各 ~0.9 credits,45s 内整数读数 197→199)——早前"裸 body 不记账"的判定是**整数取整读数吞掉 0.002 级小额探测**的假象(踩坑 #40 的预警实证);官方 GUI 客户端聊天(Max,5.04 credits)同样 ~1 分钟内 192→197。②**统计视图**(`credits-heatmap`/`credits-summary`/网页明细)对官方客户端自己的聊天也不即时收录(42 分钟/71 分钟/6 小时三个数据点均为 0)——属**按日批处理**;要让插件用量进入该层,需官方归因链:聊天 body 归因信封 + business 块 + 收尾 business/finish(mode auth)+ /api/v1/tracking(mode sign)双上报(bundle `A6e`/`g4i`/`aPl` 原文实证,字段全表在 wiki/10-provider-qoder.md)。插件网关 0.9.9 起全部对齐(verify-qoder [19] 12 断言锁定案);上报 fire-and-forget 不影响主链路
65
+ - **客户端 transcript 里的 usage 是加工记录不是线缆帧**(2026-09-22,踩坑 #40):transcript 里的 usage 带 `request_id`/`speed`/`inference_geo`/`context_usage_ratio` 且 `billable:false`,而真实线缆帧(我们抓的 SSE 原文)只有 tokens/credits 且 `billable:true`——客户端落盘前做了 enrich,逆向时不能以 transcript 字段为线缆真相
66
+
67
+ - **账户配额只读面(设置卡「余额」行,2026-09-26 P1 落地,真实联调验证)**:`GET {qoderOpenapiBaseURL}/api/v2/quota/usage` 用**裸 Bearer**(**非 COSY 签名**——签名是聊天/目录面的口径,配额面不吃那套),返回 `userQuota`/`addOnQuota`(各带 total/used/remaining/unit)+ `isQuotaExceeded`;读数为整数(小额消耗被取整吞掉,踩坑 #40 同族——判别实验用量要大于分辨率)。插件 `providers/qoder/quota.js` 60s memoize、永不 throw;POST action `qoder-quota` 消费,采样纪律同 Trae(边界采样、不轮询、「—」不编造)
68
+
69
+ - **目录逐模型声明思考能力 `thinking_config`(2026-10-04 实测 14 模型;证据 `docs/probes/qoder-thinking-config-*.json`,复跑 `node scripts/probe-qoder-thinking-config.mjs`)**:条目带 `{disabled:{…}, enabled:{efforts:{"<档>":{is_default?}}, is_default?}}`——`disabled` 在场 = 该模型**声明**支持关思考;`enabled.efforts` 的键就是可选档位。实测三种形态:`qmodel_38max`/`qfmodel` = `off` + `low/medium/xhigh`;`dmodel`/`gm51model` = `off` + `high/max`;`gmodel`/`kmodel`/`kmodel_latest` = **无 disabled** + `low/high/max`;`gfmodel` = `high/max`;`dfmodel` = `off` + `low/high/max`;`auto`/`qmodel`/`qmodel_latest`/`q37fmodel`/`mmodel` **没有命名档位**(只有一个开关)⇒ 不出档位表(不臆造)。插件侧 `qoderReasoningEfforts()`(providers/qoder/catalog.js)把它投影成模型条目的 `reasoningEfforts`(宿主 Model/Effort 选择器「推理等级」的数据源),镜像块同时声明 `compat.supportsReasoningEffort`(缺它 pi-ai 出站不会写 `reasoning_effort`)。**线上效果未定论**:6 臂单采样探针(`reasoning_effort=max/low`、`thinking_config=disabled`、`thinking_config=enabled.efforts.{low,high}`)呈自适应非单调(`disabled` 臂仍出 619 字推理、`low` 比 `max` 更长),按踩坑 #42 纪律**不据此改写出站方言**,维持既有 `reasoning_effort` 透传路径(与设置卡 prefs 同源;客户端带值时不覆盖 prefs)。**多采样复证仍非单调(2026-10-04,`scripts/probe-qoder-thinking-efforts.mjs`,显式带 reasoning_effort 避 prefs 注入,2 模型 ×3 臂 ×3 采样 = 15 次全 200,证据 `docs/probes/qoder-efforts-*.json`)**:`qmodel_38max` low 273.7→medium 248→xhigh 229、`dmodel` high 790→max 381(均值,字符)——**两模型同向:声明档位越高实测思考均值越低**;按 #42 记 INCONCLUSIVE(3 采样不能反向定论"反序/无效"),但与 Ark 侧结论互证:**档位入口不报错 ≠ 有单调语义,用户不应期待 high 比 low 思考更多**;off 臂因 openai 方言省略参数会触发 prefs 注入(变量不干净)未测。
70
+
71
+ ### CodeBuddy 思考强度事实(2026-09-22 实测;复跑 `node scripts/probe-codebuddy-efforts.mjs`,证据 docs/probes/codebuddy-efforts-\*.json)
72
+
73
+ - **目录 `reasoning` 声明有两代形态**(`GET /v3/config`):legacy `{"effort":"high","summary":"auto"}` 只声明**默认档**;current `{"supportedEfforts":["low","high","max"],"canDisableThinking":true,"defaultEffort":"high","summary":"auto"}` 是**能力清单**。2026-09-22 实测带清单的只有 4 个:`glm-5.3-flash` / `kimi-k2.8-preview`(`["low","high","max"]` + canDisableThinking **true**)、`hy4-preview` / `hy4-preview-x`(`["high"]` + **false**)。插件侧:带清单者由目录驱动档位表(`catalogReasoningEfforts`),legacy 者继续用 `cordis.patch.yml` 的静态表 —— 清单是"该模型有哪些档",`effort`/`defaultEffort` 只是"默认在哪档"
74
+ - **误拼档位有专用错误码 `11150`**(`extError.code = invalid_reasoning_effort`,"the reasoning effort value is not supported by the current model"):`deepseek-v4-pro` 显式发 `off`/`disabled`/`auto` 三拼写即 11150;而**同一拼写在 `glm-5.3-flash` 上被静默接受**(HTTP 200、行为同默认档)——**拼写接受面逐模型不一致**,所以档位表只列实测可接受/目录声明过的拼写,不臆造同义词
75
+ - **"关思考"拼写未定论 ⇒ `canDisableThinking:true` 不等于有可发的线值**:两个 canDisableThinking=true 的模型**省略参数照常思考**(`omit` 臂 reason≈1.2k,与 `defaultEffort` 一致),显式 `off`/`disabled`/`auto` 被接受但推理量不变(≈1.2–1.4k);只有 `minimal`/`none` 表现出量级下降,但**两模型不一致**(glm-5.3-flash:minimal 三次 0/11/0、none 0/101/0;kimi-k2.8-preview:minimal ≈112–167、none ≈749–1140 仍照常思考),基线 omit 在两者都是 ≈0.2–1.4k。没有跨模型可靠的关思考拼写 ⇒ 插件**不给这些模型出 off 档**(宿主选择器里的 `Off` 映射为"省略参数",对它们就是假开关)
76
+ - **`off` 档的语义 = 省略参数,且只在该模型"省略即不思考"时才是真开关**:2026-09-22 复查把 `hy3` / `hy3-preview` 的 `off` 撤掉——两模型六臂实测**每臂都出 ~510–625 字推理**(旧结论"off=省略参数已验证无 reasoning_content"已过期,模型侧行为变了);`deepseek-v3.2` / r1 家族 / v4-pro / v4-flash / GLM 5.1/5.2/5v-turbo / Kimi k2.5/k2.6 / minimax-m3 的 omit 臂仍为 0,`off` 保留
77
+ - **目录里有 ≠ /v2 可路由**(同 2026-09-22 矩阵,routing.md R-R3 再证):`glm-4.6v` / `kimi-k2-thinking` / `minimax-m2.5` / `hy4-preview-x` 四个条目在 `/v3/config` 里齐全,但 `/v2/chat/completions` 六臂全部 `11102 service info not found` ⇒ **不进静态清单**(否则选择器出一个永远失败的模型)。**2026-09-26 复核**:`hy4-preview-x` 已离开目录(目录 31 条 · 可路由 28),其余三条仍在目录且恒 11102;插件侧以 `providers/codebuddy/catalog.js` 的 `UNROUTABLE_MODELS` 为唯一真源(含已离开目录的条目,防重现时无处标注),设置卡同步行口径「目录 N · 可路由 M」、死条目置灰 + 「不可路由」徽标(0.12.0)
78
+ - **`auto` 是路由器、响应 `model` 字段才是真身**:请求 `auto` 六臂全部回显 `model:"hy4-preview"`(当前账号的 auto 落点),故 auto 不出档位表;判读响应时别拿请求 id 当路由证据(v4-pro 家族 11150 同理按响应码断言)
79
+ - **推理长度只是弱信号**:各档长度自适应、非严格单调(glm-5.1:low 662 / medium 666 / high 1101 / max 338),"长度没变"不等于"参数没生效"——档位表判据取"HTTP 200 + 无带内错误",`off` 判据取"省略参数时 reasoning_content 为 0"
80
+ - **插件侧全链路(真实上游联调,2026-09-22)**:`node scripts/probe-codebuddy-tier-wiring.mjs` —— 临时 DSH_HOME(不碰用户配置)起插件桥 → 本地捕获代理 → 真实网关,12 断言全绿:目录声明 → `model-list` 的 `efforts` 档位表 → settings.yaml 镜像带 `reasoningEfforts`(宿主 Model/Effort 选择器数据源)→ 真实 chat 出站体带被注入的 `reasoning_effort`(`max`)且上游 200;负例(未声明档位 `medium`、无表模型 `auto`)出站体不带该键。证据 docs/probes/codebuddy-tier-wiring-2026-09-22.json
81
+
82
+ ## 桥端口按宿主 profile 分流(2026-10-03 落地,goal docs/goals/bridge-port-host-split.md)
83
+
84
+ - **分流语义**:web 与 desktop 是两进程、共享同一份 `~/.dsh/codebuddy-plugin.json`——分流端口**不持久化进共享文件层**(写进去两进程读同一份仍撞),每进程按自身宿主信号现读现算。归一函数 `resolveBridgePorts`(index.js,唯一出处):默认 profile(目录名 `web`)或信号不可用 → 偏移 0(= 与既有行为逐位一致);其余宿主 profile → trae/qoder 翻译网关分流到 默认+10(**3902→3912、3903→3913**)。CodeBuddy 桥 3901 本期不分流(goal 边界,主聊天入口面最大)。
85
+ - **信号链路**:`currentProfileDirName()` 每次现读 `hostConfig.probe().documentPath`(host-config.js probe 的 documentPath 已 try/catch 兜底 null,永不 throw),取 profile 目录名小写。**永不缓存**:settings 服务经 `ctx.inject` 异步注入,首个 resolveNow(applyLive 同步段)跑时 inject 回调可能未落地——缓存会把启动竞态烙成永久错分;现读后服务就绪即自愈(下一次 sync* 端口对账触发重 listen + 镜像重铺)。保守失败方向:信号 null → shift 0 = 今日行为。
86
+ - **「显式」判定**(踩坑 #55):cordis 给 apply 的 entry config 恒含 `Config({})` 的 schema 默认端口(活 desktop 实测 entryPortKeys=`[bridgePort,traeBridgePort,traeChatTransport,qoderBridgePort]`)——entry ≠ 用户显式。故:entry 端口值**偏离 schema 默认**才算显式(verify-* 套件随机空闲口 ≠ 默认 → 采信);文件层显式恒采信(设置卡 commit 才落键,含等于默认的值);cordis 默认 entry 落回分流/文件层。
87
+ - **listen/镜像同源**:sync*Bridge 与镜像(syncQoder/syncTraeModelsToDshSettings 经模块级出口 `effectiveSettingsFn` = apply 内赋值的 resolveNow)同源同一次解析端口,根除 listen 3913 镜像写 3903 的双路径漂移。镜像 baseURL 整块重铺即热生效(路由存在性管理)。
88
+ - **设置卡观感语义**(免当 bug 报):desktop 端口字段显示 3912/3913,但 `overridden()` 判 false(文件层无该键)故**无「已覆盖」标记**;用户不主动改就不写共享层;删键/重置 = 回到分流值 391x 而非 3902。
89
+ - **活体验证**(docs/probes/port-split-2026-10-03.json):web(:3090) 持 3901/3902/3903,desktop(:19387) 持 3913(Qoder,PID 28088)——netstat 实证两实例各自持有各自端口、零 EADDRINUSE、desktop 诊断卡 Qoder 行 `running:true port:3913 lastError:null` 不再出现「另一实例代管」;desktop patch qoder 镜像 baseURL 重铺为 3913。Trae 3912 启用实测同构(验证后已还原共享层 traeEnabled=false)。
90
+
91
+
@@ -0,0 +1,76 @@
1
+ # 规则 05:OAuth 握手
2
+
3
+ > 状态:**规则成立**——state 生命周期、token 权限边界(R-O5)、refresh 轮换(R-O6)均已收束;仅剩 state 真实 TTL **未解**(需下次交互登录时顺带验证,见 §5)
4
+ > 证据:`docs/probes/oauth-2026-08-19.jsonl`(15 条无认证只读)+ `docs/probes/oauth-token-2026-08-19.jsonl`(G2 真实 token 八组)
5
+ > 脚本:`scripts/probe-oauth.mjs`(`--set core|ttl|matrix|quota|quota2|quota3|quota4|quota5|quota6|quota7|refresh`、`--state <s> --ttl-check-only` 跨会话 TTL 复检)
6
+
7
+ ## 1. 现象(上游咒语原文)
8
+
9
+ - AGENTS.md:25 —「OAuth 设备流:`POST /v2/plugin/auth/state?platform=CLI`(三个 `X-No-*` 头)→ 浏览器打开 authUrl → 轮询 `GET /v2/plugin/auth/token?state=`(`11217`=未完成)→ `GET /v2/plugin/login/account`;刷新 `POST /v2/plugin/auth/token/refresh`(`X-Refresh-Token`)」
10
+ - 实现侧(index.js:441-442):客户端轮询上限 10 分钟、间隔 1s;refresh 在 `expiresAt` 前 60s 触发,`expiresIn` 缺省按 3600s。
11
+
12
+ ## 2. 规则(每条附验证过程)
13
+
14
+ ### R-O1 state 创建:无认证、`X-No-*` 三头是迷信、`platform` 必填但任意
15
+
16
+ - 创建 `POST /v2/plugin/auth/state?platform=<X>` 无需任何凭据(200 code 0,36 字符 state + authUrl)。
17
+ - **咒语破除**:不带三个 `X-No-*` 头照常签发(P-O3 **HIT**)——它们是 CLI 遥测习惯,不是校验项。
18
+ - `platform` **必填**(省略 → `400 code 10001 "platform is empty"`)但取值任意(`WORKBUDDY` 照过,P-O4 半 HIT 半推翻:推翻"省略也行",成立"自由文本")。与 AGENTS.md:27 的 WorkBuddy 同体系互证。
19
+
20
+ ### R-O2 state 生命周期:pending/无效/过期三态不可区分
21
+
22
+ - 轮询 `GET /v2/plugin/auth/token?state=` 对**一切未完成的 state**(合法的 pending、纯编造的 bogus、推定已过期的)统一回 `200 code 11217 "login ing"`(P-O1 原预测"bogus 可区分"**MISS**,这是本课题最重要的否定发现)。
23
+ - **直接后果**:state 的服务端 TTL **不可从 token 端点观测**(+60s/+240s 均 11217,P-O5 表面 HIT 但对 bogus state 同样成立——该"存活"证据无效,TTL 标未解);客户端唯一正确策略就是插件现行的**轮询 + 本地超时放弃**(10 分钟)。
24
+ - 多 state 并发互不作废:创建 state2 后 state1 仍 11217(P-O2 **HIT**)——无单飞约束;插件 `oauthPending.active` 的单飞是纯客户端选择。
25
+
26
+ ### R-O3 account 端点:pending state → 裸 401
27
+
28
+ `GET /v2/plugin/login/account?state=<pending>` → **401 nginx HTML 页**(非 JSON 信封,无 code)(P-O6 **HIT**,预测"code ≠ 0")。即账户信息端点在 token 签发前由前置代理直接拒绝,不走业务码。
29
+
30
+ ### R-O4 refresh 失败形态:响亮失败
31
+
32
+ `POST /v2/plugin/auth/token/refresh` 带 bogus `X-Refresh-Token` → `401 code 12153 "refresh token failed:10000:token format error"`(P-O7 **HIT**:非 2xx 且业务码非 0,双信号响亮;内层码 10000=token format error)。
33
+ 插件 `refreshOAuth` 对 `!res.ok` 或 `code!==0` 均返回 undefined → 触发重新登录路径,与该失败形态匹配。
34
+
35
+ ## 3. 对重构的输入
36
+
37
+ - core 层设备流抽象只需:`createState(platform)` / `pollToken(state)` / `refresh(token)` 三接口;**"11217 永远 ambiguous"是必须写进 core 注释的契约**(轮询放弃策略由 core 提供,provider 只给端点路径与头方言)。
38
+ - X-No-* 三头从"必须"降级为 provider 方言默认值(迷信破除的证据在 P-O3)。
39
+ - 错误规范化要覆盖两种非 JSON 形态:nginx 裸 401 HTML(account 端点)与 401+JSON 业务码(refresh)。
40
+
41
+ ## 4. 探测边界声明
42
+
43
+ 本轮 15 次调用全部为**未认证公开端点的只读探测**:未创建真实会话、未铸造任何 token、未触碰审核/风控逻辑。bogus token 仅用于观测失败形态。
44
+
45
+ ## 5. 未解(解锁条件明确)
46
+
47
+ | 问题 | 状态(2026-08-19 晚 G2 解锁) |
48
+ |---|---|
49
+ | ~~token 权限边界(OAuth token vs `ck_` key 的端点可达矩阵)~~ | **已解(R-O5)** |
50
+ | ~~refresh 失效/轮换条件~~ | **已解(R-O6)** |
51
+ | **state 真实 TTL** | 仍未解:需用一个跨时 state 完成登录看是否仍可换 token(下次交互登录时可顺带验证——先创建 state、隔天再完成授权) |
52
+
53
+ ### R-O5 token 权限边界:OAuth token 是 `ck_` key 的严格超集
54
+
55
+ 证据:`docs/probes/oauth-token-2026-08-19.jsonl`(--set matrix / quota4)。
56
+ - 五端点矩阵(accounts / config / dosage-notify / agenttool-search / chat)OAuth 与 `ck_` key **完全同可达**(P-T1/P-T2 预注册命中);OAuth 下 chat 响应头同样零额度字段(P-T6 命中,R-Q1 认证不变)。
57
+ - **`/billing/meter/*` 计费路径族 OAuth-only**:get-user-resource 用 `ck_` key → 401 nginx 裸页(P-QP12);用 OAuth Bearer → 200 code 0 数值额度(详见 quota-signals.md R-Q7)。
58
+ - 结论:数值额度能力绑定 OAuth 模式——插件 api-key 模式无法显示真实剩余额度(诚实标注的 UI 含义)。
59
+
60
+ ### R-O6 refresh 轮换:**不互相作废**(实测推翻预注册)
61
+
62
+ 证据:同上(--set refresh,真实 token,成功后已按 refreshOAuth 同逻辑回写 auth 文件)。
63
+ - P-RR1 HIT:真实 refresh → 200 code 0 + 新 accessToken/refreshToken,`expiresIn=5184000`(**60 天**),响应键集 `{accessToken,expiresIn,refreshExpiresIn,refreshToken,tokenType,notBeforePolicy,sessionState,scope,domain}`。
64
+ - P-RR2 **MISS 推翻**:旧 refresh token 复跑 **仍 200 code 0**(又签发一套新令牌)——refresh 轮换**不作废旧 refresh token**(至少在观测窗口内;长期作废条件未测)。
65
+ - P-RR3 HIT:旧 access token 在 refresh 后仍可用(/v2/accounts 200)——access 也不随 refresh 作废。
66
+ - 附带发现:响应字段名是 `refreshExpiresIn`(秒),插件 `refreshOAuth` 读的是 `refreshExpiresAt`——该字段永远 undefined(良性潜伏字段名 bug,无分支消费它;记录待修)。
67
+
68
+ ## 6. 复跑路径
69
+
70
+ ```bash
71
+ node scripts/probe-oauth.mjs --set core # 创建/轮询/bogus/并发/头/platform/refresh 形态
72
+ node scripts/probe-oauth.mjs --set ttl # +60s/+240s 阶梯
73
+ node scripts/probe-oauth.mjs --state <s> --ttl-check-only # 跨会话复检某个 state
74
+ node scripts/probe-oauth.mjs --set matrix|quota|quota2|quota3|quota4|quota5|quota6|quota7|refresh
75
+ # ↑ G2 真实 token 集合(需已完成交互登录)
76
+ ```
@@ -0,0 +1,93 @@
1
+ # 规则 02:提示缓存失效边界
2
+
3
+ > 状态:**规则成立**(TTL 维度对 glm 的结论为"概率性保留",无 TTL 边界可言;未测单元格见 §4 诚实标注)
4
+ > 证据:`docs/probes/cache-boundary-2026-08-19.jsonl`(本轮 49 条)+ 存量 `cache-models-2026-08-18.jsonl`、`cache-flash-scale-2026-08-18.jsonl`、`cache-flash-thresh-2026-08-18.jsonl` + `cache-decline-2026-09-03.jsonl`(v4-flash TTL 600s 增测与经桥塌落重判)
5
+ > 脚本:`scripts/probe-cache-ttl.mjs`(`--mode ttl|sweep|thresh|predict`);存量 `scripts/probe-cache.mjs`;2026-09-03 起 `scripts/probe-cache-decline.mjs`(burst/ttl/grow/replay/whoami,ck/oauth 双凭据)
6
+
7
+ ## 1. 现象(上游咒语原文)
8
+
9
+ - AGENTS.md:30 —「提示缓存按内容寻址、自动生效,与头无关……命中粒度 128 token。按模型分策略:deepseek-v4-pro 缓存工作(阈值 ≤2684 tok),deepseek-v3 在 ≤16.3k tok 全部 0 命中」
10
+ - AGENTS.md:31 —「glm-5.1/5.2 缓存条目秒-分钟级失效,连发同 prompt 出现 0→83%→83%→0 非单调」「v4-flash 阈值 412 tok 起即缓存」「v4-flash gap 60s 无影响(TTL ≥60s)」
11
+
12
+ 咒语未回答的失效边界三维度:**前缀长度阈值 × 时间窗(TTL)× 按模型策略表**。本课题补齐。
13
+
14
+ ## 2. 规则(每条附验证过程)
15
+
16
+ ### R-C1 缓存按内容寻址、自动生效,与会话亲和无关
17
+
18
+ 存量对照(diagnosis §2.2,run3/run5):anon / session 头 / prompt_cache_key 两臂命中完全等价(2.6k、15.8k 两档)。本轮所有探测以唯一 nonce 隔离条目,复现"同内容第二次即命中"在所有缓存模型上成立。
19
+ **预注册命中**:H-POLICY 的肯定臂全部建立在此机制上并命中(见 R-C2)。
20
+
21
+ ### R-C2 策略按模型分,**不按厂商聚类**
22
+
23
+ **规则**:缓存可用性是 per-model 开关;同厂商内部策略分裂(DeepSeek:v3 ✗ / v3.2 ✓ / r1 ✗ / v4-pro ✓ / v4-flash ✓;Hunyuan:hy3 ✓ / hy3-preview ✗)。
24
+
25
+ 实测策略表(本轮 sweep,2 发即判;存量带来源标注):
26
+
27
+ | 模型 | 缓存 | 命中形态 | 证据 |
28
+ |---|---|---|---|
29
+ | deepseek-v3 | ✗ | 恒 0(≤16.3k 三档) | 存量 run1/2/4 |
30
+ | deepseek-v3.2 | ✓ | 128 粒度 | 本轮 sweep 2816/2903 |
31
+ | deepseek-r1 | ✗ | 恒 0 | 本轮 sweep 0/2903 ×2 |
32
+ | deepseek-v4-pro | ✓ | 128 粒度,floor 精确 | 存量+本轮 thresh |
33
+ | deepseek-v4-flash | ✓ | 存量 95–100% | 存量 cache-flash-* |
34
+ | glm-5.1 / 5.2 | ✓(概率性,见 R-C3) | 近全长(2304/2396) | 存量+本轮 |
35
+ | glm-5v-turbo | ✓(TTL 未测) | 近全长(2831/2833) | 本轮 sweep |
36
+ | kimi-k2.5 | ✓ | 全长 2619/2619 | 本轮 sweep |
37
+ | kimi-k2.6 | ✓ | 128 粒度 2048/2619 | 本轮 sweep |
38
+ | kimi-k2.7 | ✓ | 存量 | 存量 cache-models |
39
+ | kimi-k3 / k3-1 | ✓ | 128 粒度 2560/2704 | 本轮 sweep |
40
+ | minimax-m2.7 | ✓ | 近全长 2513/2624 | 本轮 sweep |
41
+ | minimax-m3 | ✓ | 近全长 2764/2765(首发即带 128 命中,原因未查) | 本轮 sweep |
42
+ | hy3 | ✓ | 存量 | 存量 cache-models |
43
+ | hy3-preview | ✗ | 恒 0(2.6k 与 4.6k 两档) | 本轮 sweep + P2 |
44
+ | auto | 未测(路由复合体,课题 3 覆盖) | — | — |
45
+
46
+ **预注册命中**:kimi 聚类 4/4(k2.5/k2.6/k3/k3-1 均有缓存)、minimax 2/2、r1 无缓存、hy3-preview 在 4.6k 仍 0(P2:排除"阈值未到")。
47
+ **预注册推翻(记录在案)**:H-POLICY 原猜 v3.2 无缓存(实测有)、hy3-preview 有缓存(实测无)——正是这两条推翻逼出了"per-model 而非 per-vendor"的最终表述。
48
+
49
+ ### R-C3 时间窗:分模型两类行为
50
+
51
+ - **稳定 TTL 类**(DeepSeek 缓存系、v4-flash):条目在实测窗内确定存活。
52
+ - v4-pro:60s / 120s / 240s 三档全部命中 2560/2684(本轮 ttl);**TTL ≥ 240s**,真实会话跨分钟级轮次命中(存量诊断 §1.3)与此一致。
53
+ - v3.2:60s 命中 2304/2538(**P1 预注册命中**);TTL ≥ 60s。
54
+ - v4-flash:20s×3 + 60s 全命中(存量);**2026-09-03 增测:16k 与 32k 条目无刷新存活 600s(99.2%/99.8%,oauth 凭据,probe-cache-decline.mjs --mode ttl)**。经桥真实会话的"秒级失效/塌落"已重判为桥逐分片解码损坏,非网关 TTL——见 docs/diagnosis-cache-decline.md(H7 证伪)。
55
+ - **概率保留类**(glm-5.1/5.2):**不存在 TTL 边界**。glm-5.2 时间阶梯:5s miss、15s hit、30s miss、60s miss、120s hit——5s 可以丢、120s 反而中;2s 极速连发四连 miss/hit/miss/hit 交替(**P3 预注册命中**:≥1 miss)。咒语"秒-分钟级失效"的真身是**网关对 glm 条目的概率性保留**,任何确定性的"存活 T 秒"表述都不成立。glm-5v-turbo 未见 flap(仅 2 发),归类待复测。
56
+
57
+ **预注册推翻**:H-TTL 原猜"glm 条目死于 5–120s 内某点"——非单调数据直接否决了确定性 TTL 的存在。
58
+
59
+ ### R-C4 前缀长度阈值与命中粒度
60
+
61
+ - **阈值**:v4-pro ≤173 tok 即缓存(128/173 命中);观测极限 128 tok(更小时命中计数恒为 0,不可观测)。v4-flash ≤412 tok(存量)。两模型阈值都低于咒语给出的上界(2684)。
62
+ - **粒度**:
63
+ - v4-pro:命中 = `floor(prompt/128)×128` **精确**,9/9 尺寸档复现(512/553、1024/1114、1536/1660、2048/2167、2688/2713、128/173、256/287、384/439、4608/4657)。**预注册命中**:4400 档预测"命中恰为 floor"→ 4608 = 36×128 ✓(P4 修正轮,预测先发于会话记录)。
64
+ - v3.2:128 倍数但**可少一块**(2816/2903 精确;2304/2538、3072/3238 少 128)——**P4 原预测"精确 floor"在此 MISS**,规则修订为"≤ floor,偶少一块"后由 P1/复跑数据支撑。
65
+ - kimi-k2.6/k3/k3-1:128 倍数;k2.5、minimax、glm:近全长(非 128 倍数)。粒度同样 per-model。
66
+
67
+ ## 3. 失效边界总表(前缀 × 时间窗 × 模型)
68
+
69
+ | 模型 | 可缓存最小前缀 | 粒度 | 时间窗行为 |
70
+ |---|---|---|---|
71
+ | deepseek-v4-pro | ≤173 tok | 128,floor 精确 | ≥240s 确定存活 |
72
+ | deepseek-v3.2 | 未测(≤2.5k) | 128,偶少一块 | ≥60s 确定存活 |
73
+ | deepseek-v4-flash | ≤412 tok | 128(存量) | ≥600s 确定存活(2026-09-03);存量"40k+ 真实内容保留不稳"**已重判为桥逐分片解码损坏**(docs/diagnosis-cache-decline.md),网关直连受控探测稳定 |
74
+ | glm-5.1 / 5.2 | 未测(≤2.4k) | 近全长 | **概率性保留,无 TTL 边界**(5s 可丢 / 120s 可中) |
75
+ | kimi / minimax / glm-5v / hy3 | 未测 | 见 R-C2 表 | 未测 |
76
+ | v3 / r1 / hy3-preview | —(不缓存) | — | — |
77
+
78
+ ## 4. 未解 / 未测(诚实标注)
79
+
80
+ - glm 条目保留概率的驱动因子(负载?分片?)客户端不可观测;只能断言"不可依赖 glm 缓存"。
81
+ - kimi/minimax/glm-5v/hy3 的 TTL 与阈值未测(单元格留空,不为完成标准凑数)。
82
+ - v4-pro 在 >240s 的存活未测(真实会话证据支持分钟级,未做小时级探测)。
83
+ - minimax-m3 首发即命中 128 的现象观察到 1 次,未定位(疑共享前缀前缀段,nonce 在首句内,理论上前 128 tok 不含差异部分——存疑待查)。
84
+ - 网关缓存写/读对 credit 的计价口径沿用存量诊断 §3.1,本轮未重新拟合。
85
+
86
+ ## 5. 复跑路径
87
+
88
+ ```bash
89
+ node scripts/probe-cache-ttl.mjs --mode sweep --models <逗号分隔> # 策略表
90
+ node scripts/probe-cache-ttl.mjs --mode ttl --model M --gaps 5,15,30,60,120
91
+ node scripts/probe-cache-ttl.mjs --mode thresh --model M --sizes 130,260,390,...
92
+ node scripts/probe-cache-ttl.mjs --mode predict # P1–P4 预注册确认轮
93
+ ```
@@ -0,0 +1,125 @@
1
+ # 规则 04:额度信号地图
2
+
3
+ > 状态:**规则成立**(额度耗尽错误码不可安全观测,标未解——见 §4)
4
+ > **2026-08-19 晚重大修订**:数值剩余额度 API **已找到**(R-Q7)——`/billing/meter/get-user-resource`
5
+ > 等控制台计费路径族接受 OAuth Bearer token(两域名同构),旧结论"数字剩余额度无
6
+ > CLI/api-key 可达 API"对 **OAuth token 不成立**(对 `ck_` key 仍成立:401)。
7
+ > 证据:`docs/probes/quota-map-2026-08-19.jsonl`(9 条)+ `docs/probes/oauth-token-2026-08-19.jsonl`
8
+ > (G2 矩阵 matrix/quota/quota2/values/quota3–7/refresh 八组)+ 存量 `quota-2026-08-18.json`
9
+ > 脚本:`scripts/probe-quota2.mjs`、`scripts/probe-oauth.mjs --set matrix|quota|quota2|values|quota3|quota4|quota5|quota6|quota7|refresh`(可复跑)
10
+
11
+ ## 1. 现象(上游咒语原文)
12
+
13
+ - AGENTS.md:26 —「额度信号盘点:`GET /v2/accounts` 账户元数据;`POST /v2/billing/meter/get-dosage-notify` 低额告警源,健康时返回空文案;**数字剩余额度无 CLI/api-key 可达 API**——chat 响应头无 quota 字段……计费只有每请求 `usage.credit` 自报」
14
+
15
+ 咒语是一份**点状清单**;本课题把它升级为**全端点 × 全响应头 × 响应体字段**的完整否定/肯定地图。
16
+
17
+ ## 2. 规则(每条附验证过程)
18
+
19
+ ### R-Q1 响应头:全网关零额度信号
20
+
21
+ **规则**:任何端点、任何响应形态(成功/错误)的响应头都不携带额度信息。
22
+ **验证**:chat 存量 12 头全枚举无 quota(quota-2026-08-18.json);本轮 P-Q1a/accounts、P-Q1b/config、P-Q1c/dosage 三端点 **0 quota 头 HIT**;P-Q4 错误信封(12403)同样 **0 quota 头 HIT**。现存响应头全集:cache-control/connection/content-type/date/eo-*/server/traceid/x-request-id/x-user-id/x-waf-uuid 等传输与追踪头。
23
+
24
+ ### R-Q2 agenttool 响应体:无计量字段
25
+
26
+ **规则**:`/agenttool/v1/search` 与 `/agenttool/v1/webfetch` 的响应体都**没有** usage/credit 字段(深度键名扫描全文)。
27
+ **验证**:P-Q2a search 无 usage **HIT**(预注册);P-Q2b webfetch 原预测"有 usage"(由 index.js:653 `data?.usage` 条件记录推断)**MISS**——实测 `{url,title,content}` 全文无任何计量字段。推翻已记录;附带结论:**插件 webfetch 的 usage 记录是死路径**(重构时可删,注释标注本证据)。
28
+
29
+ ### R-Q3 dosage-notify:无参接口,健康形态固定
30
+
31
+ **规则**:`POST /v2/billing/meter/get-dosage-notify` 忽略请求参数;健康时恒返回 `{dosageNotifyCode:0, dosageNotifyZh:"", dosageNotifyEn:"", skipUrl:""}`。
32
+ **验证**:P-Q3 携带 `{threshold:100, level:"high"}` 返回与 `{}` 完全同形 **HIT**(预注册)。非健康形态(告警文案/ dosageNotifyCode 非 0)当前账号无法诱发——见 §4。
33
+
34
+ ### R-Q4 /v3/config 的 `models[].credits`:展示倍率,不是费率表
35
+
36
+ **规则**:目录每个模型带字符串字段 `credits: "xN.NN credits"`(本账号实测:v4-pro x0.51、v4-flash x0.17、v3-2-volc x0.29、glm-5.2 x0.79、kimi-k2.6 x0.52、hy3 x0.00)。它是**相对展示倍率**:与实测 credit/1k tokens 不成线性(glm-5.2 倍率最高 0.79,实测 0.171 credit/1k 却低于 v4-pro 的 0.257);唯一成立的硬映射是 **x0.00 ⟺ 实测零计费**。
37
+ **验证**:倍率字段本轮发现于 P-Q1b 的体扫描;**P-Q5 预注册命中**——读 `hy3 = x0.00` 后预测"hy3 微调用 usage.credit === 0",实测 200 / credit=0 / 16 tokens ✓。
38
+ **推翻记录**:"credits 是每 1k token 费率"假设被实测单价对比推翻(非线性)。
39
+
40
+ ### R-Q5 计费正信号:仅 chat SSE 的 usage.credit
41
+
42
+ 唯一按请求计费自报字段仍是 chat SSE 末 chunk 的 `usage.credit`(存量诊断 §3.1 单价拟合);agenttool 无(R-Q2)、媒体端点响应无计量字段(media 证据体扫描:url/data 结构)。**额度信息到此为止,没有更多来源。**
43
+
44
+ ### R-Q6 端点存在性附记
45
+
46
+ `GET /v2/report` → `404 page not found`(Go 风格措辞),与路由层 `404 Route Not Found`(课题 3 R-R1)是**两套 404 实现**——可作网关服务边界的指纹。
47
+
48
+ ### R-Q7 数值剩余额度 API 已找到:`/billing/meter/*` 控制台计费路径族(OAuth Bearer 可达)
49
+
50
+ **规则**:数值剩余额度存在于控制台用户中心(www.codebuddy.cn/profile/plan SPA)背后的
51
+ `/billing/meter/*` 路径族,且**接受 OAuth Bearer token**——在 copilot.tencent.com 与
52
+ www.codebuddy.cn **两域名同构可达**(实测逐路径 200 code 0 完全一致)。`ck_` key 被拒
53
+ (401 nginx 裸页)——该路径族是 **OAuth-only**。发现链:SPA HTML →
54
+ `download.codebuddy.cn/web/usercenter/<hash>/assets/*.js`(公开静态资源)→
55
+ config chunk 内的路径字面量(`un.post("/billing/meter/get-user-resource",e)` 等)。
56
+
57
+ | 端点(全部 POST,JSON body) | 认证 | 数据 |
58
+ |---|---|---|
59
+ | `/billing/meter/get-user-resource` `{}` | OAuth Bearer | **数值剩余额度主源**:`Response.Data.{TotalCount,TotalDosage,Accounts[]}`;每个资源包带 `PackageName`、`CapacitySize/Remain/Used`、`CapacityRemainPrecise`(亚 credit 精度字符串)、`CycleCapacity*`(周期视图)、`CycleStart/EndTime` |
60
+ | `/billing/meter/check-gift-claimed` `{}` | OAuth Bearer | 赠品包状态:`{claimed,claimed_at,active,credit_num,validity_period,start_time,end_time}`(本账号:1500 credits 已领、active) |
61
+ | `/billing/meter/compensation-status` `{}` | OAuth Bearer | 补偿包状态(本账号:1000 credits 未领、active:false、已过期) |
62
+ | `/billing/meter/get-enterprise-user-usage` `{}` + `X-Enterprise-Id: <enterpriseId>` | OAuth Bearer | 套餐视图:`{credit,limitNum,cycleStartTime,cycleEndTime,cycleResetTime}`——控制台套餐页 credit/limitNum 字段的数据源(本账号企业:limitNum 2000、credit 0) |
63
+ | `/billing/meter/get-user-daily-usage` `{startTime,endTime,pageNum,pageSize}` + `X-Enterprise-Id` | OAuth Bearer | 按日用量 `{total,data[]}` |
64
+ | `/billing/meter/get-user-request-usage` `{startTime,endTime,timezone,pageSize,version:2,pageToken}` + `X-Enterprise-Id` | OAuth Bearer | 按请求用量(requestId + credit 列,控制台"用量"页表格源) |
65
+
66
+ **参数纪律**:
67
+ - daily/request-usage 的 `X-Enterprise-Id` 为**必填作用域头**:省略 → `400 10001 invalid params`;
68
+ 个人上下文 = 字面量 `"personal"`(控制台 sessionStorage `profile-enterpriseId` 的缺省值),
69
+ 也可传账户 uid;企业上下文 = 真实 enterpriseId。
70
+ - endTime 允许未来时刻(`今天 23:59:59` 不报错);日期格式 `YYYY-MM-DD HH:mm:ss`。
71
+ - 未解疑点:personal 作用域本月 daily/request 均 `{total:0,data:[]}`,与资源包实测消耗
72
+ (赠送包 CycleCapacityUsed 533.27)矛盾——用量明细表可能只记企业线或有延迟,标**存疑**,
73
+ 不作为插件数据源(插件自有 usage-meter 覆盖该需求)。
74
+
75
+ **预注册命中/推翻**:P-QP1(copilot 猜测路径全 404)HIT;P-QP2(workbuddy 镜像)HIT;
76
+ P-QP3 HIT;P-QP4/P-QP5("控制台 API 拒绝 Bearer")**MISS 推翻**——`/billing/meter/*` 与
77
+ `/console/accounts` 接受 Bearer;P-QP6(同路径在网关域 404)**MISS 推翻**——网关域同样服务
78
+ 该路径族(网关路径族不止 /v2、/v3、/agenttool);P-QP7 HIT。
79
+ `/cgi/v2/user/getInfo` 在两域名均 404(cookie 包装器属于别的宿主),控制台 cookie 体系
80
+ 本身仍未触(按红线不碰)。
81
+
82
+ **对旧结论的修订**:AGENTS.md「数字剩余额度无 CLI/api-key 可达 API」与本文 §3 旧表
83
+ 「数值剩余额度——任何端点都没有」**对 OAuth token 作废**;对 `ck_` key 依然成立
84
+ (quota4-resource-ck-key → 401)。插件在 OAuth 模式下可显示真实剩余额度。
85
+
86
+ ## 3. 额度信号完整地图(结论表)
87
+
88
+ | 端点 | 响应头额度信号 | 响应体额度信号 |
89
+ |---|---|---|
90
+ | POST /v2/chat/completions | 无 | `usage.credit`(每请求计费)、`usage.prompt_cache_*`(缓存计费依据) |
91
+ | GET /v2/accounts | 无 | 账户元数据(plan type、enterprise;**无数值额度**)。注意:2026-08-19 观测到该端点网关侧持续故障(午后 500 APISIX 错误页 → 傍晚 524 origin timeout,OAuth token 有效、其余计费端点同时段正常),插件侧按 `accountsError` 降级展示 |
92
+ | GET /console/accounts | 无 | 同 /v2/accounts(OAuth Bearer 可达,两域名同构) |
93
+ | POST /v2/billing/meter/get-dosage-notify | 无 | 低额告警文案(健康时空;无参) |
94
+ | POST /billing/meter/get-user-resource | 无 | **数值剩余额度**(资源包 CapacityRemain/Precise、TotalDosage;OAuth-only) |
95
+ | POST /billing/meter/check-gift-claimed、/compensation-status | 无 | 赠品/补偿包 credit_num 与状态(OAuth-only) |
96
+ | POST /billing/meter/get-enterprise-user-usage | 无 | 套餐 credit/limitNum/周期(OAuth-only,需 X-Enterprise-Id) |
97
+ | POST /billing/meter/get-user-daily-usage、/get-user-request-usage | 无 | 用量明细(OAuth-only,需 X-Enterprise-Id 作用域;personal 实测空,存疑) |
98
+ | GET /v3/config | 无 | `models[].credits` 展示倍率(x0.00=零计费已验证) |
99
+ | /agenttool/v1/search、/webfetch | 无 | 无 |
100
+ | /v2/images/generations | 无 | 无(media 证据) |
101
+ | 错误信封(12403 等) | 无 | 无 |
102
+ | 数值剩余额度 | — | **OAuth token:`/billing/meter/get-user-resource` 可达**;`ck_` key:任何端点都没有(401) |
103
+
104
+ ## 4. 未解(诚实标注)
105
+
106
+ - **额度耗尽/超额错误码**:诱发需要真实耗尽账号额度,违反只读/低速率红线,**标未解**。存量已知告警源仅 dosage-notify 的文案字段。
107
+ - 告警形态下 dosageNotifyCode 的取值集(健康时恒 0)未观测。
108
+ - ~~网页控制台 plan API(cookie 体系)按红线不碰~~ → 2026-08-19 修订:数值数据**不再需要** cookie 体系(R-Q7,OAuth Bearer 直达);cookie 包装器(/cgi/v2/*)本身仍不碰。
109
+ - credits 倍率的精确定价口径(相对哪个基准、是否含输出折算)不可从客户端确定。
110
+ - daily/request-usage 在 personal 作用域返回空但与实测消耗矛盾(R-Q7 存疑条)——用量明细表的记账范围/延迟未解。
111
+ - get-user-resource 的 `CapacityRemain`(整包剩余)与 `CycleCapacityRemain`(周期剩余)的扣减顺序、多包优先级(哪个包先扣)未测。
112
+
113
+ ## 5. 复跑路径
114
+
115
+ ```bash
116
+ node scripts/probe-quota2.mjs # 8 臂全端点额度信号扫描
117
+ node scripts/probe-quota.mjs # 存量三端点探测
118
+ node scripts/probe-oauth.mjs --set matrix # G2:token×端点矩阵(五端点×双凭据)
119
+ node scripts/probe-oauth.mjs --set quota # G2:两域名猜测路径 + workbuddy 镜像 + 控制台候选
120
+ node scripts/probe-oauth.mjs --set quota2 # G2:控制台真实只读路径(SPA 逆向)
121
+ node scripts/probe-oauth.mjs --set quota3 # G2:/billing/meter/get-* 首测
122
+ node scripts/probe-oauth.mjs --set quota4 # G2:参数形态 + 企业用法 + ck_ key 边界
123
+ node scripts/probe-oauth.mjs --set quota5|quota6|quota7 # 作用域头判别与值捕获
124
+ node scripts/probe-oauth.mjs --set refresh # G2:真实 refresh 轮换(回写 auth 文件)
125
+ ```
@@ -0,0 +1,84 @@
1
+ # 规则 03:路由分配维度(14407)
2
+
3
+ > 状态:**规则成立**(账号/套餐维度单账号不可变,标未解——见 §5)
4
+ > 证据:`docs/probes/routing-2026-08-19.jsonl`(19 条:3 轮矩阵 + 每轮 catalog 锚点);存量锚点 `docs/probes/media-2026-08-17.json`
5
+ > 脚本:`scripts/probe-routing.mjs`(`--set matrix|r2|r3|r4` 可复跑)
6
+
7
+ ## 1. 现象(上游咒语原文)
8
+
9
+ - AGENTS.md:24 —「`/v2/videos/generations`、`/v2/3d/generations` 路由存在但当前账号一律 14407 `route config not found`(无可用模型)」
10
+ - CHANGELOG.md:50 — 同咒,作"停止规则"存档
11
+
12
+ 咒语把 14407 当作"端点不可用"的整体判断。实测它是一个**分层路由结构里某一层的失败码**。
13
+
14
+ ## 2. 规则(每条附验证过程;预测均为预注册后实测)
15
+
16
+ ### R-R1 第一层:路径路由
17
+
18
+ 未知路径 → `404 "Route Not Found"`(纯文本、无 JSON 信封、与业务码无关)。
19
+ **预注册命中**:P6 `/v2/foo/generations` → 404 ✓。
20
+
21
+ ### R-R2 第二层:家族模型注册表(14401/14407 的真身)
22
+
23
+ 注册表查找以 **(家族, 模型名)** 为键;未命中时报错码**按家族分**,消息**逐字回显模型名**(含空串):
24
+
25
+ | 家族 | 端点 | 未命中码 | 消息模板 |
26
+ |---|---|---|---|
27
+ | image | /v2/images/generations | **14401** | `Create image failed with error: Image model [<echo>] route config not found` |
28
+ | video | /v2/videos/generations | **14407** | `Create video failed with error: Video model [<echo>] route config not found`(另有兜底变体,见 R-R4) |
29
+ | 3d | /v2/3d/generations | **14407** | `Create 3d failed with error: 3d model [<echo>] route config not found` |
30
+
31
+ **预注册命中**:C1(images 省略 model → 14401 回显空串)✓、C2(video + 全新假名 `no-such-video-model` → 14407 逐字回显)✓、C3(3d 省略 model → 14407 回显空串)✓。
32
+ **推翻记录**:原假设"14407 是通用码"被 P2 推翻(image 家族用 14401)——咒语里的 14407 只是 video/3d 家族的号码。
33
+
34
+ ### R-R3 chat 家族:独立注册表 + 11102,且**与 /v3/config、cli 清单均不等价**
35
+
36
+ - chat 模型未命中 → `400 + 11102 "model [<echo>] service info not found"`(措辞与媒体家族不同)。
37
+ - chat 注册表 **不等于** 账号目录(/v3/config 24 模型):`deepseek-v3` 不在目录却每日可用;`glm-5.0` 在目录却 11102;目录内部 id `deepseek-v3-2-volc` 也能路由(200)。
38
+ - **不等于 cli 启用清单**(12 个):`kimi-k2.5` 不在 cli 清单照样 200。
39
+
40
+ **预注册命中**:C4(全新假名 `no-such-model-abc` → 11102 逐字回显)✓、C5(kimi-k2.5 非 cli 清单 → 200)✓。
41
+ **推翻记录**:C6 预测 volc 内部 id 11102 → 实测 200;C7 预测 hunyuan-chat 后端不支持 → 实测 200。chat 注册表比任何可见清单都宽,**客户端无可用的"可路由模型"权威清单**(catalog/cli/deepseek-v3 案例三方互斥)。
42
+
43
+ ### R-R4 第三层:后端派发(模型已知、家族不支持)
44
+
45
+ 模型在全局可解析但其后端不支持该家族时,错误按家族分信封:
46
+
47
+ | 家族 | HTTP | code | 消息 |
48
+ |---|---|---|---|
49
+ | chat | 500 | 11103 | `Backend [<name>] is not supported` |
50
+ | 3d | 400 | 11103 | `Backend [<name>] is not supported for 3d generation` |
51
+ | video | 400 | **14407** | `unsupported video params`(14407 兼作 video 家族兜底码) |
52
+ | image | 500 | — | **无 JSON 信封**(空 body 崩溃) |
53
+
54
+ **预注册命中**:D2(images + kimi-k2.6 → 裸 500 无信封,全新模型复现 P3)✓、D3(chat + 图像模型 → 500/11103 复测稳定)✓、E1(video + kimi-k2.6 → 400/14407 "unsupported video params" 兜底复现)✓。
55
+ **推翻记录**:D1 预测 video 走 11103 → 实测 14407 兜底,修正规程后由 E1 锁定。
56
+
57
+ ## 3. 回答课题:路由按什么维度分配
58
+
59
+ 可观测维度(单账号):
60
+ 1. **路径**(家族端点是否存在)→ 404 层
61
+ 2. **(家族 × 模型名)** 注册表 → 14401/14407/11102 层
62
+ 3. **模型 → 后端映射 × 后端支持的家族集** → 11103/14407 兜底/裸 500 层
63
+
64
+ 咒语的"当前账号一律 14407"在此框架内的准确表述:**本账号(及全局)没有名为 hunyuan-video-t2v / hunyuan-3d 的模型注册项**;/v3/config 中也没有任何 video/3d 家族模型,与"该账号无媒体家族(除 image)可用模型"一致。
65
+
66
+ ## 4. 对重构的输入
67
+
68
+ - 薄适配器侧错误映射表:14401/14407/11102/11103 皆为**客户端可结构化解析**的业务码(msg 含模型名回显),core 层只需透传 code/msg,不做字符串匹配。
69
+ - 图像家族裸 500 无信封——core 层的错误规范化要容忍"非 JSON 500"。
70
+
71
+ ## 5. 未解(诚实标注)
72
+
73
+ - **账号/套餐维度不可证伪**:单账号无法变异;目录(/v3/config)是账号级证据,但目录成员资格与可路由性三方互斥(R-R3),故"路由是否按账号套餐分配"标**未解**。
74
+ - `auto` 模型的路由分解(分配到哪个实体模型、按什么信号)未测——属课题 3 延伸,需 dump 对比 auto 与显式模型的响应头/延迟分布。
75
+ - images 家族裸 500 是网关崩溃还是刻意,不可进一步区分。
76
+
77
+ ## 6. 复跑路径
78
+
79
+ ```bash
80
+ node scripts/probe-routing.mjs # 矩阵 P1–P6 + X1
81
+ node scripts/probe-routing.mjs --set r2 # 确认轮 C1–C8
82
+ node scripts/probe-routing.mjs --set r3 # 信封轮 D1–D3
83
+ node scripts/probe-routing.mjs --set r4 # 兜底轮 E1
84
+ ```
@@ -0,0 +1,42 @@
1
+ # 逆向检查清单:<provider 名> <客户端版本>(日期)
2
+
3
+ > 用途:新增一个需要 OAuth 逆向的服务商时复制本模板,逐节执行。
4
+ > 纪律:能不动态插桩就不插桩;带凭据联调只允许一次真实登录;红线(E 节)任一不过即停工。
5
+
6
+ ## A. 静态情报(无网络)
7
+ - [ ] A1 GitHub 社区仓库检索:历史协议面/信封/域名,标注停更时间(历史参照 ≠ 协议真相)
8
+ - [ ] A2 本机安装包:product.json / package.json / manifest(版本、域名、client_id、URL scheme)
9
+ - [ ] A3 二进制 strings:路由族提取(本地 RPC 与云端路由按命名空间分辨)
10
+ - [ ] A4 官方日志/本地缓存:登录日志、网络日志(头组清单)、state.vscdb 类缓存
11
+ - [ ] A5 凭据存储排除法:明文文件 / OS 凭据管理器 / 加密存储 / 仅内存(按此顺序证伪)
12
+
13
+ ## B. 无凭据在线探测(探测边界声明先行:次数、间隔、全部只读)
14
+ - [ ] B1 端点存活矩阵:登录/token/refresh/account/chat 五面,错误信封逐条落证据
15
+ - [ ] B2 错误码指纹:假 client_id / 假 auth_code / 无 token 三层失败形态
16
+ - [ ] B3 头校验面:UA/必填头逐项二分(规则 vs 迷信,迷信头注释标注)
17
+ - [ ] B4 限流基线:连续探测触发限流的间隔(写进脚本的探测纪律,如 ≥20s)
18
+ - [ ] B5 预注册预测表:每条假设写明预测与判定标准(HIT/MISS 制度;否定发现同样成文)
19
+
20
+ ## C. 带凭据联调(一次真实登录解锁,仅此一步)
21
+ - [ ] C1 登录流全证据落盘(脱敏后入库:`<redacted:字段>` 原位替换)
22
+ - [ ] C2 token 权限边界矩阵:token × 端点族(含计费/额度族)——决定 UI 诚实标注档位
23
+ - [ ] C3 refresh 轮换语义实测:旧 refresh 复跑 / 旧 access 复用 / 字段名核对
24
+ → 产出注册表声明 `refreshRotation: rotating | non-rotating | unknown`
25
+ - [ ] C4 签名/指纹头分级:
26
+ - 可自控 → 自持密钥走完整流(如 P-256 自签 + 公钥注册)
27
+ - 无害 → 补齐对齐官方日志形态
28
+ - 不可伪造 → 省略并文档化(见头即校验的服务端强制头绝不伪造,发了必 400)
29
+ - [ ] C5 额度/配额信号:数值额度 API 探测(决定真实/估算档)
30
+
31
+ ## D. 落地与回归
32
+ - [ ] D1 骨架装配:core/oauth-flow.js 方言声明(端点/错误信封/轮换语义/authUrl 白名单)
33
+ - [ ] D2 离线 verify 脚本(mock 上游:投毒 authUrl / 非法基址 / 分片 body / 临期刷新竞态)
34
+ - [ ] D3 规则文档(docs/rules/<provider>.md)+ 未解表(每条写解锁条件)
35
+ - [ ] D4 README/免责声明更新;改派披露通道就位(如 SSE 注释行)
36
+
37
+ ## E. 红线确认(任一不过即停工)
38
+ - [ ] E1 不提取/解密官方客户端本地凭据存储
39
+ - [ ] E2 不伪造不可复刻的服务端强制签名头
40
+ - [ ] E3 不分发任何真实凭据;仓库零 secret;探测证据落盘前必脱敏
41
+ - [ ] E4 不做多账号聚合/指纹轮换/额度转售
42
+ - [ ] E5 登录仅由用户显式动作发起