Files
nana-story/tasks/plan.md

10 KiB
Raw Permalink Blame History

Implementation Plan: Wave 7 本地 Windows 闭环

Overview

integration/v1@23672e857bfa854930b0c8ab8aca316a95ba5d09 继续开发。先关闭真实 Windows 基线暴露出的可重复性问题,再补齐真实模型的当前分支连续上下文与超预算检查点, 随后实现“风险预检 → 玩家确认 → 隐藏检定失败 → 可推骰 / 可重新生成”的纵向切片。 每个阶段都必须保持回合原子提交、分支隔离和 PlayerView 脱敏边界。

Architecture Decisions

  • 继续使用 integration/v1,不在本地另起一套重建工程。
  • lapp-rs 保持相邻 path dependency,并固定到 5ba3c659…
  • 契约源码哈希统一按 LF 规范化;同时用 .gitattributes 固定文本文件换行,避免 Windows core.autocrlf=true 产生假漂移。
  • 模型上下文固定为“系统约束 → 稳定资源 → 当前分支检查点 / 原始历史 → 本轮动态尾部”, 提升前缀缓存命中;兄弟分支内容不得进入上下文。
  • 压缩检查点是可丢弃缓存,不是事实来源;删除检查点不得改变 RuntimeState
  • 风险提示是“不落节点的预检结果”,只有玩家确认后才进入现有隐藏判定与原子提交链。
  • Regenerate 复用原行动的判定记录;PushCheck 是带明确后果的新行动和新节点。
  • 在重新生成 / 推骰语义闭环前,不扩大到内容包导入、TTS、生图或第二完整角色。

Dependency Graph

Windows 可重复契约门禁
    └─ 精确 Node/pnpm + Rust/MSVC 工具链
        └─ Wave 6 全量基线
            └─ 当前分支连续上下文
                └─ 超预算检查点压缩
                    └─ 风险预检契约
                        ├─ Runtime / Store 语义
                        └─ Tauri 窄命令
                            └─ Vue 确认、推骰、重新生成界面
                                └─ Windows Demo + LAPP 冒烟

Task 1: 修复跨平台契约哈希

Description: 消除 Windows CRLF checkout 对契约源码哈希的影响,同时固定未来 checkout 的文本换行。

Acceptance criteria:

  • 干净 Windows checkout 上 node scripts/verify-contracts.mjs 通过。
  • Rust 生成器对 LF 与 CRLF 输入计算相同源码哈希。
  • Linux 既有 .source.sha256 不发生无意义变化。

Verification:

  • node scripts/verify-contracts.mjs
  • cargo test -p nana-contracts
  • cargo run -p nana-contracts -- --check
  • git diff --check

Dependencies: None

Files likely touched:

  • .gitattributes
  • scripts/verify-contracts.mjs
  • crates/nana-contracts/src/main.rs

Estimated scope: Medium

Task 2: 恢复锁定的本地工具链

Description: 让 Windows 开发机满足仓库已声明的精确依赖,不修改项目依赖版本。

Acceptance criteria:

  • Node.js 24+ 与 pnpm 10.29.2 可用。
  • Rust 1.96.0、rustfmt、clippy、MSVC Build Tools、Windows SDK 可用。
  • 相邻 lapp-rs 位于固定提交且工作树干净。

Verification:

  • node --version
  • pnpm --version
  • rustc --version
  • cargo clippy --version
  • git -C ..\lapp-rs rev-parse HEAD

Dependencies: Task 1 可并行

Files likely touched: None(仅本机工具链与依赖目录)

Estimated scope: Medium

Task 3: 关闭 Wave 6 Windows 机械门禁

Description: 在真实 Windows 目标上重新验证既有 119 项核心 Rust、18 项 Tauri、 29 项 Web 测试和无 bundle 桌面编译。

Acceptance criteria:

  • 依赖安装使用锁文件且不修改锁文件。
  • pnpm verify 等价的 Web / Rust / 契约门禁全绿。
  • pnpm tauri build --no-bundle 成功。

Verification:

  • powershell.exe -NoProfile -File .\scripts\windows-smoke.ps1 -InstallDependencies

Dependencies: Tasks 1-2

Files likely touched: None

Estimated scope: Small

Checkpoint: Windows 基线

  • 工作树只包含已审阅的 Wave 7 变更。
  • 契约、Web、Rust、Tauri 门禁均可重复。
  • 记录首个无法自动关闭的环境阻塞。

Task 4: 恢复当前分支连续上下文

Description: Store 提供按 parent_id 追溯的祖先链;Runtime 将稳定资源、当前分支 历史和本轮输入按固定顺序编译给 LAPP,解决真实模型第二轮起失忆的问题。

Acceptance criteria:

  • 第三轮模型输入包含根到当前节点的前两轮玩家输入和演出节拍。
  • 分叉后只包含本分支祖先,兄弟分支文本和隐藏状态不泄漏。
  • 系统约束、角色卡和 Persona 在连续回合中保持逐字节稳定,本轮输入位于尾部。
  • 精确骰点、目标值、状态 delta、NPC 隐藏物品和未触发世界书不进入上下文。

Verification:

  • Store 祖先链测试覆盖分叉共享祖先。
  • Runtime 捕获模型输入的三轮与兄弟分支隔离测试。
  • 既有 PlayerView / 上下文泄密 canary 通过。

Dependencies: Checkpoint: Windows 基线

Files likely touched:

  • crates/nana-store/src/lib.rs
  • crates/nana-runtime/src/context.rs
  • crates/nana-runtime/src/lib.rs
  • crates/nana-runtime/src/lapp_provider.rs
  • src-tauri/src/lib.rs

