Phase 1
MOSS v2 验收标准
MOSS v2 验收标准
状态:已执行,通过
对应实施方案:08-v2-execution-plan.md 本文定义可重复执行的验收条件、证据和退出标准 本次结果:10-v2-acceptance-report.md
一、验收目标
验收需要证明:
- 旧数据无损迁移。
- 多来源身份模型不会覆盖错误对象。
- 导入、Feedback、信号发布和 Audit Event 保持事务一致。
- 信号缓存能在输入变化后自动失效。
- 失败路径保留最后一个稳定状态。
- Today、Knowledge、Governance 和 Calibration 的真实行为符合文档。
- 本地安全边界没有扩大。
二、验收等级
| 等级 | 定义 | 处理 |
|---|---|---|
| Blocker | 数据损失、外键损坏、审计分裂、旧稳定信号丢失、无法构建 | 必须修复并完整重验 |
| Major | 核心页面或规则错误、API 契约破坏、移动端不可用 | 必须修复并重验受影响工作包 |
| Minor | 文案、视觉或非核心边界问题 | 可以记录后修,但必须有责任人与期限 |
最终验收不允许存在 Blocker 或 Major。
三、验收环境
至少覆盖以下环境:
| 环境 | 用途 |
|---|---|
| 空数据库 | 验证全新安装 |
| 旧版数据库副本 | 验证真实迁移 |
| 已迁移数据库 | 验证重复启动和日常使用 |
| 故障注入数据库副本 | 验证事务回滚和稳定状态保留 |
| 桌面浏览器 | 1280px 及以上工作台 |
| 窄桌面或平板 | Inspector 隐藏后的替代路径 |
| 移动浏览器 | 390px 宽度基线 |
验收不得直接在唯一的个人数据库上做破坏性故障测试。
所有日期、缓存和性能证据必须记录操作系统时区。性能比较必须在同一台机器、同一 Node 版本和相同数据副本上完成。
四、证据要求
每个验收项至少保存一种证据:
- 命令输出。
- SQL 查询结果。
- 测试报告。
- 浏览器截图。
- 控制台日志。
- 数据库校验值。
- Git commit SHA。
证据目录建议按以下结构保存:
artifacts/v2-acceptance/
environment/
migration/
identity/
import/
feedback/
signals/
api/
ui/
governance/
recovery/
final/证据中不得包含 auth token、cookie、密钥或不应进入仓库的个人敏感内容。
五、进入验收的条件
- 实施分支工作区干净。
- 所有目标提交已推送或可定位。
- 实施者已完成自测。
- 基线数据库和迁移前数量已记录。
- 备份已通过完整性检查。
- 失败注入仅使用数据库副本。
- README 和运行手册已反映当前能力。
任一条件不满足时,不开始正式验收。
六、构建与静态检查
| ID | 操作 | 预期结果 | 等级 | 证据 |
|---|---|---|---|---|
| BUILD-001 | 安装锁文件指定依赖 | 无未解释的依赖变化 | Blocker | 安装日志 |
| BUILD-002 | 执行 TypeScript/Next 构建 | 零类型错误、零路由冲突 | Blocker | 构建日志 |
| BUILD-003 | 执行全部测试 | 全部通过,无跳过的阻塞测试 | Blocker | 测试报告 |
| BUILD-004 | 检查 Git diff | 无无关文件、数据库、token 或个人密钥 | Blocker | git status 与审查记录 |
| BUILD-005 | 检查文档链接和代码围栏 | 无断链和未闭合围栏 | Minor | 检查日志 |
七、迁移验收
MIG-001:迁移前基线
前置条件
- 使用旧版数据库副本。
- 应用尚未运行新版初始化。
操作
- 记录旧表列表。
- 记录 bookmarks、feedback_events、import_runs 数量。
- 执行 integrity 和 foreign key 检查。
- 保存数据库校验值。
预期结果
- 数据库基线健康。
- 数量与实施记录一致。
等级:Blocker。
MIG-002:一次迁移成功
操作
- 使用新版应用打开旧数据库副本。
- 等待初始化完成。
- 查询新表和索引。
预期结果
content_items、新版feedback_events、signal_runs、signals、audit_events存在。- 旧
bookmarks已在校验完成后删除。 - content_items 数量等于旧 bookmarks 数量。
- Feedback 数量不变。
- import_runs 数量不变。
- foreign key check 无结果。
- integrity check 为通过。
等级:Blocker。
MIG-003:字段映射
抽样检查不少于 20 条,覆盖不同分类、作者和日期。
预期结果
- title、body、url、imported_at 与旧数据一致。
- source 为
x_bookmark。 - source_id 等于旧 X ID。
- domain 为 Knowledge。
- author、category 和 ordinal 正确进入 metadata。
- created_at 是对应原始日期的 ISO 8601 表达。
- tags 是空数组。
等级:Blocker。
MIG-004:Feedback 外键
预期结果
- 每个旧 Feedback 都关联到正确 content item。
- 没有孤儿 Feedback。
- Feedback ID、value 和 created_at 保持不变。
等级:Blocker。
MIG-005:历史审计回填
预期结果
- 每个历史 Import Run 有对应 Import Audit Event。
- 每个历史 Feedback 有对应 Feedback Audit Event。
- ref_type、ref_id 和时间正确。
- 重启后不会再次重复回填。
等级:Major。
MIG-006:重复启动幂等
连续启动新版应用至少三次。
预期结果
- 数据数量不增加。
- Audit Event 不重复回填。
- schema 不重复创建异常索引。
- 应用每次都能正常启动。
等级:Blocker。
MIG-007:非法日期回滚
在旧数据库副本中注入一条不符合 X 日期协议的数据。
预期结果
- 迁移失败并指出 content ID 与原始日期。
- 旧 bookmarks 和旧 Feedback 表仍完整。
- 没有半迁移数据。
- 没有用当前时间伪造 created_at。
等级:Blocker。
MIG-008:迁移中途故障
在复制完成但校验或审计回填前注入失败。
预期结果
- 整个迁移事务回滚。
- 原数据库仍可被旧版本读取。
- 恢复备份后可以重新执行迁移。
等级:Blocker。
MIG-009:schema 版本
预期结果
- 旧版未标记数据库成功迁移后,
PRAGMA user_version等于 2。 - 全新数据库创建后,
user_version同样等于 2。 - 迁移失败时版本号保持原值。
- 人工设置高于 2 的版本后,应用拒绝打开并报告“不支持的数据库版本”,不修改任何表。
等级:Blocker。
八、内容身份验收
| ID | 场景 | 预期结果 | 等级 |
|---|---|---|---|
| ID-001 | 同一 source、同一 source_id 重复导入 | 更新原对象,内部 id 不变,数量不增加 | Blocker |
| ID-002 | 两个 source 使用相同 source_id | 形成两个不同对象,互不覆盖 | Blocker |
| ID-003 | 无原生 ID 的连接器契约单元测试 | scheme/host 大小写、默认端口、fragment、空 path 和 query 顺序等价样本得到相同 url:v1:sha256: ID;业务 query 差异仍得到不同 ID;本期不要求接入第二个真实连接器 |
Major |
| ID-004 | source_id 为空 | 导入被拒绝,不写入半成品记录 | Blocker |
| ID-005 | 新增 X 内容 | 内部 id 是有效 UUID;重复导入同一 X source_id 时不重新生成 | Blocker |
需要保存导入前后 id、source、source_id、title 的对照结果。
九、导入事务验收
IMP-001:正常导入
预期结果
- 内容成功 upsert。
- 新增一个 Import Run。
- 新增一个引用该 Import Run 的 Audit Event。
- 三类写入时间一致或处于同一事务时间点。
IMP-002:重复导入
预期结果
- content_items 数量不增加。
- 可更新内容字段。
- 内部 id 不变化。
- 新增 Import Run 和 Audit Event,用于记录本次处理。
IMP-003:跨来源碰撞
预期结果
- source A 的更新不能修改 source B 的内容。
(source, source_id)唯一约束生效。
IMP-004:审计写入失败
预期结果
- 内容 upsert 和 Import Run 同时回滚。
- API 或 CLI 返回失败。
- 重试不会遇到半成品状态。
IMP-005:JSON 与空 URL
预期结果
- tags 和 metadata 是有效 JSON。
- 缺失 URL 写为 NULL。
- 查询层不会因未定义绑定或 JSON 解析失败而崩溃。
IMP-001 至 IMP-005 均为 Blocker。
十、Feedback 验收
| ID | 操作 | 预期结果 | 等级 |
|---|---|---|---|
| FB-001 | 对存在内容提交合法 Feedback | 返回 { event },事件字段正确 |
Blocker |
| FB-002 | 查询 Feedback 历史 | 新事件可见,最新一条成为当前值 | Major |
| FB-003 | 提交非法 value | 返回 400,不产生 Feedback 或 Audit Event | Blocker |
| FB-004 | 提交不存在 contentId | 返回 404,不产生 Audit Event | Blocker |
| FB-005 | 注入 Audit Event 写入失败 | Feedback 同时回滚,客户端可安全重试 | Blocker |
| FB-006 | 对同一内容连续反馈 | 保留事件历史,画像使用最新值 | Major |
| FB-007 | UI 提交成功 | 当前卡片更新,刷新后数据库结果一致 | Major |
十一、规则引擎验收
SIG-001:首次运行
预期结果
- 创建一个 active Signal Run。
- rule_count 等于启用规则数。
- signal_count 等于关联 Signals 数量。
- 生成对应 Audit Event。
- generation key 包含当前输入与规则版本语义。
SIG-002:缓存命中
在没有 Import、Feedback、日期或规则版本变化时重复访问 Today;同时覆盖“普通批次后重复访问”和“强制刷新成功后再普通访问”两种路径。
预期结果
- 不新增 Signal Run。
- 不新增 Signal Run Audit Event。
- 不重新执行规则评估。
- 返回相同 active signals。
SIG-003:Feedback 自动失效
提交新 Feedback 后访问 Today。
预期结果
- generation key 改变。
- 发布新的 active run。
- 旧 run 变为 superseded。
- 任一时刻只有一个 active run。
SIG-004:Import 自动失效
完成一次导入后访问 Today。
预期结果
- generation key 改变。
- 新信号使用最新内容统计。
SIG-005:规则版本失效
仅提升规则版本,不改变数据。
预期结果
- 新 active run 发布。
- Audit Event 能定位新 run。
SIG-006:强制刷新
调用刷新接口。
预期结果
- nonce 使 generation key 唯一。
- 创建新 active run。
- 不在新批次成功前删除旧信号。
- 刷新后第一次普通访问命中该 active run,不再次创建或评估批次。
SIG-007:规则评估失败
在事务开始前让一条规则抛错。
预期结果
- 不修改当前 active run。
- 不创建不完整 Signal Run。
- Today 仍能读取旧信号。
SIG-008:发布事务失败
在新 run、signals 或 Audit Event 写入阶段注入失败。
预期结果
- 新批次全部回滚。
- 旧 run 恢复或保持 active。
- 不存在两个 active run。
- 不存在无 run 的孤儿 signal。
SIG-009:规则阈值
为每条初始规则准备阈值上下边界数据。
预期结果
- 阈值以下不触发。
- 临界值行为符合技术方案。
- 超过阈值时 domain、urgency、title、body、tags 和 metadata 正确。
SIG-001 至 SIG-009 均为 Blocker。
十二、API 验收
| ID | 接口 | 场景 | 预期结果 | 等级 |
|---|---|---|---|---|
| API-001 | Feedback POST | 合法请求 | 2xx,返回 { event } |
Blocker |
| API-002 | Feedback POST | 非法 JSON | 400,无写入 | Blocker |
| API-003 | Feedback POST | 非法 value | 400,无写入 | Blocker |
| API-004 | Feedback POST | content 不存在 | 404,无写入 | Blocker |
| API-005 | Signals Refresh POST | 正常刷新 | 2xx,返回新 active 信号数量 | Major |
| API-006 | Signals Refresh POST | 发布失败 | 5xx,旧 active 信号保留 | Blocker |
| API-007 | Signals Refresh | 非 POST 方法 | 不执行刷新 | Major |
| API-008 | 所有 API | 远程暴露检查 | 标准启动命令仅监听 loopback;无公网网卡绑定、反向代理或隧道配置 | Blocker |
十三、查询层验收
| ID | 查询 | 预期结果 | 等级 |
|---|---|---|---|
| QUERY-001 | Latest Signals | 只返回 active run 的 signals | Blocker |
| QUERY-002 | Latest Signals 无 active | 返回空数组,不抛错 | Major |
| QUERY-003 | Domain Coverage | 固定返回 6 个域 | Major |
| QUERY-004 | Domain Coverage | item/signal/feedback 数量与 SQL 抽查一致 | Blocker |
| QUERY-005 | Audit Events | 按 created_at、id 稳定倒序并遵守 limit | Major |
| QUERY-006 | Content Flow | 总数、覆盖率、来源分布正确 | Blocker |
| QUERY-007 | Category Breakdown | 只统计 X Bookmark 分类 | Major |
| QUERY-008 | JSON 解析 | tags、metadata 返回结构化值 | Blocker |
十四、路由与共享壳验收
| ID | 操作 | 预期结果 | 等级 |
|---|---|---|---|
| ROUTE-001 | 打开 / |
重定向到 /today |
Major |
| ROUTE-002 | 打开四个目标路由 | 均正常渲染,无 404/500 | Blocker |
| ROUTE-003 | 检查桌面壳 | 只有一套 Sidebar、Topbar、Inspector | Major |
| ROUTE-004 | 切换路由 | 导航高亮与 pathname 一致 | Minor |
| ROUTE-005 | 打开 Calibration | 不出现嵌套 app shell | Major |
| ROUTE-006 | 浏览器前进后退 | 路由与高亮恢复正确 | Major |
| ROUTE-007 | 构建路由检查 | 无重复根 route | Blocker |
十五、Today 验收
| ID | 场景 | 预期结果 | 等级 |
|---|---|---|---|
| TODAY-001 | 正常数据 | Hero 数量与 active signals 一致 | Major |
| TODAY-002 | warn/danger 信号 | 只在 Focus 区显示高优先级信号 | Major |
| TODAY-003 | 全部信号 | Signal Cards 不漏 active signals | Major |
| TODAY-004 | Coverage | 显示 6 个域,空域为 0 | Major |
| TODAY-005 | 空数据 | 提供明确导入说明,无伪造数字 | Major |
| TODAY-006 | 无信号 | 正确空状态,不显示错误 | Major |
| TODAY-007 | 刷新失败 | 保留旧信号并显示失败反馈 | Blocker |
| TODAY-008 | 本地日期 | 日期和每日 generation key 使用本机日期 | Major |
十六、Knowledge 验收
| ID | 场景 | 预期结果 | 等级 |
|---|---|---|---|
| KNOW-001 | 内容统计 | 总内容数与 content_items 一致 | Blocker |
| KNOW-002 | Feedback 覆盖 | 分子为有 Feedback 的唯一内容数 | Major |
| KNOW-003 | 来源分布 | 各来源合计等于总内容数 | Major |
| KNOW-004 | 分类分布 | X 分类数量和标签正确 | Major |
| KNOW-005 | 最近导入 | 与最新 Import Run 一致 | Major |
| KNOW-006 | 未实现模块 | 明确显示待接入,不展示伪造数据 | Major |
| KNOW-007 | 空数据库 | 显示可执行的导入指引 | Major |
十七、Governance 验收
| ID | 场景 | 预期结果 | 等级 |
|---|---|---|---|
| GOV-001 | 审计列表 | 来自真实 audit_events | Blocker |
| GOV-002 | 新导入 | 刷新后出现对应 Import Audit Event | Major |
| GOV-003 | 新 Feedback | 刷新后出现对应 Feedback Audit Event | Major |
| GOV-004 | 新信号批次 | 出现对应 Signal Run Audit Event | Major |
| GOV-005 | 引用 | ref_type/ref_id 能定位业务对象 | Major |
| GOV-006 | UI 操作 | 不提供 Audit Event 更新或删除入口 | Blocker |
| GOV-007 | 策略文案 | 区分已执行约束和待实施设计 | Major |
| GOV-008 | append-only 表述 | 不宣称未被数据库强制的绝对不可变性 | Major |
十八、Calibration 回归验收
| ID | 场景 | 预期结果 | 等级 |
|---|---|---|---|
| CAL-001 | 内容列表 | 基线记录的全部内容均可浏览和筛选;当前样本基线为 996 条 | Blocker |
| CAL-002 | 作者与分类 | metadata 正确映射到 UI | Major |
| CAL-003 | Feedback | 提交、刷新和历史正常 | Blocker |
| CAL-004 | 画像 | 使用最新 Feedback 计算 | Major |
| CAL-005 | 历史 | Feedback 和 Import 历史完整 | Major |
| CAL-006 | X 原帖链接 | URL 正确,使用新标签打开 | Major |
| CAL-007 | 空数据库 | 显示导入指引 | Major |
| CAL-008 | 文案 | 通用位置使用“内容”,X 专属位置保留准确描述 | Minor |
十九、响应式与可访问性验收
19.1 视口
至少检查:
- 1440 × 900。
- 1280 × 800。
- 1024 × 768。
- 768 × 1024。
- 390 × 844。
19.2 标准
| ID | 检查 | 预期结果 | 等级 |
|---|---|---|---|
| UI-001 | 横向溢出 | 所有目标路由均无页面级横向滚动 | Major |
| UI-002 | Inspector 隐藏 | 窄宽度仍有直接打开详情的路径 | Blocker |
| UI-003 | 移动导航 | 可打开、可关闭、可键盘操作 | Major |
| UI-004 | 焦点 | 所有交互元素均有可见 focus 状态;Tab 顺序与视觉和阅读顺序一致 | Major |
| UI-005 | 对比度 | 普通文字至少 4.5:1,大文字和 UI 边界至少 3:1 | Major |
| UI-006 | 主题 | 浅色和深色均可读,无错误闪烁 | Major |
| UI-007 | 键盘 | 核心导航和 Feedback 不依赖鼠标 | Major |
| UI-008 | 控制台 | 无运行时 error | Blocker |
二十、恢复验收
REC-001:恢复迁移前备份
预期结果
- 可恢复旧数据库。
- 旧版本能够读取。
- 校验值或数据数量与基线一致。
REC-002:恢复迁移后备份
预期结果
- 新版可以正常启动。
- active run、Feedback 和 Audit Event 完整。
REC-003:失败副本隔离
预期结果
- 故障注入副本不会覆盖有效备份。
- 失败原因、时间和使用的 commit 可追溯。
REC-001 至 REC-003 均为 Blocker。
二十一、性能基线
Phase 1 不设置高并发目标。计时前预热 3 次,再执行至少 10 次并记录中位数和 p95;迁移测试至少执行 3 个干净副本:
| ID | 场景 | 基线要求 | 等级 |
|---|---|---|---|
| PERF-001 | 当前 996 条内容迁移 | 单次不超过 60 秒,3 次全部成功且无需人工逐条操作 | Major |
| PERF-002 | 缓存命中 Today | 不重复评估规则,不新增 run | Blocker |
| PERF-003 | Calibration 本地首屏 | 热启动 p95 不超过 2 秒,且不高于迁移前同机基线的 125% | Major |
| PERF-004 | Category/Author 查询 | 查询计划使用预期表达式索引;单次热查询 p95 不超过 200ms | Major |
| PERF-005 | 连续 Feedback | 连续提交 20 次,零 SQLITE_BUSY/丢失;本地 API p95 不超过 500ms |
Major |
实际耗时需记录为本次基线,后续版本以此比较。
二十二、最终数据对账
最终验收报告必须包含:
| 指标 | 迁移前 | 迁移后 | 允许差异 |
|---|---|---|---|
| 内容总数 | 记录值 | 记录值 | 0 |
| Feedback Event | 记录值 | 记录值 | 0,验收新增事件需单列 |
| Import Run | 记录值 | 记录值 | 0,验收新增批次需单列 |
| 孤儿 Feedback | 0 | 0 | 0 |
| active Signal Run | 不适用 | 1 或空库时 0 | 符合场景 |
| 孤儿 Signal | 不适用 | 0 | 0 |
| 历史 Audit Event | 预期回填数 | 实际值 | 0 |
验收过程中产生的新 Feedback、Import Run、Signal Run 和 Audit Event 必须单独列出,不能与迁移差异混在一起。
二十三、退出标准
v2 验收通过必须同时满足:
- 所有 Blocker 通过。
- 所有 Major 通过。
- Minor 均有记录、责任人和处理计划。
- 构建与测试通过。
- 迁移和恢复演练通过。
- 数据对账无未解释差异。
- 四个路由通过桌面和移动端验收。
- 控制台无错误。
- 文档、图表和实现一致。
- 验收证据可以由另一台机器复现。
二十四、验收报告模板
基本信息
| 字段 | 内容 |
|---|---|
| 分支 | |
| Commit SHA | |
| 验收日期 | |
| 验收人 | |
| Node/npm 版本 | |
| 操作系统 | |
| 操作系统时区 | |
| 数据库副本标识 |
结果汇总
| 类别 | 通过 | 失败 | 未执行 |
|---|---|---|---|
| 构建 | |||
| 迁移 | |||
| 身份与导入 | |||
| Feedback | |||
| Signals | |||
| API | |||
| UI | |||
| Governance | |||
| Recovery |
问题记录
| ID | 等级 | 描述 | 证据 | 责任人 | 状态 |
|---|---|---|---|---|---|
结论
- 通过。
- 有条件通过。
- 不通过。
“有条件通过”只允许存在 Minor,不允许绕过 Blocker 或 Major。