Skip to content

fix(issue-fix): record changed paths without Git quoting - #8426

Merged
huangruiteng merged 12 commits into
loopx-project:mainfrom
gcl-coder:fix/issue-fix-changed-files-paths
Nov 10, 2026
Merged

huangruiteng merged 12 commits into
loopx-project:mainfrom
gcl-coder:fix/issue-fix-changed-files-paths

Conversation

@gcl-coder

@gcl-coder gcl-coder commented Nov 9, 2026 •

Copy link
Copy Markdown
Contributor

动机 / Motivation

issue-fix 的调用方验收包需要准确列出分支真实变更的文件,并可靠判断这些证据是否足以进入评审。主干原先按 Git 的默认文本输出按行切分,并把引号、换行和首尾空格当作路径内容,中文或特殊文件名无法与仓库文件对齐。

本 PR 前几轮已修复 CR/LF/CRLF 合并、合法 UTF-8 字面值、非 UTF-8 路径未就绪规则,以及 20 条展示截断前的全量字节健康判断。本轮发现 Git 默认的未跟踪目录摘要仍会让完整输入依赖 status.showUntrackedFiles:同一个包含 26 个文件的目录可能只返回一条 nested/。本修订明确要求 Git 展开未跟踪目录,再计算完整数量、不可表示性和就绪状态。

改动思路 / Approach

  • 在 NUL 分帧、去重和聚合阶段始终保留 bytes,并收集全部唯一路径。
  • 未跟踪文件读取明确使用 status --porcelain -z --untracked-files=all,不继承目录摘要设置,也不忽略 Git 的 exclude 规则。
  • 在完整集合上计算不可表示路径数量,然后才投影 20 条公开列表。
  • changed_file_count 表示完整去重集合大小,changed_files / files_changed 仍最多 20 条;changed_files_truncated 只在完整集合超过 20 时置为 true。
  • 合法 UTF-8 路径原样输出,包括真实 U+FFFD、CR/LF、首尾空格、反斜杠以及原本以 git-bytes: 开头的名字。
  • 非 UTF-8 路径仅作为 git-bytes:<repr(bytes)> 诊断值保留,并记录全量不可表示计数;存在这种路径时 review_packet.ready=false。

具体改动 / Changes

对主干的风险 / Risks

  • 路径测试、reviewer-history framing 与临时工作区测试共 19 passed。
  • 真实 CLI 对照:26 个嵌套未跟踪文件在默认目录摘要和 status.showUntrackedFiles=no 下均得到 changed_file_count=26、20 条显示、truncated=true、ready=true。
  • 25 个普通文件加 b"z-\\xff.txt" 时,默认排序与 diff.orderFile 提前排序均得到不可表示计数 1、ready=false;移除该路径并重建 HEAD 后恢复计数 0、ready=true。
  • 合法 git-bytes:report.txt 与真实 U+FFFD 保持字面值。
  • macOS 文件系统不接受这些原始字节文件名,因此碰撞夹具从真实 Git 索引/树构造。原生 Windows 未运行;全量 issue-fix 测试在当前环境受 TypeScript Effect runtime 权限限制,相关摘要保留为环境失败。远端 CI 状态见 PR checks。

Signed-off-by: ChengLong GU <88359731+gcl-coder@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] NUL 分帧前仍会把回车变成换行。 _run_git_capture() 的 text=True 会将 CR 和 CRLF 转换为 LF,三个 diff 路径也一样。实际 caller-repo-branch --execute 中,Git 返回 12 个不同路径,评审包只记录 6 个且仍显示 ready=true。请以字节模式获取路径输出,并用 LF、CR、CRLF 三种真实文件复验公开包。 对应改动

动机 / Motivation

让 issue-fix 评审包记录分支实际变更的文件,让评审者能定位每个路径。 Issue-fix 调用方执行 caller-repo-branch 后,用评审包的文件清单核对本地修复。

主干把 Git 的引号和转义留在清单里,中文和带空格的路径无法直接对上文件。换行和回车变体虽然同样被转义,但仍各占一条记录。 候选能准确写出中文、首尾空格和只含 LF 的名称。有效的回车路径仍会丢失,评审清单可能只剩一部分文件。

候选能准确写出中文、首尾空格和只含 LF 的名称。有效的回车路径仍会丢失,评审清单可能只剩一部分文件。 本轮在 macOS 的隔离 Git 仓库验证合法 UTF-8 路径。Windows 和无法解码为 UTF-8 的文件名字节未验证。

改动思路 / Approach

保留 Git NUL 分帧。三个 diff 路径和 status 应共用保留字节的读取方式,避免文本转换先改掉路径。相邻 reviewer history 也使用 NUL,可比对捕获和解码语义。 仅本地分支修复证据里的文件清单,保留原 20 项限额、验证失败和本地权限行为。

具体改动 / Changes

评审提交 8a48049c687822f9b1a7b62dc4ed2cdd022a7017,对照 71190b6b4ef4e146f3bf4a10d31ce61ac42fd021。2 个文件,+164/−10。路径捕获与解析只改一个生产文件。新增用例缺少造成静默合并的成对文件名。

规范:loopx/capabilities/issue_fix/docs/protocols/issue-fix-acceptance-loop-v0.md(71190b6b4ef4e146f3bf4a10d31ce61ac42fd021)。

  • exact-repo-relative-paths(待修):评审包记录准确的仓库相对变更路径。 真实 Git 的 NUL 分隔输出包含 12 个不同路径。公开 CLI 在候选上只报告 6 个,少掉的 6 个都有 CR 或 CRLF。已提交、暂存、未暂存和未跟踪四个来源均受影响。changed_files_truncated=false,评审包仍显示 ready=true。主干的 12 条引号表示各自不同,可确认这次新增了去重丢失。
  • caller-validated-branch(已验证):分支经调用方批准且实际验证,无变化不 ready。 同一 repo 干净分支运行验证不 ready。
  • private-and-remote-boundaries(已验证):只授权本地执行,计划不读本地,包不含本机路径。 未传 --execute 时返回计划,且不读取本地仓库。空分支验证通过仍不会标记 PR-ready。

