Repository navigation
Settle governed continuous-monitor proposals in the Kernel - #3511
Conversation
|
@maxliu Could you review the provider/Kernel authority boundary and replay semantics here? This deliberately limits the first version to continuous-monitor upsert/completion and keeps all Todo mutation inside the Kernel. |
huangruiteng
left a comment
There was a problem hiding this comment.
Request changes conclusion (author-owned PR; GitHub blocks formal self-review)
Findings
[P1] 不要在 durable writeback 成功前完成唯一的重试 monitor
终态 reconcile 在 loopx/extensions/governed_capability_execution.py:608-615 先调用 _settle_journal_transition_proposals,而 continuous_monitor_complete 又在 loopx/control_plane/work_items/governed_transition_proposal.py:205-245 以 no_followup=True 直接把 monitor 标成 done。随后 execute_turn_driver_settlement 才从 loopx/extensions/governed_capability_execution.py:642-692 尝试 durable writeback。触发条件是 provider 已返回 terminal receipt 和 monitor-complete proposal,但 writeback callback 拒绝、抛错或只缺少 effect_receipt_digest。这时外部结果尚未写入 LoopX 的正式 settlement surface,函数返回 settlement_failed,但负责后续 reconcile 的 continuous monitor 已经关闭且没有 successor;如果 host 没有在同一进程外额外保留重试,自动化会永久失去恢复入口。现有 test_material_settlement_fails_closed_without_effect_receipt_writeback 只断言 spend 没有执行,没有检查 monitor 仍可调度,所以没有覆盖这个 liveness 破坏。
最小修复:把 continuous_monitor_complete 的物化延后到 durable writeback 已通过之后(至少不能早于 successful writeback receipt);running/upsert proposal 仍可立即 checkpoint。若完整 settlement 失败,保留原 monitor 为 open,或原子创建一个明确的 settlement-retry successor。增加负向回归:终态 provider + rejected writeback 后,journal 为 settlement_failed,原 monitor 仍为 open/可重试;下一次 reconcile 成功时才完成它,并且 provider 不重复执行。
动机
这个 PR 要消除外部 provider 私有适配层:provider 只提交 provider-neutral 的 continuous-monitor upsert/complete proposal,LoopX Kernel 负责把它验证、物化、回放并纳入同一个 effect journal。旧路径能得到 provider 的 typed proposal,却没有一个受 profile allowlist 约束的通用 Todo 落地边界;每个集成都要自行持有 registry/Todo 权限,容易形成第二套状态权威。新的目标是 provider 不接触 registry,也不能任意改 Goal,仅能在 operation profile 明确允许的 monitor identity、action、target 和 capability 范围内提案。这个动机成立,而且比让各 provider 直接调用 Todo API 更小、更安全。
改动思路
入口仍是 start_governed_external_capability / reconcile_governed_external_capability。manifest 的 transition_contract 是权威输入;TypeScript validateGovernedCapabilityResult 负责 proposal kind、字段、前缀、capability 和 running/terminal 约束;Python bridge 只接收已验证结果,并由新的 work-item 模块调用现有 Todo API。每次物化后立刻写 content digest receipt 到 mode-0600 invocation journal,所以“Todo 已改、receipt 尚未落盘”的 crash 可由 stable monitor key / completion identity 重放。正向路径和越权拒绝路径都清楚。问题不在 admission,而在 effect ordering:当前把 terminal monitor completion 当成普通 proposal 提前执行,使它越过了后面的 durable-writeback gate。
具体改动
生产代码为 706+/5-:TypeScript validation/dispatch 204+/2-,Kernel proposal materializer 310+,governed execution bridge 77+,manifest schema 115+/3-。测试为 322+/1-,文档为 42+/5-;没有 generated 或机械搬迁。范围虽然大,但围绕一个完整 vertical slice,存在真实调用点,不是 coverage-only scaffolding。
关键代码讲解
validateTransitionProposals(loopx/control_plane/governed_capability.ts:148)把 profile allowlist 变成 typed fail-closed admission:running 只能 upsert,terminal 才能 complete,并限制 exact fields、key/action/target/capability。这里是正确的 provider/Kernel authority boundary。_upsert_monitor/_complete_monitor(loopx/control_plane/work_items/governed_transition_proposal.py:136,205)复用正常 Todo API,约束 task class 和 Agent ownership,并用 stable binding/completion key 支持 replay。问题是 complete 自身没有 settlement-phase gate。_settle_journal_transition_proposals(loopx/extensions/governed_capability_execution.py:378)逐 proposal checkpoint,解决 mutation-before-receipt crash;但 reconcile 在 writeback 前调用它,因此同一 helper 同时承载了“可立即落地的 upsert”和“必须等 durable writeback 的 complete”两种不同 phase 语义。reconcile_governed_external_capability(loopx/extensions/governed_capability_execution.py:565)随后复用共享 Turn settlement driver,保留 writeback-before-spend;目前新增 monitor completion 没有进入这个 ordering contract。
对主干的风险
权限面总体收窄:provider 没有 registry path,manifest 与 TS 双层约束 proposal,另一个 Agent 的 monitor、非 monitor Todo 和 completed monitor 都会 fail closed。默认行为也是 opt-in 的 transition_contract,没有静默改变已有 provider。文档把这是机器强制的 allowlist/settlement obligation 讲清楚,文本保持 domain-neutral。
主干阻塞风险是上述 liveness 顺序。最强失败场景不是 provider 重复 side effect,而是 terminal external effect 已发生、Kernel 提前关掉唯一 monitor、durable writeback 又失败;此后 public Goal state 没有完整 effect receipt,也没有 due monitor 触发 recovery,只剩 private journal。回滚可以重新打开 monitor 或手工重跑 reconcile,但这违背本 PR 要提供的 crash-safe autonomous path。最小修复和负向用例都局限在 reconcile phase ordering,不需要扩大 capability contract。
验证矩阵:exact head f01adcd4ce3861ad0ca8085628a207d0da8c0e06;GitHub 11 个 checks 全绿;本地 exact-head TS focused test 11/11;本地 uv run --with pytest 的两组 extension tests 40/40;Python compile 通过;git diff --check 通过。npm run typecheck:control-plane 在隔离 worktree 因本机没有 tsc 跳过,但 PR 声明的 typecheck 与远端 checks 无失败。现有验证足以确认 admission/replay 主路径,也恰好暴露缺少“writeback failure keeps monitor open”的语义断言。
我的整体评价
架构方向、capability placement 和 typed authority boundary 都是对的:这是 existing governed external-write contract 的可选扩展,不应另建 capability;新的 Python module也有直接 caller,并显著减少 provider 私有 authority。代码量大但基本必要,最高价值的 bounded refine 是按 settlement phase 拆分 upsert 与 completion 的 materialization,而不是再加抽象层。
当前结论仍是阻塞合并:请先修复 terminal completion 的 writeback ordering,并补充负向 liveness 测试;其余未发现新的 blocking finding。修复后应重新读取 exact head,并重跑 focused TS/Python tests 和 repository-required checks。
English summary: The provider/Kernel boundary and typed allowlists are sound, but a terminal continuous_monitor_complete is materialized before durable writeback. If writeback fails, the invocation becomes settlement_failed while the only retry monitor is already done with no successor, which can strand automatic recovery. Defer monitor completion until successful durable writeback (or atomically create a retry successor), and add a regression proving a rejected writeback leaves the monitor schedulable.
English verdict: REQUEST_CHANGES
Signed-off-by: huangruiteng <huangrt01@163.com>
Signed-off-by: huangruiteng <huangrt01@163.com>
f01adcd to
b19a8ac
Compare
|
|
Self-review of exact head I rebased, re-reviewed, and refined this PR against the current Resolved blocker:
Bounded TypeScript refinement:
Authority and scope judgment:
Validation:
Future-facing refactor pass: applied. The related phase split and discriminated TS decoder make the next governed proposal kind harder to add incorrectly without introducing a generic schema framework. Verdict: no remaining blocking finding after the phase-ordering repair; merge once exact-head CI is green. |



Summary
transition_contractto governed external-write operationsMotivation
Long-running external providers can already return typed transition proposals, but integrations still need a private adapter to turn those proposals into durable LoopX monitor state. This change closes that provider-neutral gap without giving providers registry access or arbitrary Goal mutation authority.
The first version deliberately supports only bounded continuous-monitor upsert and completion. The integration profile allowlists proposal kinds, monitor-key prefixes, action kinds, target-key prefixes, and required capabilities.
Validation
python3 -m pytest -q tests/extensions/test_governed_capability_execution.py tests/extensions/test_external_capability_admission.py(40 passed)npm run typecheck:control-planenpm run test:control-plane(103 passed)python3 examples/docs-governance-smoke.pypython3 -m loopx.cli canary premerge --from-git-diff --tier standard --format json --no-progressSafety properties
Signed-off-by: huangruiteng huangrt01@163.com