Repository navigation
fix(issue-fix): verify GitHub repository redirects in PR wait observation - #7988
Conversation
…tion A renamed GitHub repository keeps its pull request numbers, but the provider URL now names the canonical owner. Comparing the recorded dependency URL byte-for-byte therefore rejects a valid merged dependency and leaves the Todo blocked on a PR that already landed. Verify the redirect with `gh repo view <repo> --json nameWithOwner` and accept the dependency only when the canonical name matches the provider URL repository. Malformed responses, unrelated same-number PRs and failed verification still fail closed; the verified canonical repo is carried on the transient payload for the wait reconciler and is not persisted. Signed-off-by: lusendong.6789 <lusendong.6789@bytedance.com> Co-authored-by: TRAE CLI <traecli@bytedance.com>
583c5db to
96f55db
Compare
loopx-agent
left a comment
There was a problem hiding this comment.
Reviewer: model_agent; gpt-6.1-sol; OpenAI; runtime_reported; reasoning_effort=max
动机 / Motivation
使用 issue-fix 自动等待 GitHub PR 合并的用户,在仓库更名后仍可能持有原仓库地址。 原来 GitHub 已返回同一个 PR 的规范新地址,等待器仍按旧地址逐字比较而拒绝,导致合并后的工作无法继续;现在先核验仓库重定向,再允许相同 PR 编号的已验证别名。 已验证的结果是 File 和 SQLite 上,真实等待、合并事实记录和后续任务可以从更名后的依赖继续,重放不会重复执行或结算。 本 PR 只修复 PR 身份观察,不新增合并权限,不自动关闭用户目标,不把任意同编号 PR 当成同一个依赖。 生命周期目录 smoke 和六个既有等待测试仍失败,严格质量回执不通过;真实应用 Host 与跨平台行为没有完成资格验证。
改动思路 / Approach
先比较 PR 类型和编号;仓库相同时维持原路径,仓库不同时才调用 gh repo view 取请求仓库的规范名称,要求它与 provider 返回的仓库一致。核验结果只在当前 provider 数据中传递,不写一个需要人工同步的别名表。身份不变量由 issue-fix 的既有 GitHub provider 校验,规范仓库名由 provider IO 获取,合并事实与后续执行仍交给原有 owner;没有为别名再建一份持久状态。 当前交付边界是更名依赖的身份核验与既有等待恢复,不扩展合并、调度或结算权限。
| 输入情况 | 当前结果 |
|---|---|
| 同仓库、同编号且 MERGED | 沿原路径记录合并事实 |
| 已核验重命名、同编号且 MERGED | 接受别名,进入原继续执行路径 |
| 无关仓库、错误编号、缺失 URL、查询失败 | 拒绝身份,不生成合并事实 |
| 身份正确但 OPEN/CLOSED | 保持未合并语义 |
表格是精确 head 的源码分支说明;执行证据另列在风险部分。
具体改动 / Changes
规范依据:docs/reference/todo-continuation-readback.md,固定版本 6020ddf57e4975dd08a9b02101fd51b2ecda48e8;并核对同版本 loopx/capabilities/issue_fix/README.md 的身份及等待约定。规范原文没有编号,下列是定位名称而非新增政策:same-pr repository-alias identity 已实现同编号与规范仓库双重核验;existing pr_merge observation and continuation 已实现沿原事实写入与继续执行 owner 运行,未把观察变成执行授权。
关键代码讲解
fetch_github_pr_lifecycle_payload:860只有仓库不一致时增加规范名称查询;类型、编号或证明不匹配都失败,不凭编号猜身份。validate_github_pr_provider_identity:956把请求引用和 provider 身份重新绑定;缺 URL 仍由既有解析器归为非 PR 并拒绝。_reconcile_locked:51用统一身份校验替换 URL 字节比较,原有MERGED、合并时间、失败观察节奏和pr_merge写入条件继续生效。
4 个文件、+129/-4,把新增成本限制在 provider IO、一个身份判断和对应测试。普通路径不多查仓库,重命名路径多一次只读查询;没有新 CLI、持久配置、通用核心状态或第二个继续执行实现。
对主干的风险 / Risks
最大反例是误认无关仓库的同编号 PR,让尚未满足的依赖继续。PASS:File/SQLite 的20个生产 fetch→native 用例覆盖正确别名、无关仓库、错误编号、缺 URL、查询失败、坏 JSON、超时、OPEN/CLOSED;只有正确身份的合并响应产生事实,后创建的无关同编号依赖仍不就绪。真实 GitHub 对旧仓库 #7102 的只读响应已确认规范地址及编号;未获取或等待 CI。
PASS:相同原生继续执行 fixture 在 head 的两个后端都达到一次协议 Host、一次合并事实、一次结算和独立产物验收,重放没有额外 GH/Host/副作用;base 因旧 URL 比较被阻塞且零副作用。协议 Host 是合成实现,只有 GitHub JSON IO 被替换,不声称验证真实 App 或付费模型。Ruff、语义检查和 premerge 的6项直接检查通过。FAIL:扩展测试 head68通过/6失败、base65通过/6失败,六项均在改动前的观察 fixture 返回 None 后报同样 TypeError;原生 catalog 的生命周期 smoke 在 base/head 同样于571行报 KeyError: 'evidence'。最终9项选中检查8通过、1失败,既有维护性预算建议也保留。严格 CQR 失败,quality_invalid_receipt 合并限制没有取消。
我的整体评价 / Verdict
没有发现当前 PR 引入的阻塞问题,APPROVE。长期工作路径判定 improved,仅限已验证的依赖恢复与一次结算/重放;用户体验判定 improved,已有原地址无需人工改写或新增确认即可继续,失败仍走原恢复路径。身份不变量由 issue-fix 的既有 GitHub provider 校验,规范仓库名由 provider IO 获取,合并事实与后续执行仍交给原有 owner;没有为别名再建一份持久状态。 当前交付边界是更名依赖的身份核验与既有等待恢复,不扩展合并、调度或结算权限。 接受输入的变化明确且符合已有别名约定,不改变默认开关、权限或 quota。复用既有身份词汇,内部证明字段只是当前 provider 数据的派生投影。检查过的 issue-fix provider 与等待入口没有渲染内容改动,视觉评审不适用;真实应用 Host、Windows 和整套既有测试失败仍未解决。评审结论与 CQR、集成验证、合并授权分别保留,不能据此宣称可直接合并。
English verdict: APPROVE at 96f55db339ec335f915ccf71f611cfb90cba8717. Verified repository redirects restore the existing continuation path without accepting foreign PRs; strict quality and lifecycle-smoke holds remain.
Summary
Fixes a false
waiting_externalblock after a GitHub repository rename.A recorded PR dependency keeps its number when the repository moves to a new owner, but the provider URL then names the canonical owner. The wait reconciler compared the recorded URL byte-for-byte, so a valid merged dependency was rejected as
PR dependency provider identity mismatchand the Todo stayed blocked.fetch_github_pr_lifecycle_payloadnow verifies the provider response against the requested repo/number and, when the owner differs, asks GitHub for the canonical name withgh repo view <repo> --json nameWithOwner.validate_github_pr_provider_identityaccepts the dependency only when the canonical name matches the provider URL repository. Malformed responses, unrelated same-number PRs and failed verification still fail closed._loopx_verified_requested_repositorypayload field for the reconciler; it is not persisted into the lifecycle packet or rollout evidence.Validation
pytest tests/capabilities/test_issue_fix_pr_lifecycle_review_response.py tests/capabilities/test_pr_wait_observation.py— 57 passed.origin/mainac74f90c4(test_pr_wait_lifecycle.pycached-readiness and host-inheritance cases, and two SQLite grouped-monitor materialization cases).python examples/issue-fix-pr-review-reconcile-smoke.py— ok.loopx canary premerge --from-git-diff --git-diff-base origin/main— direct checks and changed-file compile passed. Two catalog canaries fail identically on pristineorigin/main6020ddf57and are inherited, not caused by this diff:issue-fix-pr-lifecycle-smoke.py(KeyError: 'evidence'when reading the active-state projection) andsemantic-vocabulary-drift-smoke.py(pre-existing budget slack).Boundary
Touches the issue-fix PR wait observation behavior. No merge authority is claimed; maintainer review and merge are required.
CI status (run 41632739505 / 41632739409)
kernel-static-checksfails on F811 intests/test_lark_private_conversations.py; the duplicate fixture request was introduced by fix(chat): retain native completion before response parsing #7986 onmainand is unrelated to this diff. Fixed in fix(tests): mark injected Lark fixtures for lint #7991. This PR will be rebased onto the fixedmainbefore merge.Release Artifacts / buildfails inexamples/personal-workspace-browser/research-display-language.mjswith a 30swaitForFunctiontimeout. This diff only touches issue-fix PR-wait code; the same scenario passed on earlier Release Artifacts runs, so it will be rerun after the rebase.checks,pytest, andmerge-gatefailures are downstream ofkernel-static-checks.