Repository navigation
fix(issue-fix): preserve exact changed Git paths and history - #8558
huangruiteng merged 1 commit into
Conversation
c17bb86 to
0d89fc9
Compare
loopx-agent
left a comment
There was a problem hiding this comment.
Reviewer: model_agent · gpt-6.1-sol · OpenAI · runtime_reported · max
评审提交 0d89fc9
[P2] 历史查询需要按字面路径匹配。 两个真实 Git 仓库只修改一个文件,分别是含换行和星号的文件、含换行且以 :(exclude) 开头的文件。候选保留原名,git log 仍按 pathspec 解释,读到另一个文件的三次提交,并将无关作者排第一,标作变更路径贡献者。 在现有历史查询中对文件名和模块目录启用 Git 的 --literal-pathspecs,并用完整 reviewer-plan 断言不能把别的路径计作精确历史。
动机 / Motivation
使用 reviewer-plan 为已有改动选择熟悉该文件的审阅者的开发者或 Agent。 文件名包含中文或换行时,旧的逐行读取可能把它变成另一个名字。候选保留了原名,但名字里的通配符或路径规则仍能让历史查询读到别的文件。 普通的特殊字符文件已能找到原作者。带换行的通配符和排除规则文件仍会把无关作者排在第一。 本轮覆盖本地差异、作者历史和候选排序。对外请求审阅沿现有独立授权。
改动思路 / Approach
Git 用 NUL 分隔返回准确路径。下游查询仍走现有 Git 历史,但需要按字面匹配才能把贡献记录绑定到该文件。 本轮覆盖本地差异、作者历史和候选排序。对外请求审阅沿现有独立授权。 现有查询同时为精确文件和模块兜底取历史。在这一个调用启用字面路径,可以保留两个分支和现有评分。NUL 分帧解决 Git 输出边界,字面匹配解决 Git 输入边界。
具体改动 / Changes
- NUL 记录解码 保留中文、换行、空格及反斜杠。实际 CLI 对中文加 CRLF 的路径返回正确作者,主干没有候选。
- 历史查询 在参数分隔符之后仍按 pathspec 解释文件名。我在两个真实 Git 仓库执行同一条 reviewer-plan 命令。Git NUL 清单证明只改了一个文件,但候选把另一个文件的三次提交计入精确历史。仅切到 Git 的字面路径模式,两例都只返回正确作者。
- 依据 主干协议 的 beff0f3。Exact changed pathname 通过。Exact-path author evidence 未达到,扩大查询只应发生在明确的模块兜底。Independent request authority 已确认,本地计划没有对外请求。生产 +50/−8,测试 +41。
对主干的风险 / Risks
同一 Python 范围主干 21 项通过,候选 27 项通过。候选 quick premerge 的 6 项直接和 3 项选定检查通过。新增测试止于路径提取,独立 CLI 负例覆盖实际排序和证据字段,复现两项未被现有断言发现的错误。显式路径预览在不存在的仓库也保持原结果和无读取行为。
我的整体评价 / Verdict
保留 NUL 分帧,修复历史查询边界,再用真实 reviewer-plan 覆盖两种特殊路径。回归需要断言无关提交无法进入该文件的精确贡献记录。变更只影响本地 CLI 和 Git 查询,视觉检查不适用。
English verdict: REQUEST_CHANGES. Derived paths are framed correctly, but Git pathspec interpretation can rank unrelated authors as exact-path contributors.
| if not name or path.is_absolute() or ".." in path.parts: | ||
| raise ValueError("changed files must be non-empty repo-relative paths") | ||
| if name not in files: | ||
| files.append(name) |
There was a problem hiding this comment.
[P2] 历史查询需要按字面路径匹配。 两个真实 Git 仓库只修改一个文件,分别是含换行和星号的文件、含换行且以 :(exclude) 开头的文件。候选保留原名,git log 仍按 pathspec 解释,读到另一个文件的三次提交,并将无关作者排第一,标作变更路径贡献者。 在现有历史查询中对文件名和模块目录启用 Git 的 --literal-pathspecs,并用完整 reviewer-plan 断言不能把别的路径计作精确历史。
0d89fc9 to
5932714
Compare
|
已在
验证:
|
loopx-agent
left a comment
There was a problem hiding this comment.
Reviewer: model_agent · gpt-6.1-sol · OpenAI · runtime_reported · max
评审提交 5932714
[P2] 结果校验拒绝合法的 Git 字面文件名。 真实 Git 仅修改根目录中名为 \notes.txt 的文件。候选读到了准确原名和唯一正确作者,但包校验把字面反斜杠换成斜杠,将名字误判为绝对路径。公开 CLI 返回退出码 1 和 changed_files must contain only repo-relative paths。单空格和包含字面反斜杠包围两个点的文件名也被拒绝。 对已解码的 Git 输出按原始 POSIX 路径验证,保留显式 --changed-file 的旧入口规范化。用真实 CLI 断言 \notes.txt 返回有效包和唯一正确作者;保留显式预览兼容对照。
动机 / Motivation
用 issue-fix 按实际改动选择审阅者的开发者或 Agent。 文件名含中文、换行或字面反斜杠时,旧的按行 Git 输出会让历史查询使用另一个名字。 候选已修复通配符和路径规则扩大查询的问题;部分合法 POSIX 文件名仍在返回前被拒绝。 本轮覆盖本地差异、作者历史、推荐结果。对外请求审阅仍需单独授权。
改动思路 / Approach
Git 用 NUL 分帧输出,解码后的文件名原样传到既有评分路径。历史查询使用字面路径,模块兜底继续只在精确历史不可用时触发。末尾包校验仍沿用显式输入的规范化。 现有实现边界成立;在同一 owner 修复。没有新增状态、schema、权限或迁移。 上轮 0d89fc9 到本提交生产增加 8 行、测试增加 60 行。换行通配符和排除规则的两个旧反例、字面模块目录兜底均只返回正确作者;输出校验是本轮独立发现。
具体改动 / Changes
关键代码讲解
- _derive_changed_files:对 Git 输出做 NUL 分帧后解码,原样保留 UTF-8 文件名。
- _collect_history:将精确文件和模块目录作为 Git 字面路径查询,沿用现有评分。
- validate_issue_fix_reviewer_recommendation_packet:仍以显式输入规则解释 Git 输出;字面反斜杠会变成斜杠。
上轮 0d89fc9 到本提交生产增加 8 行、测试增加 60 行。换行通配符和排除规则的两个旧反例、字面模块目录兜底均只返回正确作者;输出校验是本轮独立发现。 普通路径、中文加 CRLF、两种旧反例和字面模块目录都通过;显式预览保留 docs/one.py,且无需仓库存在。
依据主干约定(beff0f3e55d1f70eceebbd8e78c11f1cff34643b):Exact Git pathname:保留实际文件名(通过);Literal file and module history:精确路径优先,明确的模块历史兜底保留(通过);Valid output for legal Git paths:合法路径能输出有效推荐包(未达到);Local-only planning:不产生对外审阅请求(通过)。
对主干的风险 / Risks
PASS:主干 21 项、候选 29 项通过;Ruff、Git diff --check、quick premerge 的 6 项直接和 3 项选定检查通过。 FAIL:真实 Git 仅修改根目录中名为 \notes.txt 的文件。候选读到了准确原名和唯一正确作者,但包校验把字面反斜杠换成斜杠,将名字误判为绝对路径。公开 CLI 返回退出码 1 和 changed_files must contain only repo-relative paths。单空格和包含字面反斜杠包围两个点的文件名也被拒绝。 显式预览不打开不存在的仓库,输入兼容、权限和无请求边界保留。 未执行真实对外请求;未独立验证 Windows 文件系统。 远端 CI 按评审配置未询,合并资格仍须单独确认。
语义与 CI 对齐
已解码 Git 字面路径与精确历史沿用既有约定,没有新增语义词汇。修复后重跑同一真实入口反例及定向测试,并保留对应的正向和降级对照。
我的整体评价 / Verdict
该改变值得在现有能力中交付;独立反例仍阻断完整结果,修复后应重跑同一对照。 对已解码的 Git 输出按原始 POSIX 路径验证,保留显式 --changed-file 的旧入口规范化。用真实 CLI 断言 \notes.txt 返回有效包和唯一正确作者;保留显式预览兼容对照。 本轮覆盖本地差异、作者历史、推荐结果。对外请求审阅仍需单独授权。
English verdict: REQUEST_CHANGES. Literal history now fixes the previous wildcard and magic cases, but the CLI rejects legal Git filenames during final validation.
| if not name or path.is_absolute() or ".." in path.parts: | ||
| raise ValueError("changed files must be non-empty repo-relative paths") | ||
| if name not in files: | ||
| files.append(name) |
There was a problem hiding this comment.
[P2] 结果校验拒绝合法的 Git 字面文件名。 真实 Git 仅修改根目录中名为 \notes.txt 的文件。候选读到了准确原名和唯一正确作者,但包校验把字面反斜杠换成斜杠,将名字误判为绝对路径。公开 CLI 返回退出码 1 和 changed_files must contain only repo-relative paths。单空格和包含字面反斜杠包围两个点的文件名也被拒绝。 对已解码的 Git 输出按原始 POSIX 路径验证,保留显式 --changed-file 的旧入口规范化。用真实 CLI 断言 \notes.txt 返回有效包和唯一正确作者;保留显式预览兼容对照。
Git's default core.quotePath C-quotes non-ASCII and control-character pathnames in a line-oriented listing. _normalise_changed_file turned those quote escapes into slashes, so reviewer coverage matched paths such as /344/270/255 that do not exist. Capture -z output as bytes and decode each record strictly so CR, CRLF, spaces and POSIX literal backslashes survive. The derived names were still interpreted as pathspecs by git log. A name containing a wildcard or pathspec magic could collect commits from other files and rank their authors as exact changed-path contributors. Use --literal-pathspecs for both exact-file and module-directory history. Packet validation also reused caller-input normalization, turning a decoded POSIX literal backslash into a separator and rejecting valid names such as \notes.txt as absolute. Validate derived Git names as emitted while keeping the explicit --changed-file normalization boundary unchanged. Signed-off-by: ChengLong GU <88359731+gcl-coder@users.noreply.github.com>
5932714 to
b72e3a9
Compare
|
已在 包校验不再复用显式输入的分隔符规范化:已解密的 Git 路径按原始 POSIX 语义验证, 验证:
|
songoow
left a comment
There was a problem hiding this comment.
Reviewer: model_agent · GPT-6 Astra Pro · OpenAI · self_reported
评审提交:b72e3a96702d8433a7f781a55f314153c37f5593;基线:beff0f3e55d1f70eceebbd8e78c11f1cff34643b。本轮重新检查完整两个文件的 diff,并复核前两次 review 的全部意见。
动机 / Motivation
使用 issue-fix 为已有改动选择审阅者的开发者和 Agent,会把实际变更路径交给本地 Git 历史查询。文件名含中文、换行或字面反斜杠时,旧实现可能把一个真实文件解释成另一个名字,导致候选缺失;路径含通配符时,还可能把无关文件的作者算作该文件的贡献者。
本 PR 的可观察目标是:从 Git 推导的文件名原样进入完整推荐结果,精确历史只支持对应文件;显式路径输入和默认预览继续兼容。本轮实际 CLI 对照验证了这一目标。范围是现有本地推荐能力的路径读取、历史查询及结果校验,不包括对外发起审阅请求或改变 GitHub 权限。
改动思路 / Approach
实现沿用既有 owner:公开 reviewer-plan 进入 build_issue_fix_reviewer_recommendation_packet,在 --execute 后读取调用者选定的本地仓库,再按 CODEOWNERS、维护者映射、精确历史和模块兜底的现有顺序评分。供后续 reviewer-request 消费的推荐结构与权限边界不变。
这次修复需要同时处理三个边界:Git 输出用 NUL 分帧,避免引号、换行及文本模式的 CR 转换;Git 输入启用字面 pathspec,避免通配符扩大历史查询;最终 packet 按 POSIX 原始路径验证,避免再次把反斜杠改成分隔符。三者是同一完整用户结果所需的修复,单独更换分隔符会保留已发现的错误。
保留显式输入规范化、单独验证 Git 原始路径有明确调用语义依据。现有 acceptance-loop 的字节路径显示辅助服务于诊断包,并不适合直接复用为可查询的 reviewer 路径;在当前 provider owner 内增加小型 bytes helper,比引入通用路径协议或迁移状态更合适。当前 PR 边界是修复现有推荐入口,不新增配置、状态、schema 或命令。
具体改动 / Changes
关键代码讲解
_run_git_bytes与_derive_changed_files:使用git diff --name-only -z --no-ext-diff,先按 NUL 分割 bytes,再逐条严格 UTF-8 解码。去重和最多 100 个文件的限制保留;中文、CRLF、首尾空格、字面反斜杠不再被改写。_collect_history:在git log前加--literal-pathspecs,精确文件查询和模块目录兜底共享这一边界。候选排序、历史基线和身份解析仍由原 builder 管理,feature branch 的新作者不会因此进入历史证据。_validate_derived_changed_file与 最终 packet 校验:允许合法 POSIX 字面路径,同时拒绝空路径、绝对路径和真正的父目录段。显式--changed-file docs\one.py仍经旧规范化得到docs/one.py,不与 Git 原始文件名混用。- 新增测试从路径解码延伸到完整 packet 和公开 CLI;我另外用同一组真实 Git 仓库比较 base/head,避免只依靠新增 helper 的断言。
采用已有推荐协议,固定修订为 beff0f3e55d1f70eceebbd8e78c11f1cff34643b,逐项结论如下:
| 契约项 | 当前 head 的证据与结论 |
|---|---|
exact_git_path:Input Contract 的非空、仓库相对路径 |
已实现。中文加 CRLF、根反斜杠、单空格与字面 .. 的名字均原样返回。 |
literal_history:Evidence Order 的精确路径优先、模块历史兜底 |
已实现。换行通配符、:(exclude) 与字面模块目录用例只返回预期作者,精确/模块 reason 区分保留。 |
preview_compatibility:默认预览不读取仓库 |
已实现。不存在仓库上的显式反斜杠输入得到与 base 完全相同的有效预览。 |
local_only_planning:Required Boundaries 不发送外部请求 |
已实现。实际 CLI 观察到外部读写及 review request 均为 false,仓库状态保持不变;外部请求仍属于单独授权入口。 |
旧意见一的 pathspec 污染和旧意见二的末尾校验拒绝,均已在本 head 的真实入口复核通过。线程是否已解决是 GitHub 工作流状态,不代替这次代码及行为证据。
对主干的风险 / Risks
PASS:相同两组能力测试在 base 为 21 passed、head 为 34 passed;推荐能力原有 smoke 通过。独立公开 CLI 对照共 12 组:8 个实际路径/历史场景,以及预览无读取、非法显式输入优先于缺失仓库、空 diff 和非 UTF-8 失败路径。普通 ASCII、显式预览及已有拒绝分支的完整输出与 base 一致,仓库状态均未被修改。非 UTF-8 文件名现在明确返回错误;它不会被替换字符或转义文字伪装成另一个可查询路径。
quick premerge 的 6 个直接检查,以及 maintainability、issue-fix-workflow 两项选定检查通过;语义扫描首次因专属检出缺少 npm 依赖失败,复用已安装依赖后,仅重跑该失败检查并通过,保留首轮环境失败记录。远端 CI 观察仍含 queued、cancelled 与 skipped,原因未逐项归因,不宣称远端全绿。这里的代码结论与后续合并资格分别判断。
主要剩余限制是本轮实际运行在 Linux/Python 3.12,未独立验证 Windows 文件系统;CODEOWNERS 仍保持协议声明的 common_subset,非 UTF-8 Git 路径仍不受该 JSON 推荐入口支持。生产改动 +74/−9,测试 +184,均围绕同一读取和校验边界,没有第二套评分规则或长期迁移成本。
语义与 CI 对齐
本次修复恢复现有 issue_fix_reviewer_recommendation_v0 的路径及证据含义,未扩展公共 vocabulary。错误消息说明严格 UTF-8 边界;已有 --execute 与独立外部写授权语义保持。定向真实入口证据覆盖本 PR 的实际变化,远端任务未完成不应被改写成 PASS。
我的整体评价 / Verdict
当前 head 达成所声明的完整修复,建议 APPROVE。用户体验得到改善:同一条推荐命令可以处理这些合法文件名,不再需要重命名或手动替换路径。长程工作边界保持:结果仍是无持久化副作用的建议,实际后续 review request 保持独立授权;本轮没有据此声称长期效率收益。
从原问题重新审视范围,三处 Git/packet 边界修复及相应回归是适度且必要的;保留显式输入兼容也有真实调用依据,无需再增加公共协议层。本改动仅涉及 CLI/Git 处理,不改变渲染界面,视觉检查不适用,未验证范围为 Windows 文件系统及非 UTF-8 路径的未来支持。
English verdict: APPROVE at b72e3a9. Both previous findings are fixed; real CLI base/head comparisons and focused tests validate literal Git paths, exact history, and preview compatibility. Remote CI and merge readiness remain separate.
Problem
issue-fix reviewer-planderives changed files from--base-ref...HEADwhen--changed-fileis omitted._derive_changed_filesreadgit diff --name-onlyin text mode. With Git's defaultcore.quotePath=true, non-ASCII and control-character names arrived C-quoted, and_normalise_changed_fileturned the escape text into unrelated paths such as/344/270/255/....Once a derived name was preserved,
git log -- <path>still interpreted it as a pathspec. A name containing a wildcard or starting with pathspec magic such as:(exclude)could include commits from other files in the exact changed-path history and rank unrelated authors as contributors.Packet validation also reused caller-input normalization. That replaced POSIX literal backslashes with slashes, so a valid derived root path such as
\notes.txtfailed as an absolute path after the recommendation had been computed correctly.Change
_derive_changed_filescapturesgit diff --name-only -z --no-ext-diffas bytes, frames records on NUL, and decodes each record strictly as UTF-8. It preserves CR, CRLF, surrounding spaces and POSIX literal backslashes while validating repo-relative paths._validate_derived_changed_filevalidates decoded Git paths as emitted, without treating a literal backslash as a separator.--changed-fileinput keeps the established separator normalization and remains the preview compatibility boundary._collect_historyuses--literal-pathspecsfor both the exact changed-file query and the module-directory fallback.Validation
python3 -m pytest tests/capabilities/test_issue_fix_candidate_evidence.py tests/capabilities/test_issue_fix_reviewer_history_framing.py -q: 34 passed.reviewer-plan --execute --format jsonCLI accepts a repository whose only derived filename is\notes.txt; it returnsok=true, preserves the exact path, and ranks only the expected author with one exact-history commit..., wildcard and:(exclude)names also preserve the exact path and exclude unrelated authors.--changed-file docs\one.pystill normalizes todocs/one.pywithout reading the absent repository.git diff --checkand bytecode compilation pass.