关键代码讲解

  • _git_untracked_paths:按 Git status 的 NUL 记录取 ??,在改动后的调用仍使用 text=True 的旧 helper。 源码
  • _changed_files:三个 diff 使用 NUL。捕获仍转换回车,聚合再把不同路径当成相同字符串去重。 源码
  • _split_git_paths:拆分不会再改变记录,但无法恢复进入函数前已改写的字节。 源码
  • build_issue_fix_caller_repo_branch_packet:当前只需有一条路径且验证通过即可进入 ready,因去重丢掉部分路径时没有可见标记。 源码
  • special path tests:覆盖中文、空格、LF、重命名和上限。需增加同一来源内的 CR/CRLF 对照。 源码

对主干的风险 / Risks

同一真实 Git fixture 和公开 CLI 配对。主干 12 条转义记录,候选 6 条。11 项 Python 测试通过。快速预合并 6 项直接和 3 项所选检查无失败。

真实 Git 的 NUL 分隔输出包含 12 个不同路径。公开 CLI 在候选上只报告 6 个,少掉的 6 个都有 CR 或 CRLF。已提交、暂存、未暂存和未跟踪四个来源均受影响。changed_files_truncated=false,评审包仍显示 ready=true。主干的 12 条引号表示各自不同,可确认这次新增了去重丢失。

本轮在 macOS 的隔离 Git 仓库验证合法 UTF-8 路径。Windows 和无法解码为 UTF-8 的文件名字节未验证。

语义与 CI 对齐

未传 --execute 时返回计划,且不读取本地仓库。空分支验证通过仍不会标记 PR-ready。 本轮未查询或等待远端 CI。

我的整体评价 / Verdict

保留 NUL 分帧,修正路径读取后再复审。 以字节模式捕获路径命令的 stdout,按 NUL 拆帧后按既定路径编码解码,再去重。为同一来源的 LF、CR、CRLF 分别建真实文件,并断言公开评审包的路径和计数。

English verdict: REQUEST_CHANGES. Head 8a48049. Capture path output as bytes before decoding. The real caller-branch packet records six of 12 distinct UTF-8 paths while readiness remains true.

def _git_untracked_paths(workspace: Path) -> list[str]:
"""Return the untracked paths exactly as Git recorded them."""

result = _run_git_capture(workspace, ["status", "--porcelain", "-z"])

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.

[P2] NUL 分帧前仍会把回车变成换行。 _run_git_capture() 的 text=True 会将 CR 和 CRLF 转换为 LF,三个 diff 路径也一样。实际 caller-repo-branch --execute 中,Git 返回 12 个不同路径,评审包只记录 6 个且仍显示 ready=true。请以字节模式获取路径输出,并用 LF、CR、CRLF 三种真实文件复验公开包。

Signed-off-by: ChengLong GU <88359731+gcl-coder@users.noreply.github.com>
@gcl-coder

gcl-coder commented Nov 9, 2026 •

Copy link
Copy Markdown
Contributor Author

P2 成立,已按字节模式修复。

_run_git_paths() 现在不传 text=True:三个 diff 和 status 的 stdout 以 bytes 返回,先按 NUL 拆分,再逐条 UTF-8 解码,之后才做去重。文本模式会在分帧之前把 CR、CRLF 折成 LF,line\n、line\r、line\r\n 三个合法名字因此在旧实现里合并成一条。dirty 检测 _git_status_lines() 只看是否非空,保持原样。

复核用的是同一类真实夹具:一个仓库四个来源(已提交、已暂存、未暂存、未跟踪)各放 LF、CR、CRLF 三份,走公开 CLI issue-fix caller-repo-branch --execute --format json。现在 rc=0、branch_ready=true、12/12 条、名称与 Git 输出逐字节一致、changed_file_count=12、changed_files_truncated=false;修复前是评审看到的 6/12。

新增/补齐用例:

  • 未跟踪来源的 LF/CR/CRLF 三条必须并存(旧实现会去重成一条);
  • 已提交 + 暂存来源同样保留 CR 名字;
  • 公开 packet 分别断言三类与四来源 12 条场景的 changed_file_count 和完整名称集合。

本地 9 条新用例加既有 6 条相关测试共 15 passed。原生 Windows 未执行;控制字符文件名用例仅在 POSIX 运行,-z 本身是 Git 通用选项。

Signed-off-by: ChengLong GU <88359731+gcl-coder@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] 当 Git 路径包含非 UTF-8 字节时,decode(..., errors='replace') 将 lossy-\xfe.txt、lossy-\xff.txt 和真实的 lossy-\uFFFD.txt 都变成 lossy-�.txt。真实 Git 树的 diff 有 3 项,主干包也记录 3 项,当前提交去重后只记录 1 项,同时仍返回 review_packet.ready=true。未跟踪路径使用同样的解码。 在两类路径读取中复用无损编码,或为不可解码的名字返回明确的未就绪结果。增加含真实 U+FFFD 的冲突用例。 对应改动

动机 / Motivation

让 issue-fix 的公开验收包保留实际变化的路径,使后续评审能定位和核查修复。 loopx issue-fix caller-repo-branch --execute --validation-command true(本地 Git 仓库,JSON 输出)

旧实现按行读取 Git 的 C 风格转义。三个不同的 Git 路径在包中仍有三条可区分记录。 NUL 分帧及 bytes 捕获已修复旧提交的 CR/LF/CRLF 合并。四类来源的 12 条有效 UTF-8 路径全部原样进入包。

NUL 分帧及 bytes 捕获已修复旧提交的 CR/LF/CRLF 合并。四类来源的 12 条有效 UTF-8 路径全部原样进入包。 Windows 文件名及平台行为留待平台验收。反例从 Git 树读取,因此独立于 Mac 本地文件系统能否创建该字节名。

改动思路 / Approach

