RxJS 7 到 RxJS Next 迁移收尾审查清单(Migration Closeout Checklist)完整指南
【免费下载链接】rxjsA reactive programming library for JavaScript项目地址: https://gitcode.com/gh_mirrors/rx/rxjs
迁移从“代码改完、测试变绿”到“可以宣告完成”,中间隔着一次系统性的收尾审查。本文以 RxJS 仓库中.agents/skills/rxjs-next-migration技能套件的收尾清单(review-checklist.md)为核心骨架,结合 SKILL.md 定义的八阶段工作流、@rxjs/migrate包源码与 migration-report.md 报告模板,逐条讲解迁移收尾时必须验证的五个维度:权限与来源(Authority and provenance)、基线与覆盖(Baseline and coverage)、目标契约(Target contract)、机械批次(Mechanical batches)、验证与交接(Verification and handoff)。读完本文,你将掌握一套可执行的收尾审查协议——知道在什么条件下迁移才算真正完成,什么情况下必须挂起(blocker),以及如何产出既通过模式校验、又通过就绪评估的迁移契约。
适用前提:本清单面向使用 Agent 主导工作流、以
@rxjs/migrate确定性引擎执行有界改写(bounded rewrite)的 RxJS 7 → RxJS Next 迁移项目。清单中引用的命令、版本与 schema 均以当前仓库实际安装的包为准。
收尾审查在迁移流程中的位置
在审查清单之前,先明确它属于整个工作流的哪一环。技能套件将迁移划分为八个阶段,且要求按顺序推进、随时可回退重入:
- Stage 1建立权限与范围(authority and scope)
- Stage 2评估用法、生命周期风险与覆盖(assessment)
- Stage 3建立绿色 RxJS 7 基线(green baseline)
- Stage 4分类并批准目标契约(target contract)
- Stage 5规划并试运行有界引擎变更(dry-run)
- Stage 6应用一个小迁移批次(write batch)
- Stage 7构建、测试、诊断与修复(verify & repair)
- Stage 8收尾与交接(close out and hand off)
收尾清单正是Stage 8 的强制入口——SKILL.md 明确要求:更新契约清单与报告后,必须逐项审查 review-checklist.md,并如实报告“行为与生命周期契约改了什么、源码与测试改了什么、跑过哪些门禁及结果、修复的迁移缺陷与遗留的产品缺口、已批准的偏差与环境限制、剩余阻塞项及其负责人与验收状态”。只有在就绪评估返回ready(或开发者明确选择的ready-with-accepted-blockers)时才允许宣告完成,否则只能作为未完成迁移移交,并给出下一步具体决策或动作。
核心立场贯穿始终:这是一项经过评审的项目工作,不是一次 codemod 运行。一个被转换的文件、一份干净的 diff、一个通过的测试,都不足以证明迁移完成。
一、权限与来源(Authority and Provenance)
这一小节回答“我们凭什么改、改的是什么版本、工具链是否自洽”。清单要求四个可核验事实:
1.1 仓库指令、范围与策略在动手前就已记录
- 仓库级指令(repository instructions)、允许写入的范围、包管理器(package manager)与网络策略(network policy)必须在任何大规模变更前记录在案;
- 既有工作(existing work)必须受保护,每个被修改的文件都必须落在授权的迁移边界(migration boundary)之内;
- 变更涉及读取、写入、依赖与命令范围时,需在动手前明确声明。
对应到流程,SKILL.md 的 Stage 1 要求:定位仓库指令、包与 workspace 元数据、lockfile、CI 配置、RxJS 版本、构建/测试命令与当前工作树状态;当目标仓库或允许范围不清晰、既有改动与迁移重叠、或需要破坏性/联网/外部/更广权限的动作时,必须暂停征求开发者意见。
1.2 版本与指纹完全可复现
清单要求以下身份信息精确且可复现:
- 源仓库(source repository)与修订版本(revision);
- RxJS 版本(来源版本 RxJS 7 与目标版本 RxJS Next);
- 引擎版本(engine version)与注册表版本(registry version);
- 规范 Skill 摘要(canonical Skill digest)。
报告模板在 migration-report.md 中为“工具与依赖身份”专门设计了一张表格,逐项填写:Source RxJS、Target RxJS Next、@rxjs/migrateengine、Capability registry、Canonical Skill、Contract schema 的版本或摘要及证据位置。这些字段在 Stage 8 收尾时不允许留空。
1.3 已安装 Skill 与已安装包必须一致
“已安装的 Skill 内容必须与已安装的@rxjs/migrate包匹配”。如果发现不匹配,流程要求停止并先同步,之后才允许信任这些指令。这一条防止用“记忆中的能力表”代替“安装版注册表”进行判断——后文“机械批次”一节还会反复强调:能力判定必须来自安装的版本化注册表,而不是从 Skill 或记忆中重建。
二、基线与覆盖(Baseline and Coverage)
没有基线就没有迁移。这一小节确保:迁移开始前的 RxJS 7 是绿的,任何失败都被显式记录,且每条生命周期敏感路径都有明确的覆盖处置。
2.1 未变更源码上的门禁全部通过
清单要求:约定的构建、类型、lint、测试与行为门禁(build, type, lint, test, behavior gates)必须在未修改的 RxJS 7 源码上运行。对应 SKILL.md 的 Stage 3:记录精确命令、环境事实、退出码与简明结果;起始门禁失败时暂停,由开发者决定“先修复”“缩小范围”还是“记录为已接受的既有失败”,严禁静默改判为迁移回归或忽略。
2.2 每个基线失败都有明确归属
每个基线失败要么被修复,要么被显式记录为“既有失败”并获得开发者接受(developer acceptance)。不允许“本地能过”这种没有命令与环境支撑的口头结论——verification-and-closeout.md 规定:未记录命令和环境的 “Passed locally” 不构成验证记录。
2.3 生命周期敏感路径的覆盖处置
每条生命周期敏感路径必须关联以下四者之一:
- 既有测试覆盖(existing coverage)——有命名测试证明相关行为;
- 特征化测试(characterization)——迁移前新增的聚焦 RxJS 7 测试;
- 显式不支持(explicit unsupported status)——没有可接受的 Next 表面能保留该声明,保留证据并记录为产品缺口;
- 开发者接受的未覆盖风险(accepted uncovered risk)——记录批准人、时间、理由与影响。
assessment-and-contract.md 给出了覆盖处置的完整定义,并建议对重复订阅、副作用、共享、迟到订阅者、取消、teardown、时序、错误或公共 API 行为在现有测试无法证明时优先补充特征化测试。缺覆盖不等于行为安全——“Missing coverage is not evidence that behavior is safe”。
2.4 特征化测试必须在依赖迁移前于 RxJS 7 上通过
“特征化测试必须在依赖/源码迁移之前于 RxJS 7 上通过。”特征化测试的要点(见 assessment-and-contract.md 的 Characterization protocol 一节):新增能证明外部可观测声明的最窄测试,优先断言值、完成/错误、生产者启动次数、并发与迟到观察、取消归属、abort 原因、teardown 顺序、虚拟或宿主时序与可见副作用;避免锁定无关的 RxJS 7 内部实现。迁移依赖后才补的特征化测试不构成 RxJS 7 基线,除非能针对固定源码环境单独演示。
三、目标契约(Target Contract)
目标契约把“把代码改成什么”落成可审查、可批准的决策记录。这是整份清单中最强调“意图必须显式”的部分。
3.1 每个单元必须有完整档案
清单要求每个迁移单元(migration unit)都具备:
- 稳定的源码位置(stable source locations);
- 行为声明(behavioral claim);
- 一个目标生命周期(one target lifecycle);
- 一个证据分类(evidence classification);
- 支撑证据(supporting evidence)。
对应 SKILL.md 的工作记录要求:为每个单元保留源码位置,并记录其当前 RxJS 7 行为声明、开发者选择的目标生命周期、证据分类与支撑测试、批准状态/诊断/任何有意偏差、验证结果或具名阻塞项。报告模板的 “Target contract units” 表则要求逐行填写:Unit ID、Source locations、RxJS 7 claim、Target lifecycle、Evidence classification、Approval、Evidence。
3.2 没有单元可停留在未决状态
“没有必需单元保持未解决(unresolved)或待批准(pending approval)。”引擎可以识别风险,但不能替开发者选择生命周期意图——unresolved是停止状态。当平台共享行为(platform-shared)与每次直接订阅各起生产者(producer-per-direct-subscription)两种解释都成立,或 Subject 语义、取消、调度器顺序、错误行为、互操作或公共行为变化未被证明时,必须暂停征求开发者。
3.3 生命周期选择必须基于意图而非语法推断
“平台共享与每次直接订阅各起生产者的行为是有意选择的,而非从语法推断的。”SKILL.md 将其列为不可谈判规则:绝不根据语法、文件名、运算符名称或当前通过的输出来推断平台共享 vs. 每次订阅独立生产者的行为。可接受的生命周期取值以安装版契约清单 schema 为准,包括:活跃平台生产者共享并在存在观察者时引用计数、通过显式 Next API 按直接订阅创建生产者工作、有意的热 Subject 行为、无生产者生命周期、所需行为不支持、意图仍未解决。同时禁止用笼统的 “hot/cold” 标签描述平台 Observable——正确的行为描述是:首个观察者启动活跃生产者,并发观察者加入,最后离开的观察者触发 teardown,后续观察者可以启动新的一轮。
3.4 需重点审查的行为维度
清单点名要求逐项审查(如适用):Subjects、重复订阅、取消(cancellation)、teardown、时序(timing)、错误(errors)与输入转换(input conversion)。这些维度与 verification-and-closeout.md 中生命周期敏感代码的验证清单一一对应:生产者激活次数与重启、并发与迟到观察、单独与最终取消、abort 原因与上游关闭、Subject 当前值/重放/终态行为、teardown 顺序、时间与调度顺序、错误投递与迟到/未处理错误行为、输入转换接受或显式拒绝。
3.5 有意偏差必须完整记录
每个有意偏差(intentional divergence)必须记录:旧声明与新声明、用户影响(user impact)、证据、批准人(approver)、时间戳与理由(rationale)。且偏差的批准有先后顺序——先做结构校验(schema validation),再跑就绪评估(readiness assessment),两者是独立检查,不能互相替代(清单“验证与交接”一节再次强调)。含未决意图或待批准单元的批次不得继续推进。
四、机械批次(Mechanical Batches)
这一小节约束引擎改写过程本身:能力判定、dry-run、写入与幂等性。
4.1 能力判定来自安装版注册表
“能力决策来自已安装的版本化注册表(installed versioned registry);不使用复制的运算符清单或仅名称匹配。”engine-and-batches.md 要求:从项目安装的包读取引擎数据(公开 API 导出默认能力注册表、注册表与清单 schema、迁移函数、契约就绪评估、引擎/schema 版本),而不是从提示词、Skill 或 harness 适配器里复制清单。选择转换前必须核对:注册表 schema/版本与引擎版本匹配安装包、源导入绑定确为引擎识别的绑定且未被遮蔽或复用、调用形态/元数/调度器与结果选择器形态/管道上下文满足全部声明的前置条件、fixture 证据覆盖目标映射与证据类别、迁移单元已有批准的生命周期契约。名称相似、TypeScript 签名兼容或转换后测试变绿,都不足以替代上述检查。
仓库中的公开 API 在 packages/migrate/src/index.ts 可直接印证:它导出defaultCapabilityRegistry、defaultTestSchedulerCapabilities、capabilityMappingSchema、capabilityRegistrySchema、migrationContractManifestSchema、assessMigrationContractReadiness、parseCapabilityRegistry、parseMigrationContractManifest、migrateTestSchedulerSemantics、migrateTestSource以及capabilityRegistryVersion、migrationContractSchemaVersion、migrationEngineVersion等版本常量。本地检查可以用类似 engine-and-batches.md 给出的形态遍历注册表并校验清单:
import { assessMigrationContractReadiness, defaultCapabilityRegistry, migrationContractManifestSchema } from '@rxjs/migrate'; for (const capability of defaultCapabilityRegistry.capabilities) { // Review id, legacy/source name, target Symbol, adapter, arity, // preconditions, status, and fixture evidence for this exact package. } const parsed = migrationContractManifestSchema.safeParse(manifest); if (parsed.success) { const readiness = assessMigrationContractReadiness(parsed.data, { expectedSkillDigest, }); }expectedSkillDigest从已安装适配器的完整性检查或 Node-only 的@rxjs/migrate/skillAPI 获取,精确签名以安装的 TypeScript 声明为准。
4.2 每个引擎操作先 dry-run
“每个引擎操作先以精确来源信息 dry-run,必要时使用显式的生命周期模式。”CLI 的 dry-run 形态(来自 engine-and-batches.md):
rxjs-migrate \ --source-root <authorized-root> \ --source-repo <source-repository> \ --source-sha <exact-revision> \ --mode <approved-cold-or-platform-mode> \ --framework preserve \ <selected-files>要点:选中源码不需要生命周期选择时省略--mode,绝不让目录名或包装器隐式选择它;框架适配器只在开发者单独批准框架变更时使用。不带--write时,CLI 返回版本化 JSON 报告且不执行任何写入,需记录其引擎版本、注册表版本、操作、文件结果、有序诊断与退出状态——当前 CLI 契约区分完成、结构化拒绝、无效参数与运行失败四种结果。
4.3 dry-run 范围、诊断与变更路径必须在写入前审查
“写入前审查 dry-run 范围、诊断与变更路径。”所有诊断都要审阅,包括源码跨度(source span)、严重性(severity)、处置(disposition)、拒绝范围(refusal scope)、分类(classification)、下一步动作(next action)与能力 ID(capability ID)。被拒绝的批次必须保持源与目标均不变。
4.4 被拒绝或不支持的源码必须保持可见
“被拒绝或不支持的源码保持可见,不得通过部分转换偷运(smuggled through)。”engine-and-batches.md 的拒绝与人工修复一节给出四条出路:收窄批次到可独立安全的单元;补特征化测试、获得开发者决策并在引擎声称输出之外做受审语义编辑;报告 RxJS Next 产品缺口;保留源码并接受具名阻塞项。禁止通过绕开诊断把被拒语法伪装成机械输出。人工工作同样受基线、生命周期、审查与验证门禁约束,且不得被描述为 fixture 证明的引擎输出。
4.5 写入受控且不覆盖本地内容
写入阶段的命令形态(同样来自 engine-and-batches.md):
rxjs-migrate \ --source-root <authorized-root> \ --source-repo <source-repository> \ --source-sha <exact-revision> \ --mode <approved-cold-or-platform-mode> \ --framework preserve \ --write --out-dir <authorized-destination> \ <selected-files>引擎在写入前规划整个批次,并拒绝词法、规范或符号链接路径逃逸(lexical, canonical, or symlink path escape);不得用手工批量写入绕过包含(containment)与不覆盖(no-overwrite)行为。若受审目标就是当前源码树,必须显式声明该范围与覆盖决策并保持可恢复性。写入报告与 dry-run 报告在契约要求处逐字节比对;随后不带写入地重跑同一转换,第二次结果必须不变且诊断稳定——任何输出或诊断漂移都视为引擎缺陷,停止批次并保留复现。
4.6 输出必须保留项目自有代码与测试
“输出保留项目自有源码、直接测试、断言与所选框架。”对应 SKILL.md Stage 6 的要求:通过项目常规工具格式化;确保项目自有源码与直接测试声明保留,不在结果中遗留动态生成器、隐藏用例注册表或兼容断言层;立即检查解析、最窄类型边界与引擎幂等性,不满足则恢复该批次到受审起点并上报引擎缺陷。
测试迁移的细节规则见 test-migration.md:默认保留外层框架(describe/it/test、钩子、断言库、spies 与配置),框架变更视为独立适配器;TestScheduler.run(...)包装器替换为一次直接rxTest调用并返回/等待其Promise<void>;cold()表示每次订阅各起生产者的证据,hot()表示类 Subject 的绝对时间线,observable()表示共享引用计数的平台生产者,expectObservable()保留订阅弹珠带来的取消,flush()是异步的必须 await。调度器参数仅在安装版目标能力与 fixture 能证明宿主时序映射、且rxTest可虚拟化时才移除。
4.7 每个已应用的转换必须可解析、可在窄边界类型检查、幂等且诊断稳定
这是对“应用过”本身的验收标准:可解析(parseable)、在其最窄边界可类型检查(type-checkable at its narrow boundary)、幂等(idempotent)、诊断稳定(stable diagnostics)。清单原句:“Every applied transform is parseable, type-checkable at its narrow boundary, and idempotent with stable diagnostics.”
五、验证与交接(Verification and Handoff)
收尾清单的最后一节,回答“凭什么说做完了、交给谁、缺口怎么带”。
5.1 聚焦测试与全部约定门禁用精确命令运行
“聚焦特征化/迁移测试与所有约定项目门禁都以精确命令、环境、退出码与结果运行。”verification-and-closeout.md 给出验证阶梯(由窄到宽,保证失败可诊断):
- 解析并格式化变更文件;
- 运行聚焦类型检查;
- 运行特征化与直接迁移的测试;
- 运行受影响包或 workspace 的构建、类型、lint 与测试门禁;
- 运行约定的集成、浏览器、native/polyfill 或仓库级门禁;
- 重跑诊断期间环境发生变化的任何命令。
每次都要记录精确命令、相关环境事实、退出码、状态与简明摘要。
5.2 失败分类不得为了“绿色报告”而改标签
失败必须分类为:迁移缺陷(migration defects)、产品缺口(product gaps)、有意偏差(intentional divergences)、基线/环境问题(baseline/environment issues)或未解决(unresolved)——不得为了一份全绿的报告而重新贴标签。四类失败的标准应对(见 verification-and-closeout.md 的失败分类表):
| 分类 | 含义 | 必需响应 |
|---|---|---|
| 迁移缺陷 | 编辑破坏了语法、类型、测试意图、映射或所选契约 | 小批次修复并重跑受影响门禁 |
| RxJS Next 产品缺口 | 已接受的目标表面无法满足保留的证据 | 保留证据可见,报告产品缺口 |
| 有意偏差 | 已批准的 Next 行为不同于 RxJS 7 声明 | 先记录新旧声明、影响、证据与批准,再改期望 |
| 基线/环境 | 失败在迁移前就存在,或所需运行时/工具不可用 | 保留其原始状态,记录限制或已接受失败 |
| 未知 | 证据尚无法定位原因 | 调查或暂停,绝不图方便改标签 |
允许的修复是:澄清或修正迁移代码、加强特征化、或修复已证明的迁移缺陷且不破坏已批准契约。以下动作必须暂停征求开发者:删除/跳过/隔离/弱化测试;改变公共行为声明;添加本地运算符、调度器、兼容门面或断言垫片;改变平台行为以模仿 RxJS 7;超出受审范围的广泛依赖或配置变更;接受红色或未运行的必需门禁。
5.3 任何测试不得在无批准下被弱化
“没有测试在未经明确开发者批准与记录契约变更的情况下被弱化、跳过、删除或替换。”这直接呼应 SKILL.md 的不可谈判规则:不得仅为让迁移后的套件变绿而弱化、跳过、删除或替换行为期望。
5.4 结构校验与就绪评估必须同时运行
“schema 校验与就绪评估都运行;一个不能替代另一个。”结构校验只回答“形状是否正确”,就绪评估则要检出:未解决的生命周期单元、待批准事项、未解决或被拒的诊断、未批准的偏差、缺失或红色的门禁、身份不匹配与未接受的阻塞项(见 verification-and-closeout.md 的 Manifest closeout 一节)。清单(manifest)必须依据安装包导出的确切 schema 构建,至少记录:该版本要求的 schema 与引擎身份、能力注册表版本、规范 Skill 摘要、精确的源/目标 RxJS 版本、基线检查、迁移单元、诊断、有意偏差、验证结果与阻塞项。对应源码在 packages/migrate/src/index.ts 中可见:migrationContractManifestSchema、assessMigrationContractReadiness、parseMigrationContractManifest均作为公开 API 导出。
5.5 所有诊断必须已解决、有负责人或由显式接受的阻塞项代表
“所有诊断已解决、带有负责人,或由显式接受的阻塞项代表。”一个被接受的阻塞项必须具名列出:负责人(owner)与理由(reason)、受影响单元(affected units)、支撑证据(evidence)、其阻止的行为/环境/发布声明(prevented outcome)、显式开发者接受(acceptance)。报告模板的 “Accepted blockers” 表即为这五列设计。不得用阻塞项掩盖无法解释的回归。
5.6 最终报告只陈述测得结果与局限
“最终报告陈述测得结果与局限,不声称通用自动迁移。”verification-and-closeout.md 的最终交接要求用报告资产(即 migration-report.md 模板)汇总:范围与来源;引擎/注册表/Skill/源 RxJS/目标 RxJS 身份;RxJS 7 基线与特征化证据;生命周期决策与批准;按连贯批次划分的源码与测试变更;精确的最终命令与结果;诊断及其解决或携带方式;修复的迁移缺陷;遗留的产品缺口、偏差与环境限制;阻塞项归属与下一步动作。
禁止报告 “automatic migration succeeded”。只能陈述测得项目结果及其局限。这也是收尾清单整份文件想要防住的最后一件事:用“一次通过”粉饰迁移,而不是用“我测量了什么、我限制了什么、谁在为什么负责”来诚实交接。
附:收尾审查速查表
| 维度 | 核心问题 | 判定为通过的最低标准 |
|---|---|---|
| 权限与来源 | 谁授权改、改到哪、版本可复现吗 | 范围/包管理器/网络策略已记录;变更均在授权边界内;源修订、RxJS 版本、引擎/注册表版本、Skill 摘要精确可复现;Skill 与安装包匹配 |
| 基线与覆盖 | 迁移前是绿的吗、风险都有人管吗 | 未改动 RxJS 7 上约定门禁通过或既有失败被接受;特征化测试在迁移前于 RxJS 7 上通过;每条生命周期敏感路径都有覆盖/特征化/不支持/接受风险的处置 |
| 目标契约 | 每个单元要变成什么、谁批准的 | 每单元有位置/声明/生命周期/证据分类/证据;无未决或待批准单元;生命周期为有意选择;偏差记录新旧声明、影响、证据、批准人、时间与理由 |
| 机械批次 | 引擎用得对吗、写入受控吗 | 能力来自安装版注册表;dry-run 先于写入且诊断被审查;拒绝源码保持可见;写入在批准目标内且不覆盖;重跑幂等且诊断稳定 |
| 验证与交接 | 测过什么、缺口怎么带走 | 聚焦测试与全部门禁以精确命令运行;失败按五类如实分类;无测试被无批准弱化;schema 校验与就绪评估都运行;诊断已解决/有主/被接受阻塞项代表;报告只陈述测得结果与局限 |
按此清单逐项核对后,就绪评估返回ready或ready-with-accepted-blockers才可宣告完成,否则连同“下一步具体决策或动作”一起移交给开发者——这正是 RxJS 7 → RxJS Next 迁移收尾该有的样子。
【免费下载链接】rxjsA reactive programming library for JavaScript项目地址: https://gitcode.com/gh_mirrors/rx/rxjs
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考