Skip to content

feat(handoff): complete context and strict receiver independent of review packets - #4444

Merged
huangruiteng merged 6 commits into
loopx-project:mainfrom
fengyin-solo:codex/project-agent-handoff-shards
Sep 25, 2026
Merged

huangruiteng merged 6 commits into
loopx-project:mainfrom
fengyin-solo:codex/project-agent-handoff-shards

Conversation

@fengyin-solo

@fengyin-solo fengyin-solo commented Sep 15, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Oversized project-agent handoffs previously dropped material context and delivery requirements. This revision keeps the complete prepared context available to existing consumers and provides a shipped receiver that verifies and restores the transport representation.

  • Extract the status-derived ProjectAgentContext into the existing handoff boundary. Full Review Packet and direct handoff-only CLI share that assembly; human questions and gate drafts remain presentation-only.
  • Keep project_agent_handoff and handoff_text complete. Overflow adds an array containing every shard, including index 0. Complete-text budgets honestly report overflow; each transport shard retains the 16-line / 1800-character limit. In-budget shape and text remain unchanged.
  • Add loopx handoff restore --input handoff.json --format json (or --input-format markdown). Strict verification rejects incomplete, mixed, reordered, duplicate or altered sets without returning partial success. Restoration never executes content or changes ownership.
  • Remove the unused collector, permissive ordering option, detector and duplicate validation. Document the receiver in the managed skill, CLI help, status contract and bilingual RFC replacement map.

Issue Or Task

Contributor task T003; implements the existing CR1–CR5 revision request. This is the context/transport/receiver slice of the semantic-handoff direction, not completion of M2/M3 collaboration lifecycle.

Validation

Rebased from the contributor head 7a04a3e700989204116410af7fe6b0a4aead27ef onto 41ba6f4d97ba2219f4e7d7e24f164cd34f85051c. Validation targets the revised head recorded in the accompanying revision comment.

  • Exact base/candidate equality for complete packets and minimized JSON across seven in-budget action kinds.
  • 223 focused pytest tests passed (final exact head); covers codec, real-process receiver negatives, source immutability, ownership-argument separation, CLI/architecture boundaries, budgets and manager context.
  • Real CLI full/handoff-only × JSON/Markdown overflow production and restoration; material context, work constraints and complete commands survive.
  • Existing context, delivery-contract and Todo-continuation smokes; Ruff, configured mypy, semantic-vocabulary drift and diff hygiene.
  • Exact-diff quality receipt is valid; risk-based premerge 19/19 passed, with no failures, skips or manual holds. Details are recorded in the revision comment. No live model, CI polling or provider promotion.

Entry Points And Boundaries

CLI and managed skill changed. The Dashboard independently builds buildActionPacket / buildApprovedAgentHandoff from status in apps/presentation/dashboard/src/data/action-packet.ts; it does not consume these Python packet fields. No frontend or packaged asset change is needed for this CLI contract. Lark transport, arbitrary Markdown renderers, cross-host recovery and automatic receiver adoption/result return are not qualified here.

Losslessness starts at prepared text, after existing bounded status projection and command normalization. Content hashes are neither sender authentication nor business request identity. Current Todo, claim/lease, source freshness and operator gates retain their existing owners. Runtime/CLI change: leave merge to the maintainer after review of the new head.

@huangruiteng huangruiteng 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.

动机

超预算 handoff 之前是有损的:fit_project_agent_handoff_budget 会先压缩最后一段 bash 块,然后按前缀逐组丢掉 Agent 待办候选、材料上下文:、交付观测:、交付合同:,删完仍然超预算就照样返回那份超预算文本。把交付合同/交付观测丢掉,项目 Agent 就会按不完整的契约干活,所以"不要再丢内容"这个方向我认同。本 head 改成:整段归一化后(只做无损的 bash 块压缩)切成带信封的有序分片,project_agent_handoff 放第 0 片,其余进 project_agent_handoff_fragments。方向没问题,但改的是对接收端可见的输出契约,有两处必须先收口。

改动思路

新增 loopx/control_plane/handoff/handoff_fragments.py:信封行 <!--loopx-handoff v=1 id=… i=… n=… c=… p=… d=…--> 承载内容派生的 set id、序号/总数、单片校验和、前片哈希链与全文 digest;packer 保证围栏不被切开、超长行用续行标记折行;读取侧提供 parse_handoff_shard/is_handoff_shard_text/reassemble_handoff_shards/restore_handoff_text/HandoffShardCollector/extract_handoff_shards/build_handoff_shard_manifest,并在编码末尾用自校验保证逐字节可逆。review_packet.py 里旧的丢段函数被删除,改由 normalize_project_agent_handoff_text + split_handoff_text 承担;cli_commands/status.py 让 handoff-only markdown 打印全部分片,JSON 额外暴露 fragments 与 manifest。

具体改动

  • loopx/control_plane/handoff/handoff_fragments.py(新,736 行):信封、packer/折行、解析与校验、collector、extractor、manifest。
  • loopx/review_packet.py(+92/-26):删除 fit_project_agent_handoff_budget,新增 normalize_project_agent_handoff_text、prepare_project_agent_handoff_shards、render_handoff_only_text;packet 侧 agent_text = handoff_shards[0](第 711-712 行)。
  • loopx/cli_commands/status.py(+21):handoff-only JSON 透传 project_agent_handoff_fragments/handoff_fragment_manifest(143-145),markdown 走 render_handoff_only_text(898-905)。
  • docs/status-data-contract.md(+27/-2):登记分片契约与逐字节可逆承诺。
  • tests/test_handoff_fragments.py(+560,新文件):32 个测试覆盖分片、缺失/乱序/篡改/重复、围栏与续行。

关键代码讲解

  1. split_handoff_text(handoff_fragments.py:285):未超预算时原样返回 [text](无信封),超预算才分片;每片生成后再核对 len(shard.split("\n")) <= 16、len(shard) <= 1800,最后 reassemble_handoff_shards(shards) != text 就抛错——编码器自校验,这点做得扎实。
  2. review_packet.py:711-712:handoff_shards = split_handoff_text(prepared_agent_text)、agent_text = handoff_shards[0]。这一行决定了 project_agent_handoff/handoff_text 的语义在超预算时从"完整文本"变成"第 0 片"。
  3. review_packet_handoff_only_payload(status.py:128-129,143-145):handoff_text 复制的就是 project_agent_handoff,即第 0 片。