Estimated scope: Medium

Task 5: 增加超预算分支检查点

Description: 根据模型上下文窗口预算保留“最近祖先检查点 + 检查点后原始节点 + 本轮 输入”;超预算时使用同一 LAPP 模型压缩旧段,并把检查点作为当前节点的非权威缓存。

Acceptance criteria:

  • 500 节点分支恢复不扫描无关分支并保持在输入预算内。
  • 检查点只继承自当前祖先链,来源哈希不符时拒绝使用。
  • 删除检查点后 RuntimeState、分支头和 PlayerView 不变。
  • 压缩取消、超时或畸形输出不创建节点、不移动分支头。

Verification:

  • SQLite v2 → v3 无损迁移测试。
  • 预算边界、检查点继承、来源哈希和删除重建测试。
  • 压缩调用复用既有取消控制与原生单飞闸门。

Dependencies: Task 4

Files likely touched:

  • crates/nana-domain/src/lib.rs
  • crates/nana-store/src/lib.rs
  • crates/nana-runtime/src/context.rs
  • crates/nana-runtime/src/lapp_provider.rs
  • src-tauri/src/lib.rs

Estimated scope: MediumCore 与 Runtime 可在内部契约冻结后并行)

Checkpoint: 连续上下文

  • 三轮真实上下文连续。
  • 兄弟分支隔离。
  • 稳定前缀可缓存。
  • 500 节点与超预算检查点测试通过。

Task 6: 增加不落节点的风险预检契约

Description: 高风险玩家行动先返回脱敏风险描述和确认令牌,不调用隐藏判定、不推进 状态、不创建故事节点。

Acceptance criteria:

  • 普通行动仍沿用现有单次提交路径。
  • 高风险行动首次提交只返回玩家可理解的风险提示。
  • 预检结果不包含骰点、目标值、NPC 隐藏信息或精确关系数值。

Verification:

  • Domain / Runtime 契约测试。
  • Tauri 命令测试证明预检不写 SQLite。
  • PlayerView 泄密 canary 继续通过。

Dependencies: Checkpoint: 连续上下文

Files likely touched:

  • crates/nana-domain/src/lib.rs
  • crates/nana-runtime/src/
  • src-tauri/src/lib.rs
  • contracts/

Estimated scope: Medium

Task 7: 完成确认、推骰与重新生成纵切

Description: 把现有 Regenerate / PushCheck 领域语义接到 Tauri 与 Vue,让玩家在失败 后选择承担结果、推骰或重新生成叙述。

Acceptance criteria:

  • 确认风险后只产生一个完整节点。
  • Regenerate 复用原判定,不允许刷骰。
  • PushCheck 明示后果并创建新行动、新判定和新节点。
  • 回溯后两条线路的判定、物品、许诺和关系互不污染。

Verification:

  • Runtime / Store 端到端测试。
  • Tauri 命令测试。
  • Vue 交互测试覆盖确认、取消、推骰、重新生成。
  • 完整 pnpm verify

Dependencies: Task 6

Files likely touched:

  • crates/nana-runtime/src/adjudication.rs
  • crates/nana-store/src/lib.rs
  • src-tauri/src/lib.rs
  • src/app/
  • src/App.vue

Estimated scope: Medium(按契约、后端、前端三个小提交交付)

Checkpoint: 可玩纵切

  • 风险提示先于隐藏检定。
  • 失败、推骰、重新生成的语义可被玩家区分。
  • 取消、超时和畸形响应仍不产生半轮。
  • Demo 与真实 LAPP 各完成一次隐藏判定。

Task 8: Windows 桌面冒烟与交付

Description: 启动隔离存档的 Demo 窗口,验证两次重启、终局、回溯与双线路隔离;随后 执行真实 LAPP 最小连接及隐藏判定。

Acceptance criteria:

  • Demo 窗口启动并正常退出。
  • 两次重启恢复、终局和双线路隔离通过。
  • 真实 LAPP 连接测试及一轮工具调用通过,日志无凭据。

Verification:

  • scripts/windows-smoke.ps1 -Launch -Demo
  • scripts/windows-smoke.ps1 -Launch

Dependencies: Task 7

Files likely touched: 仅状态报告;若冒烟发现缺陷则另建小任务。

Estimated scope: Medium

Risks and Mitigations

Risk Impact Mitigation
Gitea SSH 2222 被本机代理拦截 无法自动 fetch/push 本地开发不依赖 fetch;提交前使用用户终端 SSH 或短期 HTTPS 凭据
Rust/MSVC 未安装 无法关闭 Tauri 门禁 先完成纯文本跨平台修复;工具链作为显式环境任务
精确 pnpm 下载不稳定 Web 验证延迟 保留锁文件;优先使用 Corepack 官方包并重试,不升级项目版本
祖先链错误按 branch_id 过滤 分叉后丢失共享历史 只按 parent_id 追溯并做兄弟分支隔离测试
压缩摘要被误当事实 删除缓存后剧情状态变化 检查点保持非权威,状态仍只由根状态 + delta 重建
风险预检变成第二套状态机 原子性回归 预检只产生短期确认数据,唯一 reducer / SQLite 提交路径不变
重新生成可刷骰 破坏公平性 判定绑定原 action/check;只有 PushCheck 创建新判定

Open Questions

  • 无产品阻塞问题。Rust/MSVC 安装若需要管理员交互,将在 Task 2 单独请求用户操作。