docs: ADR-017/README/阶段4移交清单

- ADR-017 导入管道决策五项:幂等双轨身份键(六列快照行+五列内容身份)与
  canonical.ts 共享 checksum 输入域/收编 UPDATE 语义;自建 term((domain,nicename)
  兜底 + auto: 前缀 + name 回退 + 双序终态等价含 null-id 收编);counts 键全局
  命名空间求和聚合;stale 回收维持 created_at 近似 + 24h 不加心跳列(REST 化重审)
  与报告 issues 封顶;编排串行分派契约(锚点依赖推导)
- README:快速开始加 sf import 全链示例(register→import);当前状态更新
  (阶段 3 完成:192 条目真实落库/二导幂等 0 新修订/333 测试);ADR-001~017
- Plan 3 计划文档:Task 8 勾选 + 验收 6 项全过核验 + 文末新增"移交 Plan 4 清单"
  8 项(publish 命令/Render Snapshot 六文件/pilot-minimal 六类页面+Astro 五禁/
  Preview Server/最小门禁/导入产物消费接口与副本路径/续传项/度量基线 51.8s·20.3s·304MiB)

Co-Authored-By: Claude Code <noreply@anthropic.com>
This commit is contained in:
浅念
2026-10-21 21:20:21 +08:00
parent a7177afde7
commit 6d9f7b6ad7
3 changed files with 74 additions and 18 deletions
@@ -128,16 +128,33 @@ tests/integration/import-*.test.ts
- [ ] 内存/耗时记录;证据文档;commit `test(evidence): 阶段3真实全量导入验收`
- [ ] 任何计数不符 → 如实报告停下分析(同 Task 8 纪律)
### Task 8: 收尾
### Task 8: 收尾 ✅ 完成(ADR-017 五决策/HTML 报告与 issues 封顶/orchestrator.ts 抽取(import.service 849→754 行,零行为变更)/README 全链示例与阶段 3 状态/移交 Plan 4 清单 8 项;333 测试全绿;两个 commit:feat(import) + docs,不 push——推送由用户执行)
- [ ] ADR-017(导入幂等语义:稳定身份键选择/checksum 输入域/自建 term 策略);README 状态更新;typecheck 四段链/lint/test 三绿;阶段 4 移交清单(publish 命令消费的接口:current 指针集合/审计动作形状;site_config_revisions 首版生成时机建议)
- [ ] commit + push 由用户执行
- [x] ADR-017(导入幂等语义:稳定身份键选择/checksum 输入域/自建 term 策略)——`docs/adr/ADR-017-导入管道决策.md` 五决策:①幂等双轨身份键(六列快照行 + 五列内容身份)/canonical.ts 共享 checksum 输入域/收编 UPDATE 语义 ②自建 term((domain,nicename) 兜底 + auto: 前缀 + name 回退 + 双序终态等价含 null-id 收编)③counts 键全局命名空间 + 求和聚合 ④stale 回收 24h 常量 + **不加心跳列**(单进程 CLI 下收益低,REST 化重审)⑤编排串行分派契约(锚点依赖推导);附带报告 issues 封顶(REPORT_ISSUES_CAP=10k)决策入册
- [x] HTML 报告 + 错误封顶(Task 6 推迟项兑现):`report-html.ts` renderImportReportHtml(Plan 2 Task 6 模板纪律——全动态文本转义/静态骨架无 script/分组固定序)+ import.html 落盘(与 JSON 同 try 同失败口径);import.json issues/issueGroups 封顶 10k + issuesTruncated 计数(终态判定用全量长度——截断不吞 succeeded_with_issues 事实);测试 7 单元(恶意 payload 转义/结构/封顶注记)+ 1 集成(10_003 条注入:截断计数/原文保留/HTML 转义)
- [x] orchestrator.ts 抽取(审查触发器:import.service 849 行):orchestratedPipeline + mergeOutcomes + sumCounts + trySyncFinish 迁至 `apps/api/src/modules/import/orchestrator.ts`(纯函数 over ctx;契约类型单源 import.service.ts 不动——写入器同款 type-only 反向引用);既有测试全绿即证零行为变更
- [x] README 状态更新:快速开始加 `pnpm sf import` 全链示例(register→import);当前状态更新(阶段 3 完成:192 条目真实落库/二导幂等 0 新修订/333 测试);ADR-001~017;下一步阶段 4 指向文末移交清单
- [x] 阶段 4 移交清单(见文末新节定稿——含 publish 消费接口、Render Snapshot 六文件、pilot-minimal 六类页面、Preview、最小门禁、度量基线 8 项)
- [x] typecheck 四段链/lint/test 三绿(333 测试);commit 两个(feat(import) + docs);push 由用户执行
## 验收(对照 spec §15 阶段 3)
## 验收(对照 spec §15 阶段 3)✅ 全过(Task 7/8 收官核验)
- [ ] 同 Snapshot 二次导入 0 新 Revision
- [ ] Permalink 变化不创建重复 Content Entry
- [ ] 媒体歧义不自动匹配(多候选全列报告)
- [ ] URL 冲突和不支持对象全部进入报告
- [ ] 真实全量导入成功 + 幂等重跑 + 报告对照
- [ ] 三绿;published 指针全程未动
- [x] 同 Snapshot 二次导入 0 新 Revision(Task 7 独立复跑 21 断言全 PASS:revisionsCreated=0;集成测试 import-full/import-content 钉死)
- [x] Permalink 变化不创建重复 Content Entry(五列内容身份与 URL 解耦——import-content 用例 + 真实 836 301 反查)
- [x] 媒体歧义不自动匹配(多候选全列报告)(mediaAmbiguous 计数 + 逐条 issue)
- [x] URL 冲突和不支持对象全部进入报告(routesCollisions/issueGroups 六组 + unsupported → source_records parse_status='unsupported' 可审计)
- [x] 真实全量导入成功 + 幂等重跑 + 报告对照(192/1122/927(自建 476)/836/2772 逐桶对拍,见 `docs/evidence/phase3-import.md`)
- [x] 三绿;published 指针全程未动(333 测试;published_revision_id 全库 0 非 NULL——Task 6/7 双重断言)
---
## 移交 Plan 4 清单(Plan 3 收官定稿——阶段 4:content:publish + Render Snapshot + pilot-minimal 主题 + Astro 构建 + 本地 Preview,计划的必读输入)
1. **content:publish 命令**(V2 spec §8):dry-run/confirm(preview-token)/批量/审计动作形状——`published_revision_id = current_revision_id` 单语句语义、不得 UPDATE content_revisions、拒绝未解决 P0 issue、拒绝跨 site、重复发布幂等。**published 指针此刻才开始动**(Plan 3 全程未碰——ADR-010;查询起点:entry_locales where current_revision_id is not null and published_revision_id is null)。site_config_revisions 首版生成时机建议:随首次 publish 物化(site 行快照进 Render Snapshot 的 site.json 来源),本清单第 2 项消费。
2. **Render Snapshot 生成**(V2 §9.2 六冻结文件):从 **published 修订** + routes + media + site 配置物化 `site.json / content.json / taxonomies.json / routes.json / assets.json / render-manifest.json`(不可变派生产物,hash 锚定——§10.2 冻结输入)。
3. **pilot-minimal 主题 + Astro 构建管线**:六类页面按迁移快线第 8.1 节顺序(首页 → 普通页 → 产品列表 → 产品详情 → 新闻列表 → 新闻详情);ThemeManifest 最小契约(V2 §9.1);构建**只读快照**——禁查 PG/禁 Control API/禁读 storage/ 原始输入/禁站点 seed/禁构建期网络(V2 §9.2 五禁)。
4. **Preview Server**(V2 §12):route_manifest 驱动(§12.1 字段面);只绑 127.0.0.1、只读指定 build 的 Dist+Manifest;301/410/404 按 Manifest 声明;全响应 `X-Robots-Tag: noindex`;路径穿越/目录列表防御。
5. **最小门禁**(V2 §13 子集):死链(内链命中 route manifest 全量非抽样)/sitemap 双向对照/title-canonical-H1 四恰一/大小写冲突(lowercase collision)。
6. **导入产物消费接口**:published 修订集合(entry_locales.published_revision_id → content_revisions.data)、routes(route_registry 全表)、**media_assets ready 集合**(status='ready'——quarantined/unsupported 排除语义:其路由行是旧 URL 空间台账,构建/产物侧不复制文件);`storage/incoming/` 副本路径保留(WXR 副本 + 媒体副本 2625 文件/164.53 MiB + 侧车,含 storage/snapshots content-addressed 双份共约 345MB——见 `docs/evidence/phase3-import.md` §6)供构建期媒体复制。
7. **续传携带**:Task 0.2 cms 数据备份(用户暂缓——**阶段 6 L3 验收前必须补做**,Plan 2 清单第 6 项责任链延续);836 条 attachment 301 的 nginx conf 输出(V2 §14 route compile)——Plan 4 或 Plan 5 定,数据已齐(route_registry redirect 行含 location)。
8. **度量基线**(Plan 4 构建耗时对照):导入首跑 51.8s / 二导 20.3s(逐事件串行分派的交互式往返口径——提速方向批量锚点解析,见 phase3-import.md §5);内存峰值 304.3 MiB(进程集上界口径);登记 media_bundle 19.0s(2625 文件哈希+副本)。