对主干的风险

阻塞项 1(P1,接收端契约没跟上,且校验入口不可达)。我用真实 CLI 做了反事实:live loopx-meta 的 handoff 是 14 行/1370 字符(未超预算,--handoff-only 输出与 head 之外无差异);把它加上 必读、成员、交付合同 三行变成 17 行/1541 字符后,markdown 输出分成 2 片(shard 0 = 15 行/1569 字符,shard 1 = 4 行/272 字符),而可执行的 ```bash 命令落在第 2/2 片;JSON 里 handoff_text/`project_agent_handoff` 只等于 shard 0。但 `skills/loopx-project/SKILL.md:700` 仍写着"JSON 返回带 `handoff_text` 的 minimized handoff",`:710` 仍把 `给项目 Agent` 说成 "the executable handoff context"——本 PR 只更新了 `docs/status-data-contract.md`,没更新这个接收端 skill。全仓 `rg` 的结果是:`reassemble_handoff_shards`/`restore_handoff_text`/`HandoffShardCollector`/`extract_handoff_shards` 除了本模块与单测没有任何调用方,也没有 CLI 入口,所以转发文案里承诺的"收齐全部 N 片并按序号校验通过后再执行;缺片、乱序或内容改动都会明确报错"在接收端其实不可达:我把只含 shard 0 的 `handoff_text` 交给 `restore_handoff_text` 会抛 `code=missing`,可接收 Agent 没有任何 shipped 途径走到这一步,若它直接按字段执行,则既没有命令、也没有报错。最小修复二选一:(a) 补一个接收端可用的 verify+restore 入口(例如文档化的 `loopx review-packet --restore-handoff`)并写进 skill;(b) 分片时把 `handoff_text`/`project_agent_handoff` 显式标成"不可单独执行",并同步改 `skills/loopx-project/SKILL.md` 与转发文案,让按 skill 行动的 Agent 不可能只执行第 0 片。

阻塞项 2(P1,改动落在 CLI 契约上却没有真实入口级验证)。examples/control_plane/review-packet-cli-smoke.py 本 PR 未改动,它的 dense fixture 在 head 上仍是 13 行/1319 字符(未分片),所以"markdown 打印多片""JSON 新增 project_agent_handoff_fragments + handoff_fragment_manifest"这两条被改动的契约在 CLI/契约层零覆盖;新覆盖全在 tests/test_handoff_fragments.py(560 行、合成超行文本)。我实测:pytest tests/test_handoff_fragments.py → 38 passed;review-packet-cli-smoke.py、runtime-handoff-status-read-path-smoke.py、platform-migration-material-registry-smoke.py 均通过——正因为它们都不触发分片。本仓库对 status/packet 这类表面的改动要求比单元测试更强的证据。最小修复:在 public CLI smoke 补一个超预算 case(断言 markdown 的分片段、JSON 的 fragments+manifest、以及一次可校验的重组),并把 loopx canary premerge --from-git-diff 的结果贴到 PR 评论。

P3(体量与触发条件):736 行新模块 + 560 行单测,而触发条件(16 行/1800 字符)在仓库现有 fixture 与 live goal 上都没有被观察到(loopx-meta 14 行、dense fixture 13 行,我只在人为加三行后才触发)。同时旧的丢段回落被整体删除,packet 路径不再有任何更简单的兜底。建议把"验证的一半"(collector/extractor/manifest/transport markers)留到真有接收端调用点再上,或保留现有单文本行为作为第一层、只在仍超预算时才分片;已上线的部分请让每个 helper 都有活的调用方。

其余非阻塞观察:ENVELOPE_CHAR_RESERVE=200 相对实际信封长度(我构造的两片分别是 142/157 字符)是保守的,我的 hostile 用例没有出现预算越界;分片标题行只出现在后续片上并写作「交接分片 2/2」,第 0 片没有对应标题,读者容易误判第 0 片是完整文本;splitter 对以信封前缀/续行标记开头的正文是 fail-closed,这一点只写在模块 docstring 里,没有写进接收端文档。

我的整体评价

REQUEST_CHANGES。无损 relay 的方向我认同,实现本身也自洽:信封把 set id 绑到内容 digest,每片校验和 + 前片哈希链 + 全文 digest 齐全,围栏不被切开、超长行可逆折行,编码末尾还有逐字节自校验,未超预算路径与既有 smoke 全绿。但这次改的是 review-packet/handoff 对接收端可见的输出契约:超预算时 project_agent_handoff/handoff_text 不再是可直接执行的完整文本(命令跑到最后一片),而接收端既没有 skill/文案更新、也没有任何 shipped 的校验或重组入口;同时被改动的 CLI 契约没有任何真实入口级覆盖。收口建议很小:补接收端入口或显式声明不可单独执行 + 更新 skill,补一个 CLI 超预算 case 并跑 canary premerge;如果想更保守,也可以按上面 P3 收缩成"单文本优先、仅必要时分片"。改完后请让我按新的 exact head 再做一次复审。

English verdict: REQUEST_CHANGES at 7a04a3e. Keeping over-budget handoffs lossless is the right goal, and the relay implementation is internally consistent (content-derived set id, per-shard checksum, previous-shard hash chain, full-content digest, fence-safe packing, byte-exact encoder self-check; 38 focused tests pass and the in-budget path is unchanged in a live CLI run). The problem is the receiving contract: for an over-budget handoff, project_agent_handoff/handoff_text become shard 0 only. In my probe of a realistic 17-line handoff the executable ```bash command lands in shard 2/2, so the documented minimized field is not executable, while skills/loopx-project/SKILL.md still presents that field and the 给项目 Agent section as the executable handoff and was not updated by this PR. The promised explicit shard errors are also unreachable from the receiver surface: reassemble_handoff_shards/restore_handoff_text/HandoffShardCollector/extract_handoff_shards have no caller outside this module and its tests, and no CLI entry point exists. Secondly, the changed CLI contract has no entry-point coverage: review-packet-cli-smoke.py was not updated and its dense fixture stays in budget (13 lines / 1319 chars), so the new markdown shard sections and the new JSON fragment fields are covered only by unit tests over synthetic text. Please add a receiver-reachable verify+restore surface (or mark the field non-executable and update the skill), add an over-budget CLI smoke case, and post loopx canary premerge results, then I will re-review the new exact head.

