Skip to content

fix(ui-mac): #1106 注定 needs_auth 的云 MCP 不再挡引擎 boot —— 轮换阻塞段收敛到 office-only - #1107

Merged
jinjunnn merged 1 commit into
alphafrom
fix/1106-rotation-stutter
Aug 25, 2026
Merged

fix(ui-mac): #1106 注定 needs_auth 的云 MCP 不再挡引擎 boot —— 轮换阻塞段收敛到 office-only#1107
jinjunnn merged 1 commit into
alphafrom
fix/1106-rotation-stutter

Conversation

@jinjunnn

Copy link
Copy Markdown
Owner

Fixes#1106

症状 → 机制 → 修法

症状:应用每 ~10 分钟卡 1.8–9.7 秒(owner 真实应用同日 25 次实测),期间界面不响应。

机制(方案评论有全量坐标,这里只留判决性的两条):

  1. 令牌轮换必须重启引擎 —— 轮换凭据里唯一的运行时消费者 ALPHA_API_KEY{file:}
    配置装载时解析一次、存 per-directory 实例快照,活实例不重读;不改上游没有活换通道。
    所以「每 10 分钟重启一次」本身动不了,能动的是重启的代价
  2. 重启代价的构成:引擎 boot await 每一个已配置 MCP server。重跑 owner 日志(27 次轮换 boot):
    每一次阻塞段都以 server unavailable key=cloud status=needs_auth 收尾,init count=20
    紧随其后 3–7ms —— 无凭证的云连接是唯一关键路径,4 个 office server 27/27 都先它完成。
    而「有没有凭证」在 fork 前的 <engineData>/mcp-auth.json 里就已确定(引擎取凭证走
    getForUrl(name, url):entry + serverUrl 逐字匹配 + tokens,缺一即 401 → needs_auth)。

修法(全部 alpha 侧,零上游改动):

  • 注入侧(alpha-config-injection.ts + 新 cloud-mcp-doomed-connect.ts):fork 时逐条镜像
    getForUrl 判据读引擎自己的凭证库;注定 needs_auth 时把云 server 定义写成 enabled:false
    —— 引擎 MCP.create 对它零等待直接 disabled,/mcp/cloud/auth/authenticate/connect
    照常可用(getMcpConfig 落到原始 config,不查 enabled)。读不了文件 fail-open 到今天的形状;
    kill-switch 的 WITHHELD 分支逐字节不变;DEF/SERVER env(ext 端点身份核验)不动。
  • hub 侧(use-extensions.ts):loadStatus 观察到云条目 disabled 时补发一次
    /mcp/cloud/connect —— 把「今天 boot 里那次连接尝试」搬到有人看状态的时刻,引擎状态
    如实回归 needs_auth,#733 的授权补救按钮原样点亮(不然会退回 [REQ-130][CODE] alpha-code 改走标准 MCP OAuth —— 删静态 bearer、对齐回调、贯通 needs_auth #733 修掉的
    「一行灰字没有可点的东西」)。守卫只有 in-flight 一道,无 sticky 标记(推演见代码注释)。

实测(机制级,真引擎)

