# QNE Main Node View Session System Doctrine V2

Status: current superseding operational doctrine
Date: 2026-06-13
Layer: Layer A/B bridge doctrine for current QNE node architecture
Workspace anchor: qne-node-v00589, qne-view-session-v00536, qne-scene-data-v00502, qne-window-v00500, qne-theme-v00500, qne-ui-components-v00507, qne-keyboard-v00505, qne-spelling-v00500, qne-scene-renderer-skia-v00562, qne-ui-v00555, qne-android-app-v00516

This doctrine supersedes `QNE_Main_Node_Shadow_System_Doctrine_V1.md` and
previous QNE node/system doctrine for main nodes, master nodes, seed nodes,
QNENodeSkills, QNESceneData, mobile/tablet clients, browser trials, remote
assist, and node-hosted view sessions. Older doctrine remains useful history,
but this document is the current source of truth for implementation decisions
in the next node work.

## Summary

The QNE system is centered on a minimal capable QNE node. A capable node owns
identity, persistence, QNE P2P, QNENodeSkill lifecycle, DHT participation when
appropriate, and node-hosted QNEViewSessions for browser, mobile, tablet,
kiosk, remote-assist, and other thin surfaces.

Mobile, tablet, and similar apps are not QNE runtimes. They are native QNE UI
surfaces that display node-generated QNEViewSession frames, return user
actions, and bridge approved native capabilities. Executable behavior remains
on capable nodes as QNENodeSkills.

The current design is mobile-first. A mobile QNEViewSession is one primary
agent scene sized to the mobile viewport, with desktop-style window management,
panpanel scroll bars, and side restore/minimize circles disabled. The active
Android evaluation scene is the node-hosted mobile Personal Assistant agent at
`/qne-view-session/mobile-pa`; the invite/trial route is retained only as a
historical harness until it is rebuilt from the single-scene approach. Mobile
agent scenes use a double-height agent toolbar at the top of the scene frame.
Row one centers the agent name. The QNE logo sits on the left and is the agent
menu selector. On the row two right side, controls work inward as:
`hands-up` waiting-agents indicator, Vaadin bolt quick action, Vaadin plus, and
Vaadin minus. The `hands-up` icon is displayed only when at least one agent is
waiting for attention; when no agent is waiting the bolt occupies the far-right
control slot. Desktop surfaces may later show multiple mobile-compatible agent
scenes, but mobile is the reference interaction model. The Android local
evaluation path currently uses a cable-loopback HTTP frame/control bridge;
production mobile transport is still QNE P2P. A temporary `/mobile-pa` browser
shell exists for same-LAN iPhone/Safari visual checks of the same
node-generated frame.

Vaadin Icons are the standard QNE UI icon set for generic controls. QNE brand
icons remain separate brand assets. The first vendored Vaadin assets are
`bolt.svg`, `hands-up.svg`, `keyboard.svg`, `plus.svg`, and `minus.svg` under
`/home/paulf/QNE-developer/assets/icons/vaadin`. Vaadin icons are drawn by
the renderer and may be colored by theme/token state. The `hands-up` waiting
indicator uses a distinct attention color when visible so waiting agents are
not confused with normal quick actions.

## Core Naming Doctrine

Use QNE all caps in new mixed-case names.

The internal executable capability trait is QNENodeSkill. Do not use QNESkill as
a separate product term. Client/mobile render payloads are QNESceneData, not
skills.

The node-side live UI/session mediation term is QNEViewSession. A QNEViewSession
is a node-hosted session that owns view state, frame generation, action/control
handling, resize/pan/viewport behavior, and session descriptors for a thin UI
surface.

Use QNEViewSession for new code and doctrine. Do not use QNEShadowSession as a
new type name. Historical persisted records and older route names may retain
`shadow` only as compatibility inputs. Current storage and route contracts use
QNEViewSession naming.

Node-side approved mobile/tablet device registration is QNEMobileDeviceRecord,
not QNEMobileShadow. Platform bridge code is QNEMobileAdapter. A mobile or
tablet may open one or more QNEViewSessions, but the durable approved-device
record and the live view session are separate concepts.

The browser adapter is a dumb frame display and control-return surface. It does
not render QNESceneData directly once a QNEViewSession is active; it displays
frames generated by the node-side QNEViewSession and sends pointer/keyboard/
viewport/control events back.

The Rust view-session crate is a separate versioned project named
`qne-view-session-vNNNNN`. QNE node projects depend on it by versioned path.
View-session changes should create a new qne-view-session project version and
must not force a qne-node version unless the node adapter, routes, persistence,
or node contract changes.

