From fa7d95191acd3de6e7bfe60fd87d15fdf32befeb Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Sat, 10 Oct 2026 20:06:28 +0200 Subject: [PATCH] Thing 2.0 map: model page, consumer contract, cut order; fork prior art Imagination pass imagination-thing2-contract (session self-2026-10-10c-eureka). docs/thing2-map.md holds body facts P1-P11, the model page, the consumer contract (closed node set, compositions, one binding path, one command envelope), the fate of every Thing 1 kind, the authority map and the cut order by deliverable. docs/research/thing2-contract-forks-prior-art.md holds the prior art for the forks code-home, thing-script-form, advertisement-owner and port-cutover. Co-Authored-By: Claude Opus 5.5 --- .../thing2-contract-forks-prior-art.md | 97 +++++ docs/thing2-map.md | 369 ++++++++++++++++++ 2 files changed, 466 insertions(+) create mode 100644 docs/research/thing2-contract-forks-prior-art.md create mode 100644 docs/thing2-map.md diff --git a/docs/research/thing2-contract-forks-prior-art.md b/docs/research/thing2-contract-forks-prior-art.md new file mode 100644 index 0000000..4007553 --- /dev/null +++ b/docs/research/thing2-contract-forks-prior-art.md @@ -0,0 +1,97 @@ +# Thing 2.0: prior art for the contract forks (Imagination, 2026-10-10) + +Forks served, all raised in `thing2:campaign:self`: `thing2:question:code-home`, +`thing2:question:thing-script-form`, `thing2:question:advertisement-owner`, +`thing2:question:port-cutover`. Agent `imagination-thing2-contract`, session +`self-2026-10-10c-eureka`. Facts read today through `gh api repos//contents` +(top-level and named subdirectories); **[background]** marks prior knowledge not +re-fetched in this pass. It does not repeat `thing2-foundation-prior-art.md` or +`thing2-text-input-a11y-prior-art.md`. + +## 1. How established toolkits split their code across repos (fork `code-home`) + +| Project | What one repo holds (read today) | What lives in other repos | +| --- | --- | --- | +| Slint (`slint-ui/slint`) | `internal/` = compiler, core, interpreter, `backends/` (android-activity, linuxkms, qt, selector, testing, winit), `renderers/` (anyrender, femtovg, skia, software); `api/` = cpp, node, python, rs, wasm-interpreter. `api/node` is a Rust napi crate (`Cargo.toml`, `build.rs`, `binding.cjs`) in the same tree. | none needed for the shipped language APIs | +| egui (`emilk/egui`) | `crates/` = egui, epaint, emath, ecolor, eframe, egui-wgpu, egui-winit, egui_glow, egui_kittest (tests), egui_extras, egui_plot, demo app | community backends (Bevy, macroquad) live with their hosts **[background]** | +| iced (`iced-rs/iced`) | core, runtime, widget, renderer, wgpu, tiny_skia, winit, graphics, futures, test, tester | none for first-party backends | +| Xilem (`linebender/xilem`) | masonry, masonry_core, masonry_winit, masonry_testing, xilem, xilem_core, xilem_web | Parley and Vello are separate linebender repos (independently consumed libraries) | +| AccessKit (org) | `accesskit` = schema crate, consumer, every platform adapter | `accesskit-c` (C bindings, CMake) and `accesskit-python` (maturin) are separate repos | +| Flutter | `flutter/flutter` now holds `engine/` beside `packages/`; `flutter/engine` is archived (last push 2025-02-25). The engine was merged into the framework repo to end cross-repo "rolls" **[background on the reason]**. | plugins and federated platform packages live in `flutter/packages` **[background]** | +| Adaptive Cards (`microsoft/AdaptiveCards`) | `source/` = android, dotnet, ios, nodejs, uwp, shared: every host renderer of one card schema in one repo; `source/nodejs` adds `adaptivecards-templating`, `ac-typed-schema`, the designer | hosts (Teams, Outlook) are not in the repo | +| Taffy | one crate, `test_fixtures/` + generated tests | Python binding `stretchable` is a third-party repo | + +Pattern: the schema, the core and the first-party backends and language bindings +share one repo when they share one build system or can be built from one +workspace. Separate repos appear where a binding needs a different packaging +toolchain (AccessKit C/Python) or is an independently consumed library (Parley, +Vello). Flutter is the counter-example in the other direction: two repos with a +version roll between them were merged into one. + +The operator's July concern (`thing2-foundation-prior-art.md` 1.1, 2026-07-10) +names what made the Thing 1 monorepo risk a swamp: "every runtime build system, +plugin fixture, platform SDK, and product demo starts sharing one git status". +Under the Thing 2.0 target, plugin fixtures and per-renderer lowerers do not +exist (invariants `compose-not-kind`, `closed-commands`); the remaining platform +SDKs with their own toolchains are Unity (UPM, Unity Editor) and Flutter (pub, +Android/iOS SDKs). Neither has a live consumer (census section 5: EveUnity and +EveFlutter are BUILD only; Aetheria publishes nothing). + +## 2. How surface documents are authored (fork `thing-script-form`) + +- **Typed document published by services, rendered by hosts:** Adaptive Cards + (JSON card schema; `ac-typed-schema` package read today; hosts render with + their own HostConfig theme **[background]**). Data binding is a separate + templating package (`adaptivecards-templating`, read today) that expands a + template against data before render. Slack Block Kit: JSON blocks with builder + libraries per language **[background]**. +- **Text language compiled to a typed tree:** Slint `.slint`, compiled by + `internal/compiler` and also loadable at run time by `internal/interpreter` + (both read today as directories); QML, XAML **[background]**. +- **Code builders only:** Flutter, SwiftUI, Jetpack Compose, egui, Xilem + **[background]**. All are single-process: the tree never crosses a wire. +- **Body:** Thing 1 has both. The text DSL `web/eve-dsl.js` (544 lines) parses + `.eve` fixtures; its local mesh lets a button `append`/`set` state directly in + the renderer and computes `derive ... count|latest` there (`eve-dsl.js:103-155`). + The C# builder `packages/org.gamecult.eve.surface/Runtime/EveSurfaceBuilder.cs` + (876 lines) and every provider's hand-built JSON (census) are the builder side. + Ruling `thing:ruling:operator-dsl-thing-script` names the authoring DSL Thing + Script and keeps the retained tree schema-named; target r1 calls the published + typed documents Thing Script. + +## 3. Who owns service discovery (fork `advertisement-owner`) + +- Body: `gamecult.eve.provider_advertisement.v1` (329 lines, 18 properties, + 11 required) carries Verse discovery (`verseId`, `serviceId`, + `canonicalService`, `locatedService`, `cultMeshAddress`, `freshness`, + `schemas`, `witnesses`) beside UI facts (`surfaces`, `commands`). Odin reads it + as `EveProviderAdvertisementRecord { value: Value }` + (`Odin crates/odin-core/src/documents.rs`, origin/main): an untyped blob. + CultLib's CultMesh runtimes declare no service-advertisement document of their + own (`git grep -i advertis` over `src/` and `packages/cultmesh-ts/src`: only + transport endpoint and certificate-pin mentions). So the Verse's only provider + discovery document lives in the UI library's namespace. +- Weksa also writes `gamecult.eve.interface_binding.v1` holding a third copy of + its routes (`provider.endpoints`, `routes`) and its whole surface + (`weksa-daemon.mjs:321-341`); Odin reads it as + `EveInterfaceBindingCompatRecord { value: Value }`. +- Prior art: app or service manifests are separate from UI payloads in the + service-driven UI systems above: a Teams app manifest declares bots and + commands, and cards are message content **[background]**; service registries + (Consul, Kubernetes Services) are not owned by any UI toolkit **[background]**. + +## 4. How a cutover crosses many live consumers (fork `port-cutover`) + +- Thing 1 plan (campaign `thing` revision 5): one Verse window, every E1 carrier + flips together, because a rename of one kind cannot be read under two ids + without an alias (ruling `thing:ruling:operator-compat-rebuild` forbids it). +- Expand/contract ("parallel change") and the strangler-fig pattern migrate + consumers one at a time while the old and new paths coexist, then delete the + old path when the last consumer leaves **[background: Fowler]**. +- Body: Thing 2.0 kinds are not renames of Thing 1 kinds. The document shape, + the command envelope and the binding model differ (see the map's model page), + so an aggregator reading both is reading two kinds, not one kind under two ids. + Live viewers today: Ghostlight's web client (vendored `eve-browser-lowering`, + `ajv` in `web/package.json`) and the Nightwing browser reference + (`nightwing-eve-browser-reference`, `Repo = "Eve"`, runtime-enforced, `Deploy = + $null`, gamecult-ops `idunn-deployment-targets.ps1:262-272`). diff --git a/docs/thing2-map.md b/docs/thing2-map.md new file mode 100644 index 0000000..4794ea4 --- /dev/null +++ b/docs/thing2-map.md @@ -0,0 +1,369 @@ +# Thing 2.0 map + +Campaign `thing2` in the eureka mind. Imagination pass `imagination-thing2-contract`, +session `self-2026-10-10c-eureka`, 2026-10-10. Target `thing2:target:r1` +(`docs/thing2-target.md`). Rulings in force and cited by id: +`thing:ruling:thing2-one-solver-taffy`, `thing:ruling:thing2-thing-owns-text`, +`thing:ruling:wire-rename-freeze-fold`, `thing:ruling:operator-compat-rebuild`, +`thing:ruling:hold-renames-for-thing2`, `thing:ruling:operator-dsl-thing-script`, +`thing:ruling:operator-member-names-keep`, `thing:ruling:operator-aetheria-eve-rename`. + +This page holds body facts, the model page, the consumer contract at the level +consumers need, the cut order at the level of deliverables, and rationale. The +questions it raises are documents in the mind (`thing2:question:*`); it does not +restate their options. Research for the forks: +`docs/research/thing2-contract-forks-prior-art.md`. Evidence it builds on: +`docs/research/thing2-consumer-census.md` (census, cited as C§n, BD1-BD9), +`docs/research/thing2-foundation-prior-art.md`, +`docs/research/thing2-text-input-a11y-prior-art.md`, and `docs/thing-campaign.md` +(rename table T, edges E1-E7, body facts B1-B28). + +## Body facts + +Probes run 2026-10-10 against `origin/` after `git fetch` unless a +local path is named. Scripts are in the session scratchpad +`imagination-thing2-contract/`. + +**P1. The Thing 1 contract is 38 schemas, most of them process machinery.** +`p1_schemas.py` over Eve `schemas/` at `a758787`: 38 files. Eleven describe +conformance, hand-off, split-target, release, capture and witness bookkeeping +(`conformance_*`, `*_handoff`, `runtime_*`, `capability_matrix`, +`provider_scenario`); five describe one renderer's output (`unity_*`, +`electron_shell_projection`, `web_layout_probe`, `tui_grid`); seven describe the +plugin system (`plugin*`). Every schema but `command_invocation`, +`command_result`, `entity_soa_view`, `input_*` and `asset_catalog` sets +`additionalProperties: true`. + +**P2. Commands travel in four overlapping envelopes, and the result is hand-built +JSON.** `command.v1` (descriptor, open), `command_invocation.v1` (closed), +`command_receipt.v1` (open, `state` enum `accepted|denied|pending|reconciled`) +and `command_result.v1` (closed: exactly `schema, receipt, transientProjection, +pluginPayload, draftDirective`). Ghostlight `crates/ghostlight-dungeon/src/eve.rs` +at `327cbe3`: `validate_invocation` (`:665-700`) re-checks the envelope by string +comparison; `command_result` (`:734-`) takes `state: &str` and builds the receipt +with `json!`; its own log filter names a state `"completed"` that the receipt +enum does not admit (`:746`). Today it passes only `accepted` and `denied` +(tally of call sites). The browser rejects a flat result whole through `ajv` +(`web/package.json` depends on `ajv`; `eve.rs:723-731` comment). Nothing but +convention stands between a provider and a result the viewer refuses. + +**P3. One surface kind has two schemas and is stored as an untyped blob.** +`surface.v1` declares `type: const "surface-state"`; `surface_state.v1` exists +only as code: CultLib `packages/cultcache-ts/src/swarm-documents.ts:82-96` +(members `providerId, title, version, updatedAt, surface: object`) and Odin +`crates/odin-core/src/documents.rs` (`EveSurfaceStateRecord { surface: Value }`; +advertisement and interface binding are `{ value: Value }`). The load-bearing +shape is JSON inside CultCache. + +**P4. `interface_binding.v1` is not a binding.** weksa +`scripts/weksa-daemon.mjs:321-341` writes routes (`endpoints`, `routes`, +`cultMeshAddress`) and the whole operator surface into it; its document type +parses anything (`schema: { parse: (value) => value }`, `:418`). It is a third +copy of the advertisement's routes and the surface. + +**P5. The text DSL lets the renderer write state.** `web/eve-dsl.js:103-155`: +`var`, `collection`, `derive` (`count`, `latest`) live in a renderer-local mesh, +and `applyAction` appends or sets values there on a button press +(`web/fixtures/reactive-composition.eve`: `button "Append Event" append +swarm.events ...`). + +**P6. A domain-looking kind is layout plus a server-side command.** Muninn +`crates/sleipnir-daemon/src/main.rs:1374-1415`: `binding.target` is a labelled +target with `x, y, anchorX, anchorY` over a controller image; "listening" is the +daemon's `pending_learn` state. Absolute positioning (Taffy `position: +absolute` with insets), a button and a bound label compose it. + +**P7. Login needs a host effect, not a plugin payload.** Ghostlight +`web/src/heimdall-access-adapter.ts:48-66`: a `pluginPayload` of schema +`heimdall.auth_navigation_receipt.v1` makes the client call +`window.location.assign(url)`; on return it reads the URL and resumes +(`:82`, `:134`). + +**P8. Two live viewers render surfaces.** Ghostlight's web client vendors +`@gamecult/eve-browser-lowering` and `eve-contracts` from `vendor/eve` +(`web/package.json`). gamecult-ops `scripts/idunn/idunn-deployment-targets.ps1:262-272` +at `9aed01f`: `nightwing-eve-browser-reference`, `Repo = "Eve"`, +`Status = "runtime-enforced"`, `Deploy = $null`. Odin aggregates and renders +nothing. + +**P9. CultCache-rs members are serde types.** CultLib +`packages/cultcache-rs/src/lib.rs:5501-5520`: a `DatabaseEntry` whose member is a +struct holding an enum round-trips through the MessagePack store. Whether the TS, +C# and Python CultCache runtimes decode a recursive tagged union written by Rust +with parity was not established in this pass. It is the first thing the +contract cut proves (see the cut order). + +**P10. The stale `.voidbot` lines are still on Eve main.** `a758787`: +`.gitignore:28-30` and `scripts/stage-to-eve.ps1:24` (`--exclude=.voidbot`). +`git grep -n '\.voidbot' -- .gitignore scripts` prints exactly those four lines; +`Sources/EVEViewController.mm` mentions `voidbot.swarm` (no dot) and is not +matched. + +**P11. The campaign's repo list has room for the early cuts only.** Mind, +`thing2:campaign:self`: repos `GameCult/Eve`, `GameCult/gamecult-ops`. +`eureka-substrate:cut_spec:cut-campaign-repos.r1` (target-revision repo sets, up +to 16) is in force with no report; both its questions are answered +(`eureka-substrate:ruling:campaign-repo-set-home`, `:campaign-repo-removal`). + +## The model page + +Every persistent kind Thing 2.0 has. Ids follow rename table T: schema +`gamecult.thing..v`, mesh key `thing::`. No row keeps a +compatible eve id (`operator-compat-rebuild`). + +| Kind | What names it | What happens to it over time | Who decides (one writer) | +| --- | --- | --- | --- | +| Thing Script document (a published surface) | schema `gamecult.thing.surface.v1`; key `thing:surface:.