Skip to content
Open
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
41 changes: 41 additions & 0 deletions docs/architecture/rfcs/monorepo-distribution-split-v0.md
Original file line number Diff line number Diff line change
Expand Up @@ -1357,6 +1357,47 @@ comparison before adopting a performance change. This checkpoint creates no
new owner, budget, preset or default. R0's complete census, R1/minimal,
D2/D5/D6, I3/D3, hard-lease/context/model and split-install acceptance remain
open; independent exact-head review and required validation govern adoption.
### 2026-11-07 — Original-Turn closeout survives automatic Todo archival

The complete CLI comparison in #8257 exposed a lifecycle failure with 101
synthetic Todos. Fresh source-console reproductions on `4a33eb4b5` retain
`todo_archived` on both File and default SQLite after ordinary completion,
durable writeback and one quota debit. The frozen comparison remains unchanged;
these failed episodes are not accepted latency samples.

The proposed repair stays in `todo_terminal_lifecycle.ts`. Its existing
same-Turn fence and exact ordinary-completion receipt verification also qualify
an archived Todo's closeout before the active-only rejection. One local helper
owns both active and archived parent checks. Original claim/lease, task digest,
validation declaration/receipt and provider CAS checks remain in force; archive
selection and retention thresholds are unchanged. This permits only the
original completion's terminal phase, without reopening archived work.

Real File/SQLite console fixtures now complete the large-state sequence and
replay completion, writeback, quota spend and terminal closeout with one debit
and an unchanged independently verified JSON result. The durable CLI regression
uses a real validator and ordinary hard-lease claim: premature settlement,
unrelated archived work, another actor, claim or Turn, and changed completion
intent are refused. Terminal closeout retains the original passed validation
receipt, first completion time and archive state without rerunning the validator.
Existing provider conformance retains source/digest, validation, lease and replay
checks; an isolated real PostgreSQL suite qualifies its shared owner separately.

