Skip to content

refactor(delegation): collapse turn recovery bridge into TypeScript - #7322

Closed
hhyykk wants to merge 1 commit into
mainfrom
codex/direct-ts-bridge-retirement-20261025
Closed

hhyykk wants to merge 1 commit into
mainfrom
codex/direct-ts-bridge-retirement-20261025

Conversation

@hhyykk

@hhyykk hhyykk commented Oct 25, 2026

Copy link
Copy Markdown
Collaborator

A rejected delegation read previously crossed the Python/TypeScript runtime boundary to find its Turn journal, reopened that JSON in Python, then crossed again to project the validation failure. The new collaboration.delegation.turn_recovery handler composes journal lookup and failure/revalidation projection directly in TypeScript. The measured CLI/MCP service read now makes one runtime crossing instead of two.

  • Retire Python task_failure and committed_revalidation_key, duplicate journal JSON reads, and Python phase/status qualification. Reuse the journal already parsed by the TypeScript query owner.
  • Compose revalidation with recoverRevalidatedDelegation directly and remove its standalone RPC registration. Send only qualified receipt facts across the boundary.
  • Keep explicit settlement recovery on its existing transition owner. Inspection alone does not apply the rejected-only recovery transition. Host replay, authorization, locks, and fenced writes retain their existing owners.
  • Add a real-filesystem regression for the combined TypeScript projection. No inventory, quota, Todo, or Vision-wait redesign is included.

Three-gate evidence

Baseline: 06f51b7e4 (origin/main at the accepted comparison). Same synthetic rejected delegation fixture; five warmups followed by 50 timed Delegations.read operations per side, using the real managed TypeScript runtime.

Gate Before After Result
Live runtime crossings per read 2 1 Journal lookup and failure projection compose in TypeScript
p50 latency 82.302795 ms 64.054452 ms Lower in the accepted paired run
p95 latency 129.146010 ms 85.143157 ms Lower in the accepted paired run
MCP service JSON 693 bytes / 174 estimated tokens 693 bytes / 174 estimated tokens Exact serialized-byte SHA-256 matched; delta 0
CLI JSON stdout 708 bytes / 177 estimated tokens 708 bytes / 177 estimated tokens Exact serialized-byte SHA-256 matched; delta 0
Production Python diff — 44 additions / 105 deletions −61 lines
Whole repository diff, including tests — 162 additions / 109 deletions +53 lines across 6 files

Token estimate: ceil(bytes / 4). The selected delegation CLI/MCP path returns JSON and has no separate Markdown representation.

The benchmark ran under steady shared-host background load, not an idle machine. Its host-load exception and the retained verification results were explicitly accepted for this submission. Earlier latency runs varied; the table reports the accepted latest-base paired comparison, not an idle-host guarantee. The final LOC counts above supersede preliminary counts.

Retained verification

Command Recorded result
npm ci Completed before verification; dependencies removed afterward
npm run typecheck:control-plane Passed
node --no-warnings --experimental-sqlite --experimental-strip-types --test tests/control_plane_ts/turn_journal_query.test.ts 30 passed
uv run --extra test pytest tests/control_plane/test_delegation_lane_readiness.py tests/control_plane/test_delegation_source_authority.py tests/test_delegation_stop_recovery.py tests/test_delegation_task_revalidation.py tests/test_independent_delegation_validation.py -k 'not never_promoted_authority_needs_no_delegation_lease' 104 passed, 2 deselected
uv run --extra test pytest tests/test_delegation_task_revalidation.py 12 passed after the final receipt-payload refinement
uv run --extra test ruff check loopx/collaboration_mcp.py loopx/control_plane/collaboration/delegation_validation.py Passed
npm run test:control-plane Latest complete run: 5,494 passed, 76 skipped, 1 heartbeat-start timeout
node --no-warnings --experimental-sqlite --experimental-strip-types --test --test-name-pattern='completion wait appearing during renewal cancels delegated Host' tests/control_plane_ts/host_process.test.ts The failing heartbeat case passed alone

