Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
# Complete durable-completion evidence read (2026-11-02)

The built-in `turn run-once` provider is the only production consumer of the
Python durable-completion projection. Its intent, post-completion, ordinary
recovery and terminal recovery now use the existing `todo.read` transaction.
`todos/read_transaction.ts` collects canonical source pages in process;
`todos/read_projection.ts` composes the existing completion fence and owns
continuation/recovery validation, successor existence and result construction.
Canonical refusal never falls back to stale Markdown. Fence rejection retains
precedence over continuation projection during recovery.

## Economics and retained boundary

Instrumented File/SQLite reads measure ordinary recovery **2 → 1**, terminal
Comment thread
loopx-agent marked this conversation as resolved.
Resolved
recovery **2 → 1**, intent **1 → 1**, post-completion **1 → 1**, and explicit legacy
materialized reads **0 → 1** Python/TypeScript calls. Canonical collection stays
inside the request, including pagination. The legacy increase removes its Python
semantic authority; it is not a latency improvement claim.

Deleted Python authority includes `_project_durable_completion`, terminal fence
composition, the separate Turn fence call and the entire `completion_fence.py`
facade, and the obsolete public persisted-record readers. No string-dispatch consumer remains for `todo.completion_fence.evaluate`,
so its registration is removed. Native fence imports and tests remain.

Python retains registry/path resolution, legacy Markdown observation/decoding,
Python scalar/container encoding, rejection exception compatibility and transport.
The canonical source-result decoder is shared with existing authority reads to
preserve unavailable/refusal error types without an extra provider request.
Compatibility projection functions delegate to the same complete native owner;
they do not interpret continuation or recovery.

The facade exits when `turn run-once` is native and no Python caller requires
legacy persisted-format observation or the projection import contract. The
completion-evidence read kind can then become an in-process call; the ordinary
`todo.read` operation remains for other Python consumers. Characterization
fixtures may retire with that facade after independent native coverage retains
its negative cases. No long-horizon effectiveness/efficiency benefit is claimed.

## Evidence and scope
Comment thread
loopx-agent marked this conversation as resolved.
Resolved

The pre-cutover corpus pins 83 complete JSON observations, exact diagnostics,
field absence and ordered missing-successor lists. Baseline instrumentation and
existing focused tests passed before authority moved; expected bytes remain
unchanged. Native fence tests remain independent of that corpus. Real CLI checks
cover File/SQLite crash-after-completion recovery and stale-display identity.
The delivery report records exact commands, results, source line deltas and any
unqualified gates. No storage format, write authority, scoring or default setting
changes are intended. This internal read refactor uses the existing CLI journey
and adds no capability or configuration surface.

Wheel and sdist were installed into separate fresh Python 3.12 environments.
Each installed package executed completion evidence, canonical refusal and a
real canonical recovery while importing solely from `site-packages`; all three
checks passed.

Matched default-SQLite qualification used the pinned base `867615e2c` and this
head with the same synthetic fixture, 32 cold starts, 128 warm typed requests,
64 complete canonical transactions, 64 full-CLI recovery transactions and a
256-request burst. The base → head results are: cold-start p50/p95
115.522/128.518 → 102.829/135.269 ms; complete transaction
68.774/103.729 → 9.806/14.320 ms; full CLI recovery
358.661/611.397 → 264.324/334.687 ms; process-tree RSS
30/30 → 32/33 MiB idle/burst. The cold-start p95 difference is +6.747 ms
(+5.25%) with a lower median, below the 25 ms additive allowance. The typed
warm request includes the persisted remote read; it is not the non-durable
in-process kernel budget. The complete transaction and operator CLI both
improve materially on the matched SQLite baseline.
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
# 完整 durable-completion 证据读取(2026-11-02)

内置 `turn run-once` provider 是 Python durable-completion 投影的唯一生产消费者。
其 intent、完成后读取、普通恢复和终态恢复现在复用既有 `todo.read` 事务。
`todos/read_transaction.ts` 在进程内收集 canonical 来源分页;
`todos/read_projection.ts` 组合既有 completion fence,负责 continuation/recovery
验证、后继存在性检查和结果构造。canonical 拒绝不会回退到陈旧 Markdown。
恢复时 fence 拒绝仍优先于 continuation 投影。

## 经济性与保留边界

