summaryrefslogtreecommitdiff
path: root/docs/evidence/p66-verification.txt
blob: 8221027c2fdc404602cc8f36d14846e450ccba47 (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
P66(职业收尾切片:每日任务目标具体化 TargetNpc/TargetTile)验证记录
基线:commit cf6672e(P66 补充限定记录)。本单未 push。

范围与设计(design §2.4-3,仅此一条)
- DailyTask 的 TargetNpc/TargetTile 从恒 None(通配)改为按 hash 在**可达集合**内定点。
- 纯 Kernel 加函数 + Desktop 接线;禁改 Sim.fs/Sim.step(本单 `git diff -- src/LivingVillage.Kernel/Sim.fs` 为空)。
- 可达集合由世界/样板场景派生(WorldBootstrap.reachableTargets):
  - NPC = 世界中实际存在的村民 id(30 个开局 → 0..29)。
  - 瓦片 = 样板场景菜地 VegetableGarden 的世界瓦片 (33,25)/(34,25)——设计口径「自家地块」,legacy/riverscape 一致。
- 定点 = splitmix 同源的另一段流:`taskHash (seed ⊕ salt) occupationSeed dayIndex mod |候选|`,
  候选先排序(NPC 按 id、瓦片按 (x,y))以消除输入顺序影响;禁 System.Random。

每条模板的定点影响(关键:不做超范围语义变更)
- 帮工 HelpWork → **TargetNpc 定点**(既有 satisfiesCompletion 已读 `Some target -> target = npc`);
  现在玩家必须与指定村民对话才完成,非目标村民不完成(新单测断言)。
- 翻土 TillSoil → **TargetTile 定点**(既有 `Some target -> target = (tileX,tileY)`);
  现在必须到达指定地块才完成(新单测断言)。
- 其余 8 模板(送粮/夜捕/卖渔/询价/收货/转卖/观察记事/论理)的 satisfiesCompletion **不读目标**,
  故目标保持 None(通配),完成语义逐字节不变;不制造「有目标却不判定」的死数据。
- 历史口径保留:`Occupation.dailyTaskOf` / `refreshToday` / `refreshState` / `WorldBootstrap.occupationStateFor`
  / `refreshOccupationToday` 仍走空候选(目标恒 None),既有调用点/测试不受影响;
  定点走新增的 `dailyTaskOfWith` / `refreshTodayWith` / `refreshStateWith` /
  `WorldBootstrap.occupationStateForWorld` / `refreshOccupationTodayWorld`(Game 真实开局与跨日刷新已切换)。

改动文件
- src/LivingVillage.Kernel/Occupation.fs(TaskTargets + targetNpcOf/targetTileOf + dailyTaskOfWith/refreshTodayWith/refreshStateWith;旧入口保留为通配包装)
- src/LivingVillage.Desktop/WorldBootstrap.fs(reachableTargets + occupationStateForWorld/refreshOccupationTodayWorld)
- src/LivingVillage.Desktop/Game.fs(StartNewGame、逐帧跨日刷新、P55 证据刷新、P31 剧情证据改用世界候选定点)
- src/LivingVillage.Desktop.Tests/P66TaskTargetTests.fs(新,8 例)+ .fsproj 挂载
- scripts/p66-target-report.fsx(新,可复跑证据生成)+ docs/evidence/p66-analysis.txt

红先
- 先建 P66TaskTargetTests.fs 引用未实现的 TaskTargets/reachableTargets/occupationStateForWorld/
  refreshOccupationTodayWorld/dailyTaskOfWith → 暂存实现文件后编译红(FS0039/FS0041),恢复后转绿。

构建/测试
- dotnet build LivingVillage.sln -c Release → 0 错误,1 警告(P40ArtTests.fs FS0760,既有)
- dotnet test src/LivingVillage.Desktop.Tests -c Release --no-build → 328/328(320→+8,P66TaskTargetTests)
- dotnet test src/LivingVillage.Kernel.Tests -c Release --no-build → 119/119
- P54ProfessionDailyTests / P55ProfessionRewardTests 全绿:二者手工构造的任务目标恒 None,
  定点不触碰其完成语义。

证据(真实 Release 程序集,可复跑)
- dotnet fsi scripts/p66-target-report.fsx → docs/evidence/p66-analysis.txt,verdict: PASS
  - seed=42 / 30 NPC / 可达瓦片 (33,25),(34,25)
  - 4 职业 × 60 天 = 240 条:帮工定点 NPC=22、翻土定点瓦片=16、其余保持通配=202
  - 目标 ∈ 可达集合 = true;同输入两次逐字节一致 = true;历史 dailyTaskOf 目标全 None

确定性 / 存档
- dotnet run -c Release --project src/LivingVillage.Headless -- --performance-baseline ×3
  → final_digest 全等 953775FAEB2FDDE97289491AA260BD8D390C571E48A7A13AD2CB6FB7124F7F6C,determinism=PASS
- save(None) 仍 LV_WORLD_SAVE_V2 且 = saveWith None world(单测逐字节);v3(含定点目标)round-trip 稳定,
  same-input 两次写盘文本逐字节一致。

边界
- 未改 Sim.fs/Sim.step、HUD/对话框结构、字形表、地图 seed、外部素材;未 push。
- 未做 §2.4-5(旧档→新档迁移 UI)与目标在任务面板的中文展示(属后续独立切片;本单只落状态与判定)。