Skip to content

X 号缺发图权限记成权限不够只叫人重连,别的 403 只败这一条,GIF 等处理完,改稿被拒会报错 - #128

Merged
joesmart merged 3 commits into
mainfrom
joesmart/fix-x-token-scope
Oct 25, 2026
Merged

joesmart merged 3 commits into
mainfrom
joesmart/fix-x-token-scope

Conversation

@joesmart

@joesmart joesmart commented Oct 25, 2026 •

Copy link
Copy Markdown
Contributor

为什么

#118 让接口授权的 X 草稿能带图,传图要 media.write。之前连上的 X 号授权里没有它,X 回 403,代码把所有 403 都记成登录过期:账号整个变「已过期」,连发字都停了。产品定了:权限不够单独一个状态,只叫人重连。

改了什么

  • 权限不够单独记:shared 的 Account 加 missingScope: AccountScope | null(字面量联合,现在只有 media.write),失败原因加 missing_scope、forbidden、media_failed。login 仍只管令牌死没死,expired 只留给 401 且换不到新令牌。迁移 0052 只加 accounts.missing_scope 一列,不回填。
  • 403 分类是纯函数:control-plane/src/publish/forbidden.ts 的 classifyForbidden 看这一条要不要额外范围、授权时存下的 scope、X 的回包。缺范围 → 账号记 missing_scope、登录照旧有效,这一条记权限不够;别的 403(内容重复、GitHub 无权限)→ 账号不动,只这一条失败,原因写明是平台拒了这一条。
  • 发之前就挡:授权时存下的 scope 已看出缺 media.write 的,带图的稿子认领时就记权限不够,一条请求都不打;不带图的照发。授权回调和刷新令牌都按平台回的 scope 重算 missing_scope,重连给全了就清掉。账号状态变化照旧按凭据代际比,被拒之后已重连的不改。
  • GIF 等处理完:/2/media/upload 回包带 processing_info 的,按 check_after_secs 查 STATUS,到 succeeded 才挂到帖子上;failed 或等满 5 分钟记 media_failed,不发帖。等待由注入的 sleep 做,测试不真等。
  • 改稿被拒不再无声:edit_draft 改走中枢 POST /hub/v1/drafts/:id/edit,当场拿到结果。正在发或已发出、改了类型、配图不合规则、找不到的,控制面回中文原因,运行器抛「草稿没改:…」,模型拿到 isError 工具结果。旧运行器的 draft_edit 上行照收。
  • Web:账号页和草稿卡写「X 账号缺发图权限,重新连接一次就好」,带「重新连接」按钮,走接入时的同一个 OAuth 入口。重连之后卡上只留原因、按钮收起。新的三种失败原因都有中文文案。
  • 两份 README 写了新规则。

怎么验的

先红:新测试在 main 上都红(控制面撤掉实现 7 条失败,forbidden.test.ts 缺模块;运行器撤掉 src 2 条失败;Web 撤掉 UI 2 条失败,找不到 scope-reconnect-text)。

pnpm format:check && pnpm typecheck && pnpm lint      # 通过;lint 只有改动外的 3 条既有 warning
pnpm --filter @baize/shared test                      # 13 files, 283 passed
pnpm --filter @baize/bot-runner test                  # 21 files, 1711 passed | 15 skipped
pnpm --filter @baize/computer-agent test              # 15 files, 209 passed | 1 skipped
.lane/pg-serial.sh pnpm --filter @baize/control-plane test   # 129 passed | 1 skipped (130); 1633 passed | 1 skipped
.lane/pg-serial.sh pnpm --filter @baize/e2e test      # 27 files, 55 passed
pnpm --filter @baize/web test                         # vitest 51 files 366 passed;Playwright 540 passed

另用 Playwright 对 mock 点过账号页和草稿卡,390 宽不横向滚动。全程不打真 X 接口。

