Skip to content

Settle governed continuous-monitor proposals in the Kernel - #3511

Merged
huangruiteng merged 2 commits into
mainfrom
codex/governed-monitor-proposal-settlement-20260823
Aug 23, 2026
Merged

huangruiteng merged 2 commits into
mainfrom
codex/governed-monitor-proposal-settlement-20260823

Conversation

@huangruiteng

Copy link
Copy Markdown
Collaborator

Summary

  • add an optional, bounded transition_contract to governed external-write operations
  • validate continuous-monitor proposals at the TypeScript authority boundary
  • materialize admitted monitor upserts and completions through LoopX-owned Todo APIs
  • checkpoint content-bounded transition receipts in the governed journal for crash-safe replay
  • document the provider/Kernel ownership boundary and add synthetic end-to-end coverage

Motivation

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-plane
  • npm run test:control-plane (103 passed)
  • python3 examples/docs-governance-smoke.py
  • python3 -m loopx.cli canary premerge --from-git-diff --tier standard --format json --no-progress
  • public-boundary scan clean for all 9 changed files

Safety properties

  • provider receives no registry path and cannot call Todo APIs directly
  • proposals outside the exact profile authority fail before state mutation
  • running results cannot complete monitors
  • another Agent's monitor and completed monitors cannot be mutated
  • a crash after Todo mutation but before receipt checkpoint replays without duplicate monitors
  • legacy journals with no transition proposals remain readable

Signed-off-by: huangruiteng huangrt01@163.com

@huangruiteng

Copy link
Copy Markdown
Collaborator Author

@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 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.

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>
@huangruiteng
huangruiteng force-pushed the codex/governed-monitor-proposal-settlement-20260823 branch from f01adcd to b19a8ac Compare August 23, 2026 06:48
@sonarqubecloud

Copy link
Copy Markdown

@huangruiteng

Copy link
Copy Markdown
Collaborator Author

Self-review of exact head b19a8aca29f9b02043bc031c91dd9de85ce747da

I rebased, re-reviewed, and refined this PR against the current main.

Resolved blocker:

  • The previous head materialized continuous_monitor_complete before durable Turn writeback. A rejected writeback or spend could therefore leave the invocation settlement_failed while its only recovery monitor was already done.
  • Monitor upsert is now an explicit pre-settlement transition. Monitor completion is an explicit post-settlement transition and runs only after the shared writeback-before-spend transaction commits.
  • A failed writeback or spend leaves the monitor open. The next reconcile reuses the already observed terminal provider result and does not invoke the provider again.
  • Post-settlement completion remains crash-safe: if the Todo mutation happens before its journal checkpoint, the stable completion key replays the same completion and the missing receipt is restored.

Bounded TypeScript refinement:

  • The provider proposal decoder now narrows kind with a runtime literal decoder into a discriminated union.
  • Exhaustive switch dispatch plus assertNever replaces the former arbitrary-string/null fallback, so adding a new proposal kind requires an intentional decode branch at compile time.
  • Runtime validation remains mandatory because provider JSON is external input; the TS union governs only values after decoding.

Authority and scope judgment:

  • The provider still receives no registry path and cannot call Todo APIs.
  • Manifest/profile allowlists and the TS boundary constrain exact proposal kind, monitor identity, action, target, and required capabilities.
  • Python performs only the LoopX-owned Todo side effects through existing APIs and shared Turn settlement; no provider-specific state authority or second lifecycle was added.
  • The 1.2k-line total PR is a cohesive vertical slice rather than a leaf migration: manifest contract, TS admission, Kernel materialization, journal replay, docs, and negative tests ship together.

Validation:

  • npm run typecheck:control-plane: passed
  • npm run test:control-plane: 107 passed
  • focused governed execution and admission suite: 41 passed
  • uvx ruff check --select E,F,I on changed Python: passed
  • docs governance smoke: passed
  • loopx canary premerge --from-git-diff --goal-id loopx-meta --tier standard: 10 selected checks passed, 0 failures, 0 manual holds
  • public/private boundary scan: clean
  • change-quality receipt cqr_07696598d4a5ba8245f9: valid for the exact base and diff
  • exact-head GitHub checks: 8 passed, 3 deployment/publish jobs skipped as expected, 0 failures; the initially concurrency-cancelled Frontstage build was rerun and passed

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.

@huangruiteng
huangruiteng merged commit 7a243e0 into main Aug 23, 2026
11 of 13 checks passed
@huangruiteng
huangruiteng deleted the codex/governed-monitor-proposal-settlement-20260823 branch August 23, 2026 06:59
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