# 听娜娜讲故事

`nana-story` 是一个本地优先、纯 BYOK 的 AI 对话游戏。V1 聚焦一段可回溯、可分支、状态可重放的单角色纵切。

## 当前阶段

M0 契约基线已建立；M1 状态、投影与持久化主链已经接通，M2 正在进入真实模型循环。

目前包括：

- Tauri 2 + Vue 3 + TypeScript 工程；
- Rust workspace 与模块所有权边界；
- Rust 领域类型作为契约唯一事实来源；
- 生成的 JSON Schema 与 TypeScript DTO；
- canonical `PlayerView` fixture；
- 最小娜娜内容包；
- 原子化状态 reducer，覆盖关系、许诺、知识、持有物、时钟与判定；
- 保持同一语义的内存与 SQLite StoryStore，支持事务追加、恢复和回溯分叉；
- SQLite schema v1、旧库完整性校验、WAL、busy timeout 与未来版本拒绝；
- 写入与恢复时的状态哈希校验；
- `RuntimeState → PlayerView` 脱敏投影与隐藏信息 canary 测试；
- `TurnPlan → reducer → SQLite → PlayerView` 单轮提交链；
- 随故事节点持久化并恢复 scene、expression、pose、beats 与 suggestions；
- 基于 `lapp-rs` 的非流式 LAPP TurnPlan provider 与严格输出校验；
- Turn 请求/结果校验、Fake Provider 与确定性世界书触发；
- 可交互的主演出屏、持有物/线索/许诺、关系与回溯面板。

浏览器模式继续使用确定性的本地 Turn adapter，方便无桌面壳开发；Tauri
模式已经通过 `submit_turn` 使用 SQLite 自动保存和恢复。当前桌面端 provider
仍是确定性的娜娜纵切实现。真实 LAPP provider 已实现并通过注入式测试，但会等
上下文编译和引擎掌控的类型化隐藏检定工具循环完成后再设为默认。

Rust 1.96 下的核心测试、Clippy、契约生成检查和 Tauri 全 target 类型检查已经
通过。当前 Linux Work 环境缺少 WebKitGTK 等桌面开发库，因此真实桌面窗口启动
与 Windows 打包仍需在具备原生依赖的环境补跑。

## 开发

要求：

- Node.js 24+
- pnpm 10.29.2
- Rust 1.96
- 与本仓库同级的 `lapp-rs`，固定到 `lapp-rs.lock` 中的提交

```text
workspace/
├─ lapp-rs/
└─ nana-story/
```

```bash
pnpm install
pnpm verify
pnpm tauri dev
```

只验证前端和已提交契约时可运行：

```bash
pnpm verify:web
```

## 边界

- 模型供应商协议与凭据处理属于 `lapp-rs`。
- 前端只接收 `PlayerView`，不会得到完整 `RuntimeState`。
- V1 不使用向量记忆库、导演 Agent 或多个完整角色。
- 模型与前端都不能直接修改运行时状态。