File/SQLite 插桩测得 Python/TypeScript 调用数:普通恢复 **2 → 1**、终态恢复
**2 → 1**、intent **1 → 1**、完成后读取 **1 → 1**、显式 legacy materialized
读取 **0 → 1**。canonical 收集(含分页)留在请求内部。legacy 增加一次调用是为了
删除 Python 语义权限,不据此声称延迟改善。

删除的 Python 权限包括 `_project_durable_completion`、终态 fence 组合、Turn
独立 fence 调用、整个 `completion_fence.py` facade 及已过时的公开持久记录读取接口。
`todo.completion_fence.evaluate` 已无字符串分派消费者,因此删除其注册;原生
fence 导入和测试保留。

Python 保留 registry/路径解析、legacy Markdown 观察与解码、Python 标量/容器
编码、拒绝异常兼容和传输。canonical 来源结果解码器与现有权限读取共享,以在
不增加 provider 请求的情况下保留不可用/拒绝的异常类型。兼容投影函数委托同一个
完整原生 owner,不解释 continuation 或 recovery。

当 `turn run-once` 原生化,且没有 Python 调用者需要 legacy 持久格式观察或投影
导入契约时,删除 facade。completion-evidence 读取种类届时可改成进程内调用;
其他 Python 消费者使用的普通 `todo.read` 操作继续保留。独立原生覆盖保留负例后,
刻画 fixture 可随该 facade 退役。不声称长程效果/效率收益。

## 证据与范围

迁移前语料固定 83 个完整 JSON 观察、精确诊断、字段缺席及有序缺失后继列表。
权限迁移前,基线插桩和既有聚焦测试通过;期望字节保持不变。原生 fence 测试
独立于该语料。真实 CLI 检查覆盖 File/SQLite 完成后崩溃恢复和陈旧展示身份。
交付报告记录精确命令、结果、源码行增减及尚未合格的门禁。不计划改变存储格式、
写入权限、计分或默认设置。此内部读取重构复用现有 CLI 旅程,不增加能力或配置界面。

wheel 与 sdist 分别安装到全新的 Python 3.12 环境。两个安装包均只从
`site-packages` 导入,并执行 completion evidence、canonical 拒绝和真实
canonical recovery;三项检查全部通过。

默认 SQLite 的同条件资格使用固定 base `867615e2c` 与当前 head,以及相同合成
fixture、32 次冷启动、128 次 warm typed 请求、64 次完整 canonical transaction、
64 次完整 CLI recovery 和 256 次请求 burst。base → head 结果为:冷启动
p50/p95 115.522/128.518 → 102.829/135.269 ms;完整 transaction
68.774/103.729 → 9.806/14.320 ms;完整 CLI recovery
358.661/611.397 → 264.324/334.687 ms;进程树 RSS 的 idle/burst
30/30 → 32/33 MiB。冷启动 p95 差异为 +6.747 ms(+5.25%),但中位数下降且
低于 25 ms 加性余量。warm typed 请求包含持久化远程读取,不套用非持久化进程内核
预算;完整 transaction 和操作者 CLI 在同条件 SQLite 基线上均明显改善。
26 changes: 16 additions & 10 deletions docs/architecture/rfcs/shared-goal-authority-state-provider-v0.md
Original file line number Diff line number Diff line change
Expand Up @@ -2129,16 +2129,22 @@ when Markdown is absent, and carries an authority receipt in the response.
Provider missing, corruption, protocol drift, or Todo read-model semantic drift
all fail closed; no post-cutover Markdown fallback is permitted.

Durable completion continuation read-back
(`durable_completion.py`: `read_persisted_todo_record` /
`project_durable_completion_outcome`) is a provider read point: it re-reads
the persisted lifecycle record (Markdown first, event projection fallback)
after the completion write and before settlement. The persisted record
carries an explicit `completion_continuation`; the seam fails closed when a
done record omits it or when it contradicts the recorded successor or
no-follow-up fields, so a provider that holds completion state must store
that field byte for byte. Once a remote provider becomes canonical, this seam
flips to provider-first without changing the typed outcome contract below.
Durable completion continuation read-back uses `read_durable_completion_evidence`
in `loopx/control_plane/todos/durable_completion.py` as the provider read point
after the completion write and before settlement. With `runtime_root` and
`goal_id`, the adapter reads the persisted lifecycle record through the
TypeScript `todo.read` transaction of kind `completion_evidence`:
`readCompletionEvidence` in `loopx/control_plane/todos/read_transaction.ts`
first collects the canonical provider snapshot, then selects the Todo and
passes its record and the existing Todo ids to `projectCompletionEvidence` in
`loopx/control_plane/todos/read_projection.ts`. This canonical path has no
Markdown or event-projection fallback; the adapter's explicit legacy path
reads Markdown only. The persisted record carries an explicit
`completion_continuation`; the seam fails closed when a done record omits it
or when it contradicts the recorded successor or no-follow-up fields, so a
provider that holds completion state must store that field byte for byte.
Once a remote provider becomes canonical, this seam flips to provider-first
without changing the typed outcome contract below.

