Skip to content

refactor(app): unify capability settings with explicit device and Goal scope - #5187

Merged
huangruiteng merged 4 commits into
mainfrom
codex/capability-settings-scope
Sep 27, 2026
Merged

huangruiteng merged 4 commits into
mainfrom
codex/capability-settings-scope

Conversation

@huangruiteng

@huangruiteng huangruiteng commented Sep 27, 2026 •

Copy link
Copy Markdown
Collaborator

Problem and result

Settings exposed “Capability Center” and “Goal capabilities” as competing destinations, leaving users to infer whether a change affects device defaults or one Goal. One Capability Center now selects that target explicitly. Goal settings links preserve their Goal; global entry never silently chooses one.

The detail distinguishes configuration ownership scopes from effective configuration source, using the existing catalog; editor permissions remain separate. Machine-only capabilities stay out of the Goal catalog. Goal-specific values can return to device defaults through the existing preview/apply flow. Changing scope or Goal discards the old draft and preview and fetches the selected target.

Implementation and scope

  • Reuse the existing TypeScript editors, revision-checked APIs, readback, errors and rollback. No new configuration authority or live configuration migration.
  • Document the per-capability scope decisions for all 16 built-ins in the desktop RFC; test that declarations and unsupported-scope rejection preserve these boundaries. Read-only Goal bindings still show Goal ownership.
  • Keep steward settings first-class; remove redundant scope badges and update English/Chinese navigation guidance.
  • Future-facing simplification: one rendered navigation destination, preserving existing entry aliases; shared detail header derives ownership from supported_scopes; canEditCapability continues to own editor availability.
  • This is an S5 settings-usability improvement, not completion of the broader G1/R3 collaboration journey. CLI and Lark contracts are unchanged because this change only composes existing App configuration surfaces.

Validation

  • Dashboard TypeScript/build and packaged chat frontend passed.
  • Capability-scope browser scenario passed against development and packaged builds: explicit target, fresh reads, isolated drafts/previews, no writes during navigation, Goal-entry preservation, desktop and 390px mobile layout.
  • Existing typed-actions browser passed: preview, apply, readback, restore/rollback and errors. Cadence and steward-model settings scenarios passed.
  • Configuration API/catalog suites: 57 passed, including disposable real configuration backend coverage. Workspace contract test and public-boundary/diff checks passed.
  • Visually inspected desktop/mobile viewport: scope and Goal identity precede the catalog; configuration details retain effective source.

Full premerge suite has not been run. CI and maintainer merge remain pending; the running installation has not been updated.

Signed-off-by: huangruiteng <14976749+huangruiteng@users.noreply.github.com>
Signed-off-by: huangruiteng <14976749+huangruiteng@users.noreply.github.com>

@huangruiteng huangruiteng left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approval conclusion (author-owned PR; GitHub blocks formal self-approval)

Reviewed exact head: 4a8f372
Baseline: d23f1c8

动机

这包解决能力设置入口拆成两处、编辑 owner 依赖“从哪进入”的真实用户路径。配置的生效值、支持范围和这次要改的目标是三件不同的事;只写“全局/Goal”而不在当前页显式选择,重复操作时容易混淆设备默认与一个 Goal override。

我以 desktop-execution-frontends 的既有配置 owner 与本次 scope matrix、design.md 的整屏注意力规则,以及实际 general/Goal settings callers 判断。目标是一段完整的配置 UX 改进,不是换导航后就宣称 desktop roadmap、host timer 或新 authority 已完成。

改动思路

保留原有 MachineConfigurationSettings、GoalCapabilitySettings 和统一 workbench,只把导航合成能力中心。在 catalog 前用原生 radio 表达“此设备默认 / 单个 Goal”,用 select 表达明确目标。general 入口不默选 Goal;Goal 入口继续保留 initialGoalId。机器默认仍可能被多个 Goal 继承,但选择 scope 本身不启用能力,也不提交配置。

持久配置继续由既有 typed owner 和 revision-locked preview/apply/readback 负责。Goal key 随目标变化,切换 scope 也会卸载旧 editor,退休本地草稿/preview;notification 使用同一目标 id。共享 header 从 configuration_editor.supported_scopes 推导 owner,不再拿“能否编辑”替代“支持何种 ownership”。provider、steward 和 cadence 的不同决策边界保留。

具体改动

