Repository navigation
Conversation
Signed-off-by: ChengLong GU <88359731+gcl-coder@users.noreply.github.com>
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
APPROVE:未发现阻断问题;真实 Git 的 fsmonitor 阻塞会得到明确错误,未写入 pending-change ledger,解除阻塞后可继续记录。
动机 / Motivation
启用了仓库变更时间窗的开发者在提交或记录未合入工作时,需要及时得到允许、拒绝或读取失败的明确结果。旧实现会在 Git helper 卡住时无限等待;本次为每次 Git 操作设置等待上限,出错即拒绝继续,而不是把未读到的状态当成 clean。可验证的改进是调用能返回、失败不写错误指纹、解除阻塞后可重试;时间 policy、安装启用和远端写权限不在修改范围。
改动思路 / Approach
入口仍是 repository.git:正常调用保留 bytes、stdin 和非零返回处理,只有无法按时取得答案时才走已有 RepositoryChangeWindowError。新子进程在 POSIX 上拥有独立 session;取消或超时调用既有 process_runtime.retire_owned_process,统一承担进程组、Windows taskkill 和管道回收。后者有独立的有界清理预算,因此 10 秒是每次 Git communicate 的等待预算,不能解释为整个 CLI 的总 deadline。
现有 change_quality.scope 已采用同一清理 owner;复用进程生命周期而保留两个能力自己的 bytes/text、异常与输入接口,比增加跨能力 Git 框架更小。Python 代码仍属于既有 Git provider IO,没有新增 Core 决策 owner。当前切片只改变本能力的 Git 等待与取消;不改变时间 policy、安装激活、ledger 状态和提交权限。这个边界可独立回滚,也不要求用户补一次确认。
具体改动 / Changes
全 PR 为 2 文件,+236/-6;生产文件 +59/-6,新增测试 177 行。规范依据 loopx/capabilities/repository_change_window/README.md,不可变版本 4e949f405528fd8087f0623526c62f890c1ce982;使用变更前已存在且本 PR 未改的正文:install-and-inspect 的默认关闭、preview-first、安装不得授予远程写权限保持;pending-change-ledger 的完整指纹、重试幂等和失败不得伪造 clean 状态保持;authority-and-enforcement-boundary 的本地权限边界保持。
关键代码讲解
gitL53 接收 repo、Git 参数、check 和可选二进制 stdin。communicate 正常完成后重建 CompletedProcess;check=False 的真实错误退出码仍传给调用者,check=True 的原有 stderr/stdout 细节仍保留。没有把非零结果改成空成功。_retire_owned_readL34 只清理本次拥有的进程树;清理未确认不能替换原本的 timeout 或 KeyboardInterrupt。共享 runtime 的同版本实现已核对,未为本能力复制 Windows/POSIX 清理规则。repository_change_fingerprintL339 仍由 staged、unstaged、untracked 的真实 Git 读取生成指纹;异常发生在 ledger 写入前。独立公开 CLI 夹具验证 preview、execute、重复记录、verify、resolve、终态 list、未安装 reconcile 拒绝和恢复,base/head 的完整规范化 JSON 与退出码一致。
对主干的风险 / Risks
PASS:101 tests,1 skipped;包括真实 provider/hook、ledger、负例、stdin、退出码和共享 process runtime。独立 fsmonitor 夹具使用真实 Git,并仅将测试内等待常量设为 0.5 秒:旧版 3 秒仍不返回,由外层测试停止;本 head 约 1.85 秒返回 git diff --cached --name-only -z --no-ext-diff did not answer within 0.5 seconds,helper 心跳停止、ledger 文件摘要未变。关闭故障后两版均成功,完整恢复结果相同。首次夹具用了过短 change_id,在 Git 读取之前被拒绝,已保留该无效观察并改正,未将它算作超时证据。
本地 standard premerge 的 6 项直接检查和 2 项 catalog 检查通过。另行执行的 maintainability ratchet 仍 FAIL:Lark private_conversations.py 的 module_metric_budget;同一命令在不可变 base 与 head 的完整 450 字节输出相同,相关规则、配置及模块未改,原阈值保留。它是独立告警,不能掩盖本次反例。未查询或等待远端 CI。
默认关闭的 provider 不会因 Git 入口可用而安装或执行 hook;未安装/外部 guard 的路径和手动 ledger 路径已对照,现有真实安装/卸载与 linked-worktree 测试通过。测试仅在隔离仓库写状态。原生 Windows 未运行;POSIX 上注入的 Windows taskkill 超时/非零测试通过,但不据此认证原生 Windows 清理。极慢的合法 Git 读取也会被拒绝,这是公开 PR 已明确的默认行为变化;清理时间不计入那 10 秒等待值。
我的整体评价 / Verdict
long_horizon:improved,原本无限等待变成可观察失败与可恢复重试;未测真实模型采用或长期净成本。user_experience:improved,正常 CLI 合同保持且故障可返回,无新增操作轮次。此处没有 rendered presentation 改动,已检查 CLI/provider/ledger 路径,visual_review 为 not_applicable,未验证范围为原生 Windows 和生产安装采用。新增常量与两个本地函数不扩展共享语义词汇或 actor 权限。局部回收 wrapper 对接既有 owner,当前没有必须阻断的抽象重构;更广 Git runner 合并可按真实复用需求再判断。
English verdict: APPROVE — bounded Git failure and recovery are independently verified; native Windows remains unverified.
动机 / Motivation
安装并启用
repository-change-window后,每次 commit/push 都会由 Git hook 读取仓库状态并生成 pending-change 指纹。这里所有 Git 读取都走repository.git()的subprocess.run,没有上限;stale index lock、网络挂载或卡住的 fsmonitor helper 会让 hook 一直等待,进而把 Git 操作本身挂住。8169 修的是 change-quality 的 scope 读取,8152/8153/8154 各有自己的 owner,这个默认关闭、一旦安装就位于提交路径的能力还没有同样的边界。改动思路 / Approach
repository.git()是repository.py中所有 Git 读取的唯一入口,因此只改这一处即可覆盖 scope、fingerprint、worktree inventory、provider config 与 hook admission 的读取。每次读取仍在独立 POSIX session 中启动;10 秒预算用尽或收到取消时,交给共享 runtime 的retire_owned_process在同一个 deadline 内回收本次读取自己的进程组、关闭未排空的管道。随后抛出RepositoryChangeWindowError,让调用方 fail closed,而不是把未观察到的仓库当成 clean/empty。正常读取的 bytes、exit code 与 stdin 语义不变。这里的 10 秒是每次读取重新分配的预算,不是整个命令的共享 deadline。Windows 分支不再是本次读取的弱点:
retire_owned_process复用force_terminate_process的有界路径,taskkill卡住或返回非零都只会得到「清理未确认」,不会越过 deadline;管道close()放在 daemon helper 上按剩余预算 join,descendant 持有 reader 也不能延长原调用的等待。清理失败不替换本次读取的 timeout 或取消。具体改动 / Changes
repository.git(): 从无上限的subprocess.run改为独立 session 的Popen+communicate;超时或取消时先回收再抛出类型化错误。_retire_owned_read(): 只回收本次读取拥有的进程组,Windows 与 POSIX 都由共享 runtime 约束终止与管道收尾。test_change_window_git_budget.py: 覆盖正常 bytes/exit code/stdin、阻塞读取在预算内拒绝且 helper 不再存活、Git 无法启动时仍按原样抛OSError,以及在 Windows 分支上taskkill卡住或非零时超时与取消都能返回。对主干的风险 / Risks
os.name指向 Windows 分支来注入真实子进程,非 POSIX 平台按os.name != "posix"跳过。git diff --binary;这是有意的 fail-closed 边界,调用方会得到明确错误,而不是无限等待。没有改 policy、ledger schema、CLI 参数或 merge authority。retire_owned_process;本分支基于包含该提交的 main。