Existing lowercase binary, crate, and protocol names such as qne-node, qne-p2p,
and CLI commands may remain lowercase.

When code changes begin, rename the existing Rust trait from QneNodeSkill to
QNENodeSkill directly. Do not leave a temporary compatibility trait or alias.

## Node Doctrine

A QNE node is the durable execution and authority unit.

Every capable node owns:

- a node UUID
- a persisted QNE P2P static key under persist/secrets
- one full QNE filesystem layout
- QNE P2P transport
- QNENodeSkill lifecycle
- local policy enforcement
- optional DHT participation
- optional user hosting
- optional QNEMobileDeviceRecord approval and QNEViewSession hosting
- optional repository, seed, or master roles

The base node should remain small. It provides identity, persistence, QNE P2P,
DHT hooks, QNENodeSkill lifecycle, configuration, startup/shutdown, and policy
boundaries. Features such as user hosting, device approval, view-session
hosting, repository service, DHT service, UI service, network tests, and
payment/account flows are QNENodeSkills, support crates, or node roles built on
that base.

A node update stops the service, preserves identity and persist, installs the new
binary, restarts, restores QNENodeSkill state, and resumes network presence.
Hot-swapping the base node is not the doctrine.

## QNENodeSkill Doctrine

A QNENodeSkill is executable QNE behavior running on a capable QNE node.

A QNENodeSkill has:

- a unique sequence number
- a stable skill name
- numbered actions
- message send/process/receive methods
- lifecycle start/restore/shutdown methods
- pack/unpack persisted state
- access only through node-provided context and policy

QNENodeSkills may be invoked locally or over QNE P2P. The architecture must not
split into separate local skills and network skills unless a concrete need
appears.

QNENodeSkills can produce QNESceneData, request capabilities, update DHT records,
route messages, host users, manage storage, or coordinate workflows. They do not
execute on mobile/tablet apps.

## QNESceneData Doctrine

QNESceneData is declarative render data produced by a QNENodeSkill.

QNESceneData may describe windows, layout, text, images, controls, actions,
media references, scene state, capability prompts, and user input targets.

QNESceneData must not contain downloaded executable code, mobile-side plugins, or
arbitrary scripts. This keeps iOS and Android clients reviewable and makes the
architecture clear: the node computes; the client renders.

The mobile app receives QNESceneData, renders it with reviewed native code, and
returns action/capability results to the node.

Mobile Personal Assistant conversation entries are rendered as rounded
full-width rectangles inside the agent scene. Agent entries use the theme's
pastel blue conversation color. User entries and the pending input target use
the theme's pastel green conversation color. When the scene is waiting for user
or agent input, the pending target is shown as an empty rounded rectangle with a
cursor, not as loose text on the background. The send action is a separate
same-color rounded square button at the end of the user input row using the
Vaadin enter-arrow icon. The button is line-height sized and aligned to the
final line, so multi-line input can use the full input width above the final
line.

Mobile devices that show one active agent scene use a fixed two-part toolbar
layout. The main double-height agent toolbar is at the top of the viewport. Its
top line centers the agent name; its second line carries the QNE logo menu
selector on the left and fixed right-side slots for `hands-up`, Vaadin bolt,
Vaadin plus, and Vaadin minus. The keyboard toggle is not in the main toolbar.
A one-line toolbar sits at the bottom of the viewport and carries the Vaadin
keyboard toggle. When the keyboard is open, it is rendered above this bottom
toolbar and the conversation content is reflowed between the top toolbar and
the keyboard/bottom-toolbar area.

## QNE Theme And Component Doctrine

QuickNEasy UI color specifications are standardized on OKLCH. Design colors are
to be stored, named, and reviewed as OKLCH lightness/chroma/hue values so
relative perceived color strength remains stable across hues. Renderers and
adapters convert OKLCH to their target output format, such as Skia sRGB `Color`
or browser CSS, at the adapter edge.

Legacy RGB constants may remain until touched, but new or changed UI colors
must not be specified by ad hoc RGB/HSL values unless they are direct technical
outputs from an OKLCH conversion. The standard Personal Assistant window
title-bar color is pastel green.

Theme tokens live in the separate `qne-theme` crate. Standard reusable UI
component models and geometry live in the separate `qne-ui-components` crate.
Renderer crates draw those components for their target output, and
QNEViewSession uses the same component geometry for hit testing and action
routing.