复核后补的几处

  • 刷新回包不带 scope 不抹掉已知缺权限:令牌端点没回 scope 时存成空串,原来 saveGrant 拿空串重算,把授权时记下的 missing_scope 清成 null,凭据的 scope 也被覆盖成空串,之后真缺 media.write 的 403 会被说成「内容重复」。现在 scope 为空串时,凭据上已存的 scope 和账号的 missing_scope 都不动,SavedGrant 带回落库后算数的 scope,刷新拿到的令牌用它做发前预检。
  • 403 分清出在哪一步:PlatformForbidden 带 step(upload 传图,post 发帖),X 的传图循环里碰到的 403 改标成 upload。classifyForbidden 仍是纯函数,多一条:传图那一步回不点名的 403,而 scope 不知道(account-add 挂的号恒为空串),按缺 media.write 处理,叫人重连。内容重复只会出在发帖那一步,发帖那一步不点名的 403 照旧记 forbidden。
  • 中枢改稿只认这个 Bot 自己起的:editDraft 的条件补上 drafts.bot_id,同群别的 Bot 起的草稿回 404,和 README 说的一致。旧上行 draft_edit 走同一个函数,同样只改自己的。
  • 通知按平台写缘故:forbidden 的通知 GitHub 写「GitHub 拒绝了这一条,账号授权还有效,多半是仓库权限、组织的 SSO 或限流」,X 保留原文案。
  • 发布循环默认的等待定时器 unref,关进程时不为等动图多挂一分钟。

新用例:

  • control-plane oauth.test.ts「X 刷新令牌的回包不带 scope:已知缺的发图权限还记着,存下的 scope 不变」
  • control-plane publish.test.ts「不知道给过哪些权限的 X 号,传图那一步回不点名的 403:账号记缺发图权限、登录照旧有效,这条记权限不够、叫人重连」
  • control-plane publish.test.ts「不知道给过哪些权限的 X 号,图传上去了、发帖那一步回不点名的 403:只这一条记平台拒了,账号不动」
  • control-plane publish.test.ts「多 Bot 群里另一个 Bot 经中枢改别人起的草稿:回 404,草稿不动」
  • publish.test.ts「X 别的 403 和 GitHub 的 403 都不动账号…」补断言 GitHub 的通知文案
  • forbidden.test.ts 表驱动每行带上 step,新增 5 行:scope 不知道传图回通用 403、回空 403,scope 缺发图权限传图回通用 403,都算缺;scope 不知道发帖回通用 403、scope 有发图权限传图回通用 403,都算平台拒了

先红(在 e85d2ad 的实现上跑新用例):6 条失败,其中「发帖那一步回不点名的 403」那条本来就绿,是守着不退化的。

复核后的门禁(head f2ea3cf):

pnpm format:check && pnpm typecheck && pnpm lint                     # 通过;lint 只有改动外的既有 warning
pnpm --filter @baize/shared test                                      # 13 files, 283 passed
pnpm --filter @baize/bot-runner test                                  # 21 files, 1711 passed | 15 skipped
pg-serial.sh pnpm --filter @baize/control-plane test                  # 129 passed | 1 skipped (130); 1642 passed | 1 skipped
pg-serial.sh pnpm --filter @baize/e2e test                            # 27 files, 55 passed

这一轮没动 web 和 shared,web 测试没重跑。

Closes #38

🤖 Generated with Claude Code

https://claude.ai/code/session_01Be3SZps2JjqvyrJ1vbLmni

@joesmart
joesmart force-pushed the joesmart/fix-x-token-scope branch from f2ea3cf to 81e2255 Compare October 25, 2026 13:49
@joesmart
joesmart merged commit 7e5d802 into main Oct 25, 2026
1 check failed
@joesmart
joesmart deleted the joesmart/fix-x-token-scope branch October 25, 2026 13:50
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.

走接口授权(GitHub、X)的草稿不能带图

1 participant