@huangruiteng

Copy link
Copy Markdown
Collaborator

RFC 对齐补充评审

评审对象:7a04a3e700989204116410af7fe6b0a4aead27ef。RFC 参考版本:当前 main 的 4f33d5ac6f63a00028cd8ac6815c03c15d17e154。

本次按请求补充 RFC 定位与交付顺序;已有完整评审仍对应同一 head,正式 REQUEST_CHANGES 结论保持不变。以下不重复发起一次相同提交的全面审计,也不把未来 RFC 验收项全部追加为本 PR 阻塞项。

动机

保留超预算交接中的约束、材料和交付要求,符合强能力管家与语义交接 RFC §5.4:投影应披露遗漏,不能静默删除用户约束。不过该节同时要求小而适配任务的投影,以及可实际读取的完整材料。逐字重组解决文本传输完整性,只能作为语义交接的一个基础环节。

改动思路

建议将本 PR 定位为 现有 review-packet 的无损传输与兼容性修复。新增 Python codec 可以留在现有 handoff 边界;本次没有接管 Todo、claim、lease 或 request 状态机,没必要为了目录名或未来 M2 而增加 Python↔TypeScript 往返。

管家 RFC §11/§11.1允许独立的格式/投递修复先于通用协作重构交付。因而本 PR 不必等待 M2 双消费者、M3 自动回传或共享存储提升;也不应以分片功能完成来宣告这些里程碑已完成。

具体改动

本次对照了现有评审、PR 描述及相关源码:

  • handoff_fragments.py 提供分片、校验、重组、collector、extractor 与 manifest;review_packet.py 生成第 0 片和 continuation shards。
  • cli_commands/status.py 在 handoff-only JSON 透传分片,在 Markdown 渲染全部分片;契约文档和 focused tests 是另外两个修改面。
  • 当前 project_agent_handoff / handoff_text 在分片时仍只承载第 0 片;skills/loopx-project/SKILL.md 仍描述 minimized handoff_text 和 executable handoff。重组工具的调用仍局限于新模块内部与单测。已有接收端契约问题尚未通过新提交修复。

按 RFC 节奏建议这样收口:

阶段 建议与验收边界
本 PR:补齐已有阻塞项 接收端必须能明确识别不完整交接,并有文档化、实际可调用的校验/恢复路径;同步 managed skill 与字段说明,去掉“第 0 片保持完整字段语义”的误导。新增真正触发溢出的 CLI case,覆盖 Markdown、JSON、完整恢复,以及仅收到第 0 片时的明确拒绝/不可执行反馈。继续保留未超预算输出兼容性。
本 PR:有界整理建议 按实际接收路径决定是否需要 collector、自由文本 extractor 等入口;接入的保留,没有真实调用或明确兼容契约的可延后。不要单纯因新增行数大或合成输入才触发就否定这项修复;检验的是完整的生产者→接收者路径是否值得这些代码。无损 codec 的边界用 prepared text 说明清楚,避免把前置命令归一化也称为原始输入逐字保留。
M2:语义请求与接收方评估 在已有 request/brief/authority 边界上接入语义上下文;分片 set id 仅用于同一内容的重组,不得成为业务 request id、任务去重键或授权凭据。相同文字的两次独立请求必须保留各自义务,接收方 assessed/adopted 也不能由 checksum 成功推断。
M3:完整结果与渠道恢复 通过现有 outbox/return route 证明长结果、重启与不确定投递能够恢复;再验证实际渠道是否保留 HTML 注释信封,以及附件或分段传输的可读性。不要在本 PR 引入新投递账本或承诺已支持 Lark/跨主机恢复。

M2 的身份与回执边界来自§5.6:内容哈希不能合并独立请求,传输、评估、执行和答案送达是独立事实。未来如迁移这些状态规则,再执行TS 迁移 RFC §5的 owner/删除旧规则/桥接成本证明;纯传输 codec 不需要伪装成一次状态机迁移。

对主干的风险

当前主要风险仍是完整文本字段变成首片后,旧接收方式可能遗漏约束或命令,以及真实 CLI 溢出路径的证据不足。这里的“收齐再执行”需要落实到接收路径;仅写提示不能声称已有机器强制保证。

还有两项非阻塞的演进约束:

  1. 每片满足 16 行 / 1800 字符,并不能证明整组投影仍然紧凑。后续优先复用有权限且能解析的材料引用,披露未读取内容;不要默认把全部分片注入每个 Turn。管家 RFC A14 的跨主机材料可读性需要单独验证,本次 codec 测试不覆盖它。
  2. 已交付的 Stage A继续由 handoff prepare/inspect/adopt 和现有 Todo authority 管理所有权;分片校验成功不能替代当前 revision、claim/lease 或 transfer grant。无需在这里再建一套接管机制。

结合刚合并的语义词汇 M0,下一修订更新到当前基线时,应检查新增协议常量是否使生成 inventory 过期,并运行 python3.11 examples/semantic-vocabulary-drift-smoke.py;需要时随源码更新 inventory。不要为本 PR 提前实施 M1–M4 全部词汇迁移。

我的整体评价

保留 REQUEST_CHANGES,支持修复接收闭环后作为独立传输改进交付。 先完成既有接收端兼容与 CLI 验证,再把请求身份/语义评估、自动回传分别放进 M2/M3。未来重构检查的具体边界是 codec 与协作状态机:当前建议收敛到真实调用,避免增加第二个请求或权威状态 owner。

验证说明:本次是同一 exact head 的 RFC 补充,对照了远端讨论、上述版本化 RFC、字段投影及调用点;没有重新运行全面测试,没有生成新的全面审计或合并资格结论。先前测试结果见原评审,不能当作下一修订的验证。按本 Goal 配置,本次未查询、轮询或等待 CI;接收端与本地验证缺口仍需补齐。

English verdict: REQUEST_CHANGES remains at 7a04a3e. This RFC alignment supplement preserves the existing exact-head review: complete receiver compatibility and real over-budget CLI coverage first. Keep sharding a bounded transport codec; reserve semantic request identity/assessment for M2 and durable result return for M3. RFCs and source call sites were inspected; tests were not rerun and CI was not consulted.

