diff --git a/docs/plans/2026-07-25-modern-runtime-slice-j.md b/docs/plans/2026-07-25-modern-runtime-slice-j.md index 4d713f29..a1b0aa97 100644 --- a/docs/plans/2026-07-25-modern-runtime-slice-j.md +++ b/docs/plans/2026-07-25-modern-runtime-slice-j.md @@ -143,6 +143,9 @@ git revert 854d9e9cd13092bd5aaa3cf025d73eeb4600e9f8 ### J2 — session lifetime and ordered transport group +**Detailed execution plan:** +[`2026-07-25-modern-runtime-slice-j2.md`](2026-07-25-modern-runtime-slice-j2.md). + - Remove App presentation dependencies from `LiveSessionController`, `LiveSessionHost`, lifecycle host, event router, and command router. - Move the same owner instances into Runtime with Core.Net transport and diff --git a/docs/plans/2026-07-25-modern-runtime-slice-j2.md b/docs/plans/2026-07-25-modern-runtime-slice-j2.md new file mode 100644 index 00000000..ef4bb7bd --- /dev/null +++ b/docs/plans/2026-07-25-modern-runtime-slice-j2.md @@ -0,0 +1,190 @@ +# Modern runtime Slice J2 — session lifetime and ordered transport + +**Status:** ACTIVE +**Parent:** `2026-07-25-modern-runtime-slice-j.md`, J2 +**Production base:** `854d9e9cd13092bd5aaa3cf025d73eeb4600e9f8` +**J1 documentation:** `f84624b1e9b83f928debdbe65a5a1576b999ee34` + +## 1. Objective + +Move the one canonical live-session lifetime, transport generation, ordered +inbound subscription owner, and route activation/teardown transaction from +`AcDream.App` into `AcDream.Runtime`. + +The move is structural. It must preserve the exact current connect, character +selection, EnterWorld, packet dispatch, command activation, tick, reconnect, +logout, and retryable cleanup order. App remains the graphical host and +supplies credentials, retained-UI/domain callbacks, the graphical command +projection, and presentation reset acknowledgements. + +## 2. Fixed ownership after J2 + +`AcDream.Runtime` owns: + +- the exact `WorldSession` generation and its connect/enter/tick/dispose + transaction; +- generation validation and live-session lifecycle state; +- the serial route lifecycle: attach inbound before Connect, activate outbound + only after EnterWorld, make commands inert before detaching inbound; +- the retryable teardown suffix and exact acknowledgement stages; +- the complete ordered inbound subscription set and all Core/Core.Net event + wiring; +- connection options with no dependency on App `RuntimeOptions`; +- the production endpoint/session operations and deterministic operations + seam used by no-window tests. + +`AcDream.App` owns: + +- conversion from `RuntimeOptions` into immutable Runtime connection options; +- graphical reset, identity, layout, toolbar, settings, dialog, and + presentation callbacks; +- the `ICommandBus` projection needed by the current UI until gameplay command + groups move in J4/J5; +- graphical source adapters for existing App interfaces while those consumer + groups await their own J3–J6 migrations. + +The App adapters borrow the Runtime session and command route. They do not +dispose the transport, track another generation, retain a second active route, +or mirror in-world state. + +## 3. Type and file migration + +### J2.1 — Runtime lifetime contracts + +Add under `src/AcDream.Runtime/Session/`: + +- `LiveSessionConnectOptions` +- `RuntimeLiveSessionController` +- `RuntimeLiveSessionHost` +- `RuntimeLiveSessionBinding` +- `IRuntimeLiveSessionLifecycleHost` +- `IRuntimeLiveSessionOperations` +- `IRuntimeLiveSessionEventRoute` +- `IRuntimeLiveSessionCommandRoute` +- the Runtime-only lifecycle host and retryable route rollback owner + +The host implements the J1 `IRuntimeSessionCommands` surface directly. Start, +Reconnect, and Stop are generation-gated at that owner; the J1 App command +adapter no longer translates a second session result or invents teardown +stages. + +`RuntimeLiveSessionController` exposes only borrowed state: +`CurrentSession`, `IsInWorld`, `Generation`, and `Tick`. It carries no UI +command bus and implements no App interface. + +### J2.2 — Ordered inbound route move + +Move the existing `LiveSessionEventRouter` and +`LiveSessionSubscriptionSet` into Runtime without changing subscription order: + +1. object/property table wiring; +2. combat-state wiring; +3. entity and environment messages; +4. inventory/item state; +5. character/spell state; +6. social/chat state. + +The existing accepting gate, reverse-order retryable unsubscribe, construction +rollback, and reentrant-cleanup rejection remain line-for-line. The route +bindings remain delegates over current owners for J2; their owner groups move +in J3/J4. + +### J2.3 — Graphical host adapter + +Replace the App lifetime implementation with focused adapters: + +- a session source bridge for existing App `IsInWorld`, `CurrentSession`, + frame-tick, and retained-UI seams; +- a graphical route factory that constructs the moved Runtime event router and + the current App command projection; +- a single active-command projection whose retained UI reference becomes + inert before route detachment; +- graphical lifecycle callbacks for reset, selection, EnterWorld, connecting, + and connected presentation. + +Delete the superseded App controller, lifecycle-host logic, subscription +owner, and route rollback implementation in the same commit. Do not keep +delegating compatibility copies of lifetime state. + +### J2.4 — Test ownership + +Move controller, host, lifecycle, event-router, and subscription tests into +`AcDream.Runtime.Tests`. Preserve every existing call-order, duplicate start, +reentrant reconnect/stop/dispose, rollback-failure, stale generation, malformed +packet, and retryable teardown case. + +Keep graphical command-projection and App bridge tests in +`AcDream.App.Tests`. Add assertions that: + +- the bridge has no generation or in-world backing fields; +- the command projection has at most one borrowed active route; +- stale command references are inert after replacement; +- press-time graphical input still reaches the same owner synchronously. + +Add a Runtime-only construction test that creates the production lifetime +graph with deterministic transport operations, enters and exits a session, +and verifies that App, UI, Silk.NET, OpenAL, Arch, and ImGui assemblies are +not loaded. + +## 4. Exact behavioral order + +Start: + +1. advance generation; +2. drain any retired teardown suffix; +3. reset the supplied host when required; +4. validate enabled state and credentials; +5. resolve endpoint and create the one `WorldSession`; +6. construct and attach all inbound routes; +7. publish connecting state; +8. Connect and receive the character list; +9. publish connected state; +10. select the first available character and publish identity; +11. EnterWorld; +12. activate the outbound command route; +13. mark in-world and publish entered-world presentation. + +Stop/replacement: + +1. advance generation and reject further old-generation commands; +2. make the active graphical command route inert; +3. detach inbound subscriptions in reverse order; +4. dispose `WorldSession`, preserving its graceful F653/disconnect behavior; +5. detach the exact host/session pair; +6. reset domain and presentation state; +7. acknowledge only the completed stages. + +If a stage throws, the exact remaining suffix is retained. A retry never +replays a completed stage. + +## 5. Acceptance + +Focused: + +- Runtime lifetime and event-route suites all pass after moving from App; +- App graphical bridge and command projection suites pass; +- J1 normalized traces are identical before and after the move; +- source/dependency guards find no Runtime presentation/backend dependency; +- Runtime-only session construction and teardown load no forbidden assembly. + +Complete: + +- `dotnet build AcDream.slnx -c Release`; +- full Release solution tests; +- connected capped login/six-checkpoint/logout plus fresh uncapped reconnect + on the exact binary; +- both processes exit gracefully; +- no packet/order, reveal, route, teardown, or resource-convergence failure. + +J2 changes no pixels, input feel, or retail algorithm. A separate user visual +pause is therefore not required unless the connected gate exposes a +presentation symptom. + +## 6. Rollback + +The exact J2 rollback commit is recorded here before its connected gate. J1 +remains independently reversible: + +```text +git revert 854d9e9cd13092bd5aaa3cf025d73eeb4600e9f8 +``` diff --git a/docs/research/2026-07-25-slice-j1-runtime-contract-closeout.md b/docs/research/2026-07-25-slice-j1-runtime-contract-closeout.md index 936a18d1..88677265 100644 --- a/docs/research/2026-07-25-slice-j1-runtime-contract-closeout.md +++ b/docs/research/2026-07-25-slice-j1-runtime-contract-closeout.md @@ -67,4 +67,3 @@ J0 remains independently reversible with: ```text git revert b632672e5ccabfb44c551e08f1c411ab2669c44a ``` -