feat(onboarding/parity): 接入包改写托管块前检测块外未提交改动,给出混合文件预警(P10) #29

Merged
lanrtop merged 2 commits from feat/agent-client-parity-p10 into master 2026-10-03 03:36:33 +08:00
Owner

目标

蓝图 agent-client-parity 的 P10(S 级):apply_onboarding_pack 往带有项目未提交改动的文件里升级炼境托管块时,会制造「同一文件混有炼境与项目两种来源改动」的混合文件(2026-10-01 enterprise 的 git-workflow.md 即此例),按「禁止字符串手术」无法拆分提交。本 PR 让接入包在这种情况下对该文件给出明确预警;默认仍只改托管块、不改块外内容。

改动

  • TemplateResult 新增可选 warning(缺省时不序列化;src/lib/commands.ts 同步为 warning?: string)。
  • apply_onboarding_pack 在模板分发与 buff 蓝图规则同步前后夹一层检测(dispatch_templates_with_mixed_file_check):
    • 写入前对 AGENTS.md、docs/ai-context/git-workflow.md、CLAUDE.md 跑 git --no-optional-locks status --porcelain --untracked-files=all -- <文件>;有改动再取 git show HEAD:./<文件>(不在 HEAD 中按空内容算:未跟踪、仅暂存、尚无提交)。
    • 两边去掉 ONBOARDING_MANAGED 与 BLUEPRINT_MANAGED 块后比较,忽略行尾、行末空白与空行(炼境追加块时插入的空行不算项目改动)。
    • 写入后只对本次确被改写的文件给出 warning,文案含文件名与「块外有未提交改动,升级后将成为混合文件」。CLAUDE.md 只由蓝图规则同步改写、不在模板结果里,预警时补一条结果。
    • git 不可用、非仓库或命令失败一律静默;不阻断、不改块外内容。
  • BLUEPRINT_MANAGED 标记提为 blueprint.rs 的 pub(crate) 常量,检测与 upsert 共用。
  • MCP apply_onboarding_pack:单项目输出在该文件行下加 ⚠️ 行,批量输出追加混合文件清单;工具描述同步。
  • 炼境 UI(BlueprintModal 接入包结果)在对应行下显示琥珀色预警。
  • docs/ai-context/project-context.yaml 契约说明同步;蓝图 P10 标 ✅,记录验证与已知限制;manifest 进度 50→55。

自验

  • cargo test --locked(src-tauri):lib 270 passed / 5 ignored / 0 failed。
  • 新增测试:
    • outside_managed_content_strips_blocks_and_ignores_eol_and_blank_lines:纯函数,剔除两种块、忽略 CRLF 与空行、不在 HEAD 时有块外内容才算、残缺块按块外处理。
    • mixed_file_warning_only_for_uncommitted_changes_outside_managed_blocks:临时 git 仓库,走与 apply 相同的检测夹层 + 真实 sync_blueprint_rules。git-workflow.md 块外未提交改写 → updated 且带预警,块外改写原样保留,托管块升到模板版本;未跟踪 CLAUDE.md 含项目内容 → 补 appended 结果并预警;与 HEAD 一致的 AGENTS.md 照常升级、无预警;全部提交后只改托管块版本并整体转 CRLF → 升级且全部无预警、不补 CLAUDE.md 行。
    • mixed_file_warning_is_silent_outside_git:非 git 目录升级无预警(--nocapture 确认没有走「临时目录在仓库内」的跳过分支)。
  • 变异自检:把探测函数强制返回 true,两个场景测试均失败,已还原。
  • pnpm typecheck 通过;pnpm test(vitest)16 passed;lefthook pre-commit / commit-msg 通过;.gitea/scripts/check-commit-msg.mjs 本地通过。

没验什么

  • 没有在真实子项目(如 enterprise)上调用 apply_onboarding_pack 走一遍:需要重建安装炼境,本次只在 cargo test 的临时仓库里验证;测试也绕过了 buff 中需要炼境 DB 的部分和 lefthook 激活(二者不改托管块文件)。
  • MCP 输出与 UI 预警行只经编译与类型检查,没有实际调用 MCP 工具或打开界面看效果。
  • 仓库里没有 apply_onboarding_pack 的预览命令,acceptance 里的「预览」无处可挂:检测在写入前完成,但升级照常进行,调用方拿到结果时混合文件已经产生;真正的「先提示再决定」需要 P8 的只报告 diff 模式复用本检测。
  • 已知误报(安全方向):从未提交过的炼境新建文件(块���整段是模板 TODO)在模板升版后重跑也会预警,因为文件不在 HEAD 中,无法区分块外内容的来源。
  • 不覆盖:单独调用 sync_blueprint_rules(UI 同步蓝图规则、批量同步)不经此检测;只比较 HEAD 与工作区,暂存区与工作区不同的中间状态不单独判断;WSL UNC 路径项目上 git 的行为没有实测(失败时静默)。