@huangruiteng

Copy link
Copy Markdown
Collaborator

Change request:把交接上下文从 Review Packet 中分离,补齐可用的接收路径

对应 head:7a04a3e700989204116410af7fe6b0a4aead27ef。

这是维护者针对长期 handoff 方向提出的具体修订要求,补充已有 REQUEST_CHANGES,并细化上一条 RFC 意见。本次希望包含一次有界的职责重构,而不止增加分片恢复命令。 这是明确的设计范围调整,不是声称在同一 head 上又复现了一个新的运行时缺陷。

动机

当前 build_review_packet 同时组装 Goal 状态、给人的判断与 gate 提示、给 Agent 的交接上下文、执行命令和最终 Markdown。#4444 在这段已经渲染的文本上增加分片协议,改善了内容丢失,却进一步把交接绑定到“生成 Review Packet → 人复制 → Agent 执行”的旧入口。

长期 handoff 要支持有上下文的工作委派、接收方重新评估、会话替换和结果回传。因此需要调整依赖方向:交接上下文有自己的组装边界,Review Packet 消费它来生成人工可读投影,传输层再按渠道需要编码。 review-packet 可以保留为兼容 CLI 和人工评审视图,但不应拥有通用工作请求、交接状态或执行授权。

依据:handoff RFC §5.2–5.6。该 RFC 已要求区分应用、协作语义和运行时/渠道适配,现有模块位置是迁移输入。

改动思路

建议本次交付路径如下;方框表示职责,不要求照此创建同名模块或公共 schema:

现有 Goal/Todo/决策/材料来源
          ↓
共同的交接上下文组装边界
          ├── Review Packet:给人的状态、判断与展示
          └── Agent handoff:给接收方的完整上下文
                         ↓
                 渠道渲染 / 必要时分片
                         ↓
                 接收端校验与恢复
                         ↓
                 接收方按现有权限继续处理

这里的“共同”必须由真实的 full packet 与 handoff-only 路径消费。不要仅搬一个函数、保留两份事实推导,也不要为未来消费者建立空框架。接收端恢复成功只证明内容完整,不代表已接受工作、获得 claim/lease 或可直接执行其中的命令。

具体改动

CR1:提取上下文组装职责,保留 Review Packet 的展示职责

请先列出 project_agent_section、build_review_packet、handoff-only payload/rendering 的生产者与消费者,再在最近的现有 handoff 边界提取一个内部的、有类型的上下文表示及其组装逻辑。

  • 从当前实际使用的信息出发,保留目标与来源、必读材料、当前工作/约束、交付要求、候选下一步或命令及其适用边界。复用现有结构与引用,不复制 Todo、Vision、权限或进度的事实源。
  • 同一上下文同时供完整 Review Packet 和 handoff-only 使用。完整 Review Packet 额外添加给人的判断/gate 部分;handoff-only 无需先构造完整人工评审文本再裁剪。
  • 不通过解析 材料上下文:、交付合同: 等文案前缀来识别或删除语义。调整文案不应改变保留哪些约束。
  • 本次只需覆盖现有调用使用的内容。不要提前补全通用 request schema、持久化 brief store、协作状态机或第二套任务数据库。
  • 普通交接的描述不要自动继承“必须由人再批准”的前提;已有 operator-gate 场景保留其真实限制,也不扩大既有权限。

完成标准: 状态/上下文事实只有一个组装来源,两个现有输出路径均消费它;旧的重复组装逻辑在本 PR 删除,调用关系与职责可以从源码直接看清。

CR2:分片属于传输;修正完整文本字段的语义

当前 project_agent_handoff / handoff_text 在溢出时成为第 0 片,文档仍说保持同样字段语义。这一兼容性声明必须修正。

  • 未超预算时保留现有文本、JSON 形状及行为。
  • 溢出时,旧的“完整交接文本”消费路径必须得到完整内容,或明确拒绝这个不支持的表示,不能成功返回一个容易被当作完整交接的首片。只添加 manifest 或另一处提醒,不能证明忽略新字段的旧消费者已经安全。
  • 请在上述兼容原则内选择一种明确方案,说明旧消费者会看到什么、新消费者如何获取所有片。若需要显式选择新表示或版本化输出,请随真实入口与测试一并提供;不要求为此建立通用版本协商框架。
  • 16 行 / 1800 字符保留为当前接口/单片预算,不作为长期上下文的总语义容量。每片合规不能被报告成整组内容已满足原来的总输出预算。
  • “逐字无损”明确以哪份文本为基准:当前 splitter 接收的是 prepared text;前置命令归一化与传输重组是不同步骤。
  • set_id/checksum 仅表示内容与传输完整性,不表示请求身份、发送者认证、接收方接受或执行授权。相同文本的两个独立工作请求不能因内容哈希相同而被业务去重。

完成标准: 完整交接、单片和恢复结果在契约上不混淆;未收齐内容的兼容消费者没有“成功收到完整交接”的假象。

CR3:交付接收方实际能用的校验/恢复入口

请提供一个已文档化、可以由接收 Agent 调用的真实入口,并在 managed skill 中写出可运行步骤。它应属于 handoff 的内容接收职责;不要仅因当前生产者是 review-packet 就把恢复协议继续绑定到人工评审概念。

具体命令拼写可以沿用仓库注册模式;若选用现有 handoff CLI 家族,请清楚区分内容恢复与已交付的 prepare/inspect/adopt 所有权流程。

  • 接收实际生产者输出的完整分片集,校验并恢复完整交接文本。
  • 缺片、混入其他集合、内容篡改等返回可操作的明确错误;不要输出可误认为完整成功结果的半份文本。
  • 顺序与重复策略保持明确:直接有序恢复与 collector 幂等导入若允许不同行为,分别说明并测试,避免同时声称“重复总是错误”和“重复总是无操作”。
  • 恢复入口只处理内容,不自动执行命令、不申请或转移 claim、不修改 Todo、不自动启动会话。
  • skills/loopx-project/SKILL.md 同步描述完整/分片表示、收集与恢复步骤,以及恢复后的现有权限检查。不要以“模型看到警告就会遵守”代替可用的校验入口。
  • collector、自由文本 extractor 等 helper 只保留真实接收路径需要的部分;没有活调用或明确兼容需要的部分可删除/延后。已有 focused tests 中证明实际编码边界的内容仍值得保留。

