9.0 KiB
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
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
- 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. - Page Controller/Presenter receives explicit state and presentation
inputs, returns a deep-copied
ViewDatasnapshot and command eligibility. It does not access Godot nodes or persistence. - 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.
- Domain Service remains the only authority for mutations, receipts, conflict/idempotency behavior and Save writes.
- Router/Context owns screen identity, caller, return route, focus and presentation mode. It carries no Company or Battle authority.
- 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
PageViewcontract/base and explicitPageContext/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
EntryShellas 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,ABGPageContextand the OUT-004ABGRecoveryPageVieware 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 indocs/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
088f46bwith the evidence and ordered migration map indocs/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.gdin one step. - No deletion of compatibility/history files,
.uid,.importorprototype_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_OKexactly once.- Existing
ABG_M30_RECOVERY_CONTROLLER_OK,ABG_DEV5_CANDIDATE_SUITE_OKandABG_MVP_FIRST_CYCLE_AUDIT_OKremain green. - Extracted View has no direct imports of Domain Services, Save,
facadeorcurrent_screen; it emits explicit intents and renders supplied ViewData. - Recovery normal
100%captures at760x360,844x390and1280x720inzh_CN/enremain 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