17 个文件 +283/-49:六个现有生产 UI 文件 +90/-36,测试/原生 browser 场景 +127/-7,五份公开设计/用法文档 +66/-6。没有新增后端、API、CLI 参数、持久字段或 capability。scope matrix 覆盖 16 个 built-in editors,明示 machine-only、machine+Goal 和 Goal-only/read-only 等组合;测试分别校验 supported/writable scopes 和 unsupported scope 拒绝。

关键代码讲解

  • apps/presentation/dashboard/src/features/personal-workspace/workspace-settings-page.tsx:53,WorkspaceSettingsPage initialization:旧 machine tab 归到能力中心;旧 capabilities Goal-entry 保留 Goal intent,初始 Goal id 来自现有 caller,没有从第一条 Goal 推断用户授权。
  • apps/presentation/dashboard/src/features/personal-workspace/workspace-settings-page.tsx:174,target header:radio/select 与范围说明先于 catalog,全部使用现有 goals projection 和中英文文案;选择只改变本地 intent,不发 apply。
  • apps/presentation/dashboard/src/features/personal-workspace/workspace-settings-page.tsx:213,GoalCapabilitySettings keyed mount:key、goalId 与 notification 都对应 capabilityGoalId。换 Goal 或转设备范围时旧 editor 退休,不能把旧 preview 当新目标的确认。
  • apps/presentation/dashboard/src/features/personal-workspace/capability-workbench.tsx:125,CapabilityDetailHeader:scope badge 取 supported_scopes,权限仍由 canEditCapability 和后端决定。只读 Goal binding 的“不能编辑”不等于“机器+Goal 都拥有”。

正向路径是进入 general/Goal 设置 → 明确目标 → 读 current/effective source/revision → preview → 显式 apply/readback。现有 typed-actions packaged 场景和独立 backend suite 继续覆盖这条操作链;我另用同一 public-entry harness 在 base/head 捕获中英文 periodic_report preview,Goal、capability、配置字段完全相同,navigation apply_count 都为 0。

负向路径从 product-release 已 preview 开始:延迟 research-monitor GET,立即切回 product-release,再放行旧响应;新版当前 preview 仍绑定 product-release,旧草稿不会复活。设备/Goal 切换和键盘 Space 返回会要求新 preview;空 Goal 没有 writable detail,随后明确选择第三个已有 Goal 可以继续正确 preview。read-only Goal binding、machine-only capability 和不支持 scope 的拒绝也有对应证据。

对主干的风险

主要风险是统一入口后目标不一致、旧 async 结果/preview 混入新 Goal、scope label 暗示额外写权限,以及窄屏增加控件造成拥挤。新 key/unmount、同 id notification、supported-scope label 和现有后端 revision/scope checks 分别对应这些问题,没有把 UI state 当成新的配置 authority。与 backend 共用的 CLI/Lark mutation contract 未改,所以不需要另建 companion mutation;没有声称 live Lark 实测。

验证:dashboard TypeScript/Vite 与 bundled Chat build、workspace contract smoke 通过;capability-scope source/dev 和 packaged browser 均通过;既有 packaged typed-actions、automation-cadence、steward-model-settings 场景均通过。五个 config/API suite 在 head 为 80 passed,immutable base 为 64 passed,新增 16 个 scope matrix cases。真实 1512×982 desktop 和 390×844 mobile 浏览器,中英文键盘/选择操作均无 JS error 或横向溢出;我检查了首屏布局,目标先于 catalog,effective source 先于字段。

语义与 CI 对齐

复用既有 configuration editor contract,ownership 与 writability 分开。统一导航是有意的 UI 行为变化,RFC/design 与 periodic-report/usage-ping 双语入口说明、native scenes 已同步。独立新契约 oracle 在旧版明确因“没有显式编辑目标”失败,新版通过;保留的 preview 观察指纹两版同为 e620af7a1402e1bd8b562a2f634bff7108fc69f206aebe6d2884748d367847c7,fixture 指纹 5e5166fc195ae40a41675c0139fca695c65a72e8e9662ab39bae6f6f2985b82a。

证据边界必须分开:browser 使用真实 React/packaged asset server,但 API 由 synthetic fixture 拦截;实际配置 scope、写入/readback 和拒绝由另跑的 isolated native HTTP/config-owner suite 支撑,不能把截图或 mock 请求说成真实后端写入。没有验证 deployed Electron、host timer、live Lark 或“新建 Goal 自动授权”;本 PR 没改这些规则。按 capability wait_for_ci=false 未查询远端 CI;diff whitespace 通过,批准不表示合并就绪。

我的整体评价

