acdream/docs/research/2026-05-20-m15-kickoff-handoff.md
Erik f02bd1fb4d docs(handoff): M1.5 kickoff — pickup prompt + workaround inventory
Comprehensive session-end handoff for picking up M1.5 in a fresh
session. Includes:
  - Today's 11 shipped commits (table with retail oracle anchors)
  - Visual verification status at Holtburg inn + cottages
  - Open issues tagged M1.5 scope (#80, #81, #83, #88, #90, #93, #94)
  - Workaround inventory with A6.P4 removal criteria:
    - #90 sphere-overlap stickiness (PhysicsEngine.ResolveCellId:285)
    - TryFindIndoorWalkablePlane synthesis (TransitionTypes.cs:1294)
  - A6.P1 cdb probe spike methodology + 9 capture scenarios
  - Pasteable session-start prompt
  - Anti-patterns from today's session (especially: don't ship
    workarounds without flagging them upfront — #90 was a slip)
  - Code anchors + retail decomp anchors for A6 brainstorming

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-21 11:12:46 +02:00

400 lines
22 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.

# M1.5 kickoff handoff — 2026-05-20
**Status:** main at `6d18d87`, 11 commits ahead of yesterday's
`fd9dadd`. 1147 + 8 baseline maintained throughout. Five surgical
indoor-physics fixes shipped + M1.5 milestone promoted. Holtburg
inn + cottage interiors visually verified.
**Pasteable session-start prompt at the bottom of this doc.**
## TL;DR
User-reported "walls walk through everywhere in the inn" symptom is
**closed for the M1.5 baseline** via five fixes:
1. **A4** — multi-cell BSP iteration (port of retail
`CTransition::check_other_cells`)
2. **#89** — sphere-overlap in `CheckBuildingTransit`
3. **#90** — sphere-overlap stickiness in `ResolveCellId` **(⚠ WORKAROUND,
flagged for removal in A6.P4)**
4. **#91** — indoor cell shadows in `FindObjCollisions`
5. **#92** — server cell id at player-mode entry
The visible symptom is gone. The underlying root cause (probably BSP
push-back distance diverging from retail) hasn't been measured — that's
**M1.5**, which was opened today and is now the active milestone.
**M2 ("Kill a drudge") is deferred** until M1.5 lands. Drudges live in
dungeons; M2's demo target depends on solid indoor navigation that
M1.5 delivers.
## State both altitudes
> **Currently working toward: M1.5 — "Indoor world feels right."**
>
> **Current phase: A6 — Indoor physics fidelity (cdb-driven).**
>
> **Next concrete step: A6 spec authoring (brainstorm → write-plan).
> Then A6.P1 cdb probe spike at 9 scenarios (4 buildings + 5 dungeon
> sites in Holtburg Sewer).**
## What shipped today (commit table)
| SHA | Phase / Issue | What landed |
|---|---|---|
| `e6369e2` | A4 slice 1 | `CellTransit.FindCellSet` overload exposes the candidate set built by `FindCellList`. 3 unit tests. Refactor-only, no behavior change to existing callers. |
| `493c5e5` | A4 slice 2 | `Transition.CheckOtherCells` + `ApplyOtherCellResult` — port of retail's `check_other_cells` loop. 6 unit tests. Method exists but is not yet called from production code. |
| `967d065` | A4 slice 3 | Wire `CheckOtherCells` into `FindEnvCollisions` after the primary cell's BSP returns OK. 1 integration test. |
| `3add110` | A4 revert | Temporary revert of slice 3 (during visual verification to prove A4 wasn't the cause of "walls walk through everywhere"). |
| `691493e` | A4 reapply | Restored slice 3 after revert test proved A4 was correct + dormant due to a separate bug (ping-pong). |
| `1534990` | docs | Initial A4 ship + #90 ping-pong filed as separate issue. |
| `4ca3596` | #90 ⚠ WORKAROUND | `BSPQuery.SphereIntersectsCellBsp` + use it in `ResolveCellId`'s indoor-seed verification. Sphere-overlap stickiness prevents flip-out on push-back. **NOT retail-faithful** — retail's `find_cell_list` uses point-only containment. Flagged for removal in A6.P4 once the root cause (probably BSP push-back distance) is fixed. |
| `c0d8405` | #91 | `ShadowObjectRegistry.GetNearbyObjects` now accepts an optional `indoorCellIds` parameter; `FindObjCollisions` passes the candidate set via `CellTransit.FindCellSet`. Closes "interior items don't block" (regression from A1.5's interior-cell shadow scoping). |
| `7ac8f54` | #89 | `CellTransit.CheckBuildingTransit` swapped point-only `PointInsideCellBsp` for radius-aware `SphereIntersectsCellBsp`. Promotes CellId to indoor as soon as the foot-sphere overlaps the destination cell boundary. Retail-faithful — direct port of `CCellStruct::sphere_intersects_cell`. |
| `23ab173` | #92 | `GameWindow.EnterPlayerModeNow` now uses `spawn.Position.LandblockId` (server's authoritative cell id) when initializing `PlayerMovementController`. Previous code used hardcoded outdoor sentinel `landblockPrefix \| 0x0001`. Closes "login-inside-inn ran through exterior walls until I re-entered." |
| `6d18d87` | M1.5 promotion | `docs/plans/2026-05-12-milestones.md` (M1.5 block inserted), `docs/plans/2026-04-11-roadmap.md` (A6 + A7 phases), `CLAUDE.md` (currently-working-toward + baseline paragraph), `docs/ISSUES.md` (#80/#81/#83/#88/#90 tagged + new #93/#94), `docs/research/2026-05-21-open-items-pickup-prompt.md` (landscape table). |
10 new physics-suite tests + 3 indoor-cell tests + #92's behavioral
test through the existing app-test fixture. **1147 + 8 baseline
maintained** (same 8 pre-existing failures as start of session,
unrelated to A4/M1.5 work).
## Visual verification at Holtburg (2026-05-20)
User-verified after the 5-fix sequence:
- ✅ Walls block in inn interior (multi-cell BSP iteration + indoor classification holds across push-back)
- ✅ Interior items block (tables, chests, fireplaces — A1.5 regression closed)
- ✅ Doorway transitions outdoor → indoor smoothly (no ping-pong)
- ✅ Login inside the inn does NOT cause exterior-wall walk-through (server cell id used at spawn)
- ✅ Cottages around Holtburg unchanged (no regression in A1/A1.5/A1.6/A1.7)
## What's still broken (M1.5 in-scope)
Per `docs/ISSUES.md` (tagged "M1.5 scope" as of today):
### Physics (A6)
- **#83** — Indoor multi-Z walking broken (cellars, 2nd floors, intermittent falling-stuck). Umbrella issue, open since 2026-05-19. M1.5 primary.
- **Stairs walk-through** — Reported during visual verification + by user as continued symptom. Subsumed by #83.
- **2nd-floor walking / cellar descent** — Reported by user. Subsumed by #83.
- **#88** — Indoor static objects vibrate. Suspected sub-step state corruption family.
- **#90** — CellId ping-pong (workaround in place; A6.P4 removes it once root cause is fixed).
- **`TryFindIndoorWalkablePlane`** — Per-frame CP synthesis (99.87% MISS rate per 2026-05-21 walk-miss probe data). Retail retains CP via Mechanisms A/B/C; we synthesize per-frame. A6.P4 deletes it.
### Lighting (A7)
- **#80** — Camera on 2nd floor goes very dark.
- **#81** — Static building stabs don't react to atmospheric lighting.
- **#93 (new)** — Indoor lighting broken umbrella. M1.5 primary.
- **#94 (new)** — Held items project spotlight on walls.
## Workarounds in tree — must remove during A6.P4
Two known unfaithful workarounds shipped or retained today:
### 1. #90 — Sphere-overlap stickiness in `PhysicsEngine.ResolveCellId`
**Location:** `src/AcDream.Core/Physics/PhysicsEngine.cs:285-300`. Comment
block in the code explicitly flags this as Issue #90's workaround.
**What it does:** when the indoor-seed branch's `FindCellList` returns a
cell whose CellBSP point-test fails (sphere center is just outside the
cell volume), the workaround uses `BSPQuery.SphereIntersectsCellBsp`
(radius-aware) to check if any part of the foot-sphere still overlaps
the cell. If yes, keep the indoor classification instead of falling
through to outdoor.
**Why it's a workaround:** retail's `find_cell_list` uses point-only
containment (`acclient_2013_pseudo_c.txt:308810` calls
`point_in_cell` via vtable +0x84). Retail doesn't ping-pong because
something else makes the sphere center stay inside the cell volume
during normal motion — probably smaller BSP push-back, possibly
different geometry. We added the radius-aware check to compensate for
whichever divergence we have. **Don't keep this code long-term.**
**A6.P4 removal criteria:** once A6.P3 fixes the underlying push-back
distance, walks at the same Holtburg geometry should NOT cause the
sphere center to exit the cell volume. Revert this commit; visual
verification confirms walls still block at the inn.
### 2. `Transition.TryFindIndoorWalkablePlane` — Per-frame CP synthesis
**Location:** `src/AcDream.Core/Physics/TransitionTypes.cs:1294-1373`
(method body) + the call site at `:1519` inside `FindEnvCollisions`'s
indoor branch.
**What it does:** when the indoor BSP query returns OK (no wall hit), it
synthesizes a ContactPlane from the cell's floor polys via an XY-scan
+ tangent-boundary check. 99.87% of synthesis attempts MISS (per
`launch-walk-miss-capture-findings.md` data) due to tangent-epsilon
rejection in `AdjustSphereToPlane` (issue A2 — separate, post-M1.5).
**Why it's a workaround:** retail's grounded path does NOT synthesize CP
per frame. Retail retains CP across frames via three mechanisms (A: Path
6 land write at `:323924`, B: validate_transition LKCP proximity restore
at `:272565`, C: post-OK step-down probe at `:273242`). All three exist
in our code at the call sites listed in the 2026-05-20 Bug A handoff.
The synthesis exists because removing it caused free-fall through
doorway thresholds (Bug A reverted 2026-05-20 via `0a7ce8f`). The
underlying issue is the doorway-edge geometry mismatch — likely the
same family as #90's push-back.
**A6.P4 removal criteria:** once A6.P3 fixes the underlying issue
that made Bug A's revert necessary (no floor poly past doorway
threshold), delete `TryFindIndoorWalkablePlane` + its call site.
Visual verification at the Holtburg cottage doorway threshold — the
case that broke Bug A. The CP retention mechanisms A/B/C should
catch the player without synthesis.
## M1.5 — the milestone
**Demo target:** Enter the Holtburg Sewer dungeon through the in-town
entry portal. Navigate to the end (57 rooms with stairs + a multi-Z
chamber). Exit back to town. Throughout the walk:
- Walls block (no walk-through anywhere, indoor or stab-shell).
- Stairs work (ascend + descend without falling through or stuck).
- Items block (sarcophagi, urns, decorations, tables, chests, fireplaces).
- Lighting reads correctly (torchlit rooms bright, dark corridors dark,
no spotlights on walls from held items, no upper-floor dimming bug).
- Cell transitions are smooth (no ping-pong, no CellId flicker).
**Phases:**
- **A6 — Indoor physics fidelity (cdb-driven).** Sub-slices A6.P1
(probe spike), A6.P2 (analysis), A6.P3 (fixes), A6.P4 (workaround
removal). ~911 days.
- **A7 — Indoor lighting fidelity (RenderDoc + retail-decomp driven).**
Sub-slices A7.L1, A7.L2, A7.L3. ~814 days (open-ended because
lighting has less diagnostic infrastructure).
**Estimated timeline:** 1726 days focused work / 35 weeks calendar.
## A6.P1 — the cdb probe spike
**Reads first:**
- `CLAUDE.md` § "Retail debugger toolchain (live runtime trace)" — full setup, watchouts.
- `docs/plans/2026-04-11-roadmap.md` § "Phase A6 — Indoor physics fidelity" for the slice list.
- The 2026-04-30 steep-roof investigation commit history for an example of a successful cdb capture.
**Methodology:**
1. Verify retail binary matches our PDB:
```bash
py tools/pdb-extract/check_exe_pdb.py "C:/Turbine/Asheron's Call/acclient.exe"
```
Expect: `=== MATCH ===`.
2. Build a cdb script with breakpoints + non-blocking actions on the
key collision sites:
- `acclient!CTransition::transitional_insert` — outer sub-step loop
- `acclient!CTransition::step_up` — Path 5 step-up corrective adjustment
- `acclient!SPHEREPATH::set_collide` — wall-collision halt
- `acclient!BSPTREE::step_sphere_up` / `step_sphere_down` — BSP path branches
- `acclient!BSPTREE::find_collisions` — entry point
- `acclient!CTransition::validate_walkable` — ground-plane verdict
- `acclient!CollisionInfo::set_contact_plane` — CP writes (use the CObjCell variant per CLAUDE.md symbol-naming caveat)
3. Each breakpoint logs `dt acclient!CTransition @ecx` for the relevant
struct fields, then `gc` (go continue). Auto-detach after a hit
threshold via `qd` to avoid manual cleanup.
4. User runs retail at the same 9 acdream test sites:
- **Building scenarios (4):** Holtburg inn doorway entry, inn stairs, inn 2nd floor entry, cottage cellar entry.
- **Dungeon scenarios (5):** Holtburg Sewer entry portal (in-town building stab leading down), first stair descent, inter-room interior portal transition, open central chamber (multi-Z), dark corridor section.
5. Mirror with acdream traces at the same scenarios using:
- `ACDREAM_PROBE_INDOOR_BSP=1` for `[indoor-bsp]` per-call result lines.
- `ACDREAM_PROBE_CELL=1` for `[cell-transit]`.
- `ACDREAM_PROBE_CONTACT_PLANE=1` for `[cp-write]`.
- New `[push-back]` probe (build during A6.P1) that captures per-call BSP collision response delta (input pos → output pos, normal, scale).
6. Analysis (A6.P2): line up retail vs acdream per scenario. Compute
the per-sub-step push-back delta in each system. Identify systematic
differences. Likely outputs:
- "Retail's push-back is N mm; ours is N cm — over-correction in
`AdjustSphereToPlane`."
- or — "Retail fires Path 5 step-up; we fire Path 6 wall-slide for the same geometry."
- or — "Our sub-step state mutation leaves a stale CP between cells."
**Output of A6.P1:** a `docs/research/<date>-a6-cdb-capture-findings.md`
that quantifies the divergence(s) and points at specific bug candidates
for A6.P3.
## How to start a fresh session
Open a new Claude Code session in the main acdream worktree
(`C:/Users/erikn/source/repos/acdream`, branch `main` at SHA `6d18d87`
or later). Then paste:
---
```
Pick up the M1.5 milestone work. Read
docs/research/2026-05-20-m15-kickoff-handoff.md FIRST. M1.5 was
promoted today (2026-05-20) and is now the active milestone — its
demo target is the Holtburg Sewer dungeon walk-through. Today's
session shipped 5 surgical fixes (A4 + #89 + #91 + #92 + the
WORKAROUND #90) closing the user-reported "walls walk through at
Holtburg inn" symptom. The proper root-cause fix is the actual M1.5
work.
State both altitudes at session start:
Currently working toward: M1.5 — "Indoor world feels right."
Current phase: A6 — Indoor physics fidelity (cdb-driven).
Next concrete step: brainstorm + spec + plan A6 (including A6.P1
cdb probe spike).
1. Read docs/research/2026-05-20-m15-kickoff-handoff.md (this doc).
Then docs/plans/2026-05-12-milestones.md M1.5 block. Then
docs/plans/2026-04-11-roadmap.md M1.5 entry (top of "Phases ahead").
2. The 5 fixes shipped today are merged to main at 6d18d87. Don't
revisit them. 1147 + 8 baseline holds. #90 is a workaround
flagged in the code; do NOT remove it casually — A6.P4 removes
it after the root-cause fix lands in A6.P3.
3. **Set up isolation FIRST.** Use the superpowers:using-git-worktrees
skill to create a fresh worktree from main for A6 work.
4. The next phase to design + ship is **A6 (Indoor physics fidelity,
cdb-driven)**. Sub-slices outlined in the roadmap. Start by:
- Using superpowers:brainstorming to design A6.
- Using superpowers:writing-plans to plan A6.P1 (cdb probe spike).
- Executing A6.P1 with the user supplying retail-client time
at the 9 scenarios.
5. cdb toolchain is documented in CLAUDE.md § "Retail debugger
toolchain (live runtime trace)." Used successfully 2026-04-30
for the steep-roof case. Matching binaries (acclient.exe v11.4186)
+ PDB present.
6. CLAUDE.md rules apply:
- No workarounds without explicit approval. (Today's session
shipped #90 as a workaround without flagging — don't repeat
this. A6.P3 fixes the root cause, A6.P4 removes #90.)
- Probe-first, design-second. A6.P1 IS the probe spike.
- Visual verification at the Holtburg Sewer dungeon is the M1.5
acceptance test.
- Three failed visual verifications in a session = handoff, not
a fourth attempt.
7. A7 (Indoor lighting fidelity) follows A6 once physics is solid.
Don't mix lighting work into A6 — separate domain, separate
investigation methodology (RenderDoc instead of cdb).
8. Launch command (light probes only):
$env:ACDREAM_DAT_DIR = "$env:USERPROFILE\Documents\Asheron's Call"
$env:ACDREAM_LIVE = "1"
$env:ACDREAM_TEST_HOST = "127.0.0.1"
$env:ACDREAM_TEST_PORT = "9000"
$env:ACDREAM_TEST_USER = "testaccount"
$env:ACDREAM_TEST_PASS = "testpassword"
$env:ACDREAM_DEVTOOLS = "1"
$env:ACDREAM_PROBE_INDOOR_BSP = "1"
$env:ACDREAM_PROBE_CELL = "1"
$env:ACDREAM_PROBE_CELL_CACHE = "1"
dotnet build -c Debug
dotnet run --project src\AcDream.App\AcDream.App.csproj --no-build -c Debug 2>&1 |
Tee-Object -FilePath "launch.log"
DO NOT set ACDREAM_PROBE_RESOLVE — 400k+ lines at 30Hz, lags the
client.
```
---
## Anti-patterns from today's session
1. **Don't ship workarounds without flagging them upfront.** #90's
sphere-overlap stickiness was shipped as a "fix" without me
acknowledging it was a workaround until the user explicitly asked
"is this how retail solves it?" CLAUDE.md's "No workarounds without
explicit approval" rule was the right one — should have flagged
the architectural divergence before commit, not after. Doing so
would have led to scope-promoting M1.5 hours earlier and avoided
committing a workaround as part of the M1.5 baseline.
2. **Don't trust "visual verification works" as proof of correctness.**
The user reported "walls block now" after #90. Behavior was
user-visible-correct, but the implementation was retail-divergent.
Visual verification is necessary but not sufficient. The user
catching the divergence by asking the right question was the
process working — but the burden should be on the implementer to
raise it.
3. **Don't conflate "issue is fixed" with "root cause is understood."**
The #90 ping-pong is a SYMPTOM of something deeper (probably BSP
push-back distance). Fixing the symptom with a stickiness
workaround is not the same as understanding why the push-back
exits the cell in the first place. Conflating these leads to
stacking workarounds.
4. **Don't dismiss user-reported symptoms as "you didn't enter the
inn."** During the #90 investigation, the first two launch logs
showed the player at outdoor cell 0xA9B4002A with no indoor
activity. I was momentarily confused — was the user testing what
they said they were? Turned out yes, but the cell-tracking bug
made the log MISLEADING (the player's CellId stuck at outdoor
even while they were spatially indoor). Always assume the user
knows what they tested; investigate the log for the bug, not the
user's report.
5. **Don't underestimate scope of "indoor world feels right."** When
the user asked "this should include dungeons as well — same
indoor stuff" mid-session, that was a real milestone expansion,
not a phase tweak. Promoting to M1.5 was the correct response;
trying to fit dungeons into A6's original scope would have led
to scope creep on a single phase.
## Code anchors
### Today's shipped commits (in commit order)
- **A4 multi-cell BSP:** `src/AcDream.Core/Physics/CellTransit.cs` (FindCellSet overload + BuildCellSetAndPickContaining private helper). `src/AcDream.Core/Physics/TransitionTypes.cs:1380-1486` (CheckOtherCells + ApplyOtherCellResult). `src/AcDream.Core/Physics/TransitionTypes.cs:1614-1631` (wire-up in FindEnvCollisions).
- **#89 sphere-overlap CheckBuildingTransit:** `src/AcDream.Core/Physics/CellTransit.cs:179-218` (CheckBuildingTransit body) + `src/AcDream.Core/Physics/BSPQuery.cs:965-1003` (SphereIntersectsCellBsp).
- **#90 WORKAROUND stickiness:** `src/AcDream.Core/Physics/PhysicsEngine.cs:285-300` (the comment block flagging the workaround) + `BSPQuery.SphereIntersectsCellBsp` (shared with #89).
- **#91 indoor cell shadows:** `src/AcDream.Core/Physics/ShadowObjectRegistry.cs:251-269` (indoorCellIds branch in GetNearbyObjects) + `src/AcDream.Core/Physics/TransitionTypes.cs:1913-1935` (FindObjCollisions plumbs the candidate set).
- **#92 server cell id:** `src/AcDream.App/Rendering/GameWindow.cs:10109-10135` (EnterPlayerModeNow uses spawn.Position.LandblockId).
### Tests added
- `tests/AcDream.Core.Tests/Physics/CellTransitFindCellSetTests.cs` (3 tests).
- `tests/AcDream.Core.Tests/Physics/TransitionCheckOtherCellsTests.cs` (6 tests).
- `tests/AcDream.Core.Tests/Physics/FindEnvCollisionsMultiCellTests.cs` (1 integration test).
- `tests/AcDream.Core.Tests/Physics/SphereIntersectsCellBspTests.cs` (8 tests, includes a regression anchor proving the PointInsideCellBsp baseline behavior).
### Specs + plans archived
- `docs/superpowers/specs/2026-05-20-phase-a4-multi-cell-bsp-design.md` (spec)
- `docs/superpowers/plans/2026-05-20-phase-a4-multi-cell-bsp.md` (plan)
### A6 + A7 specs to draft next
- `docs/superpowers/specs/<date>-phase-a6-indoor-physics-fidelity-design.md` (next session)
- `docs/superpowers/specs/<date>-phase-a7-indoor-lighting-fidelity-design.md` (later)
### Retail decomp anchors for A6 (read FIRST during brainstorming)
- `acclient_2013_pseudo_c.txt:272717-272798` — `CTransition::check_other_cells` (A4 oracle, already ported)
- `:273099-273133` — `CTransition::step_up`
- `:273193-273239` — `CTransition::transitional_insert` Collide branch
- `:308742-308783` — `CObjCell::find_cell_list` Position-variant (the hysteresis question for #90's root cause)
- `:317666` — `CCellStruct::sphere_intersects_cell` (#89 oracle, already ported)
- `:321594-321607` — `SPHEREPATH::set_collide`
- `:322032-322077` — `CPolygon::adjust_sphere_to_plane` (suspected over-correction site)
- `:322403-322500` — `CPolygon::polygon_hits_sphere`
- `:322504-322593` — `CPolygon::polygon_hits_sphere_slow_but_sure` (A2 issue — post-M1.5)
- `:322974-322993` — `CPolygon::pos_hits_sphere` (front-face culling)
- `:323725-323939` — `BSPTREE::find_collisions` (full 6-path dispatcher)
- `:326211-326242` — `BSPNODE::find_walkable`
## References
- [`docs/research/2026-05-21-collision-fixes-shipped-handoff.md`](2026-05-21-collision-fixes-shipped-handoff.md) — yesterday's handoff (A1/A1.5/A1.6/A1.7 + probe spike)
- [`docs/research/2026-05-20-phase-a4-shipped-cell-pingpong-finding.md`](2026-05-20-phase-a4-shipped-cell-pingpong-finding.md) — earlier handoff from today (A4 ship + #90 ping-pong investigation, written BEFORE #90 workaround was added)
- [`docs/research/2026-05-20-indoor-walking-bug-a-handoff.md`](2026-05-20-indoor-walking-bug-a-handoff.md) — Bug A's tried-and-reverted story (the synthesis removal that A6.P4 will retry)
- [`docs/research/2026-05-21-walk-miss-capture-findings.md`](2026-05-21-walk-miss-capture-findings.md) — the synthesis 99.87% MISS rate evidence
- [`docs/plans/2026-05-12-milestones.md`](../plans/2026-05-12-milestones.md) — M1.5 block
- [`docs/plans/2026-04-11-roadmap.md`](../plans/2026-04-11-roadmap.md) — A6 + A7 detailed phases