diff --git a/research-wiki/designs/2026-07-22-m4-migration-design.md b/research-wiki/designs/2026-07-22-m4-migration-design.md index c9a0bb0..94f25a6 100644 --- a/research-wiki/designs/2026-07-22-m4-migration-design.md +++ b/research-wiki/designs/2026-07-22-m4-migration-design.md @@ -35,14 +35,14 @@ **CHS 漂移**(5ac9f59→7eb8482,135 文件 +9818/−1853,治理关键文件仅 44+/83−): - positioning 子系统重构为纯图像模板分类(`TemplateVascularPositioner`),**position worker 不再消费 VLM**;`PositionCallScheduler` 端口与 `load_single_vlm_capacity` 已删除。 - 影响修订三条:迁移文档 §2"load_single_vlm_capacity 保留改读库聚合"作废;§6-S3"VLM 灰度先切 position worker"作废(VLM 消费点收敛为 extractors.py/classifiers.py,同属 pipeline worker,灰度只剩一段);调用点清单中 vascular_positioner.py:329 一行作废。 -- governance/invokers/limiter/scripts/selector/streaming/errors/judge/contracts_limiter **零实质变更**(仅格式化),迁移文档其余 file:line 证据仍有效。 +- governance/invokers/limiter/scripts/selector/streaming/errors/judge/contracts_limiter **零实质变更**(仅格式化);迁移文档其余证据**语义有效,行号以实施时实测为准**(tracking/config/container/ports 有小幅行号漂移)。 ## 4. 决策 1:迁移工作区机制 | 方案 | 内容 | 优点 | 缺点 | |---|---|---|---| | A 直接改 reference/(用户原话方向) | 放开 pre-tool-guard 对 reference/ 的写拦截(文件工具 + Bash 的 checkout/sed/rm 等),CLAUDE.md 铁律措辞同步改;在 reference/ 内切 feature 分支实施 | 与用户直觉一致;路径最少 | ① 钩子里 `git checkout` 也在拦截清单,A 必须动钩子,硬边界整体弱化(误删保护一并失去);② 分支切走后**旧版治理代码从工作区消失**,而迁移全程要逐段对照旧实现验证 shim 等价性,只能靠 `git show` 翻历史;③ 迁移文档/ARCHITECTURE 的 file:line 证据在工作区失效 | -| **B git worktree(推荐)** | 保持 reference/ 只读与钩子零改动;`git -C reference/ worktree add /Users/yuchengzhang/Projects/m4-worktrees/ -b feat/polygateway-migration`;实施全部发生在 worktree(路径不含 reference/,钩子天然放行;`worktree`/`commit`/`push` 子命令均不在拦截清单) | ① 硬边界一行不改;② reference/ 本体停在 main:旧版代码、蓝本、file:line 证据全程可对照——这正是"迁移前先做旧版行为审计"的物理保障;③ commit/push 走同一 origin,与 A 的 git 效果完全相同;④ 项目自带 `using-git-worktrees` skill,惯例现成 | 多一个目录;用户在别处打开项目时需知道实施分支在 worktree 里(向用户交代路径即可) | +| **B git worktree(推荐)** | 保持 reference/ 工作区只读与钩子零改动;`git -C reference/ worktree add /Users/yuchengzhang/Projects/m4-worktrees/ -b feat/polygateway-migration`;实施全部发生在 worktree(路径不含 reference/,钩子天然放行;`worktree`/`commit`/`push` 子命令均不在拦截清单) | ① 硬边界一行不改;② reference/ 本体停在 main:旧版代码、蓝本、file:line 证据全程可对照——这正是"迁移前先做旧版行为审计"的物理保障;③ commit/push 走同一 origin,与 A 的 git 效果完全相同;④ 项目自带 `using-git-worktrees` skill,惯例现成 | ① 多一个目录,且在 PolyGateway 工作目录之外——**前置**: 需把 `/Users/yuchengzhang/Projects/m4-worktrees/` 加入工具写权限(settings `additionalDirectories` 或人类门口头授权),否则实施期逐次询问;② 措辞澄清: worktree 的 add/commit/push 会向 `reference//.git` 写入 refs 与对象,"只读"实质收窄为"工作区文件与 main 检出不变"——本设计将此收窄视为可接受并明示 | | C 外部独立 clone | 在项目外重新 clone 两仓库实施 | 与 B 同等隔离 | 双份仓库易漂移(reference/ 更新后 clone 不同步);B 是 C 的严格上位 | **推荐 B**。它交付的正是用户要的东西(在项目本体仓库的 feature 分支上真实迁移、可 push),但不付出硬边界与蓝本对照的代价;用户拍板 A 的实质诉求是"能改真仓库",B 完全满足。若人类门坚持 A,则钩子改法为:reference/ 写拦截整段替换为"仅拦 rm -rf 类危险命令",CLAUDE.md §1/§5 的"只读勿改"措辞改为"M4 起为迁移工作区;蓝本对照以 git 历史为准"。 @@ -63,7 +63,7 @@ judge(`core/eval/judge.py`,快照后零变更)默认 provider=anthropic,同步 | 方案 | 内容 | 权衡 | |---|---|---| -| **走实验室 OpenAI 兼容中转(推荐)** | judge 配 `JUDGE__{PROVIDER}__1__*` 指向实验室中转网关,claude 模型名经中转;`_call_llm` 改 `asyncio.run(client.chat(...))`(Judge 端口同步、runner 无事件循环,桥接安全),解析换库 `JsonRepairStrategy` | 零库改动;**前置确认**: 中转网关是否代理 judge 所需 claude 模型(人类门时确认,不通则回退方案 3) | +| **走实验室 OpenAI 兼容中转(推荐)** | judge 配 `JUDGE__{PROVIDER}__1__*` 指向实验室中转网关,claude 模型名经中转;`_call_llm` 改同步桥接,解析换库 `JsonRepairStrategy`。**桥接方案钉死**: 每次调用一个完整 `asyncio.run(...)`,client 的构造(from_env)与 `aclose()` 都在该协程内完成——httpx 连接池绑定事件循环,跨 `asyncio.run` 复用常驻 client 会触发 "Event loop is closed"(经典坑);judge 是低频评估路径,放弃连接复用换正确性。备选(judge 调用量大时): 常驻单线程事件循环 + `run_coroutine_threadsafe` | 零库改动;**前置确认**: 中转网关是否代理 judge 所需 claude 模型(人类门时确认,不通则回退方案 3) | | 库新增 Anthropic 原生 transport | D2 有端口预留 | 新子系统 = 新公共承诺 + 独立设计与测试,为单一消费点开新承诺违反 YAGNI;M4 内否决,留 D2 储备 | | judge 暂缓收编 | judge.py 保持裸调,标注技术债 | 违背"全量迁移"验收口径;仅作中转不可用时的降级,需用户显式同意 | @@ -78,7 +78,7 @@ judge(`core/eval/judge.py`,快照后零变更)默认 provider=anthropic,同步 | G3 | `.env`/`.env.example` 改键(平铺单源 → `LLM__{PROVIDER}__1__*`;新增 namespace 等;凭据先读 .env 真实值再写) | `from_env()` 无缺配置报错 | commit | | G4 | 装配进 api lifespan 与 arq worker 入口(显式 `retryable_exceptions=(TransientError, AllSourcesExhausted)` + `aclose()`) | govdoc 业务测试绿;注错验证步级重试可触发 | commit | | G5 | `retrieval/embedding.py` 删除换 `EmbeddingClient`(映射: batch_size→`EMBED__BATCH_SIZE`、dimension→`EMBED__EXPECTED_DIM`、on_usage→遥测) | retrieval 相关测试绿 | commit | -| G6 | 删 llm/ 六文件 + test_breaker.py;改写 types.py(re-export)/protocols.py(删 TelemetryRecorder)/test_imports.py;docagent-core pyproject 移除 redis extra、根 pyproject 加 polygateway | `make ci` 全绿 + import-linter 过 | commit | +| G6 | 删 llm/ 六文件 + test_breaker.py;改写 types.py(re-export)/protocols.py(删 TelemetryRecorder)/test_imports.py;docagent-core pyproject 移除 redis extra、根 pyproject 加 polygateway;**Makefile install 行同步改**(现硬编码 `docagent-core[redis,dev]`,extra 删除后引用失效) | `make ci` 全绿 + import-linter 过 | commit | | G7 | 验收: 验收公式逐项核对 + 冒烟/回归(§9)+ 独立 verifier | ci 输出 + verifier 报告 | — | GovDoc 特有事实(迁移文档 §1): 装配层从未存在、`GovernedLLMClient` 零生产调用方、零异常捕获点——业务代码对治理层消费零改动,风险≈0;缓存 key 全变无成本(未上生产)。 @@ -104,11 +104,11 @@ CHS 特有约束: 遥测后端配 `PGW_TELEMETRY_BACKEND=postgres` 指 PG 实例 | 项目 | 冒烟(已定) | 回归候选 | |---|---|---| | GovDoc | G2 的 spike: AgentLoop 真实调用 + 遥测/缓存命中实测 | 无旧遥测基线(骨架期),**建议冒烟即回归**;可加"重跑同请求缓存命中率非零"一条 | -| CHS | 单张真实样本走完整提取 pipeline(worktree 内,治理走库) | (a)**小批对拍(建议)**: 选 20-50 张真实样本,旧版(reference/ main)与新版(worktree)各跑提取,对比结构化结果一致率 + 错误率/延迟(新版读库遥测,旧版读运行日志);(b) testing 环境 docker 部署跑 e2e;(c) 只冒烟不批跑。样本量、一致率阈值、跑批环境届时拍板 | +| CHS | 单张真实样本走完整提取 pipeline(worktree 内,治理走库) | (a)**小批对拍(建议)**: 选 20-50 张真实样本,旧版(reference/ main)与新版(worktree)各跑提取,对比结构化结果一致率 + 错误率/延迟(新版读库遥测,旧版读运行日志);(b) testing 环境 docker 部署跑 e2e;(c) 只冒烟不批跑。**先行写死两条**: 新旧两轮**串行执行**(并行则对同一真实上游 RPM 双份消耗,同"禁止双栈并跑"精神);旧版跑批同样只用实验室 Redis db3 与 PG polygateway 库,不触生产后端。样本量、一致率阈值、跑批环境届时拍板 | ## 10. v1.0 发布清单(两项目验收全过后) -① 库版本 bump `1.0.0` + 汇总 changelog;② `python -m build` 出 wheel+sdist;③ twine 上传 Gitea PyPI(token 用户提供,写 `~/.pypirc` 或环境变量,不入任何仓库);④ 一次性干净 conda 环境从 Gitea index 回装,重跑两项目测试套件绿;⑤ 两项目 pyproject 定稿 `==1.0.*` 并记录安装命令;⑥ 打 git tag `v1.0.0`;⑦ 文档同步(§15)。发布后库仓库亦推送至 Gitea 托管(用户提及"托管到 gitea",与 GitHub 双远端或迁移,人类门确认)。 +① 库版本 bump `1.0.0` + 汇总 changelog + **库自身 `make ci` 重跑全绿(发布门)**;② `python -m build` 出 wheel+sdist;③ twine 上传 Gitea PyPI(token 用户提供,写 `~/.pypirc` 或环境变量,不入任何仓库);④ 一次性干净 conda 环境从 Gitea index 回装,重跑两项目测试套件绿;⑤ 两项目 pyproject 定稿 `==1.0.*` 并记录安装命令;⑥ 打 git tag `v1.0.0`;⑦ 文档同步(§15)。发布后库仓库亦推送至 Gitea 托管(用户提及"托管到 gitea",与 GitHub 双远端或迁移,人类门确认)。 ## 11. 旧版行为审计 @@ -116,7 +116,7 @@ CHS 特有约束: 遥测后端配 `PGW_TELEMETRY_BACKEND=postgres` 指 PG 实例 ## 12. 非功能维度 -- **并发与取消**: 治理层行为全部由库承载(M1-M3 已验收);项目侧新增物仅 shim(纯映射,无状态)与装配代码。CHS `asyncio.run` 桥接点(judge)在同步 runner 线程调用,无嵌套事件循环风险(实施时以 `asyncio.get_running_loop()` 探测断言钉住)。CancelledError 穿透:shim 不含 try/except 包裹,天然穿透。 +- **并发与取消**: 治理层行为全部由库承载(M1-M3 已验收);项目侧新增物仅 shim(纯映射,无状态)与装配代码。CHS judge 桥接按 §6 钉死: client 构造与 aclose 均在单次 `asyncio.run` 协程内,杜绝 httpx 连接池跨事件循环复用;同步 runner 线程无嵌套循环风险(实施时以 `asyncio.get_running_loop()` 探测断言钉住)。CancelledError 穿透:shim 不含 try/except 包裹,天然穿透。 - **降级方向**: 继承库铁律(缓存/遥测静默、限流/熔断报错);GovDoc B15 步级重试作为业务侧兜底显式保留(G4 注入库异常类型,静默失效风险以注错测试钉死)。 - **幂等与重复**: 迁移步骤均以 commit 为回滚点、可重入(重复执行 editable install/改键无副作用);Gitea 同版本重复上传会被 409 拒绝,重发布必须 bump 版本。 - **持久化与原子性**: 项目侧不新增持久化;CHS 生产切换的 Redis key 前缀切换风险(短暂限流清零)已在迁移文档 §8 论述,手册中标注低峰执行。 @@ -125,7 +125,7 @@ CHS 特有约束: 遥测后端配 `PGW_TELEMETRY_BACKEND=postgres` 指 PG 实例 - 缺口回补的判定口径: 迁移中任何"库能力不足以让原测试通过/原行为复现"即边界缺口 → 回补进库(走库侧常规红绿流程 + 小版本)→ 项目侧重验;禁止在项目侧用变通代码掩盖库缺口。 - 项目侧新增代码(shim/装配)的失败路径: 全部落库四分类语义,shim 不吞不改异常类型;每个 shim 有先失败后通过的单测证据(测试结果门照旧)。 -- 测试基线纪律: 迁移前基线的 pass/skip 剖面留档;迁移后全绿且 skip 不增;两项目测试在各自 conda 环境跑,不与库 soak 并跑(Redis db3 FLUSHDB 冲突)。 +- 测试基线纪律: 迁移前基线的 pass/skip 剖面留档,并同步留存**预期测试增删清单**(G6/C6 删除的自测文件导致分母变化,核对时按清单修正);迁移后全绿且 skip 不增;两项目测试在各自 conda 环境跑,不与库 soak 并跑(Redis db3 FLUSHDB 冲突)。 ## 14. 风险 @@ -139,7 +139,7 @@ CHS 特有约束: 遥测后端配 `PGW_TELEMETRY_BACKEND=postgres` 指 PG 实例 ## 15. 文档同步清单(实施尾声执行) -① ROADMAP §1/§5: M4 范围改两项目、VT 标注放弃(2026-07-22 用户拍板)、状态推进;② ARCHITECTURE §11.2: 标注 VT 已放弃不迁移(能力倒推记录保留);§13 Q1/Q6 落拍板结果;③ migrations/video-tree-trm5.md 头部标注放弃;④ migrations/{govdoc-saas,chsanalyzer}.md: 漂移修订(§3)与实施结果回写;⑤ CLAUDE.md: 若人类门选方案 A 则改 reference/ 铁律措辞,选 B 则零改动;⑥ 库 README/发布说明: Gitea 安装命令。 +① ROADMAP §1/§5: M4 范围改两项目、VT 标注放弃(2026-07-22 用户拍板)、状态推进;② ARCHITECTURE §11.2: 标注 VT 已放弃不迁移(能力倒推记录保留);§13 Q1/Q6 落拍板结果;③ migrations/video-tree-trm5.md 头部标注放弃;④ migrations/chsanalyzer.md: 漂移修订(§3)与实施结果回写;migrations/govdoc-saas.md: extras 名更正(文中 `[redis,telemetry-sqlite]` 不存在,实为 `[redis,structured]`)、"不迁 embedding 待 Q3"已被拍板推翻(G5 迁移)、实施结果回写;⑤ CLAUDE.md: 若人类门选方案 A 则改 reference/ 铁律措辞;选 B 则钩子与铁律条文零改动,但"只读"语义收窄(§4-B ②)在 CLAUDE.md reference/ 条目加一行括注;⑥ 库 README/发布说明: Gitea 安装命令;⑦ **迁移合并后 reference/ 本体收尾同步**: 用户在各项目远端合并 feature 分支后,`git -C reference/ pull --ff-only`(不在钩子拦截清单)把本体推进到迁移后 main,并移除 worktree(`git worktree remove`)——蓝本自此指向迁移后代码,属预期终态。 ## 16. 被否决的备选汇总 diff --git a/research-wiki/designs/m4-migration.md b/research-wiki/designs/m4-migration.md new file mode 100644 index 0000000..0fe39bc --- /dev/null +++ b/research-wiki/designs/m4-migration.md @@ -0,0 +1,14 @@ +--- +type: design +node_id: design:m4-migration +title: "M4 迁移验证设计(GovDoc→CHS,发 v1.0)" +date: 2026-07-22 +--- + +# M4 迁移验证设计(GovDoc→CHS,发 v1.0) + +正文: `2026-07-22-m4-migration-design.md`。 + +- **选定方案**: 迁移工作区用 git worktree(reference/ 本体保持只读、钩子零改动,worktree 在项目外承载 feature 分支);依赖两阶段(开发期 editable → 验收后发 v1.0.0 至 Gitea PyPI 回装);CHS judge 走实验室 OpenAI 兼容中转。 +- **被否决备选及理由**: 直接改 reference/ + 放开钩子(硬边界弱化、旧版蓝本对照丢失——若人类门坚持则按 §4-A 的钩子改法执行);外部独立 clone(双份漂移);全程 wheel 分发(迭代慢)与 git+https(放弃 pip index 价值,留作退路);Anthropic 原生 transport(单一消费点开新公共承诺,违 YAGNI);为 VT 放弃回收库能力(任务外变更)。 +- **范围拍板**: VT 项目已放弃不迁移(2026-07-22 用户),v1.0 验收改两项目。 diff --git a/research-wiki/graph/edges.json b/research-wiki/graph/edges.json index 4e32371..da5ab5b 100644 --- a/research-wiki/graph/edges.json +++ b/research-wiki/graph/edges.json @@ -75,6 +75,11 @@ "id": "finding:p7-ocr-soak", "label": "P7 OCR soak 验收: 99.73% 与 13 不变量全 PASS", "type": "finding" + }, + { + "id": "design:m4-migration", + "label": "M4 迁移验证设计(GovDoc→CHS,发 v1.0)", + "type": "design" } ], "links": [ diff --git a/research-wiki/index.md b/research-wiki/index.md index c083c9b..c5e7616 100644 --- a/research-wiki/index.md +++ b/research-wiki/index.md @@ -1,16 +1,18 @@ # Research Wiki 索引 -> 自动生成,更新时间:2026-07-22 05:33 UTC +> 自动生成,更新时间:2026-07-22 08:58 UTC -## design (8) +## design (10) - [2026-07-20-m1-core-design](designs/2026-07-20-m1-core-design.md) `design:2026-07-20-m1-core-design` - [2026-07-20-m2-distributed-design](designs/2026-07-20-m2-distributed-design.md) `design:2026-07-20-m2-distributed-design` - [2026-07-21-m25-resilience-design](designs/2026-07-21-m25-resilience-design.md) `design:2026-07-21-m25-resilience-design` - [2026-07-21-m3-ocr-design](designs/2026-07-21-m3-ocr-design.md) `design:2026-07-21-m3-ocr-design` +- [2026-07-22-m4-migration-design](designs/2026-07-22-m4-migration-design.md) `design:2026-07-22-m4-migration-design` - [M1 核心里程碑设计:公共签名冻结与治理栈落地](designs/m1-core-design.md) `design:m1-core-design` - [M2 分布式:Redis 治理后端+背压+Postgres 遥测+pricing+Embedding+压测 harness](designs/m2-distributed.md) `design:m2-distributed` - [M2.5 治理韧性: 半死源隔离与健康感知调度](designs/m25-resilience.md) `design:m25-resilience` - [M3 OCR 端口族设计](designs/m3-ocr.md) `design:m3-ocr` +- [M4 迁移验证设计(GovDoc→CHS,发 v1.0)](designs/m4-migration.md) `design:m4-migration` ## finding (9) - [2026-07-20-m2-soak-workload](findings/2026-07-20-m2-soak-workload.md) `finding:2026-07-20-m2-soak-workload` diff --git a/research-wiki/log.md b/research-wiki/log.md index cfe1385..2185168 100644 --- a/research-wiki/log.md +++ b/research-wiki/log.md @@ -39,3 +39,5 @@ - [2026-07-22 02:09 UTC] 重建索引: 26 篇页面 - [2026-07-22 05:33 UTC] 新增 finding: P7 OCR soak 验收: 99.73% 与 13 不变量全 PASS (finding:p7-ocr-soak) - [2026-07-22 05:33 UTC] 重建索引: 28 篇页面 +- [2026-07-22 08:58 UTC] 新增 design: M4 迁移验证设计(GovDoc→CHS,发 v1.0) (design:m4-migration) +- [2026-07-22 08:58 UTC] 重建索引: 30 篇页面