APPROVE,无未解决 blocker。user_experience 改善为可见的编辑范围、明确目标和准确 owner label;long_horizon 保持既有持久配置与 revision/恢复 owner,重复 scope/Goal 切换也不会自动写入或复用旧确认。这是可独立使用和回滚的 settings 切片,不需要虚构后端完成或额外 approval gate。

Future-facing pass 已应用:统一重复导航,复用 workbench/typed configuration owner,以 supported_scopes 派生标签,并用正常 React 生命周期退休本地状态;没有新增 universal editor、registry 或平行 Python rule。活跃的旧 initialTab/Goal-entry 兼容是必要的,cadence/steward/provider 不同 change reason 保留。本人 PR 用 COMMENTED review 记录批准;本轮未自合并。结论仅绑定这个完整 exact head,任何新 head 需要重新审视。

English verdict: APPROVE - 4a8f372; explicit device/Goal edit intent, correct supported-scope ownership labels and stale draft/preview retirement validated. Base/head bilingual preview payloads match; the new target oracle fails baseline and passes head. Source/packaged browser scenarios, 80 native config/API tests, build and viewport checks passed. Browser fixtures and real backend evidence are distinguished; deployed host surfaces and merge readiness are not claimed.

@huangruiteng

Copy link
Copy Markdown
Collaborator Author

Current-head frame conclusion (4a8f372): APPROVE for explicit capability configuration edit intent in the desktop settings-owner frame and scope matrix. One device/Goal center reuses existing configuration owners; supported ownership is not writability, and target/scope changes retire drafts and previews. Source/packaged browser, independent bilingual delayed-response and base/head payload checks, plus separate isolated native configuration/HTTP validation passed. No deployed host timer, live Lark, new-Goal authorization or parent-roadmap closure claimed. Full bilingual self-review; COMMENTED because GitHub blocks formal self-approval. No merge-readiness or merge action claimed.

Signed-off-by: huangruiteng <14976749+huangruiteng@users.noreply.github.com>

# Conflicts:
#	examples/personal-workspace-browser-smoke.mjs
#	examples/personal-workspace-browser/automation-cadence.mjs

@huangruiteng huangruiteng left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PR #5187 复审 — exact head dd7104814aaae8cf6de180289fd5fd2e45bf2b96

Approval conclusion (author-owned PR; GitHub blocks formal self-approval)

Exact head: dd7104814aaae8cf6de180289fd5fd2e45bf2b96;base 5eec57abd8a298d3eeb0aa1cceb59cb2be9a973a。上一 head 的完整自评结论(APPROVE)继续成立;本 head 只做
两件事:把 origin/main 合进来解决 GitHub 报的冲突,以及保持原有能力设置改造不变。

动机

能力设置入口原本分成两处,编辑 owner 取决于"从哪进入":general 入口写设备默认,Goal 入口写某个
Goal override,而页面上没有显式选择。配置的生效值、支持范围和本次要改的目标是三件不同的事,
重复操作时容易把设备默认与 Goal override 混为一谈。这包把入口合成一个能力中心,并在 catalog
之前用原生 radio(此设备默认 / 单个 Goal)加 Goal select 表达明确目标。合并后主干新增的
steward-group-trigger、conversation-return-continuity 与 cadence fixture 改动与这条路径同文件,
必须一起保持可用,因此本 head 的冲突解决本身就是本次修复内容的一部分。

改动思路

不新增编辑器,保留既有 MachineConfigurationSettings、GoalCapabilitySettings 与统一 workbench。
导航合成能力中心,scope 选择只改变本地 intent,不提交配置;Goal key 变化或 scope 变化会卸载旧
editor,退休本地草稿与 preview,notification 使用同一目标 id。共享 header 的 owner 标签从
configuration_editor.supported_scopes 推导,不再拿"能否编辑"替代"支持何种 ownership"。持久配置
继续由既有 revision-locked preview/apply/readback owner 负责,前端不成为新的配置权威。

具体改动

相对最新 main 共 17 个文件 +283/-49:六个既有生产 UI 文件、四个测试与原生 browser 场景、五份
公开设计/用法文档、一个 Python 契约测试。本 head 额外的合并解决了两处冲突:
examples/personal-workspace-browser-smoke.mjs 取并集,保留本分支的 capabilityScopeScenario 与
主干新增的 stewardGroupTriggerScenario、conversationReturnContinuityScenario;
examples/personal-workspace-browser/automation-cadence.mjs 采用新版"目标 Goal"combobox 断言,
同时保留主干把 cadence fixture 切到 Multi Agent Projection 的改动。scope matrix 覆盖 16 个
built-in editor,分别校验 supported/writable scopes 与 unsupported scope 拒绝。

