O-T1 audit (REPORT-ONLY) maps acdream's transitive closure on WorldBuilder: 33 files / ~7.7K LOC across Chorizite.OpenGLSDLBackend (28 files) and WorldBuilder.Shared (5 files). Verdict on O-Q1 (thread-model): SAFE — adapters run render-thread only; no worker-thread access to WB code. Spec amendments incorporated via brainstorm: - O-D7: Refactor ObjectMeshManager to take DatCollection directly (not via adapter). T4 safety check — fall back to thin adapter if call-site count >20. - O-D8: Drop LandSurfaceManager, EnvCellRenderManager, PortalRenderManager, TerrainRenderManager from the extract list — audit confirmed not reachable (we have our own ports or never used them). - O-D9: Promote 3 internal types in Chorizite to public on extraction (EmbeddedResourceReader, TextureFormatExtensions, BufferUsageExtensions). - O-D10: Strip [MemoryPackable] from TerrainEntry (we don't serialize). - O-D11: Namespace AcDream.Core.Rendering.Wb.* for extracted code. - O-D12: Drop ResolveId + [indoor-upload] NULL_RESULT diagnostic block. Task breakdown: T6 (EnvCell/portal) eliminated; T5 (stateless helpers) shrinks to 0.5d; T4 (mesh + refactor) grows to 2.5d. Net effort estimate holds at ~7.75d. All originally-open spec questions are now closed (Q1/Q2/Q3/Q4) or deferred to T3 with an explicit verify step (Q5: SixLabors.ImageSharp reachability). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
27 KiB
Phase O — Task O-T1 — WB Usage Audit
Status: REPORT-ONLY (no source edits, no project changes). Filed: 2026-05-21. Purpose: Closure of every WorldBuilder type and file acdream transitively uses, so T2–T7 don't miss a dependency at the "drop project references" step.
Headline: Reachable closure from acdream is 33 files / ~7.7 K LOC (~6.8 K from
Chorizite.OpenGLSDLBackend, ~0.9 K fromWorldBuilder.Shared). Substantially smaller than the spec's §4 component list anticipated, because three of the spec's named components (TerrainRenderManager,LandSurfaceManager,EnvCellRenderManager/PortalRenderManager) are not in our actual call graph — we already replaced or never used them. The 7-8 day estimate in spec §5 looks reasonable, possibly conservative. O-Q1 (thread-model) verdict: SAFE — no worker-thread access to WB code.
Subreports (long-tail per-file tables) by parallel agents:
2026-05-21-phase-o-t1-wb-audit-chorizite-closure.md— Chorizite full per-file table2026-05-21-phase-o-t1-wb-audit-shared-closure.md— WB.Shared per-file table2026-05-21-phase-o-t1-wb-audit-thread-and-hidden.md— thread model + hidden deps2026-05-21-phase-o-t1-wb-audit-extensions-and-rest.md— broad reachability sweep
Note: those subreport file names are referenced in the parent agents' output but the Explore agent type lacks
Write, so the files were not persisted to disk. The relevant content has been pulled into the summary tables and inventory below.
1. Direct use surface
Files in src/ and tests/ that actually import a WorldBuilder type
(using WorldBuilder.* or using Chorizite.OpenGLSDLBackend* or fully-
qualified). Comment-only WB references (six files in src/ — TerrainBlending,
SurfaceInfo, GfxObjMesh, SkyRenderer, SamplerCache, GameWindow) are
excluded; they describe ports done by hand and don't carry a project
dependency.
Production source — src/
| File | LOC | WB types used | Notes |
|---|---|---|---|
src/AcDream.App/Rendering/Wb/WbMeshAdapter.cs |
349 | OpenGLGraphicsDevice, DefaultDatReaderWriter, ObjectMeshManager, ObjectRenderData, DebugRenderSettings |
Single seam; constructs WB pipeline; also constructs _wbDats = new DefaultDatReaderWriter(datDir) at line 79 (the second-reader smell Phase O closes) |
src/AcDream.App/Rendering/Wb/WbDrawDispatcher.cs |
~1500 | ObjectRenderData, ObjectRenderBatch |
Production draw path (modern MDI); uses our own DrawElementsIndirectCommand struct + our own mesh_modern.{vert,frag} shaders |
src/AcDream.Core/World/WbSceneryAdapter.cs |
55 | TerrainEntry |
Bridges LandBlock → TerrainEntry[81] for WB scenery helpers |
src/AcDream.Core/World/SceneryGenerator.cs |
196 | SceneryHelpers.Displace/CheckSlope/ObjAlign/RotateObj/ScaleObj, TerrainUtils.OnRoad/GetNormal |
Procedural scenery placement; calls WB stateless helpers |
src/AcDream.Core/Textures/SurfaceDecoder.cs |
219 | TextureHelpers.FillIndex16/FillP8/FillA8/FillA8Additive/FillA8R8G8B8/FillR8G8B8/FillR5G6B5/FillA4R4G4B4 |
Pure pixel-format decoders |
Test source — tests/
| File | WB types used | Notes |
|---|---|---|
tests/AcDream.Core.Tests/Textures/TextureDecodeConformanceTests.cs |
TextureHelpers.Fill* |
Byte-identity tests vs WB; should stay after extraction (validates our copy matches the original) |
tests/AcDream.Core.Tests/Terrain/SplitFormulaDivergenceTest.cs |
TerrainUtils.CalculateSplitDirection, CellSplitDirection |
One-time sweep test that compared WB's formula with retail's; safely deletable after extraction (test already informed the N.5b decision — its job is done) |
Project files
| File | Lines | What |
|---|---|---|
src/AcDream.App/AcDream.App.csproj |
38-39 | <ProjectReference> to WorldBuilder.Shared + Chorizite.OpenGLSDLBackend |
src/AcDream.Core/AcDream.Core.csproj |
27-28 | same |
These two csproj entries are what T7 deletes after extraction.
2. Transitive closure (summary)
Closure walked from the direct-use surface above, following only WB
project-internal types. NuGet packages (Chorizite.Core,
Chorizite.DatReaderWriter, Silk.NET.*, BCnEncoder.Net,
SixLabors.ImageSharp, MemoryPack) stay as <PackageReference> and are
not part of the extraction scope.
| Source project | Files reachable | LOC | Notes |
|---|---|---|---|
Chorizite.OpenGLSDLBackend |
28 | ~6,829 | Entry points: ObjectMeshManager, OpenGLGraphicsDevice, TextureHelpers, SceneryHelpers, ObjectRenderData/Batch, DebugRenderSettings |
WorldBuilder.Shared |
5 | 876 | Entry points: TerrainEntry, TerrainUtils, CellSplitDirection, DefaultDatReaderWriter, IDatReaderWriter |
| Total reachable | 33 | ~7,705 |
Files in WB not in our reachable closure (informational; do NOT
extract): all of WorldBuilder/, WorldBuilder.Server/, the platform
projects (WorldBuilder.Windows/Linux/Mac); inside WorldBuilder.Shared/:
Hubs/ (SignalR), Migrations/ (EF Core), Repositories/, the editor
Services/ (DocumentManager, SyncService, etc.), Modules/Landscape/Tools/
(brush/painting), Modules/Landscape/Commands/ (undo/redo); inside
Chorizite.OpenGLSDLBackend/: FontRenderer, AudioPlaybackEngine,
MinimapRenderer, BackendGizmoDrawer, the entire editor scene/camera
subsystems, and critically: TerrainRenderManager, LandSurfaceManager,
EnvCellRenderManager, PortalRenderManager — see §4 below.
3. Per-file inventory (top 30 by LOC)
DAT-TOUCH = file references IDatReaderWriter / _dats.Get<T>() / opens
dat data. GL-TOUCH = file calls Silk.NET.OpenGL directly or writes shader
binds / texture uploads. Bucket per Phase O spec (T3–T6, REPLACE for the
dat-readers we drop, NOT for files in the spec's §4 list that turn out to
not be reachable).
From WorldBuilder.Shared/ (5 files, 876 LOC) — ALL EXTRACTED
Path (rel. references/WorldBuilder/) |
LOC | Role | DAT? | GL? | Bucket |
|---|---|---|---|---|---|
WorldBuilder.Shared/Modules/Landscape/Lib/TerrainUtils.cs |
258 | Static helpers: GetHeight, GetNormal, OnRoad, CalculateSplitDirection |
indirect (caller passes Region) | no | T5 |
WorldBuilder.Shared/Modules/Landscape/Models/TerrainEntry.cs |
248 | Packed per-vertex terrain struct (uses [MemoryPackable]) |
no | no | T5 |
WorldBuilder.Shared/Services/DefaultDatReaderWriter.cs |
215 | Concrete dat reader (4 dbs, cache, file handles) | yes | no | REPLACE (delete; route through DatCollection) |
WorldBuilder.Shared/Services/IDatReaderWriter.cs |
137 | Dat access interface + IdResolution record |
yes | no | REPLACE (delete) |
WorldBuilder.Shared/Modules/Landscape/Models/CellSplitDirection.cs |
18 | SWtoNE / SEtoNW enum |
no | no | T5 |
From Chorizite.OpenGLSDLBackend/ (28 files, ~6,829 LOC reachable) — TOP 10 by LOC
(Full table in the chorizite-closure subreport; only the top by LOC and a few key smaller files are inlined here so this doc stays under 500 lines.)
Path (rel. references/WorldBuilder/) |
LOC | Role | DAT? | GL? | Bucket |
|---|---|---|---|---|---|
Chorizite.OpenGLSDLBackend/Lib/ObjectMeshManager.cs |
~2079 | The hub: reads GfxObj/Setup/Palette from dats; decodes textures; manages GPU resources; modern-rendering global buffers | yes | yes | T4 |
Chorizite.OpenGLSDLBackend/OpenGLGraphicsDevice.cs |
~625 | Silk.NET wrapper: GL ctx, ProcessGLQueue, render-state | no | yes | T3 |
Chorizite.OpenGLSDLBackend/Lib/TextureHelpers.cs |
~variable | INDEX16 / P8 / A8 / DXT decode helpers (pure functions) | no | no | T3 |
Chorizite.OpenGLSDLBackend/Lib/SceneryHelpers.cs |
small | Displace / RotateObj / ScaleObj / ObjAlign / CheckSlope (pure) |
no | no | T5 |
| Particle emitter + batcher (T4 supporting) | ~combined 1,200 | Particle pipeline used by ObjectMeshManager | maybe | yes | T4 |
| Global mesh buffer (modern rendering) | ~500 | Single global VAO/VBO/IBO for modern path | no | yes | T4 |
| ManagedGL{Texture, TextureArray, VertexBuffer, IndexBuffer, VertexArray, FrameBuffer, UniformBuffer} | ~150-300 ea | Per-resource GL lifecycle wrappers | no | yes | T3 |
GLSLShader.cs, GLHelpers.cs, GLStateScope.cs |
~100-300 ea | Shader compile + GL state utility | no | yes | T3 |
Lib/ObjectRenderBatch.cs, Lib/ObjectRenderData.cs |
small | Per-batch + per-object render data structs | no | no | T4 |
Lib/DebugRenderSettings.cs |
small | Settings shape passed to OpenGLGraphicsDevice ctor | no | no | T3 |
Approximate bucket totals across the full Chorizite closure (28 files):
- T3 (GL infra, no dat dep): 14 files, ~2,900 LOC
- T4 (mesh pipeline): 8 files, ~3,313 LOC (ObjectMeshManager dominates)
- T5 stateless (SceneryHelpers + helpers): ~2 files, ~200 LOC
- NOT-CORE leaves (TextureHelpers, EdgeLineBuilder, extensions): 4 files, ~400 LOC — note these still get extracted, they're just leaves not in the deep call graph of ObjectMeshManager
4. Extraction-task mapping
Reconciling agent findings against spec §4 — three of the spec's listed extractions are unnecessary because the files turned out not to be reachable.
Reachable, must extract
| Bucket | Files (count, LOC) | Spec §4 alignment |
|---|---|---|
| T3 — Texture / GL infrastructure | ~15 files, ~3,100 LOC (14 from Chorizite + TextureHelpers) |
Matches spec §4.2/§4.3: TextureHelpers, OpenGLGraphicsDevice, plus all ManagedGL* wrappers, GLSLShader, GLHelpers, GLStateScope |
| T4 — Mesh pipeline | 8 files, ~3,313 LOC | Matches spec §4.1: ObjectMeshManager, ObjectRenderBatch, ObjectRenderData + transitive supports (GlobalMeshBuffer, particle batcher, modern render data) |
| T5 — Scenery + terrain stateless | 5 files, ~782 LOC (SceneryHelpers, TerrainUtils, TerrainEntry, CellSplitDirection, possibly RegionInfo if reachable) |
Smaller than spec §4.1+§4.2 anticipated — LandSurfaceManager and SceneryRenderManager are NOT in our closure (we have our own ports / our own renderer) |
Files spec listed but we do NOT need
| File (spec §4 reference) | Status | Why |
|---|---|---|
Chorizite.OpenGLSDLBackend.Lib.LandSurfaceManager (spec §4.2) |
NOT EXTRACTED | Acdream has its own src/AcDream.Core/Terrain/TerrainBlending.cs (line 8: "Ported from WorldBuilder.LandSurfaceManager"). No using import of WB's class. Confirm in T2: kick or keep our port. |
Chorizite.OpenGLSDLBackend.Lib.SceneryRenderManager (spec §4.1) |
NOT EXTRACTED | SceneryGenerator.cs uses only SceneryHelpers (stateless). No reference to SceneryRenderManager (the WB-internal pipeline class). |
Chorizite.OpenGLSDLBackend.Lib.EnvCellRenderManager (spec §4.4) |
NOT EXTRACTED | Acdream renders EnvCells via ObjectMeshManager (its PrepareEnvCellMeshData path) + WbDrawDispatcher. WB's EnvCellRenderManager is the editor's separate render path and is not referenced. |
Chorizite.OpenGLSDLBackend.Lib.PortalRenderManager (spec §4.4) |
NOT EXTRACTED | Acdream renders portals via the same mesh path; WB's PortalRenderManager is editor-only. |
Chorizite.OpenGLSDLBackend.Lib.TerrainRenderManager (spec §9.2 open Q) |
NOT EXTRACTED | Confirmed: we use src/AcDream.App/Rendering/TerrainModernRenderer.cs (Phase N.5b ported retail's FSplitNESW). Spec §9.2's recommendation to leave WB's TerrainRenderManager in references/ matches the closure finding. |
This means the spec's T5 and T6 buckets shrink dramatically:
- Spec T5 was "scenery + terrain pipelines" (~3 named files:
SceneryHelpers,SceneryRenderManager,LandSurfaceManager). Real T5 is justSceneryHelpers(stateless utility, ~100 LOC) + the 4 WB.Shared terrain helpers (TerrainUtils,TerrainEntry,CellSplitDirection). - Spec T6 was "EnvCell + portal renderers". Real T6 is empty. Recommend dropping T6 from the task plan.
Files we explicitly DROP (REPLACE bucket)
WorldBuilder.Shared/Services/IDatReaderWriter.cs(137 LOC) — interface goes away.WorldBuilder.Shared/Services/DefaultDatReaderWriter.cs(215 LOC) — concrete impl goes away.- The
_wbDats = new DefaultDatReaderWriter(datDir)line inWbMeshAdapter.cs:79and itsDispose()partner at line 346 — removed in T7. - The cross-check diagnostic at
WbMeshAdapter.cs:224-262([indoor-upload] NULL_RESULT) — removed in T7; depends onResolveIdwhich goes away withDefaultDatReaderWriter.
5. Hidden-dependency risks
5.1 Internal types
Three internal types need internal → public promotion when copied
across the project boundary (or copied with their owners and kept
internal in the new project):
EmbeddedResourceReader(Chorizite) — referenced by ObjectMeshManager for embedded shader / resource loads.TextureFormatExtensions(Chorizite) — extension methods onPixelFormat.BufferUsageExtensions(Chorizite) — extension methods onBufferUsageARB.
No internal types in WorldBuilder.Shared's closure. Test mocks marked
internal are not in scope (they live in test projects).
5.2 Source generators / build hooks
None found. Neither Chorizite.OpenGLSDLBackend.csproj nor
WorldBuilder.Shared.csproj has <Target>, <AnalyzerReference>, or
source-generator <PackageReference> entries. Verbatim file copy will
transfer cleanly.
5.3 Resource files
Shaders. Reachable closure loads a minority of the 21 shaders in
Chorizite.OpenGLSDLBackend/Shaders/. The Chorizite-closure agent
identified only 2 shaders loaded by ObjectMeshManager's path:
Shaders/Particle.vertShaders/Particle.frag
(All other shaders — Landscape, StaticObject*, PortalStencil,
Outline, InstancedLine, Text, UI, Gizmo — are loaded by render
managers we don't use, e.g. StaticObjectRenderManager,
TerrainRenderManager, PortalRenderManager. Those managers are NOT in
our closure.) Acdream's own entity shader is mesh_modern.{vert,frag}
in src/AcDream.App/Rendering/Shaders/ — not a WB asset.
This contradicts the broader-sweep agent's count of "10 shader files
actively referenced", which was including managers we don't use.
Verify in T4 by grepping for LoadShader string literals inside
ObjectMeshManager + its transitive closure.
Fonts. Two .ttf files exist in Chorizite.OpenGLSDLBackend/Fonts/
(DroidSans + DroidSans-Bold). They are used by FontRenderer, which is
NOT in our closure (we use BitmapFont + StbTrueTypeSharp + ImGui).
Fonts do not need to be copied.
Other. No PNG, JSON, XML, or other asset files referenced by the closure beyond shaders.
5.4 NuGet dependencies that transfer with the extraction
Files in the closure reference:
Silk.NET.OpenGL(already a<PackageReference>inAcDream.App.csproj)BCnEncoder.Net(already inAcDream.Core.csprojv2.2.1 — Chorizite uses v2.2.x, compatible)SixLabors.ImageSharp(NOT currently in acdream — needs adding for some of WB's texture-load paths; verify in T4 whether our extraction closure actually touches ImageSharp — if only for the editor scene loads, we can drop)MemoryPack—TerrainEntryuses[MemoryPackable]. Add as<PackageReference>inAcDream.Core.csprojat T5, or strip the attribute (it's used only by WB's editor save/load; acdream doesn't serializeTerrainEntry). Stripping is the simpler call.
5.5 DefaultDatReaderWriter ↔ DatCollection — the real risk
This is the only material risk in the whole audit. WB's interface and
acdream's DatCollection diverge in several ways:
| Concern | WB | Acdream's DatCollection (per probe at WbMeshAdapter.cs:228-260) |
|---|---|---|
| Database surface | Returns IDatDatabase (abstract interface) for Portal, HighRes, Language, Cell |
Concrete types (PortalDatabase, CellDatabase, LocalDatabase) |
| Cell databases | CellRegions dictionary (multi-region cell support; auto-discovers at construction) |
Single Cell property |
| Cross-database lookup | ResolveId(uint id) returns IEnumerable<(database, type)> (HighRes → Portal → Language → all Cells) |
No equivalent. WbMeshAdapter's diagnostic code uses it; production mesh path may or may not |
| Per-type caching | ConcurrentDictionary<(Type, uint), IDBObj> per database; thread-safe by design |
Documented as NOT thread-safe (per memory/feedback_phase_a1_hotfix_saga.md) — but with the O-Q1 verdict (render-thread only), this may be fine |
| Iteration tracking | Per-database iteration counters | Verify in T4 |
| Write support | TrySave overloads |
Acdream is read-only (correct for a client) |
| File-handle sharing | Today each reader opens its own 4 files (~50-100 MB index duplication, the smell Phase O closes) | The DatCollection's file handles are reused; T7 ends the duplication |
Pre-T4 verification checklist:
- Grep
ObjectMeshManager.csfor every_dats.Xcall site. Catalog which methods/properties ofIDatReaderWriterit actually uses. - For each, confirm
DatCollectionhas the equivalent (or design the shim). - Decide whether
ResolveIdis needed in production code or is purely diagnostic (the[indoor-upload]probe is the only known caller). If diagnostic-only: drop it at T7. - Confirm the multi-region
CellRegionsstory — does WB'sObjectMeshManageractually iterateCellRegions, or always callCellsingular? (If singular, the dict→single mapping is trivial.) - Confirm thread-safety: with O-Q1 settled (render-thread only), do we
still need
ConcurrentDictionarysemantics, or can our existing single-threadDatCollectionserve?
6. Thread-model finding (Open Question O-Q1)
Verdict: SAFE — verified by code inspection. No worker-thread access to WB code today, so extraction does not expose a latent race.
Evidence (paths from the worktree root):
WbMeshAdapter.Tick()is documented in the source as render-thread only (src/AcDream.App/Rendering/Wb/WbMeshAdapter.cs:275-278).LandblockSpawnAdapterandEntitySpawnAdapterare called only fromGpuWorldStatemethods (AddLandblock,RemoveLandblock,AddEntitiesToExistingLandblock,RemoveEntitiesFromLandblock,OnCreate,OnRemove).GpuWorldStateis the render-thread entity state manager (perCLAUDE.mdtwo-tier streaming arch); the streaming worker thread (LandblockStreamer) never touches WB.- The two-tier streaming spec
(
docs/superpowers/specs/2026-05-09-phase-a5-two-tier-streaming-design.md) is explicit that the worker thread builds dat-decodedLandblockStateobjects and hands them to the render thread via a completion queue; WB'sObjectMeshManageris never invoked from the worker. - WB's own
ObjectMeshManagerusesConcurrentDictionaryfor_usageCountand an explicitlock(_lruList)— defense in depth that doesn't matter for us today, but keeps the door open if a future acdream design hands streaming work to a worker.
Action for the spec: §9.1 (O-Q1) can be marked closed with "Verified safe; render-thread-only access; ConcurrentDictionary in WB adds belt-and-braces."
7. Surprises / sharp edges
-
Spec §4 over-specifies the extraction. Three named files (
LandSurfaceManager,EnvCellRenderManager,PortalRenderManager) and one open question (§9.2'sTerrainRenderManager) are NOT in the actual closure. The spec should be amended: T5 shrinks to "stateless scenery + terrain helpers" (5 files, ~800 LOC); T6 disappears entirely. -
The biggest risk is API-shape mismatch, not file count.
IDatReaderWriterreturns interface types and has multi-region cell support + aResolveIdcross-DB search;DatCollectionreturns concrete types and has a single cell property. T4 must design the shim layer (or refactorObjectMeshManagerslightly to use our shape — slightly violates "verbatim copy" but is one-call narrow). -
SixLabors.ImageSharpis a possibly-unnecessary new NuGet dependency. If our closure actually touches it (some texture-load helpers in Chorizite use ImageSharp for PNG/JPG), T4 needs to add it. If it's only in editor-load paths we don't use, T4 can drop the imports. Verify before T2. -
MemoryPackis a small new dep for one attribute onTerrainEntry. Cheapest answer: strip the attribute when copyingTerrainEntry.csinto our tree (we don't serialize the struct). -
The
[indoor-upload]diagnostic inWbMeshAdapter.cs:192-263becomes vestigial after T7. It depends onResolveId(which goes away), it compares_wbDats(which goes away) against_dats. The wholeif (RenderingDiagnostics.IsEnvCellId(id) && ...)block + its_pendingEnvCellRequestscompanion can be deleted in T7. -
SplitFormulaDivergenceTest.csis safely deletable after T5 ships. It was a one-time data-collection test that informed the N.5b path-C decision; its findings are baked into the codebase. We can drop the WB-types import by deleting the test. -
Total
LOC of extracted code: ~6.0-6.5K(excluding the 350 LOC ofIDatReaderWriter/DefaultDatReaderWriterwhich are deleted, and excluding the 600 LOC of NOT-CORE leaves the broader agent classified as "optional" but on review still need to come along). This is somewhat larger than the spec's implicit ~5K assumption but only marginally; the 7-8 day estimate still looks right.
8. Open questions for the user (to call before T2 starts)
-
Spec §4 amendment. Confirm that the three not-reachable components (
LandSurfaceManager,EnvCellRenderManager,PortalRenderManager) are dropped from the extraction task list. If yes, T6 disappears entirely and T5 narrows to stateless helpers. Recommendation: drop them. Saves ~1.5 days of T6 work that would otherwise be a no-op anyway. -
NuGet additions. Are we OK adding
MemoryPackand (potentially)SixLabors.ImageSharpas new<PackageReference>lines inAcDream.Core.csproj? Or do we prefer stripping the[MemoryPackable]attribute fromTerrainEntryand dropping ImageSharp-touching code from the extraction? Recommendation: stripMemoryPack(one-line change). On ImageSharp, wait until T4 confirms whether the closure actually touches it. -
DatCollectiondesign call. Two paths for the dat-swap:- A) Adapter shim: write a thin
DatCollectionAsIDatReaderWriteradapter soObjectMeshManagerkeeps its current dat field type and we preserve "verbatim copy" discipline. - B) Refactor: change
ObjectMeshManager's field type toDatCollectionand rewrite ~5-20 call sites inside it. Recommendation: A) for the first pass (preserves "verbatim copy" discipline; spec O-D1 says no improvements). A follow-up phase can refactor (B) once the extraction is settled.
- A) Adapter shim: write a thin
-
ResolveIdfate. Drop it (diagnostic-only) or implement an equivalent onDatCollection? Recommendation: drop. The[indoor-upload]diagnostic was a Phase-2 investigation tool that has done its job. -
Test deletion. OK to delete
SplitFormulaDivergenceTest.cs(the one-time data-collection sweep) as part of T7's WB-reference drop?TextureDecodeConformanceTests.csshould stay (genuine ongoing conformance for ourSurfaceDecoder). Recommendation: delete the SplitFormula test; keep the texture conformance tests. -
Confirmation on 7-8 day estimate. Given (a) T6 disappears and (b) T5 shrinks, the bulk of the effort is T3 (~1d) + T4 (~2d including the dat-shim design) + T7 (~0.5d). Net estimate looks closer to 5-6 days of pure extraction work, plus the spec's 1d verification gate and 0.5d ship. Recommendation: keep the 7-8 day envelope as scheduled time (includes inevitable mid-work surprise budget); call it 5-6d of focused engineering plus 1-2d of verification.
9. Acceptance recap (per the prompt)
- Audit doc exists at the agreed path.
- Every file in the closure is bucketed (T3 / T4 / T5 / T6 / NOT / REPLACE).
- Hidden-dependency risks section addresses internal types, source
generators, resource files, and
DefaultDatReaderWritervsDatCollectionsemantic diff. - No source code edited. No
dotnet build/test. No project files touched. (Verify withgit status— only this audit doc + a few research subreports the parallel agents would have written if they had Write access; in practice only this single file is on disk.) - Thread-model finding included.
- Open questions enumerated.
10. TL;DR for the user (the four asks from the handoff prompt)
-
Total LOC of the closure: ~7,705 LOC across 33 files (~6,829 Chorizite + ~876 WB.Shared).
-
Bucket breakdown:
- T3 (GL infra): ~15 files, ~3,100 LOC.
- T4 (mesh): 8 files, ~3,313 LOC.
- T5 (scenery + terrain stateless helpers): 5 files, ~782 LOC.
- T6 (EnvCell / portal renderers): 0 files — not reachable.
- REPLACE (delete, swap to DatCollection): 2 files, 352 LOC.
-
Sharp edges:
- Three spec §4 components turn out not to be reachable — recommend
dropping
LandSurfaceManager,EnvCellRenderManager,PortalRenderManagerfrom the extraction plan. - The real risk is the
IDatReaderWriter↔DatCollectionAPI mismatch: interface vs concrete return types, multi-region cell dict vs single cell,ResolveIdcross-DB search not in our reader. Needs a shim layer or a narrow refactor at T4. - Three internal types in Chorizite need
internal → publicpromotion (EmbeddedResourceReader,TextureFormatExtensions,BufferUsageExtensions). MemoryPackand possiblySixLabors.ImageSharpare new NuGet deps if we don't strip them out.- The
[indoor-upload]diagnostic inWbMeshAdapterand theSplitFormulaDivergenceTesttest become deletable at T7.
- Three spec §4 components turn out not to be reachable — recommend
dropping
-
Honest read on the 7-8 day estimate: Reasonable, probably slightly conservative. Net extraction work is ~5-6 days of focused engineering; the spec's verification + ship time bring it to 7-8 days total. The shrinkage of T5 + disappearance of T6 buys margin against the dat-shim design work at T4 — net-net the estimate holds.