# M1/M2 第三并行波次状态

日期：2026-07-28

集成分支：`integration/v1`

起始基线：`4157f87`

## 本波次目标

- 在 Rust 1.96 下关闭此前未执行的核心编译、测试与 Clippy 门；
- 将动态演出完整保存到故事节点，并从节点恢复同一 `PlayerView`；
- 为 SQLite 建立可辨认、可拒绝损坏状态的 schema 生命周期；
- 实现真实 `lapp-rs` 非流式 TurnPlan provider；
- 保持模型、状态提交和玩家视图之间的安全边界。

开发继续使用 1 个集成人和 3 个独立 worktree。三个工作面分别负责
Presentation、Store Hardening 和 LAPP Provider；游戏运行时仍是单模型架构。

## 已集成

### 可恢复的演出快照

`StoryNode` 现在持久化一份 `PresentationSnapshot`：

- scene id 与公开标题；
- 主角色 id、名称、最终 expression 与 pose；
- 本轮演出 beats；
- 可编辑行动 suggestions；
- `canContinue`。

`TurnPlan` 只提交内部演出快照和 `StateDelta`，最终 `PlayerView` 仍由可信投影器
在事务提交后生成。旧的 beats-only 节点可通过默认值反序列化；重启恢复会保留
表情、姿态、节拍和建议，不再依赖运行时重新生成。

前端已消费 `characterExpression` 与 `characterPose`，浏览器确定性 adapter 也会
按本轮最后一个视觉指令更新角色状态。

### SQLite schema 生命周期

- 新数据库初始化为 schema v1，并通过 `PRAGMA user_version` 标记。
- 完整的旧版无版本数据库会在事务内采用为 v1，不丢失节点、状态或分支头。
- 不完整的 v0、损坏的 v1 和未来版本都会被拒绝，不会静默重建。
- 文件数据库启用 WAL、5 秒 busy timeout、foreign keys 与 synchronous NORMAL。
- 写入、恢复、结构列和 `state_hash` 的交叉校验继续保留。

### LAPP TurnPlan provider

- 使用固定的相邻 `lapp-rs`，启用 Rustls 客户端与系统凭据库。
- 非流式 chat 在独立 Tokio worker 中运行。
- 接受一个指定工具调用或裸 JSON，两者都经过相同严格结构校验。
- 模型只能返回 scene、character、beats、delta、suggestions 与 canContinue。
- `PlayerView`、`committedNodeId`、未知字段、歧义工具调用和无效标识符都会被拒绝。
- 提交节点 ID 由 story、branch 与 action 的稳定哈希产生，不能由模型伪造。
- 上游错误与无效输出经过脱敏，不回显 provider 原文或凭据。

真实 provider 暂不作为 Tauri 默认实现。下一步必须先建立上下文编译器和由引擎
掌控的类型化隐藏检定工具循环，避免模型直接提出未经裁决的判定记录或跨过
“一轮只提交一次”的原子边界。

### 桌面接线

- Tauri 从已提交节点恢复完整演出快照。
- “许诺 → 提交 → 恢复”测试增加 beats、suggestions、expression 与 pose 一致性。
- 补齐应用 SVG 源图标和 512×512 RGBA PNG，Tauri 宏可完整展开。
- `Cargo.lock` 首次纳入版本控制，固定 Rust 依赖解析结果。

## 已通过验证

```text
Rust 1.96.0

cargo fmt --all -- --check

cargo test -p nana-domain -p nana-engine -p nana-runtime -p nana-store -p nana-contracts
  67 tests passed

cargo clippy -p nana-domain -p nana-engine -p nana-runtime -p nana-store \
  -p nana-contracts --all-targets -- -D warnings

cargo check -p nana-story-app --all-targets
cargo clippy -p nana-story-app --all-targets -- -D warnings
  Tauri lib、binary 与 6 个 test target 类型检查通过

node scripts/verify-contracts.mjs
  16 schemas and TypeScript DTO source hash verified

vue-tsc --noEmit

vitest run
  4 test files passed
  12 tests passed

vite build
  production build succeeded
```

当前 Linux Work 环境没有 WebKitGTK、Rsvg 与完整桌面链接依赖。Tauri 检查使用
本地 compile-only pkg-config shim 完成 Rust、宏和测试 target 的类型检查，
不等价于实际链接或窗口启动。真实 `pnpm tauri dev` 和 Windows 打包仍需在具备
原生依赖的环境验证。

## 下一波次

1. 建立确定性的上下文编译器，按预算选择角色卡、世界书、Persona、剧情与状态。
2. 建立类型化工具循环，由引擎执行隐藏 CoC7 判定和受控状态操作。
3. 将 LAPP provider 接入该工具循环，并保持整轮只有一次 SQLite 提交。
4. 为回溯面板接入“从这里继续”，创建新分支且保留旧分支头。
5. 在 Windows CI 或本机完成 Tauri 启动、重启恢复和安装包冒烟。
