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）与目标在任务面板的中文展示（属后续独立切片；本单只落状态与判定）。