在两类路径读取中复用无损编码,或为不可解码的名字返回明确的未就绪结果。增加含真实 U+FFFD 的冲突用例。 原有包继续负责去重、截断和执行边界。 范围集中在当前入口、已选数据载体和可验证兼容条件。

具体改动 / Changes

评审提交 074d3ecc16f583c0a50718b2b546e789824a62a5,对照 71190b6b4ef4e146f3bf4a10d31ce61ac42fd021。2 个文件,+297/−17。全部改动集中在路径采集与测试。相对前次评审增加字节模式和覆盖所有变更来源的用例。

规范依据见 loopx/capabilities/issue_fix/docs/protocols/issue-fix-acceptance-loop-v0.md(71190b6b4ef4e146f3bf4a10d31ce61ac42fd021)。

  • utf8-fidelity(已验证)。保留合法 UTF-8 的控制字符和空白。 NUL 分帧及 bytes 捕获已修复旧提交的 CR/LF/CRLF 合并。四类来源的 12 条有效 UTF-8 路径全部原样进入包。
  • distinct-path-evidence(待修)。公开验收包记录可区分的 repo-relative changed files,包 readiness 依赖真实变更证据。 当 Git 路径包含非 UTF-8 字节时,decode(..., errors='replace') 将 lossy-\xfe.txt、lossy-\xff.txt 和真实的 lossy-\uFFFD.txt 都变成 lossy-�.txt。真实 Git 树的 diff 有 3 项,主干包也记录 3 项,当前提交去重后只记录 1 项,同时仍返回 review_packet.ready=true。未跟踪路径使用同样的解码。
  • execute-scope(已验证)。保留显式本地执行与原有发布边界。 无 --execute 的计划保持零本地读取,干净 issue 分支保持未就绪。两条路径都已独立验证。

关键代码讲解

  • _run_git_paths。Git 在现有工作区读取 NUL 记录,避免文本层转换回车。 源码
  • _split_git_paths。逐记录解码。替换解码使不同的合法 Git 字节名合并。 源码
  • _git_untracked_paths。按 porcelain 状态跳过重命名源,读取未跟踪项时使用相同解码。 源码
  • _changed_files。合并 committed、unstaged、staged 与 untracked,按字符串去重并返回有界列表。 源码

对主干的风险 / Risks

15 项本地测试通过,快速预合并 6 项直接和 3 项所选检查通过。另以实际 Git 树和 CLI 配对核验 12 条 UTF-8 路径及 3 条字节路径。

当 Git 路径包含非 UTF-8 字节时,decode(..., errors='replace') 将 lossy-\xfe.txt、lossy-\xff.txt 和真实的 lossy-\uFFFD.txt 都变成 lossy-�.txt。真实 Git 树的 diff 有 3 项,主干包也记录 3 项,当前提交去重后只记录 1 项,同时仍返回 review_packet.ready=true。未跟踪路径使用同样的解码。

Windows 文件名及平台行为留待平台验收。反例从 Git 树读取,因此独立于 Mac 本地文件系统能否创建该字节名。

语义与 CI 对齐

无 --execute 的计划保持零本地读取,干净 issue 分支保持未就绪。两条路径都已独立验证。 远端 CI 超出本轮核验范围。

我的整体评价 / Verdict

原 CR/LF 修复成立。当前验收包仍会少报 Git 路径,需要修复后再评审。 在两类路径读取中复用无损编码,或为不可解码的名字返回明确的未就绪结果。增加含真实 U+FFFD 的冲突用例。

English verdict: REQUEST_CHANGES. Head 074d3ec. NUL framing fixes the previous CR/LF bug, but replacement decoding collapses three distinct Git paths to one while the public review packet still reports ready.