工作树源码起真引擎(bun run src/index.ts serve),owner 真实配置(4 个 office MCP 原样命令 +
真实云 URL https://alpha-cloud.tidelabs.click/mcp),隔离 XDG(凭证库为空 = doomed 态),
交替 3×2,probe = 强制 MCP 全量初始化的 GET /mcp:

变体run1run2run3云终态office
cloud enabled:true(今天)2.291s2.115s2.409sneeds_auth4/4 connected
cloud enabled:false(本修复)0.359s0.300s0.309sdisabled4/4 connected

enabled 臂与 owner 日志众数 ~2.0s 吻合;修复后 MCP 段收敛到 office-only ~0.3s

反向判据(AC3,单元级;两次变异均已跑并还原)

  • 摘掉注入侧 doom 分支(doomedConnect 钉 false)⇒ cloud-mcp-oauth.test.ts4 fail
    (13 pass / 4 fail);还原 ⇒ 17/17。
  • 摘掉 hub kick(删 kickDeferredCloudMcp(next) 调用)⇒ 组件链 3 fail(14 pass / 3 fail),
    wrapper 红;还原 ⇒ 绿。

机制级的反向判据即上表:把 enabled 一位翻回去,2.1–2.4 秒当场回来。

票面 AC 的覆盖与留白(不藏)

  • AC1/AC2 的日志级全量对照(修后真实应用 ≥10 次轮换的阻塞分布)需要打包产物跑真机 ——
    本 PR 交付机制级实测 + 单元/组件闸;打包后 owner 应用每 10 分钟自动积样,挂机 2 小时即
    ≥12 个样本,建议随下一次打包验证收(VERIFY 形态)。
  • AC4:office server 的 timeout 5000 一字未动;office 连接行为(每 boot 连接)不变。
  • 已知残余(方案评论已列):已认证用户的 boot 仍等真实云连接(秒级网络);kill-switch+ext
    在场时 ext 写回 enabled:true,boot 连接照旧 —— 两者均与今天相同,不新增回归。
  • 修后轮换残余 ≈ fork/listen ~0.9s + office ~0.3s;若真机对照后仍可感知,follow-up 是方案
    评论第 ③ 条(idle 推迟换血,#1044 同款接缝,旧 token 续期后有 ~5min 余量)。

本地门

  • typecheck:tsgo -b exit 0
  • unit:bun test src —— base 4438 pass / 0 fail(307 files);本分支 4455 pass / 0 fail
    (308 files)
    ,与 base fail-set 差 = 空
  • docs gate:check-doc-links.py docs/contracts/platform-integration.md ✓ 5 links
  • north-star:全部改动落 packages/ui-mac/ + docs/,UPSTREAM_PATHS 零触碰

🤖 Generated with Claude Code

https://claude.ai/code/session_01QHDS2BFKuzm9uNH1svU2oj

push 用了 --no-verify:本仓 pre-push 钩子 exec 的是全量 alpha-check.sh,而并行 lane 纪律
(CLAUDE.md《本机验证陷阱》)禁止单 lane 跑它(第 [8/9] 步写全 worktree 共享的 core.hooksPath
并建探针树);全量门由主 session 合并前串行跑。本 lane 已单独跑过 typecheck / bun test src /
docs gate / north-star guard,输出见上。

… 收敛到 office-only
owner 日志 27/27 次令牌轮换 boot 的阻塞段全部以 key=cloud status=needs_auth 收尾
(init count=20 紧随 3–7ms)—— 无凭证的云连接是唯一关键路径,而凭证有无在 fork 前的
<engineData>/mcp-auth.json 里已确定。fork 时逐条镜像引擎 getForUrl 判据
(新 cloud-mcp-doomed-connect.ts,读不了文件 fail-open 保持今天行为),doomed 即注入
enabled:false:引擎 MCP.create 零等待直接 disabled,authenticate/connect 照常可用
(getMcpConfig 落到原始 config,不查 enabled)。hub loadStatus 观察到云条目 disabled
补发一次 connect(只有 in-flight 一道守卫,无 sticky 标记 —— 复位依赖"非 disabled 的
中间观察"而轮换与下次观察之间不保证有),状态如实回归 needs_auth,#733 授权按钮原样点亮。
真引擎交替实测(工作树源码 serve,owner 真实 office 配置 + 真实云 URL,隔离 XDG 无凭证,
probe=强制 MCP 全量初始化的 GET /mcp):enabled 臂 2.115/2.291/2.409s(与日志众数 ~2.0s
吻合)、disabled 臂 0.300/0.309/0.359s,两臂 office 均 4/4 connected。
变异复验(副本法,均已还原):摘注入 doom 分支 ⇒ cloud-mcp-oauth.test.ts 4 fail;
摘 hub kick ⇒ 组件链 3 fail、wrapper 红。还原后全绿。
kill-switch WITHHELD 分支逐字节不变(websearch-copies 文本锚随新赋值形状更新,kill-switch
臂仍钉中和条目最前);DEF/SERVER env 通道不动;office timeout 5000 未动(AC4)。
alpha-config-injection.test.ts 把 XDG_DATA_HOME 收进 MANAGED(#1106 起注入多了这个输入,
不钉住就在读宿主机真实凭证库)。已认证态 boot 仍连真实云(与今天相同);日志级前后对照
(AC2 ≥10 次轮换)归打包后 VERIFY。
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QHDS2BFKuzm9uNH1svU2oj
@jinjunnn
jinjunnn merged commit 19fdd84 into alphaAug 25, 2026
5 of 6 checks passed
@jinjunnn
jinjunnn deleted the fix/1106-rotation-stutter branch August 25, 2026 04:11
jinjunnn added a commit that referenced this pull request Aug 25, 2026
`19fdd845a`(PR #1107,`#1106` 修复,2026-08-25T04:11:48Z 合)给
`packages/ui-mac/src/main/cloud-mcp-oauth.test.ts` 加了 126 行 / 7 条用例,
**同一 commit 没有触碰 `scripts/gate-files.tsv`**(实查 `git show 19fdd84 --stat --
scripts/gate-files.tsv` 为空)。登记 10、实际 17。
`.github/workflows/alpha-ci.yml:289` 跑 `bash scripts/assert-gate-files.sh`
⇒ 这条红就是 CI 红的原因(今天 07:55 / 08:49 / 09:51 三次 alpha-ci failure)。
恒红闸门的代价不是少拦一个坏输入,而是它训练每个人忽略这道闸 —— 而
assert-gate-files 恰恰是「判据文件不得被静默删空/悄悄改条数」的唯一机器判据
(`#844`:下界留余量时有用例被删不会红,所以它判的是精确条数)。
用脚本自己的写回口径 `--update`,只改那一行的数字。
不动任何测试、不动任何生产代码 —— 新增的 7 条用例本身合法
(PR #1107 的变异复验点名过「摘注入 doom 分支 ⇒ cloud-mcp-oauth.test.ts 4 fail」)。
修后 `bash scripts/assert-gate-files.sh` exit 0。
同源:`alpha-platform#392` 同一天同一形态(新增判据 → 忘同步登记 → CI 恒红 → 无人察觉)。
Fixes#1124
Claude-Session: https://claude.ai/code/session_01QHDS2BFKuzm9uNH1svU2oj
Co-authored-by: jinjunnn <slmbaovanetti99@gmail.com>
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
Sign up for freeto 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.

[BUG][P1] 每 ~10 分钟卡 1.8–9.7 秒 —— 换令牌重启引擎,而引擎要等所有 MCP 连上才继续

1 participant

@jinjunnn