summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--docs/overnight-status.md11
-rw-r--r--src/LivingVillage.Desktop.Tests/LivingVillage.Desktop.Tests.fsproj1
-rw-r--r--src/LivingVillage.Desktop.Tests/P48MapDigestTests.fs62
3 files changed, 74 insertions, 0 deletions
diff --git a/docs/overnight-status.md b/docs/overnight-status.md
index 7fc7854..9028a66 100644
--- a/docs/overnight-status.md
+++ b/docs/overnight-status.md
@@ -132,3 +132,14 @@
- P47 整改验收 push 后,**P48(512×384 地图生成独立验收切片 / 备选长局内存 profile)已派同一 writer**(POST /session/{sid}/prompt_async 204)。
- 派发后回读最后一条 assistant assistant info.providerID=**go-b** / modelID=**deepseek-v4.1-flash** ✅(通道未漂移)。
- 验收目标:同 seed 两次生成 digest 一致 + 不同 seed 发散自动化条目(或转长局内存 profile 数字证据)+ 全量测试绿。
+
+## Tick 2026-09-28 22:1x CST(P48 完成:512×384 digest 验证条目)
+- 检查结论:512×384 参数化生成**已完整**(`paramsForSize 512 384` 4 条河、≥28 民居 2/3/4 三档宽、组团/农田/主路确定性等均已有测试),唯一未收口 = 缺「digest 形式」的同 seed 一致 / 异 seed 发散验证;故按单第 1 条执行,未触发第 2 条(长局内存 profile)。
+- 新增 `src/LivingVillage.Desktop.Tests/P48MapDigestTests.fs`(已写入 fsproj,位列 SampleTests 前),4 条:同 seed digest 稳定 / 异 seed 发散 / 同 seed 跨尺寸发散 / 512 seed=4242 digest 钉值。
+- digest = `SHA-256(MapGen.serialize map)` hex(64 字符):
+ - 512×384 seed=4242 = `904A20148C0BA385E95A1EF53B0E7ECCB08653A557D4FD49F0EED6B57857DAD0`
+ - 512×384 seeds 1/2/7/99991 = `9C1784138ED3D967…` / `88120BD7315992D4…` / `CC401AC55E2805A5…` / `69A95DB300F76847…`(5 seed 两两不同)
+ - 同 seed 4242:64×48 = `C6468FBA968A83A8470EC177DBD75C06A239362FDE061E380537A97ADB9FA98F`、256×192 = `C3B4C6D44D72179F62A181325E7498C4B720F40B26A078F1C65861B2BE8E88C2`、512×384 = `904A2014…`(三者不同)
+- build 绿证据:`dotnet build LivingVillage.sln -c Release` → **0 错误 0 警告**;Desktop **250/250**、Kernel **119/119**(build 后 `--no-build` 重跑)。
+- 未改 Kernel/Sim/HUD/对话框,未引外部素材;范围仅新增测试 + 单文件。
+- 范围外留下一单:Sim 长局内存 profile(进程 RSS + 事件历史 `Events`/`Rumors`/`Annals` 增长量化,50×10~20 天流式口径),待下 tick 派发。
diff --git a/src/LivingVillage.Desktop.Tests/LivingVillage.Desktop.Tests.fsproj b/src/LivingVillage.Desktop.Tests/LivingVillage.Desktop.Tests.fsproj
index 045c1dc..2f698f0 100644
--- a/src/LivingVillage.Desktop.Tests/LivingVillage.Desktop.Tests.fsproj
+++ b/src/LivingVillage.Desktop.Tests/LivingVillage.Desktop.Tests.fsproj
@@ -27,6 +27,7 @@
<Compile Include="P45CharacterAnimTests.fs" />
<Compile Include="P46MenuAmbienceTests.fs" />
<Compile Include="P47SceneDetailTests.fs" />
+ <Compile Include="P48MapDigestTests.fs" />
<Compile Include="SampleTests.fs" />
</ItemGroup>
diff --git a/src/LivingVillage.Desktop.Tests/P48MapDigestTests.fs b/src/LivingVillage.Desktop.Tests/P48MapDigestTests.fs
new file mode 100644
index 0000000..b8b084c
--- /dev/null
+++ b/src/LivingVillage.Desktop.Tests/P48MapDigestTests.fs
@@ -0,0 +1,62 @@
+namespace LivingVillage.Desktop.Tests
+
+open System
+open System.Security.Cryptography
+open System.Text
+open Microsoft.VisualStudio.TestTools.UnitTesting
+open LivingVillage.Desktop
+
+/// P48:512×384 地图生成的独立可验收小步(既有参数化生成器已完整,故只补 digest 验证条目)。
+///
+/// 以 `SHA-256(MapGen.serialize map)` 作为生成结果 digest,锁定:
+/// * 同 seed 两次生成 digest 一致(跨调用稳定、纯函数);
+/// * 不同 seed digest 发散;
+/// * 同 seed 不同尺寸 digest 不同(尺寸确被参数化纳入生成);
+/// * 512×384 / seed 4242 的具体 digest 钉住,作为回归护栏。
+[<TestClass>]
+type P48MapDigestTests () =
+
+ let digestOf (map: MapGen.Result) : string =
+ use sha = SHA256.Create()
+ MapGen.serialize map
+ |> Encoding.UTF8.GetBytes
+ |> sha.ComputeHash
+ |> Convert.ToHexString
+
+ [<TestMethod>]
+ member _.SameSeed512DigestIsStableAcrossRuns () =
+ let a = MapGen.generateWithSize 512 384 (uint64 4242)
+ let b = MapGen.generateWithSize 512 384 (uint64 4242)
+ let da = digestOf a
+ let db = digestOf b
+ Assert.AreEqual<int>(64, da.Length)
+ Assert.IsTrue((da = db), "same seed must yield an identical digest")
+ Assert.IsTrue((da = digestOf a), "digest must be a pure function of the map")
+
+ [<TestMethod>]
+ member _.DifferentSeeds512DigestDiverge () =
+ let seeds = [ 1UL; 2UL; 7UL; 4242UL; 99991UL ]
+ let digests = seeds |> List.map (fun s -> digestOf (MapGen.generateWithSize 512 384 s))
+ for (s, d) in List.zip seeds digests do
+ printfn "P48 digest 512x384 seed=%d = %s" s d
+ Assert.IsTrue((digests |> List.distinct |> List.length = seeds.Length),
+ "every seed must yield a distinct digest")
+
+ [<TestMethod>]
+ member _.SameSeedDigestDiffersAcrossMapSizes () =
+ let d64 = digestOf (MapGen.generateWithSize 64 48 (uint64 4242))
+ let d256 = digestOf (MapGen.generateWithSize 256 192 (uint64 4242))
+ let d512 = digestOf (MapGen.generateWithSize 512 384 (uint64 4242))
+ printfn "P48 digest 64x48 seed=4242 = %s" d64
+ printfn "P48 digest 256x192 seed=4242 = %s" d256
+ printfn "P48 digest 512x384 seed=4242 = %s" d512
+ Assert.IsTrue((d64 <> d256), "64x48 and 256x192 digests must differ")
+ Assert.IsTrue((d256 <> d512), "256x192 and 512x384 digests must differ")
+ Assert.IsTrue((d64 <> d512), "64x48 and 512x384 digests must differ")
+
+ [<TestMethod>]
+ member _.Pinned512DigestLocksGeneratorOutput () =
+ let digest = digestOf (MapGen.generateWithSize 512 384 (uint64 4242))
+ printfn "P48 digest 512x384 seed=4242 = %s" digest
+ Assert.IsTrue((digest = "904A20148C0BA385E95A1EF53B0E7ECCB08653A557D4FD49F0EED6B57857DAD0"),
+ sprintf "512x384 seed=4242 digest pinned, was %s" digest)