mirror of
https://github.com/sinanyuntu/trade-message-center.git
synced 2026-09-17 13:22:11 +08:00
9.9 KiB
9.9 KiB
缺失值、默认值与补偿
1. Scope / Trigger
凡是配置、环境变量、协议 payload、构建标识、持久化数据或跨包边界上将缺失值替换为另一个值的代码,都必须应用本规范。value || fallback、value ?? fallback 属于重点;普通布尔逻辑如 enabled || hasPermission 不属于本规则。
2. Signatures / Contracts
必填值在使用边界判空并返回稳定错误,不得生成或选择替代值:
const buildHash = process.env.BUILD_HASH;
if (!buildHash) throw new Error("BUILD_HASH must be provided by the workspace command");
workspace 根命令每次执行生成一次 BUILD_HASH,通过继承环境传给所有 package;package 只能消费:
const buildHash = randomBytes(8).toString("hex");
runPackages({ env: { ...process.env, BUILD_HASH: buildHash } });
只有用户要求、PRD/设计契约、已发布外部协议、现有可执行测试或必须保持的已确认兼容行为,才足以允许补偿。?? 只适用于契约规定 null/undefined 缺失;false、0、空字符串是否缺失必须明定。
3. Contracts
- 必填配置、协议字段和跨包环境变量缺失时必须观察到错误,不得静默改写为随机值、空值或开发值。
BUILD_HASH唯一生成者是 workspace 根命令;下层不得从 mode env 读取、重新生成或覆盖。- 允许默认值时须在代码旁或所属规范写明来源、范围和不掩盖错误的理由,并测试存在/缺失两条路径。
- 候选值优先级无证据时不得使用
a || b || c猜测,应显式报错或补齐契约。 - OneTalk
business_card的客户资料缺失不是消息事实错误:消息持久化必须保留{ version: 1, kind: "business_card" }marker;读取时没有同账号同会话 profile 也返回 marker,不能 fallback 到登录人/发送者contact,profile 单字段缺失才按 view 合同返回null。
4. Validation & Error Matrix
| 发现的代码形态 | 处理 |
|---|---|
| 必填值用 `value | |
根生成 BUILD_HASH 后向下传递 |
保留单一生成点,下层缺失直接报错 |
| 契约明确缺失时默认值 | 允许,记录证据并测试主值、缺失值和有意义 falsey 值 |
0/false/"" 合法却被 ` |
|
| 多候选值无确认优先级 | 不猜测,显式报错或先补契约 |
| 名片读取时没有客户 profile | 保留 marker;不得用消息 item.contact、登录人资料或其他会话资料补偿 |
| 名片 profile 只有部分字段 | view 仅对缺失字段返回 null;不得回写 marker 或消息事实 |
5. Good / Base / Bad Cases
- Good:根命令生成一次
BUILD_HASH,各 package 只读继承值,缺失直接失败。 - Good:必填 database URL、协议版本或设备 binding 缺失时返回稳定错误。
- Base:契约规定空标题显示“未命名会话”,且测试覆盖空/真实标题。
- Base:契约规定仅
undefined表示未配置,重试次数0合法,因此使用??并测试0/缺失。 - Base:名片当前客户资料尚未采集时,读取返回 marker;资料稍后到达由下一次读取以内存投影反映,不修改消息事实。
- Bad:
process.env.BUILD_HASH || randomBytes(8)...或?? randomBytes(...)在下层自行生成 hash。 - Bad:
Number(env.PORT) || 3000或env.PORT ?? 3000没有端口默认值契约。 - Bad:在消息观察阶段等待异步
__conversationListData__,或把登录人item.contact当作客户资料 fallback。
6. Tests Required
- 必填配置覆盖缺失、空值和合法值,缺失断言稳定错误,而不是只断言不抛异常。
- workspace 构建断言根命令只生成一次且所有 package 收到相同 hash;package 单独缺失时失败。
- 允许默认值覆盖真实、缺失及契约中合法的
0/false/""。 - 名片读取覆盖 profile 全缺失、部分字段缺失和完整字段,断言 marker/view/null 形状以及没有登录人资料 fallback。
- 修改前后搜索
||、??、三元默认值和 mode env 读取,确认没有第二个来源。
7. Wrong vs Correct
// Wrong:下层随机,掩盖根层传递错误。
const buildHash = process.env.BUILD_HASH ?? randomBytes(8).toString("hex");
// Correct:根层生成一次,下层只消费并显式失败。
const workspaceBuildHash = randomBytes(8).toString("hex");
runPackages({ env: { ...process.env, BUILD_HASH: workspaceBuildHash } });
const buildHash = process.env.BUILD_HASH;
if (!buildHash) throw new Error("BUILD_HASH must be provided by the workspace command");
// Correct:契约规定未设置时使用默认值,且 0 合法。
const retryLimit = options.retryLimit ?? DEFAULT_RETRY_LIMIT;
Scenario: Workspace 发布版本与扩展清单
1. Scope / Trigger
- Trigger:根 package 版本跨 workspace package metadata、扩展构建/watch 和 release CI 传播,且这些边界不得各自补偿或推导版本。
- Scope:根
package.json:version是唯一可编辑事实源;apps/*/package.json与packages/*/package.json的具体版本是同步镜像;扩展最终只加载生成的dist/manifest.json。
2. Signatures
validatePackageVersion(value: unknown, source?: string): string:验证同时满足 package metadata 和 Chrome Manifest 的三段数字版本。readRootPackageVersion(rootDir?: string): string:只读取并验证 workspace 根package.json。pnpm version:sync:把根版本写入所有apps/*/package.json与packages/*/package.json镜像。pnpm version:check:只检查镜像,不自动修复。pnpm version:ensure:先执行version:sync,再执行version:check;根级 dev/build/typecheck/test/format:check 通过它获得稳定的一致版本环境。TMC_PACKAGE_VERSION:由 workspace 根命令注入给下游扩展命令;扩展直接执行时缺失必须失败。
3. Contracts
- 版本必须是
major.minor.patch三段纯数字;每段在0..65535,无前导零,且不得为0.0.0。 - 禁止 prerelease、build metadata、
v前缀和第四段;root version、package mirrors、generated manifest、release archive/path 使用同一值。 BUILD_HASH仍由根 wrapper 独立生成;版本读取不能从 hash、Git tag 或任何子包 manifest 推导。- Vite entry 不得复制共享
dist的 public assets;扩展 build/dev orchestrator 只初始化一次静态资源,并独占 generated manifest。 - release quality job 输出版本,publish job 只能消费该 output;Git tag 仅负责触发、源码定位和 ancestry 校验。
- server 部署必须等待同版本扩展 ZIP 成功上传 OSS;下载接口只按运行时版本签名,上传失败时不得切换到新服务版本。
- 发布数据库门禁调用
server test:integration,串行执行所有*.integration.test.ts并设置 60 秒硬超时;普通server test排除集成测试,不能代替数据库门禁。
4. Validation & Error Matrix
| 条件 | 行为 |
|---|---|
| 根版本缺失、非字符串或 JSON 无法读取 | 读取命令、质量命令和 CI 在使用前显式失败 |
| 版本不是三段数字、含前导零、额外段、prerelease/build metadata | validatePackageVersion 显式失败,不生成/保留可发布 manifest |
版本段大于 65535 或全为零 |
显式失败,不生成/保留可发布 manifest |
| 子包镜像缺失或与根版本不同 | 单独执行 version:check 显式失败;根级质量命令先通过 version:ensure 同步,再执行检查 |
TMC_PACKAGE_VERSION 缺失或非法 |
直接扩展 build/watch 显式失败;不回退到模板或旧产物 |
| tag 与根版本不同 | CI 仍可按 tag 触发,但发布 archive/path 使用已校验的根版本 |
5. Good / Base / Bad Cases
- Good:修改根
package.json:version后直接运行根级质量命令;命令先执行version:sync,再由version:check和构建验证所有镜像与dist/manifest.json。 - Good:CI 在 checkout tag 后读取 root version,quality output 传给 publish,publish 再校验 zip 内 manifest version。
- Base:
public/icons由扩展 orchestrator 复制一次,Vite watcher 使用copyPublicDir: false。 - Bad:从
GITHUB_REF_NAME、扩展 package manifest 或manifest.template.json作为发布版本来源。 - Bad:四个 watcher 各自 public-copy,或版本缺失时继续使用旧
dist/manifest.json。
6. Tests Required
- 版本 reader/validator:覆盖合法交集、缺失、非字符串、格式、范围和全零失败,并断言稳定错误信息。
- 镜像同步:临时 workspace 中验证漂移失败、
version:sync修复、再次检查通过。 - 根脚本顺序:断言
version:ensure的顺序是 sync → check,且所有根级质量命令统一调用它。 - 构建边界:验证 root wrapper 同时传递一次
BUILD_HASH与TMC_PACKAGE_VERSION,Vite 禁止 public copy,orchestrator 复制真实 icons 并生成 root-version manifest。 - 发布契约:读取真实 release workflow,验证 tag trigger、quality output、SHA artifact、版本 archive/OSS path 和 zip manifest version check。
- 产物审计:构建后断言 manifest、icons、入口文件存在且 manifest version 等于 root version;watch smoke 可在缺少外部 URL 时明确跳过。
7. Wrong vs Correct
# Wrong:发布版本由 tag 或子包值决定。
release_version="${GITHUB_REF_NAME}"
# Correct:CI 只消费 quality job 已校验的根版本 output。
PACKAGE_VERSION="${{ needs.quality.outputs.extension_version }}"
// Wrong:下层缺失时偷偷使用旧版本或本地 package 值。
const version = process.env.TMC_PACKAGE_VERSION || "0.1.0";
// Correct:必填版本缺失或非法时显式失败。
const version = validatePackageVersion(process.env.TMC_PACKAGE_VERSION, "TMC_PACKAGE_VERSION");