CRLF names distinct, with leading and trailing spaces intact.
"""

return [item.decode("utf-8", "replace") for item in output.split(b"\0") if item]

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.

[P2] 当 Git 路径包含非 UTF-8 字节时,decode(..., errors='replace') 将 lossy-\xfe.txt、lossy-\xff.txt 和真实的 lossy-\uFFFD.txt 都变成 lossy-�.txt。真实 Git 树的 diff 有 3 项,主干包也记录 3 项,当前提交去重后只记录 1 项,同时仍返回 review_packet.ready=true。未跟踪路径使用同样的解码。 在两类路径读取中复用无损编码,或为不可解码的名字返回明确的未就绪结果。增加含真实 U+FFFD 的冲突用例。

Signed-off-by: ChengLong GU <88359731+gcl-coder@users.noreply.github.com>
@gcl-coder

Copy link
Copy Markdown
Contributor Author

已修复所述 P2,并推送新精确 head 662b17387263e7ebb6bf7950896788364c36dbd3。

  • _split_git_paths 与 _git_untracked_paths 现在返回原始 bytes;_changed_files 也按 bytes 去重,直到构造公开 packet 才显示。
  • 合法 UTF-8 保持原样;非 UTF-8 使用无碰撞的 git-bytes:<repr(bytes)> 显示编码,保留 \xfe、\xff 与真实 U+FFFD 的区别。以保留前缀开头的合法 UTF-8 路径会进入 git-bytes:utf8: 命名空间。
  • 新增真实 Git 树用例:lossy-\ufffd.txt、lossy-\xfe.txt、lossy-\xff.txt 的原始 diff 为 3 条,公开 packet 也保留 3 条不同路径并保持 ready。
  • 路径测试、reviewer-history framing 和临时工作区测试共 17 passed。CLI 复现器返回 0,changed_file_count=3,三条输出分别为 git-bytes:b'lossy-\\xfe.txt'、git-bytes:b'lossy-\\xff.txt' 和 UTF-8 lossy-�.txt。

请复审新 head。原生 Windows 和远端 CI 尚未完成本地核验。

@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] 保留合法 UTF-8 路径的字面值。 在真实仓库的 issue 分支创建 git-bytes:report.txt,执行 issue-fix caller-repo-branch --execute。当前 head 的 _display_git_path() 第214–215行把它写成 git-bytes:utf8:git-bytes:report.txt,两个公开路径列表均如此,且 review_packet.ready=true。基线和上一 head 都输出原名。现有字段和消费者仍按 repo-relative path 使用它,没有编码标记或解码步骤;这里得到的是另一个不存在的地址。请保持合法 UTF-8 路径原值;若支持 byte encoding,需显式区分表示并接入现有消费者,否则本轮可先对不可表示的名字返回未就绪。补一个前缀名称与 byte paths 共存的真实 CLI 回归。

动机 / Motivation

使用 issue-fix 公开验收包定位修复文件的维护者与评审者。 旧版会把中文、首尾空格和控制字符写成转义或合并后的路径。当前 head 修复这些情况,但将真实的 git-bytes:report.txt 改写为 git-bytes:utf8:git-bytes:report.txt,仍把公开评审包标为 ready。

四类来源的 12 个 LF、CR、CRLF 名称完整保留,三个字节路径也不再合并;普通合法 UTF-8 前缀路径仍被改名,需要先修复。 本次只判断本地 caller-repo-branch 的路径证据,不扩展发布权限,不认证 Windows、已安装 Host 或完整长程收益。

改动思路 / Approach

Git bytes 应留在现有 provider IO;本次错误在将 display encoding 混入原路径字段,修复无需新增控制面或通用框架。 当前两文件只修复路径读取与证据;公开路径契约的前缀回归须在本 PR 修好。

三个 diff 与 status 的结果先按 NUL 划分,再在 bytes 上去重,解决 text 模式提前转换 CR/CRLF 和有损解码合并路径的问题。普通命令输出和 dirty 检测保持原 owner,没有必要全面重写 Git IO。新增 git-bytes: 字符串 namespace 虽避免当前 byte-name 冲突,却越过了展示与既有路径字段的边界;修复旧问题不能以静默改变正常输入为代价。

具体改动 / Changes

精确 head 662b17387263e7ebb6bf7950896788364c36dbd3,base 71190b6b4ef4e146f3bf4a10d31ce61ac42fd021;两文件 +403/-20,其中新增测试303行。相对旧 head 074d3ecc16f583c0a50718b2b546e789824a62a5,非 UTF-8 合并缺陷已解决,但本轮另验证整个 base-to-head 提案。

接受规格为 loopx/capabilities/issue_fix/docs/protocols/issue-fix-acceptance-loop-v0.md,spec_revision 71190b6b4ef4e146f3bf4a10d31ce61ac42fd021。repo-relative-paths not_met:合法 UTF-8 名字被改写;distinct-path-evidence 在四来源控制字符和三个 byte paths 场景 implemented;execute-and-privacy implemented,计划和无变化分支保持安全原义。新 codec 的 docstring 不是独立的协议授权。

关键代码讲解

  • _run_git_paths:stdout 以 bytes 捕获,避免 text=True 在分帧前转换 CR/CRLF。
  • _display_git_path:普通 UTF-8 名称大多原样显示,但 startswith('git-bytes:') 分支将合法名称再次编码;新增公共表示没有随原字段提供解码契约。
  • _changed_files:合并 committed、unstaged、staged、untracked,按 raw bytes 去重,沿用20项限额,再把编码结果直接返回给 builder。
  • build_issue_fix_caller_repo_branch_packet:两个原有路径字段直接接收这些字符串,验证通过且列表非空时仍可 ready,因此计数正确不代表文件地址正确。

对主干的风险 / Risks

完整 focused 三模块 17 PASS,标准 premerge 6 direct +6 selected PASS。独立 CLI 同一七组真实 Git 输入在 base、074d、662b 配对:四来源的 LF/CR/CRLF 共12条在当前逐字保留;074d 将三个 byte paths 合并为1条,当前保留3条。无 execute 不读本地,干净 issue 分支不 ready,验证过程没有改写源仓库、外部写入或本机路径泄露。

但合法前缀输入在 base/074d 保持 git-bytes:report.txt,当前变成 git-bytes:utf8:git-bytes:report.txt;这不是未归因的历史失败,是新分支可独立复现的回归。现有测试没有该合法 UTF-8 前缀,全部通过不能覆盖它。请按首段收窄表示边界后重跑公开 CLI 和当前整组检查。

语义与 CI 对齐

原 public packet 的字符串仍是 repo-relative paths;新增未声明 namespace 不能自行改变该契约。未增加 actor/审批/执行权限,--execute 仍为显式本地操作开关。完整语义扫描通过只证明其覆盖范围,没有证明新表示与现有消费者一致。本轮未获取、轮询或等待远端 CI。

我的整体评价 / Verdict

REQUEST_CHANGES。NUL/bytes 的局部进展有独立价值,体量和原 IO owner 的归属相称;当前 long_horizon 与 user_experience 仍有 regression,因为错误地址会继续进入评审/证据链并要求人工解释。最小修复就在现有表示边界,不需要新 Goal、通用框架或额外用户确认。旧 CR/LF 与 byte 合并发现已分别核验解决,保留其旧版本结论,不把它们改名为本轮仍失败。

已检查现有 CLI/JSON/Markdown 调用路径;此差异没有渲染页、布局或控件变化,视觉评审不适用。 未验证范围:Windows、安装态 Host 与模型采用未验证;没有待验的渲染布局。 没有合并或更改共享安装。

English verdict: REQUEST_CHANGES — 662b173. Real CLI comparisons confirm the old CR/LF and byte-name fixes, but the new reserved-prefix branch rewrites a valid UTF-8 pathname while the existing path fields still report readiness. Preserve literal valid paths or introduce an explicit compatible representation before approval.

except UnicodeDecodeError:
return f"{_GIT_BYTE_PATH_PREFIX}{path!r}"
if text.startswith(_GIT_BYTE_PATH_PREFIX):
return f"{_GIT_BYTE_PATH_PREFIX}utf8:{text}"

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.

[P2] 保留合法 UTF-8 路径的字面值。真实仓库中创建 git-bytes:report.txt 后运行公开 issue-fix caller-repo-branch --execute,当前分支将两个公开路径字段均改写为 git-bytes:utf8:git-bytes:report.txt,同时仍报告 review_packet.ready=true;base 与上一 head 输出原名。原字段和消费者使用 repo-relative path,没有相应解码步骤,结果指向不存在的文件。请保持有效 UTF-8 路径原值;若支持字节编码,显式区分表示并适配消费者,或先对不可表示的名称返回未就绪。增加合法前缀与 byte paths 共存的真实 CLI 回归。

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

已修复并推送新 head 6a04d50ee204633424b115464fc15b4ac9a9b2df。

  • 合法 UTF-8 路径现在始终按字面值输出;真实 git-bytes:report.txt 不会再被改写成 git-bytes:utf8:...。
  • 非 UTF-8 路径仅作为 git-bytes:<repr(bytes)> 诊断值保留,并记录 changed_files_unrepresentable_count / files_changed_unrepresentable_count;只要存在这种路径,review_packet.ready=false,不再把不可打开的显示值当作 repo-relative path 放行。
  • 新增真实 Git 树用例,同时放入 git-bytes:report.txt、真实 U+FFFD、\xfe 与 \xff;公开 builder 返回 4 条证据、2 条不可表示项、合法前缀保持原值且 ready=false。
  • 路径测试、reviewer-history framing 与临时工作区测试共 17 passed。CLI 复现返回 0,changed_file_count=4、files_changed_unrepresentable_count=2。
  • 协议文档已补明合法 UTF-8 字面输出和不可表示路径未就绪的消费者边界。

请复审新 head。

Signed-off-by: ChengLong GU <88359731+gcl-coder@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] 在截取展示列表前判断完整变更集的可表示性。 _changed_files() 的 add_paths 在20条后返回,新增计数又只遍历 files[:20](第332–335行)。真实 Git issue 分支提交25个 a00.txt–a24.txt 加一个字节名 b"z-\xff.txt",执行公开 caller-repo-branch --execute 并让 caller validation 通过:当前输出 truncated=true、不可表示计数0、ready=true。保持 Git HEAD/tree 和校验不变,仅用 diff.orderFile 将 z* 排在前面,就变成计数1、ready=false。因此作者回复中“只要存在这种路径”即不就绪的修复仍可被展示顺序绕过。在完整 raw-byte 变更集合上先计算不可表示性,再截取20条展示;同时调整计数与 validator 的范围约束,避免用截断视图的零计数证明全量不存在。 请补同一公开 CLI 输入的前后排序及移除不支持路径后恢复用例,保留20项输出上限。

动机 / Motivation

使用 caller-repo-branch 验收包定位修复文件、决定是否进入评审的维护者与自动调用方。 原版把控制字符和中文路径写成 Git 引用字符串;当前 head 保留合法名称,但同一26文件变更仅调整 diff 展示顺序就会把 ready 从 true 改为 false。

四类来源的12个控制字符路径和合法 git-bytes: 前缀均已保真;不可表示路径落在20项上限之外仍被错误放行为 ready。 范围为现有本地 Git 验收入口;不新增发布、合并或执行授权,不扩展其他 capability,也不认证 Windows、安装态 Host 或完整长程收益。

评审先读取固定基线协议和之前的发现,再分别判断旧发现修复与整个提案。原调用已经给出仓库、分支和校验命令,仍只需一次有授权的调用,无需新增确认轮次。问题是当前就绪信号不再只由同一组修复事实决定,后续自动评审或人工定位会承担额外排查成本。

改动思路 / Approach

Git 字节读取归属现有 provider IO;路径可表示性属于就绪不变量,20项上限属于展示,二者必须分开计算。 本 PR 保留现有 acceptance_loop owner,仅需在全量判定后截取展示,并覆盖相同变更集的顺序与恢复反例。

保持现状会继续输出不能直接定位的引用字符串;只改文本拆行或关闭 quotePath 仍不足以保留控制字符和 byte identity。新增 bytes/NUL 读取属于本地 Git provider 的恰当小修,复用 reviewer recommendation 的 POSIX 路径归一化反而会丢失首尾空格和反斜杠。不需要新 codec 注册表、控制面、用户设置或额外发布步骤。当前机制体量相称,阻断点是这个可局部修复的不变量。

具体改动 / Changes

审查准确 head 6a04d50ee204633424b115464fc15b4ac9a9b2df,base 71190b6b4ef4e146f3bf4a10d31ce61ac42fd021,上轮正式评审为 662b17387263e7ebb6bf7950896788364c36dbd3。完整提案3个路径 +459/−22:生产代码134/−22、协议6行、新测试319行。五个提交均有 DCO sign-off。上轮合法 git-bytes:report.txt 被改名的问题已独立验证修复;旧 CR/LF 和 byte-name 合并问题也分别保留原版本结论,不当作本轮仍失败。

规范基线为 loopx/capabilities/issue_fix/docs/protocols/issue-fix-acceptance-loop-v0.md,spec_revision 71190b6b4ef4e146f3bf4a10d31ce61ac42fd021。repo-relative-paths、validation-and-change-readiness、execute-and-privacy 的原有条件通过本地 caller 路径验证。新增不可表示性阻断另依既有评审讨论和当前修复承诺判断;head 新增文档没有被当成独立授权,当前完整集合边界仍失败。

关键代码讲解

  • _run_git_paths:先按 bytes 捕获,再按 NUL 分帧,避免 text 模式在分帧前转换 CR/CRLF。
  • _display_git_path:合法 UTF-8 直接保留,包括 git-bytes: 前缀;非法字节返回可区分的诊断和布尔标志,定位旧前缀修复。
  • _changed_files:汇总 committed、unstaged、staged、untracked。Git 已返回完整输出,但收集和新增计数都受20项展示限制,首段反例就在这里。
  • build_issue_fix_caller_repo_branch_packet:沿用 caller validation 和分支 owner,在原条件上加计数等于零;两个 JSON count 都来自同一截断结果,validator 也无法补回丢失事实。

对主干的风险 / Risks

PASS:三模块17项局部测试通过。相同10组真实 Git/公开 CLI 输入分别运行于 base、上一评审 head 和当前 head。当前四类来源12个 LF/CR/CRLF 名称逐字保留,quotePath 开关下相同;合法前缀、真实 U+FFFD、中文、首尾空格和反斜杠正常。小集合的两个非法字节路径被阻断;校验失败、无变更、无 execute 的缺失仓库均维持原安全边界。移除不支持的路径后恢复 ready,且所有已执行调用都未改写 fixture 的 HEAD/index,未发生外部读写或本机路径捕获。

FAIL:当前10组独立要求检查中9组满足,1组为首段截断逃逸。同一 Git HEAD/tree 的展示顺序对照是直接反例。原17项测试分别覆盖20项上限和4条 byte paths,却没有组合两者,因而全绿仍能漏检。base 和上轮的旧失败已完整保留,并用各自实际输入/输出区分,不将旧环境或旧版本失败移名为作者当前缺陷。

本地验证:标准 premerge 的6项 direct 通过,初次15项 selected 中14项通过;语义扫描因本 checkout 缺 TypeScript dev dependency 失败。准备 npm ci --ignore-scripts 后,同一语义命令在不可变 base 与准确 head 都通过。原失败仍保留,不删断言、不改预算。没有获取、轮询或等待远端 CI。测试产生的临时 Git 仓库均在所属测试目录内清理,没有新增长期 worktree。

语义与 CI 对齐

原 v0 packet/字段和 execute 权限继续使用,新增计数是 Git 事实的派生投影,旧 packet 缺计数时仍按原零值兼容。没有新 actor、审批、共享枚举或发布权限。生产 Python 留在专有 Git IO 边界,未新增并行控制面决策 owner。语义扫描通过只覆盖其检查范围,不证明截断集合可以代表全量不存在。

我的整体评价 / Verdict

REQUEST_CHANGES。合法路径保真和上一轮修复均有实证;完整提案仍不能提供可靠的 fail-closed 就绪条件。long_horizon 与 user_experience 的回归来自同一事实可因展示排序改变后续义务,修复应限定于现有 owner 的全量派生与投影顺序,无需新工作流或额外人工授权。

已检查 issue-fix CLI 的 JSON builder、validator 与 Markdown renderer;本差异没有渲染页面、布局或控件变化。 未验证范围:Windows、安装态 Host 与真实模型采用未验证;没有待验的渲染布局。 已验证范围为源代码公开 CLI + 真实本地 Git 与调用方子进程;并发写仓库、完整长程成本未作证明。没有合并、撤回其他评审或更改共享安装。

English verdict: REQUEST_CHANGES — 6a04d50. The literal UTF-8 prefix regression is fixed, and whole-PR positive cases pass. The new unsupported-path gate still examines only the 20-item display slice: the same Git change set becomes ready or not ready solely by changing diff ordering. Derive validity from the complete byte-path set before truncating the display, and cover late/early invalid paths plus recovery.

add_paths(_git_untracked_paths(workspace))
displayed: list[str] = []
unrepresentable_count = 0
for path in files[:20]:

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.

[P2] 请在截取20条展示前完成全量可表示性判断。真实 issue 分支包含25个 a00–a24 普通文件和 Git 字节路径 b"z-\xff.txt" 时,公开 CLI 校验通过后给出 truncated=true、计数0、ready=true;保持相同 HEAD/tree,仅用 diff.orderFile 将 z* 排在前面,就变为计数1、ready=false。收集函数已在20条处提前返回,此处又只扫描 files[:20],因此不能用该计数证明完整变更集不存在不可表示项。请先对完整 raw-byte 集合派生就绪条件,再截取展示,并增加非法路径在上限前/后及移除后恢复的真实 CLI 回归;完整证据见本次 review 正文。

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

已修复并推送新精确 head e3076c9a7456c2703b9722ec7083ce81cfb9a2ae。

  • _changed_files() 不再在第 20 条处停止收集;它先在完整去重 bytes 集合上计算 changed_file_count 与不可表示路径数量,再投影前 20 条显示。
  • changed_files_truncated=true 只表示完整集合超过 20;两个公开不可表示计数来自全量,验证器按 changed_file_count 而不是显示列表长度校验,并要求 artifact / review packet 计数一致。
  • 新增真实公开 CLI 回归:25 个 a00–a24 加 b"z-\xff.txt",默认排序时计数 1 且 ready=false;仅设置 diff.orderFile 把 z* 移到首位后结果仍为计数 1 且 ready=false;移除该字节路径后计数 0、20 条显示保留、ready=true。
  • 路径测试、reviewer-history framing 与临时工作区测试共 18 passed。全量 issue-fix 测试在当前环境受 TypeScript Effect runtime 权限限制,保留为环境失败。

请复审新 head。

Signed-off-by: ChengLong GU <88359731+gcl-coder@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

REQUEST_CHANGES — [P2] 全量计数和健康计算前,先展开未跟踪目录。 当前调用仍用 git status --porcelain -z 的默认目录摘要。真实公开 CLI 中,同一目录放26个未跟踪文件,输出 changed_files=["nested/"]、总数1、truncated=false、ready=true;只把 status.showUntrackedFiles 改成 all,总数就变26且截断为 true,文件和验证命令均未变。在既有字节采集命令明确指定 --untracked-files=all,或使用遵守相同 ignore 语义的 git ls-files --others --exclude-standard -z,再统一计算完整数量和健康,最后截取展示。

动机 / Motivation

使用本地 issue-fix 验收包定位修复文件并决定是否进入评审的维护者和自动调用方。 旧版把中文和控制字符名称写成 Git 引用字符串;当前版本修复了这些名称及展示截断,但同一目录内26个未跟踪文件仍会按 Git 展示设置被报告为1个或26个变更。

平铺路径、非法字节的已提交路径与移除非法路径后的恢复均已验证;完整未跟踪路径范围仍未满足当前计数和健康判定的承诺。 范围限于现有调用方批准的本地仓库验收,不新增发布、合并、安装、账户或执行权限。 目录汇总在基线也存在;这里没有把它说成新引入的 CR/UTF-8 回归。阻断原因是本次新增的全量计数及健康承诺仍直接依赖这个不完整输入。目录内真实文件没有进入原始集合时,零个不可表示项不能证明该目录内不存在不可表示文件。

改动思路 / Approach

Git 字节读取属于现有 provider IO;可表示性是就绪条件,展示上限不得定义它的输入范围。 改动应限制在既有 acceptance_loop 的完整路径采集、派生计数和20项展示;不需要新 workflow、配置 owner 或额外权限。

bytes 捕获、NUL 分帧和原始字节去重有充分必要性,关闭 quotePath 或复用 reviewer recommendation 的路径归一化都会改写合法名称。派生数量继续归属原 builder,不应要求用户维护额外状态。当前不需要增加抽象或拆出新服务;应让 Git 明确提供完整未跟踪文件集合,避免继承面向人工展示的目录摘要设置。

具体改动 / Changes

精确 head 7bbffe6f0921082175442b0982a54ba687b810ac,共同基线 1ff09d3a8c6f55ff92c65b84e6aec6e25402dc81;完整提案3个文件 +585/−30:生产 +167/−30、协议9行、测试409行,全部净差异已检查。新 head 整合主干后,这三个文件及其 CLI/planner/reviewer 相邻调用文件与前一评审提交内容完全一致;已在新的基线与准确 head 重跑同一公开 CLI 夹具,并重跑12项原测试,目录反例仍在。

规范为 loopx/capabilities/issue_fix/docs/protocols/issue-fix-acceptance-loop-v0.md,spec_revision 37aaff7a035d0df18b2166cfe0dc74d5fe04eaf7。repo-relative-paths、validation-and-change-readiness、execute-and-privacy 的原有条件已验证;complete-health-input 还依据变更前已接受的不可表示路径承诺判断,本轮尚未满足。没有用本 head 新写的协议文字自证要求。

关键代码讲解

  • _run_git_paths在任何分帧前捕获 bytes,保留 CR/LF/CRLF;合法 UTF-8 的诊断转换由 _display_git_path 决定,前缀本身不用于判定非法路径。
  • _git_untracked_paths能正确处理 NUL 及重命名双记录,但 status 没有请求完整未跟踪文件。缺口在输入集合,不在后续分帧。
  • _changed_files已先对完整收到的字节集合算数量和健康、再截取20项。上轮 diff.orderFile 截断逃逸已修复;当前反例是 Git 本身先提供了目录摘要。
  • build_issue_fix_caller_repo_branch_packet将验证结果与零不可表示计数组合为 ready;validator 能核对两个派生计数一致,却不能找回未收集的目录内部路径。

对主干的风险 / Risks

PASS:新增12项测试通过。独立同一公开 CLI 夹具在基线为3失败/1通过,在当前 head 为1失败/3通过;合法中文、空白、CR/LF/CRLF、字面前缀均修复。25个合法文件加末尾字节路径在默认/提前排序下始终 ready=false,移除该路径后恢复 ready=true。验证失败保持未就绪;无 execute 且 Git 元数据不可用时仍只返回计划。

FAIL:26个目录内未跟踪文件的完整范围判据仍失败。基线也只记录目录,因此这是触及的新健康保证尚未闭合,而不是已归因的新编码回归。现有绿色用例覆盖平铺未跟踪路径,不能代替目录反例。macOS 拒绝真实非法 UTF-8 文件名,Linux 目录内字节路径的就绪后果只作源码推断,未声称执行验证。完整 premerge 未执行;本轮不请求批准或合并。未获取、轮询或等待远端 CI。

语义与 CI 对齐

仍复用原 v0 包、调用方 execute 权限和现有 owner;新增数量属于 Git 事实的派生投影,没有新 actor、共享生命周期状态或发布授权。关键约束是完整源先于展示投影,两个输出计数相等不能证明源完整。复验应包含默认/all 的相同目录夹具、受支持平台的目录内非法字节,以及移除不支持路径后的恢复。

我的整体评价 / Verdict

机制与实际文件名问题相称,旧发现均有正向修复证据;当前整体交付仍是 not_yet_proven,long_horizon 与 user_experience 的缺口在完整路径证据的可信度。一次已有授权的调用足够,不需要新用户确认轮次。本次差异只改 JSON/CLI 验收包、校验和协议;没有渲染页面、控件或布局变更。 未验证原生 Windows、Linux 未跟踪的非法字节文件名,以及安装态 Host;没有待验的渲染布局。

保留既有 provider 与包 owner,只补齐明确的全量采集和反例即可重新评审;不用为这个局部缺口建立新工作流。没有安装、合并或撤回其他评审。

English verdict: REQUEST_CHANGES. Head 7bbffe6. Encoding and display-order fixes pass, but nested untracked directories still make the new full inventory depend on Git presentation settings. Expand the source before deriving counts and health.

Signed-off-by: ChengLong GU <88359731+gcl-coder@users.noreply.github.com>
@gcl-coder

Copy link
Copy Markdown
Contributor Author

已修复并推送新精确 head 83bee892dacb48c4448dfb17e534f25992b3a2f8。

  • _git_untracked_paths() 现在显式执行 git status --porcelain -z --untracked-files=all,不再接受未跟踪目录的 nested/ 摘要。
  • 完整路径集合仍先统一返回 bytes、去重并计算 changed_file_count 和不可表示计数,之后才截取 20 条显示。
  • 新增真实公开 CLI 回归:nested/ 中 26 个未跟踪文件在 status.showUntrackedFiles=normal 时原始 status 确实只有 nested/,但 packet 得到 26 条完整计数、20 条显示和 truncated=true;改成 status.showUntrackedFiles=no 后结果仍相同。
  • 先前 diff.orderFile 前后排序、移除字节路径恢复 ready、合法 git-bytes: 名称与真实 U+FFFD 的用例继续保留。
  • 路径测试、reviewer-history framing 与临时工作区测试共 19 passed。全量 issue-fix 测试在当前环境仍受 TypeScript Effect runtime 权限限制,保留为环境失败。

请复审新 head。

@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

没有发现当前 head 的阻断问题。五轮旧发现的原始失败保留;本次检查整个提案,并单独重验最后一轮未跟踪目录问题。

动机 / Motivation

使用 issue-fix 本地分支验收包定位实际修复文件并判断评审就绪的维护者与自动调用方。 同一目录含26个未跟踪文件时,旧头随 Git 展示配置只报告1个目录或0项;当前头始终报告26个文件、显示20项,保留忽略规则。

独立公开 CLI 观察验证了完整采集、字节健康先于展示截断,以及移除不支持路径后恢复就绪。 范围限于已获调用方授权的本地仓库验收;不新增外发、PR创建、合并、安装或全局执行权限。 这使一次已有授权的调用能提供可用文件证据,不要求维护者反复改变 Git 显示设置来发现遗漏。没有用绿色测试数量替代这一实际结果。

改动思路 / Approach

Git bytes 读取归既有 provider IO,路径健康和完整计数从 Git 事实派生,20项上限只属于展示;没有第二个状态或策略 owner。 保留 acceptance_loop 既有 builder、validator 和调用方 execute 边界,只修正路径采集与其公开投影。 做不到这一点时,后端收到的集合本身就不完整,后续两个计数相等也不能证明安全。改为直接关闭 quotePath 仍会受到控制字符和解码影响;复用 reviewer_recommendation 的路径归一化则会改写合法空白、反斜杠并混入另一种历史范围,不能替代当前四来源集合。

当前修改沿用原 builder、validator 和 CLI 分发,不增加服务、声明同步或第二份策略。派生数量每次重新计算,合法 git-bytes 前缀不用于判断不支持路径,避免再次误伤普通文件名。

具体改动 / Changes

精确 head 83bee89;完整基线 1ff09d3。全提案3文件 +643/−30,其中生产 +170/−30、测试462行、协议11行;最后一次7bbffe6f0921082175442b0982a54ba687b810ac至本头 +62/−4,明确增加未跟踪展开并补足真实 CLI 回归,没有只检查这几行增量。

规范为 loopx/capabilities/issue_fix/docs/protocols/issue-fix-acceptance-loop-v0.md,spec_revision 1ff09d3。repo-relative-paths:原始 UTF-8 名称和四种 Git 来源保持可定位;validation-and-change-readiness:通过验证、有变更、完整字节健康共同决定 ready;execute-and-privacy:无 execute 不访问仓库,外部发布仍独立。完整健康计算也遵守此前已接受的修复边界,没有用本头新改的规范文字自证原有要求。

关键代码讲解

  • _run_git_paths在 NUL 分帧前捕获 bytes,防止 CR、LF、CRLF 在文本模式中合并。
  • _git_untracked_paths显式请求 --untracked-files=all,只收取未跟踪文件,并越过 rename/copy 的第二条记录,保留 Git ignore 规则。
  • _changed_files按原始字节去重,对完整集合算健康和总量,最后投影20项;20项整时不再错误标为截断。
  • build_issue_fix_caller_repo_branch_packet保持原分支/验证权限,仅在完整集合没有不可表示路径时报告评审就绪;validator 同时检查派生数量关系。

对主干的风险 / Risks

PASS:19项仓库聚焦测试、两个变更 Python 文件的 Ruff、标准 premerge 的6项直接检查和15项选择检查均通过,无失败、跳过或 manual hold。六个独立公开 CLI 场景在原始基线保留5失败/1通过,上一评审头保留1失败/5通过,当前头6通过;原始失败没有改写。对同一26文件集合分别使用 normal、no、all,结果恒为26/20且截断;ignored sibling 不进入集合,后来加入第27个文件能在重跑时发现。四种来源的12个 CR/LF/CRLF 名称均独立保留。

PASS:超过20项的非法字节路径,不论被 diff.orderFile 放在前面还是后面都保持未就绪;移除后恢复。合法前缀、真实 U+FFFD、中文、空白和反斜杠保持字面值;失败验证仍不就绪。无 execute 且 Git 元数据移走时仍可返回计划。API/JSON、现有 Markdown 消费路径和公开效果标志均核对,没有自动外发。

语义与 CI 对齐

仍使用既有 v0 包与 capability owner;新增的是 Git 事实派生投影,未引入通用控制面策略或 actor 生命周期。行为默认变化及20项显示上限已在协议与 PR 说明披露。当前语义检查通过;远端 CI 按当前策略未获取、轮询或等待,不宣称其成功。

我的整体评价 / Verdict

本地持续修复流程的 long_horizon 与 user_experience 得到有界改善:同一 Git 状态不再因展示方式产生不同的健康结论,失败后的合法重跑路径也已验证。没有宣称真实长期 Agent 采用、全机成本或平台资格已经成立。兼容边界保留一个当前 builder 和既有调用方,代码规模与复现问题相称,当前不需要新的通用抽象或平行版本。

本次改变现有 JSON/CLI 验收包及其计数,不修改渲染页面、控件或布局;Markdown 消费者只显示计数和就绪状态。 未运行原生 Windows、Linux 物理未跟踪非法字节文件名及安装态 Host;没有待验的渲染布局。 APFS 不支持的原始字节名通过真实 Git 索引/树验证;未跟踪字节解析单元输入是受控数据,不能冒充 Linux 物理文件系统资格。自有测试仓库已由有界回收器收尾;没有创建新的源码 worktree、合并或撤回历史评审。

English verdict: APPROVE — 83bee89. Complete real-Git CLI comparisons close the untracked-directory and prior filename/health defects. Focused tests, lint and native premerge pass; platform and installed-host limits remain explicit. No merge authority is granted.

@huangruiteng
huangruiteng merged commit b5bf50e into loopx-project:main Nov 10, 2026
5 of 7 checks passed
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.

3 participants