docs(overhaul): contract S4-c2 final fix round
This commit is contained in:
parent
90d4ef4ac9
commit
ac74fbd84e
1 changed files with 204 additions and 0 deletions
|
|
@ -516,3 +516,207 @@ sites, the register, and the gate's CI value — the list/router/flush core stan
|
|||
**A8 (NOTE, no action)** — the non-deferring particle path keeps `ParticleSubmissionOrdering.Sort` (`ParticleRenderer.Rhi.cs:298`); it is outside the queue and pre-existing. M1's immediate draws for rows 1/5 must not add a sort (retail's immediate `RenderMeshSubset` draws in mesh order).
|
||||
|
||||
**Gate additions for this round:** the renderer-level A1 pin; the register grep proving no id collision (`grep -c "^| ~*AP-<new>"` == 1 for each new id). Allowed files unchanged except `RetailPViewRenderer.cs` (A1) and its tests.
|
||||
|
||||
## 12. S4-c2 fix round 2 (lead, 2026-09-04 — FINAL allowed round; any further code-fix finding stops the chunk and is written up)
|
||||
|
||||
**Input under review:** `048d5b12f` (chunk implementation) plus `cc8e5677a`
|
||||
(fix round 1), clean in `s4-c2-impl` and directly descended from S4-c1
|
||||
`766f9e749`. The lead verified the paired binary before writing this contract
|
||||
(`C:\Users\erikn\Downloads\acclient.exe` matches the exact retail PDB).
|
||||
|
||||
**Sequential verdicts on `cc8e5677a`:** retail-faithful **FAIL** (two major,
|
||||
five minor); production/gate-honesty **FAIL** (six major, three minor). The
|
||||
Release build, hermetic lane, InstalledDat identities, shader lane, allowed
|
||||
file scope, core two-list FIFO, strict-less valve, and the three re-performed
|
||||
round-1 mutations all pass. Fix ONLY the items below. This is round 2 of the
|
||||
two allowed by §8/the campaign process.
|
||||
|
||||
### 12.1 Retail facts that bound the fix
|
||||
|
||||
1. `CMaterial::CheckAlphaValues` @0x005396a0 uses `fcomp 1.0; test ah,5`:
|
||||
any material-alpha channel **below** 1 sets `has_alpha`; channels at or
|
||||
above 1 leave it clear (unordered does not take the claimed `else` path).
|
||||
Production particle opacity is clamped to `[0,1]`, so the top-byte
|
||||
`!= 0xff` predicate is behaviorally exact only under that stated domain.
|
||||
`SetTranslucencySimple` @0x005396f0 writes the same `1-translucency` value
|
||||
to all four channels; `Particle::Update` @0x0051c290 reaches it through
|
||||
`CPhysicsPart::SetTranslucency` at the call `0x0051c79d`.
|
||||
2. A row-5 opaque immediate subset reaches `RenderMeshSubset` @0x0059ca10
|
||||
and `SetSurface` @0x0059c4d0. For opaque/no-material-alpha the paired bytes
|
||||
at `0x0059c6e4..0x0059c6f9` and `0x0059c7b7..0x0059c806` select ONE/ZERO,
|
||||
disable alpha blending, and pass depth-write 1 to `SetDepthBufferMode`
|
||||
(call at `0x0059c866`). Immediate timing on an alpha/no-depth-write
|
||||
pipeline is therefore NOT a faithful row-5 port.
|
||||
3. `DrawEnvCell` @0x0059f170 installs environment detail at `0x0059f1c2`,
|
||||
calls `DrawMesh` at `0x0059f212`, and clears detail at `0x0059f21a`
|
||||
(fallback `0x0059f287`). With detail absent, list selection is still the
|
||||
exact constructed **per-subset** mask. `ConstructMesh` @0x0059dfa0 maps an
|
||||
alpha-family surface to `0x02`, then a pure `Base1ClipMap` surface to
|
||||
`0x08`; `DrawMesh` row 3 sends `0x08` to CLIP. Canonical installed-DAT
|
||||
witness: cell `0xF4180104`, surface `0x08000BFF`, type
|
||||
`BASE1_CLIPMAP (0x4)`, including eight reversed-side copies (see
|
||||
`oh2-cellstruct-surface-contract.md`). The extracted
|
||||
`TextureBatchData.RetailSurfaceMask` already preserves this fact; the App
|
||||
upload currently discards it.
|
||||
4. `DrawMesh` initializes two independent first-for-list flags at entry and
|
||||
clears a given flag after the first append to that list **within the same
|
||||
DrawMesh call**. The capture's 9,685 `new=1` / 871 `new=0` entries prove
|
||||
that it is not “true for every subset.” The port may continue to omit this
|
||||
unread optimization flag, but every comment and evidence claim states the
|
||||
actual quantifier.
|
||||
5. `PView::DrawCells`' `LandscapeFlush` at call `0x005a4872` is inside the
|
||||
nonzero outside-view branch. An outdoor-root frame has DrawBuilding
|
||||
barriers and the final `SmartBox::RenderNormalMode` drain, not a
|
||||
`LandscapeFlush`; no opaque world draw follows the removed call before
|
||||
`RetailAlphaQueue.EndFrame` performs that final drain.
|
||||
|
||||
### 12.2 R2-1 — opaque particle row 5 must use opaque depth state
|
||||
|
||||
Add the mesh-particle opaque pipeline beside the existing mesh alpha/additive/
|
||||
inverse pipelines, using the existing `particle_mesh` shaders and vertex
|
||||
layout, `GpuBlendMode.None`, depth test ON, depth write ON, retail world
|
||||
compare, the existing dynamic per-batch cull override, and no alpha-to-
|
||||
coverage. Row-5 immediate mesh submissions bind this pipeline. Do not change
|
||||
billboard behavior, queued row-4 replay, additive/inverse replay, the
|
||||
pre-existing non-queue `DrawOrderedRhi` sort, or add a shader.
|
||||
|
||||
The production pin must drive `DeferToRetailAlphaQueue` (not only
|
||||
`RouteParticleSubmission`): an opaque mesh particle with alpha `<1` appends
|
||||
to ALPHA, draws once at flush, and never invokes the immediate draw; the same
|
||||
mesh at alpha `1` invokes immediate once, appends nothing, and binds a
|
||||
pipeline whose description proves Blend=None and Depth=(test true, write
|
||||
true). Restoring the throw, deleting the immediate call, or selecting the
|
||||
old `_meshAlphaPipeline` must each fail a named assertion. Correct the M1
|
||||
comments: at this hardcoded scene/no-detail/no-multipass site only row 5 is
|
||||
reachable as Immediate; row 1 is not.
|
||||
|
||||
### 12.3 R2-2 — EnvCell routing is exact per subset and replay is list-filtered
|
||||
|
||||
Carry `TextureBatchData.RetailSurfaceMask` into `ObjectRenderBatch` at the
|
||||
existing upload boundary. The detail-off cell-shell path scans the real
|
||||
transparent render batches and applies `RetailAlphaMeshRouter.Route` to each
|
||||
batch's retained mask. It may coalesce only to at most one token per
|
||||
`(cellId, RetailAlphaList)`; a CLIP token's replay draws only batches routed
|
||||
to CLIP and an ALPHA token's replay draws only batches routed to ALPHA. A
|
||||
mixed cell therefore contributes to both lists without either replay drawing
|
||||
the other list's subsets. Any mask whose table result is Immediate is drawn
|
||||
at the cell turn and is excluded from both deferred replays; do not replace
|
||||
the table with “detail on/off” branching. With environment detail active,
|
||||
eligible subsets remain immediate with their detail pass at that turn.
|
||||
|
||||
Use separate CLIP/ALPHA source identity, or an equivalently discriminating
|
||||
retained token, so CLIP-then-ALPHA adjacency cannot lose the list filter.
|
||||
Retain bounded, reusable scratch; no per-frame LINQ/closure/array allocation.
|
||||
The accepted residual is **only** per-cell-per-list token granularity (rather
|
||||
than retail per-subset tokens), not list selection. Rewrite AP-238 to say
|
||||
that. Rewrite AP-240 because EnvCell pure-ClipMap subsets are now genuine
|
||||
CLIP feeders; ordinary Wb GfxObj/scenery/building ClipMap remains the
|
||||
registered alpha-to-coverage structural gap.
|
||||
|
||||
Production pins (not a hand-constructed source-only test):
|
||||
|
||||
- canonical/synthetic `RetailSurfaceMask=0x08` reaches CLIP, while `0x02`
|
||||
reaches ALPHA;
|
||||
- a mixed `0x08`/`0x02` cell creates one token in each list and each drain
|
||||
renders only its own batch set, exactly once;
|
||||
- detail OFF draws neither deferred set before the next real queue drain;
|
||||
detail ON draws at the cell turn, with detail, and queues nothing;
|
||||
- a particle/ordinary source between two cell tokens remains between them;
|
||||
- hardcoding `MaskAlphaFamily`, inverting the production immediate predicate,
|
||||
or removing the replay filter fails the named assertion. Structural IL-call
|
||||
order and a manually assembled `EnvCellAlphaDrawSource` alone do not count.
|
||||
|
||||
### 12.4 R2-3 — rejected sources still participate in frame cleanup
|
||||
|
||||
All three production callers reserve source-owned payload before
|
||||
`TryAppend`. When a list already holds 3,000 entries, `TryAppend` must still
|
||||
register that source for the frame's reset, then return false without adding,
|
||||
preparing, or drawing the rejected token. Pin with source A filling ALPHA and
|
||||
source B making its first, rejected append: B is never prepared/drawn but is
|
||||
reset exactly once at flush/end/abort, and its retained payload is empty for
|
||||
the next frame. This test must use two sources; the existing same-source
|
||||
overflow pin cannot detect the leak. Preserve retail's drop/no-immediate-
|
||||
fallback behavior and the queue's warmed scratch-retention policy.
|
||||
|
||||
### 12.5 R2-4 — replace structural/pure claims with real production pins
|
||||
|
||||
1. **M3:** drive both Wb production submit sites. Building shell + detail ON
|
||||
draws immediately at its `AlphaSubmitMark`, performs the detail pass, and
|
||||
queues nothing; detail OFF queues and drains without a detail pass; an
|
||||
ordinary non-shell translucent batch is unchanged by the building-detail
|
||||
flag. Hardcoding `detailSurfaceActive=false` at the production line must
|
||||
fail. No source-text/IL-only substitute.
|
||||
2. **M1/M6:** the tests in §§12.2–12.3 call the production dispatch methods.
|
||||
Keep the pure router/source tests as narrow unit coverage, but delete their
|
||||
false claims that a production mutation fails “here.”
|
||||
3. **A1:** add the positive renderer-level outdoor sequence pin through the
|
||||
real `RetailPViewRenderer` frame owner: `[DrawBuilding x N,
|
||||
RenderNormalMode]`, never `LandscapeFlush`, with pass-end after the last
|
||||
outdoor particle/world contribution. Restoring the deleted direct outdoor
|
||||
`FlushLandscapeAlpha` fails this test. The existing source/IL absence test
|
||||
may remain but is not the positive proof.
|
||||
4. Every new/changed behavior pin has a commit-body mutation report naming
|
||||
the exact production mutation and the **actual first failing assertion**.
|
||||
A test that still passes the mutation is not a pin and is not claimed.
|
||||
|
||||
### 12.6 R2-5 — evidence, register, and prose truth
|
||||
|
||||
- `ParticleRenderer` says CheckAlphaValues is `<1` and explicitly bounds the
|
||||
equivalence to the clamped `[0,1]` production domain.
|
||||
- `RetailAlphaQueue`/trace prose gives the true per-DrawMesh first-for-list
|
||||
lifecycle; it does not say every append is `new=1`.
|
||||
- Packet §10 names the landed `AlphaFlushSites_*` (live) and
|
||||
`AlphaFlushCounts_*` (KnownFailure) split. Zero mesh content is sufficient
|
||||
to explain the present count failure. If future-content residuals are
|
||||
described, name only the proven ones: EnvCell's coarser one-token-per-cell-
|
||||
per-list replay and ordinary-Wb CLIP's AP-240 structural gap. Do not claim
|
||||
all acdream entries are per instance—Wb and mesh particles already submit
|
||||
per batch/subset instance. Fix the stale removed Fact names and the packet's
|
||||
off-by-one sequence multipliers.
|
||||
- AP-239 says its blend mode is unchanged but overlap-dependent compositing
|
||||
can be visibly different; delete “never a visual difference.” AP-238 and
|
||||
AP-240 change as in §12.3. Fix `RetailPViewPassExecutor`'s stale AP-236
|
||||
citation to AP-238. No new AP row is needed if the production fixes satisfy
|
||||
this contract; keep the one-occurrence/id-count checks honest.
|
||||
- Focused-gate prose lists the exact filters it actually runs. The round-1
|
||||
claimed filter produced **123/123**, not 120, and the corrected filter must
|
||||
explicitly include `EnvCellAlphaDrawSourceTests` and
|
||||
`RetailPViewPassExecutorTests`. Report the new post-fix total from output,
|
||||
never a forecast.
|
||||
- Add a concise “§12 result” note only after every gate below passes; it lists
|
||||
real output and real mutation failures, not intent.
|
||||
|
||||
### 12.7 Scope, gates, and stop rule
|
||||
|
||||
**Allowed files:** `src/AcDream.App/**`, `tests/AcDream.App.Tests/**`,
|
||||
`docs/architecture/retail-divergence-register.md`, and this packet. The
|
||||
Content model/serializer already retains the mask and must not be changed.
|
||||
`docs/architecture/worldbuilder-inventory.md` may change only if a now-stale
|
||||
S4-c2 citation introduced by round 1 must be corrected. One implementation
|
||||
commit on top of `cc8e5677a` in `s4-c2-impl`.
|
||||
|
||||
**Must NOT:** reintroduce distance; add a flush site; alter S4-c1 punch/seal;
|
||||
change ordinary Wb ClipMap alpha-to-coverage (AP-240); add alpha-to-coverage
|
||||
to particles; add a shader; recover an overflow with an immediate draw; hide
|
||||
a production gap behind an IL/source-text-only test; run a graphical client
|
||||
from the implementation/review worktree.
|
||||
|
||||
**Automated gates (real output copied into the commit body/result note):**
|
||||
Release solution build, 0 warnings/errors; hermetic lane wholly green;
|
||||
InstalledDat exactly 255 pass / 10 fail / 1 skip with only TowerAscent,
|
||||
the two #383 layout sweeps, #458 doorway, and six `AlphaFlushCounts_*`
|
||||
failures (all six `AlphaFlushSites_*` pass); shaders 32/32; corrected focused
|
||||
filter including queue/router/walk/driver/particle/Wb/EnvCell/PView production
|
||||
tests; the new capacity-cleanup pins; register identities/counts; warmed
|
||||
allocation proof for the changed immediate/filter/source paths.
|
||||
|
||||
**Sequential lenses after implementation:** (1) retail-faithful, narrowed to
|
||||
the row-5 pipeline and exact EnvCell per-subset mask/list; then (2)
|
||||
production/gate-honesty, narrowed to rejected-source cleanup, production-path
|
||||
mutation discrimination, scratch bounds, gate identities, register/prose,
|
||||
and allowed scope. Each returns PASS/FAIL with file:line findings. Because
|
||||
this is the final allowed fix round, any finding that requires another code
|
||||
change is a third round: STOP, leave the implementation unlanded, and write
|
||||
the chunk failure into the packet/ledger. Comment-only clarification that
|
||||
does not change a claim may be adjudicated by the lead; it may not conceal a
|
||||
behavior or test defect.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue