Files
cms-website/docs/evidence/phase2-smoke.md
T
浅念 21ef37232d test(evidence): 阶段2真实WXR冒烟通过
真实 hesupipe WXR(5,490,399B,SHA-256 与 Plan 1 基线一致)跑 wxr:probe 全链:
计数 18 项对照全过(rows 1047 / terms 451 / unsupported 75 细分一致 / failed 0 /
item 总数 1122);heapUsed max 62.2MiB < 100MiB(setInterval(100ms) 双 max 口径,
全程 167ms 仅 2 样本如实注明);parseMs 含流 IO 等待口径注明。
nicename 锚点核对:在表 taxonomy 706/706 全命中(nicename≡slug,违例 0);
category/post_tag 共 807 引用因 wp:term 表缺该 taxonomy 不可解析——阶段 3 需按
(domain, nicename) 自建缺失 term,不能假设 term 表完备。
eslint.config.js:scripts/*.mjs 显式 node 全局(no-undef 误报)。

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-10-21 13:25:09 +08:00

144 lines
9.4 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 阶段 2 真实 WXR 冒烟证据(Plan 2 · Task 8)
**verdict:PASS**(计数对照 18 项全过 + 内存断言通过 + nicename 锚点核对完成)
| 项 | 值 |
|---|---|
| 日期 | 2026-10-21 |
| 环境 | Windows 11 · Node v24.13.0 · pnpm 10.7.1 · tsx 直吃 TS 源码(与 sf CLI 同机制) |
| 输入 | `D:/project/cms/storage/wxr/fd04d6ba8a1316b6.xml`(5,490,399 B ≈ 5.5MB,绝对只读) |
| 输入完整性 | SHA-256 `f9bc5d4497a1792af37abff78e0096268bda975cb367a956da42bcf9552b9f62` 与 Plan 1 基线一致——文件自 Task 0.4 起未变 |
| 冒烟脚本 | `scripts/smoke-real-wxr.mjs`(probe 全链 + setInterval(100ms) 内存采样 + 基线断言 + nicename 核对) |
| 证据 run | `artifacts/probe/20261021T132153-1yft49/`(smoke.json / report.json / report.html) |
| CLI run | `artifacts/probe/20261021T132302-26azne/`(report.json / report.html) |
## 实际执行的命令原文
```bash
# 冒烟主路径(仓库根 D:\project\cms-one):probe 同链路 + 内存采样 + 基线断言 + nicename 核对,stdout 出 JSON
pnpm exec tsx scripts/smoke-real-wxr.mjs # 缺省 --wxr 即 hesupipe 文件;exit 0 = PASS
# 计划钉死的 CLI 命令(Step 1 原文,只读诊断通道直读 cms)——计数与冒烟脚本一致
pnpm sf wxr:probe --wxr "D:/project/cms/storage/wxr/fd04d6ba8a1316b6.xml"
```
注:smoke 脚本为 .mjs,但 `@sf/adapter-wp` 经根 tsconfig paths 直连 packages 的 TS 源码,故须 tsx 运行(纯 node 无法解析 workspace TS 包);与 `scripts/sf.ts` 的 CLI 执行机制(Plan 2 评审钉死)相同。
## Step 1 计数对照(实际 vs 基线,逐项)
基线:`docs/evidence/real-wxr-baseline.md`。断言规则:**任何一项不一致都算 FAIL**。以下 18 项全部 `ok`(smoke.json `checks` 数组原样可查):
| 对照项 | 基线 | 实际 | 结果 |
|---|---|---|---|
| 输入字节数 | 5,490,399 | 5,490,399 | ok |
| 输入 SHA-256 | f9bc5d44…b9f62 | f9bc5d44…b9f62 | ok |
| totals.rows | 1,047(855+129+48+15) | 1,047 | ok |
| totals.terms | 451 | 451 | ok |
| totals.unsupported | 75 | 75 | ok |
| totals.failed | 0 | 0 | ok |
| item 总数(rows+unsupported+failed) | 1,122 | 1,122 | ok |
| rows `wp:attachment` | 855 | 855 | ok |
| rows `wp:post` | 129 | 129 | ok |
| rows `wp:product` | 48 | 48 | ok |
| rows `wp:page` | 15 | 15 | ok |
| unsupported `wp:nav_menu_item` | 68 | 68 | ok |
| unsupported `wp:wpcf7_contact_form` | 3 | 3 | ok |
| unsupported `wp:elementor_library` | 2 | 2 | ok |
| unsupported `wp:wp_navigation` | 2 | 2 | ok |
| counts 桶键集合(无多余/缺失桶) | 上述 8 键 | 完全一致 | ok |
| probe.fatalError | null | null | ok |
| 内存 heapUsed max | < 100MB | 65,268,760 B(62.2MiB) | ok |
计数细分(created=清洗有变化将产新内容 / skipped=无变化,导入前投影语义):
| sourceType | created | skipped | unsupported | 基线口径 |
|---|---|---|---|---|
| wp:attachment | 0 | 855 | 0 | 855 rows |
| wp:post | 87 | 42 | 0 | 129 rows |
| wp:product | 47 | 1 | 0 | 48 rows |
| wp:page | 4 | 11 | 0 | 15 rows |
| wp:nav_menu_item | – | – | 68 | 68 unsupported |
| wp:wpcf7_contact_form | – | – | 3 | 3 unsupported |
| wp:elementor_library | – | – | 2 | 2 unsupported |
| wp:wp_navigation | – | – | 2 | 2 unsupported |
清洗统计(背景数据,非对照项):changedRows=138(post 87 + product 47 + page 4;attachment 无正文零清洗全 skipped);removed-tag=3、removed-attr=4,667;rowErrors 固化 4,793 条(上限 10,000,未触顶 truncated=0)。
## Step 2 内存与耗时
**内存(计划钉死口径:smoke 脚本内 `setInterval(100ms)` 采 `process.memoryUsage()` 的 heapUsed/rss 双 max)**
| 指标 | 值 |
|---|---|
| heapUsed max | **65,268,760 B = 62.2MiB < 100MiB(断言通过)** |
| rss max | 175,218,688 B = 167.1MiB(进程整体常驻,含 node+tsx 运行时基线,仅记录不断言) |
| 采样样本数 | 2(见下方口径说明) |
口径说明(如实记录):
- 采样的是**整个进程**的 heapUsed/rss——含 tsx 加载器与模块基线,非解析增量;断言语义是"流式解析 5.5MB 文件时进程堆峰值仍 < 100MB",通过即证明无整文件缓冲(整读 5.5MB 原文 + 解析树必然显著更高,且会随文件增长线性突破)。
- probe 全程仅 ~167ms(见下),100ms 间隔只落到 2 个样本(1 个 interval tick + 终末补采 1 次)。max 以**实测下界**口径记录;考虑解析器 per-item yield、不 buffer item 列表的结构保证(Task 3 Step 2 钉死),两样本已覆盖解析爬坡段与收尾段,实测 62.2MiB 与 100MiB 线余量充足。
**耗时(smoke run / CLI run 各一次,量级一致)**
| 指标 | smoke run(1yft49) | CLI run(26azne) |
|---|---|---|
| parseMs | 73.6ms | 79.2ms |
| sanitizeMs | 81.7ms | 79.2ms |
| totalMs | 166.9ms | 169.5ms |
**parseMs 口径(Task 6 移交,务必连同数字一起引用)**:parseMs 是 `parser.next()` await 窗口累计——**含流式 IO 等待**(磁盘读、backpressure),非纯 CPU 解析耗时;totalMs 覆盖整个消费循环(含映射与报告聚合);totalMs ≥ parseMs+sanitizeMs 的差值即映射/聚合时间。
## nicename 锚点核对(Task 4 冻结点)
**核对方法**:第二遍独立流式解析(同一 parseWxrStream),全量收集 wp:term 表(taxonomy → slug 集)与 item 引用(domain → nicename 计数),流结束后交叉验证;抽检规则=文档序前 10 个含 `domain="category"` 引用的 item(该类 item 共 129 个)。
**抽检 10 条明细**(全部未解析到 term slug,原因见下):
| rawLocation | postId | post_type | category nicename(value) | ∈ wp:term slug 集 |
|---|---|---|---|---|
| wxr://item/941 | 1646 | post | company-news(Company News) | 否 |
| wxr://item/942 | 2281 | post | trade-news(Trade News) | 否 |
| wxr://item/943 | 2549 | post | progect(Progects) | 否 |
| wxr://item/944 | 2833 | post | progect(Progects) | 否 |
| wxr://item/945 | 3121 | post | progect(Progects) | 否 |
| wxr://item/946 | 3124 | post | progect(Progects) | 否 |
| wxr://item/947 | 3127 | post | progect(Progects) | 否 |
| wxr://item/948 | 3130 | post | progect(Progects) | 否 |
| wxr://item/949 | 3138 | post | progect(Progects) | 否 |
| wxr://item/950 | 3143 | post | progect(Progects) | 否 |
**抽检一致率(category nicename 可解析到 wp:term slug):0/10。根因不是 nicename≠slug,而是该 WXR 的 wp:term 表根本没有 category/post_tag 条目**。全量分层核对(grep 级独立复核结论一致):
| domain(item 引用数) | 可解析 | wp:term 表中有该 taxonomy? | 结论 |
|---|---|---|---|
| product_tag(588) | 588/588 = 100% | 有(439 term) | nicename ≡ term_slug |
| product_cat(49) | 49/49 = 100% | 有(10 term) | nicename ≡ term_slug |
| nav_menu(68) | 68/68 = 100% | 有(1 term:mainmenu) | nicename ≡ term_slug |
| elementor_library_type(1) | 1/1 = 100% | 有(1 term) | nicename ≡ term_slug |
| category(148 引用,5 个不同 nicename:trade-news 59 / progect 29 / news 28 / company-news 20 / notification 12) | 0/148 | **无(0 term)** | taxonomy 未导出,锚点无从对拍 |
| post_tag(659 引用,471 个不同 nicename) | 0/659 | **无(0 term)** | taxonomy 未导出,锚点无从对拍 |
汇总:**wp:term 表内 taxonomy 的全部 706 条引用 100% 命中 slug,nicename≠slug 违例 0 条**;category/post_tag 共 807 条引用因 term 表缺该 taxonomy 不可解析。(wp:term 总数 451 = product_tag 439 + product_cat 10 + nav_menu 1 + elementor_library_type 1,与 totals.terms 一致。)
**对阶段 3 taxonomyRefs 映射策略的结论**:
1. Task 4 的锚点设计(`sourceTermId` = item 内 @nicename)被实数据**正向验证**:凡 term 表覆盖的 taxonomy,nicename 与 term_slug 完全等同(706/706),"真实 WP 中 category @nicename 即 term slug"的假设在本文件所有可对拍域上成立;
2. 但**不能假设 wp:term 表完备**:本 WXR 未导出 category/post_tag 的 term 条目(WordPress 7.1.3 导出行为,含 nav_menu/elementor/product 域却缺这两个常规域)。阶段 3 做 slug → term_id 解析时,category(148 引用/5 nicename)与 post_tag(659 引用/471 nicename)将全部 miss——需按 (domain, nicename) 自建缺失 term(value 可作 name),不能只依赖 wp:term 事件;
3. 数据怪癖原样保留:`progect`(源站拼写如此,29 处引用)按原文迁移不修正。
## 报告产物
| 产物 | 路径 |
|---|---|
| 冒烟结果(断言/内存/nicename 全量数据,JSON) | `artifacts/probe/20261021T132153-1yft49/smoke.json` |
| probe 报告 JSON(smoke run) | `artifacts/probe/20261021T132153-1yft49/report.json` |
| probe 报告 HTML(smoke run) | `artifacts/probe/20261021T132153-1yft49/report.html` |
| probe 报告 JSON/HTML(CLI run) | `artifacts/probe/20261021T132302-26azne/report.{json,html}` |
(artifacts/ 不入库(.gitignore),产物仅存本地;smoke.json 的 `checks` 数组即上表 18 项断言的机器可读原貌。)
## 只读声明
本次冒烟对 `D:/project/cms/storage/wxr/fd04d6ba8a1316b6.xml` 仅执行读取操作(stat、sha256 流式读、两遍 createReadStream 解析读),未修改该文件及 `D:\project\cms` 下任何内容;全部写入仅发生在本仓库 `artifacts/probe/` 与上述两个新建文件。