blob: fbd6a7043e5a53b6769c244c90fe5ea7ef2974b6 (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
|
# 中文江南水乡可玩样板实施计划
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
**Goal:** 在不改变 Kernel 社会模拟的前提下,把桌面端现有程序化方块场景替换为可游玩的中文江南水乡阶段一样板,并以可验收的结构、性能、可维护性和视觉证据完成交付。
**Architecture:** 新增纯函数 `VillagePresentation` 模块,集中定义确定性的场景布局、民居入口、角色方向/动画帧、交易/需求展示状态和中文展示文案;它不依赖 MonoGame,因此可由桌面测试直接验证。新增 `VillageArt` 只负责程序化纹理和绘制原语,`Game.fs` 只负责输入、模拟调度、窗口生命周期和调用展示层,避免继续堆积绘制代码。MonoGame 层不引入外部美术文件,也不改变 `LivingVillage.Kernel` 的社会模拟接口或确定性行为。
**Tech Stack:** F#、.NET 8、MonoGame DesktopGL 3.8.5.1、MSTest、现有 SpriteBatch/Texture2D。
**Current status:** 首轮计划审查为 `NOT APPROVED`,阶段一样板源码尚未开始实现。本轮先修订结构和质量门槛;通过复审前不进入绘制实现。
---
## Mandatory Quality Gates
这些门槛是阶段一样板的验收条件,不是“以后再补”的技术债。
### 1. Responsibilities and data modeling
- `LivingVillage.Kernel` 负责模拟状态转换、交易守恒、存档格式和确定性;`VillagePresentation` 负责纯展示状态;`VillageArt` 负责纹理/绘制原语;`Game.fs` 负责平台输入、MonoGame 生命周期和组合调用。任何新绘制 helper 不直接塞入 `Game.fs`。
- 对方向、场景元素、民居模式、交易结果、失败原因等使用已有或新增 DU;跨边界失败使用明确的 `Result` 或带失败分支的 DU,不以特殊字符串表示状态。
- 对跨模块的坐标、瓦片、像素、tick/时间等单位使用合理的轻量单位类型或明确命名,避免把 `float32`、`int` 和 `int64` 无注释地混用;不为没有语义收益的每个局部值机械包装。
- 中文维护文档写在模块/API 边界,说明输入、输出、单位、不变量、失败分支、算法和性能取舍;不做逐行翻译,也不宣称现有 `Sim.fs`、`WorldSave.fs`、`Game.fs` 已经具备完整维护注释,除非实际补齐相应公共边界。
### 2. Ownership, snapshots, and purity
- 记录 `World.Npcs` 数组的所有权约束:调用方只读;`Sim.step` 的结果是逻辑快照;任何数组复制、嵌套 struct 复制和 `ResizeArray` 暂存都要标明生命周期与不可变快照假设。
- `WorldSave` 只能序列化稳定快照,读档结果不能共享会被后续 tick 修改的可变数组;存读档回归必须验证值、事件、谣言和交易状态的一致性。
- 在基线测量前不得为了“高性能”重写 `Sim.step`。优化后必须保留同 seed 同输入的结果一致性、交易守恒和存读档行为。
- 禁止用全局可变状态破坏确定性或纯度;展示动画时钟、输入缓冲等平台状态只能留在明确的桌面组合层。
### 3. Performance evidence before optimization
- 先为当前实现建立基线,至少记录固定 seed、NPC 数量、tick 数、预热方式、tick 吞吐、每线程分配字节数、Gen0/Gen1/Gen2 GC 次数和运行时版本;重复运行并保存原始输出。
- 基线覆盖 `Sim.step` 中已确认的 `Array.copy`、`ResizeArray` 和 `World`/`Mind`/`Npc` struct 复制路径。没有数据不得宣称“高性能”或提前调整热点。
- 只有基线完成后才可提出热点优化;每次优化都要重新测量,并以确定性、守恒、存读档和完整回归通过为前提。没有改善或改变语义的优化应回退。
### 4. Regression, formatting, and commit evidence
- 回归至少包含:同 seed 同输入输出摘要一致、交易数量/金钱守恒、存档读档 round-trip、现有 M5/M6/M7 验收、中文 UI 和视觉展示测试。
- 每个验收小步运行 `dotnet build ... --configuration Release`、相关 `dotnet test`、`git diff --check`;若仓库工具链可用,再运行 `dotnet format LivingVillage.sln --verify-no-changes --no-restore`,格式检查失败不得隐藏。
- 按可验收小步提交:质量基线/结构设计、失败测试和模型、最小实现、绘制集成、证据和文档分别提交;每个提交都要有测试结果,不把整轮大改留到最后。
- 每次汇报同时给出 `git rev-parse --short HEAD`、`git rev-list --left-right --count origin/main...HEAD`、`git log --oneline origin/main..HEAD` 和 `git status --short`。本地领先不等于远程可见;只有远端引用或推送结果明确变化时才报告已同步,不能把 busy/运行中当作完成。
---
### Task 0: 建立当前实现的结构与性能基线
**Files:**
- Create: `src/LivingVillage.Headless/PerformanceProbe.fs`
- Modify: `src/LivingVillage.Headless/LivingVillage.Headless.fsproj`
- Create: `src/LivingVillage.Kernel.Tests/PerformanceTests.fs`
- Modify: `src/LivingVillage.Kernel.Tests/LivingVillage.Kernel.Tests.fsproj`
- Modify: `docs/assets-and-licenses.md` only if the probe creates a new artifact type
- [ ] **Step 1: 写基线/回归测试和所有权说明**
在不改变 `Sim.step` 的前提下,先固定 seed、NPC 数量、tick 数和输入序列;增加或整理同 seed 同输入回归、交易守恒、存读档 round-trip 测试。测试文档明确 `World.Npcs` 只读、step 返回快照以及 `Array.copy`/`ResizeArray` 的所有权边界。
- [ ] **Step 2: 添加可重复性能探针**
用固定配置预热后重复测量 `Sim.step`,输出 tick 吞吐、`GC.GetAllocatedBytesForCurrentThread` 分配量和 `GC.CollectionCount(0..2)`,同时输出 seed/NPC/tick/runtime 配置。探针不能引入全局可变模拟状态,也不能改变正式 headless 验收路径。
- [ ] **Step 3: 运行基线并保存原始证据**
Run: `dotnet test src/LivingVillage.Kernel.Tests/LivingVillage.Kernel.Tests.fsproj --configuration Release --filter FullyQualifiedName~Performance`
再运行探针的固定配置命令,将完整 stdout、环境和 commit hash 保存到 `artifacts/chinese-village-prototype/<UTC-stamp>/performance-baseline/`。此处只记录事实,不设置未经测量的性能承诺。
- [ ] **Step 4: 完成基线小步提交**
在测试和原始数据可复核后单独提交;提交前检查 status/diff/log,只 stage 本任务文件,并汇报本地与 `origin/main` 的可见状态。
### Task 1: 建立可测试的样板展示模型
**Files:**
- Create: `src/LivingVillage.Desktop/VillagePresentation.fs`
- Create: `src/LivingVillage.Desktop.Tests/PrototypeTests.fs`
- Modify: `src/LivingVillage.Desktop/LivingVillage.Desktop.fsproj:8-14`
- Modify: `src/LivingVillage.Desktop.Tests/LivingVillage.Desktop.Tests.fsproj:8-12`
- [ ] **Step 1: 写失败测试**
覆盖确定性江南场景至少包含白墙黛瓦民居、桥、河岸、石板路、竹子和菜园;验证门口判断、进出民居状态、四向输入映射、动画帧随 tick 变化、NPC 外观按 ID 可区分。
- [ ] **Step 2: 运行测试确认失败**
Run: `dotnet test src/LivingVillage.Desktop.Tests/LivingVillage.Desktop.Tests.fsproj --configuration Release --filter FullyQualifiedName~Prototype`
Expected: 因 `VillagePresentation` 和测试所需类型尚不存在而失败,不得把编译错误误当作测试通过。
- [ ] **Step 3: 实现最小纯函数模块**
定义 `VillageProp`、`Direction`、`CharacterStyle`、`HomeMode`、带明确单位的场景坐标和 `PrototypeScene`;提供 `scene`、`isNearHomeDoor`、返回明确失败分支的民居切换函数、`directionForInput`、`animationFrame`、`characterStyle` 及中文文案常量。场景坐标固定、无随机副作用,民居门口位于玩家初始镜头可到达区域。输入与室内状态不能使用全局可变变量。
- [ ] **Step 4: 运行测试确认通过**
Run: `dotnet test src/LivingVillage.Desktop.Tests/LivingVillage.Desktop.Tests.fsproj --configuration Release --filter FullyQualifiedName~Prototype`
Expected: Prototype 测试全部通过。
### Task 2: 先测试再替换中文菜单与互动文案
**Files:**
- Modify: `src/LivingVillage.Desktop.Tests/PrototypeTests.fs`
- Modify: `src/LivingVillage.Desktop/MenuState.fs`
- Modify: `src/LivingVillage.Desktop/Interaction.fs`
- Modify: `src/LivingVillage.Desktop/M6Presentation.fs`
- Modify: `src/LivingVillage.Kernel.Tests/TradeTests.fs` only when a missing invariant needs a focused regression test; do not change Kernel behavior just to translate UI
- [ ] **Step 1: 添加中文行为断言并确认失败**
断言菜单项目、操作说明、设置标签、互动标题、需求标签、对话意图、昼夜和速度文案不再包含现有英文正式 UI 标签,并包含“开始新游戏”“读取存档”“互动”“需求”等中文文本。
Run: `dotnet test src/LivingVillage.Desktop.Tests/LivingVillage.Desktop.Tests.fsproj --configuration Release --filter FullyQualifiedName~Chinese`
- [ ] **Step 2: 用最小改动替换展示层字符串**
保持 Kernel DU、命令、状态转换和交易算法不变,只把展示层接到已有 `Sim.quotePrice`/`Sim.trade` API;交易 UI 必须展示报价、数量、成功/失败中文结果,并验证食物数量和金钱守恒。将原始 `Sim.annalText`/失败值转换为中文维护友好的 formatter;日志可以继续保留机器可读字段,但窗口内正式 UI 不显示调试 HUD。
- [ ] **Step 3: 解决输入优先级和状态重置**
当前 `Game.fs` 已用 `E` 触发对话,不能无条件复用为进出民居。定义可测试的输入优先级或分离按键;新建、读取、返回菜单和退出时明确重置 `HomeMode`/展示状态,测试对话和民居路径互不串线。
- [ ] **Step 4: 重新运行过滤测试**
Run: `dotnet test src/LivingVillage.Desktop.Tests/LivingVillage.Desktop.Tests.fsproj --configuration Release --filter FullyQualifiedName~Chinese`
Expected: 中文测试全部通过。
### Task 3: 集成原创程序化像素场景与角色动画
**Files:**
- Modify: `src/LivingVillage.Desktop/Game.fs`
- Modify: `src/LivingVillage.Desktop/VillagePresentation.fs`
- Create: `src/LivingVillage.Desktop/VillageArt.fs`
- Create: `src/LivingVillage.Desktop/ChineseText.fs`
- Modify: `src/LivingVillage.Desktop/LivingVillage.Desktop.fsproj`
- Modify: `docs/assets-and-licenses.md`
- [ ] **Step 1: 扩展基础地图和镜头内布局**
保留 32×32 瓦片和现有模拟坐标,增加确定性的河道、河岸、石板路和桥面;场景装饰使用固定 tile 坐标,保证启动时能看到民居、道路和河岸。
- [ ] **Step 2: 绘制原创像素资源**
在 `VillageArt` 中运行时生成带透明边缘的基础瓦片和角色纹理,并用 SpriteBatch 绘制白墙黛瓦房、门窗、桥栏、竹叶、菜畦、芦苇、石灯和水面波纹。`Game.fs` 只组合调用,不承载所有图形细节。资源不从网络下载,许可证清单明确标为仓库原创程序化资源。
- [ ] **Step 3: 加入可进入民居和角色表现**
玩家靠近门口按 `E` 进入/离开简化室内;室内显示床、桌、灶和窗,不暂停 Kernel。玩家与 NPC 使用四方向两帧动画,NPC 颜色、衣服和帽子按 `NpcId` 稳定区分;输入方向来自真实移动向量,NPC 方向来自当前位置到目标点。
- [ ] **Step 4: 重绘中文 UI 并移除调试 HUD**
在 `ChineseText`/文本绘制边界中补齐阶段一所需简体中文字形、换行和缺字失败行为;测试实际渲染字符串不能回退成 `?`。保留清晰的中文状态卡片、对话/交易/需求信息、时间和昼夜色调;不再把 fps、tick、NPC action、panel 等调试字段放进窗口标题或正式 HUD。模块文档说明字形表范围、像素单位、换行限制和性能取舍。
- [ ] **Step 5: 运行完整桌面测试和 Release 构建**
Run: `dotnet build LivingVillage.sln --configuration Release --no-restore && dotnet test LivingVillage.sln --configuration Release --no-build`
Expected: 构建 0 warning/0 error,原有测试和新增 Prototype/Chinese 测试全部通过。
### Task 4: 采集可复核的视觉交付证据
**Files:**
- Create: `/home/somhairle/projects/living-village/artifacts/chinese-village-prototype/<UTC-stamp>/`
- Modify: `docs/assets-and-licenses.md`
- [ ] **Step 1: 运行真实桌面程序**
使用现有 Linux 图形环境或 `xvfb-run`,记录命令、环境、启动日志和退出码;不得只生成概念图。
- [ ] **Step 2: 采集昼、夜、室内和互动状态**
保存至少四张实际窗口截图和一段短视频,文件名明确标识 `day`、`night`、`home`、`dialogue`,同时保存控制步骤/日志。
- [ ] **Step 3: 复核验收边界**
检查截图确实包含江南场景元素、四向角色、中文 UI、交易成功/失败、需求状态和无调试 HUD;检查许可证清单、性能基线/优化对比、格式静态检查、Git diff、M3 PID 和冻结目录未被改动。
- [ ] **Step 4: 输出结果**
只有结构设计、质量基线、所有新增测试、性能对比、完整视觉证据、提交状态和边界检查全部具备时输出 `READY_FOR_LEADER_REVIEW`;否则输出带具体原因和绝对路径的 `BLOCKED(...)`,不夸大 macOS Finder 签名状态,不宣称高性能或完整中文维护性已经完成,也不宣称完整村庄已经完成。
|