浅念
|
a7177afde7
|
feat(import): HTML 报告与错误封顶;orchestrator 抽取
- report-html.ts:renderImportReportHtml(Plan 2 Task 6 模板纪律——全动态文本
转义/静态骨架无 script/分组固定序渲染/封顶注记),import.html 与 import.json
同 try 原子落盘(同 REPORT_WRITE_FAILED 失败口径)
- 报告 issues 封顶(Task 6 推迟项):REPORT_ISSUES_CAP=10k——flat 清单与
issueGroups 各组同限截断 + issuesTruncated 计数;终态判定(succeeded_with_issues)
在全量长度上做,截断不吞终态事实;counts/sanitize 始终完整
- orchestrator.ts 抽取(审查触发器 import.service 849 行):orchestratedPipeline/
mergeOutcomes/sumCounts/trySyncFinish 迁出为纯函数 over ctx;契约类型单源
import.service.ts 不动;既有测试全绿即证零行为变更
- 测试 +8:单元 7(恶意 payload 转义/结构/分组序/封顶注记/渲染不改输入)+
集成 1(10_003 条注入:截断计数/JSON 原文保留/HTML 转义/终态判定);333 全绿
Co-Authored-By: Claude Code <noreply@anthropic.com>
|
2026-10-21 21:20:12 +08:00 |
|
浅念
|
fa6e8a35dc
|
chore(import): 终验三处一行补完——fact-12 JSDoc 分层和解、flush 措辞、tsbuildignore
Co-Authored-By: Claude Code <noreply@anthropic.com>
|
2026-10-21 20:40:30 +08:00 |
|
浅念
|
77687e2330
|
fix(import): 失败报告部分冲刷;列表路径校验(建行前);JSDoc 求和措辞;reason 归档
Task 6 质量评审四项修复:
- 失败报告部分冲刷(Fix 1):orchestratedPipeline 分派/finish 包 try/catch——
中途抛错时把可安全取得的部分产出冲入 ctx.report 后重抛:term/content 的
finish 是纯返回(已算成复用、未算成就地补算 trySyncFinish,自身抛错放弃
该部分不掩盖原错)、已收集的 adapter 问题/清洗统计、进度计数
eventsDispatched(orchestrator 键,仅失败路径出现——成功路径不占 18 键面)。
media/route finish 依赖库与先序产物,失败路径不调用(其键缺席如实反映)。
- 列表路径校验(Fix 3):ImportErrorCode 增 INVALID_LIST_PATH;解析期防线
移至阶段 2.5(建 job 行前——建行/置 running 后再抛会留悬挂行);复用
route-writer 导出的 isSafePath;normalizeListPath 自带安全拒绝(写入器
自调用位双覆盖)。CLI 无需新码(既有 ImportError 通道按 code 呈现)。
- JSDoc 求和措辞(Fix 2):content-writer/media-writer 的 counts 键契约
注记由"返回值覆盖同名键 CLOBBER"改为"同名键求和(Task 6 钉死——防覆盖
安全网)",与 ImportPipelineOutcome.counts 契约对齐。
- reason 归档(Fix 4):分派循环对 unsupported/error 事件把 reason/issue
推入 adapter 问题组(此前被静默丢弃)。
测试:import-full 增 2 例(手构流 3 事件后爆炸 → failed + eventsDispatched=3
+ 部分 content/term 计数 + unsupported/error reason 双归档;--products-path
/../x/ 等 → INVALID_LIST_PATH 零 job 行)。全量 325 通过;typecheck/lint 干净。
Co-Authored-By: Claude Code <noreply@anthropic.com>
|
2026-10-21 20:34:43 +08:00 |
|
浅念
|
8003de336b
|
feat(import): 全链编排与导入报告
Task 6(Plan 3):四家写入器汇流为默认编排管道。
- import.service:注入 events/pipeline 缺席时走真实事件流(runWxrAdapter
惰性 async generator,mapConfig.locale=site.default_locale 前置事实 8);
分派严格串行 content→term→media→route(禁 Promise.all);finish 硬序
term(sync)→content(sync)→media(await)→route(await);counts 由 ⊕ 覆盖
改为逐 key 求和聚合;新增 stale 回收(同站点 queued/running >24h 一条
SQL 置 stale);报告新增 paths/productsPath+newsPath、issueGroups 六组、
sanitize 清洗统计(事件流 changedRows/byDiffType 聚合)、adapterTiming。
- content-writer:NULL-entry 收编(快照行在而 content_entry 空,五列先验
三分支:无先验新建挂接/同 checksum 挂接 skipped/异 checksum 挂接新版本)。
- route-writer:attachment 降级汇总按去重 sourceId 计(重跑仍必现);
normalizeListPath 导出;writeAttachmentRoute 返回 written/resolved/blocked。
- 四家写入器 identity 收敛共享基类型 WriterContext =
Pick<ImportJobContext,'db'|'siteId'|'connectionId'>(type-only import,
无运行时环依赖)。
- CLI import 增 --products-path/--news-path(前置事实 9,缺省 /products/
/news/)记入 job 报告。
- 测试:tests/integration/import-full.test.ts 6 例(全链 zh-CN 接线证明
+published 全 NULL/报告四域计数+sanitize+分组/幂等重跑零写语义/
无 media 快照域缺失不失败/NULL-entry 收编/stale 回收/REPORT_WRITE_FAILED
遗留补测);import-job 契约测试钉死 counts 求和(100⊕3=103)。
全量 323 通过;typecheck/lint 干净。
Co-Authored-By: Claude Code <noreply@anthropic.com>
|
2026-10-21 20:08:06 +08:00 |
|
浅念
|
bb2d381308
|
fix(import): finish 域路径安全守卫;attachment ?p= 排除对齐;歧义/降级计数精化;permalink 形态覆盖
- isSafePath 扩至 finish 域②(分类页 public_base_path+slug)与域④(media_assets public_path)——WXR 原始 slug 与库表原样切片同携穿越向量,拒绝即 issue+不登记
- writeAttachmentRoute 与内容行同口径排除 ?p=/&page_id=(?attachment_id= 不在排除表,照常 query_key 建模),排除计数 routesExcludedQueries
- 多资产歧义消息改"命中 ≥2 行"(LIMIT 2 探针只知下界)
- 降级汇总去虚报:writeRoute 返回四态,downgraded 只计实际写入(created/updated)——重复 attachment 事件 no-op 不重复计数
- foldCollisionKey JSDoc 钉死:折叠仅 JS 侧计算落列,勿用 PG normalize 库侧重算(ICU 版本差异面)
- 测试补 permalink 形态 attachment 301(纯路径行 query_key NULL)+ 重复事件降级计数"1 条"断言 + 双 finish 域安全守卫拒绝用例(317 全绿)
Co-Authored-By: Claude Code <noreply@anthropic.com>
|
2026-10-21 19:40:35 +08:00 |
|
浅念
|
9d2cc0a46d
|
feat(import): 路由注册表生成
§6.1 处置全表落 route_registry(route 域唯一写入方):
- 内容 permalink → html(路径保真 + target_content_id 经 source_records 关联);
首页 / 与主列表 /products/ /news/(CLI 参数注入)finish 期生成;
- category/product_cat → html(public_base_path 常量 + term slug);post_tag/
product_tag → 301 对应主列表(terms×taxonomies 全表 finish 期生成);
- attachment 页一律 301 媒体文件(前置事实 10 降级一条汇总 issue;暂存事件、
finish 反查 media_assets——依赖 media-writer 先落资产的时序契约);
?attachment_id= 查询形态走 query_key 单独建模(spec §5.6 查询路由不并 path);
- 上传媒体路径 → asset(media_assets 全表;target_file 为产物路径占位);
- ?p=/&page_id= 不插行(route_kind 六值无 excluded——查询路由 SP3),计数
routesExcludedQueries + 逐条 issue 落 excluded_with_reason 报告语义;
- ADR-007 双键:/About 与 /about 并存 + collision_key 折叠预警不计失败;
同 exact_key 异 owner 冲突保留先到 + issue 列后者;
- upsert 三分:miss INSERT / 同 owner 描述字段 diff UPDATE / 异 owner 冲突;
幂等重跑零计数,--news-path 变化触发 tag 301 目标同行 UPDATE。
counts 独占五键(route 前缀):routesCreated/routesUpdated/routesRedirects/
routesCollisions/routesExcludedQueries。315 测试(+5);typecheck/lint 绿。
Co-Authored-By: Claude Code <noreply@anthropic.com>
|
2026-10-21 19:15:21 +08:00 |
|
浅念
|
7e6ce91001
|
fix(import): 媒体工厂守卫与加固——manifest 形态/侧车门控/冲突约束名/窗口边界与冲突测试
评审加固五项:
- manifest 形态守卫:bundle 在场而 metadata.manifest 非数组 → throw(与
storageRoot 守卫同风格),不与"bundle 合法缺席=空清单"共用静默空 coercion
- 侧车门控:空清单下级②不可达,跳过侧车加载——破损侧车副本不因无用输入
让整 job 失败
- public_path 冲突 catch 按约束名精确认领(postgres.js 的 constraint_name,
drizzle 包一层在 cause)——未来加第三唯一索引不误标,其余 23505 原样上抛
- 集成用例:不同 source_url 同旧 uploads 路径 → 后到不覆盖、issue 报告、
只留一行(mediaRegistered=1)
- 单测边界对拍:'<svg' 恰好收在 1024 字节窗口内(起点 1020)检出;起点
1021 被截断为 '<sv' → null
310 测试(308+2);typecheck/lint 三绿。
Co-Authored-By: Claude Code <noreply@anthropic.com>
|
2026-10-21 18:56:16 +08:00 |
|
浅念
|
ed081ec477
|
feat(import): 媒体登记与安全校验
Plan 3 Task 4:media-writer(attachment 行三级对拍 + 内容行引用提取双事件消费)
+ magic-bytes 手写签名表(零新增依赖)。
- 三级对拍(前置事实 7):①uploads 相对路径清单精确命中 ②侧车 source_url→
file_path→清单实体(精确 miss 按文件名候选,多候选歧义不自动选全列 issue)
③missing 只进报告不插行(sha256 NOT NULL 库层防线)
- 魔数校验:命中实体读存储副本头部实际字节——SVG 检出 status=quarantined 不进
产物语义(引用不建 usage);未知签名 unsupported;扩展名声明 MIME 与检测不符
→ issue(按检测登记)
- usage 两阶段时序(WXR 文档序 items 先于 attachment):内容行提取引用 + 修订
锚点(依赖 content-writer 先处理同事件——Task 6 编排顺序契约),finish 统一
对 media_assets 反查(id→source_id / URL→source_url→public_path),顺序无关
- 悬空引用计数 mediaDanglingRefs 不静默(mini 203/204 钉死)
- counts 六键 media 前缀独占(勿复用 'skipped' 的键契约注记)
- 幂等:(site,source_url) 定向 onConflictDoNothing + usage 复合主键——重跑零增行
308 测试(296+6 单测+6 集成);typecheck/lint 三绿。
Co-Authored-By: Claude Code <noreply@anthropic.com>
|
2026-10-21 18:38:10 +08:00 |
|
浅念
|
fe72df3afa
|
chore(import): unsupported/failed 分项计数与键契约 JSDoc;NULL-entry 缝注释;lineage 语义注记
审查 cheap riders 四项:handleUnmappable 分项 unsupportedRecords/
failedRecords(按事件计——拆分只在分派点可知,Task 6 无从重derive,测试
对拍两键);ImportPipelineOutcome.counts 键契约注记(跨写入器扁平全局
命名空间、同名 CLOBBER 不求和、各键归属声明、Task 4 勿复用 'skipped');
六列 NULL-entry 已知死角缝注释(23505 → Task 6 收编);态 1 checksum-diff
的 import_job_id lineage 语义注记(source_records 留建行 job、新 job 记
content_revisions)。296 全绿;typecheck/lint 通过。
Co-Authored-By: Claude Code <noreply@anthropic.com>
|
2026-10-21 18:19:37 +08:00 |
|
浅念
|
2b61431da8
|
feat(import): 内容稳定身份写入
Plan 3 Task 3:content-writer(row→entry/locale/revision/source_record,
checksum skip 幂等三态)。checksum 按前置事实 6 公式精确实现(canonicalJson
六输入域 + sha256;rawLocation 排除、版本三常量入、status 入、sourceUrl 经
route_source_values 入);六列快照行身份 + 五列内容身份(跨快照复用 entry,
permalink 变化产新修订不建新 entry);attachment/unsupported/error 只记
source_records(前置事实 11/12,error 无 postId 以 rawLocation 回退不硬造);
导入全程不触 published 指针(ADR-010)。term-writer JSDoc 补 null-id 建行
不计入 autoCreatedTerms 注脚(Task 2 遗留)。
测试:tests/integration/import-content.test.ts 7 用例(mini 全链对拍/同快照
skip/跨快照稳定身份/内容变化/ permalink 变化/unsupported+error/locale 校验),
296 全绿;typecheck 四段链/lint 通过。
Co-Authored-By: Claude Code <noreply@anthropic.com>
|
2026-10-21 17:09:06 +08:00 |
|
浅念
|
8485c51d59
|
fix(import): term 边缘欠报闭合(null-id 双序等价/同 slug 双 id 报告);handleEvent 分派形状
审查修复:
- null-id wp:term 双序等价:seen 分支同样报缺 term_id issue;自建行 name-only
收编(UPDATE name 为权威名、source_id 不动),term 先行/row 先行终态 name
与 issue 双序一致(测试钉死);真实 id 行不覆盖(first-wins)
- 同 slug 双 term_id:镜像条件显式报告(保留先到、跳过后到 + rawLocation),
文档序 first-wins 策略 JSDoc 钉死(测试含关联绑保留行)
- 冲突重查未命中由 found[0]! 改显式 throw(taxonomy/term 两处,含键上下文)
- adoptTerm catch 注明 ctx.db 直连约定(事务内 25P02 连锁风险——Task 6 包
事务时须重估);收编撞唯一约束路径补测试(自建行原样保留 + issue)
- 重构:内部件抽为 createTermEventHandler({handleEvent, finish}) 可分派形状
(Task 6 单消费方拉流分派、无 tee 的编排意图),createTermWriter 为自消费
整流便捷壳
Co-Authored-By: Claude Code <noreply@anthropic.com>
|
2026-10-21 16:44:25 +08:00 |
|
浅念
|
191c275713
|
feat(import): term 物化与缺失自建
Plan 3 Task 2:createTermWriter 管道写入器——双源物化分类域。
- wp:term 事件:taxonomies(key→object_type 映射 + public_base_path 前置事实 9
常量)+ terms(source_id=term_id 字符串)
- row 的 taxonomyRefs miss 时自建(source_id=auto:<nicename>、slug=nicename;
phase2-smoke 实证真实 WXR 的 wp:term 表缺 category/post_tag 整域);同 nicename
多次引用只建一条(内存 (taxonomy,slug) 索引 + UNIQUE 兜底)
- 单遍流式 + 收编:WXR 文档序 items 先于 wp:term——row 先到自建、wp:term 后到
就地 UPDATE 扶正 source_id/name,两种顺序终态一致(测试钉死顺序无关性)
- content_terms:is_primary 每 (entry, taxonomy) 首个 true 余 false(WP 单主分类
近似);row 无 content entry → term 仍物化、关联跳过 + issue(禁静默)
- ctx 加法扩展 events: AsyncIterable<AdapterEvent>(测试手构注入,Task 6 接真流)
- Task 1 遗留两行:ImportErrorCode 补 REPORT_WRITE_FAILED、ctx.db 事务边界 JSDoc
Co-Authored-By: Claude Code <noreply@anthropic.com>
|
2026-10-21 16:19:00 +08:00 |
|
浅念
|
eb188da5c2
|
fix(import): 复用口径忠实化;管道 Outcome 契约与 succeeded_with_issues;报告写入时序;stale 警告
评审修复(Plan 3 Task 1 复审):
- 复用路径只返回 job 锚定字段(jobId/status/reused/siteId/mapping_version/
report_path),快照/版本块仅在非复用时解析返回——复用结果不再回显编造数据
- ImportPipeline 契约钉死:返回 Promise<ImportPipelineOutcome>
({ counts, issues });服务按"累加器 ⊕ 返回值"合并(counts 同键返回值
覆盖、issues 累加器在前),issues 非空 → succeeded_with_issues;
ctx.report 即累加器(管道抛错时部分产出仍入报告)
- 报告时序:mkdir + tmp 写入 + rename 先于终态行更新——report_path 落库
即文件存在;写失败 → failed(REPORT_WRITE_FAILED),不挂悬空路径
- CLI 复用命中非终态(queued/running)→ 崩溃残留警告(重试需显式换 --key)
- 管道抛 ImportError 保留原 code 入 error_code,summary 冠 [pipeline]
- 确定性 23505 探针:未提交孪生 job 行事务内持唯一键触发真实 PG 唯一
冲突 → 败者复用既有 job
- 报告补 idempotencyKey / attempt 字段
- 计划文档 Task 6 增补 stale 回收决策项(ADR-017)
测试 282 通过(279 + 3:Outcome 合并/ImportError 前缀/23505 探针);
typecheck 四段链 + lint 全绿。
Co-Authored-By: Claude Code <noreply@anthropic.com>
|
2026-10-21 15:56:00 +08:00 |
|
浅念
|
0e8b2b5356
|
feat(import): job 骨架与生命周期
Plan 3 Task 1:sf import 命令骨架 + import_jobs 生命周期(空管道,Task 6 接真实管道)。
- import.service.ts(零装饰器):createImportJob——站点/快照解析(缺省按 (connection,
kind='wxr') 选最新;三快照绑定按前置事实 13 记入报告,job 行不扩列)、幂等建行
(默认 key=site+wxr快照+三语义版本;重复提交复用既有 job 不重跑,并发撞唯一约束
重查收敛)、状态推进 queued→running→succeeded/failed(attempt/started_at/finished_at/
error_code/error_summary)、报告落 artifacts/import/<jobId>/reports/import.json
(全四版本块:adapter/mapping/sanitizer/parser;job 行落 mapping_version)
- 可预期错误带 code:SITE_NOT_FOUND / SNAPSHOT_NOT_FOUND / NO_WXR_SNAPSHOT /
PIPELINE_FAILED——解析期失败零 job 行
- adapter 事件加法式补 postId(前置事实 12):unsupported/error 事件可选携带
String(postId),缺失时键缺席不硬造 source_id;row 事件与报告聚合零影响、不触发版本 bump
- canonicalJson 提取至 apps/api/src/common/canonical.ts 共享导出(前置事实 6),
register 侧改 import 零行为变更(既有清单哈希测试守护)
- sf CLI + import 命令(--site/--snapshot/--key/--connection),输出 job 摘要与版本块
- 测试:tests/integration/import-job.test.ts(5 例:生命周期观察/最新快照解析/幂等复用
与并发收敛/可预期失败零落行/failed 路径)+ adapter postId 3 例 + canonical 单测 6 例
(265→279 全绿);typecheck 四段链/lint 绿;临时库 CLI 冒烟(register→import→复用)通过
Co-Authored-By: Claude Code <noreply@anthropic.com>
|
2026-10-21 15:30:42 +08:00 |
|