完成标准: 一个接收方仅凭 shipped CLI/skill 即可恢复合法交接,识别不完整输入;无需临时写 Python 去导入内部函数。

CR4:补齐 RFC replacement map 与公开操作说明

请更新 handoff RFC §5.9 的替换表及中英文镜像,明确登记 review_packet.py:

现有职责 本次/后续归属 迁移完成条件
交接上下文组装 本次提取到现有 handoff 边界 full packet 与 handoff-only 共用,旧重复规则删除
人工判断、gate 展示、Review Packet 渲染 保留为展示适配器 不拥有通用 handoff 状态或另行赋予权限
长度控制、分片/重组 当前渠道适配 可用接收入口与完整性、兼容性验证通过
请求身份、评估、结果与恢复关系 后续 M2/M3 的统一协作边界 按相应阶段独立验收,不能由分片测试替代

同时修正 docs/status-data-contract.md、managed skill、受影响的 CLI help,以及 PR 描述的字段兼容性和交付范围。用户入口检查请列出 CLI、实际复制/展示该内容的前端或其他渠道消费者;确实不受影响的给出调用依据。仅测试 CLI 时,不宣称已验证 Lark、跨主机或所有 Markdown 渲染器的注释保留行为。

对主干的风险

CR5:按真实消费路径补验证

新增测试应先从下面这些语义要求写出预期,再测试实现。不要把实现生成的内容反过来当作唯一 oracle。

用例 必须证明的结果
未超预算 与 base 的匹配 fixture 比较,既有文本、字段和行为不变
实际构造的超预算上下文 使用独立写明的合成约束与交付要求,使它们分布在不同片;通过真实 CLI 输出→真实接收入口恢复后,约束、要求及命令内容均保留
完整 Markdown 与 JSON 路径 二者提供同一份交接内容;给人的 gate 问题不混入 Agent handoff
仅收到首片 明确失败/不完整,不冒充完整交接、不执行任何命令
缺片、混集、篡改 接收入口给出对应错误;不得返回成功的部分交接
乱序与重复 符合声明的直接恢复/collector 策略;内容去重不被宣称为业务请求去重
文案变化 修改展示标题或标签,不改变结构化约束是否被保留
权限与状态 成功恢复仍是内容操作,不改变现有 Todo/claim/lease/gate;不把校验成功展示为任务已接受

复用并扩展 examples/control_plane/review-packet-cli-smoke.py 等现有拥有该路径的验证;至少有真实 CLI 进程覆盖生产与接收,而非全部 monkeypatch 在内部 helper 上。不要把大段 unit cases 机械复制成另一个超大 smoke。

下一 head 请运行相关 focused tests、现有 packet/CLI 回归,以及 loopx canary premerge --from-git-diff 或明确映射到上述风险的等效本地验证集。更新到当前基线时,检查语义词汇 inventory/drift 验证是否需要随源码刷新。PR 验证评论记录 exact base/head、修改面、命令、通过结果、失败/跳过与证据边界。本 Goal 不查询或等待 CI;本地失败和缺失证据仍需明确处理。

我的整体评价

REQUEST_CHANGES 保持。建议把“上下文组装职责分离 + 明确的兼容表示 + 接收端闭环 + 聚焦验收”作为一个可独立交付的修订。 它共享同一个修改原因,属于本 PR 合适的配套重构。

本次不要求实现通用 M2 状态机、M3 自动回传、跨主机持久化、历史召回、新 artifact 服务或整体 TypeScript 迁移。纯文本/投影逻辑可以保留 Python;未来真正迁移协作状态决策时,再按 TS 迁移 RFC证明单一 owner、旧规则删除与桥接成本。

也不要求现在删除 review-packet 这个已存在的命令:保留它作为人工评审/复制入口,同时让长期 handoff 可以独立演进。相关权限转移继续复用 Stage A 已交付契约,不在 codec 内重新实现。

请在下一修订说明中逐项回复 CR1–CR5,给出实现位置与验证结果;实现选择可以不同,只要满足上述可观察契约。这条评论是具体修订要求,不是新一轮测试通过或合并资格证明。

English verdict: REQUEST_CHANGES remains at 7a04a3e. Please extract the existing handoff-context assembly from Review Packet presentation, preserve legacy compatibility without exposing shard 0 as a complete handoff, ship a receiver-accessible verify/restore path, update the RFC replacement map and managed skill, and validate real producer-to-receiver CLI flows. Keep this a bounded refactor; generic M2/M3 lifecycle, ownership transfer, and storage migration remain separately qualified work. This comment specifies the requested revision; it does not claim new test execution or consult CI.

fengyin-solo and others added 4 commits September 25, 2026 18:35
Project-agent handoffs have a fixed 16 line / 1800 character interface
budget. The old overflow pass first compacted the command block and then
deleted whole sections by fixed prefixes, returning an over-budget text
when deletion was insufficient: receivers lost content silently and
could not tell whether more existed.

Replace the lossy section drop with ordered, independently verifiable
shards in control_plane/handoff/handoff_fragments.py:

- split_handoff_text returns the input verbatim (no envelope) when it
  fits; over-budget text becomes shards, and shard 0 keeps the existing
  project_agent_handoff position and field semantics;
- each shard carries an envelope with a content-derived stable set id,
  i/total sequence, per-shard payload checksum, previous-shard hash
  chain, and full-content SHA-256;
- reassemble_handoff_shards/restore_handoff_text validate every
  payload, set consistency, the hash chain, and full digest, failing
  explicitly on missing, out-of-order, duplicate/conflicting, foreign-
  set, or tampered shards;
- HandoffShardCollector imports shards idempotently (same set/index/
  checksum is a no-op), so regeneration and re-import never duplicate
  fragments;
- fenced command blocks are never split open (strip-only close/reopen
  markers balance every shard), and over-long single lines wrap at safe
  whitespace boundaries with hard-cut fallback via continuation
  markers, restoring byte-for-byte;