The author proposal also integrates main `abf144202` (#8161), whose explicit
Goal-scoped checks do not gate local Todo completion. The archive regression
covers a failed Goal commitment alongside the local validator: ordinary and
terminal completion still preserve the original receipt and one debit, never
rerun the Goal checker, and leave the overall check failed. This is author-side
integration coverage; it does not replace independent review or reviewed-repair
wheel qualification.

This is a proposed lifecycle repair enabling the remaining R1/V4 journey and
large-state comparison. Independent exact-head review, reviewed-repair wheel
readback and remaining guard/parser characterization still govern the next
step. It does not upgrade an installed host or qualify interruption/restart,
split installation, full R0/V10/R1, M1/#8011, D2/D5/D6/D3, context/model,
adoption or complete-cost benefit. I3 remains at least one minor release.

## Appendix B: Decision log

| Date | Decision | Owner / approval | Alternatives | Normative sections changed |
Expand Down
34 changes: 34 additions & 0 deletions docs/architecture/rfcs/monorepo-distribution-split-v0.zh-CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -1016,6 +1016,40 @@ owner;采纳性能变更前必须另做匹配的真实路径对照。本 check
预算、preset 或默认行为。R0 完整清点、R1/minimal、D2/D5/D6、I3/D3、
hard-lease/context/model 和拆包安装验收仍开放;采纳仍受独立 exact-head
评审及必需验证约束。
### 2026-11-07 — 原 Turn 终结在 Todo 自动归档后仍可完成

#8257 的完整 CLI 比较在 101 个合成 Todo 下暴露了生命周期故障。基于
`4a33eb4b5` 的新源码 console 复现在 File 和默认 SQLite 上均保留同一
`todo_archived`:普通完成、持久写回和一次额度扣账已提交。冻结比较保持原样,
这些失败 episode 不计入验收通过的延迟样本。

修复提案仍由 `todo_terminal_lifecycle.ts` 拥有。在仅限 active 的拒绝之前,
复用已有同 Turn fence 与精确普通 completion receipt 校验,验证已归档 Todo
的终结资格。一个文件内 helper 统一 active 和已归档路径的父 receipt 检查。
原 claim/lease、任务 digest、validation 声明与 receipt、provider CAS 校验
继续生效;归档选择与保留阈值保持原样。允许的只是原 completion 的终结阶段,
不会重新开放已归档工作。

真实 File/SQLite console fixture 现在可以完成大状态整轮,并回放 completion、
写回、扣账和 terminal closeout:只有一次扣账,独立验证的 JSON 结果保持原样。
持久 CLI 回归使用真实 validator 和普通 hard-lease claim,拒绝过早结算、
无关归档工作、其他 actor、claim 或 Turn,以及变更后的 completion intent。
终结保留原已通过的 validation receipt、首次完成时间和归档状态,不重复执行
validator。既有 provider conformance 继续检查 source/digest、validation、
lease 和 replay;隔离真实 PostgreSQL suite 单独验证其共享 owner。

作者提案还集成了 main `abf144202`(#8161):显式 Goal 范围的检查不约束局部
Todo 完成。归档回归在局部 validator 之外加入未通过的整体 Goal 承诺检查:
普通完成和终结仍保留原 receipt 与一次扣账,不重复执行 Goal checker,整体
检查继续失败。这是作者阶段的集成覆盖,不能替代独立审阅或审阅修复后的
wheel 资格验证。

这是支持后续 R1/V4 journey 和大状态比较的生命周期修复提案。下一步仍需
独立 exact-head review、审阅修复后的 wheel 回读,以及剩余 guard/parser
刻画。它不会升级 installed host,也不验收中断/重启、split installation、
完整 R0/V10/R1、M1/#8011、D2/D5/D6/D3、context/model、adoption 或完整成本
收益。I3 继续保留至少一个 minor release。

## 附录 B:决策日志

| 日期 | 决策 | 负责人 / 批准 | 备选 | 变更的规范章节 |
Expand Down
114 changes: 67 additions & 47 deletions loopx/control_plane/coordination/todo_terminal_lifecycle.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1194,6 +1194,59 @@ function semanticDuplicate(
return undefined;
}

async function readSameTurnCompletionReceipt(
store: AuthorityStore,
input: ResolvedCoordinationTodoTerminalLifecycleInput,
normalized: CoordinationTodoTerminalLifecycleInput,
todo: JsonObject,
): Promise<CoordinationTodoTerminalLifecycleResult | null> {
if (input.command !== "complete" || normalized.operation_identity.kind !== "completion_turn" ||
!input.requested_no_followup) return null;
const validationRequired = todo.completion_validation_required === true;
const validationSha256 = todo.completion_validation_sha256;
let fence;
try {
fence = evaluateTodoCompletionFence({schema_version: TODO_COMPLETION_FENCE_REQUEST_SCHEMA,
projection_source: "materialized", goal_id: input.goal_id, todo_id: input.todo_id, todo,
requested_no_followup: input.requested_no_followup,
requested_completion_turn_key: input.requested_completion_turn_key,
requested_completion_identity_source: input.requested_completion_identity_source});
} catch (error) {
return terminalFailure("invalid_todo_completion_transaction",
error instanceof Error ? error.message : "Invalid original completion identity");
}
if (fence.outcome === "continue" && fence.reason === "same_turn_terminal_upgrade") {
const originalInput = {...input,
...(normalized.claim_operation_id === undefined ? {} : {claim_operation_id: normalized.claim_operation_id,
lease_idempotency_key: normalized.lease_idempotency_key, lease_expected_version: normalized.lease_expected_version}),
requested_no_followup: false,
operation_id: completionTurnOperationId(input, false)};
const original = await terminalReceipt(originalInput, terminalRequestSha(originalInput)).read(store);
if (original === null) return terminalFailure("terminal_completion_receipt_required",
"Same-Turn closeout requires the original accepted ordinary completion receipt.", {}, "decision_rejection");
if (original.status !== "replayed") return original;
const originalValidation = original.validation_receipt as JsonObject | null;
const receiptDigest = originalValidation?.validation_declaration_sha256;
// Revision-zero receipts may omit the digest. The exact recovered
// request already binds the canonical declaration, actor and lease;
// later declaration revisions still require the receipt's own digest.
const requiresDigest = Number.isSafeInteger(todo.completion_validation_revision) &&
Number(todo.completion_validation_revision) > 0;
if (original.completion_identity_key !== input.requested_completion_turn_key ||
(validationRequired && (originalValidation === null ||
typeof originalValidation !== "object" || originalValidation.passed !== true ||
(receiptDigest != null && receiptDigest !== validationSha256) ||
(requiresDigest && receiptDigest !== validationSha256))) ||
(input.validation_receipt !== null &&
canonicalAuthoritySha256(input.validation_receipt) !== canonicalAuthoritySha256(original.validation_receipt))) {
return terminalFailure("terminal_completion_receipt_mismatch",
"Original completion validation and identity must still match the completed Todo.", {}, "decision_rejection");
}
return original;
}
return null;
}

/**
* Execute complete/supersede as one provider-neutral CAS transaction.
*
Expand Down Expand Up @@ -1360,13 +1413,17 @@ export async function executeCoordinationTodoTerminalLifecycle(
"Todo requirements changed after Turn admission; reread the task and run a fresh Turn",
{todo_id: input.todo_id}, "decision_rejection");
}
let terminalUpgradeReceipt: CoordinationTodoTerminalLifecycleResult | null = null;
if (todo.archive_state !== "active") {
return terminalFailure(
"todo_archived",
"Todo terminal lifecycle requires an active Todo",
{},
"decision_rejection",
);
// Ordinary completion may archive this Todo before its original Turn
// settles. Only its exact accepted parent permits this second phase;
// archive alone grants no new execution or completion authority.
terminalUpgradeReceipt = await readSameTurnCompletionReceipt(store, input, normalized, todo);
if (terminalUpgradeReceipt === null) {
return terminalFailure("todo_archived", "Todo terminal lifecycle requires an active Todo",
{}, "decision_rejection");
}
if (terminalUpgradeReceipt.status !== "replayed") return terminalUpgradeReceipt;
}
const authorityTodo = todo;
let edit: ReturnType<typeof prepareUpdatedTodo> | null = null;
Expand Down Expand Up @@ -1607,50 +1664,13 @@ export async function executeCoordinationTodoTerminalLifecycle(
}
}
let completion: ReturnType<typeof reduceTodoCompletionTransaction> | null = null;
let terminalUpgradeReceipt: JsonObject | null = null;
if (input.command === "complete") {
const validationRequired = todo.completion_validation_required === true;
const validationSha256 = todo.completion_validation_sha256;
if (normalized.operation_identity.kind === "completion_turn" && input.requested_no_followup) {
let fence;
try {
fence = evaluateTodoCompletionFence({schema_version: TODO_COMPLETION_FENCE_REQUEST_SCHEMA,
projection_source: "materialized", goal_id: input.goal_id, todo_id: input.todo_id, todo,
requested_no_followup: input.requested_no_followup,
requested_completion_turn_key: input.requested_completion_turn_key,
requested_completion_identity_source: input.requested_completion_identity_source});
} catch (error) {
return terminalFailure("invalid_todo_completion_transaction",
error instanceof Error ? error.message : "Invalid original completion identity");
}
if (fence.outcome === "continue" && fence.reason === "same_turn_terminal_upgrade") {
const originalInput = {...input,
...(normalized.claim_operation_id === undefined ? {} : {claim_operation_id: normalized.claim_operation_id,
lease_idempotency_key: normalized.lease_idempotency_key, lease_expected_version: normalized.lease_expected_version}),
requested_no_followup: false,
operation_id: completionTurnOperationId(input, false)};
const original = await terminalReceipt(originalInput, terminalRequestSha(originalInput)).read(store);
if (original === null) return terminalFailure("terminal_completion_receipt_required",
"Same-Turn closeout requires the original accepted ordinary completion receipt.", {}, "decision_rejection");
if (original.status !== "replayed") return original;
const originalValidation = original.validation_receipt as JsonObject | null;
const receiptDigest = originalValidation?.validation_declaration_sha256;
// Revision-zero receipts may omit the digest. The exact recovered
// request already binds the canonical declaration, actor and lease;
// later declaration revisions still require the receipt's own digest.
const requiresDigest = Number.isSafeInteger(todo.completion_validation_revision) &&
Number(todo.completion_validation_revision) > 0;
if (original.completion_identity_key !== input.requested_completion_turn_key ||
(validationRequired && (originalValidation === null ||
typeof originalValidation !== "object" || originalValidation.passed !== true ||
(receiptDigest != null && receiptDigest !== validationSha256) ||
(requiresDigest && receiptDigest !== validationSha256))) ||
(input.validation_receipt !== null &&
canonicalAuthoritySha256(input.validation_receipt) !== canonicalAuthoritySha256(original.validation_receipt))) {
return terminalFailure("terminal_completion_receipt_mismatch",
"Original completion validation and identity must still match the completed Todo.", {}, "decision_rejection");
}
terminalUpgradeReceipt = original;
if (terminalUpgradeReceipt === null) {
terminalUpgradeReceipt = await readSameTurnCompletionReceipt(store, input, normalized, todo);
if (terminalUpgradeReceipt !== null && terminalUpgradeReceipt.status !== "replayed") {
return terminalUpgradeReceipt;
}
}
if (validationRequired && !implicitMonitorNoChange &&
Expand Down
Loading
Loading