Skip to content

refactor(frontend): 消融 #1546 projects port 死面(净 −880 行/31 文件)——portProjectsEnabled = Boolean(port) && !projects 在两个 shell 的所有可达状态恒为 false(shell 只在 hubReady 注入 port,而此时 projects 必为数组),故端口取数/游标分页/load-more 重试/端口建改与 ProjectNav sentinel UI 全部结构性不可达;按 S2 要求另开 #2290 登记 live 路径分页缺口 - #2291

Merged
DeliciousBuding merged 1 commit into
masterfrom
refactor/projects-port-ablation
Sep 3, 2026

Conversation

@DeliciousBuding

Copy link
Copy Markdown
Collaborator

做了什么

端到端删掉 #1546WorkbenchProjectsPort 死面:31 files changed, 58 insertions(+), 938 deletions(-)(净 −880 行)。这是 #2274 里 C-3 / S2 记的「本 issue 行数最大的一块死结构」,删前已在真实树上重做可达性核实(issue 是索引不是事实源)。

删除清单:

删掉的东西
契约 app/workbench/src/workbenchProjectsPort.ts(整文件)、index.tsWorkbenchProjectsPage/WorkbenchProjectsPort 导出
平台适配器 app/web/src/platform/webWorkbenchProjectsPort.ts + 其测试、app/desktop/src/platform/desktopWorkbenchProjectsPort.ts + 其测试、两个 App.tsx 的 import/useMemo/prop(含 web 侧因此变成未使用的 tCommon
hook useWorkbenchProjectsRoute.ts 298 → 154 行:端口内部取数状态、游标/hasMore/loadingMore/loadMoreError 及其 refs、loadProjectsloadMore、端口版 create/update、unmount 守卫
prop 管道 AgentHubWorkbenchTypesworkbenchFrameTypesWorkbenchFrameworkbenchFramePartsHelpersAgentHubWorkbenchHelpersworkbenchRoutesTypesWorkbenchRoutes(8 处)
UI ProjectNav 的 IntersectionObserver sentinel + loadingMore 通知 + loadMoreError/重试按钮、ProjectsPagepages/projects/types.ts 的 4 个分页 props、workbenchRoutesHelpers 的分页映射、ProjectsPage.module.css.sentinel 规则
i18n projects.loadMoreErrorprojects.retryLoadMore(zh + en,只被上面那块死 UI 用;projects.loading 保留,live 的加载态在用)
死导出 hubDataMapping.tsresolveHubProjectsDefault(0 个真实消费者,只有它自己的测试)+ 该测试块

可达性证明(为什么这是死面而不是「还没接上的功能」)

关键一行在 useWorkbenchProjectsRoute.ts

const portProjectsEnabled = Boolean(projectsPort) && !projects;

两个 shell 的注入方式(改前原文):

app/web/src/App.tsx:302       projectsPort={hubReady ? webProjectsPort : undefined}
app/web/src/App.tsx:291       projects={workbench.projects}          // = resolveWebWorkbenchProjects(...)
app/desktop/src/App.tsx:749   projectsPort={hubReady ? desktopProjectsPort : undefined}
app/desktop/src/App.tsx:772   projects={workbench.projects}          // = resolveHubProjects(...)

resolveWebWorkbenchProjects / resolveHubProjects 的返回值:hubReady=true 时恒为数组(projects ?? []).map(...),空数组也是 truthy);hubReady=false 时是 undefined(mock/fixture 模式)或 []。同时两个 model 都是 projectsActions = hubReady ? {create, update} : undefined

