From 4f6d50a7ae223b79641b20a0f3652c22c3945fdd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B5=85=E5=BF=B5?= Date: Wed, 21 Oct 2026 14:15:40 +0800 Subject: [PATCH] =?UTF-8?q?docs(plan):=20Plan=203=20=E5=A4=8D=E5=AE=A1?= =?UTF-8?q?=E4=B8=A4=20minor+=E4=BA=94=E5=BB=BA=E8=AE=AE=E2=80=94=E2=80=94?= =?UTF-8?q?status=20=E5=85=A5=20checksum=20=E5=9F=9F=E3=80=81unsupported?= =?UTF-8?q?=20=E4=B9=9F=E5=86=99=20source=5Frecords(1122)=E3=80=81?= =?UTF-8?q?=E4=B8=89=E5=BF=AB=E7=85=A7=E7=BB=91=E5=AE=9A=E8=AF=AD=E4=B9=89?= =?UTF-8?q?=E3=80=81product-tag=20=E5=8B=98=E8=AF=AF=E3=80=81permalink=20?= =?UTF-8?q?=E6=8E=AA=E8=BE=9E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Code --- .../plans/2026-10-21-slice-import-pipeline-phase3.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/superpowers/plans/2026-10-21-slice-import-pipeline-phase3.md b/docs/superpowers/plans/2026-10-21-slice-import-pipeline-phase3.md index a109999..49e9007 100644 --- a/docs/superpowers/plans/2026-10-21-slice-import-pipeline-phase3.md +++ b/docs/superpowers/plans/2026-10-21-slice-import-pipeline-phase3.md @@ -19,12 +19,14 @@ 3. 既有纪律全套沿用:TDD、临时库测试、身份断言、无包级 test 脚本、typecheck 四段链、cms 只读。 4. **导入语义核心**(spec §7.5/§8.1):同一 (site, connection, source_type, source_id, locale) 的 row → 已有 source_record 且 normalized_checksum 相同 → **skip(0 新修订)**;不同 → 新修订 + entry_locales.current_revision_id 前移(**published 不动**)。permalink 变化只影响 route,不影响条目身份。 5. wppop/extras 等未知字段已在 UniversalRow.extras——落 revision.data.extras 原样保留。 -6. **normalized checksum 输入域(P0 钉死,评审 Issue 2)**:`canonicalJson({ universal_row_version, adapter_version, mapping_version, sanitizer_version, locale, mapped_content: {title, slug, bodyHtml, seo, knownFields, extras}, taxonomy_relations: taxonomyRefs, media_reference_identities: attachmentRefs, route_source_values: {sourceUrl} })`——**rawLocation 显式排除**(位置性字段,进哈希破坏跨快照 skip);版本三常量必入(bump 语义)。canonicalJson 帮助函数从 register.service.ts 提取到 `apps/api/src/common/canonical.ts` 共享导出(register 侧改 import,零行为变更)。 +6. **normalized checksum 输入域(P0 钉死,评审 Issue 2)**:`canonicalJson({ universal_row_version, adapter_version, mapping_version, sanitizer_version, locale, mapped_content: {title, slug, **status**, bodyHtml, seo, knownFields, extras}, taxonomy_relations: taxonomyRefs, media_reference_identities: attachmentRefs, route_source_values: {sourceUrl} })`——**rawLocation 显式排除**(位置性字段,进哈希破坏跨快照 skip);版本三常量必入(bump 语义);status 必入(draft↔publish 翻转必须可见)。revision.data 顶层结构钉死:`{ title?, slug?, status, bodyHtml, seo, knownFields, extras }`。canonicalJson 帮助函数从 register.service.ts 提取到 `apps/api/src/common/canonical.ts` 共享导出(register 侧改 import,零行为变更)。**注**:sourceUrl 在哈希内(route_source_values)→ permalink 变化**会产新修订**(spec §7.5 一致),只是不建新 entry。 7. **媒体映射侧车(P0 钉死,评审 Issue 1——真实数据实证)**:真实媒体目录为扁平 GUID 命名(2625 文件无 yyyy/mm),与 WXR attachment_url 零精确命中;唯一映射在旧 cms 库 media_assets 表(source_url→file_path)。阶段 3 增加**映射侧车输入**:Task 0 从 cms PG(5433,只读 SELECT)导出该站 (source_url, file_path) 清单 JSON → 登记为 `manual_url_list` 快照(register 复用既有 kind)。对拍三级:①清单 uploads 相对路径精确命中 → ②侧车 source_url 命中(file_path 再对清单实体)→ ③missing 报告。**清单 miss 的 attachment 不插 media_assets 行**(sha256 NOT NULL 插不进),只进报告。 8. **locale 接缝坑(评审提醒)**:适配器 mapConfig.locale 缺省空串——import 必须传 `site.default_locale`,否则 1047 行全被拒为未知 locale。Task 6 编排钉死。 9. **阶段 3 站点路径来源(评审 Issue 4)**:主列表路径用 CLI 参数 `--products-path /products/ --news-path /news/`(默认值即此,记入 job metadata);taxonomy public_base_path 常量钉死(WP 默认):category→`/category/`、post_tag→`/tag/`、product_cat→`/product-category/`、product_tag→`/product_tag/`(spec §19.5 权威路径确认后可调——记入报告备注)。collision_key 折叠函数钉死:NFC + lowercase + 去尾斜杠。 10. **attachment 页三态降级(评审 Issue 3)**:阶段 3 无 sitemap 解析器——attachment 页**一律按"仅 WXR→301 媒体文件"**处理(sitemap→html 分支留待 sitemap 解析能力落地,报告注明降级)。 11. **attachment 行不建 content_entries**:wp:attachment 行只进媒体管道(media_assets)+ 路由(301);content_entries 仅 129 post + 48 product + 15 page = **192**(Task 7 计数以此为准)。sourceType→typeKey 映射钉死:wp:post→news_article、wp:page→basic_page、wp:product→product。 +12. **unsupported item 也写 source_records**(评审 Issue ②选项①):nav_menu_item 等 75 条 → source_records 行(parse_status='unsupported'、locale=站点默认、source_id=post_id、不关联 content_entry)——"不支持对象有明确结果"的可审计性;**source_records 总数 = 1122**。 +13. **import_jobs 与三快照的绑定**:job.source_snapshot_id 指向 **wxr 快照**(主输入);media_bundle 与 manual_url_list 由 CLI 按 (connection, kind) 解析最新并记入 job 报告(job 行不扩列)。Task 0 导出 SQL 加 `AND source_url IS NOT NULL`(867 中 8 行 NULL 不带出)。 ## 仓库结构增量 @@ -98,7 +100,7 @@ tests/integration/import-*.test.ts **Files:** `route-writer.ts`;Test `tests/integration/import-routes.test.ts` - [ ] 失败测试(spec §6.1 全部行有对应用例——含评审补的 asset 与首页两行,mini 数据手构补充): - - 内容 permalink → html(路径保真含 .html;target_content_id 关联);**首页 `/` → html**;**媒体上传路径 `/wp-content/uploads/...` → asset**(media public_path 生成);主列表页 `/products/`、`/news/`(**CLI 参数来源**,默认即此)→ html;产品/文章分类 → html(public_base_path 常量按前置事实 9);tag/product_tag/日期/作者 → redirect 301 主列表;attachment 页 → **一律 301 媒体文件**(前置事实 10 降级,报告注明);`?p=` → excluded_with_reason 登记 + - 内容 permalink → html(路径保真含 .html;target_content_id 关联);**首页 `/` → html**;**媒体上传路径 `/wp-content/uploads/...` → asset**(media public_path 生成);主列表页 `/products/`、`/news/`(**CLI 参数来源**,默认即此)→ html;产品/文章分类 → html(public_base_path 常量按前置事实 9,product_tag 记 `/product-tag/`——WooCommerce 默认,本切片该路径不生效仅记录);tag/product_tag/日期/作者 → redirect 301 主列表;attachment 页 → **一律 301 媒体文件**(前置事实 10 降级,报告注明);`?p=` → excluded_with_reason 登记。**"所有阶段 3 可产生的 §6.1 行"均有用例**(人工映射/确认删除两行无输入源,属合理空缺) - **exact/collision 双键**:`/About` 与 `/about` 两条并存(collision_key 折叠函数按前置事实 9 钉死);同 exact_key 冲突(两内容同路径)→ 报告 conflict 不静默覆盖 - **重导幂等**:同路径同目标 → 0 新行;目标变 → 更新(route 表可变,非不可变表) - [ ] 实现 + 绿 → commit `feat(import): 路由注册表生成`