acdream/docs/research/2026-08-06-c5c-closeout-handoff.md
Erik 1304dafa8b docs: C5c closeout + successor handoff; automated gate passes 11,196/4/0
Closes the automated half of C5c. Everything still owed needs the user at a
live client, and the probe strip cannot precede it.

AUTOMATED GATE — PASS. Complete Release suite on the final binary at
7b3e2895, run after deleting all 44 bin/obj directories rather than trusting
a rebuild flag: 11,196 passed / 4 skipped / 0 failed across all nine
projects. The clean-build precaution is not ceremony — this session had three
incidents of a runner serving a DLL that still contained deleted code, one of
them under -t:Rebuild. Campaign net: 11,106 at 02578441 -> 11,196, +90, with
no new skip anywhere and none of #302/#308/#321 firing.

STATE. Every implementation item in the placement cutover is landed and
dual-reviewed: C5b, #280, #276's remainder, AP-22 and AD-10, all with both
lenses PASS. #309 was accepted as a standing divergence by user decision
rather than fixed. What remains is connected/visual work plus the ledger
close.

WHAT THE HANDOFF CARRIES that a reader would otherwise have to rediscover:

- The connected gates owed, with the detail that matters — #280's route needs
  a LIFESTONE leg because the original repro was a recall, not a /teleloc;
  D-1's two reachability scenarios have never been reproduced live; and
  AP-136's six-step park check SURVIVES #309's deferral because it validates
  the shipped rollback path, not the deferred fix. Strip the probes after
  those, never before.
- Twelve issues filed (#321-#332). #331 is flagged first: its discriminator
  turned out to be the `body:` parameter rather than the fixture, it
  reproduces under the local player's own call profile on ramps as shallow as
  1.1 degrees, and nothing in the suite asserts uphill progress on a walkable
  slope — the test that found it passed vacuously.
- Register movement, including AD-65's corrected magnitude (25%/50%, not
  13%/29% — the row stated cos^2 and quantified 1-cos) and why that matters:
  it is a live lead for #269, and #269's existing do-not-retry covers friction
  and jump chains, not AdjustOffset.
- The bisect hazard from the C4 handoff, carried forward verbatim.
- Nine process findings stated as rules, each paid for this session. The two
  that cost the most: a blast-radius survey only reaches as far as the call
  graph its author walked (C5b missed an entire host with 11,000 tests
  green), and a test is not evidence until sabotage proves it discriminates
  (seven green-but-empty tests found or avoided).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-08-06 10:11:56 +02:00

12 KiB
Raw Blame History

C5c closeout + successor handoff — the placement cutover's automated half is done (2026-08-06)

Read this before any C5c or post-campaign work. It is the successor to 2026-08-05-c4-closeout-handoff.md (whose ⚠ BISECT HAZARD block still applies and is repeated in §6).

Branch claude/acdream-physics-divergence-5aa784, 21 commits from 02578441 to 7b3e2895. Nothing is pushed — the branch does not exist on the remote, and there are 388+ unpushed commits ahead of origin/main.


1. One-paragraph state

Every implementation item in the placement cutover campaign is now landed and dual-reviewed. C5b (classify-before-merge), #280 (portal destination prefetch), #276's remainder, AP-22 and AD-10 all shipped with both review lenses PASS. #309 was accepted as a standing divergence by user decision rather than fixed. What remains for C5c is entirely connected/visual work plus the ledger close — none of it can be done without the user at the client, and the probe strip cannot be done before it.


2. What landed, by slice

