docs(overhaul): contract exact S5 c4 detail material

This commit is contained in:
Erik 2026-09-04 23:02:33 +02:00
parent 678bffaa85
commit 9f410d8b75
3 changed files with 282 additions and 4 deletions

View file

@ -1,8 +1,7 @@
# Campaign OVERHAUL v2 — S5 consumers, material, and closeout packet
**Status:** S5-c1 and S5-c2 LANDED + lead graphical gates PROVISIONAL PASS;
S5-c3 implemented in scratch; retail review pass 3 PASS, production review
pass 4 FAIL, and bounded fix round 3 is contracted under §20.
**Status:** S5-c1 through S5-c3 LANDED + REVIEW-CLOSED with lead graphical
gates PROVISIONAL PASS; S5-c4 is contracted under §22.
**Branch:** `claude/campaign-w-retail-frame-walk`.
**Gate:** G4 remains unpassed. Nothing merges to `main` before G4.
@ -1561,3 +1560,255 @@ based alpha/selection/light sidecars and omit the active atmospheric receiver
pipeline/bindings. It exists at least at S4-c2 `252886e84`, is filed as #470,
and must be repaired before renderer-solid/G4. S5-c4 is next; #469/#470, c5,
the closeout program, and G4 remain. Nothing merges to `main` before G4.
## 22. S5-c4 contract — exact one-pass detail material and ordered production closure
This chunk replaces the acdream-only base-plus-`mesh_detail` replay with the
single fragment retail emits when the hardware single-pass detail path is
available. It applies to detail-active building and EnvCell subsets in every
current world submission path: classic grouped, walk-ordered, immediate alpha,
deferred alpha, and EnvCell opaque/transparent replay. One source subset must
produce one physical draw and one `(rgb, alpha)` result while retaining that
subset's existing queue position, blend family, alpha-test/depth state, cull,
geometry, transform, material overrides, fog policy, sampler, and mip chain.
The production audit found that the walk-ordered path currently uploads
building detail categories and forces them into solo runs but issues only the
base draw. That omission is filed as #471 and is part of this chunk: the new
one-pass detail result must be armed on that existing base draw. Do not add a
blended overlay after the run. An overlay would preserve AP-232, create a new
terrain/`StreamMark` flush obligation, and remain unlike retail.
### 22.1 Lead-verified retail and paired-binary facts
The paired executable is `C:\Turbine\Asheron's Call\acclient.exe`, SHA-256
`006FFEADC5D679C871497112A5BD1F87714D0E273E2166BAE5052DDE369297B1`.
Its CodeView identity remains GUID `{9E847E2F-777C-4BD9-886C-22256BB87F32}`,
age 1, matching the named PDB. The named pseudo-C and fresh paired-executable
disassembly agree on these exact ranges:
| Fact | VA range / length | SHA-256 |
|---|---|---|
| `SetSurface` detail stages | `0x0059C4D0..0x0059C5B5` / 229 | `090E24BE542E9DA4F77B547D091F5C2E676109495919BEA70027AD2B89E11426` |
| `SetSurface` blend/alpha/depth state | `0x0059C6C5..0x0059C866` / 417 | `1F077DA1BB09FBAC0EAF7522E125C716AAF499DFA8763DD3DDF29CCC6A76C382` |
| `RenderMeshSubset` single-pass arm | `0x0059CA10..0x0059CAF0` / 224 | `64A988D4B1611CEEA6DE135FF52CDF30FE1AFDAAFF5E3B76751FFA7FC833CC53` |
| `DrawMesh` detail/alpha routing | `0x0059D4A0..0x0059D5A5` / 261 | `20B1E5D1E90C9E19C62047AF521F817CF6700B5FEA68CE78C7404CD238862CB3` |
Named anchors are `D3DPolyRender::SetSurface @0x0059C4D0`
(`acclient_2013_pseudo_c.txt` lines 425083425303),
`RenderMeshSubset @0x0059CA10` (lines 425382425450),
`DrawMesh @0x0059D4A0`, `RenderDeviceD3D::DrawEnvCell @0x0059F170`, and
`DrawBuilding @0x0059F2A0`. The live capability result remains the VM2 CDB
record in `2026-08-22-vm2-retail-detail-path-cdb.md`: retail takes the
single-pass path, not its fallback.
Let `B` be the sampled base RGB, `D` the active diffuse/lighting RGB, `a` the
active diffuse/material alpha, and `Q=(q,qA)` the sampled detail texel. At
`0x0059C51C/52B/53A/549` retail programs:
- stage 0 colour `C0 = B * D`;
- stage 0 alpha `PREMODULATE(DIFFUSE,DIFFUSE)`, whose visible stage-0 result is
`a` but whose stage-1 `CURRENT` alpha is premultiplied by the next texture,
`a*qA`;
- stage 1 colour `BLENDCURRENTALPHA(TEXTURE,CURRENT)`; and
- stage 1 alpha `MODULATE(TEXTURE,CURRENT)`.
Therefore the exact pre-fog fragment is:
```text
w = a * qA
C = q * w + (B * D) * (1 - w)
X = a * qA * qA
```
The square in `X` is mandatory. Base texture alpha does not participate in the
detail-active final alpha. Fog is applied to `C` after the combine wherever
the subset's fixed-function policy enables fog; it never changes `X`.
`SetBlendFunction @0x005A2B90` writes one colour/alpha factor set, so the
framebuffer equations for destination `F` are:
| Raw family | Result RGB | Result alpha |
|---|---|---|
| Alpha | `C*X + F.rgb*(1-X)` | `X*X + F.a*(1-X)` |
| Alpha + Additive | `C*X + F.rgb` | `X*X + F.a` |
| Additive without Alpha | `C + F.rgb` | `X + F.a` |
| InverseAlpha | `C*(1-X) + F.rgb*X` | `X*(1-X) + F.a*X` |
| InverseAlpha + Additive | `C*(1-X) + F.rgb` | `X*(1-X) + F.a` |
| pure CLIP survivor | `C + F.rgb*(1-X)` | `X + F.a*(1-X)` |
Pure CLIP rejects iff `X < r`, with `r=100/255` for paletted and `r=200/255`
for DDS/non-paletted input; equality survives. CLIP combined with an
Alpha/Additive/Inverse family keeps that family's factors and applies the same
test. The later `TRANSLUCENT` branch at `0x0059C767..0x0059C7A6` then matters:
ordinary `T` and `T|Alpha` are straight-alpha; `T|Additive` and
`T|InverseAlpha` retain their respective family unless the skip arm applies;
every `T|CLIP` combination is forced to straight-alpha and CLIP is disabled.
Do not replace that table with a universal straight-alpha assumption.
`a` is the active material alpha, including authored
`1-Surface.Translucency` on a `Translucent` surface and the current object/part
fade multiplier. The lead's installed Surface census found 261/261
`Translucent`-flagged surfaces carry nonzero authored translucency, including
real 0.25, 0.5, 0.75, and 1.0 values. Treating `a` as always one is disproven.
Current prepared Wb payloads discard that scalar while the decoded base image
bakes it into base alpha; because retail detail excludes base alpha, it cannot
be recovered from the sampled texel. The implementation must carry authored
surface opacity explicitly from extraction through the prepared payload and
GPU batch data, multiply it by the existing live instance opacity, and use the
product as `a`. Guessing from texture alpha, querying DAT from the renderer, or
using `base.a` is forbidden.
### 22.2 One draw, one material result
Implement the combine in the ordinary and atmospheric world-mesh fragment
families, sharing one source include or otherwise proving their arithmetic
textually and numerically identical. The base texture remains the batch-owned
array sample. A detail-active exact command supplies the category texture slot
and tiling in the existing push fields; zero tiling is the unarmed value. The
per-draw GPU batch record supplies authored surface opacity. The vertex stage
passes that scalar without interpolation; the fragment multiplies it by the
existing instance-opacity varying to obtain `a`.
The prepared contract must gain the scalar without ambiguity:
- `MeshExtractor` computes it from the resolved source `Surface` for ordinary
GfxObj and CellStruct batches using the existing
`OpacityFromSurfaceTranslucency` rule;
- `TextureBatchData`, its deterministic serializer, and
`ObjectRenderBatch` preserve it exactly;
- this is a prepared-payload schema change, so advance the bake-tool recipe
identity and update every recipe/round-trip/compatibility pin in the same
commit; an old recipe must be rejected clearly, never misread; and
- the GPU batch ABI carries it explicitly with layout/stride tests for both
built-in shader families. Do not introduce a renderer-side surface table,
per-frame dictionary, or DAT lookup.
For a detail-active fragment, compute `(C,X)` before the current discard/fog
tail. Alpha testing uses `X`, not sampled base alpha. For detail-off fragments,
preserve the current byte-for-byte logical path: base-alpha discard/reference,
RGB lighting/fog, and `base.a * instanceOpacity` output alpha. The debug-light
mode remains a deliberate diagnostic bypass and must not sample detail.
At each production draw site:
1. arm detail only when the existing Building Detail Textures option is on,
the correct category binding is resident, tiling is nonzero, and the exact
command/subset belongs to the building or EnvCell detail category;
2. set the detail slot/tiling and draw that source subset exactly once through
its original base pipeline family;
3. preserve its original queue position, blend, depth test/write/reference,
alpha test, cull, geometry, draw-id offset, absolute transform base, local
sidecars, selected building GfxObj, palette/original-texture override,
lighting, fog enable, and atmospheric receiver choice; and
4. restore neutral detail push fields before the next non-detail draw.
Delete every now-unreachable `RetailDetail`/`RetailDetailTransparent` pipeline,
`GpuBlendMode.RetailDetail`, `DrawBuildingDetailRangeRhi`-style replay helper,
`mesh_detail.vert/.frag`, compiled SPIR-V entries, manifest entries, and stale
two-draw comments/tests. Keep CPU detail-category ownership only where it still
selects exact eligible commands. Do not delete or weaken the building-detail
setting, category textures, repeat/linear sampler, full mip chain, S4's two
FIFO queues, AD-120 immediate placement, AP-238 token granularity, AP-239 raw
mask residual, or AP-240 ordinary-GfxObj ClipMap placement.
The ordered-path repair for #471 is a one-pass arm on the existing solo base
run. It adds no second draw and therefore leaves `WalkFrameDriver`'s
opaque/no-blended-overlay `StreamMark` terrain-flush premise true. Tests must
prove that premise rather than adding a compensating terrain flush.
### 22.3 Audited policy table and explicit nonchanges
Add one data-driven policy test/table spanning Building and EnvCell × Opaque,
Alpha, Additive, InverseAlpha, paletted CLIP, and DDS CLIP × detail on/off. For
each row pin physical draw count, source order/FIFO, pipeline blend/depth/alpha
test/reference, detail arm, emitted `(C,X)`, and framebuffer result on a
nontrivial destination. Add raw `Translucent` combinations sufficient to pin
the later override described in §22.1. Existing AP-238/AP-239/AP-240 facts
remain visible in the table instead of being silently relabelled exact.
This chunk does not change FIFO classification/token granularity, portal or
terrain ordering, building-degrade selection, visibility/membership,
directional-shadow caster selection, #469's lighting-direction transition, or
#470's general ordered atmospheric sidecar/receiver defect. It must implement
the same material arithmetic in the atmospheric shader so the later #470
repair cannot expose a second result. No graphical client is launched by the
implementer.
Allowed production scope is the prepared mesh batch/extractor/serializer and
bake-recipe identity; world GPU batch ABI and built-in ordinary/atmospheric
mesh shaders; Wb/EnvCell detail draw/pipeline ownership; shader compiler
outputs/manifest; and the smallest render-pack ABI pins required by those
shader changes. Tests may change for those surfaces, deterministic prepared
round trips, state/pixel equations, command transcripts, allocation, shader
ABI, and package compatibility. The only authorized documentation file in the
implementation commit is
`docs/architecture/retail-divergence-register.md`: strike AP-232 with the exact
new mechanism/evidence and amend counts; add or correct a row in the same
commit for every discovered surviving deviation. Do not edit this packet,
the plan, issues, architecture prose, scripts, or generated evidence reports.
### 22.4 Required proof, mutations, and return
Focused proof must include at least:
1. independent CPU fixtures over nontrivial base/detail RGBA, diffuse colour,
authored opacity, live fade, fog, destination RGBA, and every §22.1 state;
they must distinguish `a*qA²` from `a*qA`, `base.a*a*qA²`, and today's two
draws;
2. pure/paletted/DDS CLIP values immediately below, equal to, and above the
final-`X` reference plus `Translucent|CLIP`'s disabled-test override;
3. extraction and prepared serialization round trips for opacity 1, 0.75,
0.5, 0.25, and 0, a bumped recipe identity, deterministic bytes, and clear
rejection of recipe 8 by the recipe-9 build;
4. GPU ABI pins proving the batch scalar reaches both ordinary and atmospheric
fragments, detail-off never samples the category texture, and debug-light
mode stays independent;
5. real Wb classic, walk-ordered, immediate-alpha, and delayed-alpha command
recordings proving one detail-active subset draw, original pipeline state,
exact slot/tiling/material alpha, no replay, and no stale detail arm on an
adjacent ordinary draw;
6. real EnvCell opaque, Alpha, Additive, and both CLIP-reference recordings
with the same one-draw/state/order proof;
7. production ordered sequence ordinary → opaque building detail → ClipMap
building detail → ordinary with exact one-draw adjacency and no added
terrain flush, closing #471;
8. active/inactive atmospheric receiver shader/pipeline recordings proving
identical material equations while leaving #470's separate general repair
boundary explicit;
9. setting-off and unavailable-category identity, selected-surface override,
sampler/mip, fog-after-combine, draw-id/transform-prefix, cull, and
lifecycle/reset/revisit preservation; and
10. warmed extraction-free draw/classification paths at 0 managed bytes after
warmup, with no per-frame material lookup/table/allocation.
Sabotage and restore at least these mutations, recording the first failing
test/assertion for each in the implementation commit body: change `X` to
`a*qA`; multiply `X` by base alpha; test CLIP against base alpha or 0.05;
restore any second detail draw; bind straight alpha instead of the original
subset family; omit the walk-ordered detail arm; omit the atmospheric combine;
drop authored opacity during prepared serialization; and leave the detail push
fields armed for the following ordinary draw. Include one allocation sabotage
that builds a per-frame surface map and prove the 0-B pin catches it.
Implementer return: one clean commit; exact changed-file and line-count list;
all mutation first failures; `git diff --check`; Release solution build 0W/0E;
shader compilation plus manifest/SPIR-V validation; focused content/serializer,
renderer/state/pixel/command/allocation suites; official hermetic lane; and an
inclusive InstalledDat lane with every accepted nonpassing identity named. If
the package recipe changes, also return the exact deterministic bake command,
artifact identity/size, and compatibility result. No client run.
Sequential review 1 — retail/material/deviation fidelity: re-check the named
and paired bytes, PREMODULATE semantics, squared alpha, every framebuffer and
CLIP/Translucent row, authored opacity provenance, fog placement, AP-232
retirement, AP-238/239/240 preservation, and all retail-facing mutations.
Sequential review 2 — architecture/production/gate honesty: one physical draw,
all five production paths including #471, prepared-schema compatibility, no
renderer DAT lookup or per-frame map, shader/pack ABI, state/order/reset,
allocation, build/lane/artifact provenance, and at least three independently
reproduced sabotages. Reviews run sequentially. Every code finding receives a
bounded fix contract and narrow re-review; documentation-only findings may be
corrected directly by the lead. At most ten c4 review passes may run; stop
before an eleventh. Nothing lands or launches graphically until both lenses
pass.