Files
nana-story/docs/status/2026-07-28-m1-wave2.md
T

138 lines
5.2 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# M1/M2 第二并行波次状态
日期:2026-07-28
集成分支:`integration/v1`
起始基线:`fa8bd0d`
## 本波次目标
从第一波静态契约和内存测试缝继续接通:
- `RuntimeState → PlayerView` 脱敏投影;
- 与内存实现同语义的 SQLite StoryStore
- 持久化单轮 Turn Engine
- Tauri `submit_turn` 与浏览器/Tauri 双模式前端桥接;
- “天亮前一定回来”许诺纵切的首次端到端提交与恢复。
开发时使用 1 个集成人和 3 个独立 worktree。游戏运行时仍是单模型架构,
没有引入导演 Agent。
## 已集成
### PlayerView 投影
- `project_player_view``RuntimeState` 到玩家可见状态的唯一纯投影。
- 仅显示玩家当前持有且存在公开 `ItemSpec` 的物品。
- 仅显示 `observer == player` 的知识。
- 仅显示玩家参与、已接受或已结束的许诺。
- 六维关系只映射为五档区间,不暴露精确数值。
- 判定、NPC 物品、隐藏事实、内部规则和 NPC-only 许诺不进入视图。
- 关系更新时间沿当前 lineage 查找最近一次 `nana → player` 变化,不受其他关系边影响。
### SQLite StoryStore
- `nodes``materialized_states``branch_heads` 三表初始化。
- `append_node` 使用 `IMMEDIATE` 单事务。
- 父节点、单根、节点唯一、stale head 与新分支语义和内存实现保持一致。
- 支持按分支恢复状态、按 ID 读取节点和按节点读取物化状态。
- 写入与恢复均重新计算 `state_hash`
- 节点 JSON 会与 SQLite 中的 story、node、branch、parent 结构列交叉校验。
- 有效 JSON 的静默损坏、结构列漂移和无效 JSON 都会被拒绝。
### 持久化 Turn Engine
模型侧只能返回内部 `TurnPlan`
```text
validate request
→ load branch state
→ stale check
→ provider plan
→ reducer
→ state hash
→ atomic append
→ infallible PlayerView projection
→ TurnResult
```
- 模型不能直接构造最终 `PlayerView`
- reducer、provider、store 和序列化错误都在提交前返回。
- projector 被定义为不可失败的防御性纯边界,消除“已提交但整轮报失败”的窗口。
- 提交身份由已落库状态覆盖,不信任 projector 提供的 story/node/branch。
- 上游、规则和存储错误转换为稳定、脱敏的 `TurnFailure`
### Tauri 纵切
- 首次启动在应用数据目录创建 SQLite 数据库并播种根节点。
- 启动时严格区分全新数据库、缺分支数据库和损坏数据库。
- `get_demo_player_view` 从已保存状态、当前节点和 lineage 重新投影。
- `submit_turn` 走真实 Turn Engine 与 SQLite,而不是静态 `PlayerView`
- 许诺“天亮前一定回来”会创建 accepted Promise、提高 hope、保存节点并返回脱敏视图。
- 重新打开文件数据库后恢复同一节点、许诺、关系档位和当前线路历史。
- 浏览器开发模式仍保留确定性 adapter;Tauri 模式通过同一前端 API 调用命令。
## 安全修正
交叉审查额外修正了以下问题:
- NPC 与 NPC 之间的许诺不会通过许诺侧栏或历史标签泄漏。
- NPC-only 关系变化不会触发玩家关系“最近更新”提示。
- 历史 lineage 损坏在启动恢复时会作为存档错误上报,不伪装成正常短历史。
- 节点 ID 使用 story、branch、action 的稳定哈希,避免字符清洗和跨分支碰撞。
- Tauri 错误保留 `retryable`,前端能读取结构化错误对象的 message。
## 已通过验证
```text
canonical JSON fixtures parse
node scripts/verify-contracts.mjs
15 schemas and TypeScript DTO source hash verified
vue-tsc --noEmit
vitest run
4 test files passed
12 tests passed
vite build
production build succeeded
SQLite schema smoke
branch_heads, materialized_states, nodes created in memory
```
当前源码共声明 55 项 Rust 单元/集成测试,覆盖 reducer、投影、内存/SQLite
存储、Turn Engine 和 Tauri 纵切。
## 尚未关闭
当前 Work 环境仍没有 `cargo``rustc``rustfmt`,因此 55 项 Rust 测试、
Tauri 宏展开、rusqlite 编译与桌面启动尚未实际验证。必须在 Rust 1.96 环境执行:
```text
cargo fmt --all -- --check
cargo clippy --workspace --all-targets -- -D warnings
cargo test --workspace
cargo run -p nana-contracts -- --check
pnpm tauri dev
```
在这些命令通过前,不把 M0/M1 标记为完成。
## 已知的下一阶段缺口
- Tauri provider 目前是确定性的娜娜纵切,不是真实 LAPP 模型调用。
- 动态 suggestions 和完整 scene/expression/pose 快照尚未进入持久化节点;真实
provider 接入前必须冻结 presentation snapshot 契约。
- 回溯面板尚未调用创建分支命令。
- SQLite 尚未加入 schema migration 版本和多实例 busy timeout。
## 下一波次
1. 在 Rust 1.96 环境关闭首次编译、格式、Clippy 与 Tauri 启动门。
2. 冻结可恢复的 presentation snapshot,避免动态建议和视觉状态在重启后漂移。
3.`lapp-rs` 接入真实非流式 TurnPlan provider,并继续保留 Fake Provider CI。
4. 接入上下文编译与类型化工具循环,确保整轮只有一次提交。
5. 为回溯面板增加“从这里继续”命令,验证旧分支保留和新分支状态隔离。