Skip to content

refactor(todos): unify authoring scope and explicit global gate intent - #4142

Merged
huangruiteng merged 3 commits into
mainfrom
codex/todo-update-target-admission
Sep 9, 2026
Merged

huangruiteng merged 3 commits into
mainfrom
codex/todo-update-target-admission

Conversation

@huangruiteng

Copy link
Copy Markdown
Collaborator

Summary

  • Move public Todo add/update role, continuation binding, gate scope and deferred-condition admission into todos/authoring_scope.ts. Retire todos/write_policy.py and duplicated Python scope selection. Product code under loopx/ is net -62 lines.
  • Reuse the resolved User scope invariant in native terminal successor validation, without running draft inference there or expanding execution permission.
  • Make the all-agent impact of --global-gate explicit in CLI help, actionable errors and the Todo contract. --goal-bound scopes continuation, not blocking; absent scope never becomes a global gate.
  • Update both RFCs in both languages: this closes the T1 authoring-scope prerequisite, not the full native update transaction. Existing roadmaps and promotion holds remain.

Issue Or Task

T1 follow-up to the TypeScript control-plane migration and shared Goal Authority RFC execution cards after #4137.

Intentional behavior corrections

  1. Explicit global scope plus an author identity is accepted; author defaults no longer invent a conflicting lane gate.
  2. Explicit blocks_agent determines the corresponding continuation binding, even when the author belongs to another lane.
  3. Contradictory explicit binding/scope flags are rejected without a write, rather than silently overwritten during update.

Existing omitted scope, completed-history repair, mutation authorization, completion checks, lease fences and CAS/replay remain. To narrow a global gate, use --clear-global-gate --blocks-agent <agent>; widening a lane gate requires --clear-blocks-agent --global-gate. These commands do not grant user decision authority or waive existing mutation checks.

Validation

  • Tested revision: cb1c94aba (final working-tree contents validated before the two content-identical commits).
  • Run state: finished
  • Input classes: synthetic, public_fixture
Check kind Result Public-safe evidence / limitation
static passed npm run typecheck:control-plane, touched-file Ruff, repository-defined python -m mypy (21 files), new Python adapter checked separately with --follow-imports=silent, and git diff --check.
regression_parity passed Before implementation, the focused authoring tests had 5 failures and 3 passes on the base. The five failures cover the intentional scope corrections above. Three source mutants for implicit global widening, overwriting explicit binding and mismatched successor binding were killed; their unmodified controls passed.
real_entrypoint passed 193 focused Python tests: authoring scope, mutation authority, field update, external wait, decision-scope lifecycle, local authority, shadow/native update, split-root fence, completion transaction and maintainability ratchet. Includes actual CLI add/update, dry-run/no-write and persisted readback. CLI help inspected through python -m loopx.cli todo --help.
integration passed npm run test:control-plane: 934 passed, zero skips with PostgreSQL enabled. Includes File/NoKV conformance, real terminal User-successor materialization and production-scale fixtures. NoKV uses the existing test backend, not a live NoKV deployment.
real_backend passed PostgreSQL 16.15 from Homebrew, disposable isolated server/database and synthetic tenant scopes: all 34 integration/conformance tests passed as part of the full run. No active Goal, registry or lease state was modified.
static failed An additional non-CI strict mypy invocation on broad legacy entrypoints followed their imports and reported 2,678 errors across 307 files outside the repository's selected 21-file check. This PR does not claim those entrypoints are fully strict-typed; the configured check and new adapter check above pass.

Coverage and gaps: the first PostgreSQL-enabled full run exposed a timing-dependent claim-race test: a late reader can correctly reject ownership before reaching CAS. The test now synchronizes the first two real reads, preserving the exact applied/conflict assertion; the separate late-reader owner-rejection assertion remains. The final full run passes. An initial test-harness use of Promise.withResolvers was rejected by the configured TS library target and replaced without changing that target. Full Python repository suite, a live NoKV deployment and promotion/soak qualification were not run or claimed.

Scope And Architecture Review

  • Owner: existing core Todo domain; no new capability or extension/provider distribution. Python transports facts and invokes the typed result; it does not recreate binding policy.
  • Future-facing pass: applied by sharing the resolved invariant with terminal successors and deleting duplicate Python rules. Native update retains its text/note allowlist; metadata/effect/CAS transaction closure remains separate T1/T2 work.
  • Admission is not authorization or a commit receipt. No provider default, promotion, hard-lease authority or completion policy change. This is not advertised as an entirely behavior-preserving refactor: the three corrections above are explicit.
  • No prose classifier, benchmark-specific rule or optional feature was introduced. The global-gate rule is enforced, not advisory; its CLI explanation is guidance for choosing the intended scope.
  • The adapter adds a bounded TS planning call on public authoring; this PR makes no latency-reduction claim. Coalescing that with the full typed update transaction belongs to the remaining T1 work.

