Files
aetherbound-guild/docs/plans/M32_PAGE_VIEW_ARCHITECTURE_REFACTOR.md
T

176 lines
9.0 KiB
Markdown

# M32 Page View Architecture Refactor
## Status
- Plan: `M32_PAGE_VIEW_ARCHITECTURE_REFACTOR`
- Status: `COMPLETE`
- Activated: 2026-08-25
- Baseline: `9b010b3` (`M31_MVP_RELEASE_READINESS_COMPLETE`)
- Owner authorization: the Owner requested a scalable, isolated code
architecture and asked that page Views be split out instead of leaving all
composition in `entry_shell.gd`.
## Objective
Establish a durable page architecture for future expansion without changing
the accepted MVP behavior, visuals, input, localization or persistence. The
target is an explicit one-way presentation flow with isolated Views, pure page
controllers, application/domain services and an explicit route/context
boundary.
This is an architecture migration, not a feature or visual redesign.
## Target Architecture
```text
Composition Root / App Flow
-> Screen Router + Page Context
-> Page View (Godot Control; emits user intent only)
-> Page Controller / Presenter (pure ViewData + command eligibility)
-> Application Command Boundary
-> Domain Service (rules, receipts, transactions)
-> Repository / Save
-> immutable state snapshot
-> Controller snapshot
-> View.render(ViewData)
```
### Ownership rules
1. **View** owns nodes, layout, focus and local visual state only. It does not
load/save files, call Company/Contract/Battle services, inspect `facade`, or
decide economy/progression rules.
2. **Page Controller/Presenter** receives explicit state and presentation
inputs, returns a deep-copied `ViewData` snapshot and command eligibility.
It does not access Godot nodes or persistence.
3. **Application command boundary** translates a View intent into a named
operation and routes it to the owning Domain Service. It owns no duplicate
game rules.
4. **Domain Service** remains the only authority for mutations, receipts,
conflict/idempotency behavior and Save writes.
5. **Router/Context** owns screen identity, caller, return route, focus and
presentation mode. It carries no Company or Battle authority.
6. **Compatibility adapters** remain outside the current path and cannot be
imported by new Views or Controllers.
### Why this is not strict MVVM
Godot does not provide a reliable project-wide observable binding layer here.
The project will use a **Passive View + Presenter/ViewData + Domain Service**
pattern with explicit one-way refreshes. This gives MVVM-like isolation without
introducing fragile two-way binding or a global event bus.
## Player/System Stopping Point
- The player sees the same accepted first-cycle pages and routes as M31.
- The first extracted View renders the same nodes, text, focus, touch targets,
responsive geometry and callbacks through the new View contract.
- A View can be unit-tested with a fake context and ViewData without constructing
Company, Save or historical facade state.
- A controller/service regression proves that the extracted View has not
changed any transaction or persistence semantics.
- No new page, content, economy rule, asset, audio cue, route or package is
added by this milestone.
## Ordered Steps
### M32-A — Architecture contract and inventory (`COMPLETE`)
- Record the target layering, dependency direction, forbidden imports and
migration order.
- Inventory the current EntryShell page composition, Controller seams,
service boundaries and route/context behavior.
- Select one low-risk first-cycle View pilot and define its exact acceptance
surface before product code changes.
- Commit and push this activation boundary. **Complete at source `9bde014`.**
### M32-B — View contract and pilot extraction (`COMPLETE`)
- Add a UI-only `PageView` contract/base and explicit `PageContext`/intent
boundary under the current Runtime foundation.
- Extract the OUT-004 Recovery View first because its Controller and service
boundaries are already complete and its visual composition is accepted.
- Keep `EntryShell` as the composition root for this pilot; it may mount the
extracted View and translate its intents, but the View cannot call the
services directly.
- Preserve node names, signals/callback behavior, focus order, localization,
touch targets and normal `100%` geometry byte-for-byte where applicable.
- Complete at source `23924a2`: `ABGPageView`, `ABGPageContext` and the
OUT-004 `ABGRecoveryPageView` are integrated through an explicit intent
boundary; the Recovery capture is byte-equivalent to the pre-migration
baseline at all four normal fixtures.
### M32-C — Focused verification (`COMPLETE`)
- Run the new View contract test and M30 Recovery Controller/Runtime tests.
- Run DEV-5 regressions and the full MVP first-cycle audit.
- Capture Recovery at the required normal `100%` fixtures and compare the
extracted View against the pre-migration evidence.
- Require strict diagnostics `0`, exact-once markers, parsed touch and owned
process/workspace cleanup.
- Complete at source `088f46b`: the source-bound View contract, DEV-5
candidate and full MVP first-cycle audit pass. Recovery normal captures are
byte-equivalent to the M30 baseline at all required normal fixtures. Evidence
is recorded in `docs/runtime/M32_PAGE_VIEW_ARCHITECTURE_VISUAL_AUDIT.md`.
### M32-D — Handoff and next migration map (`COMPLETE`)
- Record the pilot evidence, remaining EntryShell View blocks and the ordered
next extraction groups.
- Close only the pilot; do not claim that every View has been split.
- Update the checkpoint and development ledger, create a focused pushed commit
and leave the next page migration as a new bounded step/plan if needed.
- Complete at source `088f46b` with the evidence and ordered migration map in
`docs/runtime/M32_PAGE_VIEW_ARCHITECTURE_VISUAL_AUDIT.md`. The next page
extraction is intentionally not activated by this plan.
#### Ordered next extraction map (handoff only)
| Order | Group | Why this order | Required boundary |
| --- | --- | --- | --- |
| 1 | OUT-003 Reward Choice → OUT-002 Knockout → OUT-001 Result | Controllers and continuation facts are already complete; the three pages form one settled-result chain and share the Recovery handoff. | One View per page, explicit intents, no duplicated settlement/reward rules. |
| 2 | RSK-002 Risk Commitment → PTY-002 Readiness | Small command surfaces with explicit acknowledgement/eligibility facts; useful for validating shared command-rail primitives. | Preserve frozen Party snapshot, stale-dependency guards and receipt semantics. |
| 3 | DEV-4 Party Line → RSK-001 Risk Board | Selection-heavy preparation Views; extract after the command/intent contract has two more proven consumers. | Keep selection local to the View; Controller owns normalized order/selection data. |
| 4 | SHP-002 Recruit Review → SHP-001 Market → Contract Choice → Guild | Larger content surfaces and more route/context variants; migrate after the low-risk page grammar is stable. | Keep hire/contract/economy mutations in existing services and preserve stable IDs. |
| 5 | BAT-001 Opening → BAT-002 Live | Highest lifecycle/timeline coupling and resize/input surface; defer until passive page Views are proven. | Separate field canvas/timeline rendering from observation/receipt commands. |
Do not create a project-wide binding/event-bus layer between these steps. A
shared primitive is justified only when two extracted Views have the same
semantic contract and a focused test proves that the primitive removes
duplication without importing domain state.
## Frozen Scope
- No gameplay, economy, Company, Contract, Battle, Reward, Recovery or Save
semantic changes.
- No visual redesign, asset regeneration, localization rewrite or 130% scope.
- No mass rewrite of `entry_shell.gd` in one step.
- No deletion of compatibility/history files, `.uid`, `.import` or
`prototype_incremental/`.
- No iOS export, packaging, signing, deployment or store work.
- No global event bus, reflection-based service locator or speculative
two-way binding framework.
## Acceptance Checks
- `ABG_M32_RECOVERY_VIEW_CONTRACT_OK` exactly once.
- Existing `ABG_M30_RECOVERY_CONTROLLER_OK`, `ABG_DEV5_CANDIDATE_SUITE_OK`
and `ABG_MVP_FIRST_CYCLE_AUDIT_OK` remain green.
- Extracted View has no direct imports of Domain Services, Save, `facade` or
`current_screen`; it emits explicit intents and renders supplied ViewData.
- Recovery normal `100%` captures at `760x360`, `844x390` and `1280x720` in
`zh_CN`/`en` remain visually and interactively equivalent.
- Focused source is committed, pushed and clean for tracked files.
## Issue Register
| ID | Status | Boundary | Evidence / action |
| --- | --- | --- | --- |
| `M32-I01` | `OPEN` | `entry_shell.gd` still mixes routing, View construction and command callbacks | Extract only through the bounded pilot; do not mass-rewrite. |
| `M32-I02` | `OPEN_SCOPE` | Legacy `main.gd`/compatibility adapters remain | Preserve as an anti-corruption boundary until a later authorized migration. |
| `M32-I03` | `OPEN` | No project-wide observable binding layer | Use explicit `ViewData` refresh and intent signals; do not add a global bus. |
## Final Handoff
`ABG M32 RECOVERY VIEW PILOT COMPLETE`