Repository navigation
Conversation
Actual runtime screenshot progress: off baseline only
This is diagnostic baseline progress, not fog qualification. The run failed closed on one HTTP404 console error; fog-on variants did not execute. The image/component assertions passed, with no device-loss or runtime diagnostic. A fixture-only HTTP error log is now identifying the exact failed URL without suppressing the error. Native proof, fog-on review and hardware performance remain pending. |
Actual fog-on runtime progressOff baseline: Bounded fog enabled: Camera inside the volume: All nine unchanged captures and provenance · successful run 36990624761 Rendered source Still incomplete: the ownership receipt review finding, stronger isolated scattering/light checks, resize/repeated lifecycle qualification, native execution and hardware performance. Light toggles also change surface illumination, so their whole-frame differences are not yet an isolated volumetric-light measurement. These are actual software-rendered progress screenshots, not a merge-ready claim. |
|
Receipt-head runtime revalidation passed at This is software-rendered correctness progress. The current head adds stricter black-surface scattering controls and actual repeated teardown/return-to-off scenarios; that new run is pending. Native, resize and performance qualification remain open. Root typecheck/lint pass; full test invocation is blocked before its phases by this executor's |
|
Actual isolated-scattering progress at source Point light off, leaving directional scattering: All four unchanged PNGs and provenance. Pinned ROI mean RGB deltas are 15.96/255 for the directional source and 48.78/255 for the point source. Black evaluation area and foreground-plate patch are exactly zero; calibration pixels match exactly across controls. The overall run failed on a separate lifecycle setup-count mismatch, preserved in provenance. The new head now explicitly exercises four real fog targets with exact create/release/live assertions; that rerun is pending. These images establish software-rendered scattering progress, not completed lifecycle, native or performance qualification. |
|
Actual browser target/depth resize and resource-accounting proof passed: run 37000862324, source Small render target (browser CSS capture remains 640×400): Exact provenance, observations and limited workload/cost record. These are browser software correctness captures, not OS-window lifecycle or hardware-performance proof. Current head adds the independently reviewed native host route and measured render boundaries after every lifecycle transition; native execution remains pending. |
Native screenshot progress: rendering and teardown pass; resize remains failingActual Linux ARM64 native host captures at source Fifteen pre-resize arms passed strict per-arm console/readiness/adapter guards, including inside/outside fog and actual four-target create/release cycles. Decoded actual PNGs also pass the pinned zero-density, restored-off and isolated-scattering metrics after artifact download; this recomputation is recorded separately because the hosted script stopped before its final metric phase. Final off returns to five renderer textures and zero live fog targets. The native run failed at Unmodified PNGs, host/bundle hashes, adapter, all accepted arms, pixel metrics and failure provenance. Draft retained; no default tier or hardware-performance claim. |
…ad source The starter shipped src/render/volumetricFog.ts and nothing called it, which two template contracts reject: every module under src/render must be imported by the game, and every exported render symbol must be called. Play.ts now passes a per-graph `fog` factory to setupPost, which forwards the medium to WorldEnvironment's existing baseColour hook and releases the previous one before a tier change replaces the chain. MIST is off, so createVolumetricFog returns before it allocates and the shipped picture is unchanged. Also register the two temp-dir creators the guard rejected — both remove their scratch root in a finally — and drop five retained fog PNGs that are byte-identical to copies the authoritative 640c103 proof still carries.
…s, and let it own the air Four reviewer findings on the fog source, plus the two red invariants the review surfaced alongside them. The authored mist was a `MIST` block in `src/scenes/Play.ts`, which puts a look decision in a scene. It is now `STARTER_MIST` in `src/render/volumetricFog.ts`, and `Play.ts` only hands it the live `ctx.renderer.kind` — the old block hardcoded "webgpu" while `threenative.config.ts` asks for `preferWebGPU`, so the WebGL fallback would have built a medium the chain then silently dropped. `STARTER_MIST` is typed `Omit<IVolumetricFogOptions, "renderer">`, so no scene can claim a backend the renderer does not have. It also declared `environment.sceneFog: false` while `sky.ts` installs the scene's `FogExp2`, and the medium's own guard refuses to compose over a `scene.fog`. Turning the advertised single flag on would therefore have thrown. `createVolumetricFog` now takes the scene, takes its fog over for its own lifetime and restores it on disposal: one flag is enough, the air is never counted twice, and disabled stays allocation-free and side-effect-free. `environment.sceneFog` is deleted rather than left as a field that can only be false. There is no automatic sun — the generated source and the template instructions now say the mist is lit by `ambient` until a `sun` with an initialized shadow map is passed. `verify-volumetric-fog.spec.ts` uses `test-support/temp-dir.ts` again, so its temp-dir-guard allowlist entry is gone instead of justified. The `fog` lane in `integration.yml` gained the paths this repair touches, so fog qualification reruns when the shipped wiring changes; develop's lanes and the single job/stage pair are untouched. Red-green first: the scene-fog take-over test failed against a medium that only restored the fog on dispose, and the two new source regressions failed against the pre-repair files. Fog and fixture suites pass 30/30, temp-dir-guard with the verifier 15/15, scaffold plus template contracts 104/104, root and package typecheck pass, the doc-link/budget/CI-structure/CI-needs/mirror selection 230/230, and `pnpm lint` exits 0 with 1042 warnings. Two gates the review did not name were failing and are fixed here. `docs/verification` measured 72.7 MB against its 72 MB cap — the previous commit claimed 71.9 MB without measuring it — so the retained images are now the two authoritative fog frames plus the 2.5 KB black control, every `provenance.json` stays with its per-arm SHA256, and the six checkpoint paragraphs that linked a deleted image name the run, artifact id and digest instead; `pnpm budgets` now reports ok at a measured 71.9 MB. And the starter's CLAUDE.md mirror had crossed the 100-line scaffold limit, so the fog instruction is merged into the existing `setupPost` paragraph. Fresh hosted browser and native fog qualification plus the full repository CI are still required before any box moves; the 640c103 proof stays source-scoped to its own tree.
The fog lane used (?:...) non-capturing groups, which grep -E does not support, so the lane never matched and the integration fog job stayed false. Plain groups keep the same alternation under POSIX ERE.
…mist Disposal restored the captured scene.fog unconditionally, so a fog the game authored while the medium lived was silently clobbered on scene teardown. The medium owns the slot only while it holds it: restore the captured fog when scene.fog is still null, and leave a later authored fog as the live one. Red: the new case failed with the unconditional restore (expected the later FogExp2, got the captured one).
…it exposed The sweep ran every browser arm green on an nvidia/turing adapter at the pre-repair source c364558, with the cost arms separating transport pixels, ray steps and host frame distributions and refusing any hardware claim. It is recorded as source-scoped evidence, not as qualification of the current head: the standalone fixture imports the fog source this branch just changed.
The strict supersession detector reads the calibration card's visible=false as the pattern prewarm replaces. Keeping it visible at zero opacity is not an option here: the lifecycle and cost arms assert renderer draw and texture counts, so an always-submitted card would move the baseline they read. The card is a hidden reference the scattering controls alone reveal, which is what the annotation now says.
…e source The branch's native presentation and status-test additions moved the source digest, so the budgets gate failed closed against a record last measured on develop. Re-measured through native:coverage on the downloaded dependency tree: 44 declared contract targets instead of 42, and TOTAL line coverage 78.77% from 78.72%. No floor, threshold or cap moved.
The half arm never asserted the resolution it asked for, the summary recorded hardcoded transport pixels and ray steps, the overlap arm proved only an authored flag, and shadowOutside echoed the mode name rather than the light's actual shadow-map coverage. The wall question needed no new proof: fogLightPixelMetrics already requires the wall patch to be exactly black in all four scattering arms while the same arms show a real scattering response, which is depth-correct occlusion with the same camera and lights. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…itted ratio The first overlap gate used a channel-ratio floor picked above the real measurement and failed the actual 29-arm run. Replace it with two independent physical floors — a channel delta above 8-bit dithering and a positive signed mean, because added extinction can only brighten — so a darker or noisier overlap frame cannot pass. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The overlap gate goes back to the values it was first pinned at — five percent of channels changed by more than two levels, and a four-level maximum channel delta, both absolute differences. The signed-mean clause added in b339f89 is dropped: added extinction adds in-scattering along the ray, and a generally lit composite is not obliged to get brighter. The fixture's control was the defect, not the bar. The second bound sat where the wall, the pillar and the ceiling beams hid it, and fell off faster in height than the primary bound, so the measured effect was 0.03733 changed channels against a 0.05 floor. It is now pinned to the room's whole lit interior, Box3(-4.2, 0, -9.2)..(4.2, 3, 2.6) at density 0.28, baseHeight 0.5 and heightFalloff 0.32 — nested inside the unchanged primary bound, chosen and recorded before the capture. Two real browser WebGPU arms measure 0.09383 changed channels and a maximum delta of 43. The synthetic guard still fails identical frames and a nine-level delta on one of two pixels. fogInsideShadowMap sampled the volume's eight corners, which is false `false`: a bounding volume can enclose the whole shadow box with no corner of itself inside it. It projects the volume by the shadow camera's own view-projection and intersects the conservative clip-space AABB, reading the depth range from camera.coordinateSystem because Three syncs the shadow camera to the frame camera's convention (0..1 on WebGPU, -1..1 on WebGL). The new 40 cm map inside the room, with no room corner inside the map, failed first and passes after; the same map translated clear stays outside. fogFrameCost reported gpuMs beside a thirty-frame window, reading as a thirty-sample mean. The retained costFull console answers 4 of 30 with 26 stale, so the summary now carries gpuSamples and gpuStaleFrames and names the coverage in its own qualification. No threshold moved and no performance claim follows.
All 29 browser arms pass with zero diagnostics on the committed source carrying both repairs. Phase 3's native box, both acceptance criteria and every promotion claim stay open: the native audit still covers a6a155e.
fogFrameCost read gpu.samples/gpuStale through Number(), so a malformed or negative count reached the summary as NaN or a negative frame count, and a gpuMs with no gpu block read as a mean over an invented zero frames. parsePerformanceMarkers validates hitch and projection payloads only and pushes budget windows unvalidated, so the check belongs in the verifier. Both counts must be nonnegative integers within the measured window, and a window reporting gpuMs must carry a positive sample count; a window with no GPU query stays an explicit zero and unmeasured. Input validation only: no threshold, rendering path or fixture moved.
Rename the generated FogMedium type alias and its imports; no runtime bindings change. Refresh only starter's measured scaffold digest. Root typecheck and lint pass, and the scaffold/fog selection passes all 90 tests.
All six phase items and both acceptance criteria are now verified at the exact head b93944e, so the file moves to docs/PRDs/done/ while its sibling batch PRDs stay active. Evidence is recomputed from this run's downloaded artifacts, not carried over from 640c103: hosted integration run 37147171365 passes 29 browser WebGPU/SwiftShader arms (392 in-arm + 13 cross-arm assertions) and 29 Linux ARM64 QuickJS/wgpu-native/Mesa llvmpipe arms (419 in-arm + 13 cross-arm + 29 authored 5% nonblank results), plus both no-fog resize controls, the compiled acquisition status contract and the actual GPU destination-pixel test. Full CI run 37147171521 is SUCCESS with 72 selected checks green and ci-required passing. Only starter's generated-tree digest moved, to d51d898f, for the type-only IFogMedium -> FogMedium rename. No threshold, fixture, scenario or rendered path changed, and no gate was weakened. The two inbound links that the move broke are repointed; historical checkpoints stay as written.
…ic-fog Reconcile the merge GitHub reported as CONFLICTING/DIRTY before promotion. Sole conflict is .github/workflows/integration.yml, where this branch's fog/fog-native jobs and develop's new world-capture job were inserted at the same point. Resolution keeps both sides verbatim: upstream's streaming, virtual-shadow, resolution-scaler and world-capture world is untouched, and both fog jobs, their path filter and their retained artifacts are unchanged. The PRD's promotion line now says runtime qualified at b93944e and archive commit b655f43, instead of claiming the archive happened at b93944e. No fog source, shader, threshold, fixture, scenario or scaffold digest moved: scaffold/fixture/verifier/native-proof specs pass 122/122 and CI structure/needs/temp-dir-guard/primary-docs pass 214/214 on the combined tree, with root typecheck, lint, budgets and check:docs green.
…ation Appends the reconciliation evidence for merge 8431684 to the archived PRD, after the run that produced it: the single integration.yml conflict and its both-sides-kept resolution, the unchanged lockfile and scaffold digests, the green local gates on the combined tree, and a fresh 29-arm browser WebGPU requalification at 8431684 (nvidia/turing, private Xvfb 1600x900, summary.json ac608e32, zero==off byte-identical, overlap 0.093828125 / 43). Linux native is explicitly not carried forward from b93944e: only the hosted fog-native lane can qualify it at this head, so the earlier native proof stays source-scoped and the exclusions are unchanged. No box was moved and no threshold relaxed; prd:progress still prints prd:100% — ready.
…ic-fog Develop advanced again while the first reconciliation was in flight: 2c005f9 (#418) replaces the per-lane gh api + grep selection in the integration paths job with scripts/ci-integration-scope.mjs, which is strictly fail-closed. A PR that conflicts gets no pull_request run at all, so this merge is what lets the fog lane execute again. Sole conflict is the same file's lane-selection block. Resolution keeps upstream's selector verbatim and registers this branch's fog lane in the new TN_LANE_FILTERS inventory, because the script refuses to start when a paths output has no filter or a filter has no root job. The fog pattern is the old lane filter with the trailing integration\.yml clause dropped: upstream now selects a lane for workflow edits by comparing each job and filter instead, and the fog job plus fog-native dependency are unchanged. This is a selection-mechanism port, not a gate change: the fog regex still names exactly the files the lane's steps execute, and ci-integration-scope, ci-structure, ci-needs and ci-template-selection pass 256/256 on the combined tree. No fog source, shader, threshold, fixture, scenario or scaffold digest moved.
…ualification Appends the 2c005f9 reconciliation to the archived PRD after the run that produced it: why a conflicting pull request gets no hosted run at all, why the fog lane had to be registered in the new TN_LANE_FILTERS inventory or the selector throws, and the measured selection result (this merge selects all eight lanes as the shape change, a fog-source-only list selects fog alone). Records a fresh 29-arm browser WebGPU requalification at 6701a80 with its own arm digests and summary.json 9cd50fb3, since that is a new source. Linux native at this head stays unticked and unclaimed until the hosted fog-native lane runs; the b93944e native proof remains source-scoped. prd:progress still prints prd:100% — ready, and no threshold, fixture or box moved.
…ic-fog Develop advanced a third time (#419) while the second reconciliation was in flight, consolidating docs/PRDs into contextual folders. That change conflicts with this branch's archived VQ-07 PRD in a way that needs a decision rather than a textual merge, so it is resolved on the docs' own rule: a finished PRD is never un-filed or replaced by a fresh plan. The consolidation moved the original PROPOSED planning copy from docs/PRDs/batch-2026-10-01-visual-quality/ to docs/PRDs/rendering/, which put a second, unticked PRD-VQ-07 next to this branch's completed, archived copy in done/. The stale planning copy is deleted so exactly one VQ-07 exists and it is the qualified one; its ticked boxes, evidence and landed commits stay. No develop document links to that path (only VQ-08 names VQ-07 in prose), so nothing is left dangling. The batch README row this branch had repointed at the archive is gone with the folder, and no replacement index exists on develop. Everything else is develop's: all thirteen other VQ PRDs and the rest of the folder moves are preserved as upstream made them. This is a docs-only delta, so no fog source, fixture, scenario, threshold or CI contract changed; root typecheck and lint exit 0, the doc-links/evidence/mirror/primary-docs selection passes 46/46, check:docs exits 0 and budgets reports evidence budget: ok.
|
Superseded by #397 to keep related exposure/fog work on one coherent CI board. The published survivor head is The frozen native dry-run repair is retained with a separately reviewed lint-only lazy-import split. All 84 native runner tests pass; timeouts and required scenarios are unchanged. The actual combined browser GPU evidence, including off/both screenshots and the preserved first failed lifecycle attempt, is linked in #397. Sailing first-height readback and fluid CI failures remain unresolved; this supersession is not a merge to develop or a green exact-head CI claim. Closing this source PR only after verified publication and cross-links. Its branch is retained. |











Bounded, depth-correct volumetric fog now ships as generated starter source in
src/render/, with opt-in density, colour, overlapping bounds, height falloff, resolution and step controls. The default stays off. Directional shadows and an explicitly unshadowed finite-range point-light subset contribute independently of extinction. Scene depth occludes the medium; inactive, unsupported and zero-density paths allocate no fog targets. Owned targets/materials and scene-fog suppression are released through the existing graph lifecycle.PRD-VQ-07 is complete and archived: six phase boxes and two acceptance criteria verified; label
prd:100% — ready.Validation at
e87faa6f9669e85742db659a08a15ec5a8cd8ea5:ci-requiredand native platform checks. Rain's initial adapter/device-loss failure passed on its exact-job retry.11283674657, SHA256dc6c332a…; Chromium WebGPU/SwiftShader, 640×400 screenshots.11285180012, SHA2565a9d03ff…; llvmpipe, runtime5a164cc2…, bundleb76f3417….Nonblocking integration failure:
fluid consumersfailed three executions with screenshot stability timeout, advance timeout, then SwiftShader device loss/blank capture and a failedmaxSpeedobservation (latest artifact11285747559). No more retries or threshold changes were made. Independent review confirmed this PR changes no fluid simulation or capture-harness code; its output-graph APIs are unused by that browser fixture. The integration run therefore ends failed although both fog jobs passed. This is outside VQ-07's scope; branch rules require the passingci-requiredcheck. No protection or required check is bypassed.Qualification is software correctness only. GPU means retain sparse query coverage (browser4/30 answered, native4/30,4/30,3/30). No phone/hardware performance, default-tier admission, OS-window lifecycle or wider local-shadow claim is made.
Protected merge queue status
The PR remains unmerged. Merge-group CI 37156742265, attempt 2 passed RTS on its bounded retry, but required rain still failed:
rain-simulation-advancesobserved zero frames because the WebGPU adapter request resolved null (TN_PLAYTEST_CAPTURE_PROVENANCE_MISSING). Its preceding scenarios passed assertions with software-device-loss warnings.ci-requiredcorrectly failed. No source, assertions, provenance requirements, timeouts, or branch protections were changed. Further blind retries stopped after the repeated adapter failure; queue runner WebGPU availability remains unresolved.Rain software-quality correction at
edd5e1d6eef2ef306234a615d6f392861b2ee0f8Rain previously chose the software-safe built-in post chain but its UI still selected the expensive high study on wide windows. Scene loading now chooses the existing performance study before the first software-rendered frame; URL and player choices remain explicit overrides, and hardware retains its existing 700px window policy. The four-tier scenario explicitly chooses high through its existing quality menu, with every original assertion, transition and screenshot retained.
Validation: 87 focused tests, scoped scaffolder TypeScript, all 66 scaffold contracts and the normal pre-push lint/docs/agent/drift checks passed. Independent review found no blockers. A generated byte comparison reproduces both Rain scaffold hashes: exactly the four reviewed template files changed, with 108 files unchanged; every other template pin and the hash guard remain intact.
Matched local simulation runs on real SwiftShader passed the original 120-tick assertions on both baseline and candidate, with empty diagnostics. The candidate retained performance/32 cloud steps rather than baseline high/64. The corrected four-tier gate passed all eight original assertion results and retained six screenshots, with empty diagnostics; the labeled requested-high state observed high/64 steps before the original high checkpoint, followed by balanced/48, performance/32 and ultra/88. The initial unsupported resource-setup experiment failed before assertions because the engine state provider is read-only; its failure evidence was retained and that setup removed.
These runs establish the bounded quality-policy fix, but the healthy baseline does not establish the cause or resolution of the queue's adapter-null/device-loss failures. Fresh CI 37169021789 and integration 37169021686 are pending on this exact head. No blind retry, workflow/routing/runner change, merge or protection bypass was performed.
The fog implementation, qualification fixtures and completed VQ-07 PRD are byte-identical to
e87faa6fin this correction. The fog acceptance evidence above remains tied to that original head; it is not presented as a fresh run on the new head. New-head fog and other selected integration checks remain subject to current CI.