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>
This commit is contained in:
Erik 2026-08-06 10:11:56 +02:00
parent 7b3e2895cd
commit 1304dafa8b

View file

@ -0,0 +1,225 @@
# 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.