- build_review_packet exposes project_agent_handoff_fragments plus a
  compact handoff_fragment_manifest only when fragmented; full packet
  and handoff-only markdown render every shard, and handoff-only JSON
  passes the fragments through. Within-budget output is byte-identical.

Tests cover split/restore, missing/out-of-order/tamper/digest errors,
idempotent regeneration and import, over-long lines and fence
splitting, a budget matrix, packet/handoff-only integration, and the
within-budget compatibility shape.

Signed-off-by: fengyin-solo <292015025+fengyin-solo@users.noreply.github.com>
Describe the lossless overflow protocol: shard 0 keeps the existing
project_agent_handoff semantics, continuation shards use a stable
content-derived set id with index/total, per-shard checksum, hash chain,
and full digest, and receivers fail explicitly on missing, out-of-order,
duplicate, or tampered shards. Document fence close/reopen and line
continuation handling, idempotent re-import, and byte-identical output
within the 16 line / 1800 character budget.

Signed-off-by: fengyin-solo <292015025+fengyin-solo@users.noreply.github.com>
…restore

Signed-off-by: huangruiteng <14976749+huangruiteng@users.noreply.github.com>
Signed-off-by: huangruiteng <14976749+huangruiteng@users.noreply.github.com>
@huangruiteng
huangruiteng force-pushed the codex/project-agent-handoff-shards branch from 7a04a3e to 68b02bb Compare September 25, 2026 10:51
@huangruiteng huangruiteng changed the title feat(handoff): lossless ordered shards for over-budget project-agent handoff feat(handoff): complete context and strict receiver independent of review packets Sep 25, 2026
@huangruiteng

Copy link
Copy Markdown
Collaborator

已按此前完整评审及 CR1–CR5 重构,并 rebase 到 41ba6f4d97ba2219f4e7d7e24f164cd34f85051c。本次提交:68b02bbad6e7b274396cf779739ab24f3bbed33a。保留贡献者原提交与 DCO,新增实现/验证和文档两组提交。

要求 本次落实与证据
CR1:上下文独立组装 handoff/project_agent_context.py 的 typed ProjectAgentContext 复用已有 Todo/material/required-read/delivery-contract 投影。build_review_packet 消费它再追加人的判断;--handoff-only 直接构造交接。删除原 packet 组装逻辑及六份重复上下文行列表。测试强制禁止 handoff-only 调用 build_review_packet,并证明修改人工展示不会丢掉约束。
CR2:完整字段与传输分离 project_agent_handoff / handoff_text 始终是完整 prepared text;溢出数组包含 index 0 在内的所有片。全文预算如实返回超限,单片仍满足 16 行 / 1800 字符。与 base 对照七类预算内完整 packet 和精简 JSON,逐字段/文本相同。没有新增业务请求身份或哈希去重。
CR3:真实接收入口 loopx handoff restore --input handoff.json --format json;raw Markdown 可用 --input-format markdown,stdin 可用 --input -。完整校验后才输出全文;缺片、首片、乱序、重复、混集、篡改、损坏 manifest 均明确失败,不返回半份文本。删除没有生产调用的 collector、宽松顺序选项和 detector。接收进程使用不存在的 registry/runtime 仍可恢复,且不会执行文本、建立状态或接管工作。
CR4:契约与使用说明 状态契约、managed skill、CLI help、中英文 RFC §5.9 replacement map 已同步。恢复成功仅证明内容一致性;后续按现有 Goal/权限/claim/lease 路径处理,不额外添加一般性交接审批。
CR5:真实消费路径验收 扩展现有 CLI smoke:真实 status/registry fixture 产生溢出,full/handoff-only × JSON/Markdown 四种输出经真实接收进程恢复;独立断言材料、待办、停止边界及完整命令保留。真实进程负例覆盖缺片/混集/篡改/乱序/重复、首片单独接收与 ownership 参数隔离;恶意声明巨大分片数也会有界失败。

生产者/消费者盘点:collect_status → assemble_project_agent_context → full Review Packet / direct handoff-only → transport codec → handoff restore。Dashboard 的 action-packet.ts::buildActionPacket/buildApprovedAgentHandoff 独立消费 status,没有读取本次 Python packet/fragment 字段,因此此次 CLI 变更不需要前端或打包资产修改。没有验证 Lark、跨主机或任意 Markdown 渲染器;推荐 JSON 避免注释信封被渲染器剥离。

有界重构已应用在共享上下文和严格传输边界,没有新增通用请求库、持久化 brief store、协作状态机或第二个权限 owner。当前增量是“已有交接内容不再因长度而丢失,接收方有实际可调用的恢复路径”;它不证明接收方已采用任务,也不代表 M2/M3 自动协作/回传验收完成。

验证(source-checkout Python 3.13.13):

  • uv run --extra test python -m pytest -q tests/test_handoff_fragments.py tests/test_handoff_receiver.py tests/test_cli_entrypoint.py tests/test_cli_argument_diagnostics.py tests/architecture/test_control_plane_import_boundaries.py tests/control_plane/test_cli_output_budget.py tests/test_manager_context_handoff.py:223 passed。
  • uv run --extra test python examples/control_plane/review-packet-cli-smoke.py:通过,包括四种真实溢出恢复路径。既有 review-packet-handoff-context-smoke.py、review-packet-handoff-delivery-contract-smoke.py、todo-continuation-policy-smoke.py 通过。
  • 修改 Python 路径的 Ruff、仓库配置 mypy(23 files)、semantic-vocabulary-drift-smoke.py、git diff --check 通过;未修改词汇 inventory,也未放宽预算。
  • loopx canary premerge --from-git-diff(启用本地项目的精确质量 gate):19/19 passed,catalog 10、risk-profile 8、public boundary 1;direct diff/compile/maintainability 检查通过,0 failures、0 skips、无 manual hold。
  • 精确 diff 质量回执 cqr_fbbd7ed36292b837ff10:valid,15 files;scope fbbd7ed36292b837ff103277875de8e11710211e7fbff5d7b290e15ed0ec0b37;允许并应用 1 次有界简化,0 blockers / warnings / advisories。
  • 验证过程中两项 fixture 前置条件已修正后重跑:人工展示变更用例不再被“已批准 gate”文案覆盖;真实 CLI 溢出用例先完成 fixture 的 owner 待办再生成已批准交接。最终无未解决本地失败。