对主干的风险

主要风险是统一入口后目标不一致、旧 async 结果或 preview 混入新 Goal、scope 标签暗示额外写权限,
以及窄屏控件拥挤。新 key/unmount、同 id notification、supported-scopes 派生标签与后端既有
revision/scope 校验分别覆盖前三点;浏览器场景覆盖 1512×982 与 390×844 两种视口。合并后主干新增
场景在同一 harness 内全部通过,说明冲突解决没有回退主干行为。主干本身仍是红的:
typecheck:control-plane 在 sqlite_authority_store.ts 报 3 处类型错误、7 项 SQLite 用例失败、
registry IO census 与 maintainability ratchet 各有继承性失败——都在不含本 diff 的 origin/main 上
复现,与本变更无关。

我的整体评价

入口统一是这条 settings 路径上真实存在的重复与歧义,改动复用既有 typed configuration owner,
没有新增后端、API、持久字段或 capability,可独立使用与回滚。合并后的验证覆盖 Dashboard 覆盖率
运行器、21 个真实浏览器场景(含 capability-scope、automation-cadence、steward-group-trigger、
conversation-return-continuity)、dashboard 构建与 typecheck、workspace contract smoke、30 项
Python capability configuration 用例,以及目标内 16 项 premerge 检查;质量回执 valid 且
blocking=false。遗留红灯全部继承自主干,不构成本 PR 的 blocker。结论:建议合入。

English verdict: APPROVE - exact head dd71048. The unified capability centre keeps the explicit
device/Goal intent, correct supported-scope ownership labels and stale draft/preview retirement, and
this head additionally merges origin/main with both conflicts resolved so main's new browser
scenarios still pass. Dashboard coverage, 21 browser scenarios, build/typecheck, the workspace
contract smoke, 30 Python capability cases and the goal-scoped premerge all pass; remaining red
checks reproduce on untouched origin/main.

Signed-off-by: huangruiteng <14976749+huangruiteng@users.noreply.github.com>

@huangruiteng huangruiteng left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PR #5187 复审 — exact head 85c0fadcbb6a844f092e032deae881be0889f096

Approval conclusion (author-owned PR; GitHub blocks formal self-approval)

Exact head: 85c0fadcbb6a844f092e032deae881be0889f096;base 14ff38a6337c4a54f29c656b1b2ffd2ff1dd9edf。上一 head 的完整自评结论(APPROVE)继续成立;本 head 只做
两件事:把 origin/main 合进来解决 GitHub 报的冲突,以及保持原有能力设置改造不变。

动机

能力设置入口原本分成两处,编辑 owner 取决于"从哪进入":general 入口写设备默认,Goal 入口写某个
Goal override,而页面上没有显式选择。配置的生效值、支持范围和本次要改的目标是三件不同的事,
重复操作时容易把设备默认与 Goal override 混为一谈。这包把入口合成一个能力中心,并在 catalog
之前用原生 radio(此设备默认 / 单个 Goal)加 Goal select 表达明确目标。合并后主干新增的
steward-group-trigger、conversation-return-continuity 与 cadence fixture 改动与这条路径同文件,
必须一起保持可用,因此本 head 的冲突解决本身就是本次修复内容的一部分。

改动思路

不新增编辑器,保留既有 MachineConfigurationSettings、GoalCapabilitySettings 与统一 workbench。
导航合成能力中心,scope 选择只改变本地 intent,不提交配置;Goal key 变化或 scope 变化会卸载旧
editor,退休本地草稿与 preview,notification 使用同一目标 id。共享 header 的 owner 标签从
configuration_editor.supported_scopes 推导,不再拿"能否编辑"替代"支持何种 ownership"。持久配置
继续由既有 revision-locked preview/apply/readback owner 负责,前端不成为新的配置权威。

具体改动

相对最新 main 共 17 个文件 +283/-49:六个既有生产 UI 文件、四个测试与原生 browser 场景、五份
公开设计/用法文档、一个 Python 契约测试。本 head 额外的合并解决了两处冲突:
examples/personal-workspace-browser-smoke.mjs 取并集,保留本分支的 capabilityScopeScenario 与
主干新增的 stewardGroupTriggerScenario、conversationReturnContinuityScenario;
examples/personal-workspace-browser/automation-cadence.mjs 采用新版"目标 Goal"combobox 断言,
同时保留主干把 cadence fixture 切到 Multi Agent Projection 的改动。scope matrix 覆盖 16 个
built-in editor,分别校验 supported/writable scopes 与 unsupported scope 拒绝。