Keyboard models, profiles, layout geometry, and tolerant key hit testing live
in the separate `qne-keyboard` crate. The default QNE keyboard option is the
minimum-pain round-key keyboard for agent conversation windows: round visible
keys, larger invisible hit circles, direct common symbols, visible editing
actions, and context-shaped profiles. Native-like Android and iOS options are
available for familiarity, but QNE round keys are the default. Mobile
conversation keyboards do not draw a separate keyboard background panel or an
edit strip above the first key row; renderers show only the keys over the
normal scene background. The keyboard crate remains renderer-neutral; Skia,
browser, Android, and iOS adapters draw or bridge the model.

Agent conversation scenes open the QNE keyboard automatically when input is
expected. The bottom keyboard toolbar icon toggles the keyboard hidden or
shown without leaving the scene. When the keyboard is open, the view-session
reserves keyboard height above the bottom keyboard toolbar and reflows the
conversation/input region so the active input remains visible. Keyboard hit
testing and text state are owned by QNEViewSession; renderer crates only draw
the keyboard model and current input state. In the first implementation slice,
send clears the current draft input and keeps the keyboard ready.

The QNE round keyboard uses full available row width for 10-key rows with 2 px
gaps between keys. Shorter character rows keep the same 10-column circle size
and are centered. Renderers fit key labels to each key shape so the character
is as large as the key allows without crossing the circle or ellipse.

For mobile agent conversation use, the QNE keyboard is a strict four-line
viewport. Lines one to three are the active character rows. Line four is always
one centered `Space` key with width 50% of the keyboard viewport. There is no
keyboard action row for hide, cursor movement, delete, or send; send and line
editing are handled later in the agent input area. First display of the
keyboard resets to the default qwerty character viewport. A downward swipe on
the keyboard switches to the numbers viewport (`0123456789`, `qwertyuiop`,
`asdfghjkl`). An upward swipe switches to the three symbol rows. Browser/mobile
surfaces still receive full node-rendered frames; they do not keep a local
delta keyboard framebuffer. Mobile browser adapters must treat keyboard
`pointercancel` as a release event because mobile browsers may cancel a touch
gesture instead of delivering a normal pointer-up event.

Project source zips are locally archived under `/home/paulf/QNE-archive` and
then backed up using the QNE encrypted online storage tool on the Hetzner
Storage Box. Online-storage uploads that update the encrypted manifest must be
run sequentially, not in parallel, because the manifest is a single encrypted
remote object.

Spelling and correction primitives live in the separate `qne-spelling` crate,
not in `qne-keyboard`. Spelling starts as suggestion-only: the system may mark a
word and offer suggestions, but it must not silently auto-replace user text.
Dictionary lookup, user words, ignored words, language selection, and future
personal phrase prediction belong in `qne-spelling` or node/user persist
adapters that feed it.

Reusable controls must accept `QNEUiScale` so the standard size spinner adjusts
text, hit geometry, status circles, hover labels, select lists, combo boxes,
menus, and spinner triangles consistently. Standard UI text defaults to 14px
across combo boxes, select lists, context menus, PA title text, and PA content.
The size spinner changes this shared font size by 1px per press. The main bar
is called the toolbar; window bars are called title bars. Quick actions use the
standard Vaadin bolt icon, not a text Q mark. Window title text is bold and 2px
larger than the shared text size. The main toolbar and PA window title bar
default to 40px. The main toolbar height scales with the standard size spinner
state. Combo boxes are standard
`qne-ui-components` controls with
bordered rounded ends, dropdown geometry, shared hit/render geometry, and a
height eight pixels less than the current main toolbar height. The standard
size spinner is a compact borderless vertical control with only a black
up-pointing triangle over a black down-pointing triangle. Its height is eight
pixels less than the current main toolbar height and the center gap between
triangles is 5px. The triangle height is reduced by 20% from the full
half-height calculation. It does not show a numeric value and does not have a
filled background.

Window/status circles are standard components. They must support configurable
hover labels, including label placement above, below, left, or right of the
circle.

Internal view-session windows are standard configured window instances. The
base window shell owns the title bar, chrome circles, rectangle, move/resize,
minimize/close state, palette index, and z-order behavior. The work area inside
the window is a separate typed configuration, such as Personal Assistant, My
Device Guru, camera view, browser view, form, or future scene canvas. New
windows should be created by adding another window instance and work-area kind,
not by duplicating window chrome logic.