Slice Commits Outcome
C5b — classify before merge (#275) 735f0a72, ed806997, 23aa62f2, ff100cf3, 9ee9c1a1 Retired AP-131 and AD-60's legacy half. Seven production lines; five commits, because the review found a headless regression the change itself introduced.
#280 — portal destination prefetch 3aab05b0, 73cdb95c, bcb66ccd Reveal window now derives from the live streaming radii. D-1, an unrecoverable portal hang, was found by review and fixed.
#276 remainder 408c8e8f, fafc0b65 Settle now adopts the transition's resolved cell across an indoor seam.
#316, #317 429775d4, 1d2d4bb8 Report-only investigations. #316 cosmetic; #317 no retail basis.
#309 43cfdc4a Accepted as a standing divergence (user decision), not a planned fix. AP-136 is its permanent record.
AP-22 bc4679cd, 619de97a, ef976c6d Invented collision cylinder deleted in all three copies. Row retired.
AD-10 fe6ee877, 886333a2, fb454b74, 2223ed17, 7b3e2895 Retired by deletion — its stated justification was false at HEAD.

2.5 C5c's automated gate — PASS

Run at 7b3e2895 on the final binary, after deleting all 44 bin/obj directories (see §7 rule 4 — this session had three stale-artifact incidents, so an incremental result would not have been evidence):

dotnet test AcDream.slnx -c Release -m:1     # ACDREAM_PAK_PATH set

11,196 passed / 4 skipped / 0 failed, all nine projects:

Project Passed Skipped
AcDream.App.Tests 4,172 3
AcDream.Core.Tests 4,261 1
AcDream.Runtime.Tests 1,220 0
AcDream.Core.Net.Tests 764 0
AcDream.UI.Abstractions.Tests 546 0
AcDream.Content.Tests 125 0
AcDream.Headless.Tests 89 0
AcDream.Bake.Tests 15 0
AcDream.Cli.Tests 4 0

The 4 skips are the pre-existing set; no new skip was added anywhere in the campaign. None of the three known load-sensitive flakes (#302, #308, #321) fired in this run — but they are separately filed and must never be conflated if one does.

Net movement across the campaign: 11,106 at 0257844111,196, +90.


3. WHAT C5C STILL OWES — all of it needs the user

Nothing below can be discharged without a live client. The automated half is complete.

3.1 Connected gates, batched into one sitting

  1. #280's reveal gate. The user's original repro was a recall, so the route needs a lifestone leg, not only /teleloc, plus a first-login stop. A/B with ACDREAM_PROBE_REVEAL_RADIUS, ACDREAM_STREAM_RADIUS unset. The pre-fix run is expected to show the defect; the post-fix hold must be measurably longer. If it isn't, the gate widened nothing.
  2. #280 D-1's two reachability scenarios, never reproduced live: two consecutive recalls to the same landblock with walking in between, and a mid-hold quality-preset drop. Both are fixed and unit-covered; neither has been seen on a running client.
  3. AP-136's six-step park checkACDREAM_PROBE_PARK=1. This survives #309's deferral: it validates the SHIPPED rollback path (restorableOnCancel in SubmitPreparedPlacementCore, the shared core behind every production placement), not the deferred fix.
  4. Route-7 thickening — its gate passed on one cause=propagate probe line; the evidence is THIN.
  5. AD-65 / AD-66 need a local-player visual gate before any fix (see §5).
  6. C5c proper: two-client observation, canonical nine-stop soak, lifecycle/reconnect route on the final binary, and the user's visual matrix.

3.2 Then, and only then

The probe strip. Six flags — ACDREAM_PROBE_REMOTE_LANDING, ACDREAM_PROBE_REMOTE_SLIDE, ACDREAM_PROBE_PARK, ACDREAM_PROBE_REMOTE_TELEPORT, ACDREAM_PROBE_CHILD_CELL, ACDREAM_PROBE_LOCAL_TELEPORT — plus ACDREAM_PROBE_REVEAL_RADIUS. Strip as a family, and NOT before the gates above have consumed them. Stripping first would delete the instrumentation §3.1's items depend on.

3.3 Then close the ledger

Register / roadmap / milestones / memory, and the campaign ledger close.


4. Issues filed this session

# Subject
#321 DatSoundCacheTests concurrent-decode dedup, full-suite load (third load-sensitive flake)
#322 Two callers compute the same pre-placement flags from the same inputs
#323 A far-snap store can silently stale a pending initial-create receipt
#324 Graphical and no-window hosts run parallel, non-shared inbound routes
#325 Gate A's teleport test is narrower than retail's== where retail is "not older"
#326 acdream has no Viewing Distance option (retail's Render.LandscapeDrawDistance)
#327 No analogue of retail's DDD prefetch progress readout
#328 Camera far plane hardcoded 5000 f; retail's zfar is byte-verified 4000
#329 Portal wait cue arms 5 s late; retail emits per tunnel rotation segment
#330 Headless registers no live-entity collision at all — a bot walks through every NPC
#331 ResolveWithTransition refuses ALL uphill motion with a body supplied
#332 Headless bots appear to have no remote dead-reckoning

#331 is the one to look at first. Severity was raised from UNKNOWN once the discriminator was found: it is the body: parameter, not the fixture. With body: null the uphill sweep climbs; with a body it returns ok=False and zero movement — under a call profile identical to the local player's (IsPlayer | EdgeSlide, human two-sphere Setup), on ramps as shallow as 1.1°. A diagonal request keeps cross-slope X and zeroes only up-slope Y. Nothing in the suite asserts uphill progress on a walkable slope, which is why it was invisible — the test that found it passed vacuously.


5. Register movement

Retired: AP-1, AD-1 (C5a) · AP-145 (C5a) · AP-131, AD-60's legacy half (C5b) · AP-22 · AD-10.

Filed: AP-147 (delta-stream cardinality) · AP-148 (#325's Gate A narrowing) · AP-149 (outer ring accepts terrain-only) · AP-150 (wait-cue delay is not retail's trigger) · AP-151 (gate stricter than retail on the GPU-upload axis) · AP-152 (live path emits primitives and BSP additively where retail is exclusive; 172/5,935 Setups incl. BSP doors) · AD-64 (the duplicated residency decision) · AD-65, AD-66.

AD-65 deserves attention. Its magnitude was filed at half the truth: the row states cos²θ but quantified 1cosθ. Corrected to 25% short at 30°, 50% at 45°, confirmed by measurement (#331's probe: 0.0735 m for a 0.1 m request at 30.96° = cos²(30.96)). It is a live lead for #269's slope-slide residual — and note that project memory's #269 do-not-retry covers friction and jump chains, which are byte-exonerated; AdjustOffset is a different function and is not covered by it.


6. ⚠ BISECT HAZARD — carried forward

Commits 735f0a72..23aa62f2 contain a live headless defect: every remote entity's FullCellId is frozen at its placement value for the whole session in AcDream.Headless, and the local player loses one of AP-146's three cell-refresh edges. Introduced by 735f0a72, fixed at ff100cf3. Nothing throws; no test in the range catches it.


7. Process findings — stated as rules, each paid for this session

  1. A blast-radius enumeration only reaches as far as the call graph its author walked. C5b's was performed over the graphical OnPosition path and missed AcDream.Headless entirely — 11,000 green tests, one frozen host. Ask which traversal, and what it structurally could not reach. Both hosts, every time.
  2. Two independent adversarial reviewers converging is near-proof; a lone finding is a lead. It happened three times this session (the headless hole, the missing payload gate, D-1) and all three were real.
  3. Assume a test does not discriminate until sabotage proves it. SEVEN green tests covering nothing were found or avoided: C5b's conservation test, #276's three settler tests, #280's tautological integration fixture, the atlas-tier seam 4,170 tests missed, AD-10's only existing test (a dead method with a hard-coded formula), and AD-10's contract-specified T1 sabotage which came back green and was rejected rather than shipped.
  4. bin/obj can serve deleted code even under --no-incremental and -t:Rebuild. Three incidents. Delete all 44 directories before any verdict-deciding result. A stale artifact does not look like an error — it produces a plausible failure, or a plausible pass.
  5. Every contract in this campaign has been wrong at least once, and the implementation is what catches it. C5b's §3-D2 (a "dead" ternary that was live), #280's §7 (three false items), AP-22's §7.1 (a literal that was a three-way condition), AD-10's §7.1 (a non-discriminating sabotage). Brief implementers to rebut, and treat a reasoned rebuttal as more valuable than a compliant edit.
  6. Verify a cited address is the construct you claim. AP-150 mis-cited 0x004D7064 — a PStringBase constructor — as the SendNotice call, despite being filed with a byte-level disassembly. Precision of method does not prevent an error of line.
  7. Binary Ninja drops flag tests. if (-((eax_7 - eax_7)) == 0) renders an always-true where a real wrap-safe compare lives. Confirmed at Gate A (0x00454054), DoVectorUpdate (0x004521F5), HandlePlayerTeleport (0x00452186), and FindObjCollisions. Disassemble the PDB-paired binary wherever a comparison or constant is load-bearing.
  8. Do not fan out subagents. Two blowups: six agents spawning their own children exhausted a session usage limit and killed four tasks mid-flight; a later three spawned five more. Every brief must say "do not spawn subagents" explicitly — none of the early ones did. One code-writer at a time; the shared worktree tolerates no more.
  9. A shell failure inside a compound command can leave a commit claiming work it did not do. ef976c6d was needed because a heredoc invoked python (absent here; py is the binary) while the commit still reported success.

8. Where to start

  • Post-campaign: #331 first (§4), then AP-152 and #330 — both are real collision divergences with user-visible consequences.
  • Domain entry points remain claude-memory/project_physics_collision_digest.md and claude-memory/project_render_pipeline_digest.md.
  • The campaign plan (docs/plans/2026-08-02-placement-cutover.md) item 5 now records AP-22 and AD-10 as retired; item 3 records #280 as done.