Shared-authority RFC Fixture Impact

  • Fixture schema: loopx_coordination_production_scale_fixture_v0.
  • Dimensions: User binding/global/lane scope; existing complex terminal lifecycle and archive dimensions remain exercised. Added actual User-successor readback to shared conformance in both native and legacy record shapes.
  • Provider arms: File, NoKV test backend, isolated real PostgreSQL.
  • Read-only legacy/file/PostgreSQL three-arm promotion rehearsal: not applicable to this admission-only change; no promotion, runtime routing or compatibility projection change. D1–D3 evidence requirements remain intact.

Delivery

  • Base branch: main at f24a93411c7e2096687590fff544c37207ab582f.
  • Two DCO-signed commits: runtime/regression validation, then public contract/RFC updates.
  • Classification/privacy scan: only core product, durable validation and public docs included. No credentials, local state, raw evidence, private links or local paths are included in the diff or this body.
  • Temporary local Git-hook bypass was explicitly authorized for this branch/PR only; no permanent gate changes. Not self-merging.

@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-request-changes)

动机

这个 PR 要解决的方向是对的:Todo authoring 的 binding/gate 语义不应由 Python 和 TypeScript 各维护一套,global_gate 也不能由 author identity、缺失 binding 或 goal_bound 暗中推导。完整 diff 显示,新 planner 把 explicit global、lane-local gate、continuation binding 和 deferred resume 规则集中到 typed TypeScript boundary,并让 terminal successor 复用 resolved-scope conflict 规则;这比继续补 Python 条件更可靠。

改动思路

planTodoAuthoringScope 只根据显式 intent、现有 Todo 与 registered agents 规划 scope,不授予 lifecycle/write authority。global gate 必须显式 global_gate=true 并配 goal-wide continuation;lane gate 必须让 blocks_agent === bound_agent;update 省略字段保持原 scope,widen/narrow 需要相应 clear + replacement。Python adapter 只传事实并把 TS rejection 转成写入前的 ValueError,现有 provider/legacy transaction 继续拥有 commit。

正向语义在 focused tests 中成立,但当前 exact head 还不能进入主干:PR 自己改动的 provider-conformance fixture 使用了仓库 Node 22.6 strip-types 不支持的局部变量 definite-assignment 语法,required check 在载入测试时直接 SyntaxError。

具体改动

完整 diff 为 16 个文件、+572/-339。生产侧新增 authoring_scope.ts 和窄 Python adapter,删除旧 write_policy.py,接入 todo add/update、effect handler 与 terminal successor validation;测试、mutants 和双语文档覆盖显式 global/lane scope 与反例。

关键代码讲解

  1. authoring_scope.ts 将 global_gate、goal_bound、blocks_agent、bound_agent 的合法组合放到一个 typed owner;userTodoScopeConflict 同时供 terminal lifecycle 验证 resolved successor。
  2. todos.py 通过事实 adapter 获取有效 scope,再复用现有 write transaction;没有把 commit/permission 移入 adapter。
  3. scope tests 和 mutants 能抓住 global inferred、explicit scope overwritten、successor unbound 等语义倒退。
  4. 阻塞点在 tests/control_plane_ts/authority_store_conformance.ts:1111:let releaseReaders!: () => void 通过 tsc,本地 Node 25 也能运行;但 CI 的 Node 22.6 --experimental-strip-types 去掉类型标注后留下 !,报 SyntaxError: Unexpected token '!'。这导致 control-plane suite 4 个 imported provider case 失败,进而 checks、pytest aggregator 与 merge-gate 全红。

对主干的风险

这不是 transient CI:失败精确落在当前 PR 新增的语法,job 102461626171 可稳定读回错误。我的本地 Node 25 验证 40 个 focused TS tests 通过,typecheck、Ruff 和 16 个 focused Python/native semantics tests 通过;两者反而说明“新 runtime/typecheck 绿色”不能证明仓库支持的 Node 22 执行路径。当前 full control-plane validation 在执行 provider conformance 之前就终止,因此不能用其它 shard 绿色替代。