未运行 live model、未查询/等待 CI、未执行真实项目工作或 provider promotion。原 REQUEST_CHANGES 针对旧 head;以上是本次修订与验证记录,请按新 exact head 复审,不将本评论视为合并批准。

English revision summary: complete handoff fields now remain complete, both producer paths share context assembly, and handoff restore provides a strict content-only receiver. Real producer-to-receiver CLI coverage and negative cases pass. Transport integrity is not authentication, request identity, receiver adoption or execution authority. This revision is ready for maintainer review; it does not claim M2/M3 or cross-channel qualification and does not merge the PR.

@huangruiteng huangruiteng 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.

动机

评审 exact head 68b02bbad6e7b274396cf779739ab24f3bbed33a,以维护者此前的 CR1–CR5为当前交付边界。旧的 Review Packet 在交接超出 16 行或 1800 字符时会按文案前缀删去待办、材料及交付约束;接收者可能在缺少关键条件时继续工作。本 PR 把“完整上下文 + 可校验的超限传输”做成一段可独立验证的 CLI 交付,确实比保留有损裁剪更有价值。它修的是交接内容,不代表接收方已接受任务、完成协作或把结果送回原入口。

改动思路

collect_status 仍是事实来源;新增的 assemble_project_agent_context 从既有 Goal、Todo、材料和交付合同投影组装只读上下文。完整 Review Packet 消费它后添加人的判断,--handoff-only 则直接消费同一来源。ProjectAgentContext.payload 保持完整 prepared text,在超限时额外生成包含首片的分片数组和 manifest;handoff restore 从 JSON 或原始 Markdown 校验后恢复文本,不打开 registry、不执行命令、不转移 Todo/claim/lease。这样复用原有状态及权限 owner,并把 codec 的内容完整性与业务请求身份、工作采用清楚分开。预算内输出我用同一合成状态对 base/head 的七种 action kind 比较,完整 packet 与精简 JSON 均逐字段相同。

具体改动

  • loopx/control_plane/handoff/project_agent_context.py 承接原 review_packet.py 的状态查找、动作推断、命令及交接文案组装;review_packet.py 留下人类问题、gate 展示与 Markdown 呈现。status.py 的 handoff-only 路径不再先建完整人工 packet。
  • handoff_fragments.py 为超限文本生成有序信封、片校验、前片哈希链和全文摘要,处理长行及 fenced code,恢复时拒绝缺片、重复、混集、乱序和篡改。完整文本字段与分片数组并存,预算数值报告完整文本超限。
  • handoff_restore.py 及 todo_continuation.py 注册独立的 loopx handoff restore 内容接收入口,同时保留 prepare/inspect/adopt 的身份参数和原权限路径。status_registration.py 更新 CLI help。
  • 状态契约、双语 RFC 替换清单及 managed skill 解释完整字段、恢复命令和非授权边界;CLI smoke、fixture 与两个聚焦测试文件覆盖生产、恢复和大部分失败路径。

关键代码讲解

  1. ProjectAgentContext.payload(project_agent_context.py:499)从一次组装生成完整文本和必要时的所有 shards;build_review_packet 与 handle_review_packet_command 分别把它用于人工 packet 和直接 handoff-only。
  2. split_handoff_text / reassemble_handoff_shards(handoff_fragments.py:292/519)在超限时编码和验证每片,预算内保留单文本;摘要只证明收到的内容一致,不是 sender 或 request 的身份。
  3. restore_handoff_input(handoff_restore.py:19)选择 JSON/Markdown 接收路径;JSON 分片和 manifest 的严格检查有效,但 Markdown 对“看起来像分片、却丢失或移动了信封”的输入会落入未校验的纯文本成功分支,这是下面的阻塞项。

对主干的风险

P1 阻塞:Markdown 分片失去信封后被错误地当成成功恢复。 本 PR 的 render_handoff_transport 会给每片加 【交接分片 i/n】 标题,信封是 HTML 注释。用真实 CLI 生成 25 行合成上下文的两片 Markdown 后,删除注释信封(模拟文档自身提醒的 Markdown 渲染器剥离)再调用 python -m loopx.cli --format json handoff restore --input - --input-format markdown,观察到退出码 0、ok=true,但返回的 handoff_text 不等于原文,仍含“交接分片”标题。仅把信封行缩进两个空格,也得到同样的假成功:restore_handoff_input 看见前缀而调用 restore_handoff_text,后者只识别行首前缀并原样返回。这正穿过了 CR3/CR5 要求的“缺失或改动时无部分成功”边界,接收方可能把传输包装误当成工作上下文。

最小修复是在 Markdown 入口识别分片标题、保留标记或出现在非行首的信封:只要输入表现为分片传输而没有可验证的完整信封组,就返回非零 error_code,绝不降级为普通文本;仍允许真正的预算内 handoff-only 纯文本。为“剥离 HTML 注释”和“缩进信封”各加一个真实 handoff restore CLI 负例,断言无 handoff_text,再重跑 CLI smoke 与聚焦测试。若任意 Markdown 转换无法被可靠检测,文档应收窄支持边界,但本次带有明确分片标题的输入可以判别。

其余风险已较好隔离:两个旧阻塞项中的“完整字段只含首片”与“没有可调用接收入口”已在此 head 修复;本轮独立运行的 223 项聚焦测试、review-packet-cli-smoke.py、Ruff 与 git diff --check 均通过。此前贡献者报告的 19/19 premerge 本轮未独立重跑;依 capability 当前 wait_for_ci=false,未查询 CI。Lark、跨主机、任意渲染器及接收方实际采用/回传不在本 PR 验收范围,不能把此 codec 的成功映射成这些里程碑通过。

语义与 CI 对齐

docs/status-data-contract.md 当前宣称修改的 shards 会严格拒绝且不返回部分文本;上述真实 Markdown 入口反例违反这项当前接收契约。未新增业务请求 ID、授权或状态转移语义,已有完整文本字段和 Todo/claim/lease owner 保持独立。修复后用同一 CLI 负例复测;CI 状态不是本轮结论依据。

我的整体评价

