Define the exact Runtime/App ownership boundary, lifecycle ordering, teardown suffix, no-window gate, and deletion criteria before moving transport ownership.
190 lines
7.1 KiB
Markdown
190 lines
7.1 KiB
Markdown
# 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
|
||
```
|