🤖 Generated with Claude Code

## 目标 蓝图 agent-client-parity 的 P10(S 级):apply_onboarding_pack 往带有项目未提交改动的文件里升级炼境托管块时,会制造「同一文件混有炼境与项目两种来源改动」的混合文件(2026-10-01 enterprise 的 git-workflow.md 即此例),按「禁止字符串手术」无法拆分提交。本 PR 让接入包在这种情况下对该文件给出明确预警;默认仍只改托管块、不改块外内容。 ## 改动 - `TemplateResult` 新增可选 `warning`(缺省时不序列化;`src/lib/commands.ts` 同步为 `warning?: string`)。 - `apply_onboarding_pack` 在模板分发与 buff 蓝图规则同步前后夹一层检测(`dispatch_templates_with_mixed_file_check`): - 写入前对 `AGENTS.md`、`docs/ai-context/git-workflow.md`、`CLAUDE.md` 跑 `git --no-optional-locks status --porcelain --untracked-files=all -- <文件>`;有改动再取 `git show HEAD:./<文件>`(不在 HEAD 中按空内容算:未跟踪、仅暂存、尚无提交)。 - 两边去掉 ONBOARDING_MANAGED 与 BLUEPRINT_MANAGED 块后比较,忽略行尾、行末空白与空行(炼境追加块时插入的空行不算项目改动)。 - 写入后只对本次确被改写的文件给出 warning,文案含文件名与「块外有未提交改动,升级后将成为混合文件」。CLAUDE.md 只由蓝图规则同步改写、不在模板结果里,预警时补一条结果。 - git 不可用、非仓库或命令失败一律静默;不阻断、不改块外内容。 - `BLUEPRINT_MANAGED` 标记提为 `blueprint.rs` 的 `pub(crate)` 常量,检测与 upsert 共用。 - MCP `apply_onboarding_pack`:单项目输出在该文件行下加 ⚠️ 行,批量输出追加混合文件清单;工具描述同步。 - 炼境 UI(BlueprintModal 接入包结果)在对应行下显示琥珀色预警。 - `docs/ai-context/project-context.yaml` 契约说明同步;蓝图 P10 标 ✅,记录验证与已知限制;manifest 进度 50→55。 ## 自验 - `cargo test --locked`(src-tauri):lib 270 passed / 5 ignored / 0 failed。 - 新增测试: - `outside_managed_content_strips_blocks_and_ignores_eol_and_blank_lines`:纯函数,剔除两种块、忽略 CRLF 与空行、不在 HEAD 时有块外内容才算、残缺块按块外处理。 - `mixed_file_warning_only_for_uncommitted_changes_outside_managed_blocks`:临时 git 仓库,走与 apply 相同的检测夹层 + 真实 `sync_blueprint_rules`。git-workflow.md 块外未提交改写 → `updated` 且带预警,块外改写原样保留,托管块升到模板版本;未跟踪 CLAUDE.md 含项目内容 → 补 `appended` 结果并预警;与 HEAD 一致的 AGENTS.md 照常升级、无预警;全部提交后只改托管块版本并整体转 CRLF → 升级且全部无预警、不补 CLAUDE.md 行。 - `mixed_file_warning_is_silent_outside_git`:非 git 目录升级无预警(`--nocapture` 确认没有走「临时目录在仓库内」的跳过分支)。 - 变异自检:把探测函数强制返回 true,两个场景测试均失败,已还原。 - `pnpm typecheck` 通过;`pnpm test`(vitest)16 passed;lefthook pre-commit / commit-msg 通过;`.gitea/scripts/check-commit-msg.mjs` 本地通过。 ## 没验什么 - 没有在真实子项目(如 enterprise)上调用 apply_onboarding_pack 走一遍:需要重建安装炼境,本次只在 cargo test 的临时仓库里验证;测试也绕过了 buff 中需要炼境 DB 的部分和 lefthook 激活(二者不改托管块文件)。 - MCP 输出与 UI 预警行只经编译与类型检查,没有实际调用 MCP 工具或打开界面看效果。 - 仓库里没有 apply_onboarding_pack 的预览命令,acceptance 里的「预览」无处可挂:检测在写入前完成,但升级照常进行,调用方拿到结果时混合文件已经产生;真正的「先提示再决定」需要 P8 的只报告 diff 模式复用本检测。 - 已知误报(安全方向):从未提交过的炼境新建文件(块���整段是模板 TODO)在模板升版后重跑也会预警,因为文件不在 HEAD 中,无法区分块外内容的来源。 - 不覆盖:单独调用 sync_blueprint_rules(UI 同步蓝图规则、批量同步)不经此检测;只比较 HEAD 与工作区,暂存区与工作区不同的中间状态不单独判断;WSL UNC 路径项目上 git 的行为没有实测(失败时静默)。 🤖 Generated with [Claude Code](https://claude.com/claude-code)
lanrtop added 1 commit 2026-10-03 03:01:50 +08:00
feat(onboarding/parity): 接入包改写托管块前检测块外未提交改动,给出混合文件预警(P10)
All checks were successful
Push & PR Check / check (push) Successful in 1m2s
Push & PR Check / check (pull_request) Successful in 59s
13aa3a1a8c
2026-10-01 enterprise 的 git-workflow.md 在有项目未提交改写时被升级了托管块,
同一文件混有炼境与项目两种来源的改动,按「禁止字符串手术」无法拆分提交,只能交人定案。
管家应在制造混合文件时明确告知,而不是事后由人发现。

