feat(handoff): complete context and strict receiver independent of review packets - #4444
Conversation
huangruiteng
left a comment
There was a problem hiding this comment.
动机
超预算 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 个测试覆盖分片、缺失/乱序/篡改/重复、围栏与续行。
关键代码讲解
split_handoff_text(handoff_fragments.py:285):未超预算时原样返回[text](无信封),超预算才分片;每片生成后再核对len(shard.split("\n")) <= 16、len(shard) <= 1800,最后reassemble_handoff_shards(shards) != text就抛错——编码器自校验,这点做得扎实。review_packet.py:711-712:handoff_shards = split_handoff_text(prepared_agent_text)、agent_text = handoff_shards[0]。这一行决定了project_agent_handoff/handoff_text的语义在超预算时从"完整文本"变成"第 0 片"。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.
RFC 对齐补充评审评审对象: 本次按请求补充 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 描述及相关源码:
按 RFC 节奏建议这样收口:
M2 的身份与回执边界来自§5.6:内容哈希不能合并独立请求,传输、评估、执行和答案送达是独立事实。未来如迁移这些状态规则,再执行TS 迁移 RFC §5的 owner/删除旧规则/桥接成本证明;纯传输 codec 不需要伪装成一次状态机迁移。 对主干的风险当前主要风险仍是完整文本字段变成首片后,旧接收方式可能遗漏约束或命令,以及真实 CLI 溢出路径的证据不足。这里的“收齐再执行”需要落实到接收路径;仅写提示不能声称已有机器强制保证。 还有两项非阻塞的演进约束:
结合刚合并的语义词汇 M0,下一修订更新到当前基线时,应检查新增协议常量是否使生成 inventory 过期,并运行 我的整体评价保留 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. |
Change request:把交接上下文从 Review Packet 中分离,补齐可用的接收路径对应 head: 这是维护者针对长期 handoff 方向提出的具体修订要求,补充已有 REQUEST_CHANGES,并细化上一条 RFC 意见。本次希望包含一次有界的职责重构,而不止增加分片恢复命令。 这是明确的设计范围调整,不是声称在同一 head 上又复现了一个新的运行时缺陷。 动机当前 长期 handoff 要支持有上下文的工作委派、接收方重新评估、会话替换和结果回传。因此需要调整依赖方向:交接上下文有自己的组装边界,Review Packet 消费它来生成人工可读投影,传输层再按渠道需要编码。 依据:handoff RFC §5.2–5.6。该 RFC 已要求区分应用、协作语义和运行时/渠道适配,现有模块位置是迁移输入。 改动思路建议本次交付路径如下;方框表示职责,不要求照此创建同名模块或公共 schema: 这里的“共同”必须由真实的 full packet 与 handoff-only 路径消费。不要仅搬一个函数、保留两份事实推导,也不要为未来消费者建立空框架。接收端恢复成功只证明内容完整,不代表已接受工作、获得 claim/lease 或可直接执行其中的命令。 具体改动CR1:提取上下文组装职责,保留 Review Packet 的展示职责请先列出
完成标准: 状态/上下文事实只有一个组装来源,两个现有输出路径均消费它;旧的重复组装逻辑在本 PR 删除,调用关系与职责可以从源码直接看清。 CR2:分片属于传输;修正完整文本字段的语义当前
完成标准: 完整交接、单片和恢复结果在契约上不混淆;未收齐内容的兼容消费者没有“成功收到完整交接”的假象。 CR3:交付接收方实际能用的校验/恢复入口请提供一个已文档化、可以由接收 Agent 调用的真实入口,并在 managed skill 中写出可运行步骤。它应属于 handoff 的内容接收职责;不要仅因当前生产者是 具体命令拼写可以沿用仓库注册模式;若选用现有
完成标准: 一个接收方仅凭 shipped CLI/skill 即可恢复合法交接,识别不完整输入;无需临时写 Python 去导入内部函数。 CR4:补齐 RFC replacement map 与公开操作说明请更新 handoff RFC §5.9 的替换表及中英文镜像,明确登记
同时修正 对主干的风险CR5:按真实消费路径补验证新增测试应先从下面这些语义要求写出预期,再测试实现。不要把实现生成的内容反过来当作唯一 oracle。
复用并扩展 下一 head 请运行相关 focused tests、现有 packet/CLI 回归,以及 我的整体评价REQUEST_CHANGES 保持。建议把“上下文组装职责分离 + 明确的兼容表示 + 接收端闭环 + 聚焦验收”作为一个可独立交付的修订。 它共享同一个修改原因,属于本 PR 合适的配套重构。 本次不要求实现通用 M2 状态机、M3 自动回传、跨主机持久化、历史召回、新 artifact 服务或整体 TypeScript 迁移。纯文本/投影逻辑可以保留 Python;未来真正迁移协作状态决策时,再按 TS 迁移 RFC证明单一 owner、旧规则删除与桥接成本。 也不要求现在删除 请在下一修订说明中逐项回复 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. |
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>
7a04a3e to
68b02bb
Compare
|
已按此前完整评审及 CR1–CR5 重构,并 rebase 到
生产者/消费者盘点: 有界重构已应用在共享上下文和严格传输边界,没有新增通用请求库、持久化 brief store、协作状态机或第二个权限 owner。当前增量是“已有交接内容不再因长度而丢失,接收方有实际可调用的恢复路径”;它不证明接收方已采用任务,也不代表 M2/M3 自动协作/回传验收完成。 验证(source-checkout Python 3.13.13):
未运行 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 |
huangruiteng
left a comment
There was a problem hiding this comment.
动机
评审 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 与两个聚焦测试文件覆盖生产、恢复和大部分失败路径。
关键代码讲解
ProjectAgentContext.payload(project_agent_context.py:499)从一次组装生成完整文本和必要时的所有 shards;build_review_packet与handle_review_packet_command分别把它用于人工 packet 和直接 handoff-only。split_handoff_text/reassemble_handoff_shards(handoff_fragments.py:292/519)在超限时编码和验证每片,预算内保留单文本;摘要只证明收到的内容一致,不是 sender 或 request 的身份。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
left a comment
There was a problem hiding this comment.
动机
#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 覆盖完整、缺片、乱序、篡改、信封剥离与缩进。
关键代码讲解
ProjectAgentContext.payload从一次状态投影返回完整 prepared text 与可选全部分片,供完整 packet 和直接交接两条真实调用链使用。split_handoff_text与reassemble_handoff_shards对超限文本生成、验证有序信封和全文摘要;预算内原文不加包装,摘要只证明内容一致,不证明发送者身份。restore_handoff_text在最新 head 检查分片标题和信封的数量、相邻位置及行首格式;受损包装返回HandoffShardError,完整集合才可重组。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.
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.
ProjectAgentContextinto the existing handoff boundary. Full Review Packet and direct handoff-only CLI share that assembly; human questions and gate drafts remain presentation-only.project_agent_handoffandhandoff_textcomplete. 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.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.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
7a04a3e700989204116410af7fe6b0a4aead27efonto41ba6f4d97ba2219f4e7d7e24f164cd34f85051c. Validation targets the revised head recorded in the accompanying revision comment.Entry Points And Boundaries
CLI and managed skill changed. The Dashboard independently builds
buildActionPacket/buildApprovedAgentHandofffrom status inapps/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.