Closed and minimized window circles are fixed viewport overlays below the
toolbar, not toolbar contents and not panpanel contents. Closed windows are
listed in a right-side column with horizontal hover labels to the left.
Minimized windows are listed in a left-side column with horizontal hover labels
to the right. These circles remain in constant viewport positions while the
panpanel scrolls or windows move. Clicking any visible internal window focuses
that window and moves it to the top z-order. The active window is rendered last
inside the node-generated frame.

Context-menu window actions are targeted, not global. The context menu records
the visible internal window under the point where the menu was opened. Arrange
and reset actions from that menu apply only to that recorded window. If the menu
opens over empty viewport, or over a hidden, minimized, or closed window, those
window actions are no-ops and must not change other windows.

Mobile-shaped QNEViewSession viewports use a mobile UI scale. Until the Android
and mobile adapters report exact density as an explicit capability, a
phone-class physical viewport such as `720x1600` or `1600x720` is treated as a
mobile surface: standard text starts at 42px, and touch targets must remain
comfortably larger than desktop mouse targets. Rendered toolbar and chrome
components may use bounded component scale to avoid overlap in portrait mobile
viewports. Hit geometry must still use mobile-sized interaction zones: internal
title-bar hit testing covers the full mobile title-bar height, resize-border
hit testing uses direct mobile scale, and touch drag on visible window body
content may pan the panpanel when there is overflow. In portrait mobile
viewports, internal windows should fit the device-width work area rather than
retaining desktop window widths.

Desktop, browser, mobile, tablet, and remote-assist views must not fork into
separate view-session engines. They share `QNEViewSession` state, window
instances, panpanel geometry, renderer contracts, and control reducers. Device
differences are expressed through `QNEViewProfile` classification,
profile-derived layout constraints, input policy, and renderer wrapping/layout
rules. Long data values such as UUIDs and invite tokens must wrap inside the
window work area instead of clipping off the mobile viewport.

## QNEViewSession Doctrine

A QNEViewSession is a node-hosted live view/control session for an approved
browser, mobile, tablet, kiosk, desktop thin client, remote-assist peer, or
other UI surface.

It is not a full node clone and not a user home. It is a live mediator between
QNENodeSkills, QNESceneData, users, approved devices, remote peers, frame
generation, and returned user controls.

A QNEViewSession owns:

- session ID
- view ID
- hosted user UUID or node-owner context
- view kind, such as browser trial, mobile device, or remote desktop
- frame source kind, such as QNESceneData/Skia, desktop capture, camera capture,
  or future media source
- transport kind, such as browser HTTPS/WSS, local loopback HTTP for development,
  or QNE P2P
- preferred frame encoding, initially JPEG key frames for browser trials and
  later H.264/VP9/AV1/video-delta modes where useful
- viewport and panpanel state
- window chrome state
- control-channel pointer/keyboard/action state
- frame revision and backpressure/caching policy
- capability request/result state where applicable
- audit markers for sensitive actions

QNEViewSession implementation lives in the separate `qne-view-session` crate.
Reusable window and panpanel mechanics live in the separate `qne-window` crate:
rectangle geometry, resize-edge hit testing, window resize math, panpanel
extents, panpanel view clamping, and scroll-bar geometry. Theme and standard
component geometry live in `qne-theme` and `qne-ui-components`. The scene
renderer lives in a separate renderer crate, currently
`qne-scene-renderer-skia`. qne-node is the adapter that authenticates, loads
records, constructs QNEViewSessionConfig, serves the browser shell/HTTP routes,
persists state snapshots, and applies node policy.

The browser adapter must remain a dumb frame display plus control channel. It
must not contain QNE business logic, downloaded executable behavior, or direct
skill execution.

## View-Session Storage Doctrine

Current invite/browser storage uses:

- invite key `browser_view_session_id`
- browser view-session records under `persist/browser-view-sessions/`
- browser view-session state files under `persist/browser-view-sessions/`
- mobile device records under `persist/mobile-devices/`

Legacy inputs may still be read from `browser_shadow_id`,
`persist/browser-shadows/`, and `persist/mobile-shadows/` only to migrate or
resume old pilot data. The node CLI command `storage-migrate --qne-home PATH`
rewrites old invite records, browser records, browser state files, and mobile
device records into the current layout. New code must write only the current
storage names.

## QNEMobileDeviceRecord Doctrine

A QNEMobileDeviceRecord is a durable node-level approval record for a mobile,
tablet, or similar native device.

It is not a QNEViewSession and not a user home. It records approval, identity,
policy, and adapter capability for the physical/native device. The approved
device may later open QNEViewSessions.

