fix(run): authority-root 跨盘 symlink 下 create_dir_all 假阳性自愈,两处消息补路径 (#279) - #280
Conversation
Code Intel change risk
Top signals
revspec: |
|
✅ Health of changed files: 7.2 → 7.4 (+0.2) 📋 At a glance ✅ Health gate: passed 🔎 More signals (3)🗺️ Change map flowchart LR
subgraph PR ["Changed in this PR (3 with dependents)"]
f_crates_code_intel_cli_src_artifacts_rs[".../src/artifacts.rs 🔥"]:::changed
f_crates_code_intel_cli_src_project_context_rs[".../src/project_context.rs 🔥"]:::changed
f_crates_code_intel_cli_tests_primary_entry_rs[".../tests/primary_entry.rs"]:::changed
end
f_crates_code_intel_cli_src_main_rs[".../src/main.rs"]
f_crates_code_intel_cli_src_artifacts_rs --> f_crates_code_intel_cli_src_main_rs
f_crates_code_intel_cli_src_run_cli_rs[".../src/run_cli.rs"]
f_crates_code_intel_cli_src_artifacts_rs --> f_crates_code_intel_cli_src_run_cli_rs
f_crates_code_intel_cli_src_cli_primary_rs[".../cli/primary.rs"]
f_crates_code_intel_cli_src_project_context_rs --> f_crates_code_intel_cli_src_cli_primary_rs
f_crates_code_intel_cli_src_cli_project_query_rs[".../cli/project_query.rs"]
f_crates_code_intel_cli_src_project_context_rs --> f_crates_code_intel_cli_src_cli_project_query_rs
f_crates_code_intel_cli_src_project_context_rs --> f_crates_code_intel_cli_src_main_rs
f_crates_code_intel_cli_src_mcp_serve_handlers_rs[".../mcp_serve/handlers.rs"]
f_crates_code_intel_cli_src_project_context_rs --> f_crates_code_intel_cli_src_mcp_serve_handlers_rs
f_crates_code_intel_cli_src_cli_command_catalog_mod_rs[".../command_catalog/mod.rs"]
f_crates_code_intel_cli_tests_primary_entry_rs --> f_crates_code_intel_cli_src_cli_command_catalog_mod_rs
f_crates_code_intel_cli_tests_primary_entry_rs --> f_crates_code_intel_cli_src_cli_primary_rs
f_crates_code_intel_cli_tests_primary_entry_rs --> f_crates_code_intel_cli_src_main_rs
more(["+2 more dependents"])
PR --> more
classDef changed fill:#dbeafe,stroke:#1d4ed8,color:#1e3a5f
classDef warn fill:#fef3c7,stroke:#b45309,color:#78350f
classDef guard fill:#dcfce7,stroke:#15803d,color:#14532d
Solid arrows: code that imports the changed files (8 direct dependents, from the last indexed snapshot). Dashed: history/tests. 🔥 Hotspots touched (5)
2 more
💀 Dead code (1 finding)
📊 See the full report for this PR |
|
Warning Review limit reached
Next review available in: 57 minutes Limit details: You’ve used all 1 included review currently available under your plan. You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (6)
✨ Finishing Touches📝 Generate docstrings
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
收口补充:加 |
46807c1 to
261e369
Compare
…s,两处消息补路径 (#279) `code-intel .` quick start 在 authority root 是跨盘 symlink 时首次调用就撞 "create repository authority root: ... already exists (os error 183)" exit 74——`CreateDirectoryW` 对经过跨卷 symlink 的全新子目录会误报 ERROR_ALREADY_EXISTS,`create_dir_all` 自带的 is_dir() 兜底救不了,因为 is_dir() 走的是同一个 reparse point。 新增 artifacts::ensure_directory 对最近已存在祖先目录 canonicalize 后重试 自愈;project_context.rs::run() 与 execution_kernel.rs::nest_authority_root() 两处共享调用点都换过去,真撞车时错误消息补上目标路径。退出码维持 74 不变。 Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…t --check 挂了) Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
261e369 to
a0104f9
Compare
Fixes #279.
问题
README/
--help的 quick start——code-intel .(等价于code-intel . --mode lite --json)——在本仓自身跑会崩:sentrux check .等窄命令完全正常,只有 authoritative-run 的 authority-root 创建这一步坏。细节、复现过程、根因排查见 #279。根因
fs::create_dir_all(path)在 Windows 上有一个反直觉行为:当path的某个祖先分量是指向另一块盘的 symlink 时,为一个从未存在过的子目录创建目录会返回ERROR_ALREADY_EXISTS(os error 183)——目标在调用前后都不存在,立即重试也是同样的错误(不是竞态)。create_dir_all自带的兜底("AlreadyExists 就查path.is_dir(),是目录就当成功")救不了这个场景,因为is_dir()也是穿过同一个 reparse point 解析的,同样返回false。两处调用点用同一条消息模板把这个 IO error 直接折叠成裸文本,一个路径都不带:
crates/code-intel-cli/src/project_context.rs(ProjectContext::run())——quick start 实际经过的这一处crates/code-intel-cli/src/authoritative_run/execution_kernel.rs(nest_authority_root(),run execute用的姊妹调用点)这和 #145 修的缺陷同源:把一个具体的 IO 情况塞进一个笼统的 error 分支,吐出不可执行的裸 OS error。#145 修的是发布一个已完成的 run 撞到已存在的发布名;这次是创建 authority root 目录本身这一步——调用点不同、症状也不同(这次多数情况下目标根本不存在,说"已经发布在这里"是假话),但缺陷类是同一个。
改动
artifacts.rs新增pub(crate) fn ensure_directory(path) -> io::Result<PathBuf>:正常情况直接create_dir_all后原样返回path(对普通、非 symlink 场景零行为变化);命中"AlreadyExists 但is_dir()也是 false"这个 Windows 症状时,对最近一层已存在的祖先目录canonicalize后重试,返回解析出的真实路径;真撞车(比如目标被同名文件占用)时原样把底层io::Error传回去,不吞。project_context.rs::run()与execution_kernel.rs::nest_authority_root()两处都换成调用这个共享 helper,并且都把目标路径补进错误消息(之前两处都是零路径上下文的裸 OS error,同一个缺陷类)。调用方现在用 helper 返回的(可能被解析过的)路径继续走下去。ProjectError::host_io/RunError::io)不变——run_error.rs自己的注释已经把 74 定义为"host 侧真出问题",这本来就是正确分类,不需要像 fix(run): 发布名撞车给出独立退出码 73 与可解析 stdout,终结「exit 65 + 零字节」 #145 那样新开一档退出码。为什么不是照抄 #145 的"就是消息写清楚":多数真实触发场景下(跨盘 symlink)目标压根不存在,"已经发布在这里,换个名字或删掉" 是假话,会把人往错误方向引导。看了 authority root 的创建/使用方式后发现:
create_dir_all本来就是为了"这个容器目录该被复用"这个语义选的(相对于会在已存在时报错的create_dir)——bug 不是"没把已存在的 root 当可复用",而是这份幂等性在这一种 Windows 症状下被打破了。所以修法是把幂等性真正修好,而不是把假阳性包装成一条更好看的报错。测试
新增:
artifacts_tests.rs:ensure_directory的三个可移植单测(新建、幂等、真文件挡路时报错)+ 一个#[cfg(windows)]尽力而为单测(真实复现过一次,但发现这个 Windows 症状依赖某种"陈旧"OS 状态——同进程现建的跨盘 symlink 无论对哪块盘都摇不出来,只有长期存在的那个稳定复现;测试如实尝试,摇不出来就 skip 而不是断言假象)+ 一个纯路径运算的确定性单测覆盖恢复逻辑本身。project_context/tests.rs与execution_kernel.rs的mod tests:各一个单测,用"目标位置被同名文件占用"这个可移植、确定性的方式验证真撞车时报错仍然失败,且消息里带上了被挡住的路径。tests/primary_entry.rs:root_entry_names_the_authority_root_path_when_a_file_blocks_it,走编译后的二进制端到端复现code-intel .这条调用链,同样用文件占位的方式验证。cargo check -p code-intel --tests:clean。所有新增/相关测试单独跑通过;cargo test -p code-intel --locked全量结果见下方评论(或 CI)。legacy/tools/check-hardcoded-paths.ps1:OK(129 files;本 PR 未新增/修改任何.ps1/.psm1/.md/.yml,也未触碰orchestration/**/*.json的任何 digest pin)。DR-0001 适用性
这不是"装不上/装上跑不了"那一类——普通 checkout +
cargo build --release+ 直接跑二进制就能稳定复现,--help、sentrux check都正常。不需要进 install-smoke 闸;已在 #279 里写明这个判断。Sentrux 会话闸
legacy/Invoke-SentruxAgentTool.ps1 session_start "."已在改动前跑过(baseline 已存,gate pass);session_end将在推送前跑,本 PR 不会带着未过session_end的改动。