diff --git a/docs/ISSUES.md b/docs/ISSUES.md index 2a73ddff..b02b0547 100644 --- a/docs/ISSUES.md +++ b/docs/ISSUES.md @@ -122,8 +122,8 @@ left no client. The separate #469 lighting-direction transition remains open. ## #469 — Atmospheric shadow-gate transition switches the whole outdoor lighting direction abruptly and can darken the world -**Status:** OPEN — found 2026-09-04 by the S5-c2 lead graphical gate; Campaign -OVERHAUL v2 renderer-solid/G4 scope. This predates S5-c2: exact parent +**Status:** IN FLIGHT — lead contract written 2026-09-05 in S5 packet §31; +Campaign OVERHAUL v2 renderer-solid/G4 scope. This predates S5-c2: exact parent `5c106bcdf` and candidate `ef819eedf` reproduce the same dark re-enable. **Evidence:** parent @@ -147,13 +147,12 @@ IA-24 records that this alignment was intentional, so the repair must preserve the declared opt-in behavior or explicitly revise that deviation—not quietly mix two incompatible directions. -**Bounded next step before G4:** write a focused pack-lighting contract that -keeps the pack-active receiver direction stable across shadow-work gate -transitions (or proves a better single-direction policy), pins meshes and -terrain together, preserves exact pack-off pixels/work, recompiles and verifies -the shader manifest, then repeats this exact off/on/dusk A/B. G4 cannot call the -renderer solid while this remains unexplained and visibly severe; alternatively -the owner may explicitly accept the transition as part of IA-24. +**Bounded repair before G4:** packet §31 restores retail's authored `uLights` +direction as the sole base-light direction in both atmospheric vertex +receivers, while preserving the selected celestial direction for the opt-in +shadow/volumetric projection and correcting IA-24 in the same implementation +commit. Production SPIR-V plus a real Vulkan mesh/terrain witness must +discriminate the old branch before this exact off/on/dusk A/B is repeated. ## #468 — Teleport to the Holtburg cottage doorway pose seats the player in the house-interior cell at a point outside its floor; the player falls through the world diff --git a/docs/plans/2026-09-01-campaign-overhaul-world-solidity.md b/docs/plans/2026-09-01-campaign-overhaul-world-solidity.md index efc1bd38..5ce24da2 100644 --- a/docs/plans/2026-09-01-campaign-overhaul-world-solidity.md +++ b/docs/plans/2026-09-01-campaign-overhaul-world-solidity.md @@ -694,7 +694,7 @@ Update immediately when a slice changes state. Chat is not the ledger. | S5-c3 | **LANDED + REVIEW-CLOSED 2026-09-04** at `c673f767e` (reviewed scratch `01e5a15d0`; packet §§17–21). | **C3 SCOPE SELF-GATE PROVISIONAL PASS; whole-renderer finding #470 OPEN. G4 UNPASSED.** | OpenAI retail pass 3/10 PASS and production narrow re-review pass 5/10 PASS. Fix round 3 added ordinary landblock-lifetime ownership for every unique nonzero ladder GfxObj, rearmed walk-frame miss requests, and made the one-tick-before-BeginFrame proof discriminating. Fresh clean campaign: Release 0W/0E; focused 101/101; hermetic 16,811/16,811; InstalledDat 469 pass / the unchanged documented 10 fail / 1 skip; manifests 30/30. Self-gate `logs/selfgate-20260904-223345-s5c3-building-degrade` produced five PNGs, exited 0/gracefully, and left no client. The selected building shells are complete; the Holtburg frame also exposed pre-existing atmospheric ordered-draw sidecar defect #470, which is not a c3 regression and blocks renderer-solid/G4 until repaired. | | S5-c4 | **LANDED + REVIEW-CLOSED 2026-09-05; LEAD GRAPHICAL GATE PROVISIONAL PASS.** Campaign stack `75664805f` -> `15ed57a1e` -> `d5cfd1c91` -> `03a108ffa`; reviewed scratch tip `db8136448`; packet §§22–26. | G4 UNPASSED | Retail/material pass 3/10 PASS. Full production pass 4/10 found one classic/private detail-off regression; fix round 3 restored the prior AlphaBlend/coalescing path, and narrow production pass 5/10 PASS reproduced all three mutations. Fresh campaign Release 0W/0E, App 245/245, Content 71/71; scratch hermetic 16,971/16,971 and InstalledDat 469/10/1 with both manifests 32/32. Full recipe-10 bake: 2,237,865 keys, zero failures, SHA `4E0FA6C5…29B59B`. Gate `logs/selfgate-20260905-020703-s5c4-onepass-detail`: 13/13 PNGs, exit 0, graceful, no client left; visual PASS provisional. #471 DONE; #470 narrowed to local-sidecar indexing. | | S5-#470 | **LANDED + REVIEW-CLOSED 2026-09-05; LEAD GRAPHICAL A/B PROVISIONAL PASS.** Campaign implementation stack `15a796c3a` -> `7506e5f14` -> `b333edb4f`; route `19b44e5e3`; reviewed scratch `51f974da4` -> `2cad9c84` -> `98c004aa7`; packet §§27–30. | G4 UNPASSED | Retail/behavior pass 2/10 and production pass 4/10 closed the two evidence-only findings. Fresh campaign Release 0W/0E and focused 48/48; exact scratch hermetic 16,976/16,976 and canonical InstalledDat 386/10/1, manifests 30/30. Pinned gate `logs/selfgate-20260905-032132-s5-470-pinned-shadow-ab-r1`: retail/off -> High -> retail/off, 3/3 PNGs, exit 0, graceful, no client; visual PASS provisional. The stale recipe-8 pre-route launch is excluded and recorded in §30. | -| S5 | IN FLIGHT — c1–c4 plus #470 landed/review-closed/provisionally self-gated; #469, c5, closeout, and G4 remain | G4 | Packet §§7 and 12–30 are binding. Next: bound, implement, review, and graphically gate #469's lighting-direction repair; then c5 cleanup, closeout, and G4. Never merge main before G4. | +| S5 | IN FLIGHT — c1–c4 plus #470 landed/review-closed/provisionally self-gated; #469 contract written; c5, closeout, and G4 remain | G4 | Packet §§7 and 12–31 are binding. Next: implement, sequentially review, land, and graphically gate §31's #469 authored-light repair; then c5 cleanup, closeout, and G4. Never merge main before G4. | --- diff --git a/docs/research/2026-09-01-overhaul/s5-consumers-material-closeout-packet.md b/docs/research/2026-09-01-overhaul/s5-consumers-material-closeout-packet.md index 6c7208ce..5f51e588 100644 --- a/docs/research/2026-09-01-overhaul/s5-consumers-material-closeout-packet.md +++ b/docs/research/2026-09-01-overhaul/s5-consumers-material-closeout-packet.md @@ -2687,3 +2687,168 @@ frame. High retains the separately registered #469 lighting-direction shift; that known blocker is neither waived nor attributed to #470. #470 changes no retail-visible policy and requires no divergence-register row. Next is #469, then S5-c5, closeout, and G4. Nothing has merged to `main`. + +## 31. S5-#469 contract — keep retail world lighting stable across the opt-in shadow gate + +### 31.1 Lead-recovered retail and binary boundary + +Issue #469 is not an ambiguous art-direction choice. Retail owns exactly one +outdoor directional-light channel, authored by `SkyTimeOfDay`; the atmospheric +pack's visible sun/moon choice is an acdream-only shadow-projection input and +must not replace that lighting channel. + +The lead re-read the named retail decomp and its verbatim type header before +writing this contract: + +- `SkyTimeOfDay` contains `dir_bright`, `dir_heading`, `dir_pitch`, and + `dir_color` (`acclient.h` lines 53124–53137). +- `SkyDesc::GetLighting @0x00500A80` interpolates those fields between the two + surrounding authored time-of-day records, constructs one directional vector, + and returns one directional colour. +- `LScape::set_landscape_lighting @0x005054D0` copies that vector and colour to + `LScape::sunlight` and then `Render::world_lights.sunlight`; it has no shadow- + gate or celestial-mesh selection input. +- `PrimD3DRender::UpdateLightsInternal @0x0059AED0`, specifically + `0x0059B4ED–0x0059B5CE`, derives the D3D sunlight colour and direction from + that same `Render::world_lights.sunlight`. It does not replace the direction + when any drawing feature is enabled or disabled. + +The paired executable was independently verified again with +`tools/pdb-extract/check_exe_pdb.py`: `C:\Users\erikn\Downloads\acclient.exe` +is PE32 v11.4186, whole-file SHA-256 +`006FFEADC5D679C871497112A5BD1F87714D0E273E2166BAE5052DDE369297B1`, CodeView +GUID `{9E847E2F-777C-4BD9-886C-22256BB87F32}`, age 1, and matches +`C:\Users\erikn\source\repos\acdream\refs\acclient.pdb`. Exact function-range +SHA-256 anchors are: + +| Function | File range | Bytes | SHA-256 | +|---|---:|---:|---| +| `SkyDesc::GetLighting` | `0x00100A80..0x00100CDF` | 608 | `9D82E8EDDBD66C52DBD3F08D07D661482DB545C4F513E81AB4F16E4EDF410188` | +| `LScape::set_landscape_lighting` | `0x001054D0..0x0010565F` | 400 | `DF3FD816845AE0F6E2423442A325CE43A44A8204E1B857D7674BBB8F4640D0CB` | +| `PrimD3DRender::UpdateLightsInternal` | `0x0019AED0..0x0019B5DF` | 1,808 | `E18FD7AD9A8EB819AB9602D25DE5D1BB99FADD1D439B35140E443EB1E0437F84` | + +This agrees with the pre-existing static source study +`docs/research/2026-08-22-dereth-celestial-shadow-sources.md`: celestial meshes +supply only the opt-in shadow **direction**; colour and energy remain retail's +single authored channel; existing retail scene lighting remains driven by +`SkyStateProvider`. + +The current atmospheric receiver shaders violate that declared boundary. +When shadow flag bit 0 is clear they use the plain pipeline's authored +`-uLights[].dirAndRange.xyz`; when it is set they abruptly use normalized +`uShadowLightDirectionAndSource.xyz`. Shadow strength is blended later, so this +binary vertex-light switch produces the whole-world relight captured in both +the exact parent and S5-c2 candidate A/Bs. It is not absent shadow work and it +is not caused by S5-c2. + +### 31.2 Bounded production repair and IA-24 correction + +Restore one stable lighting owner in both atmospheric vertex receivers: + +1. `mesh_atmospheric.vert` computes every outdoor directional-light `Ldir` + with the exact plain-mesh expression `-uLights[i].dirAndRange.xyz` in every + shadow-gate state. Preserve its unnormalized value and its per-light loop. +2. `terrain_atmospheric.vert` computes `surfaceToLight` with the exact plain- + terrain expression `-uLights[0].dirAndRange.xyz` in every shadow-gate state. + Preserve `MIN_FACTOR`, authored colour/energy, and the split directional + varying used by the fragment receiver. +3. Delete the obsolete `shadowGatedOff` branches and replace their comments + with the retail ownership above. +4. Keep `uShadowLightDirectionAndSource` unchanged for cascade projection, + receiver depth/bias/PCF, and atmospheric volumetrics. The optional shadows + may therefore be geometrically directed at the selected visible celestial + source while the receiver's base lighting remains the authored retail + direction. That separation is deliberate and was already the original + IA-24 research boundary. +5. Recompile the committed shader set and update only the generated atmospheric + vertex SPIR-V and manifest/hash entries required by those source changes. +6. Amend IA-24 in the **same implementation commit**: remove its statement that + receiver lighting switches to the celestial direction while shadows render; + state instead that authored `uLights` remains the sole base-light direction + in every gate state, while the selected celestial source drives only the + opt-in shadow/volumetric projection. Explicitly record the possible visual + light/shadow-angle separation as the cost of preserving retail lighting and + eliminating the binary relight. This is the required deviation-register + update; add no second row. + +Do not change `SceneLighting`, `SkyStateProvider`, the celestial-source +resolver or its sun/moon priority, shadow strength/fades, cascade matrices, +shadow caster selection, receiver binding/descriptor ABI, fragment shadow +lookup, PCF/bias, volumetric policy, render-pack selection, plain shaders, +materials, fog, tone mapping, colour/energy, terrain `MIN_FACTOR`, indoor +lighting, point/spot lights, visibility, geometry, package recipe, or any +unrelated renderer. Do not normalize the authored direction, blend the two +directions, invent another runtime state owner, hide the switch behind a +threshold, or add per-frame work/allocation. If any wider production change is +needed, stop and return the exact dependency before expanding scope. + +Allowed production scope is the two atmospheric vertex shader sources, their +regenerated SPIR-V/manifest pins, and the IA-24 row. Tests may add only the +smallest structural and real-shader proof below. The implementer changes no +packet, plan, issue, package, gate artifact, architecture text outside IA-24, +or campaign memory. + +### 31.3 Discriminating proof, mutations, and return + +Permanent proof must establish both halves of the boundary rather than merely +matching a copied CPU formula: + +1. compile and inspect the committed production atmospheric vertex SPIR-V and + prove mesh and terrain take their diffuse-light direction only from the + corresponding authored `uLights` member, with the exact unnormalized plain- + shader expressions and no shadow-flag/celestial-direction selection; +2. exercise the committed production atmospheric receiver shaders in a real + offscreen Vulkan pixel witness for both mesh and terrain. Holding authored + light/material/geometry constant while toggling only shadow flag and + celestial direction must leave the unshadowed base directional-light result + invariant; choose inputs for which the pre-fix branch gives a different + pixel. The witness is explicitly `Lane=Vulkan`, uses the existing dedicated + lavapipe/local lane, and fails rather than skips when that lane lacks Vulkan; +3. prove the committed fragment receiver and volumetric shaders still consume + `uShadowLightDirectionAndSource` for opt-in shadow projection/bias/visibility, + so the repair cannot silently disable or redirect shadows; +4. prove active and inactive receiver states still select/bind the same + atmospheric/plain pipelines and descriptors as before; +5. pin that neither plain shader source/SPIR-V nor any pipeline-selection or + renderer source changed from the contract parent; and +6. read the live IA-24 row and fail if it again claims celestial direction owns + base receiver lighting or omits the explicit light/shadow separation. + +Apply and independently restore at least these mutations, recording the first +discriminating failure for each in the implementation commit body: + +1. restore the shadow-flag/celestial-direction branch in + `mesh_atmospheric.vert`; +2. restore it in `terrain_atmospheric.vert`; +3. normalize either authored vertex-light direction; +4. redirect a fragment shadow/volumetric use from the celestial source to the + authored light, or remove its celestial-source read; and +5. restore IA-24's old assertion that pack-active base lighting follows the + celestial source. + +Return one clean implementation commit atop this contract; exact changed-file +and line counts; all mutation first failures; both `git diff --check` forms; +exact shader compiler command and generated hashes; the dedicated physical +`Lane=Vulkan` result; focused atmospheric shader/receiver/manifest/source- +resolver tests; Release solution build with zero warnings/errors; official +hermetic lane; and canonical-inclusive InstalledDat with every accepted +nonpassing identity named. Recipe 10 and prepared content are unchanged, so no +bake is required. No graphical client launch. + +Review is sequential. Retail/deviation pass 1/10 first verifies the three +named-retail functions and paired bytes, the stable authored-light rule, IA-24 +truth, pack-off preservation, and that the pixel/structural tests actually fail +on both old branches. Only after PASS does production/gate-honesty pass 2/10 +inspect the complete source-to-SPIR-V-to-pipeline path, run the real Vulkan +witness, reproduce at least mutations 1–4, and rule on portable/dedicated-lane +ownership and full gate sufficiency. A failed pass receives one bounded fix +contract. The owner-authorized ceiling is ten review passes. Nothing lands or +launches graphically before both lenses pass. + +After landing, the lead repeats the exact fixed-pose retail/off -> High -> +retail/off plus dusk transition used to file #469, with Release green, a clean +tree, UDP/client preflight, one background command, and graceful self-owned +shutdown. PASS requires no whole-world base-light jump as shadow work gates, +while pack-active shadow direction/visibility still changes and the final +retail frame restores. Record exact PNG paths; the result remains provisional +until owner inspection.