A mobile device record includes:

- device UUID
- device public/static key binding
- adapter kind, initially Android
- approval/revocation state
- permissions
- queued scene updates
- queued actions
- capability request/result state
- delegated DHT presence state
- audit markers for sensitive actions

A device may serve the node owner, a member, or a pass-through user/member
session according to node policy. The device record is created at node level so
it can mediate these relationships instead of being owned by one user directory.

## Home Node Pairing Doctrine

The user-facing name for the fixed capable node that owns a person's approved
devices and view sessions is Home Node.

The intended mobile/tablet first-connection flow is QR pairing from the Home
Node. The Home Node creates a short-lived pairing offer containing network ID,
manifest hash, Home Node UUID, reachable UDP endpoint, Home Node static public
key, pairing nonce, and expiry time. The QR code is only a bootstrap and
location mechanism; it is not the permanent credential.

The mobile app scans or receives the pairing payload, connects to the Home Node
endpoint over QNE P2P, presents its device UUID and static public key, and the
Home Node writes or confirms the QNEMobileDeviceRecord allowlist record. Normal
reconnect uses the saved Home Node endpoint and identity. If the endpoint later
changes, discovery can be added through LAN discovery, fixed seed lookup, or
delegated DHT presence.

The first headless implementation may print the pairing payload from CLI. A
later UI/mobile adapter may render the same payload as a QR code.

## QNEMobileAdapter Doctrine

A QNEMobileAdapter translates generic QNEViewSession and capability requests
into platform-specific client behavior.

The initial adapter target is Android. Later adapters may include iOS,
tablet-specific variants, browser, desktop thin client, and kiosk/TV surfaces.

The adapter boundary handles camera, microphone, files, photo picker, sharing,
notifications, biometrics/device unlock confirmation, justified location use,
platform permission prompts, and platform-specific scene rendering details.

The adapter does not execute QNENodeSkills. It only renders QNESceneData, sends
user actions, and returns native capability results.

## Mobile And Tablet Doctrine

Mobile and tablet apps are thin QNE UI surfaces.

They provide device identity proof over QNE P2P, secure transport, scene
rendering, touch/keyboard/camera/media input, native permissions, temporary
cache, and reconnect/resume.

They do not provide durable DHT participation, local QNENodeSkill execution,
background server behavior, downloaded executable behavior, or independent QNE
authority while offline.

The Home Node participates in the network on behalf of the device through the
QNEMobileDeviceRecord policy, delegated DHT presence, and any active
QNEViewSessions for that device.

## DHT Doctrine

DHT lookup keys remain typed. Node UUIDs, member IDs, user UUIDs, and device
UUIDs must not be conflated.

DHT records may include node presence, member/user public summaries,
repository/seed records, and delegated device presence.

For mobile/tablet devices, the DHT advertises delegated presence:

```text
device_uuid -> reachable_via node_uuid
```

It must not advertise that the physical mobile device is directly online when it
is offline or sleeping.

The home/main node is responsible for refreshing delegated presence, queueing
messages, and resuming device sessions.

## User And Member Doctrine

Node identity is separate from user identity and member identity.

Users live under:

```text
QNE/users/<user-uuid>
```

User state includes private user persist, status, UI state, and policy. QNE
Community Members additionally have a seed-assigned member ID/qnename.

User homes must not contain private downloaded skill copies. Shared QNENodeSkill
packages live under the node repository and are gated by policy.

A QNEMobileDeviceRecord may be authorized to serve a user/member context, but it
is not stored under that user/member. It remains a node-level approved-device
record. Live UI/control state belongs in QNEViewSession state.

## Master Node Doctrine

The network master is the public control-plane authority for the network.

The master is responsible for network manifest authority, system node registry,
seed/repository monitoring, governance records, master-authorized testnet
operations, observing heartbeats from system nodes, publishing required network
state, and coordinating trusted rollout policy.

The master is not a general user login server, a global owner of all private
user state, a mobile runtime, a UI host by default, or a replacement for
node-owned identity.

The master may activate network test QNENodeSkills against chosen nodes. Normal
base nodes do not run master test batches unless authorized.

## Seed Node Doctrine

A seed is a normal QNE node running the seed role/QNENodeSkill.

A seed provides first network contact, node presence registry, repository-node
hints, available QNENodeSkill index hints, DHT bootstrap, seed-side enrollment
decisions where required, and delegated DHT record acceptance under policy.

