Phase 1

MOSS v2 本地工作台运行手册

MOSS v2 本地工作台运行手册

状态:当前可运行实现 更新:2026-07-24 适用范围:本地内容导入、旧库迁移、Calibration、Feedback、Today 信号、Knowledge、Governance、备份与恢复

本文描述仓库中已经交付的能力。长期规划不等于当前代码能力。

1. 运行链路与边界

data/phase-1a-input/*.md
  → npm run import:content
  → content_items + import_runs + audit_events
  → Calibration + Feedback
  → signal_runs + signals
  → Today / Knowledge / Governance

当前应用不会读取浏览器登录态、请求 X、调用云端模型、创建定时任务或执行外部写操作。RSS、统一搜索、语义关系和其他业务域仍明确标记为待接入。

标准启动命令绑定 127.0.0.1。当前 API 没有认证、用户隔离或公网防护,不得改为 0.0.0.0,也不要通过反向代理或隧道公开。

2. 运行前提

  • Node.js 20 LTS 或更高;本次验收使用 Node.js v24.14.0
  • npm 与 Git。
  • 可选 SQLite CLI,用于人工检查、备份和恢复。
  • 原生依赖 better-sqlite3 的 ABI 必须与当前 Node 版本一致;切换 Node 大版本后若出现 NODE_MODULE_VERSION 错误,应在该 Node 版本下重新安装或 rebuild 依赖。

所有命令从仓库根目录执行。默认路径:

data/phase-1a-input/  Markdown 输入
data/moss.sqlite      SQLite 数据库

测试副本可通过环境变量隔离:

MOSS_DATABASE_PATH=/absolute/path/to/moss-copy.sqlite npm run dev

3. 从零启动

git clone <repository-url> moss
cd moss
npm ci
npm test
npm run import:content
npm run dev

打开 http://127.0.0.1:3000。根路由会重定向到 /today

若 3000 端口被占用:

npm run dev -- --port 3001

生产验证:

npm run build
npm run start

不要在开发服务器使用同一 .next/ 目录时并行执行生产构建。

4. 导入协议

通用入口:

npm run import:content

兼容入口:

npm run import:bookmarks

两者执行同一逻辑。解析器扫描 data/phase-1a-input/ 中匹配 NN-*.md 的文件,README.md 不导入。当前受控样本是 996 条内容;测试会验证样本总量和日期协议。

每条 X Bookmark 格式:

# 分类名称

## 1. 标题

- 作者:[显示名 (@handle)](https://x.com/handle)
- 时间:Wed Jul 22 12:57:33 +0000 2026
- 原帖:[在 X 上打开](https://x.com/handle/status/1234567890)
- ID:`1234567890`

正文。

---

日期解析会验证格式、真实日历日期、时间、星期和时区偏移。非法值会报告内容 ID 与原始日期,并阻止整次导入或迁移;不会使用当前时间代替。

导入语义:

  • source = x_bookmark
  • X ID 写入 source_id
  • 新内容 id 使用 UUID。
  • (source, source_id) 唯一;重复导入更新原对象但不改变内部 ID。
  • URL 缺失时写入 SQL NULL
  • 内容 upsert、Import Run 和 Audit Event 在同一事务中提交。
  • 导入不会删除数据库中已存在、但输入文件已移除的内容。

5. schema v2

PRAGMA user_version = 2。主要表:

作用
content_items 通用内容;内部 ID 与来源身份分离,tags/metadata 为 JSON。
feedback_events 追加式 Feedback 事件,外键指向 content_items.id
import_runs 每次导入批次。
signal_runs 信号生成版本、输入版本与 active/superseded 状态。
signals 某个 Signal Run 生成的可追溯信号。
audit_events Import、Feedback、Signal Run 的应用级审计事件。

SQLite 启用 WAL、foreign keys 和 5 秒 busy timeout。audit_events 没有 UI 更新或删除入口,但这只是应用约束,不是数据库层绝对不可变。

检查数据库

sqlite3 data/moss.sqlite "PRAGMA user_version;"
sqlite3 data/moss.sqlite "PRAGMA integrity_check;"
sqlite3 data/moss.sqlite "PRAGMA foreign_key_check;"
sqlite3 data/moss.sqlite "SELECT source, COUNT(*) FROM content_items GROUP BY source;"
sqlite3 data/moss.sqlite "SELECT status, COUNT(*) FROM signal_runs GROUP BY status;"

预期 schema 版本为 2、完整性为 ok、外键检查无输出、active Signal Run 最多一条。

6. 旧数据库迁移

应用打开未标记版本且存在 bookmarks 表的旧库时,会自动执行一次事务化迁移:

  1. 创建 v2 目标表。
  2. 严格解析全部旧 X 日期。
  3. 保留旧内容内部 ID,并把旧 X ID 同时写入 source_id
  4. 把作者、分类和 ordinal 写入 metadata。
  5. 重建 Feedback 外键,保留事件 ID、value 和时间。
  6. 校验内容数、Feedback 数和孤儿外键。
  7. 回填 Import 与 Feedback Audit Event。
  8. 校验成功后删除 bookmarks,最后写入 schema 版本 2。

任何一步失败都会回滚,旧表和版本保持不变。高于版本 2 的数据库会被拒绝打开,不做猜测式降级。

迁移必须先在副本上演练:

sqlite3 data/moss.sqlite ".backup 'backups/moss-before-v2.sqlite'"
sqlite3 backups/moss-before-v2.sqlite "PRAGMA integrity_check;"
cp backups/moss-before-v2.sqlite backups/moss-migration-drill.sqlite
MOSS_DATABASE_PATH="$PWD/backups/moss-migration-drill.sqlite" npm run dev

如果备份本身是旧 schema,最后一条命令会在演练副本上触发迁移。不要在唯一数据副本上做故障注入。

7. 页面行为

路由 真实能力
/today 读取或生成 active Signal Run;Focus 仅显示 warn/danger;显示全部信号与固定六域覆盖。
/knowledge 显示内容总数、Feedback 覆盖率、来源、最近导入和 X 分类分布;未实现模块明确标注。
/governance 展示本地策略与真实 Audit Event,不提供审计修改或删除。
/calibration 浏览、筛选内容,提交 Feedback,查看画像和历史,并打开 X 原帖。

桌面使用 Sidebar、主内容、Inspector 三栏;中等宽度用 Sheet 打开 Inspector;移动端使用单列、可打开/关闭的主导航 Sheet 和上下文 Sheet。四个路由共享一套外壳。

主题选择保存在浏览器本地偏好中。浅色和深色都使用同一组设计 token。

8. Feedback API

POST /api/feedback
Content-Type: application/json

{
  "contentId": "<MOSS internal id>",
  "value": "worth_following"
}

允许值:

worth_following | deep_dive | read_later | not_interested | duplicate_or_known
  • 合法请求返回 200{ "event": ... }
  • 非法 JSON、字段或 value 返回 400
  • 内容不存在返回 404
  • Feedback 与 Audit Event 同事务写入;审计失败时两者都回滚。
  • 对同一内容可连续反馈,历史全部保留,页面和画像使用最新事件作为当前值。

9. Today 规则与刷新

五条规则:

Rule 条件
uncalibrated-categories X 分类总数大于 20 且 Feedback 覆盖低于 10%。
stale-import 最近导入超过 7 天为 warn,超过 30 天为 danger。
feedback-coverage 全部内容的唯一 Feedback 覆盖低于 10%。
author-review X 作者至少 5 条内容且没有正向 Feedback。
category-skew 单个 X 分类占 X 来源内容超过 30%。

普通访问按“本机日期 + 最新 Import Run ID + 最新 Feedback ID + 规则版本”命中缓存。Import、Feedback、日期或规则版本变化会自动失效。

强制刷新:

POST /api/signals/refresh

成功返回 { "signalCount": number }。新候选在事务外计算,发布采用 append-and-publish;规则或发布失败时旧 active run 继续可读。规则逻辑修改时必须提升 signalRuleVersion

10. 备份与恢复

数据库、Feedback、信号和审计都属于敏感个人数据。备份不进入 Git,不提供公网 URL,权限只授予本机用户。

运行中一致性备份

umask 077
mkdir -p backups
sqlite3 data/moss.sqlite ".backup 'backups/moss-backup.sqlite'"
sqlite3 backups/moss-backup.sqlite "PRAGMA integrity_check;"
sqlite3 backups/moss-backup.sqlite "PRAGMA foreign_key_check;"

WAL 模式下不要只复制 moss.sqlite 主文件;可能遗漏 WAL 中已提交数据。应用停止后可复制主文件及同名 -wal-shm,但 .backup 更适合可重复操作。

恢复演练

不要覆盖当前库。先把快照恢复到隔离路径:

cp backups/moss-backup.sqlite backups/moss-restore-drill.sqlite
sqlite3 backups/moss-restore-drill.sqlite "PRAGMA integrity_check;"
sqlite3 backups/moss-restore-drill.sqlite "PRAGMA foreign_key_check;"
MOSS_DATABASE_PATH="$PWD/backups/moss-restore-drill.sqlite" npm run dev -- --port 3001

确认四个路由、Feedback、active Signal Run 和 Audit Event 可读后停止演练服务。

实际恢复时:

  1. 停止 MOSS,阻止所有写入。
  2. 保留故障数据库及 WAL/SHM 作为隔离副本。
  3. 将已验证快照放到新的目标路径。
  4. 运行 integrity 与 foreign key 检查。
  5. 原子切换数据库路径或文件。
  6. 启动后再次检查数量与四个路由。

恢复会回退到快照时间点;之后的 Feedback、Import Run、Signal Run 和 Audit Event 会丢失,因此必须先记录差异。

11. 验证与排障

自动化验证:

npm test
npm run verify:v2
npm run build
git diff --check

测试覆盖解析、严格日期、来源身份、迁移与回滚、schema 版本、导入/Feedback/信号事务、API 契约、规则阈值、空库查询和在线备份。

最小手工回归:

  1. 打开 /,确认重定向 /today
  2. 导航四个路由,确认高亮正确且没有双重外壳。
  3. 在 Calibration 提交 Feedback,刷新后确认卡片与历史一致。
  4. 回到 Today,确认输入变化发布一个新 active run。
  5. 点击“刷新信号”,确认成功反馈且随后普通刷新不重复创建 run。
  6. 在 Governance 确认新 Feedback 与 Signal Run Audit Event。
  7. 在 1440、1024、768 和 390 宽度检查无页面级横向滚动,窄屏可通过 Sheet 打开 Inspector。
  8. 切换浅色/深色主题,确认可读且控制台无 error。

常见问题:

现象 处理
页面提示没有内容 在仓库根目录执行 npm run import:content
NODE_MODULE_VERSION 不一致 使用当前 Node 版本重新安装或 rebuild better-sqlite3
数据库版本高于 2 使用匹配该 schema 的新版应用;不要修改版本号伪装降级。
迁移报告日期错误 修正对应源 Markdown 或旧库副本后重新演练;不要写入伪造时间。
刷新信号失败 旧 active 信号应继续显示;查看服务日志并修复失败原因后重试。
SQLITE_BUSY 确认没有多个写进程或人工长事务;不要删除 WAL 文件强制解锁。

12. 代码地图

位置 职责
scripts/import-content.ts 通用导入 CLI。
scripts/import-bookmarks.ts 兼容入口。
src/lib/parsers/x-bookmarks.ts X Markdown 解析。
src/lib/parsers/x-date.ts 迁移与导入共用的严格日期解析。
src/lib/db.ts schema、迁移、事务、查询与审计。
src/lib/rules/ 五条规则与信号发布引擎。
src/app/(workbench)/ 四个共享外壳路由。
src/app/api/feedback/route.ts Feedback Route Handler。
src/app/api/signals/refresh/route.ts 强制刷新 Route Handler。
tests/ 解析、数据库、规则和 API 自动化验收。

正式退出标准与编号项见 MOSS v2 验收标准