浅念
|
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 |
|