The initial network uses one permanent master seed. Replica seeds may be added
later for availability and geography, but the authority model remains one master
seed unless explicitly revised.

Permanent cloud seeds use IPv6 UDP for QNE network communication.

## Repository Node Doctrine

A repository node provides trusted QNENodeSkill package discovery and
distribution.

Public qne.info downloads are for platform installers and bootstrap artifacts.
Runtime QNENodeSkill distribution should come from QNE repository nodes or
seeds.

Repository nodes publish available package indexes. Nodes cache the available
index and apply policy before enabling or installing any QNENodeSkill.

Base node updates remain trusted node updates, not arbitrary network plugin
replacement.

## Network Startup Doctrine

A new node startup follows this order:

1. Create or restore the QNE home and keep area.
2. Validate the full filesystem layout.
3. Load or create node UUID.
4. Load or create the QNE P2P static key under persist/secrets.
5. Read node config and network manifest.
6. Prefer known same-network LAN peers if available.
7. Fall back to configured seeds.
8. Bind QNE P2P UDP.
9. Start bundled QNENodeSkills through lifecycle start/restore.
10. Advertise node presence to the seed if policy allows.
11. Receive repository/available-skill hints.
12. Start optional role QNENodeSkills: seed, repository, device approval, user hosting, DHT, UI bridge.
13. Resume queued approved-device work, QNEViewSession snapshots, and delegated presence.
14. Enter service loop.

Shutdown follows the reverse doctrine:

1. Stop accepting new local work.
2. Send best-effort presence leave where appropriate.
3. Ask each QNENodeSkill to shutdown gracefully.
4. Pack QNENodeSkill state.
5. Persist lifecycle markers.
6. Preserve node identity, secrets, peer cache, users, approved-device records, QNEViewSession snapshots, and repository state.
7. Stop the service cleanly.

## Transport Doctrine

QNE node-to-node communication remains UDP-only through QNE P2P.

Transport does not define application semantics. QNENodeSkill IDs, action IDs,
topics, and payloads define behavior.

QNE P2P may keep sessions open without constant heartbeat traffic. Mobile apps
should still be treated as intermittent clients because OS battery policy,
sleep, and network changes make durable mobile participation unreliable.

## Installer And Upgrade Doctrine

Desktop/laptop installs receive the QNE node installer. Mobile/tablet installs
receive native apps.

Installers should eventually inspect the device and enable appropriate roles:

- desktop/laptop: capable node, possible DHT, user hosting, UI, repository cache
- old laptop/VM: capable node with adjustable resource use
- server/cloud: seed, repository, master, DHT
- mobile/tablet: thin native client only

Runtime upgrades must preserve:

- QNE/qnenode/persist
- persist/secrets
- persist/lmdb
- persist/ltr
- node UUID
- QNE P2P static key
- users
- QNEMobileDeviceRecord records
- QNEViewSession snapshots where policy requires resume
- peer cache
- rollback material

The base node is stopped for update and restarted after install.

## First Implementation Direction

The current implementation anchor is the v00589 family:

- `qne-node-v00589`
- `qne-view-session-v00536`
- `qne-window-v00500`
- `qne-theme-v00500`
- `qne-ui-components-v00507`
- `qne-keyboard-v00505`
- `qne-spelling-v00500`
- `qne-scene-renderer-skia-v00562`
- `qne-ui-v00555`

Implementation priorities:

- Keep qne-node as the node/invite/auth/persistence adapter.
- Keep QNEViewSession behavior in the separate qne-view-session project.
- Keep reusable window/panpanel mechanics in the separate qne-window project.
- Keep theme tokens in the separate qne-theme project.
- Keep standard UI component geometry/state in the separate qne-ui-components
  project.
- Keep keyboard profiles, round-key geometry, native-like options, and tolerant
  key hit testing in the separate qne-keyboard project.
- Keep spelling lookup, ignored/user words, and suggestion-only correction in
  the separate qne-spelling project.
- Keep frame drawing in renderer crates such as qne-scene-renderer-skia.
- Remove old `shadow` aliases from new code once route and persistence
  compatibility are migrated.
- Move view-session behavioral tests from qne-node into qne-view-session.
- Add Android-first QNEMobileAdapter protocol shape using QNEViewSession.
- Add manual mobile device allowlist CLI and QNEMobileDeviceRecord storage.
- Add delegated DHT presence record shape.
- Add lifecycle tests for QNEViewSession start, shutdown, restore, revocation,
  queued scenes, queued controls, and delegated presence.

This doctrine is the source of truth for the next architecture slice.