对主干的风险

主要风险是统一入口后目标不一致、旧 async 结果或 preview 混入新 Goal、scope 标签暗示额外写权限,
以及窄屏控件拥挤。新 key/unmount、同 id notification、supported-scopes 派生标签与后端既有
revision/scope 校验分别覆盖前三点;浏览器场景覆盖 1512×982 与 390×844 两种视口。合并后主干新增
场景在同一 harness 内全部通过,说明冲突解决没有回退主干行为。主干本身仍是红的:
typecheck:control-plane 在 sqlite_authority_store.ts 报 3 处类型错误、7 项 SQLite 用例失败、
registry IO census 与 maintainability ratchet 各有继承性失败——都在不含本 diff 的 origin/main 上
复现,与本变更无关。

我的整体评价

入口统一是这条 settings 路径上真实存在的重复与歧义,改动复用既有 typed configuration owner,
没有新增后端、API、持久字段或 capability,可独立使用与回滚。合并后的验证覆盖 Dashboard 覆盖率
运行器、21 个真实浏览器场景(含 capability-scope、automation-cadence、steward-group-trigger、
conversation-return-continuity)、dashboard 构建与 typecheck、workspace contract smoke、30 项
Python capability configuration 用例,以及目标内 16 项 premerge 检查;质量回执 valid 且
blocking=false。遗留红灯全部继承自主干,不构成本 PR 的 blocker。结论:建议合入。

English verdict: APPROVE - exact head 85c0fad. The unified capability centre keeps the explicit
device/Goal intent, correct supported-scope ownership labels and stale draft/preview retirement, and
this head additionally merges origin/main with both conflicts resolved so main's new browser
scenarios still pass. Dashboard coverage, 21 browser scenarios, build/typecheck, the workspace
contract smoke, 30 Python capability cases and the goal-scoped premerge all pass; remaining red
checks reproduce on untouched origin/main.

@huangruiteng
huangruiteng merged commit f40f837 into main Sep 27, 2026
10 checks passed
@huangruiteng
huangruiteng deleted the codex/capability-settings-scope branch September 27, 2026 18:26
@huangruiteng

Copy link
Copy Markdown
Collaborator Author

Merged as f40f8379af (squash, admin bypass) on the exact reviewed head 85c0fadcbb.

Exact-head evidence:

Repair carried in this head: the PR was CONFLICTING against main. It is now merged with the latest origin/main twice (through #5188 and #5218) with both conflicts resolved:

  • examples/personal-workspace-browser-smoke.mjs: took the union — this branch's capabilityScopeScenario plus main's new stewardGroupTriggerScenario and conversationReturnContinuityScenario.
  • examples/personal-workspace-browser/automation-cadence.mjs: kept the new 目标 Goal combobox assertion from this branch, while retaining main's fixture switch to Multi Agent Projection and its goal_id-scoped cadence rules.

The capability-settings change itself was not altered: explicit device/Goal scope selection, supported_scopes-derived ownership labels, keyed editor lifecycle that retires stale drafts/previews, and the existing revision-locked preview/apply/readback owner.

Validation on this head: dashboard coverage runner (npm run test:dashboard:coverage, 100% statements); 21 real browser scenarios including capability-scope, automation-cadence, steward-group-trigger and conversation-return-continuity; npm run build:desktop (tsc --noEmit + vite build); personal-workspace drawer contract smoke; python -m pytest tests/capabilities/test_capability_configuration_ui.py (30 passed); goal-scoped premerge with a valid quality receipt. First-viewport screenshots from the real harness: output/playwright/personal-workspace/capability-scope-defaults.png, capability-scope-goal.png, capability-scope-mobile.png.

Pre-existing main reds, not owned by this PR (all reproduce without this diff):

  • npm run typecheck:control-plane: 3 errors in loopx/control_plane/coordination/sqlite_authority_store.ts (TS2554/TS2339 at lines 457–462).
  • npm run test:control-plane: 7 SQLite control-plane cases fail.
  • tests/architecture/test_project_registry_io_census.py / test_goal_instance_binding_inventory.py: checked-in registry I/O manifest metadata drift inherited from main.

Admin bypass was used because the PR is authored by the maintainer and the exact head carries a published review, a valid change-quality receipt and a goal-scoped premerge pass; the remaining red checks belong to main, not to this diff.

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