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

225 lines
12 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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 `02578441`**11,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 check**`ACDREAM_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.