REQUEST_CHANGES。 这次重构把上下文从人工 Review Packet 中分离,补上真实 receiver,并证明预算内路径保持兼容;这些是有用且边界清楚的进展。代码体量主要来自 codec 和真实入口测试,不能只按行数否决,也不必把未来 M2/M3 强加给本 PR。但当前接收端会对一个实际可出现的不完整 Markdown 传输报成功,损害长任务接续及用户对恢复结果的判断。修好上述 fail-closed 分支并加 CLI 回归后,再按新的 exact head 复审。没有发现需要扩大本 PR 到管家路由、工作采用或跨渠道回传的理由。

English verdict: REQUEST_CHANGES - head 68b02bb. Markdown shards with stripped or indented HTML envelopes return success with un-restored transport text. The 223 focused tests, real CLI smoke, Ruff and diff hygiene pass, but the demonstrated receiver-negative case needs a fail-closed fix and CLI regression coverage.

Signed-off-by: huangruiteng <14976749+huangruiteng@users.noreply.github.com>
Signed-off-by: huangruiteng <14976749+huangruiteng@users.noreply.github.com>

@huangruiteng huangruiteng 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.

动机

#4444 修复项目 Agent 交接超过 16 行或 1800 字符时的有损裁剪。旧路径可能直接删掉待办、材料或交付约束,让接收者在不完整上下文中继续工作。本次按此前 CR1–CR5 的交付边界复审最新 head:完整内容可从 CLI 产出并严格恢复;这是一段可独立使用的交接能力,不把内容完整性误称为任务已被接收或完成。

改动思路

现有 collect_status、Goal/Todo 和权限路径仍是事实与执行权限的来源。assemble_project_agent_context 只读组装完整交接,人工 Review Packet 与 --handoff-only 共用它;超预算时,codec 另给出有序分片、校验和及完整摘要。loopx handoff restore 只恢复内容,不打开 registry、不执行命令,也不领取 Todo。预算内输出的七类 action kind 与基线逐字段一致,超限才出现分片传输。前次复审发现 Markdown 信封被剥离或缩进会假成功;本 head 让可识别的分片标记必须进入校验路径,无法校验就明确失败。

具体改动

  • project_agent_context.py 从原 review_packet.py 拆出只读上下文组装;完整文本字段继续提供完整内容,分片数组和 manifest 只在超限时出现。status.py 的直接交接路径不再为此先构造人工评审展示。
  • handoff_fragments.py 实现定长分片、顺序及内容校验、Markdown 传输和恢复。此次补丁识别可见分片标题及位置异常的信封,禁止受损传输降级为普通文本成功。
  • handoff_restore.py 将 Markdown 输入统一送入恢复分类器;JSON 恢复和无分片纯文本路径继续保留。todo_continuation.py 注册内容恢复命令,原 prepare/inspect/adopt 身份与权限检查不变。
  • 状态契约、双语 RFC 和 managed skill 说明内容恢复的支持范围;聚焦测试及公开 CLI smoke 覆盖完整、缺片、乱序、篡改、信封剥离与缩进。

关键代码讲解

  1. ProjectAgentContext.payload 从一次状态投影返回完整 prepared text 与可选全部分片,供完整 packet 和直接交接两条真实调用链使用。
  2. split_handoff_text 与 reassemble_handoff_shards 对超限文本生成、验证有序信封和全文摘要;预算内原文不加包装,摘要只证明内容一致,不证明发送者身份。
  3. restore_handoff_text 在最新 head 检查分片标题和信封的数量、相邻位置及行首格式;受损包装返回 HandoffShardError,完整集合才可重组。
  4. restore_handoff_input 让 Markdown 与 JSON 都通过对应内容校验,成功只返回恢复文本,失败由 CLI 返回非零及 error_code,无部分 handoff_text。

对主干的风险

此前 P1 反例现已修复:我用真实 handoff restore CLI 对同一两片合成文本复测,完整 Markdown 退出 0 且逐字等于原文;剥离 HTML 信封或将信封缩进时均退出 1、error_code=envelope,且不返回交接文本。新增 CLI 回归还覆盖只缺一个信封;真正无分片文本仍可原样恢复。局部合并当前 main 后,231 项聚焦测试、公开 Review Packet CLI smoke、其他相关 smoke、Ruff、限定模块 mypy、diff hygiene 均通过;风险预合并检查 19/19 通过、无失败或人工 hold。前次缺少 node_modules 的语义 smoke 环境问题已通过 npm ci 补齐后跑通;CI 按本 Goal 的 wait_for_ci=false 策略未查询。

剩余边界是任意渲染器若同时删除可见标题与隐藏信封,纯文本无法证明自己原本是分片;文档因此要求在这类转换中使用原始 JSON。Lark、跨主机传递、接收方实际采用与结果回传不属于本 PR;不能由 codec 通过推断这些旅程已验收。没有新增持久状态、授权、调度或业务领域特化错误文案。

语义与 CI 对齐

当前状态契约要求有分片标记的受损交接不得部分成功。本 head 的真实 CLI 负例与文档现在一致;复用现有 Goal/Todo/claim 权限语义,没有另造 agent 生命周期或接收状态。若后续要证明工作采用与回传,应在协调能力的 owner 上另行验收。此次本地检查覆盖受影响的生产 CLI 入口及失败路径,CI 等待策略不改变合并前的 exact-head 复审要求。

我的整体评价

APPROVE,exact head 2b444a72592c1a6db7f0dc5cf148e212f3e047c0。 先前阻塞项已由可复现的真实入口负例修掉,长任务交接不再因已知 Markdown 转换产生假成功,用户也能得到明确重试反馈。新增的分片机制有维护成本,但相对“悄悄丢掉执行约束”的失败后果是合理的;上下文组装与内容恢复各有单一 owner,没有复制 TS 协调状态。预算内兼容性、完整性和失败反馈均有本地证据,未发现新的阻塞问题。后续仍需按原路线验证跨 Agent 采用及结果回传。

English verdict: APPROVE - head 2b444a7. The previously blocking Markdown false-success case now fails closed in the real CLI. Focused tests (231 passed), CLI smokes, 19/19 risk-based premerge checks, and exact-head review evidence pass; CI was not queried under the resolved wait_for_ci=false policy.

@huangruiteng
huangruiteng merged commit b5340da into loopx-project:main Sep 25, 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