hubReady projectsPort projects portProjectsEnabled port.listProjects port.createProject/updateProject
true port 数组(truthy) false 永不(effect 以 portProjectsEnabled 为门) 永不(if (onProjectCreate) return onProjectCreate(draft),hubReady 时回调必存在)
false undefined undefined / [] false 永不(无 port) 永不(if (!projectsPort) return

⇒ 端口分支在两个 shell 的所有可达状态下都不执行。下游同理:loadMoreundefinedhasMorefalseloadingMorefalseloadMoreErrorundefined,所以 ProjectNav 的 sentinel(if (!sentinel || !hasMore) return)与重试按钮也永不渲染。

两个 shell 的注释自己就承认了这件事(改前原文):"Injected only in real mode — parent-managed projects keep the port dormant while demo mode falls back to mock fixtures."

逐条行为等价审计(删掉的每个分支在可达状态下的常量值)

删除项 改前在所有可达状态下的值 改后
sourceProjects projects ?? (false ? portProjects : (realDataMode ? [] : MOCK)) projects ?? (realDataMode ? [] : MOCK) — 同值
effectiveProjectsStatus projectsStatus ?? (false ? portProjectsStatus : undefined) projectsStatus — 同值
canMutateProject Boolean(onProjectCreate ?? onProjectUpdate ?? projectsPort);hubReady 时前两者必有、demo 时三者皆无 Boolean(onProjectCreate ?? onProjectUpdate) — 同值
handleProjectCreate/Update 有回调走回调;无回调时 port 也必为 undefined ⇒ no-op 无回调 ⇒ no-op — 同值
loadMore / hasMore / loadingMore / loadMoreError undefined / false / false / undefined 字段删除,消费方(分页 UI)一并删除 — 无可观察差异

证据(主机实跑)

$ pnpm -r typecheck                                       rc=0(5 包全绿)
$ pnpm exec vitest run                      # workbench   rc=0  Test Files 169 passed / Tests 1714 passed(473.31s)
$ pnpm exec vitest run                      # shared      rc=0  150 / 2746(与 master 相同:删的 2 个 i18n 键没有测试断言)
$ vitest run --config vitest.desktop-ci.config.ts         rc=0  48 / 430
$ pnpm exec vitest run                      # web         rc=0  32 / 265
$ pnpm exec eslint src --max-warnings 0     # web         rc=0(删 port 后 `tCommon` 变未使用,已一并删;这是 web 的真门禁)
$ pnpm exec eslint src                      # desktop     10 problems(6 err) → 9 problems(5 err):改好没改坏(该 job 在 CI 里是 advisory,理由写在 YAML)
$ python3 scripts/verify/verify-i18n-deadkeys.py          rc=0(bundles 2 / dynamic prefixes 6)
$ python3 scripts/verify/verify-i18n-callsites.py         rc=0(74 files / 610 CJK lines ≤ baseline)
$ python3 scripts/verify/verify-i18n-terminology.py       rc=0
$ bash /tmp/run-validate.sh <worktree>                    PASS=61 FAIL=0 SKIP(merge-ref)=1
$ git diff --check origin/master...HEAD                   rc=0

用例数账(诚实记):净 −19 例,全部只断言被删代码——workbench 1722→1714(端口驱动 describe 的 11 例:8 例随代码删除,3 例改写成父级驱动版本保留,另新增 1 例「mutation affordance 只来自父级回调」);desktop 435→430(适配器测试整文件 5 例);web 271→265(适配器测试整文件 6 例)。workbenchRoutesHelpers.test.ts 里 2 处 props.hasMore/onLoadMore 断言随字段删除而去掉(用例本身保留)。contacts/tasks 的分页测试未触碰(那是活面)。

关联

Negative constraints(刻意没做)

…rtProjectsEnabled = Boolean(port) && !projects 在 hubReady 的两种取值下恒为 false(shell 只在 hubReady 时注入 port,而此时 projects 必为数组),于是端口内部取数/游标分页/load-more 重试/端口建改与 ProjectNav 的 sentinel UI 全部结构性不可达;删端口契约 + 两个平台适配器及其测试 + hook 的 144 行端口分支 + 8 处 prop 管道 + 分页 UI + 2 个只被死 UI 用的 i18n 键 + 死 CSS 类 + 0 消费者的 resolveHubProjectsDefault(31 文件净 −879 行,可达行为逐条对照未变)

Co-authored-by: Cursor <cursor@vectorcontrol.tech>
@coderabbitai

coderabbitai Bot commented Sep 3, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Team

Run ID: 7961da5a-f80c-4d4d-a638-4d2c7389a70f

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@DeliciousBuding
DeliciousBuding enabled auto-merge (squash) September 3, 2026 13:54
@DeliciousBuding
DeliciousBuding merged commit 98f2c9f into master Sep 3, 2026
43 checks passed
@DeliciousBuding
DeliciousBuding deleted the refactor/projects-port-ablation branch September 3, 2026 14:02
DeliciousBuding added a commit that referenced this pull request Sep 4, 2026
…ale coverage exclude(语义裁决见 ADR-034)

round-74 普查(lane-artifacts/round-74/b6-vocabulary-survey.md,526 行)+ 主机独立
复核确认的事实:Hub 的 workspace/project **没有 status 事实**(model/service/
handler/openapi/migration/live DB 六处逐字一致,live 表仅 6 列),而 UI 的
status filter 100% 前端内存过滤、三个同名 mapper 产 5 个与 Hub 交集为 ∅ 的词。
因此「让筛选对真实 Hub 数据成立」在没有 L3 事实源之前不可达——语义部分交
operator 裁决(ADR-034,DEFERRED 带触发条件),本批只做不需要裁决的四件事:

1. 删 app/workbench/src/hubDataMapping.ts 的 workspaceProjectToProjectInfo:
   它把每个 Hub 项目硬编码成 status:'Active'(Hub 侧不存在的词)。#2291 删掉它
   唯一调用者后成为 0 非测试消费者孤儿;desktop 只 import 编排函数
   (resolveHubProjects 等)并传自己的本地 mapper,web 用自己的副本——主机已逐
   import 复核。连带删除仅被它使用的 formatProjectDate。
2. 修 hubDataMapping.test.ts 的错误注释:它宣称「Desktop 用 resolveHubProjects +
   workspaceProjectToProjectInfo」,正是这句错注释让孤儿活了下来;resolveHubProjects
   是纯编排器,测试改用 stub mapper(−4 例)。
3. openapi 枚举对齐 0074 的真实取值域:team run status 补 pending_review(×2)、
   assignment type 补 compete(×3),与 model 常量及 0074 CHECK 逐字一致。漂移根因
   登记进 ADR-034:现有 3 个 verifier 只比路由形状与「2xx 有没有 schema」,不比字段
   集/enum(openapi-schema-baseline.json 逐字 [])。
4. 清 app/workbench/vitest.config.ts coverage 对 src/workbenchProjectsPort.ts 的
   stale exclude——该文件已被 #2291 删除。

验收:workbench typecheck 绿 + 25/25;三包全量 workbench 1712 / web 270 /
desktop 4975 全绿;本地复跑 checks.yml validate job 62 条命令 PASS=62 FAIL=0。

Refs #2274 (B-6)

Co-authored-by: Cursor <cursor@vectorcontrol.tech>
DeliciousBuding added a commit that referenced this pull request Sep 4, 2026
…ale coverage exclude(语义裁决见 ADR-034) (#2316)

round-74 普查(lane-artifacts/round-74/b6-vocabulary-survey.md,526 行)+ 主机独立
复核确认的事实:Hub 的 workspace/project **没有 status 事实**(model/service/
handler/openapi/migration/live DB 六处逐字一致,live 表仅 6 列),而 UI 的
status filter 100% 前端内存过滤、三个同名 mapper 产 5 个与 Hub 交集为 ∅ 的词。
因此「让筛选对真实 Hub 数据成立」在没有 L3 事实源之前不可达——语义部分交
operator 裁决(ADR-034,DEFERRED 带触发条件),本批只做不需要裁决的四件事:

1. 删 app/workbench/src/hubDataMapping.ts 的 workspaceProjectToProjectInfo:
   它把每个 Hub 项目硬编码成 status:'Active'(Hub 侧不存在的词)。#2291 删掉它
   唯一调用者后成为 0 非测试消费者孤儿;desktop 只 import 编排函数
   (resolveHubProjects 等)并传自己的本地 mapper,web 用自己的副本——主机已逐
   import 复核。连带删除仅被它使用的 formatProjectDate。
2. 修 hubDataMapping.test.ts 的错误注释:它宣称「Desktop 用 resolveHubProjects +
   workspaceProjectToProjectInfo」,正是这句错注释让孤儿活了下来;resolveHubProjects
   是纯编排器,测试改用 stub mapper(−4 例)。
3. openapi 枚举对齐 0074 的真实取值域:team run status 补 pending_review(×2)、
   assignment type 补 compete(×3),与 model 常量及 0074 CHECK 逐字一致。漂移根因
   登记进 ADR-034:现有 3 个 verifier 只比路由形状与「2xx 有没有 schema」,不比字段
   集/enum(openapi-schema-baseline.json 逐字 [])。
4. 清 app/workbench/vitest.config.ts coverage 对 src/workbenchProjectsPort.ts 的
   stale exclude——该文件已被 #2291 删除。

验收:workbench typecheck 绿 + 25/25;三包全量 workbench 1712 / web 270 /
desktop 4975 全绿;本地复跑 checks.yml validate job 62 条命令 PASS=62 FAIL=0。

Refs #2274 (B-6)

Co-authored-by: DeliciousBuding <DeliciousBuding@users.noreply.github.com>
Co-authored-by: Cursor <cursor@vectorcontrol.tech>
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.

1 participant