176 lines
9.0 KiB
Markdown
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`
|