Skip to content

Commit 67ffe60

Browse files
authored
Merge pull request #4856 from loopx-project/codex/authority-ts-convergence-0921
fix(coordination): converge terminal validation and reviewed recovery
2 parents a550de5 + db51008 commit 67ffe60

30 files changed

Lines changed: 729 additions & 83 deletions

‎apps/presentation/dashboard/smoke/action-review-plan-smoke.ts‎

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,24 @@ check(isStaleActionFailure({ error_code: "action_conflict" }), "Typed conflicts
6666
check(isStaleActionFailure({ proposal: { status: "stale" } }), "Typed stale proposal survives error wrapping");
6767
check(!isStaleActionFailure({ error_code: "canonical_action_failed", error: "conflict with unrelated external service" }), "Error wording cannot classify source state");
6868

69+
for (const [action_kind, operation] of [["todo.update", "complete"], ["monitor.update", "stop"]] as const) {
70+
for (const status of ["applying", "failed"] as const) {
71+
const terminal = typedActionProposalSchema.parse({...proposal, action_kind, status,
72+
normalized_parameters: {goal_id: "sample-goal", todo_id: "todo_work", operation},
73+
canonical_update_basis: {schema_version: "loopx_chat_canonical_terminal_basis_v0",
74+
provider_revision: "revision-1", registry_sha256: "a".repeat(64), source_authority: "file_v0"},
75+
failure: {error_code: "canonical_update_projection_pending", message: "Display pending", retry_safe: true}});
76+
const plan = compileActionReviewPlan(terminal);
77+
check(plan.canApply && plan.retryOriginal === true, "Terminal recovery retries the original proposal");
78+
check(plan.reason === "canonical_update_projection_pending", "Pending display is distinct from failed business mutation");
79+
check(compileActionReviewPlan({...terminal, status: "stale"}).canApply === false, "A stale terminal preview must be regenerated");
80+
check(compileActionReviewPlan({...terminal, normalized_parameters: {...terminal.normalized_parameters, operation: "edit"}}).canApply === false,
81+
"A terminal review basis cannot enable retries of unrelated operations");
82+
check(compileActionReviewPlan({...terminal, status: "applied", receipt: {projection_verified: true}}).interaction === "completed",
83+
"Only current display readback completes terminal presentation");
84+
}
85+
}
86+
6987
const operationProposal = typedActionProposalSchema.parse({
7088
...proposal,
7189
proposal_id: "operation-1",

‎apps/presentation/dashboard/src/data/chat.ts‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -442,7 +442,7 @@ export const typedActionProposalSchema = z.object({
442442
checkpoint: z.record(z.string(), z.unknown()).nullable().optional(),
443443
failure: z.record(z.string(), z.unknown()).nullable().optional(),
444444
canonical_update_basis: z.object({
445-
schema_version: z.literal("loopx_chat_canonical_update_basis_v0"),
445+
schema_version: z.enum(["loopx_chat_canonical_update_basis_v0", "loopx_chat_canonical_terminal_basis_v0"]),
446446
provider_revision: z.string().min(1),
447447
source_authority: z.enum(["file_v0", "sqlite_v0"]),
448448
registry_sha256: z.string().regex(/^[a-f0-9]{64}$/),

‎apps/presentation/dashboard/src/features/personal-workspace/i18n.tsx‎

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -694,10 +694,10 @@ const en = {
694694
"actionReview.readback_unverified": "The action returned without verified readback. Completion is not confirmed; recheck the state.",
695695
"actionReview.operation_group_confirmation": "This exact request can only be confirmed on its original card in the bound Feishu group. The Dashboard does not expose a local execution control.",
696696
"actionReview.operation_result_delivery_pending": "The operation outcome was recorded, but the original group result card has not passed readback verification yet.",
697-
"drawer.recoverEditResult": "Recover edit result",
697+
"drawer.recoverEditResult": "Recover operation result",
698698
"drawer.retryOriginal": "Retry original operation",
699699
"actionReview.canonical_update_retry": "The edit is not yet verified. Retry this operation to recover its result.",
700-
"actionReview.canonical_update_projection_pending": "The edit was committed; display delivery is pending. Retry this operation to restore the current view.",
700+
"actionReview.canonical_update_projection_pending": "The operation was committed; display delivery is pending. Retry this operation to restore the current view.",
701701
"actionReview.apply_failed": "Execution did not complete. Check the failure and regenerate the preview before retrying.",
702702
"actionReview.inactive_proposal": "This proposal is no longer ready to execute. Recheck it before continuing.",
703703
"proposal.gate.default": "Host confirmation required",
@@ -1782,10 +1782,10 @@ const zhCN: Record<WorkspaceMessageKey, string> = {
17821782
"actionReview.readback_unverified": "操作返回但未通过读回验证。尚不能确认完成,请重新检查状态。",
17831783
"actionReview.operation_group_confirmation": "这份精确请求只能在已绑定飞书群的原始卡片确认;Dashboard 不提供本地执行入口。",
17841784
"actionReview.operation_result_delivery_pending": "操作结果已经记录,但原群结果卡尚未通过回读核验。",
1785-
"drawer.recoverEditResult": "恢复编辑结果",
1785+
"drawer.recoverEditResult": "恢复操作结果",
17861786
"drawer.retryOriginal": "重试原操作",
17871787
"actionReview.canonical_update_retry": "编辑结果尚未确认。重试此操作以恢复原结果。",
1788-
"actionReview.canonical_update_projection_pending": "编辑已提交,展示尚未同步。重试此操作以恢复当前视图。",
1788+
"actionReview.canonical_update_projection_pending": "操作已提交,展示尚未同步。重试此操作以恢复当前视图。",
17891789
"actionReview.apply_failed": "执行未完成。请检查失败原因并重新生成预览后再试。",
17901790
"actionReview.inactive_proposal": "此提案当前不可执行。请重新检查后再继续。",
17911791
"proposal.gate.default": "需要宿主确认",

‎docs/architecture/rfcs/loopx-overall-roadmap-v0.md‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -486,6 +486,11 @@ a parallel team-orchestration program.
486486

487487
### R5: TS Convergence and Local Persistence
488488

489+
L2/L5 terminal checkpoint: Agent completion and Monitor stop now use source-bound
490+
TS validation and canonical receipt/display recovery. Real-provider mixed-graph
491+
counterexamples cover concurrent changes and lost responses. [Scope and remaining
492+
boundaries](../../reference/canonical-terminal-review.md); this does not settle R5 or D1–D3.
493+
489494
L3 checkpoint: standalone acquisition/takeover, atomic claim admission and maintenance share typed lease facts/rules and provider opening. Exact acquisition retry verifies current execution proof; real CLI completion can recover missing Markdown display. Full-state scope conflicts, process interruption and File/SQLite/PostgreSQL read-only rehearsal are covered. [Remaining executor and integration boundaries](../../reference/canonical-lease-renew.md); R5, D2/D3 and default qualification remain open.
490495

491496
- **Owner:** TS T0–T4 and shared-authority D1–D3; retain their numbering and gates.

‎docs/architecture/rfcs/loopx-overall-roadmap-v0.zh-CN.md‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -415,6 +415,10 @@ steer;传输成功不关闭请求。复用现有 R2/R3 后继,不另开平
415415

416416
### R5:TS 收敛与本地持久化
417417

418+
L2/L5 终结检查点:Agent 完成、Monitor 停止现使用绑定来源的 TS 验证与 canonical
419+
回执/显示恢复;真实 provider 的混合图反例覆盖并发变化和响应丢失。
420+
[范围及剩余边界](../../reference/canonical-terminal-review.zh-CN.md),不据此结清 R5 或 D1–D3。
421+
418422
L3 检查点:独立领取/接管、原子 claim 准入与维护共用 typed lease facts/rules 和 provider opening;原领取重试校验当前执行 proof,真实 CLI 完成可恢复缺失 Markdown 展示。覆盖完整 scope 冲突、进程中断及 File/SQLite/PostgreSQL 只读演练。[剩余 executor 与集成边界](../../reference/canonical-lease-renew.md);R5、D2/D3 和默认化资格仍未完成。
419423

420424
- **Owner:** TS RFC T0–T4、shared-authority D1–D3;保留两套编号及原门禁。

‎docs/architecture/rfcs/shared-goal-authority-state-provider-v0.md‎

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,13 @@
3131

3232
## Current implementation checkpoint
3333

34+
The terminal caller family now binds review and validation to the canonical
35+
source and recovers historical receipts independently of private argv. Agent
36+
completion and Monitor stop share current-head display acknowledgement with
37+
ordinary edits. [Caller and recovery contract](../../reference/canonical-terminal-review.md).
38+
This advances L2/L5 without closing executor-held fences, D1–D3 or default
39+
onboarding; the conditional 5–8-package estimate below remains unchanged.
40+
3441
The local registry witness now spans canonical create/claim/update/Monitor poll
3542
and terminal mutations through one TS owner. File, SQLite and service-injected
3643
PostgreSQL execute the same source checks and preserve historical receipts.

‎docs/architecture/rfcs/shared-goal-authority-state-provider-v0.zh-CN.md‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,11 @@
2828

2929
## 当前实现检查点
3030

31+
终结 caller 现将审核与验证绑定 canonical 来源,历史回执恢复不再依赖私有 argv。
32+
Agent 完成和 Monitor 停止复用普通编辑的当前 head 显示确认。
33+
[调用与恢复合同](../../reference/canonical-terminal-review.zh-CN.md)。此批推进 L2/L5,
34+
未闭合 executor-held fence、D1–D3 或默认 onboarding,下文有条件的 5–8 批估算不变。
35+
3136
本地 registry witness 现经同一 TS owner 覆盖 canonical create/claim/update、
3237
Monitor poll 与 terminal mutation;File、SQLite、service-injected PostgreSQL
3338
执行相同来源检查并保留历史回执。

‎docs/architecture/rfcs/typescript-control-plane-migration-v0.md‎

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,14 @@ Retain T0 caller/parity inventory, T1/T2 transaction/effect convergence, T3 comp
2222

2323
## Current implementation checkpoint
2424

25+
Terminal review and validation now converge in the existing TS terminal owner.
26+
Agent completion and Monitor stop reuse Chat's canonical receipt-first recovery
27+
and display acknowledgement; v2 binds validation continuation to its source
28+
revision and resolves private declarations only after admission/replay. Python's
29+
separate terminal review selection and eager declaration sequencing are removed.
30+
This closes a T1/T2/L2 terminal caller family, not the remaining leased metadata,
31+
executor fences or T4 retirement. [Semantics, crossings and rollback](../../reference/canonical-terminal-review.md).
32+
2533
Linked User completion now has one typed owner, `todos/user_completion.ts`.
2634
The terminal transaction commits exact-target scope consumption, reject/cancel
2735
outcomes and conditional resume with its own completion/receipt; the Markdown

‎docs/architecture/rfcs/typescript-control-plane-migration-v0.zh-CN.md‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,12 @@
2121

2222
## 当前实现检查点
2323

24+
终结审核与验证已收敛到既有 TS terminal owner:Agent 完成、Monitor 停止复用 Chat
25+
先恢复 canonical 回执再确认显示的路径;v2 把验证 continuation 绑定来源 revision,
26+
准入/回放之后才请求私有声明。删除 Python 的终结操作审核分流和提前解析声明编排。
27+
这闭合 T1/T2/L2 的一组真实终结 caller,剩余 leased metadata、executor fence 和 T4
28+
仍未完成。[语义、调用次数与回滚](../../reference/canonical-terminal-review.zh-CN.md)。
29+
2430
Canonical create/claim/update/Monitor poll/terminal 事务现共用
2531
`coordination/authority_source.ts`;Python adapter 经 `authority_registry_source`
2632
在注册/grant 投影前后校验来源。外部验证结束后保留原 witness,在新 effect/提交前
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
# Canonical terminal review and validation
2+
3+
On an explicitly promoted local Goal, Agent completion and Monitor stop now use
4+
the same reviewed recovery path as Todo edits and User completion. The initiating
5+
Chat action binds the complete provider revision and registry digest, preserves
6+
one operation identity, and acknowledges display only after the existing
7+
projection outbox confirms the current view.
8+
9+
## Operate and recover
10+
11+
For ordinary CLI completion, retain the same explicit completion identity after
12+
a lost response:
13+
14+
```bash
15+
loopx todo complete --goal-id example-goal --todo-id todo_work \
16+
--agent-id agent-a --completion-identity-key reviewed-result --no-follow-up
17+
loopx todo list --goal-id example-goal --todo-id todo_work
18+
loopx todo project-markdown --goal-id example-goal --execute
19+
```
20+
21+
Use `--no-follow-up` only when no successor is needed. Leased work additionally
22+
requires its current `--task-lease-idempotency-key` and
23+
`--task-lease-expected-version`; owner confirmation is not a lease or a lifecycle
24+
grant. Chat users retry the same failed proposal. A stale proposal requires a
25+
fresh preview, not a replacement identity that bypasses review.
26+
27+
| Boundary | Observable result |
28+
| --- | --- |
29+
| Provider/registration changes before a fresh reviewed completion | Reject before private validation execution; Chat marks the proposal stale |
30+
| Provider changes during validation | Reject the old validation result; Todo remains unfinished |
31+
| Lease expires during validation | Recheck runtime time and reject stale execution proof |
32+
| Canonical commit succeeds, display delivery fails | Business remains committed; Chat reports recoverable failure without a successful display receipt |
33+
| Response/action receipt is lost after commit | Retry recovers the original business receipt before checking current review freshness |
34+
| Same operation carries a changed reviewed note, evidence, reason or basis | Reject identity reuse; never silently acknowledge the changed intent |
35+
| Private declaration is unavailable after successful completion | Business receipt can recover from its public commitment; lossless display recovery still requires restoring the original declaration |
36+
37+
The TypeScript terminal owner performs admission, source checks, validation
38+
planning, lease retirement, linked effects, CAS and receipt recovery. Python
39+
transports facts, resolves private argv only when requested, executes declared
40+
validation and drains projection. It does not decide whether a stale validation
41+
can complete work. The preview executes no validator. Separate user-completion
42+
edits retain their existing combined edit/terminal semantics and old stored Chat
43+
proposals retain their existing protocol.
44+
45+
## Wire and migration boundary
46+
47+
The current Python terminal adapter sends
48+
`loopx_local_coordination_todo_terminal_lifecycle_request_v2`. The existing
49+
terminal method accepts these bounded additions:
50+
51+
- `review_basis`, when present, contains exactly `provider_revision` and
52+
`registry_sha256`. It binds reviewed intent and is part of receipt identity.
53+
- `validation_source_provider_revision` is null before an issued effect and is
54+
the returned revision on continuation. It is a freshness constraint, not new
55+
operation identity. Both caller validation and Goal acceptance validation
56+
require it in v2.
57+
- `validation_declaration_sha256` carries the canonical public commitment.
58+
Historical recovery precedes private declaration resolution. Fresh execution
59+
still requires the matching declaration and current authorization.
60+
61+
The existing method may return `resolve_validation` before `execute_validation`.
62+
Both responses bind the source revision; neither commits the business operation.
63+
For a validated fresh completion the host crosses the runtime boundary three
64+
times (resolve, plan effects, commit), versus two before this change. Unvalidated
65+
completion and historical recovery remain one terminal request. This bounded
66+
extra crossing makes receipt recovery independent of host-local argv; it can
67+
disappear when the native host owns declaration resolution and effect execution.
68+
69+
v0/v1 retain their old request fingerprints and validation contract. They reject
70+
the new fields rather than silently discarding obligations. A v2 request without
71+
review preserves the existing CLI terminal fingerprint. Existing receipts are
72+
not rewritten. The public completion facade rejects a reviewed canonical request
73+
if authority has reverted to an unpromoted legacy path.
74+
75+
No provider default, promotion, permission, retention or storage format changes.
76+
Rollback restores compatible code while retaining provider data, receipts and
77+
writer fences. Older code cannot execute v2; regenerate a preview with compatible
78+
code instead of stripping its review fields. Markdown stays a permanent display.
79+
These changes close the terminal review/recovery family, not all leased metadata
80+
updates, executor-held external-effect fencing, D1–D3 or whole-Goal cutover.
81+
82+
Shared provider conformance uses the complete production-scale fixture, both
83+
native and imported records, stale review/validation, expired proof, lost commit
84+
response and unchanged non-target state. Real File/SQLite Chat HTTP tests exercise
85+
the packaged entrypoint and retry feedback. The frontend runtime decoder and shared action-review plan now recognize the
86+
terminal basis for exactly Agent completion and Monitor stop. The packaged Chat
87+
bundle includes the original-operation retry path and distinguishes pending
88+
display from verified completion; no new configuration or visual control is required. Lark receives no new
89+
command or transport in this slice.

0 commit comments

Comments
 (0)