#### Stage 2 slice status (2026-08-23)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1704,14 +1704,20 @@ pipeline;Markdown 缺失时仍可执行 provider-only read,并在响应中
receipt。provider 缺失、损坏、协议漂移或 Todo read-model 语义漂移都会 fail closed;
cutover 后禁止回退 Markdown。

完成续接(continuation)的持久化读回
(`durable_completion.py`:`read_persisted_todo_record` /
`project_durable_completion_outcome`)是一个 provider read point:它在完成写入之后、
settlement 之前重新读取已落盘的 lifecycle record(Markdown 优先,event projection
兜底)。落盘记录带有显式的 `completion_continuation`;done 记录缺少该字段、或该字段
与 successor / no-follow-up 字段矛盾时,seam 都 fail closed,因此持有完成状态的
provider 必须逐字节保存这个字段。一旦远端 provider 成为 canonical,这个 seam 翻转为
provider-first,且不改变下述 typed outcome 合同。
完成续接(continuation)的持久化读回以
`loopx/control_plane/todos/durable_completion.py` 中的
`read_durable_completion_evidence` 为 provider read point,在完成写入之后、
settlement 之前执行。提供 `runtime_root` 和 `goal_id` 时,adapter 通过 kind 为
`completion_evidence` 的 TypeScript `todo.read` transaction 读取已落盘的 lifecycle
record:`loopx/control_plane/todos/read_transaction.ts` 中的
`readCompletionEvidence` 先收集 canonical provider snapshot,再选出 Todo,并将其
record 与已有 Todo id 传给 `loopx/control_plane/todos/read_projection.ts` 中的
`projectCompletionEvidence`。这条 canonical 路径不回退 Markdown 或 event projection;
adapter 的显式 legacy 路径只读取 Markdown。落盘记录带有显式的
`completion_continuation`;done 记录缺少该字段、或该字段与 successor / no-follow-up
字段矛盾时,seam 都 fail closed,因此持有完成状态的 provider 必须逐字节保存这个
字段。一旦远端 provider 成为 canonical,这个 seam 翻转为 provider-first,且不改变
下述 typed outcome 合同。