最小修复是把该声明改成 Node-22 strip-types 可接受的初始化/类型写法,同时保留“两次真实 read 都拿到同一 head 后才 release”的 race barrier,然后用 CI 同一 Node 22 命令跑完整 suite。不要删除 barrier 或只改成普通 Promise.all,否则 CAS race regression 又会退回非确定性。

Future-facing pass:typed scope 的抽取与 terminal reuse 已经是有价值的 bounded consolidation;无需再扩大框架。修复 runtime compatibility 后,应继续保留全套 explicit/missing/contradictory counterfactuals。

我的整体评价

REQUEST_CHANGES 当前 exact head cb1c94aba5031f402a2d5f6b018098a8ccf85216。

Scope 设计与主要语义证据可信,但 required repository runtime 当前无法解析 PR-owned test code,完整门禁并未通过。修复这一处 Node 22 compatibility blocker、跑绿完整 control-plane checks 后即可复审;未发现需要推翻当前 authoring-scope 架构的其它 blocker。

English verdict: REQUEST_CHANGES — exact head cb1c94aba5031f402a2d5f6b018098a8ccf85216 has a sound typed authoring-scope direction, but its new let releaseReaders!: () => void fixture syntax fails the repository's Node 22.6 strip-types runtime before provider conformance runs. Replace it with Node-22-compatible initialization while preserving the two-reader race barrier, then rerun the complete required control-plane workflow.

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

动机

这个 PR 要解决的方向是对的:Todo authoring 的 binding/gate 语义不应由 Python 和 TypeScript 各维护一套,global_gate 也不能由 author identity、缺失 binding 或 goal_bound 暗中推导。完整 diff 显示,新 planner 把 explicit global、lane-local gate、continuation binding 和 deferred resume 规则集中到 typed TypeScript boundary,并让 terminal successor 复用 resolved-scope conflict 规则;这比继续补 Python 条件更可靠。

改动思路

planTodoAuthoringScope 只根据显式 intent、现有 Todo 与 registered agents 规划 scope,不授予 lifecycle/write authority。global gate 必须显式 global_gate=true 并配 goal-wide continuation;lane gate 必须让 blocks_agent === bound_agent;update 省略字段保持原 scope,widen/narrow 需要相应 clear + replacement。Python adapter 只传事实并把 TS rejection 转成写入前的 ValueError,现有 provider/legacy transaction 继续拥有 commit。

正向语义在 focused tests 中成立,但当前 exact head 还不能进入主干:PR 自己改动的 provider-conformance fixture 使用了仓库 Node 22.6 strip-types 不支持的局部变量 definite-assignment 语法,required check 在载入测试时直接 SyntaxError。

具体改动

完整 diff 为 16 个文件、+572/-339。生产侧新增 authoring_scope.ts 和窄 Python adapter,删除旧 write_policy.py,接入 todo add/update、effect handler 与 terminal successor validation;测试、mutants 和双语文档覆盖显式 global/lane scope 与反例。

关键代码讲解

  1. authoring_scope.ts 将 global_gate、goal_bound、blocks_agent、bound_agent 的合法组合放到一个 typed owner;userTodoScopeConflict 同时供 terminal lifecycle 验证 resolved successor。
  2. todos.py 通过事实 adapter 获取有效 scope,再复用现有 write transaction;没有把 commit/permission 移入 adapter。
  3. scope tests 和 mutants 能抓住 global inferred、explicit scope overwritten、successor unbound 等语义倒退。
  4. 阻塞点在 tests/control_plane_ts/authority_store_conformance.ts:1111:let releaseReaders!: () => void 通过 tsc,本地 Node 25 也能运行;但 CI 的 Node 22.6 --experimental-strip-types 去掉类型标注后留下 !,报 SyntaxError: Unexpected token '!'。这导致 control-plane suite 4 个 imported provider case 失败,进而 checks、pytest aggregator 与 merge-gate 全红。

对主干的风险

这不是 transient CI:失败精确落在当前 PR 新增的语法,job 102461626171 可稳定读回错误。我的本地 Node 25 验证 40 个 focused TS tests 通过,typecheck、Ruff 和 16 个 focused Python/native semantics tests 通过;两者反而说明“新 runtime/typecheck 绿色”不能证明仓库支持的 Node 22 执行路径。当前 full control-plane validation 在执行 provider conformance 之前就终止,因此不能用其它 shard 绿色替代。