The broader Python sweep included all delegation and Turn-journal suites, tests/control_plane/test_cli_output_budget.py, tests/architecture/test_semantic_*.py, and tests/architecture/test_goal_instance_binding_inventory.py. Output budgets and semantic/architecture checks passed in that sweep. Recorded failures also included the File/SQLite test_never_promoted_authority_needs_no_delegation_lease probes and test_the_in_turn_tool_pins_the_conversation_it_runs_in chat-wake fixture imports. Those failures are disclosed, not counted as passes; the two provider-absence probes were deselected only in the later focused rerun. Recovery regressions discovered during development were fixed and the affected 104-case set passed afterward.

These results span the development snapshots and accepted final focused checks; the full suites were not all rerun on this exact final commit after the last rebase/refinements. Existing verification was explicitly accepted as-is for submission. TypeScript and Python suites ran sequentially. clean-code-guard and test-guard reviews were applied. No merge is included in this proposal.

Signed-off-by: aihop <4408344+hhyykk@users.noreply.github.com>

@loopx-agent loopx-agent left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewer: model_agent | gpt-6.1-sol | OpenAI | runtime_reported | reasoning_effort=max

[P2] 保留日志冲突的公开异常和聊天降级语义。 5d2246e3 的 turn_recovery 直接调用新 RPC,绕过了 journal_store 原有的 EffectRuntimeConflict → ValueError 转换。现有 ChatLoopXMode.snapshot 只将 ValueError、KeyError、OSError 降级为成员 unavailable。我用同一实际持久化夹具和真实 HTTP GET,在 File、SQLite 两臂均得到:基线日志不可读时 200 + unavailable delivery,当前版本 409 + 检查配置并重连会话,恢复原日志后两版均 200。重复 exact journal 也改变公开异常类型。请在组合传输边界保留原异常合同,或一致更新真实消费者以保留局部不可用行为,并加入该 GET 的不可读、重复、正常、恢复和零模型调用回归。仅补一个新 helper 的单测不足以覆盖这个消费者。

动机

通过聊天查看受委派成员结果的用户,在某个原始 Turn 日志不可读或出现重复身份时,需要看见该成员暂不可核验,并继续读取当前模式的其他状态。旧版把日志冲突转换为既有的公开异常,聊天快照返回正常响应并把成员结果标为 unavailable;新版跳过这层转换,整个模式读取改为 409 和检查配置、重连会话的提示。同一份 File 和 SQLite 夹具、同一实际 HTTP 入口均复现 200 到 409;恢复日志后两版都恢复 200。正常结果逐字节相同,恢复子路径也确实减少一次运行时调用,但当前异常路径不等价。本次评审只判断该恢复读回重构,不要求重做 inventory、配额或整个迁移;不将局部时延、测试通过或安装成功视作长期效果或合并授权。

改动思路

把日志查找和失败事实投影合入既有 TypeScript owner 是合适的有界简化,但 Python 传输边界仍须保留现有消费者依赖的冲突语义。保留单次恢复查询和独立 settlement transition,在当前 PR 修复冲突异常到聊天降级的衔接,并补充真实快照负例。原先恢复读取先请求 TypeScript 找 journal,再由 Python 重读 JSON、判断阶段,必要时再次请求失败投影;现在查询 owner 使用同一次解析,直接调用既有失败和重验证规则。检查只产生派生事实,显式恢复仍经过原有 rejected-only transition,Host、授权、依赖、操作锁和 fenced write 没有移交给只读查询。

这能删除重复 Python 语义,而无需新 capability 或状态缓存。相比不改代码,它降低了已复现读取成本;相比增加通用恢复框架,它维持现有边界。当前缺口恰在传输兼容层,不能因为语义代码迁入 TypeScript 就丢失调用方早已使用的异常合同。

具体改动

依据 docs/architecture/rfcs/typescript-control-plane-migration-v0.md,规格版本 06f51b7e43adc546b16b6b2590d9bd2ea27bae31:Payoff-phase PR contract 的 owner 收敛与生产代码删除有证据;Caller-observable semantic parity is a promotion gate 未满足,具体为上述异常类型、HTTP 状态及恢复指引变化。没有用作者的成本接受声明豁免这个实际语义回归。

