feat(control-plane): add company work routing contract - #4577
KashiwaByte wants to merge 17 commits into
Conversation
Signed-off-by: KashiwaByte <471314513@qq.com>
Signed-off-by: KashiwaByte <471314513@qq.com>
Signed-off-by: KashiwaByte <471314513@qq.com>
Signed-off-by: KashiwaByte <471314513@qq.com>
Signed-off-by: KashiwaByte <471314513@qq.com>
Signed-off-by: KashiwaByte <471314513@qq.com>
Signed-off-by: KashiwaByte <471314513@qq.com>
Signed-off-by: KashiwaByte <471314513@qq.com>
Signed-off-by: KashiwaByte <471314513@qq.com>
Signed-off-by: KashiwaByte <471314513@qq.com>
Signed-off-by: KashiwaByte <471314513@qq.com>
huangruiteng
left a comment
There was a problem hiding this comment.
仓库最新出了一个loopx roadmap rfc,可以融合重构一下,可以给rfc提pr
huangruiteng
left a comment
There was a problem hiding this comment.
动机
评审 head:b6b0a753de9e20d8bc76305c2733da2de5eb0aa8;base:main(merge-base 81f435d6b)。
交付判定(policy 6):goal_achieved(新能力本身按声明交付),但本 review 给出 REQUEST_CHANGES,原因是一条共享契约的默认行为被悄然放宽且未披露——这与新能力自身的质量无关,且修复成本很低。
PR 要解决的问题是真实的:把"公司工作"路由进 LoopX 既有的 agent / 人类决策 / 人类执行 / monitor / blocker 这些 Todo lane,并把证据汇回下一轮规划,避免靠手工维护 Todo 来对齐计划。作者选择扩展现有 control_plane/work_items owner(而不是新建 capability 或 provider),并复用 add_goal_todo/list_goal_todos 这类既有受治 Todo 写入口——这两点都是正确的取舍。
改动思路
入口是 loopx company-control-loop(project / upgrade / save / show / sync-todos / reconcile-todos / next-cycle),经由 Python CLI 调 managed TS effect handlers。TS 侧两个新模块分工明确:company_control_loop.ts 负责校验与路由(work route 是字面量集合,输入有界、id 需 public-safe、拒绝悬空 outcome 引用),company_control_state.ts 负责带 revision 校验的持久化与 readback(atomicWriteJson + withFileMutationLock,冲突抛错而不是覆盖)。Python 侧只做参数与编排,Todo 写入走既有受治 owner,save/sync-todos/reconcile-todos 默认 dry-run、写操作需要 --execute。
这个"TS 掌状态、Python 适配"的分布与仓库既定边界一致,新状态也没有变成第二个 Todo 权威。
具体改动
16 个文件、+2650/-2:新 TS 约 870 行、CLI 约 460 行、测试约 1250 行、文档 105 行、handler/tsconfig 注册 26 行,以及共享模块 monitor_metadata.ts 的 4 行改动(问题所在)。
关键代码讲解
company_control_loop.ts:COMPANY_WORK_ROUTES = [ai_execute, human_decide, human_execute, observe, reject],配 MAX_OUTCOMES/MAX_WORK_ITEMS/MAX_FEEDBACK_ITEMS 上界与 PUBLIC_ID 正则;校验失败抛 schema 前缀明确的 EffectRuntimeRequestError。投影只描述"该由谁做",不授予执行或配额权限。
company_control_state.ts:store/reconcile/next-cycle 三套 v0 schema;写入前校验 revision,读取时校验存储 schema,坏状态直接拒绝。
cli_commands/company_control_loop.py:dry_run: not execute 的门控,Todo 创建调用 add_goal_todo(...) 而不是直接改状态。
todos/monitor_metadata.ts:191(问题点):共享的 Todo metadata planner 的角色守卫从 target_key requires --role agent 改成 --role agent or user,同时本 PR 把原先编码"旧默认"的断言从 assert.throws 改成 assert.deepEqual。
对主干的风险
阻塞项(P2):monitor_metadata.planMonitorMetadata 是所有 Todo create/update 走的共享 planner,不是本能力的私有路径。这条 4 行改动把"user 角色不能带 target_key"变成"可以",而仓库自身规则明确要求默认行为变更必须披露:说明旧/新默认、点名受影响的 lane/消费方、并更新文档("rename the smoke that encoded the old default, update docs/release notes, and name the affected lanes")。当前三项都没做到:PR 描述只把它写成"preserve target keys on human decision/action Todos"这一条功能收益,docs/reference/monitor-configuration.md 仍把 target_key 描述为 monitor 配置字段,被改写的断言也没有标注这是默认变更;而读取 target_key 的消费方(monitor successor/poll 的 target 身份、scheduler frontier identity、governed_capability.ts 基于 target_key 前缀的操作授权)都不会重新检查 role/task_class。最小修复有三件事:在描述里写明 old→new 默认与受影响消费方、更新 monitor-configuration 文档、并考虑把允许范围限定在 company-control-loop 绑定而不是对所有 user-role Todo 放开。复跑:node --experimental-strip-types --test tests/control_plane_ts/monitor_metadata.test.ts 加两个 company suite。
其余部分我独立复核通过:聚焦测试 25 TS + 76 Python 全绿;更重要的是我对比了同一个全量 TS 套件在 base 与 head 的结果——base 1681 tests / 1495 passed / 162 failed,head 1696 tests / 1510 passed / 162 failed:失败集合是既有的环境门槛问题(本机 Node/SQLite 低于声明下限),本 PR 只新增 15 条且全过,没有新增失败。
P3(非阻塞):PR 描述把这批失败描述成"four provider parity failures",与实测的 162(base/head 相同)不符。建议直接写 base/head 对比,免得 reviewer 去追一个对不上的数字。
P3(非阻塞):新模块、6 个 work_item.company_control_* effect id 与 CLI 都把"company"这一产品词汇放进了通用 work_items 边界。作者的放置理由成立,但仓库要求通用控制面契约保持领域中立;建议与 owner 确认这是有意的产品面,还是应当中性命名、把"company"作为 profile 绑定。
我的整体评价
baseline(无该能力;user-role target_key 被拒)与 head(新能力可用;user-role target_key 被接受)对比:新能力的实现路径、权限边界与 dry-run 设计都站得住(写操作需 --execute、走受治 Todo owner、revision 冲突不覆盖、精确 readback),测试也覆盖了 e2e 生命周期;唯一越出本能力范围的是那条共享规则放宽。
体量上,对一个完整生命周期能力而言 2650 行(其中约一半是测试)并不算失控;我也明确说明本次审阅在新模块上到 API/校验语义深度,未逐行审计全部约 870 行路由语义,也未复跑作者的 wheel/隔离与 premerge。只要补齐披露(并考虑收敛放开范围),这份变更就可以通过。
English verdict: REQUEST_CHANGES - exact head b6b0a75; the new company-control-loop capability itself checks out (25 TypeScript and 76 Python focused tests pass, writes stay behind --execute and route through the governed Todo owner, revisions conflict instead of overwriting, and the full control-plane suite shows no new failures: 1495/162 at the merge base versus 1510/162 at the head). The blocker is one 4-line change in the shared Todo metadata planner: monitor_metadata.ts now accepts target_key for role=user where it previously required role=agent, and the assertion that encoded the old default was rewritten in place without declaring the old/new default, naming the affected consumers (monitor target identity, scheduler frontier identity, governed-capability target-key authorization) or updating docs/reference/monitor-configuration.md. Minimum repair: disclose the default change, update that reference, and consider scoping the allowance to the company-control-loop binding. Two non-blocking P3s: the PR body understates the pre-existing shared-suite failures as "four" (measured 162 at both revisions), and a product-specific vocabulary is added to the generic work_items owner.
huangruiteng
left a comment
There was a problem hiding this comment.
评审 head 变更说明(取代上一条 review):我按 b6b0a753de9e20d8bc76305c2733da2de5eb0aa8 完成取证并发布过一条 review,随后作者又推了 8ca5259f5 fix(control-plane): bound derived company feedback ids(company_control_state.ts +28 与测试 +42)。我在新 head 上重读了该 diff 并重跑了全部相关测试(TS 4 个文件 fail 0,Python 76 passed),结论不变(阻塞项仍是共享 target_key 角色规则未披露);请只以本条与当前 head 为准。
该新提交本身是正向修复:把派生的 feedback id 从 todo_<work_item_id>_done 改为todo_feedback_<sha256 前缀>(由 work item + 状态 + todo id + cycle 派生),避免 id 越界与碰撞,并新增了对应测试。
动机
评审 head:8ca5259f51b9ec233057c529724d3c89182170f0;base:main(merge-base 81f435d6b)。
交付判定(policy 6):goal_achieved(新能力本身按声明交付),但本 review 给出 REQUEST_CHANGES,原因是一条共享契约的默认行为被悄然放宽且未披露——这与新能力自身的质量无关,且修复成本很低。
PR 要解决的问题是真实的:把"公司工作"路由进 LoopX 既有的 agent / 人类决策 / 人类执行 / monitor / blocker 这些 Todo lane,并把证据汇回下一轮规划,避免靠手工维护 Todo 来对齐计划。作者选择扩展现有 control_plane/work_items owner(而不是新建 capability 或 provider),并复用 add_goal_todo/list_goal_todos 这类既有受治 Todo 写入口——这两点都是正确的取舍。
改动思路
入口是 loopx company-control-loop(project / upgrade / save / show / sync-todos / reconcile-todos / next-cycle),经由 Python CLI 调 managed TS effect handlers。TS 侧两个新模块分工明确:company_control_loop.ts 负责校验与路由(work route 是字面量集合,输入有界、id 需 public-safe、拒绝悬空 outcome 引用),company_control_state.ts 负责带 revision 校验的持久化与 readback(atomicWriteJson + withFileMutationLock,冲突抛错而不是覆盖)。Python 侧只做参数与编排,Todo 写入走既有受治 owner,save/sync-todos/reconcile-todos 默认 dry-run、写操作需要 --execute。
这个"TS 掌状态、Python 适配"的分布与仓库既定边界一致,新状态也没有变成第二个 Todo 权威。
具体改动
16 个文件、+2650/-2:新 TS 约 870 行、CLI 约 460 行、测试约 1250 行、文档 105 行、handler/tsconfig 注册 26 行,以及共享模块 monitor_metadata.ts 的 4 行改动(问题所在)。
关键代码讲解
company_control_loop.ts:COMPANY_WORK_ROUTES = [ai_execute, human_decide, human_execute, observe, reject],配 MAX_OUTCOMES/MAX_WORK_ITEMS/MAX_FEEDBACK_ITEMS 上界与 PUBLIC_ID 正则;校验失败抛 schema 前缀明确的 EffectRuntimeRequestError。投影只描述"该由谁做",不授予执行或配额权限。
company_control_state.ts:store/reconcile/next-cycle 三套 v0 schema;写入前校验 revision,读取时校验存储 schema,坏状态直接拒绝。
cli_commands/company_control_loop.py:dry_run: not execute 的门控,Todo 创建调用 add_goal_todo(...) 而不是直接改状态。
todos/monitor_metadata.ts:191(问题点):共享的 Todo metadata planner 的角色守卫从 target_key requires --role agent 改成 --role agent or user,同时本 PR 把原先编码"旧默认"的断言从 assert.throws 改成 assert.deepEqual。
对主干的风险
阻塞项(P2):monitor_metadata.planMonitorMetadata 是所有 Todo create/update 走的共享 planner,不是本能力的私有路径。这条 4 行改动把"user 角色不能带 target_key"变成"可以",而仓库自身规则明确要求默认行为变更必须披露:说明旧/新默认、点名受影响的 lane/消费方、并更新文档("rename the smoke that encoded the old default, update docs/release notes, and name the affected lanes")。当前三项都没做到:PR 描述只把它写成"preserve target keys on human decision/action Todos"这一条功能收益,docs/reference/monitor-configuration.md 仍把 target_key 描述为 monitor 配置字段,被改写的断言也没有标注这是默认变更;而读取 target_key 的消费方(monitor successor/poll 的 target 身份、scheduler frontier identity、governed_capability.ts 基于 target_key 前缀的操作授权)都不会重新检查 role/task_class。最小修复有三件事:在描述里写明 old→new 默认与受影响消费方、更新 monitor-configuration 文档、并考虑把允许范围限定在 company-control-loop 绑定而不是对所有 user-role Todo 放开。复跑:node --experimental-strip-types --test tests/control_plane_ts/monitor_metadata.test.ts 加两个 company suite。
其余部分我独立复核通过:聚焦测试 25 TS + 76 Python 全绿;更重要的是我对比了同一个全量 TS 套件在 base 与 head 的结果——base 1681 tests / 1495 passed / 162 failed,head 1696 tests / 1510 passed / 162 failed:失败集合是既有的环境门槛问题(本机 Node/SQLite 低于声明下限),本 PR 只新增 15 条且全过,没有新增失败。
P3(非阻塞):PR 描述把这批失败描述成"four provider parity failures",与实测的 162(base/head 相同)不符。建议直接写 base/head 对比,免得 reviewer 去追一个对不上的数字。
P3(非阻塞):新模块、6 个 work_item.company_control_* effect id 与 CLI 都把"company"这一产品词汇放进了通用 work_items 边界。作者的放置理由成立,但仓库要求通用控制面契约保持领域中立;建议与 owner 确认这是有意的产品面,还是应当中性命名、把"company"作为 profile 绑定。
我的整体评价
baseline(无该能力;user-role target_key 被拒)与 head(新能力可用;user-role target_key 被接受)对比:新能力的实现路径、权限边界与 dry-run 设计都站得住(写操作需 --execute、走受治 Todo owner、revision 冲突不覆盖、精确 readback),测试也覆盖了 e2e 生命周期;唯一越出本能力范围的是那条共享规则放宽。
体量上,对一个完整生命周期能力而言 2650 行(其中约一半是测试)并不算失控;我也明确说明本次审阅在新模块上到 API/校验语义深度,未逐行审计全部约 870 行路由语义,也未复跑作者的 wheel/隔离与 premerge。只要补齐披露(并考虑收敛放开范围),这份变更就可以通过。
English verdict: REQUEST_CHANGES - exact head 8ca5259; the new company-control-loop capability itself checks out (25 TypeScript and 76 Python focused tests pass, writes stay behind --execute and route through the governed Todo owner, revisions conflict instead of overwriting, and the full control-plane suite shows no new failures: 1495/162 at the merge base versus 1510/162 at the head). The blocker is one 4-line change in the shared Todo metadata planner: monitor_metadata.ts now accepts target_key for role=user where it previously required role=agent, and the assertion that encoded the old default was rewritten in place without declaring the old/new default, naming the affected consumers (monitor target identity, scheduler frontier identity, governed-capability target-key authorization) or updating docs/reference/monitor-configuration.md. Minimum repair: disclose the default change, update that reference, and consider scoping the allowance to the company-control-loop binding. Two non-blocking P3s: the PR body understates the pre-existing shared-suite failures as "four" (measured 162 at both revisions), and a product-specific vocabulary is added to the generic work_items owner.
Signed-off-by: KashiwaByte <471314513@qq.com>
…ive-v0 Signed-off-by: KashiwaByte <471314513@qq.com>
Signed-off-by: KashiwaByte <471314513@qq.com>
Signed-off-by: KashiwaByte <471314513@qq.com>
|
已按上一轮 review 的阻塞项和 roadmap 建议更新,当前精确 head 为
本地验证:76 个 Python 测试、27 个 TypeScript 测试、 GitHub 当前仍未生成任何 status-check rollup,因此没有把“无 checks”当作 CI 通过,也没有合并。请在当前 head 上重新 review;若 CI 是必需门禁,仍需远端检查证据。 English update: the previous shared-default blocker is addressed at exact head |
huangruiteng
left a comment
There was a problem hiding this comment.
动机
这个 PR 想解决的是:一个长期的公司方向,需要把有界工作分派给 AI、人的决策、人的执行、监控或阻塞,并把结果证据回流成下一轮规划。作者新增 loopx company-control-loop 七个动词(project/upgrade/save/show/sync-todos/reconcile-todos/next-cycle),复用 Goal/Todo/证据/quota/replan 既有 owner。
本次复审的框架来自你(owner)的疑问:"company" 这个产品词汇被放进了通用 work_items 边界。因此我按仓库自己的判断基准重做,而不是只看代码形状:
- 总纲 loopx-overall-roadmap-v0.md §1:"Domain behavior belongs to capabilities/packages; … private semantics cannot become generic kernel rules."
- 同文 §5(第 171 行):"This change adds no capability/provider. R1/R3 should extend existing work-items/collaboration ownership … Each implementation PR records its placement rationale first."
- 同文 §7:每个实现 PR 要回答 outcome/R card/owning RFC acceptance ID/ownership;"New authority, state machines, cross-host identities and incompatible schema changes require the relevant owner's review of the exact diff."
- AGENTS.md:核心控制面义务与错误文本必须保持 domain-neutral,不得把产品/基准专属措辞放进通用 work-lane、quota、todo、settlement 契约。
改动思路
实现分四层,方向本身是干净的:
- TS 规划器
work_items/company_control_loop.ts:校验有界、public-safe 的 outcomes / work items / feedback,把每个工作项按 route 与 authority/capability 事实映射成 agent advancement Todo、阻塞型 user gate、user action、有界 continuous monitor 或 blocker。 - TS 状态 owner
work_items/company_control_state.ts:<runtime_root>/goals/<goal>/company-control-loop/state.json的原子写 + sha256 revision CAS,以及reconcile与next_cycle。 - CLI 适配层
cli_commands/company_control_loop.py:默认 dry-run,物化/对账都走既有add_goal_todo/list_goal_todos,没有另造 Todo 写入口。 - 文档与总纲:README、总纲中英行(第 59 行)、新参考文档、monitor 参考中英段。
相对我上一轮复审的 head(8ca5259f5),本 head 的增量确实回应了当时的关切:
- 新增
### Roadmap placement,把 S1/S3 边界写进参考文档; - 总纲中英两侧各加一行,把 profile 声明为 Goal/Todo/evidence owner 的 bounded caller;
docs/reference/monitor-configuration.md中英都补了target_key的 before/after 规则与"消费者仍需自行做 authority 检查";- PR 描述新增 "Roadmap and placement" 与 "Shared default behavior change" 两节;
- 规划器补了 id/
target_key唯一性与cyclesafe-integer 校验。
我上一轮指出的"共享默认未披露、受影响 lane 未点名"在本 head 已基本闭合,而且我独立验证了它的 authority 语义(见下文与"关键代码讲解")。
具体改动
按 19 个文件分组:
- 新运行时(+911 行):
work_items/company_control_loop.ts(projectCompanyControlLoop、upgradeCompanyControlLoopState、COMPANY_WORK_ROUTES、A–D authority tier)、work_items/company_control_state.ts(companyControlStatePath、load/write/reconcile/planNextCycle)。 - 共享内核表(+16 行):
effect_runtime_handlers.ts注册 6 个work_item.company_control_*effect id。 - 共享默认变更(10 行):
todos/monitor_metadata.ts的targetAllowed。 - CLI(+487 行):
cli.py注册 +cli_commands/company_control_loop.py(_sync_todos、_reconcile_todos)。 - 文档:README(+1)/README.zh-CN(+1)、总纲中英各 +1 行、新增
docs/reference/company-control-loop.md(120)、docs/reference/monitor-configuration.md(+15)。 - 测试(+1989 行):Python CLI/authority(476+22)、TS planner/state/e2e(215+380+154)、monitor_metadata.test.ts(+15)。
- 构建:
tsconfig.control-plane.json加入 4 个文件。
对主干的风险
F1(P1,阻塞)产品词汇与新持久 schema 家族落在通用 work_items 边界。
loopx/control_plane/ 下 518 个文件里,主干只有 issue_meta_surface.py 一个带产品味的名字;本 PR 加入 company_control_loop.ts、company_control_state.ts,并让通用 effect 表出现 6 个 work_item.company_control_* id、四个 company_control_*_v0 schema 版本串。这不是风格问题:effect id 与 schema 是内核公共面,一旦合入,改名就要迁移持久状态与外部调用方。总纲 §1 明确把领域行为放在 capabilities/packages,§5 要求实现 PR 先记录 placement rationale,而承载该边界的总纲行是同一个 PR 自己加的第 59 行——所以它记录的是作者声明,不是 owner 的放置决策。§7 又单独要求"新增状态机与持久 schema 需要相关 owner 审阅 exact diff",这正是你现在在做的事。
最小修复(二选一):把 profile 移到以调用者结果命名的 capability/package;或保留在 work_items 但把面向内核的 id/schema 改成中性命名(例如 routing-plan 词汇),把 "company" 留在 profile 的文档与 CLI 里。
F2(P2)legacy upgrade 通道在仓库里没有生产者。
LEGACY_COMPANY_CONTROL_STATE_SCHEMA_VERSION(loopx_company_control_state_v0)只出现在本 PR 自己的代码、文档与测试中;整仓 rg 找不到生产者或样本文件。按仓库的 scope-fit 规则,兼容缝只有在真实外部导入、已持久状态、CLI/API 契约或迁移窗口存在时才保留。
F3(P2)内核级 Todo 默认被单一 profile 拉宽。
旧默认:target_key 仅 --role agent。新默认:再加 user_gate/user_action。披露是完整的(PR 描述、monitor 参考中英、总纲行、回归测试),authority 隔离我也独立验证了:
- 未标注 typed lane 的 user 角色仍被拒绝(错误文本
target_key requires an agent Todo or a user gate/action Todo); user_gate+cadence仍被拒(monitor schedule metadata requires --role agent --task-class continuous_monitor);- 带
target_key的 user Todo 交给scheduler.monitor_target.select仍被拒(monitor-poll todo writeback target must be task_class=continuous_monitor); governed_capability.ts仍要求selected_todo是 open agent Todo;monitor_successor.ts同样要求 role=agent + continuous_monitor。
但事实是:这条共享规则的唯一生产者就是这个 profile(它的 sync/reconcile 靠遍历 Goal Todo 匹配 target_key)。要么让 profile 把 work_item→todo 身份存进自己带 revision 的状态里,保持内核规则 agent-only;要么把这条规则表述成对 user Todo 通用的 correlation identity 契约,而不是由单一 profile 塑形的例外。
验证与反例。 27 个 TS 用例、76 个 Python 用例全过,tsc --project tsconfig.control-plane.json --noEmit 干净,语义词汇 drift smoke ok(26/26),架构语义测试 101 过。我另外用真实 effect runtime(非 mock)补了两个作者测试未覆盖的反例:未标注 lane 的 user 角色、以及 user item 作为 monitor target——两者都 fail closed。未验证项:packaged wheel 安装与打包后 CLI smoke 只在更早 head 上跑过,本 head 未复跑;也没有真实 Lark/打包前端路径。
我的整体评价
REQUEST_CHANGES。这个 PR 不是 off-goal:它是一个真实可用、默认 dry-run、复用 canonical Todo writer、测试确实通过的增量,上一轮我提的披露问题也确实修好了。但按你要求的总纲/RFC 视角,它现在停在"placement 未决"上:一个带产品名的模块、effect id 与持久 schema 家族要进入通用内核,而总纲把这类判断交给相关 owner,且承载该边界的行由本 PR 自己添加。在 placement 决定之前,proportionality 也无法收敛——同一份 diff 作为 capability/package profile 是合适的体量,作为新的通用内核词汇就偏重。
建议的下一步很具体:你先给 placement 决策(re-home 或中性命名),顺带砍掉 F2 那条没有生产者的 legacy 通道;F3 则决定是否让内核保留这条仅为单一 profile 存在的 target_key 放宽。做完这些我可以立刻复审并给合并建议。
关键代码讲解
loopx/control_plane/todos/monitor_metadata.ts:191(targetAllowed):共享 planner 里唯一的默认语义变更点。旧代码一行role !== "agent"直接拒绝;新代码把接受集合变成"agent,或 user 且 task_class ∈ {user_gate,user_action}"。不变量是:target_key只做身份关联,频率/到期/watch-only/expires 仍只属于 agent 的 continuous_monitor。loopx/control_plane/work_items/company_control_loop.ts:252(projectCompanyControlLoop):纯投影,先做有界数组、public-safe id、四类 id 唯一性、safe-integer cycle 校验,再按 route 决定 Todo lane;未知 outcome 引用直接拒绝。它不写任何状态,所以失败时没有半成品。loopx/control_plane/work_items/company_control_state.ts:77(companyControlStatePath/writeCompanyControlState):把规划文档落在goals/<goal>/company-control-loop/state.json,替换必须带精确expected_revision,写后 readback 必须匹配;冲突抛EffectRuntimeConflictError。这是"计划文档 + CAS",不是第二套工作权威——Todo 仍是唯一工作/终态权威。loopx/cli_commands/company_control_loop.py:155(handle_company_control_loop_command/_sync_todos):CLI 适配与幂等物化。_sync_todos先列 Goal Todo 按target_key建索引,发现重复身份直接失败,创建一律委托add_goal_todo,因此没有绕过既有 Todo 规则。loopx/control_plane/effect_runtime_handlers.ts:464:通用 effect 表新增 6 个work_item.company_control_*条目。这一行正是 F1 的具体位置:内核表在改动前只出现 planning_inventory、refresh_recommendation、delivery_history 这类中性条目。
语义与 CI 对齐
semantic_alignment = not_yet_proven。本 diff 在通用契约里 create_vocabulary:新 effect id 家族、四个 schema 版本串、CLI 命名空间,以及共享 planner 里一条 lane 专属例外。我把仓库的 semantic-vocabulary drift smoke 与架构语义测试都跑在本 head 上:semantic-vocabulary-drift-smoke: ok(coverage 26/26 vocabularies、owner_symbols 51/51),tests/architecture 101 过——也就是说这些新名字没有被登记为内核词汇,所以现有 smoke 无法判断这次放置是否合适,这恰好是该交由 owner 决策的部分。若最终决定保留在内核,请按 RFC 的 same-diff 规则登记词汇;若 re-home,则内核侧不应留下 company 前缀。CI 侧我按管理策略没有轮询远端检查,只使用本 head 的本地必需验证。
English verdict: REQUEST_CHANGES - reviewed exact head 36deb32. The profile works and its disclosed target_key widening is authority-isolated (verified by direct effect-runtime probes: untyped user lanes still reject, schedule fields stay agent-only, user items are not monitor targets, governed capability still needs an open agent Todo), and the earlier disclosure gap is closed. The blocker is roadmap/RFC placement: product-domain naming plus a new durable schema and effect-id family inside the generic work_items boundary, where roadmap section 1 keeps domain behavior in capabilities/packages, section 5 requires a recorded placement rationale, and section 7 requires the owner's review for a new state machine and durable schema - the roadmap row carrying this boundary was added by this same PR, so it is an author declaration, not the owner's decision. Minimum repair: record the placement decision, then either re-home the profile or rename the kernel-facing ids and schemas neutrally; drop the producer-less legacy upgrade seam. Validation: 27 TS + 76 Python focused tests pass, tsc control-plane clean, semantic drift smoke ok, 101 architecture tests pass.
Signed-off-by: KashiwaByte <471314513@qq.com>
|
Addressed F2 in Validation:
F1 and F3 remain open and are next: neutralize kernel-facing contracts, then persist Todo correlation inside the profile state so the shared user Todo rule can return to agent-only. |
Signed-off-by: KashiwaByte <471314513@qq.com>
|
Addressed the remaining F1/F3 review blockers in
Validation at
|
huangruiteng
left a comment
There was a problem hiding this comment.
动机
上一轮我在这个 PR 上给了 REQUEST_CHANGES,理由是产品词汇与新的持久 schema 家族落在通用 work_items 边界:模块名、6 个 work_item.company_control_* effect id、四个 company_control_*_v0 schema,加上一条把共享 target_key 默认放宽到 user_gate/user_action 的改动,以及一个仓库里没有生产者的 legacy upgrade 通道。总纲 §1 把领域行为划给 capabilities/packages,§5 要求实现 PR 先记录 placement rationale,§7 要求新增状态机与持久 schema 由相关 owner 审阅 exact diff。
这个 head(bbdf631c0)是对那份评审的直接回应,逐条都做了。
改动思路
作者选择了"保留在 work_items,但让内核侧命名中性、把 profile 的词留给 CLI 与文档"这条路,并额外用 profile 自己的状态解决身份关联:
- 内核命名中性化:
company_control_loop.ts→outcome_routing_plan.ts,company_control_state.ts→outcome_routing_state.ts;effect id 改为work_item.outcome_routing_plan.project与work_item.outcome_routing_state.{bind,load,next_cycle,reconcile,write};schema 版本改为outcome_routing_plan_request_v0/outcome_routing_plan_v0/outcome_routing_state_*_v0。company现在只出现在 CLI 命令名、README 行与参考文档里。 - 回退共享默认:
loopx/control_plane/todos/monitor_metadata.ts与它的两处测试相对 main 零 diff,target_key继续只对--role agent生效。 - 身份关联改为 profile 自持:新增
bindOutcomeRoutingTodos,把work_item_id → todo_id存在 profile 自己的带 revision 状态里;sync-todos只对role == "agent"设置target_key,human 车道保持普通user_gate/user_action记录,reconcile-todos也按 binding 匹配而不是按target_key。这正是我上轮给出的更小替代方案。 - 删除无生产者的兼容缝:
loopx_company_control_state_v0与upgrade动词整段移除,文档同步去掉对应段落。
具体改动
loopx/control_plane/work_items/outcome_routing_plan.ts(+341):OUTCOME_ROUTING_PLAN_REQUEST_SCHEMA_VERSION/OUTCOME_ROUTING_PLAN_SCHEMA_VERSION、OUTCOME_WORK_ROUTES(ai_execute/human_decide/human_execute/observe/reject)、projectOutcomeRoutingPlan的有界校验(public-safe id、id 唯一、safe-integer cycle、未知 outcome 拒绝)。loopx/control_plane/work_items/outcome_routing_state.ts(+543):路径与 revision CAS、bindOutcomeRoutingTodos、reconcileOutcomeRoutingState(done 无证据→awaiting_evidence,blocked→replanning,dry-run 默认)、planOutcomeRoutingNextCycle(replan_required/goal_converged)。loopx/control_plane/effect_runtime_handlers.ts(+16):6 个中性 effect id 注册。loopx/cli_commands/company_control_loop.py(+492)与loopx/cli.py(+26):CLI 适配,物化/对账一律走add_goal_todo/list_goal_todos,human gate 带decision_scope,失败即ok=false且不写半成品。- 文档:README 中英各 1 行、总纲中英各 1 行、新增
docs/reference/company-control-loop.md(+121),其中明确写出"控制面契约使用中性的outcome_routing_*家族,避免共享 work-item 内核获得公司专属词汇"。 - 测试:
outcome_routing_plan.test.ts、outcome_routing_state.test.ts、outcome_routing_e2e.test.ts与test_company_control_loop_cli.py,覆盖 AI 交付、人类决策、人类执行、重启恢复、失败升级、重规划与收敛。
对主干的风险
我认为主干风险已经收敛。 逐条核对上一轮的三个发现:
- 内核词汇:
git diff origin/main...HEAD里company只出现在 docs/README;内核侧模块名、effect id、schema 串全部中性。 - 共享默认:
monitor_metadata.ts、monitor_metadata.test.ts、test_todo_mutation_authority.py三处零 diff,此前那条放宽及其测试一并回退,因此不再存在"内核规则被单一 profile 塑形"的问题。 - legacy 缝:
loopx_company_control_state_v0与upgrade已删除,没有留下无人调用的兼容路径。
我另外检查了身份关联的正确性:reconcile 只接受能解析到已存 work target 的 observation,重复 target_key 或 binding 缺失时直接报错,不做文本猜测回退;human 车道的 target_key 只存在于 profile 状态,不进 Todo 元数据。因此即使 profile 状态过期,也不会把别的 Todo 状态误算到某个工作项上。
剩下的是非阻塞的一条:PR 描述相对本 head 已过时——它仍在描述那条已被回退的 target_key 共享默认变更,引用的还是 company_control_loop.ts/company_control_state.ts 旧文件名,验证数字(27 TS / 76 Python)也对不上本 head(我在本 head 跑出 16 个聚焦 TS 用例、10 个聚焦 Python 用例)。合并记录应当与审阅的 head 一致,请在合并前更新描述。
我的整体评价
APPROVE。 这个 head 把我上轮的阻塞项逐条修掉了,而且选的是更小的那条路:中性命名 + profile 自持身份 + 去掉兼容缝,而不是把产品词继续塞进内核。行为覆盖面没有缩水(AI/人类/重启/升级/重规划/收敛六个场景仍在测试里),共享面零改动,回滚也只是删掉三个附加模块、一处 CLI 注册和文档。
我没有发现新的阻塞问题。唯一要求是更新 PR 描述,使合并记录不再声称一个本 head 不存在的共享默认变更。
关键代码讲解
outcome_routing_plan.ts:14(schema 常量):这是上一轮最直接的整改点。内核公共面的字符串从company_control_loop_*变成outcome_routing_plan_*。schema 串一旦发布就要迁移才能改名,所以中性化应当发生在合入之前——现在就是那个时间点。outcome_routing_state.ts:253(bindOutcomeRoutingTodos):把work_item_id → todo_id绑定写进 profile 自己的状态,并用expected_revision+ 写后 readback 保护。它替换了上一版"放宽共享target_key规则"的做法:human 车道的 Todo 元数据保持原样,关联身份留在 profile 内,revision 未变时返回written=false表示幂等重放。outcome_routing_state.ts:355(reconcileOutcomeRoutingState):先由todoReconciliation把 observation 映射回已存 work target(未知 target 直接拒绝),再在execute=true时原子写回;done缺证据转awaiting_evidence、blocked转replanning,dry-run 不写。这让"证据回流规划"这一步有单一 owner,而不是散在 CLI 里。company_control_loop.py:211(_sync_todos/_reconcile_todos):现在只对role == "agent"设置target_key,human 车道走decision_scope/bound_agent与 profile binding;创建一律委托add_goal_todo,因此没有绕开既有 Todo 契约的第二条写路径。loopx/cli.py:335:唯一的 CLI 注册点,命令名保留company-control-loop(产品入口),与内核契约命名分层——这正是"profile 名留在产品面、内核保持中性"的落地方式。
语义与 CI 对齐
semantic_alignment = new_semantics_justified(candidate_decision = create_vocabulary)。本 head 新增的词表是面向行为命名的 outcome_routing_* 家族,产品名只留在 CLI 与参考文档;与 semantic vocabulary convergence RFC 的"按语义角色收敛、不按名字合并枚举"一致。本 head 的 semantic-vocabulary-drift-smoke: ok,tsc --project tsconfig.control-plane.json --noEmit 退出 0,聚焦 TS 16 过、Python 10 过。CI 侧按管理策略不轮询远端检查,只使用本 head 的本地必需验证;packaged wheel 安装/打包 CLI smoke 未在本 head 复跑,已如实计入 residual risk,不作为"已通过"。
English verdict: APPROVE - reviewed exact head bbdf631. The previous blockers are resolved at this head: kernel-facing modules, effect ids and schemas are now domain-neutral (outcome_routing_*), the shared target_key default change and its tests are fully reverted (zero diff on monitor_metadata.ts and its suites), human-lane correlation identity moved into the profile's own revisioned bindings, and the producer-less legacy upgrade path was removed. Validation at this head: 16 focused TS tests pass, 10 focused Python tests pass, tsc control-plane exit 0, semantic drift smoke ok; no shared surface is modified. One non-blocking item: the PR description is stale (it still documents the reverted shared default change, old module names, and outdated test counts) and should be updated before merge so the merge record matches the reviewed head.
Summary
Roadmap and placement
This change aligns with the LoopX Overall Roadmap v0 as a bounded S1/S3 profile over the existing Goal, Todo, evidence, quota, and replan owners. It does not create a second steward, work ledger, scheduler, authority store, or provider.
Kernel-facing modules, effect IDs, and schemas use the neutral
outcome_routing_*vocabulary. Thecompany-control-loopname remains at the product-facing CLI and documentation layer. Work-item to Todo identity is stored in the profile's own revisioned bindings, so shared Todo metadata rules remain unchanged.The current acceptance boundary is the CLI and packaged-runtime lifecycle in this PR. Broader R2/R3 steward claims still require real multi-Agent adoption, dependent artifacts, independent acceptance, restart recovery, and automatic result return through their existing owners. The English and Chinese roadmap mirrors link this profile and record that boundary.
Implementation
outcome_routing_plan.tsvalidates bounded, public-safe, unique outcomes, work items, target keys, and feedback; it routes work by authority and capability facts.outcome_routing_state.tsowns atomic persistence, exact revision checks, profile-localwork_item_id -> todo_idbindings, reconciliation, deterministic bounded feedback IDs, and next-cycle planning.company_control_loop.pyadapts CLI commands to the managed TypeScript owners and reuses governed Todo add/list paths.sync-todossets sharedtarget_keyonly for Agent Todos; human decision/action correlation stays in the profile's own state.Validation
npm run typecheck:control-planepassedmain; all commits carry DCO sign-offDelivery boundary
This PR delivers the typed planning profile, state lifecycle, governed Todo projection, evidence reconciliation, next-cycle planning, operator documentation, and the six v0 lifecycle scenarios. It does not claim R2/R3 multi-Agent steward qualification. Merge remains with the maintainer.