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

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

  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