fix(frontend): round-64 批2——desktop 右键「转发」接上真 Hub mutation + toast.actionUnavailable zh/en 键落地(不再谎称「请重试」) + 消息动作 port 假注释订正 (#2241) - #2249
Merged
Conversation
#2238 登记的写集外尾巴之一:announceUnavailableAction 已经按 UNAVAILABLE_ACTION_TOAST_KEY='toast.actionUnavailable' 查找,但键不在 chatview bundle 里,i18next 把键名 echo 回来 ⇒ 派发器回落到 effect 自带的 failureMessage(如"置顶失败,请重试")。不静默、不假成功,但"请重试"是假的:该端根本没接这个 port,重试永远不会成功。 本次只加键、不改派发器(mappers 禁改,键一落地自动切换): - zh '该操作在当前端未接入' / en 'This action is not wired in this client'(#2238 正文建议值),两边都插在 toast.artifactDownloadFailed 之后=对应相对位置;TransKey 取自 en 块,故 zh/en 同时加且键名逐字一致。 - resources.test.ts 追加 3 个 it:钉死 zh/en 具体文案、不许出现"重试/retry"、键确在 dispatcher 所用的 chatview namespace 下。 - 新增 workbench/src/__tests__/unavailableActionToastI18n.test.ts:用真实 i18next 实例(getFixedT('zh'|'en','chatview'),非 stub)驱动真实 applyTranscriptChromeSideEffects,对 7 个未接线 effect 逐个断言恰好一次 toast == 新键文案,且不是裸键/成功文案/原 failureMessage,并且 softHide/pulse/dispatchComposer 均未发生。 红→绿实测:抽掉键后 workbench 该文件 3 failed、shared resources.test.ts 3 failed|12 passed;键落地后 workbench 6 files/97 passed(基线 92 + 新 5)、shared 15 passed(基线 12 + 新 3)。门禁:deadkeys ok / terminology ok / callsites PASS(current 74 files 597 行 ≤ baseline 78/608)。 Co-authored-by: Cursor <cursor@vectorcontrol.tech>
原文断言 'Optional — Desktop/demo shells omit them and pin/unpin/recall/react stay hidden (#1818)',在 #2238 之后与代码相反: - 判据早已不是"有没有 sessionId",而是 workbenchTranscriptChromeHelpers.contextMenuGroups 的逐 action capabilities(pin/unpin/recall = Boolean(sessionId) && handler 存在;forward = handler && conversations;regenerate = handler); - Desktop 确实设 sessionId(AgentHubWorkbenchHelpers.ts:156-157,activeConversationId doubles as the session id),也确实接了 pin/unpin/recall(#2154)与 forward(本 lane 下一个 commit,#2241);真正"没有 port"的只有 demo shell 与 Hub 未就绪的 shell; - react 条目当前根本不渲染(#1822 把只写的表情子菜单摘了),所以没有 capability 依赖 onAddMessageReaction。 只改注释:类型定义、字段、可选性一字未动。验收:pnpm --filter @agenthub/workbench exec tsc --noEmit 0 error;eslint 该文件仅 4 条 pre-existing no-invalid-void-type(:81/:85,用 42ba064 原始 blob 就地探针复现同样 4 条,与本次改动无关,未顺手修)。 Co-authored-by: Cursor <cursor@vectorcontrol.tech>
#2238 登记的写集外尾巴之三:shared hubClient.forwardMessage(messageId, targetSessionIds) 一直在,desktop 只缺 api 层包装,所以 #2154 把菜单改成按 handler fail-closed 之后,desktop 的"转发"条目直接消失了。 - desktop/src/api/sessionQueries.ts 新增 useHubForwardMessage(形态照抄同文件 pin/unpin/recall 包装:mutateAsync({messageId, targetSessionIds}) → 真实 hubClient.forwardMessage,onSuccess 失效 ['hub','sessions'];web 侧 useWebWorkbenchModel.forwardMessageMut 同一 REST 契约,不分叉)。 - desktop/src/App.tsx 接线 onForwardMessage,剥前缀与取 sessionId 的方式与 pin/unpin/recall 完全一致(messageId.replace(/^hub-message-/, '')),并同样以 chatActions 存在为门(demo / Hub 未就绪时保持 undefined ⇒ 条目继续隐藏,不丢 #2154 不变量)。未改门禁本身:条目因 handler 存在而自动回来。 - 顺手订正 App.tsx 里 #2154 那段注释(原文断言 forward 保持 undefined,接上后同样会变成假话)。 - regenerate 明确不接(死规矩):regenerateAgentTask 在 desktop 的 DesktopHubTaskBridge/agent task 语义下未验证,接了等于把未证语义推给用户;onRegenerate/onAddMessageReaction 的 undefined 断言原样保留。 测试(分层,均未 mock 被测物): - 新增 workbench/src/__tests__/forwardMenuPort.test.tsx:真实 AgentHubWorkbench + desktop 形态 fixture,port 在 ⇒ "转发"条目渲染、点开选择器选 sess-2 确认 ⇒ spy 收到 ('hub-message-m1', ['sess-2']);port 缺 ⇒ 条目与选择器都不渲染。 - desktop App.messageActions.test.tsx 新增正向用例:真实 useHubForwardMessage → 真实 hubClient.forwardMessage('m1', ['sess-2','sess-3'])(只在 client 边界打桩),并在 chatActions 缺失用例里补 onForwardMessage undefined。既有断言 expect(props.onForwardMessage).toBeUndefined() 按规矩登记在 /tmp/lane-b-BLOCKED.md §1(该断言的前提"desktop 没有 forward hook"已被本 commit 证伪)后移除,其余断言未动,测试数 3 → 4。 - App.v4.test.tsx 只加 1 行 sessionQueries mock 夹具(该 mock 是显式导出清单,不补则 App 渲染即 not a function);实测抽掉该行 App.v4 全红、补回 14 passed。断言一字未改。 红→绿实测:注掉 App.tsx 的 onForwardMessage 后 desktop App.messageActions 1 failed|3 passed(onForwardMessage must reach the workbench deps: expected undefined to be type of 'function');还原后 4 passed。workbench 6 files/97 passed。desktop tsc -p tsconfig.app.json 与 -p tsconfig.json 均 0 error。 Co-authored-by: Cursor <cursor@vectorcontrol.tech>
|
Important Review skippedAuto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Team Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
DeliciousBuding
added a commit
that referenced
this pull request
Sep 2, 2026
…ticcheck 拆到与 shard 并行的 go-*-static job(聚合 job 2m52s→23s、1m40s→19s,真实 run 已证),并补 TEST_RESULT/STATIC_RESULT fail-closed 断言修掉「测试 shard 红了 required check 仍可能全绿」的既有漏洞;7 个 required check 名与全部门禁一字未改 (#2251) #2251 切片 1(PR #2257,round-65 lane G + 主机两次追加裁决)。 ## 改了什么 `go-hub` / `go-edge` 里**不消费 shard 覆盖率产物**的静态门禁搬到与测试**并行**的新 job `go-hub-static` / `go-edge-static`(`needs: changes` only,与 `go-*-test` 同时起跑);两个 required check **保留原名**,只留「下载 shard 覆盖率 → 合并 → 覆盖率门」+ 既有两个兜底 step,并新增对 test/static 两条上游 lane 的 fail-closed 结果断言。 - `go-hub-static`:checkout、setup-go、Lint(硬门 #1812)、Hub lint fingerprint ratchet(#1573)+ 自测、sa-cache、gosec、`go vet`、staticcheck。 - `go-edge-static`:同上(Lint 仍 `continue-on-error: true` + `only-new-issues`,#1840 软硬性质未变,由 `verify-ci-gates.py` 与 `quality-debt-baseline.json` 双向钉住)+ orchestrator 依赖方向门(#1566)+ 自测。 - `backend-required` 的 `needs` **未改**(static 失败经 `go-edge`/`go-hub` 传导,注释已写明)。其余 32 job 解析级逐一相等;`concurrency` 块与 `changes` 的 filter 定义一字未动。 ## 顺带修掉一个既有 CI 诚实性漏洞 改前 `go-hub`/`go-edge` 的 job 级 `if: ${{ !cancelled() }}` 让它在 **shard 测试失败时照样运行**,而 job 内从不检查 `needs.go-*-test.result`;`go test -coverprofile` 失败时仍落盘 profile ⇒ Download + Merge + Coverage 三步全过 ⇒ **required check 可能报绿**,`backend-required` 只断言 `go-hub`/`go-edge` ⇒ 跟着绿。即「单元测试 shard 红了,7 个 required check 仍可能全绿」。改后由 `TEST_RESULT` / `STATIC_RESULT` 显式 fail-closed(`!= success` 即 `exit 1`,**skipped 不算通过**),对齐 `windows-go` / `backend-required` 既有约定。诚实边界:近 120 次 run 无 `go-*-test` 失败样本可实证,属结构性推论。 ## 真实 run 证据(本 PR 自己的 run `33685438788`,全矩阵) 新 job 图按设计工作,聚合 job 的串行尾巴已消失: | job | 起→止 | 时长 | 改前同族时长 | |---|---|---|---| | `go-hub-static`(与 shard **并行**) | 21:31:25 → 21:34:12 | **2m47s** | (原本串行挂在测试之后) | | `go-hub-test (2)` | 21:32:41 → 21:37:28 | 4m47s | 4m09s(#2255 run) | | `go-hub`(聚合,只剩覆盖率 3 步 + 2 条断言) | 21:39:24 → 21:39:47 | **23s** | **2m52s**(#2255 run)/ 2m45s(#2249 run) | | `go-edge-static` | 21:31:25 → 21:33:01 | 1m36s | — | | `go-edge`(聚合) | 21:34:18 → 21:34:37 | **19s** | **1m40s** | | `backend-required` | 21:39:51 → 21:39:56 | 5s | 4s | ⇒ 静态门禁(2m47s)已**不在关键路径上**(被 4m47s 的 shard 覆盖),聚合 job 从 2m52s 降到 23s,与 lane G 用 step 级计时推演的 ~20s 一致。⚠️ **本 run 的总墙钟不能当稳态收益读数**:改 `checks.yml` 命中 `changes` 的全部 filter ⇒ 跑全矩阵;且实测 `go-hub-test (1)` 直到 21:36:27 才起跑(比同批晚 ~5min),是新增 2 job 后的 runner 排队(lane G 已预告峰值并发 ~18 可能触档)。**稳态收益必须由合并后第一个 Go-only PR 的真实 run 回填 #2251 验收表**(改前基线:Go-only 8m36s,推演改后 ≈6m03s)。 ## 写集(7 文件) ``` .github/workflows/checks.yml | 317 ++++++++----- ← 主体 docs/architecture/github-actions-ci-cd-policy.md | 10 +- ← job 图 SSOT scripts/verify/verify-ci-gates.py | 65 +++-- ← 被迫(按 job 名定位 step) scripts/verify/tests/verify-ci-gates.Tests.py | 113 ++++-- ← 被迫 scripts/verify/quality-debt-baseline.json | 4 +- ← 被迫(soft gate 以 "go-edge: Lint" 为键) docs/governance/verifier-map.md | 10 +- ← 主机追加(4 行 job ID 过期) AGENTS.md | 2 +- ← 主机追加(L0 分层行;仍 284 行 / 预算 300) ``` 被迫扩展的 3 个文件属**改宿主、不减断言**:`verify-ci-gates.py` **新增 6 条拆分契约断言**(含「`go-*-static` 必须不含 `download-artifact`」防止把覆盖率门也搬走、「聚合 job 必须绑定并断言两条 lane 结果」),自测 35 → 39 用例;`quality-debt-baseline.json` 只把 soft gate 的 `location` 从 `go-edge: Lint` 改为 `go-edge-static: Lint`,`issue`/`owner`/`introduced_at`/`review_by` 语义一字未改。不改这 3 个则 required check `validate` 必红、PR 不可合(lane 报告 §2.7 有实测红输出)。 `verifier-map.md` 的 `:81`(`merge-coverprofiles.py → go-edge / go-hub`)**仍正确、一字未改**——合并步骤本来就留在聚合 job。 ## 门禁(主机在 rebase 到 `c226baab` 之后的树上实跑) ``` actionlint -no-color .github/workflows/checks.yml → EXIT=0;findings 多重集与 pristine master 完全一致(11 条:6×SC2034 / 2×SC2069 / 3×SC2086)⇒ 零新增 python3 yaml.safe_load → 36 jobs;7 个 required check 名 missing=[];go-* needs 图核对 verify-ci-gates.py → ci gate policy ok verify-ci-gates.Tests.py → Ran 39 tests OK verify-doc-ssot.py → doc SSOT ok(AGENTS 96 paths) verify-commit-messages.sh origin/master → ok (3 commits) git diff --check → clean ``` ## 未验证 / 未做 1. **稳态墙钟收益未经 Go-only run 实测**(本 PR 是全矩阵);#2251 验收线「Go-only ≤6m00s」待下一个 Go-only PR 回填。推演落点 ≈6m03s,**卡在验收线之上 ~3s** ⇒ 要稳过线需做**切片 2**(shard 重平衡:`go-hub-test` 291s vs 163s,`checks.yml` 注释自称 round-robin「balanced and disjoint」已被实测推翻——disjoint 成立、balanced 不成立)。本 PR 刻意不做切片 2(需可复核的成本表,不接受拍脑袋分片)。 2. 切片 3(frontend `@agenthub/workbench` coverage 7m31s 长杆)未做,#2251 要求先出耗时构成实测。 3. org 的 Actions 并发档未查询(Free=20 是文档口径推断);本 run 观察到的 ~5min shard 起跑延迟与此一致。 4. actionlint 的 11 条 baseline 告警未修:`go test $SHARD_PKGS` 的 SC2086 **不能**加引号(靠 word splitting 展开包列表,加引号=改语义=可能破坏 shard 门),其余 8 条在 `frontend-mobile`/`real-e2e-stack`/`vuln-scan-js`,与本切片无关。
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
这是什么
round-64 wave 批 2(tracker #2241),lane B。批 1(edge 审批门属主化 + hub health 兜底诚实化)已在 #2242 合入 master
4a7af8c6;本分支已 rebase 到该 master,rebase 无冲突(批 1 只碰 Go 与api/openapi.yaml,本 PR 只碰app/**)。3 个 commit,均带
(#2241):fix(i18n)— 补toast.actionUnavailable的 zh/en 键。workbenchTranscriptChromeActionMappers.ts:545早已导出UNAVAILABLE_ACTION_TOAST_KEY = 'toast.actionUnavailable'并在 7 个调用点(:625/:660/:693/:709/:725/:741/:757)使用,但 chatview bundle 里没有这个键 ⇒ i18next 回落判据resolved !== KEY不成立,announceUnavailableAction落到effect.failureMessage,用户看到的是「…失败,请重试」——一句对「这个端根本没接线」的错误指导。docs(workbench)— 订正AgentHubWorkbenchTypes.ts:165-171的假注释。原文称 "Desktop/demo shells omit them and pin/unpin/recall/react stay hidden ([P1] 假内容与假交互清理:任务页/上下文菜单/设置项/demo 身份 #1818)",与workbenchTranscriptChromeHelpers.ts:515-531的逐 action capabilities、以及 Desktop 确实设activeConversationId并接线 pin/unpin/recall([整理] 静态审计 backlog 跟踪(探索 lane 剩余项) #2154)的事实矛盾。feat(desktop)— 接上 Hub 转发 mutation:新增desktop/src/api/sessionQueries.ts的useHubForwardMessage,在App.tsx接线onForwardMessage,desktop 右键「转发」条目重新渲染并真派发(此前 fix(frontend): desktop 消息右键菜单死条目收口——pin/unpin/recall 接上已有 mutation、forward/regenerate 按 handler fail-closed、派发器 7 处静默 break 改为一次可感知反馈 (#2154) #2238 按 fail-closed 把它关掉了,因为缺 port;现在 port 补上了)。regenerate明确不接线:regenerateAgentTask在 Desktop 的DesktopHubTaskBridge/ agent task 语义下未经验证,接了等于把未证语义推给用户 ⇒ 保持 fail-closed,onRegenerate/onAddMessageReaction的 undefined 断言原样保留。证据(本机实测)
红→绿双向:
unavailableActionToastI18n.test.tsexpected 'toast.actionUnavailable' to be undefined(i18next 把键 echo 回来)3 failed;sharedresources.test.tsexpected undefined to be '该操作在当前端未接入'3 failed | 12 passed。绿:shared 15 passed(基线 12 + 新 3)、workbench 97 passed(基线 92 + 新 5)。App.tsx的onForwardMessage整块注掉):onForwardMessage must reach the workbench deps: expected undefined to be type of 'function',1 failed | 3 passed。绿:desktop messageActions + App.v4 共 18 passed。App.v4.test.tsx那 1 行vi.mock导出 ⇒ 12+ 用例全红;补回 ⇒ 14 passed(该文件任何断言一字未改)。主机侧独立复跑(rebase 到
4a7af8c6之后):lane B 自跑门禁(HEAD
7c3a92c5,rebase 前):两处需要 reviewer 知情的取舍
App.messageActions.test.tsx的expect(props.onForwardMessage).toBeUndefined()。它的前提写在它自己的注释里——"forward needs auseHubForwardMessageport",即「desktop 没有这个 mutation 所以只能是 undefined」;本 PR 的交付物正是补上该 hook 并接线,接线后该断言与事实相反。处理:只删这一条,同 test 内onRegenerate/onAddMessageReaction两条 fail-closed 断言原样保留;另在「chatActions 缺失」那个 test 里新增expect(props.onForwardMessage).toBeUndefined(),保住 [整理] 静态审计 backlog 跟踪(探索 lane 剩余项) #2154 的 fail-closed 不变量(demo / Hub 未就绪时条目仍不渲染)。测试数只增不减(3 → 4)。02a1dee0(原5cd150e1)的注释里已写 "plus forward ([整理] round-64 wave:edge 审批门零属主(安全 P1) + desktop 菜单尾巴(前端/i18n) + health/version 诚实化(可观测性) #2241)",而 forward 由紧随其后的 commit 才落地 ⇒ 该中间 SHA 上注释超前一句;分支 tip 与 squash 后的结果完全为真。squash merge 会消掉这个中间态。未验证(如实)
pnpm -r build未跑、web/mobile 包测试未跑(4 核机 + 本轮纪律)⇒ websrc/App.test.tsx的 10 passed 基线未本地复跑。本 PR 不含 web 文件,但resources.ts是 web 也吃的 bundle ⇒ 由 CI 的frontend-web/frontend-required判。AgentHubWorkbench/ 真实 i18next bundle / 真实hubClient.forwardMessage方法调用,仅在 client 边界打桩),不是 packaged 端到端;按 AGENTS.md §10 标注real_tested=false(无真 Hub 往返)。['hub','sessions'],与 pin/unpin/recall 及 web 侧同契约)。app/node_modules,按 fix(frontend): desktop 消息右键菜单死条目收口——pin/unpin/recall 接上已有 mutation、forward/regenerate 按 handler fail-closed、派发器 7 处静默 break 改为一次可感知反馈 (#2154) #2238 同款做法软链到主 checkout、包级@agenthub/*重建为指向本 worktree(readlink -f已验证跑的是本分支代码),未跑pnpm install。