最小修复是把该声明改成 Node-22 strip-types 可接受的初始化/类型写法,同时保留“两次真实 read 都拿到同一 head 后才 release”的 race barrier,然后用 CI 同一 Node 22 命令跑完整 suite。不要删除 barrier 或只改成普通 Promise.all,否则 CAS race regression 又会退回非确定性。

Future-facing pass:typed scope 的抽取与 terminal reuse 已经是有价值的 bounded consolidation;无需再扩大框架。修复 runtime compatibility 后,应继续保留全套 explicit/missing/contradictory counterfactuals。

我的整体评价

REQUEST_CHANGES 当前 exact head cb1c94aba5031f402a2d5f6b018098a8ccf85216。

Scope 设计与主要语义证据可信,但 required repository runtime 当前无法解析 PR-owned test code,完整门禁并未通过。修复这一处 Node 22 compatibility blocker、跑绿完整 control-plane checks 后即可复审;未发现需要推翻当前 authoring-scope 架构的其它 blocker。

English verdict: REQUEST_CHANGES — exact head cb1c94aba5031f402a2d5f6b018098a8ccf85216 has a sound typed authoring-scope direction, but its new let releaseReaders!: () => void fixture syntax fails the repository's Node 22.6 strip-types runtime before provider conformance runs. Replace it with Node-22-compatible initialization while preserving the two-reader race barrier, then rerun the complete required control-plane workflow.

@huangruiteng
huangruiteng force-pushed the codex/todo-update-target-admission branch from cb1c94a to 7dd415f Compare September 9, 2026 13:17
Signed-off-by: huangruiteng <huangrt01@163.com>
Signed-off-by: huangruiteng <huangrt01@163.com>
Signed-off-by: huangruiteng <huangrt01@163.com>
@huangruiteng

Copy link
Copy Markdown
Collaborator Author

Review resolution and merge evidence

The Node 22.6 blocker is fixed at exact head 7b217323f789f1348e1e3d4d3b26981b2d99d620.

Decision on the CI Node version

I did not raise the CI runtime. LoopX 1.0.2 publicly supports Node.js 22.6+, and the required workflows intentionally exercise that minimum. Moving CI to a newer Node would hide a compatibility regression from already-supported installations rather than fix it.

The provider-conformance race barrier now initializes its resolver with a fail-fast function before the Promise constructor replaces it synchronously. The barrier still holds both real authority reads at the same head; the emitted JavaScript is valid for Node 22.6 native strip-types.

Product and architecture judgment

The PR's typed authoring-scope direction remains sound: binding and gate admission have one TypeScript owner, terminal successors reuse the resolved-scope invariant, and Python remains a fact/rejection adapter rather than a second policy engine. The fix is intentionally limited to the test runtime compatibility defect and does not widen Node requirements, Todo permissions, provider defaults, or promotion scope.

Validation

  • Required GitHub workflow: Python Tests run 34356249996 passed Node 22.6 control-plane coverage, both complete pytest shards, Stage 2C E2E/mutants/installed, Windows, aggregate coverage, and the repository merge gate.
  • Local minimum-runtime validation: complete TypeScript control-plane suite passed on Node 22.6; the three directly affected File/NoKV entrypoints passed 100 tests.
  • Real backend: isolated PostgreSQL 16 conformance passed 34/34, including CAS competition, rollback, lost-response recovery, and tenant RLS.
  • Focused Python entrypoints: 65/65 passed. TypeScript typecheck, configured strict mypy (21 files), adapter mypy, touched-file Ruff, diff hygiene, and the public/private scan passed.
  • Exact change-quality receipt: cqr_595f77ebb0e1ed802579, fingerprint 595f77ebb0e1ed8025793add6b196dd36847688554c6d6016eac7a1b825f1a52, valid with zero unresolved blockers.
  • Local risk canary: 17/18 selected checks passed, with zero manual holds. The only failure was the pre-existing hot-path budget (dashboard_status_json: 18,387 vs 18,215); the exact origin/main baseline and this candidate produce the same 18,387 bytes, and this PR does not change the dashboard/status surface. This inherited main drift is disclosed rather than represented as green.

No additional review blocker was found. With the owner's explicit authorization in the task, the merge decision is self-merge after required GitHub checks.

@huangruiteng
huangruiteng merged commit bc18304 into main Sep 9, 2026
19 checks passed
@huangruiteng
huangruiteng deleted the codex/todo-update-target-admission branch September 9, 2026 13:35
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