diff --git a/docs/ISSUES.md b/docs/ISSUES.md index fd45b871..85d63c4e 100644 --- a/docs/ISSUES.md +++ b/docs/ISSUES.md @@ -93,12 +93,14 @@ remain closed. See **Camera-cell probe rounds (lead, 2026-09-03 21:28–21:37, `ACDREAM_PROBE_FLAP=1`, runs `logs/selfgate-20260903-212850-464-run-flap`, `-213145-464-zoom`, `-213343-464-tilt`, `-213626-464-mid`; routes `route-464-run/-zoom/-tilt/-mid.txt`):** in every frame of all four runs the sweep succeeded (`ok=True`), the eye was inside its resolved cell (`eyeInRoot=Y`), and the root fell back never (`res=None`) — the camera does NOT leave the cell. The DAT explains the two cells: `0xF4180113` (local AABB z 20.00–21.89, world z 180.0–181.9) and `0xF4180114` (z 181.89–190.7, y 16.14–24.0) are the SAME stairwell split horizontally at z 181.89 by an ExactMatch/PortalSide portal covering the whole ceiling; a player standing at the top (feet 181.12) already has their head in `0x114`, so the default eye 2.24 m up sits in `0x114` legitimately and the sweep's `pulledIn=0.00` is right. Zooming out (held CameraZoomOut, or the wheel — both call `RetailChaseCamera.AdjustDistance`) drives the desired eye to 10.31 m but the sweep stops it at 3.28 m, eye `(39.50,16.45,183.56)`, `collNormValid=True`: that contact is 0.31 m (the 0.3 m viewer sphere) in front of `0x114`'s nine-vertex EXIT portal (poly 29, flags 7, plane y=16.14, the whole back wall of the upper stairwell). Raising the camera stops it at the ceiling (`(39.50,19.59,188.27)`); look-up at the zoomed distance did not move the eye (desired stayed 3.44 m); look-up at default zoom lowered it to 1.0 m back / 0.8 m up; yaw ±1000 ms at the middle landing swung the eye to x 37.1–40.5 at z 180.8–181.0 inside `0x113`. None of those frames shows the owner's hall-through-the-walls view. **Revised reading:** the artifact is not the camera leaving the cell; the zoomed-out eye is pinned within the viewer-sphere radius of a large EXIT portal directly behind it, which is the exit-portal seam-band family (#456/#458: a portal the eye practically touches, the exit punch/seal and the `portalsDrawnCount`-gated Z clear of the outside-view block) — S4's depth/alpha territory, which is why the first-run `464-run-22.png` transient (the camera mid-descent, again next to an exit) shows the exterior slab. **Owner morning ask:** reproduce the zoom-out artifact once with the probe on so the exact eye, cell and `[flap]` portal lines are captured: ```powershell -$env:ACDREAM_PROBE_FLAP = "1"; $env:ACDREAM_SELFGATE_PASS = "testpassword"; & ./src/AcDream.App/bin/Release/net10.0/AcDream.App.exe --session-config tools/overhaul-selfgate/session.json 2>&1 | Tee-Object -FilePath launch-464.log +$env:ACDREAM_PROBE_FLAP = "1"; $env:ACDREAM_PROBE_FACILITY_STAIRS = "1"; $env:ACDREAM_SELFGATE_PASS = "testpassword"; & ./src/AcDream.App/bin/Release/net10.0/AcDream.App.exe --session-config tools/overhaul-selfgate/session.json 2>&1 | Tee-Object -FilePath launch-464.log et10.0\AcDream.App.exe --session-config tools\overhaul-selfgate\session.json 2>&1 | Tee-Object -FilePath launch-464.log ``` then `/teleloc F4180113 39.502899 19.589222 181.119247 1 0 0 0`, zoom out, tilt until the hall shows, take a screenshot, and note the time; the matching `[flap-cam]`/`[flap-sweep]`/`[flap]` lines in `launch-464.log` pin the frame. +**Investigation report (2026-09-03 21:47, `docs/research/2026-09-01-overhaul/464-camera-investigation.md`):** the read-only decomp + offline-replay investigation reaches the same conclusion independently: eleven enumerated sweep/root differences are each unreachable at this pose or make acdream MORE constrained than retail; the real-DAT replay seats the pivot in `0x114`, stops a straight-back boom on `0x114`'s east pier at y=16.448 for every pitch to 55 degrees and under the vault at 70 degrees, and the production walk from root `0x114` floods exactly `[0x114, 0x113, 0x112]` with seven exit views. **Reclassified: #464 is an interior-root DRAW defect with seven exit views (landscape flush / Z clear / exit seals under `outside_view.view_count > 0`, `PView::DrawCells` @0x005a4840), S4's depth/alpha domain, not the camera; the section 10 matrix row's invariant is re-worded from 'the eye stays inside' to 'root 0x114 with 0x113/0x112 flooded draws the stairwell solid'.** Two REAL openings let the eye out in both clients (a 4 m archway in `0x114` at y=16.15, x 33.98-38.02, reached by a boom yawed left; the open y=24 face behind a player facing up the stairs); retail's sweep passes them too (difference 7), so a frame from beyond them is again a draw-side question. The owner reproduction should also set `ACDREAM_PROBE_FACILITY_STAIRS=1` (the `[cathedral-stair]` line: viewer/player/root/eye/rootFlood per frame) next to `ACDREAM_PROBE_FLAP=1`. Owed when the fix lands: promote the two replays (the sweep stops on the pier under flat traversal; the walk from root `0x114` floods 114/113/112) into InstalledDat pins so the fix cannot regress the camera side. + ## #463 — Soak `turn` samples can report a 0.1 ms GPU p50 (the turn window catches non-world frames) **Status:** OPEN — found 2026-09-03 by the Campaign OVERHAUL v2 S3 review's perf re-measure. diff --git a/docs/research/2026-09-01-overhaul/464-camera-investigation.md b/docs/research/2026-09-01-overhaul/464-camera-investigation.md new file mode 100644 index 00000000..7a1b1835 --- /dev/null +++ b/docs/research/2026-09-01-overhaul/464-camera-investigation.md @@ -0,0 +1,68 @@ +# #464 - the cathedral stairwell camera: read-only investigation (2026-09-03 night) + +Workflow `investigate-464` (`wf_86230381-584`, one read-only agent, 132 tool uses, about 40 min) against the tree at `590fbb66c`, the named retail decomp, and an offline replay with the real engine and real DATs (F418's 24 interior cells, graph and flat traversal). Lead summary: the chase camera sweep and the render-root rule match retail's `SmartBox::update_viewer` / `CTransition::find_valid_position` / `SmartBox::RenderNormalMode` at the owner's pose; the frame is produced downstream of a correct root (0xF4180114) with seven exit views, which is S4 depth/alpha territory. The lead's four probe-on self-gate rounds the same night agree (`docs/ISSUES.md` #464). + +## Mechanism (acdream, line by line) + +ZOOM-OUT PATH (acdream, tree at 590fbb66c; camera/physics files unchanged vs the owner's ea76a3803 build — only RetailPViewRenderer.cs/WorldSceneRenderer.cs are dirty in the S4-c1 tree). +(a) Input: CameraFrameController.Tick (src/AcDream.App/Rendering/CameraFrameController.cs:75-92) feeds RetailChaseCamera.AdjustDistance/AdjustPitch (RetailChaseCamera.cs:339-366, 375-397; the CameraSet::Farther/Raise component limits |x|,|y|<10, -1.8 Roots.ViewerRoot ?? Buildings.OutdoorNode (:78, AD-21); WorldSceneRenderer (:179-225) → RetailPViewRenderer.DrawInside; walk root = ctx.ViewerCellId (RetailPViewRenderer.cs:188-205: interior id must be in the walk registry or it THROWS) → RetailFrameWalk.WalkFrame (Walk/RetailFrameWalk.cs:111: (id & 0xFFFF) < 0x100 → outdoor default view, else interior flood from the camera cell; portal admission = WalkPView seed side test :95-125 = the retail side==portal_side test). Retail: SmartBox::RenderNormalMode 0x00453aa0 (pc:92635-92660) roots on viewer_cell (a CObjCell*, land or env; the 'edi_2' mush is the viewer_cell==null test → landscape-only frame from viewer.objcell_id). +(i) Retail pattern verified line by line: update_viewer → AdjustPosition(pivot in the player's cell, viewer_sphere, stab) → makeTransition → init_object(player,0x5c) → init_sphere(1,&viewer_sphere,1) → init_path(cell, pivot, sought) → find_valid_position → set_viewer(sphere_path.curr_pos,0); viewer_cell = sphere_path.curr_cell; fallbacks AdjustPosition(sought) then set_viewer(player,1)+viewer_cell=null. +OFFLINE REPLAY (real engine + real DATs, F418's 24 interior cells, both CollisionTraversalMode.Graph and .Flat; scratch programs under the session scratchpad camsweep/ and walkrep/): at the owner's pose (feet 39.503,19.589,181.119 heading +y; pivot z=182.62) AdjustPosition seats the start in 0xF4180114 (the three stair cells are stacked 1.9 m layers: 0x112 z169.8-180, 0x113 z180-181.9, 0x114 z181.9-190.7, all with full-face exits at y=24 and 0x114 with a 4 m archway at y=16.15, x 33.98-38.02); a straight-back boom at every pitch 16.7-55 degrees stops on 0x114's east pier (physics polys 13/23/24, eye y=16.448, n=(0,1,0), pulled in 3.9-6.1 m) and at 70 degrees under the vault (n=(-0.8,0,-0.6)) — inside 0x114, ViewerCellId=0x114, Ok=true; seeding from the player cell self-heals to 0x114 at step 1; the production RetailFrameWalk from root 0x114 at every one of those eyes floods exactly [0x114,0x113,0x112] with 7 exit views, then the landscape and the buildings. + +## Differences from retail (each with reachability) + +- 1. Sweep flags: retail init_object(player,0x5c) also ORs IsPlayer 0x100 (OBJECTINFO::init 0x0050cf30 pc:274435 when weenie->IsPlayer), ethereal from the player's physics state and step_down = !MISSILE; acdream passes only 0x5c (PhysicsCameraCollisionProbe.cs:59-67, deliberate) and sets ObjectInfo.StepDown=true unconditionally (PhysicsEngine.cs:1897). Reachable effect: none for env/cell walls (only the PvP exemption block in object collisions). + +- 2. Containing-pick failure: retail check_other_cells (0x0050ae50 pc:272762-272795) leaves check_cell NULL when no cell contains the centre, every later transitional_insert returns OK without collision (0x0050b6f0 pc:273140), and update_viewer publishes viewer_cell=NULL; acdream keeps the CURRENT cell and keeps colliding against it (CellTransit.cs:1500-1560 'retail keep-curr' plus a non-retail lateral stab recovery) — acdream is MORE constrained, never less. + +- 3. Null viewer cell root: retail RenderNormalMode treats viewer_cell==NULL as outside and draws the landscape-only frame from viewer.objcell_id (pc:92645-92660); acdream replaces a 0 result with the PLAYER cell (RetailChaseCamera.cs:284-288, the FW3 fix). Only reachable through fallback 2 / cellId==0. + +- 4. Fallback-1 seed: retail AdjustPosition(&viewer_sought_position) re-seats at the sought eye's OWN objcell_id (pc:92878); acdream seeds from the player cell (AD-20, PhysicsCameraCollisionProbe.cs:96-101) and its outdoor snap requires SeenOutside on the seed. Dead in practice (Ok is false only for CurCellId==0/Invalid). + +- 5. Unloaded-neighbour admission: retail adds a portal neighbour whose CEnvCell is not loaded only when a sphere straddles the portal PLANE (pc:310060-310110); acdream's hint uses a PortalSide-directed half-space with a 0.02 m pad (CellTransit.cs:222-240). Irrelevant here (all 24 F418 cells resident). + +- 6. Outdoor other-cell branch: acdream skips a land cell's building and object channels when the terrain sample's cell id differs from the candidate id (TransitionTypes.cs:2878-2880 'continue'); retail CLandCell::find_collisions always runs env → CSortCell building → objects. Fires only at landblock edges. + +- 7. Building shell coverage is IDENTICAL (one building per ORIGIN land cell: CacheBuilding keyed by ComputeOutdoorCellId(building origin) = CLandBlock::init_buildings 0x0052fd80 → add_to_cell/CSortCell::add_building), so both clients let the viewer sphere leave the tower through the open y=24 face into land cell 0x000A without touching the shell (replay: eye (39.5,30,186), cell 0xF418000A, no hit). + +- 8. PerfectClip stop: retail collide_with_pt (0x0053a090) adjusts the check pos onto the contact and returns ADJUSTED, insert_into_cell re-tests up to 3 times; acdream CollideWithPoint (FlatBspQuery.cs:1541-1585) + InsertIntoCell (:2348) reproduce it — the replay lands the eye at exactly r=0.3 from the pier. No difference. + +- 9. Camera adjustment cadence: acdream scales the offset continuously per frame (CameraFrameController.cs:78-91) vs retail's per-keypress 0.2/8-degree units; same limits (|x|,|y|<10, -1.80, PView::DrawCells 0x005a4840; the S4 depth/alpha domain) or by a production-only state the replay cannot see (unpublished collision cells → no stop; a boom through an opening) — and #464's 'camera-versus-cell' classification is not supported by the sweep or root code. + +## Recommended fix + +Do not port anything into the camera for #464 yet: the sweep and the root rule already match update_viewer/find_valid_position/RenderNormalMode at this pose. First classify with one frame at the owner's pose and zoom: ACDREAM_PROBE_FLAP=1 ([flap-sweep]: start/ok/in/out/viewerCell/pulledIn from PhysicsCameraCollisionProbe.cs:77-90) plus ACDREAM_PROBE_FACILITY_STAIRS=1 ([cathedral-stair]: viewer/player/root/eye/rootFlood/visited/lookIn from RetailPViewRenderer.cs:383-410) and the acdream screenshot next to the owner's retail one. Expected (per the replay): out.y=16.448 or the vault, viewerCell=root=0xF4180114, rootFlood including 0x113/0x112 — then #464 is an interior-root draw defect with seven exit views and moves to S4 chunk 2 (retail alpha-depth transcript at THIS pose from the oh-capture kit, the landscape-flush/Z-clear/seal order under view_count>0, no camera change); the matrix row's invariant should be re-worded from 'the eye stays inside' to 'root 0x114 with 0x113/0x112 flooded draws the stairwell solid'. If instead the probe shows out beyond the pier/arch plane with viewerCell 0x113/0x114, the bounded retail-faithful port is difference 2 in CellTransit/RunCheckOtherCellsAndAdvance (a null check_cell after a failed containing pick, viewer_cell=null published, and the RenderNormalMode null-viewer landscape frame instead of the player-cell substitution at RetailChaseCamera.cs:284-288), which is S2 membership-owner scope. Either way, promote the two scratch replays (camera sweep at the stair pose stops on 0x114's pier under Flat traversal; walk from root 0x114 floods 0x114/0x113/0x112) into InstalledDat pins so the eventual fix cannot regress the camera side. + +## Slice + +S4 chunk 2 (the plan's own matrix row already places #464 under S4 / owner gate G3) once the probe confirms root 0x114 with the eye inside — the camera-versus-cell hypothesis should be retired from the row; only if the probe shows the eye outside the stairwell with an interior viewer cell does it become an S2 (membership owner: CellTransit containing-pick / viewer_cell null semantics) item. + +## Open questions + +- The exact boom the owner used: heading/yaw offset, number of Raise presses and zoom presses. A retail cdb capture at the pose with the oh-capture walk template (the P line = viewer eye + objcell_id, the EC/DC lines = flooded cells) settles where retail's eye stops (pier vs vault) and which cells retail floods; if retail's eye is at (39.5,16.45,z) inside 0x114 the camera side is closed. + +- One acdream frame at the pose with ACDREAM_PROBE_FLAP=1 and ACDREAM_PROBE_FACILITY_STAIRS=1 (both documented in docs/launch-options.md:319/:333): the [flap-sweep] out/viewerCell and the [cathedral-stair] root/rootFlood lines classify the defect in one line (eye inside + root 0x114 + flood 113/112 = draw side; anything else = membership/camera). + +- Did the boom pass through a real opening (the archway at y=16.15 x 33.98-38.02 with a yawed camera, or the open y=24 face with the player facing up the stairs)? Both clients' sweeps pass those (the tower shell 0x01001FB7 collides only from land cell 0xF4180009); the owner's retail screenshot should be re-read for the eye position in that case. + +- The running-down symptom (not characterized): during the descent the viewer cell hops 0x114 → 0x113 → 0x112 as the default eye (feet+2.25 m) crosses the horizontal portal planes z=181.895 (feet ≈ 179.65) and z=180 (feet ≈ 177.75) while the pivot is in yet another layer; at those frames the eye is within 0.3 m of a horizontal portal whose seed clip degenerates. Capture [cathedral-stair] root changes across the lead's route-464-run (which shot only screenshots, no probes) and check whether the player's own cell drops out of rootFlood for a frame; the presented-position vs physics-cell skew (difference 11) is the other candidate. + +- Whether the owner's Release build had F418's collision cells published at the moment of the zoom (a [flap-sweep] 'bsp=noroot'/'resolved=n' or ok=False would show an unpublished-cell no-stop, which the replay cannot reproduce). + +- S4 side: the retail alpha-depth/walk transcript at exactly this eye (seven exit views from an interior root) does not exist in the oh-capture kit; it is the capture S4 chunk 2 needs if the probe confirms root 0x114. + diff --git a/tools/overhaul-selfgate/route-464-arch.txt b/tools/overhaul-selfgate/route-464-arch.txt new file mode 100644 index 00000000..a30eabb1 --- /dev/null +++ b/tools/overhaul-selfgate/route-464-arch.txt @@ -0,0 +1,52 @@ +# #464 reproduction, part 6 (lead, 2026-09-03 night, after the investigation +# report): the 4 m archway in 0xF4180114 at y=16.15, x 33.98-38.02 lies +# behind-left of the top pose (player x=39.50). A boom yawed LEFT passes it +# where a straight boom hits the east pier at y=16.448. Run with +# ACDREAM_PROBE_FLAP=1 and ACDREAM_PROBE_FACILITY_STAIRS=1. + +wait world-visible 180000 +sleep 4000 + +command /teleloc F4180113 39.502899 19.589222 181.119247 1.000000 0.000000 0.000000 0.000000 +sleep 2000 +wait world-visible 60000 +sleep 3000 +screenshot 464-arch-00-default 15000 + +input down CameraRotateLeft +sleep 250 +input up CameraRotateLeft +sleep 400 +screenshot 464-arch-01-yaw250 15000 +input down CameraZoomOut +sleep 3000 +input up CameraZoomOut +sleep 500 +screenshot 464-arch-02-yaw250-out 15000 + +input press CameraViewDefault +sleep 800 +input down CameraRotateLeft +sleep 500 +input up CameraRotateLeft +sleep 400 +screenshot 464-arch-03-yaw500 15000 +input down CameraZoomOut +sleep 3000 +input up CameraZoomOut +sleep 500 +screenshot 464-arch-04-yaw500-out 15000 + +input press CameraViewDefault +sleep 800 +input down CameraRotateRight +sleep 500 +input up CameraRotateRight +sleep 400 +input down CameraZoomOut +sleep 3000 +input up CameraZoomOut +sleep 500 +screenshot 464-arch-05-yawright500-out 15000 + +close-client