FinClaw V1 Data and Persistence Design
状态:Accepted Initial Design / B-2 工程蓝图 日期:2026-05-16 项目:FinClaw 文档级别:项目级数据 / 持久化基线 上游文档:v1-prd.md §5 / §6 / §10、v1-product-object-and-schema-design.md(全部 §3 ~ §13)、v1-engineering-kickoff-decisions.md D-10 / D-12、v1-commercial-signal-instrumentation-design.md §3 / §8 配套文档:v1-tech-stack-and-architecture-design.md(B-1)、v1-api-contract-design.md(B-3)
1. Purpose
本文回答 V1 工程仓库 /Users/mlabs/Programs/CurvatureLabs/finclaw/ 在数据持久化层的 4 个问题:
- 哪些对象需要持久化?分别由谁写、谁读?
- V1 阶段用什么存储后端?为什么不直接上 Postgres?
- 文件系统上的路径、ID、版本号、append-only / mutable 边界如何统一约定?
- 隐私 / 保留 / 删除如何在数据层落地(与 v1-engineering-kickoff-decisions.md D-12 对齐)?
本文不重复 v1-product-object-and-schema-design.md 的字段定义;持久化只是在它之上加路径 / 版本 / 生命周期。
2. Persistence Targets
V1 持久化对象按数据分类:
2.1 一等认知对象(用户主消费)
| Object | Source | Mutability | 主要消费者 |
|---|---|---|---|
MarketCognitionSnapshot | Object Writer 写入 | append-only(一旦写入不修改) | Snapshot View / Refresh diff baseline |
MarketCognitionThread | Object Writer 写入;用户操作变更 status / 元数据 | mutable header + append-only history | Thread View / Refresh diff |
PreExecutionCheckpoint | Object Writer 写入 | append-only | Checkpoint View / Thread reference |
2.2 质量与证据支撑对象
| Object | Source | Mutability | 主要消费者 |
|---|---|---|---|
EvidenceItem | Evidence Checker | append-only(每次任务新生成;用 claim_ref 关联 snapshot) | Evidence Drawer |
DataQualityNote | Evidence Checker | append-only | Evidence Drawer / UI badges |
AdvisorOutput | Advisor Planner | append-only | Snapshot 内 advisor_outputs 引用 / debug |
2.3 用户上下文与边界对象
| Object | Source | Mutability | 主要消费者 |
|---|---|---|---|
UserContext | Task Router / Onboarding | mutable(task-scoped 默认;保存到 profile 需 ProfileConsent) | Context Engine |
ProfileConsent | ProfileConsentDialog(v1-ui-ux-interaction-design.md §5 / §8) | mutable + version-tracked | Boundary Guard / 全部敏感操作前置检查 |
SensitiveInputHandling | Sensitive Input Classifier(v1-agent-orchestration-design.md §9) | append-only | Audit / Evaluation reviewer |
TrainingAssetCandidate | Object Writer + Privacy guard | mutable status;append-only metadata | (V1 不进入训练;仅治理记录) |
2.4 评测与轨迹对象
| Object | Source | Mutability | 主要消费者 |
|---|---|---|---|
EvaluationCase | 仓库内 evaluation/cases/*.yaml(受 git 管理) | mutable via PR;运行时只读 | Evaluation Runner |
EvaluationRun | Evaluation Runner | append-only | Evaluation Review packet / Trial closeout |
Trace | AgentRuntime | append-only(一次任务一份) | Debug / Eval reviewer / Postmortem |
2.5 商业信号事件对象
| Object | Source | Mutability | 主要消费者 |
|---|---|---|---|
CommercialSignalEvent | Frontend 上报 + Backend 触发点(v1-commercial-signal-instrumentation-design.md §4) | append-only | Weekly cs report 脚本(v1-commercial-signal-instrumentation-design.md §7) |
2.6 显式不持久化对象
| 项 | 不持久化理由 |
|---|---|
| 凭证 / 私钥 / 助记词 / API key(v1-product-object-and-schema-design.md §9 credential 类) | 永不写盘;分类后立即拒收(仅 SensitiveInputHandling 记录中保留 classification + masked stub,不含明文) |
| 用户原始 chat raw(包含可能的敏感金融上下文,未经分类) | 不写 raw chat log;只写经过分类与边界检查的 UserContext / Snapshot |
| LLM raw prompt / response 全文 | 默认不入 trace;只 trace 结构化字段 + token usage(如需 debug,dev 模式下可选 --full-trace,仅本机) |
| 订单 / 仓位 / 钱包 / 链上交易状态 | FinClaw 边界外(mvp-product-definition.md §3) |
3. Storage Backend Choice
3.1 V1 默认:文件系统 + JSONL + Markdown
| 维度 | V1 选型 | 理由 |
|---|---|---|
| 主存储 | POSIX 文件系统 (本机 / docker volume) | Labs 内测 3 人,无需 RDB 并发能力 |
| 结构化对象 | JSON files (per object) | 易于 git diff、易于人工 review |
| 时序事件 | JSONL files (*.jsonl) | append-only 友好;流式读取 |
| 配置 / Skill | YAML / Markdown | 与现有 SKILL.md 体系一致 |
| 内嵌索引 | SQLite(仅 commercial signal 报表 + Trial 期临时 query) | v1-commercial-signal-instrumentation-design.md §9 已锁定 SQLite + Python 报表 |
3.2 不选 Postgres / 数据库的理由
| 项 | V1 状态 | 何时考虑 RDB |
|---|---|---|
| 用户规模 | 3 人内测 | trial 退出 / 公开扩展前(≥ 50 用户)触发 §10 迁移路径 |
| 写并发 | ReAct 同步、单进程 | 多进程 / 多 worker 时 |
| 跨用户 query | 极少(cs report 用 SQLite 即可) | 有 admin dashboard 跨用户分析需求时 |
| 事务一致性 | 单文件原子写(os.replace)足够 | 涉及多对象事务时 |
| 全文 search | V1 不实现(thread 列表按 metadata sort 即可) | 用户希望全文检索 snapshot 时 |
3.3 SQLite 的有限使用
仅以下场景使用 SQLite,不作为主存储:
| 用途 | 文件 | 写入者 | 读取者 |
|---|---|---|---|
| Commercial signal events 索引 | data/events/cs/index.sqlite | event_sink.py 旁路写入 | Weekly report 脚本 |
| Trial 期 funnel / retention 查询 | 同上 | 同上 | 同上 |
| LLM telemetry 聚合 | data/eval/llm_telemetry.sqlite | cost_telemetry.py 旁路写入 | make eval-cost-summary |
主对象(Snapshot / Thread / Checkpoint / 等)不进 SQLite。SQLite 文件可随时重建(从 JSONL replay)。
3.4 预留 RDB 接口
CognitionStore 在代码层抽象为 Protocol:
class CognitionStore(Protocol):
async def save_snapshot(self, snapshot: MarketCognitionSnapshot) -> None: ...
async def get_snapshot(self, snapshot_id: str) -> MarketCognitionSnapshot | None: ...
async def list_snapshots(self, user_id: str, *, limit: int = 20) -> list[SnapshotIndexEntry]: ...
# ... 其他对象类似
V1 实现:FileSystemCognitionStore。
V2 / 扩展时实现:PostgresCognitionStore,无需改 caller 代码。
4. Path Conventions
4.1 顶层布局(在 data/ 下)
data/
├── README.md ← 数据目录说明 + privacy 警告
├── .kill_switch ← 触发后 API 进入 503 模式(§8.5 / 8.5)
│
├── cognition/<user_id>/ ← 用户主认知数据
│ ├── snapshots/<snapshot_id>.json
│ ├── snapshots/_index.jsonl ← append-only 索引
│ ├── threads/<thread_id>.json ← thread header (mutable)
│ ├── threads/<thread_id>.history.jsonl ← refresh history (append-only)
│ ├── threads/_index.jsonl
│ ├── checkpoints/<checkpoint_id>.json
│ ├── checkpoints/_index.jsonl
│ ├── evidence/<evidence_id>.json
│ ├── evidence/_index.jsonl
│ ├── quality_notes/<quality_id>.json
│ ├── quality_notes/_index.jsonl
│ └── advisor_outputs/<advisor_output_id>.json
│
├── consents/<user_id>.yaml ← ProfileConsent (mutable, version-tracked)
├── consents/_history/<user_id>/<version>.yaml ← 历史版本
│
├── user_contexts/<user_id>/<context_id>.json
│
├── sensitive/<user_id>/<input_ref>.json ← SensitiveInputHandling (no payload, only metadata)
│
├── training_candidates/<user_id>/<candidate_id>.json
│
├── traces/<task_id>.jsonl ← per-task ReAct trace
│
├── events/
│ ├── cs/<YYYY-MM-DD>.jsonl ← Commercial signal events (per-day)
│ ├── cs/index.sqlite ← 旁路索引
│ └── system/<YYYY-MM-DD>.jsonl ← system events (kill switch, boundary block)
│
└── eval/
├── runs/<run_id>/
│ ├── manifest.yaml
│ ├── per_case/<case_id>.json
│ ├── llm_telemetry.jsonl
│ └── reviewer_notes.md
└── llm_telemetry.sqlite ← 聚合索引
4.2 Path 约定规则
| 规则 | 描述 |
|---|---|
| user_id 隔离 | 任何 user-scoped 对象路径都包含 <user_id>/;跨用户访问由 API 层 auth 拦截 |
_index.jsonl | 每个对象目录都有 append-only 索引文件(一行一个对象的 minimal metadata:id / title / created_at / status) |
_history/ | mutable 对象的历史版本归档目录 |
<YYYY-MM-DD>.jsonl | 时序事件按日切分;不按 user 切分(事件本身含 user_anon_id) |
| 文件名禁止用户输入 | snapshot_id 等 ID 由系统生成(§5);用户输入的 title 仅写入文件内容,不进文件名 |
| 大小写 | 全部 lowercase + _ 分隔;不允许 path 大小写歧义 |
4.3 文件原子写
def atomic_write_json(path: Path, payload: dict) -> None:
tmp = path.with_suffix(path.suffix + ".tmp")
tmp.write_text(json.dumps(payload, ensure_ascii=False, indent=2))
os.replace(tmp, path) # POSIX rename = atomic
JSONL 用 open(..., "a") 追加;single-process 假设保证不会出现 interleave。
4.4 引用约定
跨对象引用使用 <object_type>:<id> 形式的字符串(与 v1-api-contract-design.md §6 Object Reference Conventions 对齐):
| 字段 | 例 |
|---|---|
linked_snapshots[] | ["snapshot:snap_2026-05-18T10-23-04Z_a3f5b2"] |
pre_execution_checkpoint_refs[] | ["checkpoint:chk_..."] |
claim_ref | "snapshot:snap_xxx#supporting_reasons[2]"(§6 路径表达) |
previous_snapshot_ref | "snapshot:snap_yyy" |
CognitionStore 提供 resolve(ref: str) -> dict | None 方法做反查。
5. ID and Versioning
5.1 ID 命名规则
每个对象有 stable identifier,构造规则:
| Object | Prefix | 构造 | 例 |
|---|---|---|---|
| Snapshot | snap_ | snap_<YYYY-MM-DDTHH-MM-SSZ>_<6-char-hash> | snap_2026-05-18T10-23-04Z_a3f5b2 |
| Thread | thr_ | thr_<YYYY-MM-DDTHH-MM-SSZ>_<6-char-hash> | thr_2026-05-18T10-30-00Z_b7c1d4 |
| Checkpoint | chk_ | 同 | chk_... |
| Evidence | evi_ | 同 | evi_... |
| DataQualityNote | qln_ | 同 | qln_... |
| AdvisorOutput | adv_ | 同 | adv_... |
| UserContext | ctx_ | 同 | ctx_... |
| ProfileConsent | csn_ | csn_<user_id>_v<version> | csn_user_alice_v3 |
| SensitiveInputHandling | snh_ | 同 snapshot pattern | snh_... |
| TrainingAssetCandidate | tac_ | 同 | tac_... |
| Trace | tr_ | tr_<task_id> | tr_task_... |
| CommercialSignalEvent | evt_ | UUIDv4 | evt_<uuid> |
| EvaluationRun | run_ | run_<YYYY-MM-DDTHH-MM-SSZ>_<4-char-hash> | run_... |
| PersonaDriftLog | drift_ | 同 snapshot pattern | drift_2026-05-18T11-04-09Z_3e8a91(B-6 §3.3 新引入对象) |
<6-char-hash> 取自 secrets.token_hex(3),用于避免同秒冲突;ID 不编码 user_id(user_id 在 path 中体现)。
5.2 Version 字段
mutable 对象(Thread / ProfileConsent / TrainingAssetCandidate)有 version 字段:
schema_version: "1.0" # 字段 schema 版本,与 server 代码一起 bump
object_version: 7 # 该对象本身的修改次数(每次 mutate +1)
updated_at: <iso8601>
Snapshot / Checkpoint / EvidenceItem 等 append-only 对象没有 object_version,但仍需 schema_version。
5.3 schema_version 兼容策略
V1 期间预期 schema_version ∈ "1.0"。如发生 breaking change:
- minor 增量(
1.1):CognitionStore 加载时按字段缺省值兼容; - major 增量(
2.0):写迁移脚本server/scripts/migrate_v1_to_v2.py,落盘前备份data/.backup-pre-migrate-<timestamp>/。
5.4 时间字段约定
- 全部时间字段使用 ISO-8601 + UTC(
Z后缀); - API 出口对前端时按用户 tz 转;存储统一 UTC;
created_at写入时设置;之后不修改;updated_atmutable 对象每次写入更新;append-only 对象不含此字段。
6. Refresh Semantics
V1 的 Thread refresh 是产品核心循环(v1-prd.md §6.5、v1-product-object-and-schema-design.md §4.3)。持久化层契约:
6.1 Thread 头与历史的分离
| 文件 | 内容 | Mutability |
|---|---|---|
threads/<thread_id>.json | Thread header:当前 thesis / counter / watch_questions / refresh_conditions / invalidators / status / linked_snapshots[] / last_refreshed_at | mutable(每次 refresh 更新) |
threads/<thread_id>.history.jsonl | 一行一个 RefreshChange(v1-product-object-and-schema-design.md §4.3) | append-only |
6.2 Refresh 操作的精确语义
一次 thread refresh 完成时持久化层执行:
- 生成新
Snapshot(写入snapshots/<snap_id>.json); - 在
threads/<thread_id>.history.jsonl追加一条RefreshChange(含previous_snapshot_ref+new_snapshot_ref+ diff 字段); - 原子更新
threads/<thread_id>.json头:linked_snapshots[]追加新snap_id(不移除旧的);current_thesis/counter_thesis/watch_questions/invalidators/evidence_state替换为新值;last_refreshed_at= now;object_version+= 1;
- 写入
traces/<task_id>.jsonl; - 推送 SSE event
thread_refreshed。
6.3 历史 Snapshot 不被覆盖(硬约束)
- 任何
Threadmutation 不得修改或删除linked_snapshots[]中的历史Snapshot; Snapshot文件写入后永不修改;如发现错误,新建 corrected snapshot + 在 thread history 追加correction_note,不修改原文件。
6.4 Refresh 一致性保证
- Refresh 期间出错(步骤 1 ~ 4 任一失败):
- 新 Snapshot 文件可能已写入(无副作用,可孤立存在);
- Thread header 不更新;
- history.jsonl 不追加;
- 用户看到 SSE
task_failed,下次 refresh 重新尝试;
- 不引入跨文件事务(V1 用文件系统不要求 ACID)。
6.5 ProfileConsent 撤回的副作用
按 v1-engineering-kickoff-decisions.md D-12 与 v1-product-object-and-schema-design.md §8.2:
撤回 consent 时持久化层动作:
| 项 | 动作 |
|---|---|
| ProfileConsent | mutate:set revoked_at;写入 consents/<user_id>.yaml 新版本,旧版本归档到 _history/ |
| 已生成的 Snapshot / Thread / Checkpoint | 保留(不删除;用户仍可查看) |
| 后续 LLM 调用 | UserContext 不再注入 saved profile 字段 |
| Commercial signal events | 自撤回时刻起不新写 events;历史 events 在 48h 内由 delete_user_events 脚本删除 |
| TrainingAssetCandidate | 全部置 withdrawal_status: revoked;不进入任何后续训练流 |
7. Retention and Deletion Policy
7.1 Retention Matrix
| Object | Default Retention | Trial 期 | Trial 退出后 |
|---|---|---|---|
| Snapshot / Thread / Checkpoint | 永久(用户主动删除前) | 同 | 同;用户撤回 consent 不删除 |
| EvidenceItem / DataQualityNote | 跟随对应 Snapshot | 同 | 同 |
| AdvisorOutput | 90 天,过期归档到 _archive/ | 同 | 同 |
| UserContext (task-scoped) | 任务结束后 24 小时 | 同 | 同 |
| UserContext (saved with consent) | 跟随 ProfileConsent | 同 | 同 |
| ProfileConsent | 永久(含 _history/) | 同 | 永久(合规证据) |
| SensitiveInputHandling | 永久(仅 metadata,无明文) | 同 | 永久(合规证据) |
| TrainingAssetCandidate | 永久(受 ProfileConsent.training_use_allowed 约束) | 同 | 同;revoke 后 48h 内 purge |
| Trace | 90 天后归档到 traces/_archive/ | 同 | 同 |
| CommercialSignalEvent | 90 天后归档;trial 退出 30 天内全部脱敏 | 同 | 同 |
| EvaluationRun | 永久(受 git 管理 / 治理库副本) | 同 | 同 |
7.2 删除分类
V1 区分 4 种"删除":
| 类型 | 描述 | 实现 |
|---|---|---|
| user-soft-delete | 用户 UI 上"删除" Snapshot / Thread | 在 header 写 deleted_at;文件保留;列表过滤 |
| user-hard-delete | 用户在 settings 触发 "delete account" | python -m server.scripts.delete_user --user_id=X 物理删除该 user_id 下所有目录;ProfileConsent 保留删除日志 stub |
| consent-withdrawal | 用户撤回 consent,但保留账号 | §6.5 |
| retention-expiry | 数据到期归档 | cron-less:python -m server.scripts.archive_expired 由人工定期运行(V1 不上 cron) |
7.3 归档结构
data/cognition/<user_id>/snapshots/_archive/<YYYY-MM>/<snapshot_id>.json
data/traces/_archive/<YYYY-MM>/<task_id>.jsonl
data/events/cs/_archive/<YYYY-MM>.jsonl.gz
归档不改变 ID;查询时若主目录未命中,自动 fallback 查 _archive/。
7.4 Kill Switch 与 Retention 的关系
data/.kill_switch 触发不影响 retention:
- 已写入数据保留;
- 新写入暂停(API 拒绝);
- Trial closeout decision =
stop时再走 user-hard-delete 流程。
8. Backup and Export
8.1 V1 备份策略(Labs 内测)
| 频率 | 内容 | 落点 |
|---|---|---|
| 每天 02:00(人工) | data/ 全量 tar.gz | 本机 ~/finclaw-backups/<YYYY-MM-DD>.tgz,保留 14 天 |
| 每周(人工) | 同上 | 移动到 Labs 团队加密存储(未定,待 trial 启动前与项目发起人对齐) |
| 边界事件后立即 | 仅 data/events/system/ + 触发任务的 data/traces/ | ~/finclaw-backups/incidents/<task_id>/ |
V1 不实现自动备份(不上 cron);trial 期间由项目发起人手动触发 python -m server.scripts.backup。
8.2 用户数据导出(GDPR-friendly 雏形)
python -m server.scripts.export_user_data --user_id=X --out=./out/
输出目录结构:
<out>/<user_id>/
├── README.md ← 描述本导出包内容
├── consents/ ← ProfileConsent 全部版本
├── cognition/ ← Snapshot / Thread / Checkpoint
├── evidence/ ← Evidence + DataQualityNote
├── events/ ← 该用户的 CommercialSignalEvent(脱敏后)
├── traces/ ← 该用户的 Trace(仅 task summary,不含 raw prompt)
└── manifest.yaml ← 文件清单 + checksum
V1 内测期间用户主动请求时手动跑该脚本;V2 暴露为 API endpoint。
8.3 导出不包含
- 凭证 / 私钥(永不入库);
- 其他用户的数据(user_id 隔离);
- LLM raw prompt / response(默认未持久化);
- 内部 advisor reasoning(仅暴露最终
AdvisorOutput.key_points)。
9. Privacy Boundaries
9.1 与 v1-engineering-kickoff-decisions.md D-12 的对齐
V1 内测期间隐私 / 合规复核降紧迫但不豁免。本文已在数据层先行落地以下约束:
| 约束 | 落点 |
|---|---|
| 凭证 / 私钥永不写盘 | §2.6 显式不持久化对象 |
| ProfileConsent 必须存证 | §4.1 consents/<user_id>.yaml + _history/ 永久保留 |
| sensitive_input 仅写 metadata | data/sensitive/<user_id>/<input_ref>.json 含 classification / masked_stub,不含明文 |
| training pipeline 受 consent 闸门 | TrainingAssetCandidate 落盘需 user_authorized: true + de_identified: true + sensitive_filtered: true(v1-product-object-and-schema-design.md §11) |
| trace 保留 90 天后归档 | §7.1 |
| commercial signal 撤回后 48h 内删除 | §6.5 |
9.2 user_anon_id vs user_id
V1 区分两个标识:
| 标识 | 出现位置 | 关联 PII |
|---|---|---|
user_id | data/cognition/<user_id>/...、ProfileConsent、UserContext | 关联 Labs 内测用户真实身份(仅在邀请码 → user_id 映射表中持有;表本身存 data/_internal/user_id_map.json,仅项目发起人可读) |
user_anon_id | CommercialSignalEvent payload、EvaluationRun reviewer notes | 由 user_id 经 HMAC 派生(key 仅在 server config,不入库),仅项目发起人可逆查 |
凡跨用户聚合分析(cs report、eval reviewer notes)一律用 user_anon_id。
9.3 数据分类标签
写入对象前必须打标签:
| 标签 | 适用 | 处理 |
|---|---|---|
cognition_output | Snapshot / Thread / Checkpoint / Evidence / Quality | 默认可保存;用户可删除 |
user_voluntary_context | UserContext / ProfileConsent | 需 ProfileConsent 才长期保存 |
sensitive_metadata | SensitiveInputHandling | 永久保留 metadata(合规证据),明文不留 |
behavior_signal | CommercialSignalEvent | 受 consent_for_trial_data 闸门 |
system_observability | Trace / system events | 不含 PII;仅 task_id / structural fields |
9.4 数据流出边界
| 流向 | 允许? | 备注 |
|---|---|---|
| → 默认 LLM provider(GPT-5.5 / Kimi K2.6) | 是 | 仅当任务需要;遵守 provider TOS;不主动发送 saved profile 除非 ProfileConsent.save_to_thread |
| → BYOM provider | 是(但受限) | TrainingAssetCandidate 路径禁用 BYOM(v1-model-and-provider-policy.md §4) |
→ Labs 评测知识库 (projects/Labs-FinTecAI/evaluation/finclaw/runs/) | 是 | 仅 EvaluationRun(含脱敏 case + grade);不含 user_id 明文 |
| → 外部 channel (Telegram 等) | 否(D-02) | V1 不部署 channel |
| → 公网 webhook out | 否 | V1 不主动外推 |
| → Trading Matrix / 其他兄弟项目 | 否 | 需另外授权契约(v1-product-object-and-schema-design.md §5.2) |
10. Migration Path to RDB
10.1 触发条件
满足任一即启动 RDB 迁移设计:
| 条件 | 说明 |
|---|---|
| 用户规模 ≥ 50 | 文件系统列表性能下降明显 |
| 多 worker 部署 | 需要写并发 |
| 跨用户全文检索需求 | 文件系统不适合 |
| 商业 SLA 要求事务一致性 | 多对象事务需 ACID |
| Legal/Compliance 要求审计日志 immutable | 用 RDB + WAL |
10.2 候选目标
| 选项 | 评分 | 备注 |
|---|---|---|
| Postgres 16+ | 推荐 | JSONB 原生支持;与 Pydantic v2 + asyncpg 自然 |
| SQLite 单机扩展 | 仅 trial 备选 | 单机 + WAL;适合 5 ~ 50 用户中间态 |
| 文档数据库 (Mongo) | 不推荐 | 引入新运维栈 |
10.3 迁移工序(V2 草案)
- 实现
PostgresCognitionStore(同 Protocol 接口); - 写
server/scripts/import_from_filesystem.py:扫描data/,逐对象 upsert 到 PG; - 双写期(≤ 1 周):FileSystem + Postgres 并行写;reads 切到 Postgres;
- 校验对账脚本;
- 切换 single-source-of-truth 为 Postgres;FileSystem 仅作 backup;
- 灰度迁移商业信号 SQLite → Postgres TimescaleDB 扩展(可选)。
10.4 不变项
无论是否迁移到 RDB,以下契约不变:
- 对象 ID 命名规则(§5.1);
- schema_version / object_version 含义;
- Refresh 语义(§6);
- Privacy 边界(§9);
- API 层暴露的 endpoint shape(v1-api-contract-design.md)。
11. Acceptance
本文满足 V1 工程化 B-2 任务的接收条件:
| 项 | 状态 |
|---|---|
| 14 类持久化对象都有路径 / mutability / 消费者声明(§2 + §4) | 是 |
| V1 选用 Filesystem + JSONL + Markdown,预留 RDB 接口(§3) | 是 |
| ID / 版本 / 时间字段命名规则统一(§5) | 是 |
| Refresh 语义保证「历史 Snapshot 不被覆盖」(§6.3) | 是 |
| 凭证 / 私钥永不写盘;ProfileConsent 永久存证(§2.6 + §9.1) | 是 |
| Trace 保留 90 天后归档;CS event 撤回 48h 内删除(§7.1 + §6.5) | 是 |
| 用户数据导出脚本与 GDPR-friendly 字段就绪(§8.2) | 是 |
| 与 v1-product-object-and-schema-design.md §13 API and Persistence Boundaries 对齐 | 是 |
| Migration to RDB 的不变项明确(§10.4) | 是 |
12. Open Items
- O-1:用户数据 backup 的 Labs 加密存储位置 / 凭证 — 待项目发起人在 trial 启动前对齐;
- O-2:cs event SQLite 的 schema 详细字段 — 由 v1-commercial-signal-instrumentation-design.md 后续 sub-packet 细化;
- O-3:trial 退出时的「数据脱敏」具体规则(哪些字段 hash / 哪些 drop) — 待 GDPR 法务复核(v1-engineering-kickoff-decisions.md D-12)后定;
- O-4:是否在 V1 内引入
data/.lock文件防止人工备份与运行时并发写 — 待 backup runbook 落地时定; - O-5:trace
--full-trace模式的开关配置(仅 dev 本机;不影响 trial 数据) — 待 observability sub-packet 决定。