Document Eve surface authority contracts

This commit is contained in:
Meta Vens 2026-07-08 07:40:51 +01:00
commit a3c9dcd2a0
7 changed files with 198 additions and 57 deletions

View file

@ -154,10 +154,18 @@ payloads as `mimir.eve_media_observation.v1`.
accepted state, commands, and side effects.
See `docs/cultmesh-streaming-ui-framework.md` for the target architecture.
See `docs/repo-strategy.md` for the kernel/plugin/runtime/provider ownership
boundary and graduation rules.
See `docs/renderer-parity.md` for current browser/iOS/Android/Fensalir/Flutter
renderer parity.
See `docs/surface-contract-v1.md` for the shared CultUI/CultMesh surface and
command contract.
Nested CultUI surfaces are documented there as `embeddedDocuments` /
`surface.slot`; the parity fixture is
`web/fixtures/cultui-embedded-surface.json`, and the runtime matrix is in
`docs/parity-testing-harness.md`. Renderer runtimes lower or preserve the slot
directly; Rust proves the same `gamecult.eve.surface.v1` contract at the
CultMesh typed document sync layer in CultLib.
See `docs/eve-dsl-reactive-bindings.md` for the first Eve DSL and reactive
CultMesh binding contract.
See `docs/eve-multiverse.md` for the Eve MultiVerse philosophy and missing API
@ -172,9 +180,9 @@ Start the browser reference surface runner:
powershell -ExecutionPolicy Bypass -File .\scripts\start-browser-reference.ps1
```
Open `http://127.0.0.1:8891/`. The page can spawn:
Open `http://127.0.0.1:8891/`. The page can render local fixture and
advertisement surfaces:
- `VoidBot Live`, connected to Mimir's `/eve/deck` broker.
- `Fensalir Direct2D`, a fixture surface for the planned
CultMesh-to-`AquariumUiDocument` lowering.
- `Sai VN Surface`, a fixture for visual-novel scenes exported as
@ -186,6 +194,9 @@ Open `http://127.0.0.1:8891/`. The page can spawn:
- `Reactive DSL`, a browser-reference fixture that compiles a small `.eve`
composition language into the same surface contract and binds UI controls to
live CultMesh-shaped vars, collections, and derived fields.
- `Embedded Surface Slot`, a CultUI fixture proving that a parent surface can
reserve layout while a child CultMesh document is resolved and rendered as a
nested surface.
## VoidBot CEF Stream
@ -195,8 +206,9 @@ Start the Starfire relay from `E:\Projects\VoidBot`:
npm run swarm:eve-cef-relay -- --width 1620 --height 2160 --scale 2 --port 8792
```
EveCanvas connects to `ws://192.168.1.66:8792/stream`, displays binary JPEG
frames, and returns touch events to the relay.
EveCanvas displays binary JPEG frames and returns touch events only when a
stream lowering is configured through `EVE_STREAM_URLS`. The native app no
longer guesses a Starfire relay address.
## Mimir Sensor Uplink
@ -208,10 +220,11 @@ dotnet run --project E:\Projects\Mimir\src\Mimir.EveSensorReceiver\Mimir.EveSens
dotnet run --project E:\Projects\Mimir\src\Mimir.EveSensorReceiver\Mimir.EveSensorReceiver.csproj -- --port 8794 --path /eve/mic --source-id eve-mic --type audio-block
```
EveCanvas sends binary `mimir.eve_media_observation.v1` camera observations to
`ws://192.168.1.66:8793/eve/camera` and microphone observations to
`ws://192.168.1.66:8794/eve/mic`. Periwinkle sends camera, microphone, motion,
and touch observations through `ws://192.168.1.66:8796/eve/periwinkle`.
EveCanvas sends binary `mimir.eve_media_observation.v1` camera and microphone
observations only when `EVE_CAMERA_URLS` and `EVE_MIC_URLS` are configured.
Periwinkle sends camera, microphone, motion, and touch observations only when
launched with an explicit `org.gamecult.eve.SENSOR_URI`; the apps no longer
guess receiver URLs.
## Native Mimir Dashboard
@ -221,12 +234,12 @@ Start the dashboard authority on Starfire:
dotnet run --project E:\Projects\Mimir\src\Mimir.EveDashboard\Mimir.EveDashboard.csproj -- --port 8795
```
EveCanvas connects first to `ws://192.168.1.66:8795/eve/deck`, with
`/eve/dashboard` kept as a compatibility fallback. The Starfire broker sends
native retained `dashboard-state` snapshots. This is the current CultNet-shaped
surface document for provider id, title, scene nodes, selection, visibility,
transform, size, health, detail text, identity ids, and avatar URLs. EveCanvas
sends compact commands back:
EveCanvas connects to the Mimir dashboard WebSocket lowering for native retained
`dashboard-state` snapshots. That lowering renders the daemon-owned CultMesh
dashboard state; it is not provider discovery authority. Live provider discovery
belongs to Odin/CultMesh advertisements. Native iOS dashboard lowerings must be
configured through `EVE_DASHBOARD_URLS`; missing discovery stays visible instead
of falling back to LAN constants. EveCanvas sends compact commands back:
- `select`
- `move`
@ -254,11 +267,13 @@ Build the Android proof APK from Starfire:
powershell -ExecutionPolicy Bypass -File .\scripts\build-android.ps1
```
Install to Periwinkle:
Install to Periwinkle, then launch it. If Odin/CultMesh has provided dashboard
and sensor endpoints, pass them explicitly; otherwise the app starts with those
network paths disabled instead of guessing LAN addresses.
```powershell
& "$env:LOCALAPPDATA\Android\Sdk\platform-tools\adb.exe" -s bad9dd01 install -r .\artifacts\android\eve-debug.apk
& "$env:LOCALAPPDATA\Android\Sdk\platform-tools\adb.exe" -s bad9dd01 shell monkey -p org.gamecult.eve -c android.intent.category.LAUNCHER 1
& "$env:LOCALAPPDATA\Android\Sdk\platform-tools\adb.exe" -s bad9dd01 shell am start -n org.gamecult.eve/.MainActivity --es org.gamecult.eve.DASHBOARD_URI "ws://<odin-or-dashboard-lowering>/eve/deck/cultmesh" --es org.gamecult.eve.SENSOR_URI "ws://<odin-or-sensor-lowering>/eve/periwinkle"
```
On Xiaomi/MIUI devices, ADB install may require enabling developer setting

View file

@ -132,18 +132,19 @@ Fensalir Direct2D:
## Current Proof
The current iOS app consumes Mimir's `/eve/deck` WebSocket broker. That broker is
already shaped like the future API: provider manifests, retained dashboard
state, provider switching, commands, and typed node metadata. The VoidBot
provider proves that Eve can render an app-specific native cockpit from a
structured mesh snapshot: CTB rail, avatar images, selected Persona/status pane,
state tree, and detail panel.
The current native app consumes Mimir's dashboard WebSocket lowering for retained
dashboard state. That lowering is shaped like the future API: retained dashboard
state, provider switching, commands, and typed node metadata. It is a renderer
path over daemon-owned state, not provider discovery authority. Live provider
discovery belongs to Odin/CultMesh advertisements.
The Android proof under `android/` builds directly against the installed Android
SDK and runs on Periwinkle. It is deliberately small: display Eve's role, poll
the Mimir broker health endpoint, and show timestamped motion/touch samples.
It is a device-edge proof while the browser reference and Flutter/native shared
client are still being cut.
SDK and runs on Periwinkle. It is deliberately small: display Eve's role, render
a configured CultMesh dashboard lowering when one is provided, and capture
timestamped motion/touch/media samples. It does not bake in Mimir dashboard or
sensor URLs; missing discovery stays visible until Odin/CultMesh provides the
endpoints. It is a device-edge proof while the browser reference and
Flutter/native shared client are still being cut.
The public site now reflects the same pressure. The integrated dossier frames
CultMesh as typed distributed state. The Week 07 damage report records Fensalir

View file

@ -36,22 +36,39 @@ metric "Opacity" bind program.Field(x => x.Layers[1].Opacity)
Today the lower substrate exposes reactive document changes through CultMesh /
CultNet database watch streams. The field-level POCO binding handle is the
next ergonomic cut. Until that lands, Eve documents should still carry explicit
binding descriptors:
next ergonomic cut. Eve documents now carry explicit
`CultMeshStateBindingDescriptor` values on each component so renderers do not
have to infer provider state from string props:
- document schema;
- document id, key, or named handle;
- field path;
- value kind;
- access mode;
- authority label;
- optional command id for writes;
- freshness, prediction, denial, and reconciliation metadata where available.
- `targetProp`, the component prop that receives the live value;
- `pointerId`, the stable typed CultMesh state pointer;
- `sourceId`, the provider/CultMesh source, record, witness, or field id;
- `schemaId`, the state schema;
- `routeKind` and `routeDescription`, so runtimes can prefer in-process,
shared-memory, IPC, network, or WASM paths without app glue.
This keeps the DSL honest. The visual language can name a field; the provider
and CultMesh decide whether that field is readable, writable, predicted,
accepted, denied, stale, or missing.
Commands follow the same rule. Eve command templates carry
`CultMeshOperationBindingDescriptor` values so a button or menu item points at
a typed operation id, optional request schema, label, and route hint. The DSL
may provide friendly `button` sugar, but the compiled surface should not make a
free-floating command string the canonical operation boundary or public
runtime construction path.
When a renderer fires that command, the request carries a
`CultMeshOperationInvocationDescriptor`. That invocation preserves operation id,
request schema, preferred route, and optional idempotency through the renderer
boundary so Aetheria, Bifrost, Unity, Electron, and browser runtimes do not each
invent a local command envelope. The request payload is a
`CultMeshOperationPayload`, so renderers can ingest surface props at the edge
while command handlers read scalar fields through shared typed helpers. New
runtime code should construct requests from the invocation descriptor and
payload primitive directly; raw command strings and dictionary payloads are
serialization details, not live APIs.
Discovery of those backing documents should come from a provider advertisement
when available. See
[provider-advertisement-contract.md](./provider-advertisement-contract.md) for

View file

@ -85,27 +85,65 @@ fixture claiming to render CultUI while the retained tree no longer contains
the partitions, bindings, tokens, or slider anatomy the renderer is supposed to
lower.
The fixture matrix also includes `embedded-surface`, which proves that nested
CultMesh document slots survive the shared surface contract. The web reference,
Flutter parity body, Unity UI Toolkit lowerer, iOS UIKit renderer, and native
Android Kotlin dashboard renderer all need to understand
`surface.slot`/`embeddedDocuments`. Rust participates at the CultMesh document
sync layer: it must preserve the same `gamecult.eve.surface.v1` slot contract
through typed document replication even when it is not painting pixels.
Nested surface support is a required feature for every active GUI runtime in
`tools/parity/parity-manifest.json`. Active runtimes list
`requiredFixtures: ["embedded-surface"]` and
`supportedFeatures: ["embeddedDocuments"]`; the semantic report prints both so a
runtime cannot quietly fall out of the contract. Runtime entries also use
`expectedSourceSymbols` for the renderer files that must contain the slot
lowering path, so a runtime cannot keep a green body merely because its source
file exists. The shared fixture is `web/fixtures/cultui-embedded-surface.json`,
and renderer-specific tests should load that fixture rather than hand-authoring
a local substitute.
## Runtime Status
The harness tracks every target runtime:
- Web reference: active semantic and screenshot target through Chrome headless
using the provider query parameter.
using the provider query parameter. Required nested-surface evidence:
`node --test web\eve-dsl.test.mjs` plus the `embedded-surface` fixture in
`tools/parity/run-parity.mjs`.
- Web responsive layout: Chrome headless emits phone, tablet, and desktop PNGs.
- iOS / UIKit: screenshot target through SSH and EveCanvas'
`/var/mobile/Library/EveCanvas/capture-request` service. Current iOS capture
is fixed-device until a simulator or device-resize adapter exists.
is fixed-device until a simulator or device-resize adapter exists. Required
nested-surface evidence: run `scripts/run-parity-smoke.ps1 -ProviderId
gamecult.eve.embedded-demo` against the device target.
- Windows / Flutter: screenshot target through the Flutter parity golden smoke,
with phone, tablet, and desktop goldens.
with phone, tablet, and desktop goldens. Required nested-surface evidence:
`flutter test --plain-name embedded_surface_fixture_contract` plus
`scripts/capture-flutter-parity.ps1 -FixtureId
gamecult.eve.embedded-demo`.
- Linux / Flutter: screenshot target through Nightwing over SSH. The smoke
stages `flutter/eve_parity`, runs Flutter goldens on Nightwing, and pulls back
phone, tablet, and desktop PNGs.
phone, tablet, and desktop PNGs. Required nested-surface evidence:
`scripts/capture-linux-flutter-parity.ps1 -FixtureId
gamecult.eve.embedded-demo`.
- Android / Flutter: screenshot target through the same Flutter renderer,
packaged as a debug APK, installed on Periwinkle through `adb`, and captured
with optional `adb shell wm size`, orientation control, and `adb exec-out
screencap`; the script restores device size and rotation after each viewport.
- Android / Kotlin device edge: compatibility body for CultMesh dashboard and
sensor experiments. It is not the GUI parity target.
Required nested-surface evidence: `scripts/capture-android-flutter-parity.ps1
-FixtureId gamecult.eve.embedded-demo`.
- Android / Kotlin device edge: lightweight native CultMesh dashboard and
sensor host. Required nested-surface evidence:
`android/app/src/main/java/org/gamecult/eve/MainActivity.kt` renders
`surface.slot` with a content description containing the embedded slot
identity, and `node tools/parity/run-parity.mjs` reports
`embeddedDocuments` support for `android-kotlin`.
- Rust / CultMesh: typed document runtime rather than a CultUI renderer.
Required nested-surface evidence: `cargo test -p cultnet-rs
rust_preserves_cultui_embedded_surface_slots_through_typed_document_sync`
in CultLib.
- Fensalir Direct2D: specialized native target, adapter/capture still missing.
Pending runtimes are allowed. Silent fake parity is not.

View file

@ -167,12 +167,12 @@ Transport routes are separate from service identity:
```json
{
"kind": "cultnet",
"address": "cultnet://10.77.0.4:3075",
"address": "cultmesh://asgard.yggdrasil.streampixels/transport/cultnet",
"carries": [
"asgard.yggdrasil.streampixels/eve/tui",
"asgard.yggdrasil.streampixels/eve/gui"
],
"note": "CultNet reliable UDP route for this located service."
"note": "Odin/CultMesh-discovered CultNet reliable UDP route for this located service."
}
```

View file

@ -17,17 +17,27 @@ enough that Repixelizer remains itself across runtimes.
The shared fixture/report path lives in
[parity-testing-harness.md](./parity-testing-harness.md). That harness is the
current evidence surface for semantic parity and runtime capture gaps.
The nested CultUI surface feature is tracked as fixture `embedded-surface`,
loaded from `web/fixtures/cultui-embedded-surface.json`, and must be understood
by every renderer that claims `gamecult.eve.surface.v1` GUI parity.
Runtime discovery for the feature is in `tools/parity/parity-manifest.json`:
active GUI runtimes advertise `supportedFeatures: ["embeddedDocuments"]` and
require the `embedded-surface` fixture. Native Android/Kotlin makes a narrower
active claim: it preserves and displays embedded slot identity in its dashboard
renderer while Android Flutter remains the responsive screenshot target. Rust
proves the same contract at the CultMesh typed document sync layer.
## Current State
| Renderer | Status | Proof | Gap |
| --- | --- | --- | --- |
| Web reference | Active reference/debug renderer | `web/` renders live VoidBot and fixture surfaces through the provider picker; compiles indentation CultUI; lowers partitions, field rows, and slider anatomy; Chrome headless capture emits phone/tablet/desktop PNGs | Needs command round-trip tests |
| Windows / Flutter | Active shared graphical smoke target | `flutter/eve_parity` loads exported `gamecult.eve.surface.v1` fixture JSON and emits phone/tablet/desktop golden PNGs through `capture-flutter-parity.ps1` | Needs native window capture and tighter text/style normalization |
| Linux / Flutter | Active shared graphical smoke target | Nightwing runs the Flutter parity goldens over SSH and returns phone/tablet/desktop PNGs | Needs native window capture and runner health checks |
| Android / Flutter | Active shared graphical smoke target | The same Flutter parity app is built as an APK, installed on Periwinkle, and captured at phone/tablet/desktop plus native physical panel orientations | Needs live provider picker and command transport beyond fixture assets |
| iOS / UIKit | Active native screenshot target | SSH capture stages selected fixture JSON, EveCanvas renders it, and emits a PNG from `/var/mobile/Library/EveCanvas/latest-screenshot.png` | Needs real scene composition for `vn.stage`, Repixelizer token fidelity, and responsive/simulator capture |
| Android / Kotlin device edge | Compatibility body | Native APK consumes CultMesh dashboard/sensor documents for edge experiments | Not the GUI CultUI parity target unless direct Android ownership earns its keep |
| Web reference | Active reference/debug renderer | `web/` renders local provider advertisements and fixture surfaces through the provider picker; compiles indentation CultUI; lowers partitions, field rows, slider anatomy, and `surface.slot`; Chrome headless capture emits phone/tablet/desktop PNGs | Needs live Odin/CultMesh provider feed and command round-trip tests |
| Windows / Flutter | Active shared graphical smoke target | `flutter/eve_parity` loads exported `gamecult.eve.surface.v1` fixture JSON, including `embedded-surface`, and emits phone/tablet/desktop golden PNGs through `capture-flutter-parity.ps1` | Needs native window capture and tighter text/style normalization |
| Linux / Flutter | Active shared graphical smoke target | Nightwing runs the Flutter parity goldens, including embedded surface slots, over SSH and returns phone/tablet/desktop PNGs | Needs native window capture and runner health checks |
| Android / Flutter | Active shared graphical smoke target | The same Flutter parity app is built as an APK, installed on Periwinkle, and captured at phone/tablet/desktop plus native physical-panel orientations | Needs live provider picker and command transport beyond fixture assets |
| iOS / UIKit | Active native screenshot target | SSH capture stages selected fixture JSON, EveCanvas renders it, and emits a PNG from `/var/mobile/Library/EveCanvas/latest-screenshot.png`; `embedded-surface` is part of the required fixture matrix | Needs real scene composition for `vn.stage`, Repixelizer token fidelity, and responsive/simulator capture |
| Android / Kotlin device edge | Active lightweight renderer | Native APK consumes CultMesh dashboard/sensor documents and preserves `surface.slot` / `embeddedDocuments` identity in the dashboard renderer | Needs automated native dashboard capture |
| Rust / CultMesh | Document-sync contract runtime | CultLib replicates the `gamecult.eve.surface.v1` embedded slot contract through typed document sync | Not a pixel renderer |
| Fensalir Direct2D | Specialized native/game-runtime landing zone | Existing `AquariumUiDocument` and `DirectWriteOverlay` path | Needs adapter from Eve surface document to `AquariumUiDocument`, DirectWrite/Direct2D token lowering, and a clear reason to stay separate from Flutter for desktop UI |
## Spawned Surfaces
@ -35,8 +45,6 @@ current evidence surface for semantic parity and runtime capture gaps.
The browser reference runner now exposes local advertisements through the
provider picker:
- `VoidBot Live`: connects to Mimir's `/eve/deck` broker and opens
`voidbot.swarm`.
- `Repixelizer`: loads `web/fixtures/repixelizer.provider-advertisement.json`
and `web/fixtures/repixelizer.eve-surface.json`.
- `Fensalir Direct2D`: loads `web/fixtures/fensalir-client-surface.json`, a
@ -47,9 +55,11 @@ provider picker:
- `CultUI Inspector`: compiles `web/fixtures/cultui-slider-inspector.eve`
and proves partition/field-row/slider-anatomy lowering in the web reference.
The remaining temporary part is the local provider list itself. The runtime app
target is the same picker fed by live `gamecult.eve.provider_advertisement.v1`
documents through CultMesh/Odin.
The remaining temporary part is the local fixture provider list itself. The
runtime app target is the same picker fed by live
`gamecult.eve.provider_advertisement.v1` documents through CultMesh/Odin; the
browser reference no longer opens live providers by dialing Mimir's deck broker
directly.
Start it with:

View file

@ -79,7 +79,9 @@ Every component has:
"id": "stable.local.id",
"kind": "panel.dialogue",
"props": {},
"children": []
"children": [],
"stateBindings": [],
"embeddedDocuments": []
}
```
@ -102,6 +104,46 @@ If a renderer does not know a specialized kind, it should fall back through the
kind path: `panel.dialogue` may render as `panel`; `image.sprite` may render as
`image`.
`stateBindings` are explicit `CultMeshStateBindingDescriptor` values attached
to component props. They keep provider state identity out of ad-hoc renderer
stores and out of string-only prop conventions. A binding names:
- `targetProp`: component prop receiving the live value, usually `value`.
- `pointerId`: stable typed CultMesh state pointer id.
- `sourceId`: provider/CultMesh source, record, witness, or field id.
- `schemaId`: schema of the source state.
- `routeKind`: preferred locality such as `in-process`, `shared-memory`,
`ipc`, `network`, or `wasm`.
- `routeDescription`: optional diagnostics for tools and operators.
Renderers may still honor compatibility props such as `valueRef`, but new
CultUI/Eve runtimes should use `stateBindings` as the canonical contract and
let the CultMesh runtime resolve, watch, predict, or deny the value. Eve does
not define a parallel binding DTO; the live surface contract imports the shared
CultMesh primitive directly.
### Embedded Documents
`embeddedDocuments` are explicit CultMesh document slots attached to a component.
Use them when a provider wants one surface to own layout while a nested region
remains a separately synced document. Inventory panels, inspectors with live
subdocuments, tab bodies, drag/drop overlays, and remote tool panes should use
slots instead of copying child state into a parent DTO.
Each slot names:
- `slotId`: stable local slot identity inside the parent component.
- `documentId`: CultMesh document id to resolve and subscribe to.
- `schemaId`: expected schema, commonly `gamecult.eve.surface.v1` or a
provider-specific surface document schema.
- `presentationKind`: semantic lowering hint such as `inventory.dropdown`.
- `routeHint`: optional CultMesh locality hint for resolving the child.
Renderers lower normal `children` first, then resolve and mount
`embeddedDocuments` through their CultMesh document resolver. A renderer that
cannot resolve a slot must preserve the slot identity in diagnostics or a
placeholder; it must not invent a local substitute for the child document.
## Embedded Knowledge Surfaces
Eve must be able to place rich interactive surfaces inside another surface. For
@ -216,6 +258,24 @@ Standard command names:
- `transform.rotate`
Providers may add command names, but they must advertise them in `commands`.
Live Eve command templates carry `CultMeshOperationBindingDescriptor` values:
the operation id is the canonical command identity, `schemaId` may name the
typed request body, `label` names the visible affordance, and `routeHint`
describes the preferred invocation locality. Compatibility fields such as
`command` and `transport` may still be projected for old renderers, but they
are not the authoritative live command model and should not appear as public
runtime construction APIs.
Renderer command requests carry `CultMeshOperationInvocationDescriptor` values.
That invocation descriptor is the canonical operation identity at click/change
time and preserves request schema, preferred route, and optional idempotency.
Renderer command requests also carry `CultMeshOperationPayload`, a shared
payload value with typed scalar readers. Legacy `command` strings and string
payload fields may be serialized while old documents migrate, but live
CultUI/Eve runtimes route from the shared CultMesh invocation descriptor and
read scalar fields through the shared payload primitive. Renderer code should
construct requests from `CultMeshOperationInvocationDescriptor` and
`CultMeshOperationPayload`, not from command strings plus raw dictionaries.
## Synchronized Style