#### Stage 2 切片状态(2026-08-23)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2842,3 +2842,4 @@ with shared write/read status-phase checks. See the [2026-10-02 checkpoint](ledg
- Quota summary composition in one `todo.quota_planning.project` crossing with source references: [2026-11-02 cutover](ledger/typescript-control-plane-migration-v0/2026-11-02-quota-summary-transaction.md).
- Complete global summary and gate read transactions: [2026-11-02 checkpoint](ledger/typescript-control-plane-migration-v0/2026-11-02-global-manager-reads.md).
- Complete global-risk read ownership: [2026-11-02](ledger/typescript-control-plane-migration-v0/2026-11-02-global-risks-read.md).
- Complete durable-completion evidence read: [2026-11-02 owner and crossings ledger](ledger/typescript-control-plane-migration-v0/2026-11-02-completion-evidence-read.md).
Original file line number Diff line number Diff line change
Expand Up @@ -2107,3 +2107,4 @@ SQLite 中位数略升,收益不能外推为全面加速。这只资格化本
- 配额摘要经来源引用在一次 `todo.quota_planning.project` 跨运行时调用内完成组合:[2026-11-02 切换记录](ledger/typescript-control-plane-migration-v0/2026-11-02-quota-summary-transaction.zh-CN.md)。
- 完整全局摘要与门禁读取事务:[2026-11-02 检查点](ledger/typescript-control-plane-migration-v0/2026-11-02-global-manager-reads.zh-CN.md)。
- 完整全局风险读取所有权:[2026-11-02](ledger/typescript-control-plane-migration-v0/2026-11-02-global-risks-read.zh-CN.md)。
- 完整 durable-completion 证据读取:[2026-11-02 owner 与调用边界记录](ledger/typescript-control-plane-migration-v0/2026-11-02-completion-evidence-read.zh-CN.md)。
77 changes: 14 additions & 63 deletions loopx/cli_commands/turn_run_once.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,14 +27,7 @@
from ..control_plane.work_items.autonomous_replan_obligation import (
replan_obligation_id_from_packet,
)
from ..control_plane.todos.durable_completion import (
project_durable_completion_intent,
project_durable_completion_outcome,
project_durable_terminal_completion_readback,
read_persisted_todo_record,
read_persisted_todo_record_with_source,
)
from ..control_plane.todos.completion_fence import evaluate_todo_completion_fence
from ..control_plane.todos.durable_completion import read_durable_completion_evidence
from ..control_plane.turn_driver import (
build_loopx_turn_command_validator,
codex_cli_session_binding,
Expand Down Expand Up @@ -329,17 +322,9 @@ def completion_intent(_result: dict[str, object]) -> dict[str, object]:
project=None,
state_file=None,
)
durable_todo, existing_todo_ids = read_persisted_todo_record(
state_file,
todo_id=todo_id,
registry_path=registry_path,
goal_id=args.goal_id,
runtime_root=runtime_root,
)
return project_durable_completion_intent(
todo=durable_todo,
expected_todo_id=todo_id,
existing_todo_ids=existing_todo_ids,
return read_durable_completion_evidence(
state_file, todo_id=todo_id, registry_path=registry_path,
goal_id=args.goal_id, runtime_root=runtime_root, operation="intent",
)

def todo_completion(
Expand Down Expand Up @@ -386,17 +371,9 @@ def todo_completion(
),
}
try:
durable_todo, existing_todo_ids = read_persisted_todo_record(
Path(state_file),
todo_id=todo_id,
registry_path=registry_path,
goal_id=args.goal_id,
runtime_root=runtime_root,
)
completion_outcome = project_durable_completion_outcome(
todo=durable_todo,
expected_todo_id=todo_id,
existing_todo_ids=existing_todo_ids,
completion_outcome = read_durable_completion_evidence(
Path(state_file), todo_id=todo_id, registry_path=registry_path,
goal_id=args.goal_id, runtime_root=runtime_root, operation="outcome",
)
except ValueError as exc:
return {
Expand Down Expand Up @@ -555,23 +532,10 @@ def completion_readback() -> dict[str, object] | None:
project=None,
state_file=None,
)
durable_todo, existing_todo_ids, projection_source = read_persisted_todo_record_with_source(
state_file,
todo_id=todo_id,
registry_path=registry_path,
goal_id=args.goal_id,
runtime_root=runtime_root,
)
evaluate_todo_completion_fence(
todo=durable_todo,
projection_source=projection_source,
return read_durable_completion_evidence(
state_file, todo_id=todo_id, registry_path=registry_path,
goal_id=args.goal_id, runtime_root=runtime_root, operation="outcome",
completion_turn_key=settlement_identity.turn_instance_id,
no_followup=False,
)
return project_durable_completion_outcome(
todo=durable_todo,
expected_todo_id=todo_id,
existing_todo_ids=existing_todo_ids,
)
except (OSError, ValueError):
return None
Expand All @@ -586,23 +550,10 @@ def terminal_completion_readback() -> dict[str, object] | None:
project=None,
state_file=None,
)
(
durable_todo,
existing_todo_ids,
projection_source,
) = read_persisted_todo_record_with_source(
state_file,
todo_id=todo_id,
registry_path=registry_path,
goal_id=args.goal_id,
runtime_root=runtime_root,
)
readback = project_durable_terminal_completion_readback(
todo=durable_todo,
expected_todo_id=todo_id,
expected_completion_turn_key=settlement_identity.turn_instance_id,
projection_source=projection_source,
existing_todo_ids=existing_todo_ids,
readback = read_durable_completion_evidence(
state_file, todo_id=todo_id, registry_path=registry_path,
goal_id=args.goal_id, runtime_root=runtime_root, operation="terminal",
completion_turn_key=settlement_identity.turn_instance_id,
)
if readback["kind"] == "absent":
return None
Expand Down
Loading
Loading