关键代码讲解

  • turn_recovery 传输原 Goal/Agent/Todo/Turn 身份和已有重验证事实,替代重复恢复调用;需要补回原有冲突适配。
  • delegationTurnRecovery 将 journal 的失败、已提交重验证和已验证结算事实组成有界响应,并复用 recoverRevalidatedDelegation;它没有自动执行恢复 transition。
  • findDelegationTurnJournal 复用原精确身份、历史一致性和 no-follow 文件读取,避免 Python 再开同一 JSON。
  • _read_current 一次 inspection 供给两个读回字段,保留 worker/stop 优先级;revalidate、validated_turn_journal 和明确 settlement recovery 也改用同一事实来源。

全部 diff 为 162 增/109 删,其中生产 44 增/105 删,净减 61;新增文件系统用例 29 行。真实完整 Delegations.read 的运行时请求是 4→3,其中恢复子路径 2→1;另两次 binding 请求未改。PR 表中的“每次 read 2→1”应明确仅指恢复子路径。5 次预热、每臂 30 次串行的本机样本中,File p50/p95 约 32.06/34.81→24.19/26.95ms,SQLite 34.16/38.06→23.07/28.66ms;这是共享主机上的局部观察,不能当作生产或长期净收益。

对主干的风险

独立运行当前完整相关 Python 套件,不排除作者披露的失败:104 通过、2 失败。两项是 File/SQLite 的 test_never_promoted_authority_needs_no_delegation_lease,在不可变基线以同一测试命令也产生同一 canonical authority absence unproven 异常,直接 owner 文件逐字未变,保留为无关的既有红项。当前恢复响应丢失、撤权、停止优先、活动 worker 和缓存重验证的通过结果不抵消本次 HTTP 反例。

30 项 TS 查询测试、control-plane typecheck 和原生 premerge 的 6 direct、2 catalog、8 risk 检查均通过。正常完整 CLI/service JSON 逐字节相同,原始操作和 journal 哈希不变、Host 调用仍为一次。16 项真实读回反例覆盖缺失/错误冗余 annotation、70 个无关及后来主题、逆序文件、重复、不可读和缺失 journal;12 项相同,4 项冲突类型漂移。真实 Chat HTTP 和新建环境中物理 wheel 的同一负例进一步确认用户影响,没有伪造快照结果或调用模型。源码 wheel 首次构建因旧前端资产被正确拒绝,重建同源资产后构建、安装和串行验证通过;未绕过资产门。

语义与 CI 对齐

该 PR 复用既有状态/阶段词汇和 owner,原生语义检查通过;未新增 benchmark 或特定场景义务。当前策略为不咨询 CI,本轮未读取、轮询或等待 CI。原生门通过与旧红项的归因都不能证明当前调用方语义等价。最低修复是保留冲突的部分读回合同,重跑实际 Chat GET 反例及既有恢复套件;无需整体迁移或新跟踪任务。

我的整体评价

REQUEST_CHANGES,针对这个完整 head 的一个实际 P2。长期执行的原身份、单次 Host、显式恢复和权限边界在本轮有限验证中保留;用户体验发生已复现回归,故当前 slice 尚不能验收。把日志查找和失败事实投影合入既有 TypeScript owner 是合适的有界简化,但 Python 传输边界仍须保留现有消费者依赖的冲突语义。保留单次恢复查询和独立 settlement transition,在当前 PR 修复冲突异常到聊天降级的衔接,并补充真实快照负例。已检查 ChatLoopXMode.snapshot、实际 HTTP 读回及六文件 diff:没有布局或渲染组件改动;本次风险是返回状态和恢复语义,不以截图代替接口验证。未验证范围:原生 Windows、真实 PostgreSQL、长期并发/冷启动分布和完整费用未由本轮独立资格化;实际 HTTP 使用一次性本地存储和合成成员结果,不启动真实模型。未继承历史审批或将 memory context 当作效果证据,也未执行合并、安装到共享运行时或撤销他人评审。

English verdict: REQUEST_CHANGES 5d2246e. The composed recovery owner and normal read savings are useful, but dropping the public conflict mapping changes real File/SQLite Chat snapshots from HTTP200 with an unavailable delivery to HTTP409 and unrelated reconnect guidance. Preserve partial-failure semantics and add the real consumer regression; existing unrelated provider-absence failures remain disclosed.

@hhyykk hhyykk closed this Oct 26, 2026
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.

2 participants