- TemplateResult 新增可选 warning(序列化时缺省省略,前端类型同步)
- apply_onboarding_pack 在模板分发与 buff 蓝图规则同步前后夹一层检测:写入前对
  AGENTS.md、docs/ai-context/git-workflow.md、CLAUDE.md 跑 git status,有改动再取
  HEAD:./<文件>(不在 HEAD 中按空内容算),两边去掉 ONBOARDING_MANAGED 与
  BLUEPRINT_MANAGED 块后比较(忽略行尾与空行);写入后只对本次确被改写的文件预警,
  文案含文件名与「块外有未提交改动,升级后将成为混合文件」
- 只提示不阻断,块外内容照旧不动;git 不可用、非仓库或命令失败一律静默;
  git status 带 --no-optional-locks,不抢 index.lock
- CLAUDE.md 只由蓝图规则同步改写,不在模板结果里,预警时补一条结果
- BLUEPRINT_MANAGED 标记提为 blueprint.rs 的 pub(crate) 常量,检测与 upsert 共用
- MCP 单项目输出在该文件行下加预警行,批量输出追加混合文件清单;工具描述同步;
  炼境 UI 接入包结果行下显示预警
- 契约文档 project-context.yaml 同步;蓝图 P10 标 ✅ 并记录验证与已知限制

验证:cargo test --locked lib 270 passed / 5 ignored;新增 3 个测试(纯函数、临时 git
仓库三种情形、非 git 目录),变异自检(探测强制返回 true 时两个场景测试均失败);
pnpm typecheck 与 pnpm test 通过。

Rules-Applied: R01,R06,R12
Feature-Confirmed: true

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
lanrtop added 1 commit 2026-10-03 03:32:59 +08:00
fix(onboarding/parity): 混合文件预警收窄空白归一、失败时不丢预警、测住改写判断(P10 审查修复)
All checks were successful
Push & PR Check / check (push) Successful in 1m2s
Push & PR Check / check (pull_request) Successful in 1m5s
c9b951dd30
P10 审查核实的三处缺陷:

- 块外比较原先逐行 trim_end 并丢弃全部空行,项目在块外删空行(Markdown 两段
  并成一段)或加行尾空格(硬换行)时判为无改动,升级后不预警却产生混合文件。
  改为 CRLF 统一为 LF、托管块原位换成占位符,只把文末占位符连同其前空白按
  trim_end 归一(正好抵消炼境追加托管块时的 trim_end + 空行);文中托管块两侧
  的空行与行尾空格照常比较——炼境只原位替换文中的块,不碰两侧。
- dispatch_templates_with_mixed_file_check 先 `then()?` 后标注:buff 先同步蓝图
  规则改写了 AGENTS.md/CLAUDE.md、再写 DB 失败时,预警随 Err 一起丢失。改为
  无论成败先标注,失败时把混合文件名并入错误信息;无混合文件则原样返回错误。
- 「块外有未提交改动但托管块已是最新、本次不改写」组合没有测试,删掉 annotate
  的改写判断测试照样全绿。主场景测试补情形三。

测试:新增 outside_managed_whitespace_edits_count_as_changes、
mixed_file_warning_survives_failure_after_write,主场景补情形三;纯函数测试的
期望值随归一化收窄更新("# 标题\n项目内容" → "# 标题\n\n项目内容",保留「之前
追加的块尚未提交、只多出块前空行」不算改动的断言)。变异自检:三处修复逐一回退,
对应测试各自失败,已还原。cargo test --locked:lib 272 passed / 5 ignored,0 failed;
pnpm typecheck 通过。契约文档 project-context.yaml 与蓝图 P10 卡同步。

Rules-Applied: R07,R12
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
lanrtop merged commit 13dc75203b into master 2026-10-03 03:36:33 +08:00
Sign in to join this conversation.
No reviewers
No Label
No Milestone
No project
No Assignees
1 Participants
Notifications
Due Date
The due date is invalid or out of range. Please use the format 'yyyy-mm-dd'.

No due date set.

Dependencies

No dependencies set.

Reference: lanrtop/dev-manager-tauri#29
No description provided.