From 15b73d4acf85eae6b42a7a445dc73d79be5f0936 Mon Sep 17 00:00:00 2001 From: James Ross Date: Sun, 3 May 2026 17:22:55 -0700 Subject: [PATCH 01/21] docs: sequence echo contract hosting backlog --- ...tract-aware-intent-observation-envelope.md | 61 ++++++++++++++++ .../PLATFORM_echo-contract-hosting-roadmap.md | 50 +++++++++++++ ...tic-contract-registry-and-host-boundary.md | 56 ++++++++++++++ ...sley-compiled-contract-hosting-doctrine.md | 73 +++++++++++++++++++ ...continuum-contract-artifact-interchange.md | 55 ++++++++++++++ ...EL_contract-aware-receipts-and-readings.md | 52 +++++++++++++ ...EL_contract-strands-and-counterfactuals.md | 50 +++++++++++++ ...contract-artifact-retention-in-echo-cas.md | 52 +++++++++++++ ...graft-live-frontier-structural-readings.md | 48 ++++++++++++ .../PLATFORM_jedit-text-contract-mvp.md | 58 +++++++++++++++ ...TFORM_wesley-to-echo-toy-contract-proof.md | 54 ++++++++++++++ 11 files changed, 609 insertions(+) create mode 100644 docs/method/backlog/asap/PLATFORM_contract-aware-intent-observation-envelope.md create mode 100644 docs/method/backlog/asap/PLATFORM_echo-contract-hosting-roadmap.md create mode 100644 docs/method/backlog/asap/PLATFORM_static-contract-registry-and-host-boundary.md create mode 100644 docs/method/backlog/asap/PLATFORM_wesley-compiled-contract-hosting-doctrine.md create mode 100644 docs/method/backlog/cool-ideas/PLATFORM_continuum-contract-artifact-interchange.md create mode 100644 docs/method/backlog/up-next/KERNEL_contract-aware-receipts-and-readings.md create mode 100644 docs/method/backlog/up-next/KERNEL_contract-strands-and-counterfactuals.md create mode 100644 docs/method/backlog/up-next/PLATFORM_contract-artifact-retention-in-echo-cas.md create mode 100644 docs/method/backlog/up-next/PLATFORM_graft-live-frontier-structural-readings.md create mode 100644 docs/method/backlog/up-next/PLATFORM_jedit-text-contract-mvp.md create mode 100644 docs/method/backlog/up-next/PLATFORM_wesley-to-echo-toy-contract-proof.md diff --git a/docs/method/backlog/asap/PLATFORM_contract-aware-intent-observation-envelope.md b/docs/method/backlog/asap/PLATFORM_contract-aware-intent-observation-envelope.md new file mode 100644 index 00000000..c8782505 --- /dev/null +++ b/docs/method/backlog/asap/PLATFORM_contract-aware-intent-observation-envelope.md @@ -0,0 +1,61 @@ + + + +# Contract-Aware Intent And Observation Envelope + +Status: active planned design and RED candidate. + +Depends on: + +- [Wesley compiled contract hosting doctrine](./PLATFORM_wesley-compiled-contract-hosting-doctrine.md) +- [Reading envelope family boundary](../up-next/PLATFORM_reading-envelope-family-boundary.md) +- [Observer plans and reading artifacts](./PLATFORM_observer-plan-reading-artifacts.md) + +## Why now + +Echo already exposes generic WASM calls such as `dispatch_intent(...)` and +`observe(...)`. To host Wesley-compiled contracts, those calls need envelopes +that name contract family, schema identity, intent or observer kind, basis, +payload, and posture without hard-coding application semantics. + +## What it should look like + +Add focused RED tests for generic contract envelopes. + +Candidate intent envelope fields: + +- contract family +- schema hash +- intent kind +- basis or frontier +- payload bytes or payload ref +- caller context +- rights posture +- budget posture + +Candidate observation envelope fields: + +- contract family +- schema hash +- observer kind +- basis or frontier +- aperture payload +- rights posture +- budget posture + +## Acceptance criteria + +- Unknown contract family is rejected deterministically. +- Unsupported schema hash is rejected deterministically. +- Malformed payload is rejected before contract execution. +- Valid fake envelope reaches a registered fake handler. +- Responses preserve stable contract and schema identity. +- No text, editor, Graft, or `jedit` noun enters the Echo core ABI. + +## Non-goals + +- Do not build the registry beyond the minimum fake needed for RED tests. +- Do not implement Wesley generation. +- Do not add dynamic loading. +- Do not add application payload types. +- Do not change `jedit`. diff --git a/docs/method/backlog/asap/PLATFORM_echo-contract-hosting-roadmap.md b/docs/method/backlog/asap/PLATFORM_echo-contract-hosting-roadmap.md new file mode 100644 index 00000000..577020be --- /dev/null +++ b/docs/method/backlog/asap/PLATFORM_echo-contract-hosting-roadmap.md @@ -0,0 +1,50 @@ + + + +# Echo Contract Hosting Roadmap + +Status: active sequencing card. + +Echo should become a generic host for Wesley-compiled contract families. It +must not grow application-specific APIs for text editing, code intelligence, +debugging, or any other consumer domain. + +## Doctrine + +Echo is the deterministic witnessed causal substrate. + +Wesley authors and compiles contract families from GraphQL into generated Rust, +ABI codecs, schema identity, and contract dispatch/read surfaces. + +Applications such as `jedit` own their domain contracts and product behavior. +Echo hosts those contracts through generic intent and observation envelopes. + +## Sequence + +1. [Wesley compiled contract hosting doctrine](./PLATFORM_wesley-compiled-contract-hosting-doctrine.md) +2. [Contract-aware intent and observation envelope](./PLATFORM_contract-aware-intent-observation-envelope.md) +3. [Static contract registry and host boundary](./PLATFORM_static-contract-registry-and-host-boundary.md) +4. [Wesley to Echo toy contract proof](../up-next/PLATFORM_wesley-to-echo-toy-contract-proof.md) +5. [Contract-aware receipts and readings](../up-next/KERNEL_contract-aware-receipts-and-readings.md) +6. [Contract artifact retention in echo-cas](../up-next/PLATFORM_contract-artifact-retention-in-echo-cas.md) +7. [jedit text contract MVP](../up-next/PLATFORM_jedit-text-contract-mvp.md) +8. [Graft live frontier structural readings](../up-next/PLATFORM_graft-live-frontier-structural-readings.md) +9. [Contract strands and counterfactuals](../up-next/KERNEL_contract-strands-and-counterfactuals.md) +10. [Continuum contract artifact interchange](../cool-ideas/PLATFORM_continuum-contract-artifact-interchange.md) + +## Non-goals + +- Do not add `ReplaceRange`, `BufferWorldline`, or text-editing types to Echo + core unless they are generated application contract payloads. +- Do not add a special `jedit` ABI. +- Do not let Graft mutate Echo state directly. +- Do not build dynamic plugin loading before static contract hosting works. +- Do not start IPA, proof systems, or network Continuum protocol work in this + cluster. + +## Done looks like + +- Each item in the sequence has a narrow card with dependencies, acceptance + criteria, and non-goals. +- Future agents can pick the next card without re-arguing whether Echo owns + application-specific APIs. diff --git a/docs/method/backlog/asap/PLATFORM_static-contract-registry-and-host-boundary.md b/docs/method/backlog/asap/PLATFORM_static-contract-registry-and-host-boundary.md new file mode 100644 index 00000000..513b1c41 --- /dev/null +++ b/docs/method/backlog/asap/PLATFORM_static-contract-registry-and-host-boundary.md @@ -0,0 +1,56 @@ + + + +# Static Contract Registry And Host Boundary + +Status: active planned implementation. + +Depends on: + +- [Contract-aware intent and observation envelope](./PLATFORM_contract-aware-intent-observation-envelope.md) + +## Why now + +Echo needs a boring runtime boundary where generated contract families can be +registered and resolved. The first implementation should be static and +in-process. Dynamic plugin loading, network distribution, and external contract +installation are later problems. + +## What it should look like + +Introduce a minimal registry and handler boundary for generated contracts. + +Candidate responsibilities: + +- register a contract descriptor and handler +- resolve by contract family and schema hash +- route intent kinds to generated dispatch logic +- route observer kinds to generated read logic +- report unsupported contract, schema, intent, or observer deterministically + +Candidate descriptor fields: + +- family id +- schema hash +- registry version +- codec id +- intent kind catalog +- observer kind catalog +- Wesley generator version or generated bundle identity + +## Acceptance criteria + +- A statically registered fake contract dispatches through the generic + envelope path. +- Unknown intent kind fails closed. +- Unknown observer kind fails closed. +- Registry resolution is deterministic. +- Contract handler errors return typed admission or observation posture. +- No dynamic loader or consumer-specific code is introduced. + +## Non-goals + +- Do not implement WASM dynamic module loading. +- Do not fetch contracts over the network. +- Do not add jedit-specific registration. +- Do not make the handler trait a broad runtime facade. diff --git a/docs/method/backlog/asap/PLATFORM_wesley-compiled-contract-hosting-doctrine.md b/docs/method/backlog/asap/PLATFORM_wesley-compiled-contract-hosting-doctrine.md new file mode 100644 index 00000000..dd7a7e41 --- /dev/null +++ b/docs/method/backlog/asap/PLATFORM_wesley-compiled-contract-hosting-doctrine.md @@ -0,0 +1,73 @@ + + + +# Wesley Compiled Contract Hosting Doctrine + +Status: active planned design. + +Depends on: + +- [Echo Continuum Runtime And CAS Readings](../../../design/continuum-runtime-and-cas-readings.md) +- [0011 - Optic and observer runtime doctrine](../../../design/0011-optic-observer-runtime-doctrine/design.md) + +## Why now + +Echo is moving toward observer-relative readings, witnessed suffix admission, +and Continuum-compatible artifacts. The next architectural risk is accidentally +turning Echo into an application runtime with special APIs for the first serious +consumer. + +The corrected model is: + +```text +GraphQL contract -> Wesley generated Rust -> Echo contract host +``` + +Echo must host generated contract families generically. Domain behavior belongs +to the authored contract and consuming application. + +## What it should look like + +Write a design packet that defines Echo as a Wesley-compiled contract host. + +The packet should name at least: + +- `ContractFamilyId` +- `ContractSchemaHash` +- `ContractVersion` +- `IntentEnvelope` +- `IntentKind` +- `IntentPayload` +- `IntentBasis` +- `IntentAdmission` +- `ContractReceipt` +- `ContractWitnessRef` +- `ObservationEnvelope` +- `ContractReading` +- `ContractRuntime` +- `ContractRegistry` + +It should also map those nouns to the existing optic loop: + +```text +slice -> lower -> witness -> retain +``` + +## Done looks like + +- A design doc explains that contracts author domain optics while Echo hosts + the generic optic lifecycle. +- The doc explicitly says Echo must not add text-editor APIs, Graft APIs, or + consumer-specific ABI methods. +- The doc identifies the first implementation cards for contract-aware + envelopes and static contract registration. +- The doc distinguishes built-in substrate/debug observers from + contract-defined application observers. + +## Non-goals + +- Do not change production code. +- Do not update Wesley in this card. +- Do not define the `jedit` text contract here. +- Do not design dynamic plugin loading. +- Do not implement Continuum transport. diff --git a/docs/method/backlog/cool-ideas/PLATFORM_continuum-contract-artifact-interchange.md b/docs/method/backlog/cool-ideas/PLATFORM_continuum-contract-artifact-interchange.md new file mode 100644 index 00000000..6e9b85c7 --- /dev/null +++ b/docs/method/backlog/cool-ideas/PLATFORM_continuum-contract-artifact-interchange.md @@ -0,0 +1,55 @@ + + + +# Continuum Contract Artifact Interchange + +Status: cool idea, future protocol lane. + +Depends on: + +- [Contract strands and counterfactuals](../up-next/KERNEL_contract-strands-and-counterfactuals.md) +- [Witnessed suffix admission shells](../asap/PLATFORM_witnessed-suffix-admission-shells.md) +- external Continuum protocol publication work + +## Why later + +Echo should prove local Wesley-compiled contract hosting before protocolizing +contract artifacts across runtimes. + +Once local hosting, receipts, readings, CAS retention, and contract strands are +real, Continuum can define how sibling runtimes exchange contract-shaped +causal artifacts. + +## What it should look like + +Continuum artifacts should be able to name: + +- contract family +- schema hash +- intent or observer kind +- basis and frontier +- payload hash +- receipt refs +- witness refs +- reading refs +- admission posture +- retained artifact hashes + +Sibling runtimes should exchange protocol-shaped causal artifacts, not runtime +internals. + +## Acceptance criteria + +- One Echo contract receipt exports as a Continuum-shaped artifact. +- A second runtime or verifier can inspect the artifact family identity without + understanding Echo internals. +- Import uses witnessed suffix admission law instead of state snapshot sync. +- Missing contract family or schema support yields obstruction, not silent + downgrade. + +## Non-goals + +- Do not start before local contract hosting is real. +- Do not require proof-carrying execution. +- Do not design all network transport. +- Do not collapse contract artifacts into generic state snapshots. diff --git a/docs/method/backlog/up-next/KERNEL_contract-aware-receipts-and-readings.md b/docs/method/backlog/up-next/KERNEL_contract-aware-receipts-and-readings.md new file mode 100644 index 00000000..3077fb0c --- /dev/null +++ b/docs/method/backlog/up-next/KERNEL_contract-aware-receipts-and-readings.md @@ -0,0 +1,52 @@ + + + +# Contract-Aware Receipts And Readings + +Status: planned kernel hardening. + +Depends on: + +- [Wesley to Echo toy contract proof](./PLATFORM_wesley-to-echo-toy-contract-proof.md) +- [Reading envelope family boundary](./PLATFORM_reading-envelope-family-boundary.md) + +## Why now + +A generated contract path is not enough unless receipts and readings are honest +about the contract family, schema, basis, payload, and witness material they +commit to. + +Echo should not return global-sounding state hashes for contract-local reads. +Contract observations should emit reading identities and envelopes whose scope +is explicit. + +## What it should look like + +Extend receipt and reading identity inputs so contract execution can name: + +- contract family +- schema hash +- intent or observer kind +- basis or frontier +- payload hash +- generated handler or law version +- witness refs +- admission or residual posture + +## Acceptance criteria + +- The same intent over the same basis produces the same receipt identity. +- Changing schema hash changes receipt identity. +- Changing payload changes receipt identity. +- Contract observation reading identity includes contract family, schema, + observer kind, basis, and aperture. +- Unsupported or stale basis returns typed obstruction rather than a fake + reading. +- Existing built-in observation tests remain green. + +## Non-goals + +- Do not implement cryptographic proofs. +- Do not introduce IPA or commitment math. +- Do not require full Continuum export/import. +- Do not add consumer-specific receipt fields to Echo core. diff --git a/docs/method/backlog/up-next/KERNEL_contract-strands-and-counterfactuals.md b/docs/method/backlog/up-next/KERNEL_contract-strands-and-counterfactuals.md new file mode 100644 index 00000000..821724ad --- /dev/null +++ b/docs/method/backlog/up-next/KERNEL_contract-strands-and-counterfactuals.md @@ -0,0 +1,50 @@ + + + +# Contract Strands And Counterfactuals + +Status: planned kernel/runtime implementation. + +Depends on: + +- [Graft live frontier structural readings](./PLATFORM_graft-live-frontier-structural-readings.md) +- [Live holographic strands](../asap/KERNEL_live-holographic-strands.md) +- [0010 - Live-basis settlement correction plan](../../../design/0010-live-basis-settlement-plan/design.md) + +## Why now + +After Echo can host contract intents and readings, speculative work should use +generic strands over contract families rather than application-specific branch +APIs. + +`jedit` can use this for refactor previews and agent containment. Graft can use +it for structural impact prediction. Echo should only provide the substrate: +strand basis, local divergence, revalidation, admission, conflict, obstruction, +plurality, and retained readings. + +## What it should look like + +Add generic contract-aware strand operations: + +- create strand over contract basis +- dispatch contract intent into strand +- observe contract reading from strand +- compare strand with parent basis +- admit, preserve plurality, conflict, obstruct, or discard + +## Acceptance criteria + +- A fake contract intent can be applied inside a strand without changing the + parent frontier. +- Observing the strand returns a reading envelope that names strand basis and + contract identity. +- Parent movement outside owned divergence revalidates cleanly. +- Parent overlap returns explicit conflict or obstruction. +- `jedit` and Graft examples remain consumer-level, not Echo core APIs. + +## Non-goals + +- Do not implement final multi-party braid collapse. +- Do not implement semantic refactor prediction here. +- Do not add text or Graft domain types to Echo core. +- Do not require durable strand persistence in the first slice. diff --git a/docs/method/backlog/up-next/PLATFORM_contract-artifact-retention-in-echo-cas.md b/docs/method/backlog/up-next/PLATFORM_contract-artifact-retention-in-echo-cas.md new file mode 100644 index 00000000..848ae515 --- /dev/null +++ b/docs/method/backlog/up-next/PLATFORM_contract-artifact-retention-in-echo-cas.md @@ -0,0 +1,52 @@ + + + +# Contract Artifact Retention In echo-cas + +Status: planned platform implementation. + +Depends on: + +- [Contract-aware receipts and readings](./KERNEL_contract-aware-receipts-and-readings.md) +- [Echo Continuum Runtime And CAS Readings](../../../design/continuum-runtime-and-cas-readings.md) +- [echo-cas Browser](./PLATFORM_echo-cas-browser.md) + +## Why now + +Echo's doctrine says `echo-cas` stores retained witnesses and cached readings, +but the contract-hosting path needs concrete retention rules for generated +contract artifacts. + +CAS hashes name bytes. Semantic lookup keys name the question those bytes +answer. + +## What it should look like + +Define and implement minimal retention for: + +- intent payload blobs +- contract receipts +- witness refs +- reading payloads +- reading envelopes +- observer artifacts + +Semantic lookup should include contract identity, schema hash, basis, observer +or intent kind, aperture or payload identity, and law/projection version where +applicable. + +## Acceptance criteria + +- Stored contract receipt can be loaded by content hash. +- Stored contract reading can be loaded by content hash. +- Semantic lookup includes contract and schema identity. +- Cached reading is not reused for a newer live frontier unless a proof of + containment or equivalent witness relation exists. +- Garbage collection remains storage policy and does not mutate truth. + +## Non-goals + +- Do not build a full distributed CAS protocol. +- Do not implement proof-carrying retention. +- Do not add app-specific indexes. +- Do not make CAS content hashes stand in for reading identity. diff --git a/docs/method/backlog/up-next/PLATFORM_graft-live-frontier-structural-readings.md b/docs/method/backlog/up-next/PLATFORM_graft-live-frontier-structural-readings.md new file mode 100644 index 00000000..9e67dc9d --- /dev/null +++ b/docs/method/backlog/up-next/PLATFORM_graft-live-frontier-structural-readings.md @@ -0,0 +1,48 @@ + + + +# Graft Live Frontier Structural Readings + +Status: planned consumer integration. + +Depends on: + +- [jedit text contract MVP](./PLATFORM_jedit-text-contract-mvp.md) +- external Graft structural projection work + +## Why now + +Once `jedit` edits through Echo-hosted contract intents, Graft should observe +the live contract frontier instead of only saved files or ad hoc editor state. + +Graft must consume readings and frontiers. It must not mutate Echo state +directly. + +## What it should look like + +Use Echo/jedit contract readings as structural projection bases for Graft. + +Initial product readings: + +- dead symbols for live frontier +- symbol history for current edit group +- impacted tests for current changes +- projection safety status +- stale projection warnings + +## Acceptance criteria + +- Graft projection names the Echo/jedit contract frontier it observed. +- Projection output distinguishes current, stale, partial, unsafe, and + unavailable facts. +- `jedit` displays at least one Graft structural reading over a live Echo + frontier. +- Proposed edits flow back through `jedit` contract intents and Echo admission. +- Graft never writes directly to Echo substrate state. + +## Non-goals + +- Do not implement rename automation. +- Do not build structural counterfactuals yet. +- Do not bypass Echo admission for edits. +- Do not require Continuum interop. diff --git a/docs/method/backlog/up-next/PLATFORM_jedit-text-contract-mvp.md b/docs/method/backlog/up-next/PLATFORM_jedit-text-contract-mvp.md new file mode 100644 index 00000000..6a398d92 --- /dev/null +++ b/docs/method/backlog/up-next/PLATFORM_jedit-text-contract-mvp.md @@ -0,0 +1,58 @@ + + + +# jedit Text Contract MVP + +Status: planned consumer proof. + +Depends on: + +- [Contract artifact retention in echo-cas](./PLATFORM_contract-artifact-retention-in-echo-cas.md) +- external `jedit` hot text runtime port +- external Wesley contract authoring support + +## Why now + +`jedit` is the first serious consumer for Echo as a Wesley-compiled contract +host. The text-editing model must remain application-specific. Echo should host +the generated contract through generic dispatch and observation surfaces. + +## What it should look like + +Define a `jedit` GraphQL contract for the minimum hot editing loop. + +Candidate intents: + +- create buffer +- replace range +- open edit group +- include tick in edit group +- close edit group +- save checkpoint + +Candidate observations: + +- buffer reading +- dirty delta +- edit group history +- checkpoint status + +Wesley compiles the contract. Echo registers and hosts it. `jedit` adapts its +existing hot text runtime port to submit generated contract intents. + +## Acceptance criteria + +- `jedit` can create a buffer through a contract intent. +- `jedit` can submit a replace-range intent through Echo. +- Echo emits a contract-aware receipt for the edit. +- `jedit` can observe a buffer reading through Echo. +- Save checkpoint produces a retained contract artifact. +- Echo core contains no text-specific APIs outside generated contract payloads. + +## Non-goals + +- Do not add text-editing types to Echo core. +- Do not add a special `jedit` ABI. +- Do not wire Graft automation in this card. +- Do not require multi-buffer collaboration. +- Do not implement strands or counterfactual refactors here. diff --git a/docs/method/backlog/up-next/PLATFORM_wesley-to-echo-toy-contract-proof.md b/docs/method/backlog/up-next/PLATFORM_wesley-to-echo-toy-contract-proof.md new file mode 100644 index 00000000..24d184d4 --- /dev/null +++ b/docs/method/backlog/up-next/PLATFORM_wesley-to-echo-toy-contract-proof.md @@ -0,0 +1,54 @@ + + + +# Wesley To Echo Toy Contract Proof + +Status: planned cross-repo proof. + +Depends on: + +- [Static contract registry and host boundary](../asap/PLATFORM_static-contract-registry-and-host-boundary.md) +- [echo-wesley-gen v2 Update](./PLATFORM_echo-wesley-gen-v2.md) +- [WESLEY Protocol Consumer Cutover](../asap/PLATFORM_WESLEY_protocol-consumer-cutover.md) + +## Why now + +Before `jedit` becomes the first serious application consumer, Echo and Wesley +need one tiny contract that proves the full authoring and hosting path. + +This should be deliberately boring. The value is the path: + +```text +GraphQL -> Wesley IR -> generated Rust -> Echo registry -> dispatch -> observe +``` + +## What it should look like + +Use a tiny toy contract, such as a counter, with one intent and one observer. + +Example domain: + +- `Increment` +- `CounterValue` + +The exact schema is not important. The proof must exercise generated identity, +codecs, dispatch, receipt creation, and observation. + +## Acceptance criteria + +- Wesley compiles the toy GraphQL contract to Echo-consumable Rust artifacts. +- Echo statically registers the generated contract. +- `dispatch_intent(...)` admits one valid toy intent. +- `observe(...)` returns one contract-defined reading payload. +- The receipt names contract family, schema hash, intent kind, basis, and + payload hash. +- The reading envelope names contract family, schema hash, observer kind, and + basis. +- Golden ABI vectors are stable. + +## Non-goals + +- Do not use a text editing contract. +- Do not add dynamic contract loading. +- Do not require browser packaging. +- Do not add Continuum transport. From 4915d402ea82fd059d0c3b20054c9a5e7971b84a Mon Sep 17 00:00:00 2001 From: James Ross Date: Sun, 3 May 2026 17:26:35 -0700 Subject: [PATCH 02/21] docs: define echo contract hosting doctrine --- .../design.md | 444 ++++++++++++++++++ .../PLATFORM_echo-contract-hosting-roadmap.md | 2 + ...sley-compiled-contract-hosting-doctrine.md | 4 + 3 files changed, 450 insertions(+) create mode 100644 docs/design/0013-wesley-compiled-contract-hosting-doctrine/design.md diff --git a/docs/design/0013-wesley-compiled-contract-hosting-doctrine/design.md b/docs/design/0013-wesley-compiled-contract-hosting-doctrine/design.md new file mode 100644 index 00000000..b5cf2932 --- /dev/null +++ b/docs/design/0013-wesley-compiled-contract-hosting-doctrine/design.md @@ -0,0 +1,444 @@ + + + +# 0013 - Wesley Compiled Contract Hosting Doctrine + +_Define Echo as a generic host for Wesley-compiled contract families, not as an +application-specific runtime API._ + +Legend: [PLATFORM](../../method/legends/PLATFORM.md) + +Depends on: + +- [0006 - Echo Continuum alignment](../0006-echo-continuum-alignment/design.md) +- [0011 - Optic and observer runtime doctrine](../0011-optic-observer-runtime-doctrine/design.md) +- [Echo Continuum Runtime And CAS Readings](../continuum-runtime-and-cas-readings.md) +- [Echo Contract Hosting Roadmap](../../method/backlog/asap/PLATFORM_echo-contract-hosting-roadmap.md) +- [Wesley Compiled Contract Hosting Doctrine](../../method/backlog/asap/PLATFORM_wesley-compiled-contract-hosting-doctrine.md) + +## Why this cycle exists + +Echo is moving toward observer-relative readings, witnessed suffix admission, +contract-generated artifacts, and Continuum-compatible causal exchange. The +next architectural risk is letting the first serious consumer drag +application-specific APIs into Echo core. + +That would be the wrong cut. + +Echo should not grow privileged APIs for text editing, code intelligence, +debugging, games, simulations, or any other consuming domain. Echo should host +Wesley-compiled contract families through generic intent and observation +surfaces. + +The corrected model is: + +```text +GraphQL contract -> Wesley generated Rust -> Echo contract host +``` + +The contract authors domain meaning. Wesley compiles that meaning into Rust, +ABI codecs, schema identity, and generated dispatch or observation surfaces. +Echo hosts the resulting family as a deterministic witnessed causal substrate. + +## Human users / jobs / hills + +### Primary human users + +- Echo maintainers defining the runtime substrate boundary. +- Wesley maintainers compiling authored contracts into Echo-consumable Rust. +- Application authors using Echo through generated contract clients. +- Reviewers preventing consumer-specific behavior from entering Echo core. + +### Human jobs + +1. Decide whether a proposed API belongs in Echo substrate, Wesley-generated + contract output, or an application adapter. +2. Sequence the next implementation cards without re-arguing whether Echo owns + text editing, Graft projections, or other app-specific domains. +3. Review future changes for contract identity, schema identity, basis, + receipt, and reading honesty. + +### Human hill + +A human can classify a proposed Echo change as substrate, generated contract, +or application behavior without relying on chat context or folklore. + +## Agent users / jobs / hills + +### Primary agent users + +- Agents implementing the contract-aware intent envelope. +- Agents implementing the static contract registry. +- Agents wiring Wesley-generated toy contracts into Echo. +- Agents reviewing future jedit or Graft integration work. + +### Agent jobs + +1. Read one design packet and determine whether a change violates the + substrate/application boundary. +2. Generate RED tests for contract envelopes and registry behavior without + inventing application-specific DTOs. +3. Keep optic doctrine attached to generic contract hosting rather than + hand-written domain APIs. + +### Agent hill + +An agent can inspect a contract-hosting patch and programmatically determine +whether Echo core gained consumer-specific nouns that should instead be +Wesley-generated or application-owned. + +## Doctrine + +Echo is a deterministic witnessed causal substrate. + +Wesley is the contract compiler. + +GraphQL is the authored contract language for application/runtime families. + +Applications own domain behavior and product semantics. + +Echo owns: + +- deterministic scheduling +- basis and frontier handling +- admission outcome algebra +- witnessed transition receipts +- observer-relative reading envelopes +- witness and retained artifact references +- `echo-cas` retention policy +- strand, braid, import, and suffix admission substrate +- generic ABI entrypoints such as `dispatch_intent(...)` and `observe(...)` + +Contracts own: + +- domain nouns +- domain payload types +- intent kinds +- observer or read kinds +- domain validation +- domain transition law +- domain emission law +- domain-specific reading payloads + +Applications own: + +- product workflows +- UI and interaction policy +- adapters around generated clients +- application-specific persistence and save/open behavior where applicable +- decisions about which contract operations to expose to users + +## Bright-Line Rule + +Echo core must not add consumer-specific APIs. + +Examples of APIs that do not belong in Echo core: + +- `ReplaceRange` +- `BufferWorldline` +- `SaveCheckpoint` +- `RenameSymbol` +- `DeadSymbols` +- `GraftProjection` +- `JeditBuffer` + +Those names may appear in generated contract payloads, generated clients, +application adapters, tests for generated families, or documentation about +consumers. They should not become substrate-owned Echo runtime nouns. + +The Echo-owned shape is generic: + +```text +dispatch contract intent +observe contract reading +retain contract artifact +admit contract suffix +settle contract strand +``` + +## Contract Hosting Stack + +The intended stack is: + +```text +Application GraphQL contract + -> Wesley IR + -> Wesley generated Rust DTOs, codecs, schema identity, and handlers + -> Echo static contract registry + -> Echo contract-aware intent and observation envelopes + -> Echo deterministic admission, receipt, reading, and retention substrate + -> Application-generated client or adapter +``` + +The first implementation should use static in-process registration. Dynamic +loading, network contract distribution, and runtime installation are future +problems. + +## Required Nouns + +Future design and implementation cards should converge on these noun families. +Exact Rust names may differ, but the boundaries should stay visible. + +### Contract Identity + +- `ContractFamilyId` +- `ContractSchemaHash` +- `ContractVersion` +- `ContractCodecId` +- `GeneratedBundleIdentity` + +These identify what generated family Echo is hosting and which schema/law the +payloads claim. + +### Intent Dispatch + +- `ContractIntentEnvelope` +- `IntentKind` +- `IntentPayload` +- `IntentBasis` +- `IntentAdmission` +- `ContractDispatchContext` +- `ContractDispatchResult` + +These define the generic write-side path. Echo validates envelope shape, +resolves the registered family, calls generated contract law, and wraps the +outcome in Echo admission/receipt vocabulary. + +### Observation + +- `ContractObservationEnvelope` +- `ObserverKind` +- `ObservationBasis` +- `ObservationAperture` +- `ContractObservationContext` +- `ContractObservationResult` +- `ContractReading` + +These define the generic read-side path. Echo resolves the generated observer +or read family and emits an Echo `ReadingEnvelope` around the +contract-specific payload. + +### Witness And Retention + +- `ContractReceipt` +- `ContractWitnessRef` +- `ContractReadingRef` +- `RetainedContractArtifact` +- `ContractArtifactCoordinate` + +These define how contract execution and observation become durable, +inspectable, cacheable, and future-exportable without confusing cached +readings with substrate truth. + +### Registry + +- `ContractRegistry` +- `ContractDescriptor` +- `ContractHandler` + +These define how generated contract families become available to Echo. The +first cut should be small, static, and deterministic. + +## Optic Mapping + +Wesley contracts and Echo optics are not competing models. + +Contracts author domain optics. Echo hosts the generic optic lifecycle. + +The shared runtime pattern remains: + +```text +slice -> lower -> witness -> retain +``` + +For a contract intent: + +```text +slice: + resolve contract identity, schema identity, basis, and needed causal evidence + +lower: + run generated contract transition law under Echo admission constraints + +witness: + produce admission outcome, receipt identity, payload hash, and witness refs + +retain: + store receipt, payload, witness refs, and optional reading hints in echo-cas +``` + +For a contract observation: + +```text +slice: + resolve contract identity, schema identity, observer kind, basis, aperture, + rights, and budget + +lower: + run generated observer or emission law + +witness: + produce reading identity, witness refs, residual posture, and payload hash + +retain: + optionally cache the reading artifact by honest contract/optic coordinate +``` + +For a contract strand or counterfactual: + +```text +slice: + contract basis, parent movement, and local divergence + +lower: + revalidate or compare claims under Echo strand and admission law + +witness: + report admitted, staged, plural, conflict, or obstruction evidence + +retain: + keep the strand shell, settlement artifact, and reading artifacts as needed +``` + +## Built-In Observers Versus Contract Observers + +Echo may keep built-in substrate/debug observers for runtime inspection. + +Examples: + +- scheduler status +- commit boundary head +- commit boundary snapshot +- recorded truth channels +- receipt or provenance inspection +- neighborhood and settlement publication + +Those observers are Echo-owned because they inspect Echo substrate. + +Application observers should come from authored contracts and Wesley-generated +families. Echo should host them, not hand-author them in core. + +## ABI Direction + +Echo's public ABI should keep the generic shape: + +```text +dispatch_intent(bytes) -> bytes +observe(bytes) -> bytes +scheduler_status() -> bytes +``` + +The bytes should increasingly be contract-aware envelopes, not ad hoc payloads. + +The envelope should name: + +- contract family +- schema hash +- intent or observer kind +- basis or frontier +- payload or aperture +- rights posture +- budget posture + +The response should name: + +- admission or observation posture +- receipt or reading identity +- witness refs +- retained artifact refs where available +- contract and schema identity + +## Error And Outcome Posture + +Echo should keep failure categories separate: + +- malformed ABI payload +- unknown contract family +- unsupported schema hash +- unknown intent or observer kind +- malformed contract payload +- unresolved basis +- budget obstruction +- rights obstruction +- contract-level conflict +- contract-level plurality +- staged local admission +- admitted transition + +These should not collapse into string status fields or generic errors. + +## Human playback + +1. A human reviews a proposed `ReplaceRange` API in Echo core. +2. This design identifies it as application contract behavior, not substrate. +3. The human redirects it to a `jedit` GraphQL contract compiled by Wesley. +4. Echo only receives the generated contract family through generic envelopes. + +## Agent playback + +1. An agent reads this packet and the contract-hosting backlog cards. +2. The agent creates RED tests for contract-aware envelopes. +3. The tests mention contract family, schema hash, intent kind, basis, and + payload. +4. The tests do not introduce text, Graft, or `jedit` domain nouns into Echo + core. + +## Implementation outline + +1. Implement contract-aware intent and observation envelope RED tests. +2. Add a minimal static contract registry with fake handlers. +3. Prove one Wesley-to-Echo toy contract path. +4. Extend receipts and readings to carry contract/schema identity. +5. Retain contract artifacts in `echo-cas` with honest semantic coordinates. +6. Let `jedit` define the first serious text editing contract outside Echo + core. +7. Let Graft consume Echo/jedit frontiers and readings, not Echo internals. +8. Add generic contract strands and counterfactuals after the basic contract + path is real. + +## Tests to write first + +- RED: unknown contract family is rejected deterministically. +- RED: unsupported schema hash is rejected deterministically. +- RED: malformed contract payload fails before generated handler execution. +- RED: valid fake contract intent reaches a registered fake handler. +- RED: valid fake contract observation returns a reading envelope that names + contract family, schema hash, observer kind, and basis. +- RED: no consumer-specific domain types are required to exercise the contract + envelope path. + +## Risks / unknowns + +- **Wesley IR shape is still moving.** Keep the first Echo registry static and + fake-handler-friendly so it can be tested before full generated bundles are + stable. +- **Contract handler shape could become a broad runtime facade.** Keep the + boundary limited to dispatch and observe. Do not let it absorb scheduler, + CAS, transport, or app runtime behavior. +- **ABI compatibility pressure could preserve old payload forms too long.** + Treat this as a major boundary clarification. Compatibility shims must not + become alternate truth paths. +- **Applications may want convenient domain clients.** Generate those clients + or keep them in application adapters. Do not move them into Echo core. + +## Postures + +- **Accessibility:** This packet is architecture and backlog guidance only. + It should remain understandable as a plain Markdown read with explicit + boundary examples. +- **Localization:** Contract and runtime noun choices should remain stable and + technical. Domain-specific user-facing terms belong to applications. +- **Agent inspectability:** The packet intentionally names forbidden + consumer-specific Echo core nouns and the allowed generic substrate nouns so + agents can check future patches mechanically. + +## Non-goals + +- Do not change production code in this design cycle. +- Do not update Wesley implementation in this design cycle. +- Do not define the `jedit` text contract here. +- Do not define Graft structural projection contracts here. +- Do not implement dynamic contract loading. +- Do not implement Continuum transport. +- Do not introduce IPA or proof-carrying execution. +- Do not add consumer-specific APIs to Echo core. diff --git a/docs/method/backlog/asap/PLATFORM_echo-contract-hosting-roadmap.md b/docs/method/backlog/asap/PLATFORM_echo-contract-hosting-roadmap.md index 577020be..6031d9a7 100644 --- a/docs/method/backlog/asap/PLATFORM_echo-contract-hosting-roadmap.md +++ b/docs/method/backlog/asap/PLATFORM_echo-contract-hosting-roadmap.md @@ -22,6 +22,8 @@ Echo hosts those contracts through generic intent and observation envelopes. ## Sequence 1. [Wesley compiled contract hosting doctrine](./PLATFORM_wesley-compiled-contract-hosting-doctrine.md) + - Design packet: + [0013 - Wesley Compiled Contract Hosting Doctrine](../../../design/0013-wesley-compiled-contract-hosting-doctrine/design.md) 2. [Contract-aware intent and observation envelope](./PLATFORM_contract-aware-intent-observation-envelope.md) 3. [Static contract registry and host boundary](./PLATFORM_static-contract-registry-and-host-boundary.md) 4. [Wesley to Echo toy contract proof](../up-next/PLATFORM_wesley-to-echo-toy-contract-proof.md) diff --git a/docs/method/backlog/asap/PLATFORM_wesley-compiled-contract-hosting-doctrine.md b/docs/method/backlog/asap/PLATFORM_wesley-compiled-contract-hosting-doctrine.md index dd7a7e41..b41ec729 100644 --- a/docs/method/backlog/asap/PLATFORM_wesley-compiled-contract-hosting-doctrine.md +++ b/docs/method/backlog/asap/PLATFORM_wesley-compiled-contract-hosting-doctrine.md @@ -10,6 +10,10 @@ Depends on: - [Echo Continuum Runtime And CAS Readings](../../../design/continuum-runtime-and-cas-readings.md) - [0011 - Optic and observer runtime doctrine](../../../design/0011-optic-observer-runtime-doctrine/design.md) +Design packet: + +- [0013 - Wesley Compiled Contract Hosting Doctrine](../../../design/0013-wesley-compiled-contract-hosting-doctrine/design.md) + ## Why now Echo is moving toward observer-relative readings, witnessed suffix admission, From 06e79a7dc28ec0d8c1ab11bc46b454a709dc4442 Mon Sep 17 00:00:00 2001 From: James Ross Date: Sun, 3 May 2026 17:47:22 -0700 Subject: [PATCH 03/21] docs: align contract backlog with existing echo substrate --- .../design.md | 176 +++++++++++------- ...tract-aware-intent-observation-envelope.md | 90 +++++---- .../PLATFORM_echo-contract-hosting-roadmap.md | 14 +- ...tic-contract-registry-and-host-boundary.md | 65 ++++--- ...sley-compiled-contract-hosting-doctrine.md | 30 +-- ...EL_contract-aware-receipts-and-readings.md | 31 ++- ...contract-artifact-retention-in-echo-cas.md | 5 +- .../PLATFORM_jedit-text-contract-mvp.md | 10 +- ...TFORM_wesley-to-echo-toy-contract-proof.md | 26 ++- 9 files changed, 281 insertions(+), 166 deletions(-) diff --git a/docs/design/0013-wesley-compiled-contract-hosting-doctrine/design.md b/docs/design/0013-wesley-compiled-contract-hosting-doctrine/design.md index b5cf2932..ca269f8f 100644 --- a/docs/design/0013-wesley-compiled-contract-hosting-doctrine/design.md +++ b/docs/design/0013-wesley-compiled-contract-hosting-doctrine/design.md @@ -67,8 +67,8 @@ or application behavior without relying on chat context or folklore. ### Primary agent users -- Agents implementing the contract-aware intent envelope. -- Agents implementing the static contract registry. +- Agents inventorying the existing EINT, registry, and observation boundary. +- Agents deciding how generated registries are wired into consumers. - Agents wiring Wesley-generated toy contracts into Echo. - Agents reviewing future jedit or Graft integration work. @@ -149,8 +149,8 @@ consumers. They should not become substrate-owned Echo runtime nouns. The Echo-owned shape is generic: ```text -dispatch contract intent -observe contract reading +dispatch EINT intent bytes +observe runtime reading retain contract artifact admit contract suffix settle contract strand @@ -158,26 +158,58 @@ settle contract strand ## Contract Hosting Stack -The intended stack is: +The intended stack extends existing Echo machinery: ```text Application GraphQL contract -> Wesley IR - -> Wesley generated Rust DTOs, codecs, schema identity, and handlers - -> Echo static contract registry - -> Echo contract-aware intent and observation envelopes + -> Wesley generated Rust DTOs, codecs, schema identity, op catalog, and registry + -> app-level generated client / adapter + -> EINT v1 op_id + vars + -> Echo dispatch_intent(...) + -> Echo observe(...) -> Echo deterministic admission, receipt, reading, and retention substrate - -> Application-generated client or adapter ``` -The first implementation should use static in-process registration. Dynamic -loading, network contract distribution, and runtime installation are future -problems. +The important correction is that Echo already has the base substrate for this +path. The next work should not create a second intent envelope or registry. + +## Existing Repo Truth + +The current codebase already provides these pieces: + +- EINT v1 in `echo-wasm-abi`: + `"EINT" || op_id:u32le || vars_len:u32le || vars`. +- `dispatch_intent(...)` in `warp-wasm` as the write/control ingress. +- `KernelPort::dispatch_intent(...)` as an app-agnostic byte boundary. +- `RegistryInfo` plus `get_registry_info`, `get_codec_id`, + `get_registry_version`, and `get_schema_sha256_hex` exports. +- `echo-registry-api::RegistryProvider` for app-supplied operation catalogs. +- `echo-wesley-gen` output that includes op ids, `OPS`, `op_by_id`, + `GeneratedRegistry`, and `REGISTRY`. +- `observe(...)` returning `ObservationArtifact` with `ReadingEnvelope` + metadata for built-in observations. +- `echo-cas` as a content-addressed blob store where semantic domain + separation lives above CAS hashes. + +The next design question is therefore not "how does Echo accept intents?" or +"how does Echo expose registry metadata?" Both already exist. + +The next design question is where the first consumer should bind generated +Wesley contracts: + +- app-level generated code validates op ids and vars, packs EINT, and calls + Echo; or +- `warp-wasm` / installed kernel links an app-supplied `RegistryProvider` and + rejects unsupported op ids or malformed vars at the boundary; or +- a deliberate hybrid, with app-level validation for ergonomics and + Echo-level validation only for installed-registry handshakes. ## Required Nouns -Future design and implementation cards should converge on these noun families. -Exact Rust names may differ, but the boundaries should stay visible. +Future design and implementation cards should reuse the noun families that +already exist before introducing new ones. Exact Rust names may differ, but +the boundaries should stay visible. ### Contract Identity @@ -192,7 +224,7 @@ payloads claim. ### Intent Dispatch -- `ContractIntentEnvelope` +- EINT v1 - `IntentKind` - `IntentPayload` - `IntentBasis` @@ -200,13 +232,16 @@ payloads claim. - `ContractDispatchContext` - `ContractDispatchResult` -These define the generic write-side path. Echo validates envelope shape, -resolves the registered family, calls generated contract law, and wraps the -outcome in Echo admission/receipt vocabulary. +These define the generic write-side path. Echo already validates EINT shape and +distinguishes privileged control intents from application intents. The open +question is whether app op ids and vars are validated before dispatch by +generated application code or inside Echo by consulting an installed +`RegistryProvider`. ### Observation -- `ContractObservationEnvelope` +- `ObservationRequest` +- `ReadingEnvelope` - `ObserverKind` - `ObservationBasis` - `ObservationAperture` @@ -214,9 +249,9 @@ outcome in Echo admission/receipt vocabulary. - `ContractObservationResult` - `ContractReading` -These define the generic read-side path. Echo resolves the generated observer -or read family and emits an Echo `ReadingEnvelope` around the -contract-specific payload. +These define the generic read-side path. Echo already has `ObservationRequest`, +built-in observer plans, and `ReadingEnvelope`. The open question is how +Wesley-generated `QUERY` or observer operations map to that read boundary. ### Witness And Retention @@ -232,12 +267,13 @@ readings with substrate truth. ### Registry -- `ContractRegistry` -- `ContractDescriptor` -- `ContractHandler` +- `echo-registry-api::RegistryProvider` +- `echo-registry-api::RegistryInfo` +- `echo-registry-api::OpDef` +- generated `REGISTRY` -These define how generated contract families become available to Echo. The -first cut should be small, static, and deterministic. +These define the existing registry family. Future work should reuse it or make +an explicit replacement decision with evidence. ## Optic Mapping @@ -255,10 +291,11 @@ For a contract intent: ```text slice: - resolve contract identity, schema identity, basis, and needed causal evidence + parse EINT op id and vars; optionally validate against generated registry; + resolve basis and needed causal evidence lower: - run generated contract transition law under Echo admission constraints + run app/generated transition law under Echo admission constraints witness: produce admission outcome, receipt identity, payload hash, and witness refs @@ -271,11 +308,11 @@ For a contract observation: ```text slice: - resolve contract identity, schema identity, observer kind, basis, aperture, + resolve ObservationRequest or generated query/read operation, basis, aperture, rights, and budget lower: - run generated observer or emission law + run built-in observer or app/generated observer/emission law witness: produce reading identity, witness refs, residual posture, and payload hash @@ -328,17 +365,18 @@ observe(bytes) -> bytes scheduler_status() -> bytes ``` -The bytes should increasingly be contract-aware envelopes, not ad hoc payloads. +`dispatch_intent(bytes)` already accepts EINT v1. New work should prefer +binding generated app contracts to that existing shape instead of creating a +parallel contract envelope. -The envelope should name: +The installed runtime or app-level generated client should expose enough +handshake metadata to name: -- contract family +- codec id +- registry version - schema hash -- intent or observer kind -- basis or frontier -- payload or aperture -- rights posture -- budget posture +- op id catalog +- observation/read posture The response should name: @@ -346,16 +384,18 @@ The response should name: - receipt or reading identity - witness refs - retained artifact refs where available -- contract and schema identity +- schema and registry identity where that identity is part of the installed + app bundle or retained artifact ## Error And Outcome Posture Echo should keep failure categories separate: - malformed ABI payload -- unknown contract family +- malformed EINT +- reserved control op id misuse - unsupported schema hash -- unknown intent or observer kind +- unknown app op id when a generated registry is installed at the boundary - malformed contract payload - unresolved basis - budget obstruction @@ -372,23 +412,28 @@ These should not collapse into string status fields or generic errors. 1. A human reviews a proposed `ReplaceRange` API in Echo core. 2. This design identifies it as application contract behavior, not substrate. 3. The human redirects it to a `jedit` GraphQL contract compiled by Wesley. -4. Echo only receives the generated contract family through generic envelopes. +4. `jedit` app-level code validates and packs the generated op as EINT. +5. Echo receives canonical EINT bytes through `dispatch_intent(...)`. ## Agent playback 1. An agent reads this packet and the contract-hosting backlog cards. -2. The agent creates RED tests for contract-aware envelopes. -3. The tests mention contract family, schema hash, intent kind, basis, and - payload. +2. The agent inventories existing EINT, registry, and observation surfaces + before writing RED tests. +3. The tests reuse EINT, `RegistryInfo`, and `RegistryProvider` where possible. 4. The tests do not introduce text, Graft, or `jedit` domain nouns into Echo core. ## Implementation outline -1. Implement contract-aware intent and observation envelope RED tests. -2. Add a minimal static contract registry with fake handlers. -3. Prove one Wesley-to-Echo toy contract path. -4. Extend receipts and readings to carry contract/schema identity. +1. Inventory existing EINT, registry, generated registry, and observation + surfaces. +2. Decide whether first-consumer op/vars validation lives in app-level + generated code, Echo's WASM boundary, or both. +3. Prove one Wesley-to-Echo toy contract path using existing EINT and generated + registry output. +4. Extend receipts and readings only where existing intent ids and reading + envelopes cannot honestly identify the app contract artifact. 5. Retain contract artifacts in `echo-cas` with honest semantic coordinates. 6. Let `jedit` define the first serious text editing contract outside Echo core. @@ -398,23 +443,26 @@ These should not collapse into string status fields or generic errors. ## Tests to write first -- RED: unknown contract family is rejected deterministically. -- RED: unsupported schema hash is rejected deterministically. -- RED: malformed contract payload fails before generated handler execution. -- RED: valid fake contract intent reaches a registered fake handler. -- RED: valid fake contract observation returns a reading envelope that names - contract family, schema hash, observer kind, and basis. -- RED: no consumer-specific domain types are required to exercise the contract - envelope path. +- Inventory test: current EINT parser rejects malformed envelopes and reserved + public control op ids. +- Inventory test: generated `RegistryProvider` exposes op ids, schema hash, + codec id, and operation catalog. +- RED, if Echo-side validation is chosen: unknown app op id is rejected by + consulting an installed `RegistryProvider`. +- RED, if observe/query bridging is chosen: generated query op maps to a + reading artifact without bypassing `observe(...)`. +- Guard: no consumer-specific domain types are required in Echo core to + exercise the generated registry path. ## Risks / unknowns -- **Wesley IR shape is still moving.** Keep the first Echo registry static and - fake-handler-friendly so it can be tested before full generated bundles are - stable. -- **Contract handler shape could become a broad runtime facade.** Keep the - boundary limited to dispatch and observe. Do not let it absorb scheduler, - CAS, transport, or app runtime behavior. +- **Wesley IR shape is still moving.** Keep the first proof anchored to the + existing `echo-wesley-gen` output before depending on future IR fields. +- **Duplicate substrate risk.** Do not introduce `ContractIntentEnvelope` or a + new registry before proving EINT v1 and `RegistryProvider` are insufficient. +- **Contract handler shape could become a broad runtime facade.** Keep app + transition law in generated/app code. Do not let it absorb scheduler, CAS, + transport, or app runtime behavior. - **ABI compatibility pressure could preserve old payload forms too long.** Treat this as a major boundary clarification. Compatibility shims must not become alternate truth paths. diff --git a/docs/method/backlog/asap/PLATFORM_contract-aware-intent-observation-envelope.md b/docs/method/backlog/asap/PLATFORM_contract-aware-intent-observation-envelope.md index c8782505..865e2f0d 100644 --- a/docs/method/backlog/asap/PLATFORM_contract-aware-intent-observation-envelope.md +++ b/docs/method/backlog/asap/PLATFORM_contract-aware-intent-observation-envelope.md @@ -1,9 +1,9 @@ -# Contract-Aware Intent And Observation Envelope +# Existing EINT, Registry, And Observation Boundary Inventory -Status: active planned design and RED candidate. +Status: active design correction and inventory candidate. Depends on: @@ -14,48 +14,68 @@ Depends on: ## Why now Echo already exposes generic WASM calls such as `dispatch_intent(...)` and -`observe(...)`. To host Wesley-compiled contracts, those calls need envelopes -that name contract family, schema identity, intent or observer kind, basis, -payload, and posture without hard-coding application semantics. +`observe(...)`. It also already has EINT v1 intent envelopes, registry metadata +exports, a generic `echo-registry-api::RegistryProvider`, and +`echo-wesley-gen` output that includes a generated registry provider. + +The risk now is planning duplicate substrate. Echo does not need a second +intent envelope or a second registry model before a consumer can use it. The +next slice should inventory the existing path and identify the narrow missing +bridge for Wesley-generated app consumers. + +## Current repo truth to preserve + +- `echo-wasm-abi` defines EINT v1 as + `"EINT" || op_id:u32le || vars_len:u32le || vars`. +- `warp-wasm` exposes `dispatch_intent(...)` as the write/control ingress. +- `KernelPort::dispatch_intent(...)` is already app-agnostic over canonical + intent bytes. +- `warp-wasm` exposes `get_registry_info`, `get_codec_id`, + `get_registry_version`, and `get_schema_sha256_hex`. +- `echo-registry-api` defines the app-supplied `RegistryProvider` interface. +- `echo-wesley-gen` emits op ids, op catalogs, `GeneratedRegistry`, and + `REGISTRY`. +- `observe(...)` already returns `ObservationArtifact` with `ReadingEnvelope` + metadata for built-in observations. +- Existing schema validation helpers in `warp-wasm` are currently test-only. + +## Questions to answer + +1. Should app-level generated code validate op ids and vars before calling + `dispatch_intent(...)`, leaving Echo to ingest opaque canonical EINT bytes? +2. Should `warp-wasm` link an app-supplied `RegistryProvider` and reject + unknown op ids or malformed vars at the WASM boundary? +3. Is EINT v1 sufficient for app contract identity when one generated registry + is installed, or does multi-family hosting require an EINT v2 or registry + scope rule? +4. How should Wesley-generated `QUERY` operations relate to `observe(...)`, + `ObservationRequest`, `ReadingEnvelope`, and built-in observer plans? +5. Is `RegistryInfo` metadata enough for `jedit` handshakes, or does browser + code need the full generated op catalog at runtime? ## What it should look like -Add focused RED tests for generic contract envelopes. - -Candidate intent envelope fields: - -- contract family -- schema hash -- intent kind -- basis or frontier -- payload bytes or payload ref -- caller context -- rights posture -- budget posture - -Candidate observation envelope fields: - -- contract family -- schema hash -- observer kind -- basis or frontier -- aperture payload -- rights posture -- budget posture +Add a design/inventory packet before writing RED tests. ## Acceptance criteria -- Unknown contract family is rejected deterministically. -- Unsupported schema hash is rejected deterministically. -- Malformed payload is rejected before contract execution. -- Valid fake envelope reaches a registered fake handler. -- Responses preserve stable contract and schema identity. -- No text, editor, Graft, or `jedit` noun enters the Echo core ABI. +- The packet cites the existing EINT, registry metadata, `RegistryProvider`, + `echo-wesley-gen`, and observation/read-envelope surfaces. +- The packet states whether the next implementation validates op ids in + app-level generated code, Echo's WASM boundary, or both. +- The packet states whether EINT v1 remains the contract path for the next + consumer proof. +- The packet states the first narrow missing bridge for generated query/read + operations. +- Existing backlog cards are corrected so they do not claim that basic intent + ingress or registry metadata are missing. ## Non-goals -- Do not build the registry beyond the minimum fake needed for RED tests. -- Do not implement Wesley generation. +- Do not create a new intent envelope unless the inventory proves EINT v1 is + insufficient. +- Do not implement a new registry model. +- Do not move app-specific validation into Echo core by default. - Do not add dynamic loading. - Do not add application payload types. - Do not change `jedit`. diff --git a/docs/method/backlog/asap/PLATFORM_echo-contract-hosting-roadmap.md b/docs/method/backlog/asap/PLATFORM_echo-contract-hosting-roadmap.md index 6031d9a7..abbbc7cb 100644 --- a/docs/method/backlog/asap/PLATFORM_echo-contract-hosting-roadmap.md +++ b/docs/method/backlog/asap/PLATFORM_echo-contract-hosting-roadmap.md @@ -14,18 +14,21 @@ debugging, or any other consumer domain. Echo is the deterministic witnessed causal substrate. Wesley authors and compiles contract families from GraphQL into generated Rust, -ABI codecs, schema identity, and contract dispatch/read surfaces. +ABI codecs, schema identity, operation catalogs, and app-level helpers. Applications such as `jedit` own their domain contracts and product behavior. -Echo hosts those contracts through generic intent and observation envelopes. +Echo already exposes the generic WASM substrate: EINT `dispatch_intent(...)`, +`observe(...)`, registry metadata exports, and app-agnostic kernel boundaries. +The roadmap must extend that existing path, not invent a second envelope or +registry model. ## Sequence 1. [Wesley compiled contract hosting doctrine](./PLATFORM_wesley-compiled-contract-hosting-doctrine.md) - Design packet: [0013 - Wesley Compiled Contract Hosting Doctrine](../../../design/0013-wesley-compiled-contract-hosting-doctrine/design.md) -2. [Contract-aware intent and observation envelope](./PLATFORM_contract-aware-intent-observation-envelope.md) -3. [Static contract registry and host boundary](./PLATFORM_static-contract-registry-and-host-boundary.md) +2. [Existing EINT, registry, and observation boundary inventory](./PLATFORM_contract-aware-intent-observation-envelope.md) +3. [Registry provider wiring and host boundary decision](./PLATFORM_static-contract-registry-and-host-boundary.md) 4. [Wesley to Echo toy contract proof](../up-next/PLATFORM_wesley-to-echo-toy-contract-proof.md) 5. [Contract-aware receipts and readings](../up-next/KERNEL_contract-aware-receipts-and-readings.md) 6. [Contract artifact retention in echo-cas](../up-next/PLATFORM_contract-artifact-retention-in-echo-cas.md) @@ -39,6 +42,9 @@ Echo hosts those contracts through generic intent and observation envelopes. - Do not add `ReplaceRange`, `BufferWorldline`, or text-editing types to Echo core unless they are generated application contract payloads. - Do not add a special `jedit` ABI. +- Do not create a second intent envelope when EINT already exists. +- Do not create a second registry model when `echo-registry-api` and + `echo-wesley-gen` already exist. - Do not let Graft mutate Echo state directly. - Do not build dynamic plugin loading before static contract hosting works. - Do not start IPA, proof systems, or network Continuum protocol work in this diff --git a/docs/method/backlog/asap/PLATFORM_static-contract-registry-and-host-boundary.md b/docs/method/backlog/asap/PLATFORM_static-contract-registry-and-host-boundary.md index 513b1c41..19abf3ca 100644 --- a/docs/method/backlog/asap/PLATFORM_static-contract-registry-and-host-boundary.md +++ b/docs/method/backlog/asap/PLATFORM_static-contract-registry-and-host-boundary.md @@ -1,56 +1,61 @@ -# Static Contract Registry And Host Boundary +# Registry Provider Wiring And Host Boundary Decision -Status: active planned implementation. +Status: active planned design decision. Depends on: -- [Contract-aware intent and observation envelope](./PLATFORM_contract-aware-intent-observation-envelope.md) +- [Existing EINT, registry, and observation boundary inventory](./PLATFORM_contract-aware-intent-observation-envelope.md) ## Why now -Echo needs a boring runtime boundary where generated contract families can be -registered and resolved. The first implementation should be static and -in-process. Dynamic plugin loading, network distribution, and external contract -installation are later problems. +Echo already has a generic registry interface: +`echo-registry-api::RegistryProvider`. `echo-wesley-gen` already emits a +`GeneratedRegistry` implementation and op catalog from Wesley IR. + +The missing decision is not "invent a registry." The missing decision is how +the existing generated registry is wired into consumers and whether Echo itself +should consult it during `dispatch_intent(...)` / `observe(...)` or leave that +validation to app-level generated code. ## What it should look like -Introduce a minimal registry and handler boundary for generated contracts. +Make one explicit host-boundary decision: + +Option A: -Candidate responsibilities: +- app-level generated code validates op ids and vars using `REGISTRY` +- app-level generated code packs EINT +- Echo ingests canonical EINT bytes opaquely +- Echo exposes registry metadata for handshake -- register a contract descriptor and handler -- resolve by contract family and schema hash -- route intent kinds to generated dispatch logic -- route observer kinds to generated read logic -- report unsupported contract, schema, intent, or observer deterministically +Option B: -Candidate descriptor fields: +- `warp-wasm` or the installed kernel links an app-supplied + `RegistryProvider` +- Echo rejects unknown op ids or malformed vars before ingress +- generated query/read ops get a clear path through `observe(...)` -- family id -- schema hash -- registry version -- codec id -- intent kind catalog -- observer kind catalog -- Wesley generator version or generated bundle identity +Either option must preserve Echo's app-agnostic substrate boundary. ## Acceptance criteria -- A statically registered fake contract dispatches through the generic - envelope path. -- Unknown intent kind fails closed. -- Unknown observer kind fails closed. -- Registry resolution is deterministic. -- Contract handler errors return typed admission or observation posture. -- No dynamic loader or consumer-specific code is introduced. +- The decision cites `echo-registry-api`, `echo-wesley-gen`, EINT v1, and + current `RegistryInfo` exports. +- The decision explains where op id lookup happens for the first consumer. +- The decision explains where vars payload validation happens for the first + consumer. +- The decision explains whether generated `QUERY` ops are app-level helpers, + built-in `observe(...)` requests, or a future observe bridge. +- Any later implementation reuses `RegistryProvider` rather than creating a + parallel registry abstraction. ## Non-goals - Do not implement WASM dynamic module loading. - Do not fetch contracts over the network. - Do not add jedit-specific registration. -- Do not make the handler trait a broad runtime facade. +- Do not invent a new registry trait while `RegistryProvider` is sufficient. +- Do not make the host boundary a broad runtime facade. diff --git a/docs/method/backlog/asap/PLATFORM_wesley-compiled-contract-hosting-doctrine.md b/docs/method/backlog/asap/PLATFORM_wesley-compiled-contract-hosting-doctrine.md index b41ec729..feacff24 100644 --- a/docs/method/backlog/asap/PLATFORM_wesley-compiled-contract-hosting-doctrine.md +++ b/docs/method/backlog/asap/PLATFORM_wesley-compiled-contract-hosting-doctrine.md @@ -24,11 +24,14 @@ consumer. The corrected model is: ```text -GraphQL contract -> Wesley generated Rust -> Echo contract host +GraphQL contract -> Wesley generated Rust -> EINT / observe -> Echo substrate ``` -Echo must host generated contract families generically. Domain behavior belongs -to the authored contract and consuming application. +Echo must host generated contract families generically, but the existing repo +already has major pieces of that path: EINT v1, `dispatch_intent(...)`, +`observe(...)`, `RegistryInfo`, `echo-registry-api::RegistryProvider`, and +`echo-wesley-gen` generated registry output. Domain behavior belongs to the +authored contract and consuming application. ## What it should look like @@ -36,20 +39,22 @@ Write a design packet that defines Echo as a Wesley-compiled contract host. The packet should name at least: -- `ContractFamilyId` -- `ContractSchemaHash` -- `ContractVersion` -- `IntentEnvelope` +- EINT v1 +- `RegistryInfo` +- `RegistryProvider` +- generated `REGISTRY` +- schema hash +- codec id +- registry version - `IntentKind` - `IntentPayload` - `IntentBasis` - `IntentAdmission` - `ContractReceipt` - `ContractWitnessRef` -- `ObservationEnvelope` +- `ObservationRequest` +- `ReadingEnvelope` - `ContractReading` -- `ContractRuntime` -- `ContractRegistry` It should also map those nouns to the existing optic loop: @@ -63,8 +68,9 @@ slice -> lower -> witness -> retain the generic optic lifecycle. - The doc explicitly says Echo must not add text-editor APIs, Graft APIs, or consumer-specific ABI methods. -- The doc identifies the first implementation cards for contract-aware - envelopes and static contract registration. +- The doc identifies the first implementation cards as existing-boundary + inventory and registry-provider wiring decisions, not duplicate envelope or + registry construction. - The doc distinguishes built-in substrate/debug observers from contract-defined application observers. diff --git a/docs/method/backlog/up-next/KERNEL_contract-aware-receipts-and-readings.md b/docs/method/backlog/up-next/KERNEL_contract-aware-receipts-and-readings.md index 3077fb0c..ff24f944 100644 --- a/docs/method/backlog/up-next/KERNEL_contract-aware-receipts-and-readings.md +++ b/docs/method/backlog/up-next/KERNEL_contract-aware-receipts-and-readings.md @@ -12,9 +12,10 @@ Depends on: ## Why now -A generated contract path is not enough unless receipts and readings are honest -about the contract family, schema, basis, payload, and witness material they -commit to. +Echo already content-addresses EINT intent bytes and already emits +`ReadingEnvelope` metadata for built-in observations. A generated contract path +is not enough unless any additional receipt and reading identity claims are +honest about what they actually commit to. Echo should not return global-sounding state hashes for contract-local reads. Contract observations should emit reading identities and envelopes whose scope @@ -22,9 +23,21 @@ is explicit. ## What it should look like -Extend receipt and reading identity inputs so contract execution can name: +First inventory existing identity sources: + +- EINT `intent_id` +- ingress id +- `RegistryInfo` +- generated op id +- payload bytes or payload hash +- `ObservationArtifact::artifact_hash` +- `ReadingEnvelope` + +Only extend receipt and reading identity inputs where those existing identities +cannot honestly name the app contract artifact. + +Candidate additional identity components: -- contract family - schema hash - intent or observer kind - basis or frontier @@ -35,11 +48,11 @@ Extend receipt and reading identity inputs so contract execution can name: ## Acceptance criteria -- The same intent over the same basis produces the same receipt identity. +- The same EINT bytes over the same basis produce the same receipt identity. - Changing schema hash changes receipt identity. - Changing payload changes receipt identity. -- Contract observation reading identity includes contract family, schema, - observer kind, basis, and aperture. +- Generated observation reading identity includes schema, observer or query op, + basis, and aperture when those concepts are part of the generated read path. - Unsupported or stale basis returns typed obstruction rather than a fake reading. - Existing built-in observation tests remain green. @@ -50,3 +63,5 @@ Extend receipt and reading identity inputs so contract execution can name: - Do not introduce IPA or commitment math. - Do not require full Continuum export/import. - Do not add consumer-specific receipt fields to Echo core. +- Do not duplicate `intent_id` or `ReadingEnvelope` if they already provide the + honest identity needed for the first consumer. diff --git a/docs/method/backlog/up-next/PLATFORM_contract-artifact-retention-in-echo-cas.md b/docs/method/backlog/up-next/PLATFORM_contract-artifact-retention-in-echo-cas.md index 848ae515..bf0c37a3 100644 --- a/docs/method/backlog/up-next/PLATFORM_contract-artifact-retention-in-echo-cas.md +++ b/docs/method/backlog/up-next/PLATFORM_contract-artifact-retention-in-echo-cas.md @@ -18,7 +18,9 @@ but the contract-hosting path needs concrete retention rules for generated contract artifacts. CAS hashes name bytes. Semantic lookup keys name the question those bytes -answer. +answer. This matches existing `echo-cas` policy: CAS hashes are content-only, +while domain separation belongs in typed references and semantic coordinates +above the blob store. ## What it should look like @@ -50,3 +52,4 @@ applicable. - Do not implement proof-carrying retention. - Do not add app-specific indexes. - Do not make CAS content hashes stand in for reading identity. +- Do not change `echo-cas` content-hash policy for contract semantics. diff --git a/docs/method/backlog/up-next/PLATFORM_jedit-text-contract-mvp.md b/docs/method/backlog/up-next/PLATFORM_jedit-text-contract-mvp.md index 6a398d92..51de73d8 100644 --- a/docs/method/backlog/up-next/PLATFORM_jedit-text-contract-mvp.md +++ b/docs/method/backlog/up-next/PLATFORM_jedit-text-contract-mvp.md @@ -37,14 +37,16 @@ Candidate observations: - edit group history - checkpoint status -Wesley compiles the contract. Echo registers and hosts it. `jedit` adapts its -existing hot text runtime port to submit generated contract intents. +Wesley compiles the contract. `jedit` adapts its existing hot text runtime port +to use generated app-level code that validates payloads, packs EINT op ids and +vars, calls Echo's existing `dispatch_intent(...)`, reads registry metadata for +handshake, and decodes observations. ## Acceptance criteria - `jedit` can create a buffer through a contract intent. - `jedit` can submit a replace-range intent through Echo. -- Echo emits a contract-aware receipt for the edit. +- Echo accepts the generated EINT through the existing WASM intent ingress. - `jedit` can observe a buffer reading through Echo. - Save checkpoint produces a retained contract artifact. - Echo core contains no text-specific APIs outside generated contract payloads. @@ -53,6 +55,8 @@ existing hot text runtime port to submit generated contract intents. - Do not add text-editing types to Echo core. - Do not add a special `jedit` ABI. +- Do not move `jedit` payload validation into Echo core unless the registry + boundary decision explicitly requires Echo-side validation. - Do not wire Graft automation in this card. - Do not require multi-buffer collaboration. - Do not implement strands or counterfactual refactors here. diff --git a/docs/method/backlog/up-next/PLATFORM_wesley-to-echo-toy-contract-proof.md b/docs/method/backlog/up-next/PLATFORM_wesley-to-echo-toy-contract-proof.md index 24d184d4..4089ca09 100644 --- a/docs/method/backlog/up-next/PLATFORM_wesley-to-echo-toy-contract-proof.md +++ b/docs/method/backlog/up-next/PLATFORM_wesley-to-echo-toy-contract-proof.md @@ -7,7 +7,7 @@ Status: planned cross-repo proof. Depends on: -- [Static contract registry and host boundary](../asap/PLATFORM_static-contract-registry-and-host-boundary.md) +- [Registry provider wiring and host boundary decision](../asap/PLATFORM_static-contract-registry-and-host-boundary.md) - [echo-wesley-gen v2 Update](./PLATFORM_echo-wesley-gen-v2.md) - [WESLEY Protocol Consumer Cutover](../asap/PLATFORM_WESLEY_protocol-consumer-cutover.md) @@ -19,9 +19,13 @@ need one tiny contract that proves the full authoring and hosting path. This should be deliberately boring. The value is the path: ```text -GraphQL -> Wesley IR -> generated Rust -> Echo registry -> dispatch -> observe +GraphQL -> Wesley IR -> echo-wesley-gen Rust -> EINT -> dispatch -> observe ``` +This proof should reuse existing pieces: EINT v1, `dispatch_intent(...)`, +`RegistryInfo`, `echo-registry-api::RegistryProvider`, `GeneratedRegistry`, and +the current observation/read-envelope boundary. + ## What it should look like Use a tiny toy contract, such as a counter, with one intent and one observer. @@ -32,18 +36,21 @@ Example domain: - `CounterValue` The exact schema is not important. The proof must exercise generated identity, -codecs, dispatch, receipt creation, and observation. +op ids, vars encoding, EINT packing, dispatch, registry metadata, and one +read/observation path. ## Acceptance criteria - Wesley compiles the toy GraphQL contract to Echo-consumable Rust artifacts. -- Echo statically registers the generated contract. +- `echo-wesley-gen` emits op ids, op catalog metadata, and a generated + `RegistryProvider`. +- The consumer proof uses `pack_intent_v1(...)` with a generated op id and vars + payload. - `dispatch_intent(...)` admits one valid toy intent. -- `observe(...)` returns one contract-defined reading payload. -- The receipt names contract family, schema hash, intent kind, basis, and - payload hash. -- The reading envelope names contract family, schema hash, observer kind, and - basis. +- Registry metadata from the installed kernel or app bundle matches the + generated schema and codec metadata. +- One read path proves how generated query/observer operations relate to + `observe(...)` and `ReadingEnvelope`. - Golden ABI vectors are stable. ## Non-goals @@ -52,3 +59,4 @@ codecs, dispatch, receipt creation, and observation. - Do not add dynamic contract loading. - Do not require browser packaging. - Do not add Continuum transport. +- Do not create a second registry or intent envelope. From 7e9fc841f19bd55424d27165781e4233ed3f85fb Mon Sep 17 00:00:00 2001 From: James Ross Date: Sun, 3 May 2026 17:52:43 -0700 Subject: [PATCH 04/21] docs: inventory echo intent registry observation boundary --- .../design.md | 269 ++++++++++++++++++ ...tract-aware-intent-observation-envelope.md | 6 +- .../PLATFORM_echo-contract-hosting-roadmap.md | 2 + 3 files changed, 276 insertions(+), 1 deletion(-) create mode 100644 docs/design/0014-eint-registry-observation-boundary-inventory/design.md diff --git a/docs/design/0014-eint-registry-observation-boundary-inventory/design.md b/docs/design/0014-eint-registry-observation-boundary-inventory/design.md new file mode 100644 index 00000000..42fd1a6e --- /dev/null +++ b/docs/design/0014-eint-registry-observation-boundary-inventory/design.md @@ -0,0 +1,269 @@ + + + +# 0014 - EINT, Registry, And Observation Boundary Inventory + +_Inventory the existing Echo intent, registry, and observation substrate before +adding Wesley-generated contract hosting behavior._ + +Legend: [PLATFORM](../../method/legends/PLATFORM.md) + +Depends on: + +- [0013 - Wesley Compiled Contract Hosting Doctrine](../0013-wesley-compiled-contract-hosting-doctrine/design.md) +- [Existing EINT, Registry, And Observation Boundary Inventory](../../method/backlog/asap/PLATFORM_contract-aware-intent-observation-envelope.md) +- [Registry Provider Wiring And Host Boundary Decision](../../method/backlog/asap/PLATFORM_static-contract-registry-and-host-boundary.md) + +## Why this packet exists + +Echo already has enough generic substrate to accept app-authored intent bytes +and expose observation and registry metadata. The immediate risk is not missing +machinery. The immediate risk is planning a second machinery path because the +existing one was not named precisely. + +This packet records the current boundary so the next Wesley-to-Echo consumer +proof starts from repo truth: + +```text +Wesley-generated app code + -> validate generated op and vars + -> pack EINT v1 bytes + -> dispatch_intent(...) + -> observe(...) / app-level read helper +``` + +The packet is intentionally conservative. It does not claim that this is the +final host architecture for every future runtime. It defines the narrow first +path that avoids duplicate envelopes, duplicate registries, and accidental +app-specific APIs in Echo core. + +## Existing boundary inventory + +### EINT v1 + +`echo-wasm-abi` already defines EINT v1: + +```text +"EINT" || op_id:u32le || vars_len:u32le || vars +``` + +Important properties: + +- `pack_intent_v1(op_id, vars)` packs application intents. +- `unpack_intent_v1(bytes)` parses application-blind intent bytes. +- `CONTROL_INTENT_V1_OP_ID` is reserved for privileged control intents. +- application intents cannot use the reserved control op id. + +This gives Echo a generic write ingress without knowing application nouns. + +### WASM dispatch + +`warp-wasm` already exports: + +```text +dispatch_intent(intent_bytes) +``` + +The installed kernel parses EINT, classifies the reserved control op id, and +otherwise ingests application EINT bytes as canonical intent material. + +### Kernel port + +`KernelPort::dispatch_intent(...)` already defines the app-agnostic byte +boundary. Its docs explicitly say the boundary makes no assumptions about +installed schema, rules, or domain. + +This is important. A first jedit or toy contract proof should not require Echo +core to gain `ReplaceRange`, `CounterIncrement`, or other application nouns. + +### Registry metadata + +`echo-wasm-abi` already has `RegistryInfo` with: + +- `codec_id` +- `registry_version` +- `schema_sha256_hex` +- `abi_version` + +`warp-wasm` already exports: + +- `get_registry_info` +- `get_codec_id` +- `get_registry_version` +- `get_schema_sha256_hex` + +That is enough for a first handshake that says which generated app bundle and +codec a host believes it is serving. + +### Registry provider + +`echo-registry-api` already defines `RegistryProvider`. + +It is explicitly application-supplied and generated from GraphQL / Wesley IR. +It can expose: + +- registry metadata +- operation lookup by id +- deterministic operation catalog iteration +- enum descriptors +- object descriptors + +`echo-wesley-gen` already emits generated op ids, `OPS`, `op_by_id`, +`GeneratedRegistry`, and static `REGISTRY`. + +The open question is therefore wiring, not ontology. + +### Observation + +`KernelPort::observe(...)` already exists as the canonical world-state read +entrypoint. It accepts `ObservationRequest` and returns `ObservationArtifact` +with `ReadingEnvelope` metadata. + +Generated query or read operations should be mapped onto this existing read +surface where possible. They should not create a parallel `query_contract` +ABI until a concrete consumer proof shows that `observe(...)` cannot honestly +carry the reading. + +### echo-cas + +`echo-cas` already stores opaque blobs by content hash. CAS hashes are +content-only. Semantic identity, domain separation, reading scope, and contract +meaning belong in typed refs and coordinates above CAS. + +That means contract artifact retention should add typed semantic keys and +retention refs above CAS, not change the CAS hash law. + +## Decision 1: Do not add a second intent envelope + +EINT v1 remains the contract path for the first consumer proof. + +The first toy contract and first jedit-shaped consumer should pack generated +operation ids and encoded vars into EINT v1. They should not introduce a new +`ContractIntentEnvelope`. + +EINT v2 is deferred until one of these is concretely required: + +- multiple generated registries installed in one host at the same time; +- registry scope must be encoded per intent rather than negotiated at + handshake time; +- a consumer needs domain-separated intent bytes that EINT v1 cannot name + without ambiguity. + +## Decision 2: First validation is app-level generated validation + +For the first consumer proof, generated application code should validate op ids +and vars before calling `dispatch_intent(...)`. + +That means: + +- generated code consults generated `REGISTRY`; +- generated code packs canonical EINT bytes; +- Echo ingests application EINT bytes opaquely; +- Echo still validates EINT shape and reserved control op usage; +- Echo does not validate domain payload shape in core. + +This decision preserves the current app-agnostic `KernelPort` boundary and +matches the product direction that jedit owns text behavior in app-level code. + +Host-side registry validation remains a valid later option, but it should be a +separate implementation decision with RED tests proving what must be rejected +at the Echo boundary. + +## Decision 3: RegistryInfo is enough for first handshake + +For the first consumer proof, `RegistryInfo` is enough to prove that the host +and generated app bundle agree on: + +- ABI version; +- codec id; +- registry version; +- schema hash. + +The full op catalog may still be useful for browser UI, devtools, diagnostics, +or generated-client self-checks, but it is not required as a new Echo ABI export +before the toy proof. + +If browser-side jedit later needs runtime operation discovery, add that as an +explicit registry-catalog export card. Do not smuggle it into dispatch. + +## Decision 4: Generated query/read ops need a narrow bridge + +The first missing bridge is not write ingress. It is generated read semantics. + +Wesley-generated `QUERY` operations need one of these shapes: + +1. application-level generated helper constructs an `ObservationRequest`, calls + `observe(...)`, and decodes the returned reading payload; +2. generated query op remains app-local until Echo has a typed observer plan for + that family; +3. later host-side registry wiring maps generated `QUERY` op ids to built-in or + app-installed observer plans. + +For the first consumer proof, prefer option 1 unless a RED proves that the +current `ObservationRequest` shape cannot name the required reading. + +## First implementation implication + +The next implementation card should not be "build contract envelopes." + +The next implementation card should be the toy proof: + +```text +GraphQL contract + -> Wesley IR + -> echo-wesley-gen generated Rust + -> generated RegistryProvider + -> pack_intent_v1(generated_op_id, encoded_vars) + -> dispatch_intent(...) + -> observe(...) for one read path +``` + +Before production changes, the RED should prove only the missing consumer +bridge. It should not fail because Echo lacks a generic intent envelope or +registry metadata. + +## Rejected designs + +### ContractIntentEnvelope v1 + +Rejected for the first consumer. EINT v1 already exists. + +### ContractRegistry trait + +Rejected for the first consumer. `echo-registry-api::RegistryProvider` already +exists and `echo-wesley-gen` already emits a provider. + +### jedit-specific ABI + +Rejected. jedit behavior belongs in the app contract and generated client or +adapter, not Echo core. + +### Echo-side domain validation by default + +Rejected for the first consumer. Echo should keep app payload validation outside +core unless a host-boundary RED proves that Echo must reject a malformed +generated payload before ingress. + +## Open questions + +- Should host-side registry validation become mandatory once Echo supports + installed generated contract families? +- Does `RegistryInfo.registry_version` need to stay a string in + `echo-wasm-abi` while `echo-registry-api::RegistryInfo.registry_version` is + `u32`, or should a future compatibility card align the two surfaces? +- Should `warp-wasm` expose the full generated operation catalog for browser + handshakes and devtools? +- Which `ObservationRequest` fields are sufficient for the first generated + query/read helper? +- Should a future EINT v2 include registry scope, family id, or schema hash, or + is handshake-scoped registry identity enough? + +## Acceptance impact + +This packet completes the inventory card and narrows the next two backlog +items: + +- registry provider wiring should now focus on host-side validation and catalog + export decisions; +- the toy proof should reuse EINT v1 and `RegistryProvider` rather than invent + envelopes or registries. diff --git a/docs/method/backlog/asap/PLATFORM_contract-aware-intent-observation-envelope.md b/docs/method/backlog/asap/PLATFORM_contract-aware-intent-observation-envelope.md index 865e2f0d..7960acb8 100644 --- a/docs/method/backlog/asap/PLATFORM_contract-aware-intent-observation-envelope.md +++ b/docs/method/backlog/asap/PLATFORM_contract-aware-intent-observation-envelope.md @@ -3,11 +3,12 @@ # Existing EINT, Registry, And Observation Boundary Inventory -Status: active design correction and inventory candidate. +Status: design packet complete. Depends on: - [Wesley compiled contract hosting doctrine](./PLATFORM_wesley-compiled-contract-hosting-doctrine.md) +- [0014 - EINT, Registry, And Observation Boundary Inventory](../../../design/0014-eint-registry-observation-boundary-inventory/design.md) - [Reading envelope family boundary](../up-next/PLATFORM_reading-envelope-family-boundary.md) - [Observer plans and reading artifacts](./PLATFORM_observer-plan-reading-artifacts.md) @@ -57,6 +58,9 @@ bridge for Wesley-generated app consumers. Add a design/inventory packet before writing RED tests. +That packet now exists: +[0014 - EINT, Registry, And Observation Boundary Inventory](../../../design/0014-eint-registry-observation-boundary-inventory/design.md). + ## Acceptance criteria - The packet cites the existing EINT, registry metadata, `RegistryProvider`, diff --git a/docs/method/backlog/asap/PLATFORM_echo-contract-hosting-roadmap.md b/docs/method/backlog/asap/PLATFORM_echo-contract-hosting-roadmap.md index abbbc7cb..e9c65fbb 100644 --- a/docs/method/backlog/asap/PLATFORM_echo-contract-hosting-roadmap.md +++ b/docs/method/backlog/asap/PLATFORM_echo-contract-hosting-roadmap.md @@ -28,6 +28,8 @@ registry model. - Design packet: [0013 - Wesley Compiled Contract Hosting Doctrine](../../../design/0013-wesley-compiled-contract-hosting-doctrine/design.md) 2. [Existing EINT, registry, and observation boundary inventory](./PLATFORM_contract-aware-intent-observation-envelope.md) + - Design packet: + [0014 - EINT, Registry, And Observation Boundary Inventory](../../../design/0014-eint-registry-observation-boundary-inventory/design.md) 3. [Registry provider wiring and host boundary decision](./PLATFORM_static-contract-registry-and-host-boundary.md) 4. [Wesley to Echo toy contract proof](../up-next/PLATFORM_wesley-to-echo-toy-contract-proof.md) 5. [Contract-aware receipts and readings](../up-next/KERNEL_contract-aware-receipts-and-readings.md) From 70bbcb33d62f2ddaf047f7f60dea913152b1f4e0 Mon Sep 17 00:00:00 2001 From: James Ross Date: Sun, 3 May 2026 17:54:21 -0700 Subject: [PATCH 05/21] docs: decide registry host boundary --- .../design.md | 158 ++++++++++++++++++ .../PLATFORM_echo-contract-hosting-roadmap.md | 2 + ...tic-contract-registry-and-host-boundary.md | 10 +- 3 files changed, 169 insertions(+), 1 deletion(-) create mode 100644 docs/design/0015-registry-provider-host-boundary-decision/design.md diff --git a/docs/design/0015-registry-provider-host-boundary-decision/design.md b/docs/design/0015-registry-provider-host-boundary-decision/design.md new file mode 100644 index 00000000..fefcbb24 --- /dev/null +++ b/docs/design/0015-registry-provider-host-boundary-decision/design.md @@ -0,0 +1,158 @@ + + + +# 0015 - Registry Provider Host Boundary Decision + +_Choose the first host boundary for Wesley-generated registries without +changing Echo's app-agnostic EINT ingress._ + +Legend: [PLATFORM](../../method/legends/PLATFORM.md) + +Depends on: + +- [0013 - Wesley Compiled Contract Hosting Doctrine](../0013-wesley-compiled-contract-hosting-doctrine/design.md) +- [0014 - EINT, Registry, And Observation Boundary Inventory](../0014-eint-registry-observation-boundary-inventory/design.md) +- [Registry Provider Wiring And Host Boundary Decision](../../method/backlog/asap/PLATFORM_static-contract-registry-and-host-boundary.md) + +## Decision + +For the first Wesley-to-Echo consumer proof, Echo should use app-level generated +validation before EINT dispatch. + +That means the first consumer path is: + +```text +generated app client / adapter + -> generated REGISTRY lookup + -> generated vars validation and encoding + -> pack_intent_v1(generated_op_id, vars) + -> dispatch_intent(...) +``` + +Echo's current `dispatch_intent(...)` boundary remains app-agnostic and +application-blind. Echo validates EINT shape and reserved control op use. It +does not validate generated operation payload semantics in core for this slice. + +## Why this choice + +The existing code already establishes two important constraints: + +- `KernelPort` is explicitly app-agnostic over canonical intent bytes. +- `echo-registry-api::RegistryProvider` is application-supplied and generated + from GraphQL / Wesley IR. + +Those facts point to a conservative first cut: generated application code owns +domain validation, while Echo owns deterministic ingestion, admission, +observation, receipts, readings, and retention. + +This is also the right fit for `jedit`: text editing behavior belongs in the +application contract and generated adapter, not in Echo core. + +## Rejected for the first consumer + +### Host-side app payload validation + +Do not make `warp-wasm` reject unknown generated app op ids or malformed app +vars yet. + +That may become correct once Echo supports installed generated contract +families, but it should be introduced by a future RED that proves one of these +needs: + +- app-independent host validation before ingestion; +- runtime operation catalog export; +- multiple generated registries installed in one host; +- query op dispatch through an installed observer plan. + +### New registry trait + +Do not add a second registry abstraction. If host-side validation becomes +necessary, reuse `echo-registry-api::RegistryProvider` or document why it is +insufficient. + +### New intent envelope + +Do not add a new contract intent envelope for the first consumer. EINT v1 +remains the wire shape. + +## What Echo should expose now + +The first host handshake should use existing metadata: + +- `get_registry_info` +- `get_codec_id` +- `get_registry_version` +- `get_schema_sha256_hex` + +For generated clients, this is enough to check that the app bundle and host +agree about schema identity, codec identity, registry version, and ABI version. + +## What generated code should do now + +Generated app code should: + +- expose typed operation helpers; +- look up generated operation ids from generated constants or `REGISTRY`; +- validate operation shape before packing EINT; +- encode vars in the generated codec; +- call `pack_intent_v1(...)`; +- call `dispatch_intent(...)`; +- decode dispatch responses and observations into app-level result types. + +The generated code may use `RegistryProvider` for self-checking, diagnostics, +or op lookup. It does not need Echo core to consult the provider for the first +consumer proof. + +## Query and observation bridge + +Generated `QUERY` operations remain the narrow unresolved bridge. + +For the first proof, generated read helpers should prefer: + +```text +generated read helper + -> construct ObservationRequest + -> observe(...) + -> verify ReadingEnvelope posture + -> decode app-level reading payload +``` + +If a generated query cannot be represented through the current +`ObservationRequest`, the next RED should prove that exact missing field or +observer-plan hook. It should not add a broad `query_contract(...)` ABI. + +## Future host-side validation card + +Host-side validation is deferred, not rejected forever. + +When pulled, that future card should answer: + +- how a generated `RegistryProvider` is installed into `warp-wasm` or the + kernel; +- whether host-side validation rejects unknown op ids; +- whether host-side validation can validate vars bytes without importing + app-specific domain types into Echo core; +- whether generated query ops map to observer plans or remain app-level + helpers; +- whether registry catalog export is required for browser clients or devtools. + +## Acceptance impact + +The first implementation should now be the toy contract proof, not registry +plumbing. It should prove: + +- generated registry output exists; +- generated app code validates and packs one mutation into EINT v1; +- Echo accepts that EINT through existing dispatch; +- one read helper can use existing observation/read-envelope surfaces or + produce a narrow RED for the missing observation bridge. + +## Non-goals + +- No ABI changes. +- No new registry trait. +- No new intent envelope. +- No host-side app payload validation yet. +- No dynamic contract loading. +- No jedit-specific APIs. +- No production code in this design slice. diff --git a/docs/method/backlog/asap/PLATFORM_echo-contract-hosting-roadmap.md b/docs/method/backlog/asap/PLATFORM_echo-contract-hosting-roadmap.md index e9c65fbb..210b988e 100644 --- a/docs/method/backlog/asap/PLATFORM_echo-contract-hosting-roadmap.md +++ b/docs/method/backlog/asap/PLATFORM_echo-contract-hosting-roadmap.md @@ -31,6 +31,8 @@ registry model. - Design packet: [0014 - EINT, Registry, And Observation Boundary Inventory](../../../design/0014-eint-registry-observation-boundary-inventory/design.md) 3. [Registry provider wiring and host boundary decision](./PLATFORM_static-contract-registry-and-host-boundary.md) + - Design packet: + [0015 - Registry Provider Host Boundary Decision](../../../design/0015-registry-provider-host-boundary-decision/design.md) 4. [Wesley to Echo toy contract proof](../up-next/PLATFORM_wesley-to-echo-toy-contract-proof.md) 5. [Contract-aware receipts and readings](../up-next/KERNEL_contract-aware-receipts-and-readings.md) 6. [Contract artifact retention in echo-cas](../up-next/PLATFORM_contract-artifact-retention-in-echo-cas.md) diff --git a/docs/method/backlog/asap/PLATFORM_static-contract-registry-and-host-boundary.md b/docs/method/backlog/asap/PLATFORM_static-contract-registry-and-host-boundary.md index 19abf3ca..b637f045 100644 --- a/docs/method/backlog/asap/PLATFORM_static-contract-registry-and-host-boundary.md +++ b/docs/method/backlog/asap/PLATFORM_static-contract-registry-and-host-boundary.md @@ -3,11 +3,12 @@ # Registry Provider Wiring And Host Boundary Decision -Status: active planned design decision. +Status: design packet complete. Depends on: - [Existing EINT, registry, and observation boundary inventory](./PLATFORM_contract-aware-intent-observation-envelope.md) +- [0015 - Registry Provider Host Boundary Decision](../../../design/0015-registry-provider-host-boundary-decision/design.md) ## Why now @@ -40,6 +41,13 @@ Option B: Either option must preserve Echo's app-agnostic substrate boundary. +That decision now exists: +[0015 - Registry Provider Host Boundary Decision](../../../design/0015-registry-provider-host-boundary-decision/design.md). + +The first consumer uses Option A. Host-side app payload validation is deferred +until a future RED proves why the Echo boundary must reject generated app +payloads before ingress. + ## Acceptance criteria - The decision cites `echo-registry-api`, `echo-wesley-gen`, EINT v1, and From 776f6872e8840b650ffb7a74a8bf08aaf0e0ac99 Mon Sep 17 00:00:00 2001 From: James Ross Date: Sun, 3 May 2026 17:59:10 -0700 Subject: [PATCH 06/21] test: prove Wesley toy contract bridge missing --- crates/echo-wesley-gen/tests/generation.rs | 82 ++++++++++++ .../design.md | 125 ++++++++++++++++++ .../PLATFORM_echo-contract-hosting-roadmap.md | 2 + ...TFORM_wesley-to-echo-toy-contract-proof.md | 13 +- 4 files changed, 221 insertions(+), 1 deletion(-) create mode 100644 docs/design/0016-wesley-to-echo-toy-contract-proof/design.md diff --git a/crates/echo-wesley-gen/tests/generation.rs b/crates/echo-wesley-gen/tests/generation.rs index 76839e53..583e6e7b 100644 --- a/crates/echo-wesley-gen/tests/generation.rs +++ b/crates/echo-wesley-gen/tests/generation.rs @@ -115,6 +115,88 @@ fn test_ops_catalog_present() { ); } +#[test] +fn test_toy_contract_generates_eint_and_observation_helpers() { + let ir = r#"{ + "ir_version": "echo-ir/v1", + "schema_sha256": "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef", + "codec_id": "cbor-canon-v1", + "registry_version": 1, + "types": [ + { + "name": "CounterValue", + "kind": "OBJECT", + "fields": [ + { "name": "value", "type": "Int", "required": true } + ] + }, + { + "name": "IncrementInput", + "kind": "INPUT_OBJECT", + "fields": [ + { "name": "amount", "type": "Int", "required": true } + ] + }, + { + "name": "Mutation", + "kind": "OBJECT", + "fields": [ + { "name": "increment", "type": "CounterValue", "required": true } + ] + }, + { + "name": "Query", + "kind": "OBJECT", + "fields": [ + { "name": "counterValue", "type": "CounterValue", "required": true } + ] + } + ], + "ops": [ + { + "kind": "MUTATION", + "name": "increment", + "op_id": 1001, + "args": [ + { "name": "input", "type": "IncrementInput", "required": true } + ], + "result_type": "CounterValue" + }, + { + "kind": "QUERY", + "name": "counterValue", + "op_id": 1002, + "args": [], + "result_type": "CounterValue" + } + ] + }"#; + + let output = run_wesley_gen(ir); + assert!( + output.status.success(), + "CLI failed: {}", + String::from_utf8_lossy(&output.stderr) + ); + let stdout = String::from_utf8_lossy(&output.stdout); + + assert!(stdout.contains("pub const OP_INCREMENT: u32 = 1001")); + assert!(stdout.contains("pub const OP_COUNTER_VALUE: u32 = 1002")); + assert!(stdout.contains("pub static REGISTRY: GeneratedRegistry")); + + for required in [ + "use echo_wasm_abi::pack_intent_v1;", + "pub fn pack_increment_intent", + "pack_intent_v1(OP_INCREMENT", + "pub fn counter_value_observation_request", + ] { + assert!( + stdout.contains(required), + "generated toy contract output is missing first-consumer bridge: {required}" + ); + } +} + #[test] fn test_generate_no_std_minicbor() { let ir = r#"{ diff --git a/docs/design/0016-wesley-to-echo-toy-contract-proof/design.md b/docs/design/0016-wesley-to-echo-toy-contract-proof/design.md new file mode 100644 index 00000000..0abd22f7 --- /dev/null +++ b/docs/design/0016-wesley-to-echo-toy-contract-proof/design.md @@ -0,0 +1,125 @@ + + + +# 0016 - Wesley To Echo Toy Contract Proof + +_Prove one boring Wesley-generated contract path from generated op metadata to +EINT dispatch and an observation/read bridge._ + +Legend: [PLATFORM](../../method/legends/PLATFORM.md) + +Depends on: + +- [0013 - Wesley Compiled Contract Hosting Doctrine](../0013-wesley-compiled-contract-hosting-doctrine/design.md) +- [0014 - EINT, Registry, And Observation Boundary Inventory](../0014-eint-registry-observation-boundary-inventory/design.md) +- [0015 - Registry Provider Host Boundary Decision](../0015-registry-provider-host-boundary-decision/design.md) +- [Wesley To Echo Toy Contract Proof](../../method/backlog/up-next/PLATFORM_wesley-to-echo-toy-contract-proof.md) + +## Status + +RED. + +## Hill + +A tiny generated contract can use existing Echo substrate: + +```text +GraphQL / Wesley IR + -> echo-wesley-gen generated Rust + -> generated op id and REGISTRY + -> generated app-level EINT helper + -> dispatch_intent(...) + -> generated read helper over observe(...) / ReadingEnvelope +``` + +## Opening constraint + +Do not create a new intent envelope, registry trait, ABI, host-side app payload +validator, dynamic loading path, or jedit-specific API. + +The first proof must reuse: + +- EINT v1; +- `pack_intent_v1(...)`; +- `dispatch_intent(...)`; +- `RegistryProvider`; +- generated `REGISTRY`; +- `observe(...)` / `ReadingEnvelope` if the current read boundary can carry the + toy query. + +## RED witness + +Focused test: + +```sh +cargo test -p echo-wesley-gen test_toy_contract_generates_eint_and_observation_helpers +``` + +The test uses a tiny counter contract: + +- mutation: `increment(input: IncrementInput): CounterValue` +- query: `counterValue: CounterValue` + +It first proves current generated output already includes: + +- `OP_INCREMENT` +- `OP_COUNTER_VALUE` +- `REGISTRY` + +It then requires the missing first-consumer bridge: + +- import or use of `pack_intent_v1(...)`; +- generated mutation helper such as `pack_increment_intent`; +- EINT packing with `OP_INCREMENT`; +- generated query/read helper such as `counter_value_observation_request`. + +## Expected failure + +Current `echo-wesley-gen` emits DTOs, operation constants, operation catalogs, +and `GeneratedRegistry`. It does not yet emit app-level EINT dispatch helpers +or generated observation helpers. + +That is the correct RED. The missing piece is not Echo's intent ingress or +registry metadata. The missing piece is generated consumer glue that binds the +existing substrate into a contract-shaped app helper. + +Observed RED: + +```text +test test_toy_contract_generates_eint_and_observation_helpers ... FAILED +generated toy contract output is missing first-consumer bridge: +use echo_wasm_abi::pack_intent_v1; +``` + +## GREEN direction + +The first GREEN should stay inside `echo-wesley-gen` unless a narrow +observation-boundary RED proves a missing ABI field. + +Expected implementation shape: + +- generate vars encoder helpers for operation arguments; +- generate `pack__intent(...)` helpers that call + `pack_intent_v1(OP_..., &vars)`; +- generate one read-helper shape for query ops that maps to + `ObservationRequest` if possible; +- keep Echo core app-agnostic; +- keep host-side generated payload validation deferred. + +## Non-goals + +- Do not add a second envelope. +- Do not add a second registry model. +- Do not change `KernelPort`. +- Do not change `warp-wasm` exports. +- Do not implement host-side app payload validation. +- Do not implement dynamic contract loading. +- Do not add text-editing or jedit nouns. +- Do not add Continuum transport. + +## Remaining design question + +The RED deliberately includes a generated query/read helper. If the current +`ObservationRequest` shape cannot honestly express the toy query, the next +GREEN should stop at the precise missing observation bridge instead of +inventing a broad `query_contract(...)` ABI. diff --git a/docs/method/backlog/asap/PLATFORM_echo-contract-hosting-roadmap.md b/docs/method/backlog/asap/PLATFORM_echo-contract-hosting-roadmap.md index 210b988e..59f70c8b 100644 --- a/docs/method/backlog/asap/PLATFORM_echo-contract-hosting-roadmap.md +++ b/docs/method/backlog/asap/PLATFORM_echo-contract-hosting-roadmap.md @@ -34,6 +34,8 @@ registry model. - Design packet: [0015 - Registry Provider Host Boundary Decision](../../../design/0015-registry-provider-host-boundary-decision/design.md) 4. [Wesley to Echo toy contract proof](../up-next/PLATFORM_wesley-to-echo-toy-contract-proof.md) + - Design packet: + [0016 - Wesley To Echo Toy Contract Proof](../../../design/0016-wesley-to-echo-toy-contract-proof/design.md) 5. [Contract-aware receipts and readings](../up-next/KERNEL_contract-aware-receipts-and-readings.md) 6. [Contract artifact retention in echo-cas](../up-next/PLATFORM_contract-artifact-retention-in-echo-cas.md) 7. [jedit text contract MVP](../up-next/PLATFORM_jedit-text-contract-mvp.md) diff --git a/docs/method/backlog/up-next/PLATFORM_wesley-to-echo-toy-contract-proof.md b/docs/method/backlog/up-next/PLATFORM_wesley-to-echo-toy-contract-proof.md index 4089ca09..64deca7f 100644 --- a/docs/method/backlog/up-next/PLATFORM_wesley-to-echo-toy-contract-proof.md +++ b/docs/method/backlog/up-next/PLATFORM_wesley-to-echo-toy-contract-proof.md @@ -3,11 +3,12 @@ # Wesley To Echo Toy Contract Proof -Status: planned cross-repo proof. +Status: RED. Depends on: - [Registry provider wiring and host boundary decision](../asap/PLATFORM_static-contract-registry-and-host-boundary.md) +- [0016 - Wesley To Echo Toy Contract Proof](../../../design/0016-wesley-to-echo-toy-contract-proof/design.md) - [echo-wesley-gen v2 Update](./PLATFORM_echo-wesley-gen-v2.md) - [WESLEY Protocol Consumer Cutover](../asap/PLATFORM_WESLEY_protocol-consumer-cutover.md) @@ -39,6 +40,16 @@ The exact schema is not important. The proof must exercise generated identity, op ids, vars encoding, EINT packing, dispatch, registry metadata, and one read/observation path. +## Current RED + +The current RED is documented in +[0016 - Wesley To Echo Toy Contract Proof](../../../design/0016-wesley-to-echo-toy-contract-proof/design.md). + +`echo-wesley-gen` already emits op constants, `OPS`, `GeneratedRegistry`, and +`REGISTRY`. It does not yet emit the first-consumer app-level helper that +validates/encodes operation vars, packs EINT v1, and maps a generated query/read +helper to `observe(...)` / `ReadingEnvelope`. + ## Acceptance criteria - Wesley compiles the toy GraphQL contract to Echo-consumable Rust artifacts. From 6c391ee622d3298ce095fc3c81e185401257f505 Mon Sep 17 00:00:00 2001 From: James Ross Date: Sun, 3 May 2026 18:05:56 -0700 Subject: [PATCH 07/21] docs: track relocated Wesley schema reconciliation --- ...reconcile-relocated-wesley-echo-schemas.md | 64 +++++++++++++++++++ 1 file changed, 64 insertions(+) create mode 100644 docs/method/backlog/inbox/PLATFORM_reconcile-relocated-wesley-echo-schemas.md diff --git a/docs/method/backlog/inbox/PLATFORM_reconcile-relocated-wesley-echo-schemas.md b/docs/method/backlog/inbox/PLATFORM_reconcile-relocated-wesley-echo-schemas.md new file mode 100644 index 00000000..9cb485fe --- /dev/null +++ b/docs/method/backlog/inbox/PLATFORM_reconcile-relocated-wesley-echo-schemas.md @@ -0,0 +1,64 @@ + + + +# Reconcile Relocated Wesley Echo Schemas + +Status: inbox. + +## Why now + +During the Echo contract-hosting roadmap work, old Wesley-local Echo SDL files +appeared in an untracked `schemas/wesley-relocated/` directory. They described +Echo CAS-facing payloads and WASM ABI response shapes that had been removed +from generic Wesley during the domain-empty extraction. + +Those files were not retained as active Echo schema truth because they +duplicated and diverged from current Echo-owned sources: + +- current runtime schema fragments under `schemas/runtime/`; +- current WASM ABI DTOs under `crates/echo-wasm-abi`; +- current worldline/storage shapes under `crates/warp-core`; +- current registry boundaries under `echo-registry-api` and `echo-wesley-gen`. + +Carrying stale SDL under `schemas/` would make future agents treat old Wesley +artifacts as active schema authority. + +## What it should look like + +Create a reconciliation note or design packet that compares any old relocated +Wesley Echo schema material against current Echo truth. + +The packet should answer: + +- whether any old `@wes_codec` / `@wes_version` annotation ideas should become + current Echo schema policy; +- whether any CAS-facing payload shape should be re-authored under + `schemas/runtime/` or another Echo-owned schema family; +- whether `echo-wasm-abi` should ever get GraphQL SDL source, or stay + hand-authored Rust DTOs with spec docs; +- how `RegistryInfo.registry_version` should be represented across + `echo-wasm-abi` and `echo-registry-api`; +- whether old relocated SDL should be archived as historical reference, or left + only in Git/Wesley history. + +## Acceptance criteria + +- The packet cites current repo truth before citing old relocated material. +- No stale relocated SDL is committed under active `schemas/` paths. +- If old SDL is archived, it lives under an explicit non-authoritative archive + path and has a warning that it is stale reference only. +- If old SDL concepts are reused, they are re-authored into current schema or + code surfaces instead of copied forward blindly. +- The decision preserves the ownership split: + - Echo owns runtime, CAS, WASM ABI, and engine-specific schema truth. + - `warp-ttd` owns host-neutral debugger protocol truth. + - Continuum owns shared cross-engine contract-family truth. + - Wesley compiles owner-provided schemas; it does not own product schemas. + +## Non-goals + +- Do not restore `schemas/wesley-relocated/` as active schema truth. +- Do not duplicate current Rust DTOs as stale GraphQL SDL. +- Do not change ABI shapes in this card. +- Do not add generation plumbing in this card. +- Do not move `warp-ttd` or Continuum protocol schemas into Echo. From 8cef2fe7cf320932037de860ca0dcd4f99fb7b9c Mon Sep 17 00:00:00 2001 From: James Ross Date: Sun, 3 May 2026 18:11:08 -0700 Subject: [PATCH 08/21] feat: emit Wesley EINT observation helpers --- crates/echo-wesley-gen/src/main.rs | 70 +++++++++++++++++++ .../design.md | 49 +++++++++++-- ...TFORM_wesley-to-echo-toy-contract-proof.md | 15 +++- 3 files changed, 125 insertions(+), 9 deletions(-) diff --git a/crates/echo-wesley-gen/src/main.rs b/crates/echo-wesley-gen/src/main.rs index 1596cb30..05716171 100644 --- a/crates/echo-wesley-gen/src/main.rs +++ b/crates/echo-wesley-gen/src/main.rs @@ -152,8 +152,18 @@ fn generate_rust(ir: &WesleyIR, args: &Args) -> Result { tokens.extend(quote! { // Registry provider types (Echo runtime loads an app-supplied implementation). use echo_registry_api::{ArgDef, EnumDef, ObjectDef, OpDef, OpKind, RegistryInfo, RegistryProvider}; + use echo_wasm_abi::pack_intent_v1; }); + if ir.ops.iter().any(|op| op.kind == OpKind::Query) { + tokens.extend(quote! { + use echo_wasm_abi::kernel_port::{ + ObservationAt, ObservationCoordinate, ObservationFrame, ObservationProjection, + ObservationRequest, WorldlineId, + }; + }); + } + let mut enum_defs: Vec<_> = ir .types .iter() @@ -241,6 +251,41 @@ fn generate_rust(ir: &WesleyIR, args: &Args) -> Result { }); } + for op in &ops_sorted { + let const_name = op_const_ident(&op.name, op.op_id); + let helper_name = format_ident!("{}", to_snake_case(&op.name)); + match op.kind { + OpKind::Mutation => { + let fn_name = format_ident!("pack_{}_intent", helper_name); + tokens.extend(quote! { + /// Pack canonical vars bytes for this generated mutation into an EINT v1 intent. + pub fn #fn_name(vars: &[u8]) -> Result, echo_wasm_abi::EnvelopeError> { + pack_intent_v1(#const_name, vars) + } + }); + } + OpKind::Query => { + let fn_name = format_ident!("{}_observation_request", helper_name); + tokens.extend(quote! { + /// Build a frontier query-view observation request for this generated query. + pub fn #fn_name(worldline_id: WorldlineId, vars: &[u8]) -> ObservationRequest { + ObservationRequest { + coordinate: ObservationCoordinate { + worldline_id, + at: ObservationAt::Frontier, + }, + frame: ObservationFrame::QueryView, + projection: ObservationProjection::Query { + query_id: #const_name, + vars_bytes: Vec::from(vars), + }, + } + } + }); + } + } + } + // OPS table (sorted by op_id). let ops_entries = ops_sorted.iter().map(|op| { let kind = match op.kind { @@ -324,6 +369,31 @@ fn op_const_ident(name: &str, op_id: u32) -> proc_macro2::Ident { format_ident!("OP_{}", out) } +fn to_snake_case(name: &str) -> String { + let mut out = String::new(); + let mut previous_was_separator = true; + for (index, c) in name.chars().enumerate() { + if c.is_alphanumeric() { + if c.is_uppercase() && index > 0 && !previous_was_separator { + out.push('_'); + } + out.push(c.to_ascii_lowercase()); + previous_was_separator = false; + } else if !previous_was_separator { + out.push('_'); + previous_was_separator = true; + } + } + while out.ends_with('_') { + out.pop(); + } + if out.is_empty() { + "op".to_string() + } else { + out + } +} + fn validate_version(ir: &WesleyIR) -> Result<()> { const SUPPORTED: &str = "echo-ir/v1"; match ir.ir_version.as_deref() { diff --git a/docs/design/0016-wesley-to-echo-toy-contract-proof/design.md b/docs/design/0016-wesley-to-echo-toy-contract-proof/design.md index 0abd22f7..a011071b 100644 --- a/docs/design/0016-wesley-to-echo-toy-contract-proof/design.md +++ b/docs/design/0016-wesley-to-echo-toy-contract-proof/design.md @@ -17,7 +17,7 @@ Depends on: ## Status -RED. +GREEN 1. ## Hill @@ -91,21 +91,56 @@ generated toy contract output is missing first-consumer bridge: use echo_wasm_abi::pack_intent_v1; ``` +## GREEN 1 witness + +Implementation: + +- `echo-wesley-gen` now imports `pack_intent_v1(...)` when operations are + present. +- Mutation operations emit raw-vars helpers such as + `pack_increment_intent(vars)`. +- Query operations emit frontier query-view helpers such as + `counter_value_observation_request(worldline_id, vars)`. +- Query helpers use the existing `ObservationRequest`, + `ObservationFrame::QueryView`, and `ObservationProjection::Query` shape. + +Focused witness: + +```sh +cargo test -p echo-wesley-gen test_toy_contract_generates_eint_and_observation_helpers +``` + +Result: passed. + +Broader generator witness: + +```sh +cargo test -p echo-wesley-gen +cargo clippy -p echo-wesley-gen --all-targets -- -D warnings -D missing_docs +``` + +Result: passed. + ## GREEN direction -The first GREEN should stay inside `echo-wesley-gen` unless a narrow -observation-boundary RED proves a missing ABI field. +GREEN 1 stayed inside `echo-wesley-gen`. -Expected implementation shape: +Implemented shape: -- generate vars encoder helpers for operation arguments; - generate `pack__intent(...)` helpers that call `pack_intent_v1(OP_..., &vars)`; -- generate one read-helper shape for query ops that maps to - `ObservationRequest` if possible; +- generate read-helper shapes for query ops that map to `ObservationRequest`; - keep Echo core app-agnostic; - keep host-side generated payload validation deferred. +Still deferred: + +- typed vars encoders for operation argument structs; +- compiled generated output smoke test in a consumer crate; +- actual `dispatch_intent(...)` integration proof; +- actual `observe(...)` integration proof; +- registry metadata handshake proof against an installed kernel. + ## Non-goals - Do not add a second envelope. diff --git a/docs/method/backlog/up-next/PLATFORM_wesley-to-echo-toy-contract-proof.md b/docs/method/backlog/up-next/PLATFORM_wesley-to-echo-toy-contract-proof.md index 64deca7f..00807e0e 100644 --- a/docs/method/backlog/up-next/PLATFORM_wesley-to-echo-toy-contract-proof.md +++ b/docs/method/backlog/up-next/PLATFORM_wesley-to-echo-toy-contract-proof.md @@ -3,7 +3,7 @@ # Wesley To Echo Toy Contract Proof -Status: RED. +Status: GREEN 1. Depends on: @@ -42,7 +42,7 @@ read/observation path. ## Current RED -The current RED is documented in +The original RED is documented in [0016 - Wesley To Echo Toy Contract Proof](../../../design/0016-wesley-to-echo-toy-contract-proof/design.md). `echo-wesley-gen` already emits op constants, `OPS`, `GeneratedRegistry`, and @@ -50,6 +50,17 @@ The current RED is documented in validates/encodes operation vars, packs EINT v1, and maps a generated query/read helper to `observe(...)` / `ReadingEnvelope`. +## Current GREEN + +GREEN 1 emits raw-vars helpers from `echo-wesley-gen`: + +- mutation helpers pack EINT v1 with `pack_intent_v1(...)`; +- query helpers construct `ObservationRequest` using the existing query-view + projection. + +The next proof should compile or consume generated output in a real consumer +crate and then exercise `dispatch_intent(...)` / `observe(...)` directly. + ## Acceptance criteria - Wesley compiles the toy GraphQL contract to Echo-consumable Rust artifacts. From dbb90199acd1feb7d1c686f396be30f6f66fe2b8 Mon Sep 17 00:00:00 2001 From: James Ross Date: Sun, 3 May 2026 18:27:17 -0700 Subject: [PATCH 09/21] test: compile Wesley toy consumer bridge --- crates/echo-wesley-gen/tests/generation.rs | 283 ++++++++++++++++++ .../design.md | 31 +- ...TFORM_wesley-to-echo-toy-contract-proof.md | 16 +- 3 files changed, 325 insertions(+), 5 deletions(-) diff --git a/crates/echo-wesley-gen/tests/generation.rs b/crates/echo-wesley-gen/tests/generation.rs index 583e6e7b..840f8ae7 100644 --- a/crates/echo-wesley-gen/tests/generation.rs +++ b/crates/echo-wesley-gen/tests/generation.rs @@ -3,7 +3,9 @@ #![allow(clippy::unwrap_used, clippy::expect_used)] //! Integration test for the echo-wesley-gen CLI (Wesley IR -> Rust code). +use std::fs; use std::io::Write; +use std::path::{Path, PathBuf}; use std::process::{Command, Output, Stdio}; /// Spawns `cargo run -p echo-wesley-gen --`, pipes `ir` to stdin, and returns the output. @@ -25,6 +27,222 @@ fn run_wesley_gen(ir: &str) -> Output { child.wait_with_output().expect("failed to wait on child") } +fn workspace_root() -> PathBuf { + Path::new(env!("CARGO_MANIFEST_DIR")) + .ancestors() + .nth(2) + .expect("workspace root ancestor missing") + .to_path_buf() +} + +fn write_consumer_smoke_crate(generated: &str) -> PathBuf { + let workspace = workspace_root(); + let crate_dir = workspace + .join("target") + .join("echo-wesley-gen-consumer-smoke") + .join(std::process::id().to_string()); + if crate_dir.exists() { + fs::remove_dir_all(&crate_dir).expect("failed to remove old smoke crate"); + } + fs::create_dir_all(crate_dir.join("src")).expect("failed to create smoke crate"); + + let registry_path = workspace.join("crates/echo-registry-api"); + let wasm_abi_path = workspace.join("crates/echo-wasm-abi"); + fs::write( + crate_dir.join("Cargo.toml"), + format!( + r#"[package] +name = "echo-wesley-gen-consumer-smoke" +version = "0.0.0" +edition = "2021" +publish = false + +[workspace] + +[dependencies] +echo-registry-api = {{ path = "{}" }} +echo-wasm-abi = {{ path = "{}" }} +serde = {{ version = "1.0", features = ["derive"] }} +"#, + registry_path.display(), + wasm_abi_path.display() + ), + ) + .expect("failed to write smoke Cargo.toml"); + fs::write(crate_dir.join("src/generated.rs"), generated) + .expect("failed to write generated module"); + fs::write( + crate_dir.join("src/lib.rs"), + r#" +mod generated; + +#[cfg(test)] +mod tests { + use super::generated::{ + counter_value_observation_request, pack_increment_intent, CODEC_ID, OP_COUNTER_VALUE, + OP_INCREMENT, REGISTRY, REGISTRY_VERSION, SCHEMA_SHA256, + }; + use echo_registry_api::{OpKind, RegistryProvider}; + use echo_wasm_abi::kernel_port::{ + AbiError, BuiltinObserverPlan, DispatchResponse, KernelPort, ObservationArtifact, + ObservationAt, ObservationBasisPosture, ObservationFrame, ObservationPayload, + ObservationProjection, ReadingBudgetPosture, ReadingEnvelope, ReadingObserverBasis, + ReadingObserverPlan, ReadingResidualPosture, ReadingRightsPosture, ReadingWitnessRef, + RegistryInfo, ResolvedObservationCoordinate, RunCompletion, SchedulerState, + SchedulerStatus, WorkState, WorldlineId, WorldlineTick, ABI_VERSION, + }; + use echo_wasm_abi::unpack_intent_v1; + + #[derive(Default)] + struct ToyKernel { + accepted_intent_count: usize, + } + + fn idle_status() -> SchedulerStatus { + SchedulerStatus { + state: SchedulerState::Inactive, + active_mode: None, + work_state: WorkState::Quiescent, + run_id: None, + latest_cycle_global_tick: None, + latest_commit_global_tick: None, + last_quiescent_global_tick: None, + last_run_completion: Some(RunCompletion::Quiesced), + } + } + + impl KernelPort for ToyKernel { + fn dispatch_intent( + &mut self, + intent_bytes: &[u8], + ) -> Result { + let (op_id, vars) = unpack_intent_v1(intent_bytes).map_err(|error| AbiError { + code: 1, + message: error.to_string(), + })?; + assert_eq!(op_id, OP_INCREMENT); + assert_eq!(vars, &[0x2a]); + self.accepted_intent_count += 1; + Ok(DispatchResponse { + accepted: true, + intent_id: vec![7; 32], + scheduler_status: idle_status(), + }) + } + + fn observe( + &self, + request: echo_wasm_abi::kernel_port::ObservationRequest, + ) -> Result { + assert_eq!(request.frame, ObservationFrame::QueryView); + let ObservationProjection::Query { + query_id, + vars_bytes, + } = &request.projection + else { + panic!("expected query projection"); + }; + assert_eq!(*query_id, OP_COUNTER_VALUE); + assert_eq!(vars_bytes, &[0x01, 0x02]); + + let worldline_id = request.coordinate.worldline_id; + let state_root = vec![0; 32]; + let commit_hash = vec![1; 32]; + Ok(ObservationArtifact { + resolved: ResolvedObservationCoordinate { + observation_version: 1, + worldline_id, + requested_at: ObservationAt::Frontier, + resolved_worldline_tick: WorldlineTick::ZERO, + commit_global_tick: None, + observed_after_global_tick: None, + state_root: state_root.clone(), + commit_hash: commit_hash.clone(), + }, + reading: ReadingEnvelope { + observer_plan: ReadingObserverPlan::Builtin { + plan: BuiltinObserverPlan::QueryBytes, + }, + observer_basis: ReadingObserverBasis::QueryView, + witness_refs: vec![ReadingWitnessRef::EmptyFrontier { + worldline_id, + state_root, + commit_hash, + }], + parent_basis_posture: ObservationBasisPosture::Worldline, + budget_posture: ReadingBudgetPosture::UnboundedOneShot, + rights_posture: ReadingRightsPosture::KernelPublic, + residual_posture: ReadingResidualPosture::Complete, + }, + frame: request.frame, + projection: request.projection, + artifact_hash: vec![2; 32], + payload: ObservationPayload::QueryBytes { + data: b"counter=42".to_vec(), + }, + }) + } + + fn registry_info(&self) -> RegistryInfo { + RegistryInfo { + codec_id: Some(CODEC_ID.to_string()), + registry_version: Some(REGISTRY_VERSION.to_string()), + schema_sha256_hex: Some(SCHEMA_SHA256.to_string()), + abi_version: ABI_VERSION, + } + } + + fn scheduler_status(&self) -> Result { + Ok(idle_status()) + } + } + + #[test] + fn generated_contract_dispatches_and_observes_through_kernel_port() { + let registry_info = REGISTRY.info(); + assert_eq!(registry_info.codec_id, CODEC_ID); + assert_eq!(registry_info.registry_version, REGISTRY_VERSION); + assert_eq!(registry_info.schema_sha256_hex, SCHEMA_SHA256); + assert_eq!(REGISTRY.op_by_id(OP_INCREMENT).unwrap().kind, OpKind::Mutation); + assert_eq!(REGISTRY.op_by_id(OP_COUNTER_VALUE).unwrap().kind, OpKind::Query); + + let intent = pack_increment_intent(&[0x2a]).unwrap(); + let (op_id, vars) = unpack_intent_v1(&intent).unwrap(); + assert_eq!(op_id, OP_INCREMENT); + assert_eq!(vars, &[0x2a]); + + let mut kernel = ToyKernel::default(); + let response = KernelPort::dispatch_intent(&mut kernel, &intent).unwrap(); + assert!(response.accepted); + assert_eq!(kernel.accepted_intent_count, 1); + + let host_registry = KernelPort::registry_info(&kernel); + assert_eq!(host_registry.codec_id.as_deref(), Some(CODEC_ID)); + assert_eq!( + host_registry.registry_version.as_deref(), + Some(REGISTRY_VERSION.to_string().as_str()) + ); + assert_eq!(host_registry.schema_sha256_hex.as_deref(), Some(SCHEMA_SHA256)); + + let worldline_id = WorldlineId::from_bytes([9; 32]); + let request = counter_value_observation_request(worldline_id, &[0x01, 0x02]); + let artifact = KernelPort::observe(&kernel, request).unwrap(); + assert_eq!(artifact.frame, ObservationFrame::QueryView); + assert_eq!( + artifact.payload, + ObservationPayload::QueryBytes { + data: b"counter=42".to_vec() + } + ); + } +} +"#, + ) + .expect("failed to write smoke lib.rs"); + + crate_dir +} + #[test] fn test_generate_from_json() { let ir = r#"{ @@ -197,6 +415,71 @@ fn test_toy_contract_generates_eint_and_observation_helpers() { } } +#[test] +fn test_toy_contract_generated_output_compiles_in_consumer_crate() { + let ir = r#"{ + "ir_version": "echo-ir/v1", + "schema_sha256": "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef", + "codec_id": "cbor-canon-v1", + "registry_version": 1, + "types": [ + { + "name": "CounterValue", + "kind": "OBJECT", + "fields": [ + { "name": "value", "type": "Int", "required": true } + ] + }, + { + "name": "IncrementInput", + "kind": "INPUT_OBJECT", + "fields": [ + { "name": "amount", "type": "Int", "required": true } + ] + } + ], + "ops": [ + { + "kind": "MUTATION", + "name": "increment", + "op_id": 1001, + "args": [ + { "name": "input", "type": "IncrementInput", "required": true } + ], + "result_type": "CounterValue" + }, + { + "kind": "QUERY", + "name": "counterValue", + "op_id": 1002, + "args": [], + "result_type": "CounterValue" + } + ] + }"#; + + let output = run_wesley_gen(ir); + assert!( + output.status.success(), + "CLI failed: {}", + String::from_utf8_lossy(&output.stderr) + ); + let generated = String::from_utf8_lossy(&output.stdout); + let crate_dir = write_consumer_smoke_crate(&generated); + let output = Command::new("cargo") + .args(["test", "--manifest-path"]) + .arg(crate_dir.join("Cargo.toml")) + .output() + .expect("failed to run generated consumer smoke"); + + assert!( + output.status.success(), + "generated consumer smoke failed\nstdout:\n{}\nstderr:\n{}", + String::from_utf8_lossy(&output.stdout), + String::from_utf8_lossy(&output.stderr) + ); +} + #[test] fn test_generate_no_std_minicbor() { let ir = r#"{ diff --git a/docs/design/0016-wesley-to-echo-toy-contract-proof/design.md b/docs/design/0016-wesley-to-echo-toy-contract-proof/design.md index a011071b..71e00326 100644 --- a/docs/design/0016-wesley-to-echo-toy-contract-proof/design.md +++ b/docs/design/0016-wesley-to-echo-toy-contract-proof/design.md @@ -17,7 +17,7 @@ Depends on: ## Status -GREEN 1. +GREEN 2. ## Hill @@ -112,6 +112,31 @@ cargo test -p echo-wesley-gen test_toy_contract_generates_eint_and_observation_h Result: passed. +## GREEN 2 witness + +Implementation: + +- `echo-wesley-gen` now has a consumer smoke test that writes generated Rust + into a temporary standalone crate under `target/`. +- The smoke crate depends on local `echo-wasm-abi` and `echo-registry-api`. +- The smoke crate compiles the generated output as consumer code. +- The smoke crate exercises: + - generated `REGISTRY` metadata; + - generated `pack_increment_intent(...)`; + - EINT unpacking through `unpack_intent_v1(...)`; + - a toy `KernelPort::dispatch_intent(...)` implementation; + - generated `counter_value_observation_request(...)`; + - a toy `KernelPort::observe(...)` implementation returning query bytes. + +Focused witness: + +```sh +cargo test -p echo-wesley-gen \ + test_toy_contract_generated_output_compiles_in_consumer_crate +``` + +Result: passed. + Broader generator witness: ```sh @@ -136,11 +161,13 @@ Implemented shape: Still deferred: - typed vars encoders for operation argument structs; -- compiled generated output smoke test in a consumer crate; - actual `dispatch_intent(...)` integration proof; - actual `observe(...)` integration proof; - registry metadata handshake proof against an installed kernel. +The phrase "actual integration proof" now means an Echo-installed or +application-owned kernel path, not a generated-output compile proof. + ## Non-goals - Do not add a second envelope. diff --git a/docs/method/backlog/up-next/PLATFORM_wesley-to-echo-toy-contract-proof.md b/docs/method/backlog/up-next/PLATFORM_wesley-to-echo-toy-contract-proof.md index 00807e0e..f1aa0c0b 100644 --- a/docs/method/backlog/up-next/PLATFORM_wesley-to-echo-toy-contract-proof.md +++ b/docs/method/backlog/up-next/PLATFORM_wesley-to-echo-toy-contract-proof.md @@ -3,7 +3,7 @@ # Wesley To Echo Toy Contract Proof -Status: GREEN 1. +Status: GREEN 2. Depends on: @@ -58,8 +58,18 @@ GREEN 1 emits raw-vars helpers from `echo-wesley-gen`: - query helpers construct `ObservationRequest` using the existing query-view projection. -The next proof should compile or consume generated output in a real consumer -crate and then exercise `dispatch_intent(...)` / `observe(...)` directly. +GREEN 2 compiles generated output in a temporary standalone consumer crate and +exercises: + +- generated registry metadata; +- generated EINT packing; +- EINT unpacking; +- `KernelPort::dispatch_intent(...)`; +- generated query `ObservationRequest`; +- `KernelPort::observe(...)`. + +The next proof should wire the same generated surface into an installed Echo or +application-owned kernel path instead of a toy `KernelPort` implementation. ## Acceptance criteria From 80c1207e6becb1a5081d083296cd0efbc83745f4 Mon Sep 17 00:00:00 2001 From: James Ross Date: Sun, 3 May 2026 18:35:51 -0700 Subject: [PATCH 10/21] fix: canonicalize Wesley generated vars helpers --- crates/echo-wesley-gen/src/main.rs | 86 ++++++++++++++++++- crates/echo-wesley-gen/tests/generation.rs | 41 +++++++-- .../design.md | 52 ++++++++--- ...TFORM_wesley-to-echo-toy-contract-proof.md | 20 +++-- 4 files changed, 172 insertions(+), 27 deletions(-) diff --git a/crates/echo-wesley-gen/src/main.rs b/crates/echo-wesley-gen/src/main.rs index 05716171..7572c0db 100644 --- a/crates/echo-wesley-gen/src/main.rs +++ b/crates/echo-wesley-gen/src/main.rs @@ -164,6 +164,19 @@ fn generate_rust(ir: &WesleyIR, args: &Args) -> Result { }); } + if ir.ops.iter().any(|op| op.kind == OpKind::Mutation) { + tokens.extend(quote! { + /// Error produced while building a generated EINT intent. + #[derive(Debug)] + pub enum GeneratedIntentError { + /// Operation vars could not be encoded canonically. + EncodeVars(echo_wasm_abi::CanonError), + /// Encoded vars could not be packed into an EINT envelope. + PackEnvelope(echo_wasm_abi::EnvelopeError), + } + }); + } + let mut enum_defs: Vec<_> = ir .types .iter() @@ -254,21 +267,64 @@ fn generate_rust(ir: &WesleyIR, args: &Args) -> Result { for op in &ops_sorted { let const_name = op_const_ident(&op.name, op.op_id); let helper_name = format_ident!("{}", to_snake_case(&op.name)); + let vars_name = format_ident!("{}Vars", to_pascal_case(&op.name)); + let vars_fields = op.args.iter().map(|a| { + let field_name = safe_ident(&a.name); + let base_ty = map_type(&a.type_name, args); + let list_ty: TokenStream = if a.list { + quote! { Vec<#base_ty> } + } else { + quote! { #base_ty } + }; + + if a.required { + quote! { pub #field_name: #list_ty } + } else { + quote! { pub #field_name: Option<#list_ty> } + } + }); + let encode_fn_name = format_ident!("encode_{}_vars", helper_name); + tokens.extend(quote! { + /// Canonical vars payload for this generated operation. + #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] + pub struct #vars_name { + #(#vars_fields),* + } + + /// Encode this operation's vars using Echo canonical CBOR. + pub fn #encode_fn_name(vars: &#vars_name) -> Result, echo_wasm_abi::CanonError> { + echo_wasm_abi::encode_cbor(vars) + } + }); match op.kind { OpKind::Mutation => { let fn_name = format_ident!("pack_{}_intent", helper_name); + let raw_fn_name = format_ident!("pack_{}_intent_raw_vars", helper_name); tokens.extend(quote! { - /// Pack canonical vars bytes for this generated mutation into an EINT v1 intent. - pub fn #fn_name(vars: &[u8]) -> Result, echo_wasm_abi::EnvelopeError> { + /// Encode this mutation's vars and pack them into an EINT v1 intent. + pub fn #fn_name(vars: &#vars_name) -> Result, GeneratedIntentError> { + let vars_bytes = #encode_fn_name(vars).map_err(GeneratedIntentError::EncodeVars)?; + pack_intent_v1(#const_name, &vars_bytes).map_err(GeneratedIntentError::PackEnvelope) + } + + /// Pack already-canonical vars bytes for this generated mutation into EINT v1. + pub fn #raw_fn_name(vars: &[u8]) -> Result, echo_wasm_abi::EnvelopeError> { pack_intent_v1(#const_name, vars) } }); } OpKind::Query => { let fn_name = format_ident!("{}_observation_request", helper_name); + let raw_fn_name = format_ident!("{}_observation_request_raw_vars", helper_name); tokens.extend(quote! { - /// Build a frontier query-view observation request for this generated query. - pub fn #fn_name(worldline_id: WorldlineId, vars: &[u8]) -> ObservationRequest { + /// Encode this query's vars and build a frontier query-view observation request. + pub fn #fn_name(worldline_id: WorldlineId, vars: &#vars_name) -> Result { + let vars_bytes = #encode_fn_name(vars)?; + Ok(#raw_fn_name(worldline_id, &vars_bytes)) + } + + /// Build a frontier query-view request from already-canonical vars bytes. + pub fn #raw_fn_name(worldline_id: WorldlineId, vars: &[u8]) -> ObservationRequest { ObservationRequest { coordinate: ObservationCoordinate { worldline_id, @@ -369,6 +425,28 @@ fn op_const_ident(name: &str, op_id: u32) -> proc_macro2::Ident { format_ident!("OP_{}", out) } +fn to_pascal_case(name: &str) -> String { + let mut out = String::new(); + let mut capitalize_next = true; + for c in name.chars() { + if c.is_alphanumeric() { + if capitalize_next { + out.push(c.to_ascii_uppercase()); + capitalize_next = false; + } else { + out.push(c); + } + } else { + capitalize_next = true; + } + } + if out.is_empty() { + "Op".to_string() + } else { + out + } +} + fn to_snake_case(name: &str) -> String { let mut out = String::new(); let mut previous_was_separator = true; diff --git a/crates/echo-wesley-gen/tests/generation.rs b/crates/echo-wesley-gen/tests/generation.rs index 840f8ae7..9d84ceac 100644 --- a/crates/echo-wesley-gen/tests/generation.rs +++ b/crates/echo-wesley-gen/tests/generation.rs @@ -79,8 +79,10 @@ mod generated; #[cfg(test)] mod tests { use super::generated::{ - counter_value_observation_request, pack_increment_intent, CODEC_ID, OP_COUNTER_VALUE, - OP_INCREMENT, REGISTRY, REGISTRY_VERSION, SCHEMA_SHA256, + counter_value_observation_request, counter_value_observation_request_raw_vars, + encode_counter_value_vars, pack_increment_intent, CounterValueVars, IncrementInput, + IncrementVars, CODEC_ID, OP_COUNTER_VALUE, OP_INCREMENT, REGISTRY, REGISTRY_VERSION, + SCHEMA_SHA256, }; use echo_registry_api::{OpKind, RegistryProvider}; use echo_wasm_abi::kernel_port::{ @@ -91,7 +93,7 @@ mod tests { RegistryInfo, ResolvedObservationCoordinate, RunCompletion, SchedulerState, SchedulerStatus, WorkState, WorldlineId, WorldlineTick, ABI_VERSION, }; - use echo_wasm_abi::unpack_intent_v1; + use echo_wasm_abi::{decode_cbor, unpack_intent_v1}; #[derive(Default)] struct ToyKernel { @@ -121,7 +123,11 @@ mod tests { message: error.to_string(), })?; assert_eq!(op_id, OP_INCREMENT); - assert_eq!(vars, &[0x2a]); + let decoded: IncrementVars = decode_cbor(vars).map_err(|error| AbiError { + code: 2, + message: error.to_string(), + })?; + assert_eq!(decoded.input.amount, 42); self.accepted_intent_count += 1; Ok(DispatchResponse { accepted: true, @@ -143,7 +149,11 @@ mod tests { panic!("expected query projection"); }; assert_eq!(*query_id, OP_COUNTER_VALUE); - assert_eq!(vars_bytes, &[0x01, 0x02]); + let _decoded: CounterValueVars = + decode_cbor(vars_bytes).map_err(|error| AbiError { + code: 3, + message: error.to_string(), + })?; let worldline_id = request.coordinate.worldline_id; let state_root = vec![0; 32]; @@ -206,10 +216,14 @@ mod tests { assert_eq!(REGISTRY.op_by_id(OP_INCREMENT).unwrap().kind, OpKind::Mutation); assert_eq!(REGISTRY.op_by_id(OP_COUNTER_VALUE).unwrap().kind, OpKind::Query); - let intent = pack_increment_intent(&[0x2a]).unwrap(); + let intent = pack_increment_intent(&IncrementVars { + input: IncrementInput { amount: 42 }, + }) + .unwrap(); let (op_id, vars) = unpack_intent_v1(&intent).unwrap(); assert_eq!(op_id, OP_INCREMENT); - assert_eq!(vars, &[0x2a]); + let decoded: IncrementVars = decode_cbor(vars).unwrap(); + assert_eq!(decoded.input.amount, 42); let mut kernel = ToyKernel::default(); let response = KernelPort::dispatch_intent(&mut kernel, &intent).unwrap(); @@ -225,7 +239,12 @@ mod tests { assert_eq!(host_registry.schema_sha256_hex.as_deref(), Some(SCHEMA_SHA256)); let worldline_id = WorldlineId::from_bytes([9; 32]); - let request = counter_value_observation_request(worldline_id, &[0x01, 0x02]); + let query_vars = CounterValueVars {}; + let encoded_query_vars = encode_counter_value_vars(&query_vars).unwrap(); + let request = counter_value_observation_request(worldline_id, &query_vars).unwrap(); + let raw_request = + counter_value_observation_request_raw_vars(worldline_id, &encoded_query_vars); + assert_eq!(request, raw_request); let artifact = KernelPort::observe(&kernel, request).unwrap(); assert_eq!(artifact.frame, ObservationFrame::QueryView); assert_eq!( @@ -404,9 +423,15 @@ fn test_toy_contract_generates_eint_and_observation_helpers() { for required in [ "use echo_wasm_abi::pack_intent_v1;", + "pub struct IncrementVars", + "pub struct CounterValueVars", + "pub fn encode_increment_vars", + "pub fn encode_counter_value_vars", "pub fn pack_increment_intent", + "pub fn pack_increment_intent_raw_vars", "pack_intent_v1(OP_INCREMENT", "pub fn counter_value_observation_request", + "pub fn counter_value_observation_request_raw_vars", ] { assert!( stdout.contains(required), diff --git a/docs/design/0016-wesley-to-echo-toy-contract-proof/design.md b/docs/design/0016-wesley-to-echo-toy-contract-proof/design.md index 71e00326..6746d456 100644 --- a/docs/design/0016-wesley-to-echo-toy-contract-proof/design.md +++ b/docs/design/0016-wesley-to-echo-toy-contract-proof/design.md @@ -17,7 +17,7 @@ Depends on: ## Status -GREEN 2. +GREEN 3. ## Hill @@ -93,13 +93,13 @@ use echo_wasm_abi::pack_intent_v1; ## GREEN 1 witness -Implementation: +Historical implementation, superseded by GREEN 3: - `echo-wesley-gen` now imports `pack_intent_v1(...)` when operations are present. -- Mutation operations emit raw-vars helpers such as +- Mutation operations originally emitted raw-vars helpers such as `pack_increment_intent(vars)`. -- Query operations emit frontier query-view helpers such as +- Query operations originally emitted frontier query-view helpers such as `counter_value_observation_request(worldline_id, vars)`. - Query helpers use the existing `ObservationRequest`, `ObservationFrame::QueryView`, and `ObservationProjection::Query` shape. @@ -137,6 +137,36 @@ cargo test -p echo-wesley-gen \ Result: passed. +## GREEN 3 witness + +Implementation: + +- `echo-wesley-gen` now emits per-operation vars structs such as + `IncrementVars` and `CounterValueVars`. +- Each generated operation receives a canonical vars encoder such as + `encode_increment_vars(...)`. +- Ergonomic mutation helpers now accept generated vars structs, encode them + with Echo canonical CBOR, and then pack EINT v1. +- Ergonomic query helpers now accept generated vars structs, encode them with + Echo canonical CBOR, and then build `ObservationRequest`. +- Raw-vars helpers remain available only under explicit names such as + `pack_increment_intent_raw_vars(...)` and + `counter_value_observation_request_raw_vars(...)`. + +Focused witness: + +```sh +cargo test -p echo-wesley-gen \ + test_toy_contract_generated_output_compiles_in_consumer_crate +``` + +The smoke kernel now decodes generated EINT vars and query vars through +`decode_cbor(...)` before asserting the app-level contract values. This closes +the accidental nondeterminism seam where the app-facing helper accepted +arbitrary raw vars bytes. + +Result: passed. + Broader generator witness: ```sh @@ -148,21 +178,23 @@ Result: passed. ## GREEN direction -GREEN 1 stayed inside `echo-wesley-gen`. +GREEN stayed inside `echo-wesley-gen`. Implemented shape: -- generate `pack__intent(...)` helpers that call - `pack_intent_v1(OP_..., &vars)`; +- generate typed operation vars structs and canonical vars encoders; +- generate `pack__intent(...)` helpers that canonicalize typed vars + before calling `pack_intent_v1(OP_..., &vars)`; +- keep explicit raw-vars helpers for plumbing callers that already hold + canonical vars bytes; - generate read-helper shapes for query ops that map to `ObservationRequest`; - keep Echo core app-agnostic; - keep host-side generated payload validation deferred. Still deferred: -- typed vars encoders for operation argument structs; -- actual `dispatch_intent(...)` integration proof; -- actual `observe(...)` integration proof; +- installed-kernel `dispatch_intent(...)` integration proof; +- installed-kernel `observe(...)` integration proof; - registry metadata handshake proof against an installed kernel. The phrase "actual integration proof" now means an Echo-installed or diff --git a/docs/method/backlog/up-next/PLATFORM_wesley-to-echo-toy-contract-proof.md b/docs/method/backlog/up-next/PLATFORM_wesley-to-echo-toy-contract-proof.md index f1aa0c0b..3a3f1a1b 100644 --- a/docs/method/backlog/up-next/PLATFORM_wesley-to-echo-toy-contract-proof.md +++ b/docs/method/backlog/up-next/PLATFORM_wesley-to-echo-toy-contract-proof.md @@ -3,7 +3,7 @@ # Wesley To Echo Toy Contract Proof -Status: GREEN 2. +Status: GREEN 3. Depends on: @@ -52,13 +52,13 @@ helper to `observe(...)` / `ReadingEnvelope`. ## Current GREEN -GREEN 1 emits raw-vars helpers from `echo-wesley-gen`: +GREEN 1 emitted raw-vars helpers from `echo-wesley-gen`: - mutation helpers pack EINT v1 with `pack_intent_v1(...)`; - query helpers construct `ObservationRequest` using the existing query-view projection. -GREEN 2 compiles generated output in a temporary standalone consumer crate and +GREEN 2 compiled generated output in a temporary standalone consumer crate and exercises: - generated registry metadata; @@ -68,6 +68,16 @@ exercises: - generated query `ObservationRequest`; - `KernelPort::observe(...)`. +GREEN 3 hardens the generated app-facing helper surface: + +- generated operations now receive typed vars structs; +- generated vars are encoded through Echo canonical CBOR before EINT packing or + observation request construction; +- raw-vars helpers remain available only through explicit `_raw_vars` names for + callers that already hold canonical vars bytes; +- the consumer smoke kernel decodes generated vars before asserting app-level + values. + The next proof should wire the same generated surface into an installed Echo or application-owned kernel path instead of a toy `KernelPort` implementation. @@ -76,8 +86,8 @@ application-owned kernel path instead of a toy `KernelPort` implementation. - Wesley compiles the toy GraphQL contract to Echo-consumable Rust artifacts. - `echo-wesley-gen` emits op ids, op catalog metadata, and a generated `RegistryProvider`. -- The consumer proof uses `pack_intent_v1(...)` with a generated op id and vars - payload. +- The consumer proof uses a generated typed vars helper that canonicalizes app + vars before calling `pack_intent_v1(...)` with a generated op id. - `dispatch_intent(...)` admits one valid toy intent. - Registry metadata from the installed kernel or app bundle matches the generated schema and codec metadata. From 340af963d4f574e70fe9465667d00cd8fe56e0e6 Mon Sep 17 00:00:00 2001 From: James Ross Date: Sun, 3 May 2026 20:00:07 -0700 Subject: [PATCH 11/21] docs: explain application contract hosting --- docs/.vitepress/config.ts | 79 ++- .../application-contract-hosting.md | 495 ++++++++++++++++++ docs/index.md | 2 + 3 files changed, 552 insertions(+), 24 deletions(-) create mode 100644 docs/architecture/application-contract-hosting.md diff --git a/docs/.vitepress/config.ts b/docs/.vitepress/config.ts index f3255d07..ce40cc88 100644 --- a/docs/.vitepress/config.ts +++ b/docs/.vitepress/config.ts @@ -27,30 +27,61 @@ export default defineConfig({ ], sidebar: { "/": [ - { text: "Overview", items: [ - { text: "Docs Map", link: "/" }, - { text: "Runtime Model", link: "/architecture/outline" }, - { text: "Theory Map", link: "/theory/THEORY" }, - { text: "Current Bearing", link: "/BEARING" }, - ] }, - { text: "Kernel Specs", items: [ - { text: "warp-core", link: "/spec/warp-core" }, - { text: "Attachment Atoms", link: "/spec/SPEC-0001-attachment-plane-v0-atoms" }, - { text: "Descended Attachments", link: "/spec/SPEC-0002-descended-attachments-v1" }, - { text: "DPO Litmus", link: "/spec/SPEC-0003-dpo-concurrency-litmus-v0" }, - { text: "Scheduler", link: "/spec/scheduler-warp-core" }, - { text: "Tick Patch", link: "/spec/warp-tick-patch" }, - { text: "Merkle Commit", link: "/spec/merkle-commit" }, - { text: "Canonical Inbox", link: "/spec/canonical-inbox-sequencing" }, - ] }, - { text: "Platform Specs", items: [ - { text: "Worldlines + Observation", link: "/spec/SPEC-0004-worldlines-playback-truthbus" }, - { text: "Provenance Payload", link: "/spec/SPEC-0005-provenance-payload" }, - { text: "WASM ABI", link: "/spec/SPEC-0009-wasm-abi" }, - { text: "JS/CBOR Mapping", link: "/spec/js-cbor-mapping" }, - { text: "ABI Golden Vectors", link: "/spec/abi-golden-vectors" }, - { text: "WARP View Protocol", link: "/spec/warp-view-protocol" }, - ] }, + { + text: "Overview", + items: [ + { text: "Docs Map", link: "/" }, + { text: "Runtime Model", link: "/architecture/outline" }, + { + text: "Application Contract Hosting", + link: "/architecture/application-contract-hosting", + }, + { text: "Theory Map", link: "/theory/THEORY" }, + { text: "Current Bearing", link: "/BEARING" }, + ], + }, + { + text: "Kernel Specs", + items: [ + { text: "warp-core", link: "/spec/warp-core" }, + { + text: "Attachment Atoms", + link: "/spec/SPEC-0001-attachment-plane-v0-atoms", + }, + { + text: "Descended Attachments", + link: "/spec/SPEC-0002-descended-attachments-v1", + }, + { + text: "DPO Litmus", + link: "/spec/SPEC-0003-dpo-concurrency-litmus-v0", + }, + { text: "Scheduler", link: "/spec/scheduler-warp-core" }, + { text: "Tick Patch", link: "/spec/warp-tick-patch" }, + { text: "Merkle Commit", link: "/spec/merkle-commit" }, + { + text: "Canonical Inbox", + link: "/spec/canonical-inbox-sequencing", + }, + ], + }, + { + text: "Platform Specs", + items: [ + { + text: "Worldlines + Observation", + link: "/spec/SPEC-0004-worldlines-playback-truthbus", + }, + { + text: "Provenance Payload", + link: "/spec/SPEC-0005-provenance-payload", + }, + { text: "WASM ABI", link: "/spec/SPEC-0009-wasm-abi" }, + { text: "JS/CBOR Mapping", link: "/spec/js-cbor-mapping" }, + { text: "ABI Golden Vectors", link: "/spec/abi-golden-vectors" }, + { text: "WARP View Protocol", link: "/spec/warp-view-protocol" }, + ], + }, ], }, }, diff --git a/docs/architecture/application-contract-hosting.md b/docs/architecture/application-contract-hosting.md new file mode 100644 index 00000000..da7533ff --- /dev/null +++ b/docs/architecture/application-contract-hosting.md @@ -0,0 +1,495 @@ + + + +# Application Contract Hosting + +This page explains how applications use Echo without turning Echo into an +application framework. + +Echo is a deterministic witnessed causal substrate. Applications own product +semantics. Wesley compiles authored GraphQL contracts into generated Rust code +that can talk to Echo through generic intent and observation boundaries. + +The short version: + +```text +Application UI / adapter + -> Wesley-generated contract client + -> canonical contract operation variables + -> EINT v1 intent bytes + -> Echo dispatch_intent(...) + -> Echo causal ingress, scheduling, admission, receipts + -> Echo observe(...) + -> ReadingEnvelope + payload bytes + -> generated/application decoding + -> UI +``` + +## Core Rule + +Echo must not gain privileged application nouns. + +Names such as `ReplaceRange`, `JeditBuffer`, `RenameSymbol`, +`DeadSymbols`, `GraftProjection`, or `CounterIncrement` may appear in authored +contracts, Wesley-generated code, tests for generated families, application +adapters, and product documentation. They must not become Echo substrate APIs. + +Echo-owned APIs stay generic: + +- dispatch canonical intent bytes; +- observe runtime readings; +- retain artifacts; +- admit witnessed suffixes; +- settle strands; +- expose receipts, frontiers, readings, and witness references. + +The design evidence for this boundary lives in these repo-local packets: + +- `docs/design/0013-wesley-compiled-contract-hosting-doctrine/design.md` +- `docs/design/0014-eint-registry-observation-boundary-inventory/design.md` +- `docs/design/0015-registry-provider-host-boundary-decision/design.md` +- `docs/design/0016-wesley-to-echo-toy-contract-proof/design.md` + +## Ownership Split + +Echo, contracts, and applications have different jobs. + +```mermaid +flowchart TB + app["Application"] + contract["Authored contract"] + wesley["Wesley compiler"] + generated["Generated Rust client and registry"] + echo["Echo substrate"] + cas["echo-cas"] + + app -->|"owns UI, workflows, product policy"| contract + contract -->|"declares domain nouns, ops, reads"| wesley + wesley -->|"emits DTOs, codecs, op ids, registry"| generated + generated -->|"packs EINT, builds ObservationRequest"| echo + echo -->|"admits, schedules, witnesses, observes"| cas + cas -->|"stores retained content, witnesses, cached readings"| echo + + echo -. "does not own app nouns" .-> app +``` + +Echo owns: + +- deterministic scheduling; +- basis and frontier handling; +- admission outcome algebra; +- witnessed transition receipts; +- observer-relative reading envelopes; +- witness and retained artifact references; +- `echo-cas` retention policy; +- strand, braid, import, and suffix admission substrate; +- generic ABI entrypoints such as `dispatch_intent(...)` and `observe(...)`. + +Contracts own: + +- domain nouns; +- domain payload types; +- operation kinds; +- observer or read kinds; +- domain validation; +- domain transition law; +- domain emission law; +- domain-specific reading payloads. + +Applications own: + +- product workflows; +- UI and interaction policy; +- adapters around generated clients; +- application-specific persistence and save/open behavior where applicable; +- decisions about which contract operations to expose to users. + +## Vocabulary + +Use precise names at the boundary. + +**Contract operation variables** are typed values generated from a contract +operation. Example: `IncrementVars { input: IncrementInput { amount: 42 } }`. + +**Canonical vars bytes** are the deterministic canonical-CBOR encoding of +contract operation variables. + +**Raw vars bytes** are bytes that a low-level caller claims are already +canonical. Raw-vars helpers are plumbing surfaces, not the default application +surface. + +**EINT v1** is Echo's current intent envelope: + +```text +"EINT" || op_id:u32le || vars_len:u32le || vars +``` + +**ObservationRequest** is the generic read request. Generated query helpers map +contract query operations onto this request shape when possible. + +**ReadingEnvelope** is the read-side evidence envelope. It carries observer +plan, basis, witness refs, budget posture, rights posture, and residual, +plural, or obstructed posture. + +## Write Path + +Applications write to Echo by sending canonical intents. + +The application should not hand-roll EINT bytes. It should use generated +contract helpers. + +```mermaid +sequenceDiagram + participant UI as Application UI + participant Gen as Wesley-generated client + participant ABI as echo-wasm-abi + participant Echo as Echo KernelPort + participant Runtime as Echo runtime + + UI->>Gen: build typed contract operation variables + Gen->>ABI: encode_cbor(contract operation variables) + ABI-->>Gen: canonical vars bytes + Gen->>ABI: pack_intent_v1(op_id, vars bytes) + ABI-->>Gen: EINT v1 bytes + Gen->>Echo: dispatch_intent(EINT bytes) + Echo->>Runtime: ingest canonical causal input + Runtime-->>Echo: accepted/duplicate + scheduler status + Echo-->>Gen: DispatchResponse + Gen-->>UI: application-level result handling +``` + +For a toy mutation: + +```graphql +mutation increment(input: IncrementInput): CounterValue +``` + +the generated Rust shape is conceptually: + +```rust +let intent = pack_increment_intent(&IncrementVars { + input: IncrementInput { amount: 42 }, +})?; +``` + +The generated helper performs the deterministic boundary work: + +```text +IncrementVars + -> encode_cbor(...) + -> canonical vars bytes + -> pack_intent_v1(OP_INCREMENT, &vars_bytes) + -> EINT v1 bytes +``` + +Echo receives the EINT bytes. Echo does not need to know that the operation was +called `increment` or that the payload contained an `IncrementInput`. That +meaning belongs to the generated contract layer and the application. + +## Dispatch Is Not A Function Call + +`dispatch_intent(...)` means: + +```text +submit canonical causal input +``` + +It does not mean: + +```text +call this application method synchronously and mutate a hidden global state +``` + +Echo returns a `DispatchResponse` that says whether the intent was newly +accepted, names the content-addressed intent id, and reports scheduler status. +The application should treat that response as ingress evidence, not as a +domain-specific result object. + +## Read Path + +Applications read from Echo by observing. + +Generated query helpers should construct `ObservationRequest` values, call +`observe(...)`, verify enough of the returned `ReadingEnvelope`, and decode the +payload bytes according to the generated contract. + +```mermaid +sequenceDiagram + participant UI as Application UI + participant Gen as Wesley-generated client + participant ABI as echo-wasm-abi + participant Echo as Echo KernelPort + participant Runtime as Echo runtime + + UI->>Gen: request generated query + Gen->>ABI: encode_cbor(query variables) + ABI-->>Gen: canonical query vars bytes + Gen->>Gen: build ObservationRequest + Gen->>ABI: encode_cbor(ObservationRequest) + ABI-->>Gen: request bytes + Gen->>Echo: observe(request bytes) + Echo->>Runtime: resolve coordinate, frame, projection + Runtime-->>Echo: ObservationArtifact + Echo-->>Gen: ReadingEnvelope + payload bytes + Gen->>Gen: verify reading posture and decode payload + Gen-->>UI: generated query result +``` + +For a generated query, the projection currently uses: + +```rust +ObservationProjection::Query { + query_id, + vars_bytes, +} +``` + +The returned artifact is not just data. It includes: + +- resolved coordinate; +- reading envelope; +- declared frame; +- declared projection; +- artifact hash; +- payload. + +The application should inspect the reading posture before presenting a result +as complete. A reading may be complete, residual, plurality-preserving, +obstructed, budget-limited, or rights-limited. + +## Registry Handshake + +Applications need to know whether their generated client matches the installed +host. + +Echo already exposes registry metadata surfaces: + +- `get_registry_info`; +- `get_codec_id`; +- `get_registry_version`; +- `get_schema_sha256_hex`. + +Wesley-generated code already exposes generated registry information: + +- operation ids; +- `OPS`; +- `op_by_id(...)`; +- enum and object descriptors; +- static `REGISTRY`. + +The first handshake is intentionally small: + +```mermaid +flowchart LR + generated["Generated client registry"] + host["Installed Echo host registry info"] + decision{"schema, codec, registry, ABI match?"} + dispatch["allow generated dispatch and observe"] + reject["refuse this generated client"] + + generated --> decision + host --> decision + decision -->|"yes"| dispatch + decision -->|"no"| reject +``` + +For the current first-consumer path, generated application code validates the +operation shape and variables before dispatch. Echo validates EINT shape and +reserved control-op usage. Host-side generated-payload validation is deferred +until a RED proves that Echo itself must reject malformed app payloads at the +host boundary. + +## Determinism Boundary + +Applications may observe nondeterministic host events. Echo must not let hidden +nondeterminism cross into deterministic execution. + +Allowed pattern: + +```text +sample outside Echo + -> make the sampled value explicit contract input + -> canonicalize it + -> dispatch it + -> witness it +``` + +Forbidden pattern: + +```text +contract/runtime execution secretly reads time, random, env, filesystem, +host map iteration order, or other nondeterministic state +``` + +```mermaid +flowchart TB + host["Host/UI nondeterminism"] + sample["Explicit sampled value"] + typed["Typed contract operation variables"] + canon["Canonical CBOR bytes"] + echo["Echo deterministic boundary"] + hidden["Hidden runtime nondeterminism"] + + host -->|"user input, file picker, clock sampled by app"| sample + sample --> typed + typed --> canon + canon --> echo + + hidden -. "not allowed" .-> echo +``` + +If an application needs time or randomness, it must turn that value into an +explicit input: + +```text +InsertTimestamp { timestamp: fixed value chosen by host } +GenerateId { id: fixed value chosen by host } +UseSeed { seed: fixed value chosen by host } +``` + +Once sampled and dispatched, the value is part of witnessed causal history. It +is no longer hidden ambient state. + +## echo-cas And Cached Readings + +`echo-cas` stores content-addressed bytes. It may retain witnesses, payloads, +and cached materialized readings. + +CAS content hashes are not semantic truth by themselves. Meaning lives in the +typed coordinate or reference above the CAS blob. + +```mermaid +flowchart TB + history["Witnessed causal history"] + optic["Observer / optic / read law"] + reading["Materialized reading"] + key["Honest reading coordinate"] + cas["echo-cas blob"] + + history --> optic + optic --> reading + reading --> key + reading --> cas + key -->|"worldline, frontier, observer, aperture, law, projection"| cas + + cas -. "content only; not ontology" .-> history +``` + +A cached materialized reading is valid only relative to its basis, frontier, +observer, aperture, projection, and law. Cached readings are useful. They are +not the canonical runtime state. + +## Browser Or WASM Usage + +A browser-hosted application should follow this shape: + +1. Load Echo WASM. +2. Initialize or install a kernel. +3. Check registry metadata against the generated client. +4. Use generated Wesley helpers to build typed operation variables. +5. Pack an EINT intent through generated helpers. +6. Call `dispatch_intent(intent_bytes)`. +7. Decode `DispatchResponse`. +8. Use generated query helpers to build `ObservationRequest`. +9. Canonically encode the request. +10. Call `observe(request_bytes)`. +11. Decode `ObservationArtifact`. +12. Inspect the `ReadingEnvelope`. +13. Decode payload bytes into generated result types. +14. Render the UI. + +The UI can be highly application-specific. The Echo calls remain generic. + +## Native Rust Usage + +A native Rust consumer can operate against `KernelPort` directly: + +```rust +let intent = generated::pack_increment_intent(&generated::IncrementVars { + input: generated::IncrementInput { amount: 42 }, +})?; + +let response = echo_wasm_abi::kernel_port::KernelPort::dispatch_intent( + &mut kernel, + &intent, +)?; + +let request = generated::counter_value_observation_request( + worldline_id, + &generated::CounterValueVars {}, +)?; + +let artifact = + echo_wasm_abi::kernel_port::KernelPort::observe(&kernel, request)?; +``` + +The generated names differ by contract. Echo still receives only generic +intent bytes and observation requests. + +## What Echo Does Not Do + +Echo does not: + +- run GraphQL directly; +- own application domain types; +- expose jedit, text editing, Graft, game, or debugger-specific APIs; +- dynamically load arbitrary contract families yet; +- validate every generated operation payload in core yet; +- decode query result bytes into domain result objects for the application; +- treat cached materialized state as substrate truth. + +Those are generated-contract, application, or future host-integration +responsibilities. + +## Clean Mental Model + +```mermaid +flowchart LR + app["Application: user intent and UI"] + gen["Generated contract: schema, op ids, codecs"] + abi["Echo ABI: canonical bytes and requests"] + runtime["Echo runtime: causal admission and observation"] + reading["ReadingEnvelope: evidence posture"] + app2["Application: present result"] + + app --> gen + gen --> abi + abi --> runtime + runtime --> reading + reading --> app2 +``` + +In words: + +```text +Application: + I know what the user wants. + +Generated Wesley code: + I know the contract schema and how to encode/decode operations. + +Echo ABI: + I accept canonical intent bytes and observation requests. + +Echo runtime: + I admit, schedule, witness, retain, and observe causal history. + +ReadingEnvelope: + I tell you what kind of reading this was and what evidence posture it has. + +Application: + I decide how to present that reading to the user. +``` + +For a `jedit`-style application: + +```text +jedit owns text/editor semantics. +Wesley compiles those semantics into generated contract types and helpers. +Echo receives canonical intents and emits witnessed readings. +jedit renders buffers, cursors, diffs, diagnostics, history, and UI. +``` + +Echo gives applications deterministic causal substrate, witnessed ingress, +observation envelopes, registry identity, and retention hooks. It should not +become the application. diff --git a/docs/index.md b/docs/index.md index 110a6f29..8a138d6b 100644 --- a/docs/index.md +++ b/docs/index.md @@ -8,6 +8,7 @@ Echo's live documentation centers on the runtime carrier, the retained witnesses ## Start Here - Runtime model: [/architecture/outline](/architecture/outline) +- Application contract hosting: [/architecture/application-contract-hosting](/architecture/application-contract-hosting) - Theory map: [/theory/THEORY](/theory/THEORY) - Current bearing: [/BEARING](/BEARING) - WARP core runtime: [/spec/warp-core](/spec/warp-core) @@ -31,6 +32,7 @@ Echo's live documentation centers on the runtime carrier, the retained witnesses ## Observation And Platform Boundaries +- Application contract hosting: [/architecture/application-contract-hosting](/architecture/application-contract-hosting) - Worldlines, playback, and observation: [/spec/SPEC-0004-worldlines-playback-truthbus](/spec/SPEC-0004-worldlines-playback-truthbus) - Provenance payload and boundary records: [/spec/SPEC-0005-provenance-payload](/spec/SPEC-0005-provenance-payload) - WASM ABI contract: [/spec/SPEC-0009-wasm-abi](/spec/SPEC-0009-wasm-abi) From 0c5f580c9c0964be1cfc14fe77fadb1dee375ab3 Mon Sep 17 00:00:00 2001 From: James Ross Date: Sun, 3 May 2026 21:52:13 -0700 Subject: [PATCH 12/21] test: extract Wesley toy counter fixture --- .../tests/fixtures/toy-counter/README.md | 29 +++++ .../fixtures/toy-counter/echo-ir-v1.json | 74 +++++++++++++ crates/echo-wesley-gen/tests/generation.rs | 102 +----------------- .../design.md | 29 ++++- ...TFORM_wesley-to-echo-toy-contract-proof.md | 10 +- 5 files changed, 144 insertions(+), 100 deletions(-) create mode 100644 crates/echo-wesley-gen/tests/fixtures/toy-counter/README.md create mode 100644 crates/echo-wesley-gen/tests/fixtures/toy-counter/echo-ir-v1.json diff --git a/crates/echo-wesley-gen/tests/fixtures/toy-counter/README.md b/crates/echo-wesley-gen/tests/fixtures/toy-counter/README.md new file mode 100644 index 00000000..382b116b --- /dev/null +++ b/crates/echo-wesley-gen/tests/fixtures/toy-counter/README.md @@ -0,0 +1,29 @@ + + + +# Toy Counter Fixture + +This is the smallest shared Echo/Wesley contract-hosting fixture. + +It exists to prove: + +- generated operation ids and registry metadata; +- typed operation variable generation; +- canonical operation variable encoding; +- EINT v1 packing; +- observation request generation; +- generated output compilation in a standalone consumer crate; +- future installed-host contract smoke tests. + +It is not: + +- a `jedit` fixture; +- a dynamic loading fixture; +- a GraphQL execution fixture; +- a host-side registry validation fixture; +- a text-editing or product-domain fixture. + +Tests should consume `echo-ir-v1.json` through `include_str!(...)`. Do not copy +the toy counter IR into new tests. If the fixture needs to change, update this +single source and make the contract boundary change explicit in the test that +requires it. diff --git a/crates/echo-wesley-gen/tests/fixtures/toy-counter/echo-ir-v1.json b/crates/echo-wesley-gen/tests/fixtures/toy-counter/echo-ir-v1.json new file mode 100644 index 00000000..e3a93076 --- /dev/null +++ b/crates/echo-wesley-gen/tests/fixtures/toy-counter/echo-ir-v1.json @@ -0,0 +1,74 @@ +{ + "ir_version": "echo-ir/v1", + "schema_sha256": "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef", + "codec_id": "cbor-canon-v1", + "registry_version": 1, + "types": [ + { + "name": "CounterValue", + "kind": "OBJECT", + "fields": [ + { + "name": "value", + "type": "Int", + "required": true + } + ] + }, + { + "name": "IncrementInput", + "kind": "INPUT_OBJECT", + "fields": [ + { + "name": "amount", + "type": "Int", + "required": true + } + ] + }, + { + "name": "Mutation", + "kind": "OBJECT", + "fields": [ + { + "name": "increment", + "type": "CounterValue", + "required": true + } + ] + }, + { + "name": "Query", + "kind": "OBJECT", + "fields": [ + { + "name": "counterValue", + "type": "CounterValue", + "required": true + } + ] + } + ], + "ops": [ + { + "kind": "MUTATION", + "name": "increment", + "op_id": 1001, + "args": [ + { + "name": "input", + "type": "IncrementInput", + "required": true + } + ], + "result_type": "CounterValue" + }, + { + "kind": "QUERY", + "name": "counterValue", + "op_id": 1002, + "args": [], + "result_type": "CounterValue" + } + ] +} diff --git a/crates/echo-wesley-gen/tests/generation.rs b/crates/echo-wesley-gen/tests/generation.rs index 9d84ceac..c280bd94 100644 --- a/crates/echo-wesley-gen/tests/generation.rs +++ b/crates/echo-wesley-gen/tests/generation.rs @@ -8,6 +8,8 @@ use std::io::Write; use std::path::{Path, PathBuf}; use std::process::{Command, Output, Stdio}; +const TOY_COUNTER_IR: &str = include_str!("fixtures/toy-counter/echo-ir-v1.json"); + /// Spawns `cargo run -p echo-wesley-gen --`, pipes `ir` to stdin, and returns the output. fn run_wesley_gen(ir: &str) -> Output { let mut child = Command::new("cargo") @@ -354,62 +356,7 @@ fn test_ops_catalog_present() { #[test] fn test_toy_contract_generates_eint_and_observation_helpers() { - let ir = r#"{ - "ir_version": "echo-ir/v1", - "schema_sha256": "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef", - "codec_id": "cbor-canon-v1", - "registry_version": 1, - "types": [ - { - "name": "CounterValue", - "kind": "OBJECT", - "fields": [ - { "name": "value", "type": "Int", "required": true } - ] - }, - { - "name": "IncrementInput", - "kind": "INPUT_OBJECT", - "fields": [ - { "name": "amount", "type": "Int", "required": true } - ] - }, - { - "name": "Mutation", - "kind": "OBJECT", - "fields": [ - { "name": "increment", "type": "CounterValue", "required": true } - ] - }, - { - "name": "Query", - "kind": "OBJECT", - "fields": [ - { "name": "counterValue", "type": "CounterValue", "required": true } - ] - } - ], - "ops": [ - { - "kind": "MUTATION", - "name": "increment", - "op_id": 1001, - "args": [ - { "name": "input", "type": "IncrementInput", "required": true } - ], - "result_type": "CounterValue" - }, - { - "kind": "QUERY", - "name": "counterValue", - "op_id": 1002, - "args": [], - "result_type": "CounterValue" - } - ] - }"#; - - let output = run_wesley_gen(ir); + let output = run_wesley_gen(TOY_COUNTER_IR); assert!( output.status.success(), "CLI failed: {}", @@ -442,48 +389,7 @@ fn test_toy_contract_generates_eint_and_observation_helpers() { #[test] fn test_toy_contract_generated_output_compiles_in_consumer_crate() { - let ir = r#"{ - "ir_version": "echo-ir/v1", - "schema_sha256": "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef", - "codec_id": "cbor-canon-v1", - "registry_version": 1, - "types": [ - { - "name": "CounterValue", - "kind": "OBJECT", - "fields": [ - { "name": "value", "type": "Int", "required": true } - ] - }, - { - "name": "IncrementInput", - "kind": "INPUT_OBJECT", - "fields": [ - { "name": "amount", "type": "Int", "required": true } - ] - } - ], - "ops": [ - { - "kind": "MUTATION", - "name": "increment", - "op_id": 1001, - "args": [ - { "name": "input", "type": "IncrementInput", "required": true } - ], - "result_type": "CounterValue" - }, - { - "kind": "QUERY", - "name": "counterValue", - "op_id": 1002, - "args": [], - "result_type": "CounterValue" - } - ] - }"#; - - let output = run_wesley_gen(ir); + let output = run_wesley_gen(TOY_COUNTER_IR); assert!( output.status.success(), "CLI failed: {}", diff --git a/docs/design/0016-wesley-to-echo-toy-contract-proof/design.md b/docs/design/0016-wesley-to-echo-toy-contract-proof/design.md index 6746d456..98f730df 100644 --- a/docs/design/0016-wesley-to-echo-toy-contract-proof/design.md +++ b/docs/design/0016-wesley-to-echo-toy-contract-proof/design.md @@ -17,7 +17,7 @@ Depends on: ## Status -GREEN 3. +GREEN 4. ## Hill @@ -60,6 +60,12 @@ The test uses a tiny counter contract: - mutation: `increment(input: IncrementInput): CounterValue` - query: `counterValue: CounterValue` +The canonical toy counter IR fixture is: + +```text +crates/echo-wesley-gen/tests/fixtures/toy-counter/echo-ir-v1.json +``` + It first proves current generated output already includes: - `OP_INCREMENT` @@ -167,6 +173,27 @@ arbitrary raw vars bytes. Result: passed. +## GREEN 4 witness + +Implementation: + +- The toy counter IR is now a named test fixture at + `crates/echo-wesley-gen/tests/fixtures/toy-counter/echo-ir-v1.json`. +- The fixture has a README that defines the proof boundary and forbids copying + the toy IR into new tests. +- Both toy generator tests now use the same `include_str!(...)` source. + +This prevents future installed-host smoke work from creating a third, +silently-divergent copy of "the toy contract." + +Focused witness: + +```sh +cargo test -p echo-wesley-gen +``` + +Result: passed. + Broader generator witness: ```sh diff --git a/docs/method/backlog/up-next/PLATFORM_wesley-to-echo-toy-contract-proof.md b/docs/method/backlog/up-next/PLATFORM_wesley-to-echo-toy-contract-proof.md index 3a3f1a1b..80b9c342 100644 --- a/docs/method/backlog/up-next/PLATFORM_wesley-to-echo-toy-contract-proof.md +++ b/docs/method/backlog/up-next/PLATFORM_wesley-to-echo-toy-contract-proof.md @@ -3,7 +3,7 @@ # Wesley To Echo Toy Contract Proof -Status: GREEN 3. +Status: GREEN 4. Depends on: @@ -78,6 +78,13 @@ GREEN 3 hardens the generated app-facing helper surface: - the consumer smoke kernel decodes generated vars before asserting app-level values. +GREEN 4 extracts the toy counter IR into a named fixture: + +- `crates/echo-wesley-gen/tests/fixtures/toy-counter/echo-ir-v1.json`; +- `crates/echo-wesley-gen/tests/fixtures/toy-counter/README.md`; +- both toy generator tests consume the fixture through `include_str!(...)` + instead of copying inline JSON. + The next proof should wire the same generated surface into an installed Echo or application-owned kernel path instead of a toy `KernelPort` implementation. @@ -94,6 +101,7 @@ application-owned kernel path instead of a toy `KernelPort` implementation. - One read path proves how generated query/observer operations relate to `observe(...)` and `ReadingEnvelope`. - Golden ABI vectors are stable. +- The toy counter contract is a shared fixture, not duplicated inline JSON. ## Non-goals From 51c047df517e44851e9642bccd49257a1b785f4e Mon Sep 17 00:00:00 2001 From: James Ross Date: Sun, 3 May 2026 22:07:03 -0700 Subject: [PATCH 13/21] fix: harden Wesley generated helper output --- crates/echo-wesley-gen/src/main.rs | 163 ++++++++++++++++++++- crates/echo-wesley-gen/tests/generation.rs | 83 +++++++++++ 2 files changed, 243 insertions(+), 3 deletions(-) diff --git a/crates/echo-wesley-gen/src/main.rs b/crates/echo-wesley-gen/src/main.rs index 7572c0db..09508eaf 100644 --- a/crates/echo-wesley-gen/src/main.rs +++ b/crates/echo-wesley-gen/src/main.rs @@ -7,6 +7,7 @@ use anyhow::Result; use clap::Parser; use proc_macro2::TokenStream; use quote::{format_ident, quote}; +use std::collections::BTreeMap; use std::io::{self, Read}; /// Create an identifier safely, falling back to a raw identifier for Rust keywords. @@ -58,6 +59,8 @@ fn main() -> Result<()> { } fn generate_rust(ir: &WesleyIR, args: &Args) -> Result { + validate_generated_item_names(ir)?; + let mut tokens = quote! { // Generated by echo-wesley-gen. Do not edit. }; @@ -152,7 +155,6 @@ fn generate_rust(ir: &WesleyIR, args: &Args) -> Result { tokens.extend(quote! { // Registry provider types (Echo runtime loads an app-supplied implementation). use echo_registry_api::{ArgDef, EnumDef, ObjectDef, OpDef, OpKind, RegistryInfo, RegistryProvider}; - use echo_wasm_abi::pack_intent_v1; }); if ir.ops.iter().any(|op| op.kind == OpKind::Query) { @@ -166,6 +168,8 @@ fn generate_rust(ir: &WesleyIR, args: &Args) -> Result { if ir.ops.iter().any(|op| op.kind == OpKind::Mutation) { tokens.extend(quote! { + use echo_wasm_abi::pack_intent_v1; + /// Error produced while building a generated EINT intent. #[derive(Debug)] pub enum GeneratedIntentError { @@ -408,6 +412,10 @@ fn generate_rust(ir: &WesleyIR, args: &Args) -> Result { } fn op_const_ident(name: &str, op_id: u32) -> proc_macro2::Ident { + format_ident!("{}", op_const_name(name, op_id)) +} + +fn op_const_name(name: &str, op_id: u32) -> String { let mut out = String::new(); for (i, c) in name.chars().enumerate() { if c.is_alphanumeric() { @@ -420,9 +428,9 @@ fn op_const_ident(name: &str, op_id: u32) -> proc_macro2::Ident { } } if out.is_empty() { - return format_ident!("OP_ID_{}", op_id); + return format!("OP_ID_{op_id}"); } - format_ident!("OP_{}", out) + format!("OP_{out}") } fn to_pascal_case(name: &str) -> String { @@ -485,6 +493,155 @@ fn validate_version(ir: &WesleyIR) -> Result<()> { } } +fn validate_generated_item_names(ir: &WesleyIR) -> Result<()> { + let mut items = BTreeMap::new(); + + record_generated_item( + &mut items, + "SCHEMA_SHA256", + "generated schema hash constant", + )?; + record_generated_item(&mut items, "CODEC_ID", "generated codec id constant")?; + record_generated_item( + &mut items, + "REGISTRY_VERSION", + "generated registry version constant", + )?; + + for type_def in &ir.types { + match type_def.kind { + TypeKind::Enum => { + record_generated_item( + &mut items, + type_def.name.as_str(), + format!("enum type `{}`", type_def.name), + )?; + record_generated_item( + &mut items, + format!("ENUM_{}_VALUES", type_def.name.to_ascii_uppercase()), + format!("enum `{}` values constant", type_def.name), + )?; + } + TypeKind::Object | TypeKind::InputObject => { + record_generated_item( + &mut items, + type_def.name.as_str(), + format!("object type `{}`", type_def.name), + )?; + if type_def.kind == TypeKind::Object { + record_generated_item( + &mut items, + format!("OBJ_{}_FIELDS", type_def.name.to_ascii_uppercase()), + format!("object `{}` fields constant", type_def.name), + )?; + } + } + TypeKind::Scalar | TypeKind::Interface | TypeKind::Union => {} + } + } + + if !ir.ops.is_empty() { + for (name, source) in [ + ("ENUMS", "generated enum registry"), + ("OBJECTS", "generated object registry"), + ("OPS", "generated operation registry"), + ("op_by_id", "generated operation lookup function"), + ("op_by_name", "generated operation lookup function"), + ("GeneratedRegistry", "generated registry provider type"), + ("REGISTRY", "generated registry provider value"), + ] { + record_generated_item(&mut items, name, source)?; + } + } + + if ir.ops.iter().any(|op| op.kind == OpKind::Mutation) { + record_generated_item( + &mut items, + "GeneratedIntentError", + "generated intent helper error", + )?; + } + + for op in &ir.ops { + let kind = op_kind_name(&op.kind); + let const_name = op_const_name(&op.name, op.op_id); + let helper_name = to_snake_case(&op.name); + + record_generated_item( + &mut items, + const_name.as_str(), + format!("{kind} operation `{}` id constant", op.name), + )?; + record_generated_item( + &mut items, + format!("{const_name}_ARGS"), + format!("{kind} operation `{}` args constant", op.name), + )?; + record_generated_item( + &mut items, + format!("{}Vars", to_pascal_case(&op.name)), + format!("{kind} operation `{}` vars type", op.name), + )?; + record_generated_item( + &mut items, + format!("encode_{helper_name}_vars"), + format!("{kind} operation `{}` vars encoder", op.name), + )?; + + match op.kind { + OpKind::Mutation => { + record_generated_item( + &mut items, + format!("pack_{helper_name}_intent"), + format!("mutation operation `{}` EINT helper", op.name), + )?; + record_generated_item( + &mut items, + format!("pack_{helper_name}_intent_raw_vars"), + format!("mutation operation `{}` raw EINT helper", op.name), + )?; + } + OpKind::Query => { + record_generated_item( + &mut items, + format!("{helper_name}_observation_request"), + format!("query operation `{}` observation helper", op.name), + )?; + record_generated_item( + &mut items, + format!("{helper_name}_observation_request_raw_vars"), + format!("query operation `{}` raw observation helper", op.name), + )?; + } + } + } + + Ok(()) +} + +fn record_generated_item( + items: &mut BTreeMap, + name: impl Into, + source: impl Into, +) -> Result<()> { + let name = name.into(); + let source = source.into(); + if let Some(existing_source) = items.get(&name) { + anyhow::bail!( + "generated Rust item name collision for `{name}`: {existing_source} conflicts with {source}" + ); + } + items.insert(name, source); + Ok(()) +} + +fn op_kind_name(kind: &OpKind) -> &'static str { + match kind { + OpKind::Query => "query", + OpKind::Mutation => "mutation", + } +} + /// Map a GraphQL base type name to a Rust type used in generated DTOs. /// /// GraphQL `Float` intentionally maps to `f32` (not `f64`) so generated types diff --git a/crates/echo-wesley-gen/tests/generation.rs b/crates/echo-wesley-gen/tests/generation.rs index c280bd94..d313ac5c 100644 --- a/crates/echo-wesley-gen/tests/generation.rs +++ b/crates/echo-wesley-gen/tests/generation.rs @@ -387,6 +387,89 @@ fn test_toy_contract_generates_eint_and_observation_helpers() { } } +#[test] +fn test_query_only_contract_does_not_import_intent_packer() { + let ir = r#"{ + "ir_version": "echo-ir/v1", + "schema_sha256": "abc123", + "codec_id": "cbor-canon-v1", + "registry_version": 1, + "types": [], + "ops": [ + { "kind": "QUERY", "name": "counterValue", "op_id": 222, "args": [], "result_type": "Int" } + ] + }"#; + + let output = run_wesley_gen(ir); + assert!( + output.status.success(), + "CLI failed: {}", + String::from_utf8_lossy(&output.stderr) + ); + let stdout = String::from_utf8_lossy(&output.stdout); + + assert!(stdout.contains("pub fn counter_value_observation_request")); + assert!( + !stdout.contains("pack_intent_v1"), + "query-only generated code should not import or use EINT packing" + ); +} + +#[test] +fn test_operation_vars_type_collision_fails_with_clear_diagnostic() { + let ir = r#"{ + "ir_version": "echo-ir/v1", + "schema_sha256": "abc123", + "codec_id": "cbor-canon-v1", + "registry_version": 1, + "types": [ + { + "name": "IncrementVars", + "kind": "OBJECT", + "fields": [ + { "name": "value", "type": "Int", "required": true } + ] + } + ], + "ops": [ + { "kind": "MUTATION", "name": "increment", "op_id": 111, "args": [], "result_type": "IncrementVars" } + ] + }"#; + + let output = run_wesley_gen(ir); + assert!( + !output.status.success(), + "generator should reject duplicate generated item names" + ); + let stderr = String::from_utf8_lossy(&output.stderr); + assert!(stderr.contains("generated Rust item name collision")); + assert!(stderr.contains("IncrementVars")); +} + +#[test] +fn test_query_mutation_operation_name_collision_fails_with_clear_diagnostic() { + let ir = r#"{ + "ir_version": "echo-ir/v1", + "schema_sha256": "abc123", + "codec_id": "cbor-canon-v1", + "registry_version": 1, + "types": [], + "ops": [ + { "kind": "MUTATION", "name": "value", "op_id": 111, "args": [], "result_type": "Int" }, + { "kind": "QUERY", "name": "value", "op_id": 222, "args": [], "result_type": "Int" } + ] + }"#; + + let output = run_wesley_gen(ir); + assert!( + !output.status.success(), + "generator should reject duplicate generated operation item names" + ); + let stderr = String::from_utf8_lossy(&output.stderr); + assert!(stderr.contains("generated Rust item name collision")); + assert!(stderr.contains("OP_VALUE")); +} + #[test] fn test_toy_contract_generated_output_compiles_in_consumer_crate() { let output = run_wesley_gen(TOY_COUNTER_IR); From 4a05c2020a6a4e324eaa5c8568e77f311dfc110f Mon Sep 17 00:00:00 2001 From: James Ross Date: Sun, 3 May 2026 22:07:29 -0700 Subject: [PATCH 14/21] docs: render Mermaid diagrams in VitePress --- docs/.vitepress/config.ts | 149 ++-- package.json | 4 +- pnpm-lock.yaml | 1751 ++++++++++++++++++++----------------- 3 files changed, 1022 insertions(+), 882 deletions(-) diff --git a/docs/.vitepress/config.ts b/docs/.vitepress/config.ts index ce40cc88..654530af 100644 --- a/docs/.vitepress/config.ts +++ b/docs/.vitepress/config.ts @@ -1,88 +1,91 @@ // SPDX-License-Identifier: Apache-2.0 // © James Ross Ω FLYING•ROBOTS import { defineConfig } from "vitepress"; +import { withMermaid } from "vitepress-plugin-mermaid"; -export default defineConfig({ - title: "Echo", - description: "Deterministic WARP runtime docs for Echo", - cleanUrls: true, - srcExclude: ["method/**", "design/**"], - themeConfig: { - search: { provider: "local" }, - nav: [ - { text: "Home", link: "/" }, - { text: "Runtime Model", link: "/architecture/outline" }, - { text: "Theory Map", link: "/theory/THEORY" }, - { - text: "Specs", - items: [ - { text: "warp-core", link: "/spec/warp-core" }, - { text: "Scheduler", link: "/spec/scheduler-warp-core" }, - { text: "Tick Patch", link: "/spec/warp-tick-patch" }, - { text: "Merkle Commit", link: "/spec/merkle-commit" }, - { text: "WASM ABI", link: "/spec/SPEC-0009-wasm-abi" }, - { text: "WVP", link: "/spec/warp-view-protocol" }, - ], - }, - ], - sidebar: { - "/": [ - { - text: "Overview", - items: [ - { text: "Docs Map", link: "/" }, - { text: "Runtime Model", link: "/architecture/outline" }, - { - text: "Application Contract Hosting", - link: "/architecture/application-contract-hosting", - }, - { text: "Theory Map", link: "/theory/THEORY" }, - { text: "Current Bearing", link: "/BEARING" }, - ], - }, +export default withMermaid( + defineConfig({ + title: "Echo", + description: "Deterministic WARP runtime docs for Echo", + cleanUrls: true, + srcExclude: ["method/**", "design/**"], + themeConfig: { + search: { provider: "local" }, + nav: [ + { text: "Home", link: "/" }, + { text: "Runtime Model", link: "/architecture/outline" }, + { text: "Theory Map", link: "/theory/THEORY" }, { - text: "Kernel Specs", + text: "Specs", items: [ { text: "warp-core", link: "/spec/warp-core" }, - { - text: "Attachment Atoms", - link: "/spec/SPEC-0001-attachment-plane-v0-atoms", - }, - { - text: "Descended Attachments", - link: "/spec/SPEC-0002-descended-attachments-v1", - }, - { - text: "DPO Litmus", - link: "/spec/SPEC-0003-dpo-concurrency-litmus-v0", - }, { text: "Scheduler", link: "/spec/scheduler-warp-core" }, { text: "Tick Patch", link: "/spec/warp-tick-patch" }, { text: "Merkle Commit", link: "/spec/merkle-commit" }, - { - text: "Canonical Inbox", - link: "/spec/canonical-inbox-sequencing", - }, - ], - }, - { - text: "Platform Specs", - items: [ - { - text: "Worldlines + Observation", - link: "/spec/SPEC-0004-worldlines-playback-truthbus", - }, - { - text: "Provenance Payload", - link: "/spec/SPEC-0005-provenance-payload", - }, { text: "WASM ABI", link: "/spec/SPEC-0009-wasm-abi" }, - { text: "JS/CBOR Mapping", link: "/spec/js-cbor-mapping" }, - { text: "ABI Golden Vectors", link: "/spec/abi-golden-vectors" }, - { text: "WARP View Protocol", link: "/spec/warp-view-protocol" }, + { text: "WVP", link: "/spec/warp-view-protocol" }, ], }, ], + sidebar: { + "/": [ + { + text: "Overview", + items: [ + { text: "Docs Map", link: "/" }, + { text: "Runtime Model", link: "/architecture/outline" }, + { + text: "Application Contract Hosting", + link: "/architecture/application-contract-hosting", + }, + { text: "Theory Map", link: "/theory/THEORY" }, + { text: "Current Bearing", link: "/BEARING" }, + ], + }, + { + text: "Kernel Specs", + items: [ + { text: "warp-core", link: "/spec/warp-core" }, + { + text: "Attachment Atoms", + link: "/spec/SPEC-0001-attachment-plane-v0-atoms", + }, + { + text: "Descended Attachments", + link: "/spec/SPEC-0002-descended-attachments-v1", + }, + { + text: "DPO Litmus", + link: "/spec/SPEC-0003-dpo-concurrency-litmus-v0", + }, + { text: "Scheduler", link: "/spec/scheduler-warp-core" }, + { text: "Tick Patch", link: "/spec/warp-tick-patch" }, + { text: "Merkle Commit", link: "/spec/merkle-commit" }, + { + text: "Canonical Inbox", + link: "/spec/canonical-inbox-sequencing", + }, + ], + }, + { + text: "Platform Specs", + items: [ + { + text: "Worldlines + Observation", + link: "/spec/SPEC-0004-worldlines-playback-truthbus", + }, + { + text: "Provenance Payload", + link: "/spec/SPEC-0005-provenance-payload", + }, + { text: "WASM ABI", link: "/spec/SPEC-0009-wasm-abi" }, + { text: "JS/CBOR Mapping", link: "/spec/js-cbor-mapping" }, + { text: "ABI Golden Vectors", link: "/spec/abi-golden-vectors" }, + { text: "WARP View Protocol", link: "/spec/warp-view-protocol" }, + ], + }, + ], + }, }, - }, -}); + }), +); diff --git a/package.json b/package.json index 37561c38..6ba048d3 100644 --- a/package.json +++ b/package.json @@ -17,8 +17,10 @@ "asciichart": "^1.5.25", "graphql": "16.11.0", "markdownlint-cli2": "0.22.0", + "mermaid": "^11.14.0", "prettier": "3.8.1", - "vitepress": "1.6.4" + "vitepress": "1.6.4", + "vitepress-plugin-mermaid": "^2.0.17" }, "dependencies": { "colortap": "^0.3.0" diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 6e454393..4fc9bfdf 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -26,12 +26,18 @@ importers: markdownlint-cli2: specifier: 0.22.0 version: 0.22.0 + mermaid: + specifier: ^11.14.0 + version: 11.14.0 prettier: specifier: 3.8.1 version: 3.8.1 vitepress: specifier: 1.6.4 version: 1.6.4(@algolia/client-search@5.46.2)(@types/node@24.10.1)(@types/react@18.3.28)(postcss@8.5.6)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(search-insights@2.17.3)(typescript@5.6.3) + vitepress-plugin-mermaid: + specifier: ^2.0.17 + version: 2.0.17(mermaid@11.14.0)(vitepress@1.6.4(@algolia/client-search@5.46.2)(@types/node@24.10.1)(@types/react@18.3.28)(postcss@8.5.6)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(search-insights@2.17.3)(typescript@5.6.3)) crates/ttd-browser: {} @@ -136,43 +142,8 @@ packages: resolution: {integrity: sha512-ciPihkletp7ttweJ8Zt+GukSVLp2ANJHU+9ttiSxsJZThXc4Y2yJ8HGVWesW5jN1zrsZsezN71KrMx/iZsOYpg==} engines: {node: '>= 14.0.0'} - '@babel/code-frame@7.29.0': - resolution: {integrity: sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==} - engines: {node: '>=6.9.0'} - - '@babel/compat-data@7.29.0': - resolution: {integrity: sha512-T1NCJqT/j9+cn8fvkt7jtwbLBfLC/1y1c7NtCeXFRgzGTsafi68MRv8yzkYSapBnFA6L3U2VSc02ciDzoAJhJg==} - engines: {node: '>=6.9.0'} - - '@babel/core@7.29.0': - resolution: {integrity: sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==} - engines: {node: '>=6.9.0'} - - '@babel/generator@7.29.1': - resolution: {integrity: sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw==} - engines: {node: '>=6.9.0'} - - '@babel/helper-compilation-targets@7.28.6': - resolution: {integrity: sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA==} - engines: {node: '>=6.9.0'} - - '@babel/helper-globals@7.28.0': - resolution: {integrity: sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==} - engines: {node: '>=6.9.0'} - - '@babel/helper-module-imports@7.28.6': - resolution: {integrity: sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw==} - engines: {node: '>=6.9.0'} - - '@babel/helper-module-transforms@7.28.6': - resolution: {integrity: sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0 - - '@babel/helper-plugin-utils@7.28.6': - resolution: {integrity: sha512-S9gzZ/bz83GRysI7gAD4wPT/AI3uCnY+9xn+Mx/KPs2JwHJIz1W8PZkg2cqyt3RNOBM8ejcXhV6y8Og7ly/Dug==} - engines: {node: '>=6.9.0'} + '@antfu/install-pkg@1.1.0': + resolution: {integrity: sha512-MGQsmw10ZyI+EJo45CdSER4zEb+p31LpDAFp2Z3gkSd1yqVZGi0Ebx++YTEMonJy4oChEMLsxZ64j8FH6sSqtQ==} '@babel/helper-string-parser@7.27.1': resolution: {integrity: sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==} @@ -182,81 +153,35 @@ packages: resolution: {integrity: sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==} engines: {node: '>=6.9.0'} - '@babel/helper-validator-option@7.27.1': - resolution: {integrity: sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==} - engines: {node: '>=6.9.0'} - - '@babel/helpers@7.28.6': - resolution: {integrity: sha512-xOBvwq86HHdB7WUDTfKfT/Vuxh7gElQ+Sfti2Cy6yIWNW05P8iUslOVcZ4/sKbE+/jQaukQAdz/gf3724kYdqw==} - engines: {node: '>=6.9.0'} - '@babel/parser@7.28.5': resolution: {integrity: sha512-KKBU1VGYR7ORr3At5HAtUQ+TV3SzRCXmA/8OdDZiLDBIZxVyzXuztPjfLd3BV1PRAQGCMWWSHYhL0F8d5uHBDQ==} engines: {node: '>=6.0.0'} hasBin: true - '@babel/parser@7.29.0': - resolution: {integrity: sha512-IyDgFV5GeDUVX4YdF/3CPULtVGSXXMLh1xVIgdCgxApktqnQV0r7/8Nqthg+8YLGaAtdyIlo2qIdZrbCv4+7ww==} - engines: {node: '>=6.0.0'} - hasBin: true - - '@babel/plugin-transform-react-jsx-self@7.27.1': - resolution: {integrity: sha512-6UzkCs+ejGdZ5mFFC/OCUrv028ab2fp1znZmCZjAOBKiBK2jXD1O+BPSfX8X2qjJ75fZBMSnQn3Rq2mrBJK2mw==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-react-jsx-source@7.27.1': - resolution: {integrity: sha512-zbwoTsBruTeKB9hSq73ha66iFeJHuaFkUbwvqElnygoNbj/jHRsSeokowZFN3CZ64IvEqcmmkVe89OPXc7ldAw==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/template@7.28.6': - resolution: {integrity: sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==} - engines: {node: '>=6.9.0'} - - '@babel/traverse@7.29.0': - resolution: {integrity: sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA==} - engines: {node: '>=6.9.0'} - '@babel/types@7.28.5': resolution: {integrity: sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA==} engines: {node: '>=6.9.0'} - '@babel/types@7.29.0': - resolution: {integrity: sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==} - engines: {node: '>=6.9.0'} + '@braintree/sanitize-url@6.0.4': + resolution: {integrity: sha512-s3jaWicZd0pkP0jf5ysyHUI/RE7MHos6qlToFcGWXVp+ykHOy77OUMrfbgJ9it2C5bow7OIQwYYaHjk9XlBQ2A==} - '@cbor-extract/cbor-extract-darwin-arm64@2.2.0': - resolution: {integrity: sha512-P7swiOAdF7aSi0H+tHtHtr6zrpF3aAq/W9FXx5HektRvLTM2O89xCyXF3pk7pLc7QpaY7AoaE8UowVf9QBdh3w==} - cpu: [arm64] - os: [darwin] + '@braintree/sanitize-url@7.1.2': + resolution: {integrity: sha512-jigsZK+sMF/cuiB7sERuo9V7N9jx+dhmHHnQyDSVdpZwVutaBu7WvNYqMDLSgFgfB30n452TP3vjDAvFC973mA==} - '@cbor-extract/cbor-extract-darwin-x64@2.2.0': - resolution: {integrity: sha512-1liF6fgowph0JxBbYnAS7ZlqNYLf000Qnj4KjqPNW4GViKrEql2MgZnAsExhY9LSy8dnvA4C0qHEBgPrll0z0w==} - cpu: [x64] - os: [darwin] + '@chevrotain/cst-dts-gen@12.0.0': + resolution: {integrity: sha512-fSL4KXjTl7cDgf0B5Rip9Q05BOrYvkJV/RrBTE/bKDN096E4hN/ySpcBK5B24T76dlQ2i32Zc3PAE27jFnFrKg==} - '@cbor-extract/cbor-extract-linux-arm64@2.2.0': - resolution: {integrity: sha512-rQvhNmDuhjTVXSPFLolmQ47/ydGOFXtbR7+wgkSY0bdOxCFept1hvg59uiLPT2fVDuJFuEy16EImo5tE2x3RsQ==} - cpu: [arm64] - os: [linux] + '@chevrotain/gast@12.0.0': + resolution: {integrity: sha512-1ne/m3XsIT8aEdrvT33so0GUC+wkctpUPK6zU9IlOyJLUbR0rg4G7ZiApiJbggpgPir9ERy3FRjT6T7lpgetnQ==} - '@cbor-extract/cbor-extract-linux-arm@2.2.0': - resolution: {integrity: sha512-QeBcBXk964zOytiedMPQNZr7sg0TNavZeuUCD6ON4vEOU/25+pLhNN6EDIKJ9VLTKaZ7K7EaAriyYQ1NQ05s/Q==} - cpu: [arm] - os: [linux] + '@chevrotain/regexp-to-ast@12.0.0': + resolution: {integrity: sha512-p+EW9MaJwgaHguhoqwOtx/FwuGr+DnNn857sXWOi/mClXIkPGl3rn7hGNWvo31HA3vyeQxjqe+H36yZJwYU8cA==} - '@cbor-extract/cbor-extract-linux-x64@2.2.0': - resolution: {integrity: sha512-cWLAWtT3kNLHSvP4RKDzSTX9o0wvQEEAj4SKvhWuOVZxiDAeQazr9A+PSiRILK1VYMLeDml89ohxCnUNQNQNCw==} - cpu: [x64] - os: [linux] + '@chevrotain/types@12.0.0': + resolution: {integrity: sha512-S+04vjFQKeuYw0/eW3U52LkAHQsB1ASxsPGsLPUyQgrZ2iNNibQrsidruDzjEX2JYfespXMG0eZmXlhA6z7nWA==} - '@cbor-extract/cbor-extract-win32-x64@2.2.0': - resolution: {integrity: sha512-l2M+Z8DO2vbvADOBNLbbh9y5ST1RY5sqkWOg/58GkUPBYou/cuNZ68SGQ644f1CvZ8kcOxyZtw06+dxWHIoN/w==} - cpu: [x64] - os: [win32] + '@chevrotain/utils@12.0.0': + resolution: {integrity: sha512-lB59uJoaGIfOOL9knQqQRfhl9g7x8/wqFkp13zTdkRu1huG9kg6IJs1O8hqj9rs6h7orGxHJUKb+mX3rPbWGhA==} '@docsearch/css@3.8.2': resolution: {integrity: sha512-y05ayQFyUmCXze79+56v/4HpycYF3uFqB78pLPrSV5ZKAlDuIAAJNhaRi8tTdRNXh05yxX/TyNnzD6LwSM89vQ==} @@ -287,315 +212,155 @@ packages: cpu: [ppc64] os: [aix] - '@esbuild/aix-ppc64@0.25.12': - resolution: {integrity: sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==} - engines: {node: '>=18'} - cpu: [ppc64] - os: [aix] - '@esbuild/android-arm64@0.21.5': resolution: {integrity: sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==} engines: {node: '>=12'} cpu: [arm64] os: [android] - '@esbuild/android-arm64@0.25.12': - resolution: {integrity: sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==} - engines: {node: '>=18'} - cpu: [arm64] - os: [android] - '@esbuild/android-arm@0.21.5': resolution: {integrity: sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==} engines: {node: '>=12'} cpu: [arm] os: [android] - '@esbuild/android-arm@0.25.12': - resolution: {integrity: sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==} - engines: {node: '>=18'} - cpu: [arm] - os: [android] - '@esbuild/android-x64@0.21.5': resolution: {integrity: sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==} engines: {node: '>=12'} cpu: [x64] os: [android] - '@esbuild/android-x64@0.25.12': - resolution: {integrity: sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==} - engines: {node: '>=18'} - cpu: [x64] - os: [android] - '@esbuild/darwin-arm64@0.21.5': resolution: {integrity: sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==} engines: {node: '>=12'} cpu: [arm64] os: [darwin] - '@esbuild/darwin-arm64@0.25.12': - resolution: {integrity: sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==} - engines: {node: '>=18'} - cpu: [arm64] - os: [darwin] - '@esbuild/darwin-x64@0.21.5': resolution: {integrity: sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==} engines: {node: '>=12'} cpu: [x64] os: [darwin] - '@esbuild/darwin-x64@0.25.12': - resolution: {integrity: sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==} - engines: {node: '>=18'} - cpu: [x64] - os: [darwin] - '@esbuild/freebsd-arm64@0.21.5': resolution: {integrity: sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==} engines: {node: '>=12'} cpu: [arm64] os: [freebsd] - '@esbuild/freebsd-arm64@0.25.12': - resolution: {integrity: sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==} - engines: {node: '>=18'} - cpu: [arm64] - os: [freebsd] - '@esbuild/freebsd-x64@0.21.5': resolution: {integrity: sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==} engines: {node: '>=12'} cpu: [x64] os: [freebsd] - '@esbuild/freebsd-x64@0.25.12': - resolution: {integrity: sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==} - engines: {node: '>=18'} - cpu: [x64] - os: [freebsd] - '@esbuild/linux-arm64@0.21.5': resolution: {integrity: sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==} engines: {node: '>=12'} cpu: [arm64] os: [linux] - '@esbuild/linux-arm64@0.25.12': - resolution: {integrity: sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==} - engines: {node: '>=18'} - cpu: [arm64] - os: [linux] - '@esbuild/linux-arm@0.21.5': resolution: {integrity: sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==} engines: {node: '>=12'} cpu: [arm] os: [linux] - '@esbuild/linux-arm@0.25.12': - resolution: {integrity: sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==} - engines: {node: '>=18'} - cpu: [arm] - os: [linux] - '@esbuild/linux-ia32@0.21.5': resolution: {integrity: sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==} engines: {node: '>=12'} cpu: [ia32] os: [linux] - '@esbuild/linux-ia32@0.25.12': - resolution: {integrity: sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==} - engines: {node: '>=18'} - cpu: [ia32] - os: [linux] - '@esbuild/linux-loong64@0.21.5': resolution: {integrity: sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==} engines: {node: '>=12'} cpu: [loong64] os: [linux] - '@esbuild/linux-loong64@0.25.12': - resolution: {integrity: sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==} - engines: {node: '>=18'} - cpu: [loong64] - os: [linux] - '@esbuild/linux-mips64el@0.21.5': resolution: {integrity: sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==} engines: {node: '>=12'} cpu: [mips64el] os: [linux] - '@esbuild/linux-mips64el@0.25.12': - resolution: {integrity: sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==} - engines: {node: '>=18'} - cpu: [mips64el] - os: [linux] - '@esbuild/linux-ppc64@0.21.5': resolution: {integrity: sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==} engines: {node: '>=12'} cpu: [ppc64] os: [linux] - '@esbuild/linux-ppc64@0.25.12': - resolution: {integrity: sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==} - engines: {node: '>=18'} - cpu: [ppc64] - os: [linux] - '@esbuild/linux-riscv64@0.21.5': resolution: {integrity: sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==} engines: {node: '>=12'} cpu: [riscv64] os: [linux] - '@esbuild/linux-riscv64@0.25.12': - resolution: {integrity: sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==} - engines: {node: '>=18'} - cpu: [riscv64] - os: [linux] - '@esbuild/linux-s390x@0.21.5': resolution: {integrity: sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==} engines: {node: '>=12'} cpu: [s390x] os: [linux] - '@esbuild/linux-s390x@0.25.12': - resolution: {integrity: sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==} - engines: {node: '>=18'} - cpu: [s390x] - os: [linux] - '@esbuild/linux-x64@0.21.5': resolution: {integrity: sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==} engines: {node: '>=12'} cpu: [x64] os: [linux] - '@esbuild/linux-x64@0.25.12': - resolution: {integrity: sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==} - engines: {node: '>=18'} - cpu: [x64] - os: [linux] - - '@esbuild/netbsd-arm64@0.25.12': - resolution: {integrity: sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==} - engines: {node: '>=18'} - cpu: [arm64] - os: [netbsd] - '@esbuild/netbsd-x64@0.21.5': resolution: {integrity: sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==} engines: {node: '>=12'} cpu: [x64] os: [netbsd] - '@esbuild/netbsd-x64@0.25.12': - resolution: {integrity: sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==} - engines: {node: '>=18'} - cpu: [x64] - os: [netbsd] - - '@esbuild/openbsd-arm64@0.25.12': - resolution: {integrity: sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==} - engines: {node: '>=18'} - cpu: [arm64] - os: [openbsd] - '@esbuild/openbsd-x64@0.21.5': resolution: {integrity: sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==} engines: {node: '>=12'} cpu: [x64] os: [openbsd] - '@esbuild/openbsd-x64@0.25.12': - resolution: {integrity: sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==} - engines: {node: '>=18'} - cpu: [x64] - os: [openbsd] - - '@esbuild/openharmony-arm64@0.25.12': - resolution: {integrity: sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==} - engines: {node: '>=18'} - cpu: [arm64] - os: [openharmony] - '@esbuild/sunos-x64@0.21.5': resolution: {integrity: sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==} engines: {node: '>=12'} cpu: [x64] os: [sunos] - '@esbuild/sunos-x64@0.25.12': - resolution: {integrity: sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==} - engines: {node: '>=18'} - cpu: [x64] - os: [sunos] - '@esbuild/win32-arm64@0.21.5': resolution: {integrity: sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==} engines: {node: '>=12'} cpu: [arm64] os: [win32] - '@esbuild/win32-arm64@0.25.12': - resolution: {integrity: sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==} - engines: {node: '>=18'} - cpu: [arm64] - os: [win32] - '@esbuild/win32-ia32@0.21.5': resolution: {integrity: sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==} engines: {node: '>=12'} cpu: [ia32] os: [win32] - '@esbuild/win32-ia32@0.25.12': - resolution: {integrity: sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==} - engines: {node: '>=18'} - cpu: [ia32] - os: [win32] - '@esbuild/win32-x64@0.21.5': resolution: {integrity: sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==} engines: {node: '>=12'} cpu: [x64] os: [win32] - '@esbuild/win32-x64@0.25.12': - resolution: {integrity: sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==} - engines: {node: '>=18'} - cpu: [x64] - os: [win32] - '@iconify-json/simple-icons@1.2.64': resolution: {integrity: sha512-SMmm//tjZBvHnT0EAzZLnBTL6bukSkncM0pwkOXjr0FsAeCqjQtqoxBR0Mp+PazIJjXJKHm1Ju0YgnCIPOodJg==} '@iconify/types@2.0.0': resolution: {integrity: sha512-+wluvCrRhXrhyOmRDJ3q8mux9JkKy5SJ/v8ol2tu4FVjyYvtEzkc/3pK15ET6RKg4b4w4BmTk1+gsCUhf21Ykg==} - '@jridgewell/gen-mapping@0.3.13': - resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==} - - '@jridgewell/remapping@2.3.5': - resolution: {integrity: sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==} - - '@jridgewell/resolve-uri@3.1.2': - resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} - engines: {node: '>=6.0.0'} + '@iconify/utils@3.1.1': + resolution: {integrity: sha512-MwzoDtw9rO1x+qfgLTV/IVXsHDBqeYZoMIQC8SfxfYSlaSUG+oWiAcoiB1yajAda6mqblm4/1/w2E8tRu7a7Tw==} '@jridgewell/sourcemap-codec@1.5.5': resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==} - '@jridgewell/trace-mapping@0.3.31': - resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==} + '@mermaid-js/mermaid-mindmap@9.3.0': + resolution: {integrity: sha512-IhtYSVBBRYviH1Ehu8gk69pMDF8DSRqXBRDMWrEfHoaMruHeaP2DXA3PBnuwsMaCdPQhlUUcy/7DBLAEIXvCAw==} + + '@mermaid-js/parser@1.1.0': + resolution: {integrity: sha512-gxK9ZX2+Fex5zu8LhRQoMeMPEHbc73UKZ0FQ54YrQtUxE1VVhMwzeNtKRPAu5aXks4FasbMe4xB4bWrmq6Jlxw==} '@nodelib/fs.scandir@2.1.5': resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} @@ -614,9 +379,6 @@ packages: engines: {node: '>=18'} hasBin: true - '@rolldown/pluginutils@1.0.0-beta.27': - resolution: {integrity: sha512-+d0F4MKMCbeVUJwG96uQ4SgAznZNSq93I3V+9NHA4OpvqG8mRCpGdKmK8l/dl02h2CCDHwW2FqilnTyDcAnqjA==} - '@rollup/rollup-android-arm-eabi@4.54.0': resolution: {integrity: sha512-OywsdRHrFvCdvsewAInDKCNyR3laPA2mc9bRYJ6LBp5IyvF3fvXbbNR0bSzHlZVFtn6E0xw2oZlyjg4rKCVcng==} cpu: [arm] @@ -758,17 +520,98 @@ packages: '@tweenjs/tween.js@23.1.3': resolution: {integrity: sha512-vJmvvwFxYuGnF2axRtPYocag6Clbb5YS7kLL+SO/TeVFzHqDIWrNKYtcsPMibjDx9O+bu+psAy9NKfWklassUA==} - '@types/babel__core@7.20.5': - resolution: {integrity: sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==} + '@types/d3-array@3.2.2': + resolution: {integrity: sha512-hOLWVbm7uRza0BYXpIIW5pxfrKe0W+D5lrFiAEYR+pb6w3N2SwSMaJbXdUfSEv+dT4MfHBLtn5js0LAWaO6otw==} + + '@types/d3-axis@3.0.6': + resolution: {integrity: sha512-pYeijfZuBd87T0hGn0FO1vQ/cgLk6E1ALJjfkC0oJ8cbwkZl3TpgS8bVBLZN+2jjGgg38epgxb2zmoGtSfvgMw==} + + '@types/d3-brush@3.0.6': + resolution: {integrity: sha512-nH60IZNNxEcrh6L1ZSMNA28rj27ut/2ZmI3r96Zd+1jrZD++zD3LsMIjWlvg4AYrHn/Pqz4CF3veCxGjtbqt7A==} + + '@types/d3-chord@3.0.6': + resolution: {integrity: sha512-LFYWWd8nwfwEmTZG9PfQxd17HbNPksHBiJHaKuY1XeqscXacsS2tyoo6OdRsjf+NQYeB6XrNL3a25E3gH69lcg==} + + '@types/d3-color@3.1.3': + resolution: {integrity: sha512-iO90scth9WAbmgv7ogoq57O9YpKmFBbmoEoCHDB2xMBY0+/KVrqAaCDyCE16dUspeOvIxFFRI+0sEtqDqy2b4A==} + + '@types/d3-contour@3.0.6': + resolution: {integrity: sha512-BjzLgXGnCWjUSYGfH1cpdo41/hgdWETu4YxpezoztawmqsvCeep+8QGfiY6YbDvfgHz/DkjeIkkZVJavB4a3rg==} + + '@types/d3-delaunay@6.0.4': + resolution: {integrity: sha512-ZMaSKu4THYCU6sV64Lhg6qjf1orxBthaC161plr5KuPHo3CNm8DTHiLw/5Eq2b6TsNP0W0iJrUOFscY6Q450Hw==} + + '@types/d3-dispatch@3.0.7': + resolution: {integrity: sha512-5o9OIAdKkhN1QItV2oqaE5KMIiXAvDWBDPrD85e58Qlz1c1kI/J0NcqbEG88CoTwJrYe7ntUCVfeUl2UJKbWgA==} + + '@types/d3-drag@3.0.7': + resolution: {integrity: sha512-HE3jVKlzU9AaMazNufooRJ5ZpWmLIoc90A37WU2JMmeq28w1FQqCZswHZ3xR+SuxYftzHq6WU6KJHvqxKzTxxQ==} + + '@types/d3-dsv@3.0.7': + resolution: {integrity: sha512-n6QBF9/+XASqcKK6waudgL0pf/S5XHPPI8APyMLLUHd8NqouBGLsU8MgtO7NINGtPBtk9Kko/W4ea0oAspwh9g==} + + '@types/d3-ease@3.0.2': + resolution: {integrity: sha512-NcV1JjO5oDzoK26oMzbILE6HW7uVXOHLQvHshBUW4UMdZGfiY6v5BeQwh9a9tCzv+CeefZQHJt5SRgK154RtiA==} + + '@types/d3-fetch@3.0.7': + resolution: {integrity: sha512-fTAfNmxSb9SOWNB9IoG5c8Hg6R+AzUHDRlsXsDZsNp6sxAEOP0tkP3gKkNSO/qmHPoBFTxNrjDprVHDQDvo5aA==} + + '@types/d3-force@3.0.10': + resolution: {integrity: sha512-ZYeSaCF3p73RdOKcjj+swRlZfnYpK1EbaDiYICEEp5Q6sUiqFaFQ9qgoshp5CzIyyb/yD09kD9o2zEltCexlgw==} + + '@types/d3-format@3.0.4': + resolution: {integrity: sha512-fALi2aI6shfg7vM5KiR1wNJnZ7r6UuggVqtDA+xiEdPZQwy/trcQaHnwShLuLdta2rTymCNpxYTiMZX/e09F4g==} + + '@types/d3-geo@3.1.0': + resolution: {integrity: sha512-856sckF0oP/diXtS4jNsiQw/UuK5fQG8l/a9VVLeSouf1/PPbBE1i1W852zVwKwYCBkFJJB7nCFTbk6UMEXBOQ==} + + '@types/d3-hierarchy@3.1.7': + resolution: {integrity: sha512-tJFtNoYBtRtkNysX1Xq4sxtjK8YgoWUNpIiUee0/jHGRwqvzYxkq0hGVbbOGSz+JgFxxRu4K8nb3YpG3CMARtg==} + + '@types/d3-interpolate@3.0.4': + resolution: {integrity: sha512-mgLPETlrpVV1YRJIglr4Ez47g7Yxjl1lj7YKsiMCb27VJH9W8NVM6Bb9d8kkpG/uAQS5AmbA48q2IAolKKo1MA==} + + '@types/d3-path@3.1.1': + resolution: {integrity: sha512-VMZBYyQvbGmWyWVea0EHs/BwLgxc+MKi1zLDCONksozI4YJMcTt8ZEuIR4Sb1MMTE8MMW49v0IwI5+b7RmfWlg==} + + '@types/d3-polygon@3.0.2': + resolution: {integrity: sha512-ZuWOtMaHCkN9xoeEMr1ubW2nGWsp4nIql+OPQRstu4ypeZ+zk3YKqQT0CXVe/PYqrKpZAi+J9mTs05TKwjXSRA==} + + '@types/d3-quadtree@3.0.6': + resolution: {integrity: sha512-oUzyO1/Zm6rsxKRHA1vH0NEDG58HrT5icx/azi9MF1TWdtttWl0UIUsjEQBBh+SIkrpd21ZjEv7ptxWys1ncsg==} + + '@types/d3-random@3.0.3': + resolution: {integrity: sha512-Imagg1vJ3y76Y2ea0871wpabqp613+8/r0mCLEBfdtqC7xMSfj9idOnmBYyMoULfHePJyxMAw3nWhJxzc+LFwQ==} + + '@types/d3-scale-chromatic@3.1.0': + resolution: {integrity: sha512-iWMJgwkK7yTRmWqRB5plb1kadXyQ5Sj8V/zYlFGMUBbIPKQScw+Dku9cAAMgJG+z5GYDoMjWGLVOvjghDEFnKQ==} + + '@types/d3-scale@4.0.9': + resolution: {integrity: sha512-dLmtwB8zkAeO/juAMfnV+sItKjlsw2lKdZVVy6LRr0cBmegxSABiLEpGVmSJJ8O08i4+sGR6qQtb6WtuwJdvVw==} + + '@types/d3-selection@3.0.11': + resolution: {integrity: sha512-bhAXu23DJWsrI45xafYpkQ4NtcKMwWnAC/vKrd2l+nxMFuvOT3XMYTIj2opv8vq8AO5Yh7Qac/nSeP/3zjTK0w==} + + '@types/d3-shape@3.1.8': + resolution: {integrity: sha512-lae0iWfcDeR7qt7rA88BNiqdvPS5pFVPpo5OfjElwNaT2yyekbM0C9vK+yqBqEmHr6lDkRnYNoTBYlAgJa7a4w==} + + '@types/d3-time-format@4.0.3': + resolution: {integrity: sha512-5xg9rC+wWL8kdDj153qZcsJ0FWiFt0J5RB6LYUNZjwSnesfblqrI/bJ1wBdJ8OQfncgbJG5+2F+qfqnqyzYxyg==} + + '@types/d3-time@3.0.4': + resolution: {integrity: sha512-yuzZug1nkAAaBlBBikKZTgzCeA+k1uy4ZFwWANOfKw5z5LRhV0gNA7gNkKm7HoK+HRN0wX3EkxGk0fpbWhmB7g==} + + '@types/d3-timer@3.0.2': + resolution: {integrity: sha512-Ps3T8E8dZDam6fUyNiMkekK3XUsaUEik+idO9/YjPtfj2qruF8tFBXS7XhtE4iIXBLxhmLjP3SXpLhVf21I9Lw==} - '@types/babel__generator@7.27.0': - resolution: {integrity: sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==} + '@types/d3-transition@3.0.9': + resolution: {integrity: sha512-uZS5shfxzO3rGlu0cC3bjmMFKsXv+SmZZcgp0KD22ts4uGXp5EVYGzu/0YdwZeKmddhcAccYtREJKkPfXkZuCg==} - '@types/babel__template@7.4.4': - resolution: {integrity: sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==} + '@types/d3-zoom@3.0.8': + resolution: {integrity: sha512-iqMC4/YlFCSlO8+2Ii1GGGliCAY4XdeG748w5vQUbevlbDu0zSjH/+jojorQVBK/se0j6DUFNPBGSqD3YWYnDw==} - '@types/babel__traverse@7.28.0': - resolution: {integrity: sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==} + '@types/d3@7.4.3': + resolution: {integrity: sha512-lZXZ9ckh5R8uiFVt8ogUNf+pIrK4EsWrx2Np75WvF/eTpJ0FMHNhjXk8CKEx/+gpHbNQyJWehbFaTvqmHWB3ww==} '@types/debug@4.1.13': resolution: {integrity: sha512-KSVgmQmzMwPlmtljOomayoR89W4FynCAi3E8PPs7vmDVPe84hT+vGPKkJfThkmXs0x0jAaa9U8uW8bbfyS2fWw==} @@ -776,6 +619,9 @@ packages: '@types/estree@1.0.8': resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==} + '@types/geojson@7946.0.16': + resolution: {integrity: sha512-6C8nqWur3j98U6+lXDfTUWIfgvZU+EumvpHKcYjujKH7woYyLj2sUmff0tRhrqM7BohUw7Pz3ZB1jj2gW9Fvmg==} + '@types/hast@3.0.4': resolution: {integrity: sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==} @@ -803,11 +649,6 @@ packages: '@types/prop-types@15.7.15': resolution: {integrity: sha512-F6bEyamV9jKGAFBEmlQnesRPGOQqS2+Uwi0Em15xenOxHaf2hv6L8YCVn3rPdPJOiJfPiCnLIRyvwVaqMY3MIw==} - '@types/react-dom@18.3.7': - resolution: {integrity: sha512-MEe3UeoENYVFXzoXEWsvcpg6ZvlrFNlOQ7EOsvhI3CfAXwzPfO8Qwuxd40nepsYKqyyVQnTdEfv68q91yLcKrQ==} - peerDependencies: - '@types/react': ^18.0.0 - '@types/react@18.3.28': resolution: {integrity: sha512-z9VXpC7MWrhfWipitjNdgCauoMLRdIILQsAEV+ZesIzBq/oUlxk0m3ApZuMFCXdnS4U7KrI+l3WRUEGQ8K1QKw==} @@ -817,6 +658,9 @@ packages: '@types/three@0.169.0': resolution: {integrity: sha512-oan7qCgJBt03wIaK+4xPWclYRPG9wzcg7Z2f5T8xYTNEF95kh0t0lklxLLYBDo7gQiGLYzE6iF4ta7nXF2bcsw==} + '@types/trusted-types@2.0.7': + resolution: {integrity: sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==} + '@types/unist@2.0.11': resolution: {integrity: sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==} @@ -832,11 +676,8 @@ packages: '@ungap/structured-clone@1.3.0': resolution: {integrity: sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==} - '@vitejs/plugin-react@4.7.0': - resolution: {integrity: sha512-gUu9hwfWvvEDBBmgtAowQCojwZmJ5mcLn3aufeCsitijs3+f2NsrPtlAWIR6OPiqljl96GVCUbLe0HyqIpVaoA==} - engines: {node: ^14.18.0 || >=16.0.0} - peerDependencies: - vite: ^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 + '@upsetjs/venn.js@2.0.0': + resolution: {integrity: sha512-WbBhLrooyePuQ1VZxrJjtLvTc4NVfpOyKx0sKqioq9bX1C1m7Jgykkn8gLrtwumBioXIqam8DLxp88Adbue6Hw==} '@vitejs/plugin-vue@5.2.4': resolution: {integrity: sha512-7Yx/SXSOcQq5HiiV3orevHUFn+pmMB4cgbEkDYgnkUWb0WfeQ/wa2yFv6D5ICiCQOVpjA7vYDXrC7AGO8yjDHA==} @@ -965,6 +806,11 @@ packages: '@webgpu/types@0.1.69': resolution: {integrity: sha512-RPmm6kgRbI8e98zSD3RVACvnuktIja5+yLgDAkTmxLr90BEwdTXRQWNLF3ETTTyH/8mKhznZuN5AveXYFEsMGQ==} + acorn@8.16.0: + resolution: {integrity: sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==} + engines: {node: '>=0.4.0'} + hasBin: true + algoliasearch@5.46.2: resolution: {integrity: sha512-qqAXW9QvKf2tTyhpDA4qXv1IfBwD2eduSW6tUEBFIfCeE9gn9HQ9I5+MaKoenRuHrzk5sQoNh1/iof8mY7uD6Q==} engines: {node: '>= 14.0.0'} @@ -983,10 +829,6 @@ packages: resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==} engines: {node: '>=12'} - baseline-browser-mapping@2.9.19: - resolution: {integrity: sha512-ipDqC8FrAl/76p2SSWKSI+H9tFwm7vYqXQrItCuiVPt26Km0jS+NzSsBWAaBusvSbQcfJG+JitdMm+wZAgTYqg==} - hasBin: true - birpc@2.9.0: resolution: {integrity: sha512-KrayHS5pBi69Xi9JmvoqrIgYGDkD6mcSe/i6YKi3w5kekCLzrX4+nawcXqrj2tIp50Kw/mT/s3p+GVK0A0sKxw==} @@ -994,25 +836,10 @@ packages: resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} engines: {node: '>=8'} - browserslist@4.28.1: - resolution: {integrity: sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA==} - engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} - hasBin: true - cac@6.7.14: resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==} engines: {node: '>=8'} - caniuse-lite@1.0.30001769: - resolution: {integrity: sha512-BCfFL1sHijQlBGWBMuJyhZUhzo7wer5sVj9hqekB/7xn0Ypy+pER/edCYQm4exbXj4WiySGp40P8UuTh6w1srg==} - - cbor-extract@2.2.0: - resolution: {integrity: sha512-Ig1zM66BjLfTXpNgKpvBePq271BPOvu8MR0Jl080yG7Jsl+wAZunfrwiwA+9ruzm/WEdIV5QF/bjDZTqyAIVHA==} - hasBin: true - - cbor-x@1.6.0: - resolution: {integrity: sha512-0kareyRwHSkL6ws5VXHEf8uY1liitysCVJjlmhaLG+IXLqhSaOO+t63coaso7yjwEzWZzLy8fJo06gZDVQM9Qg==} - ccount@2.0.1: resolution: {integrity: sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==} @@ -1036,26 +863,204 @@ packages: resolution: {integrity: sha512-PAJdDJusoxnwm1VwW07VWwUN1sl7smmC3OKggvndJFadxxDRyFJBX/ggnu/KE4kQAB7a3Dp8f/YXC1FlUprWmA==} engines: {node: '>= 16'} + chevrotain-allstar@0.4.3: + resolution: {integrity: sha512-2X4mkroolSMKqW+H22pyPMUVDqYZzPhephTmg/NODKb1IGYPHfxfhcW0EjS7wcPJNbze2i4vBWT7zT5FKF2lrQ==} + peerDependencies: + chevrotain: ^12.0.0 + + chevrotain@12.0.0: + resolution: {integrity: sha512-csJvb+6kEiQaqo1woTdSAuOWdN0WTLIydkKrBnS+V5gZz0oqBrp4kQ35519QgK6TpBThiG3V1vNSHlIkv4AglQ==} + engines: {node: '>=22.0.0'} + colortap@0.3.0: resolution: {integrity: sha512-LgmIeerfTktjUE8D6dPq8W1iSaMqE2iRKDw2XBBCqOZAgssoXqCS6Lp2LAwXL40+85Fud8nTqMP81oHKqH4uLQ==} comma-separated-tokens@2.0.3: resolution: {integrity: sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==} + commander@7.2.0: + resolution: {integrity: sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==} + engines: {node: '>= 10'} + commander@8.3.0: resolution: {integrity: sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==} engines: {node: '>= 12'} - convert-source-map@2.0.0: - resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} + confbox@0.1.8: + resolution: {integrity: sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==} copy-anything@4.0.5: resolution: {integrity: sha512-7Vv6asjS4gMOuILabD3l739tsaxFQmC+a7pLZm02zyvs8p977bL3zEgq3yDk5rn9B0PbYgIv++jmHcuUab4RhA==} engines: {node: '>=18'} + cose-base@1.0.3: + resolution: {integrity: sha512-s9whTXInMSgAp/NVXVNuVxVKzGH2qck3aQlVHxDCdAEPgtMKwc4Wq6/QKhgdEdgbLSi9rBTAcPoRa6JpiG4ksg==} + + cose-base@2.2.0: + resolution: {integrity: sha512-AzlgcsCbUMymkADOJtQm3wO9S3ltPfYOFD5033keQn9NJzIbtnZj+UdBJe7DYml/8TdbtHJW3j58SOnKhWY/5g==} + csstype@3.2.3: resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==} + cytoscape-cose-bilkent@4.1.0: + resolution: {integrity: sha512-wgQlVIUJF13Quxiv5e1gstZ08rnZj2XaLHGoFMYXz7SkNfCDOOteKBE6SYRfA9WxxI/iBc3ajfDoc6hb/MRAHQ==} + peerDependencies: + cytoscape: ^3.2.0 + + cytoscape-fcose@2.2.0: + resolution: {integrity: sha512-ki1/VuRIHFCzxWNrsshHYPs6L7TvLu3DL+TyIGEsRcvVERmxokbf5Gdk7mFxZnTdiGtnA4cfSmjZJMviqSuZrQ==} + peerDependencies: + cytoscape: ^3.2.0 + + cytoscape@3.33.3: + resolution: {integrity: sha512-Gej7U+OKR+LZ8kvX7rb2HhCYJ0IhvEFsnkud4SB1PR+BUY/TsSO0dmOW59WEVLu51b1Rm+gQRKoz4bLYxGSZ2g==} + engines: {node: '>=0.10'} + + d3-array@2.12.1: + resolution: {integrity: sha512-B0ErZK/66mHtEsR1TkPEEkwdy+WDesimkM5gpZr5Dsg54BiTA5RXtYW5qTLIAcekaS9xfZrzBLF/OAkB3Qn1YQ==} + + d3-array@3.2.4: + resolution: {integrity: sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg==} + engines: {node: '>=12'} + + d3-axis@3.0.0: + resolution: {integrity: sha512-IH5tgjV4jE/GhHkRV0HiVYPDtvfjHQlQfJHs0usq7M30XcSBvOotpmH1IgkcXsO/5gEQZD43B//fc7SRT5S+xw==} + engines: {node: '>=12'} + + d3-brush@3.0.0: + resolution: {integrity: sha512-ALnjWlVYkXsVIGlOsuWH1+3udkYFI48Ljihfnh8FZPF2QS9o+PzGLBslO0PjzVoHLZ2KCVgAM8NVkXPJB2aNnQ==} + engines: {node: '>=12'} + + d3-chord@3.0.1: + resolution: {integrity: sha512-VE5S6TNa+j8msksl7HwjxMHDM2yNK3XCkusIlpX5kwauBfXuyLAtNg9jCp/iHH61tgI4sb6R/EIMWCqEIdjT/g==} + engines: {node: '>=12'} + + d3-color@3.1.0: + resolution: {integrity: sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==} + engines: {node: '>=12'} + + d3-contour@4.0.2: + resolution: {integrity: sha512-4EzFTRIikzs47RGmdxbeUvLWtGedDUNkTcmzoeyg4sP/dvCexO47AaQL7VKy/gul85TOxw+IBgA8US2xwbToNA==} + engines: {node: '>=12'} + + d3-delaunay@6.0.4: + resolution: {integrity: sha512-mdjtIZ1XLAM8bm/hx3WwjfHt6Sggek7qH043O8KEjDXN40xi3vx/6pYSVTwLjEgiXQTbvaouWKynLBiUZ6SK6A==} + engines: {node: '>=12'} + + d3-dispatch@3.0.1: + resolution: {integrity: sha512-rzUyPU/S7rwUflMyLc1ETDeBj0NRuHKKAcvukozwhshr6g6c5d8zh4c2gQjY2bZ0dXeGLWc1PF174P2tVvKhfg==} + engines: {node: '>=12'} + + d3-drag@3.0.0: + resolution: {integrity: sha512-pWbUJLdETVA8lQNJecMxoXfH6x+mO2UQo8rSmZ+QqxcbyA3hfeprFgIT//HW2nlHChWeIIMwS2Fq+gEARkhTkg==} + engines: {node: '>=12'} + + d3-dsv@3.0.1: + resolution: {integrity: sha512-UG6OvdI5afDIFP9w4G0mNq50dSOsXHJaRE8arAS5o9ApWnIElp8GZw1Dun8vP8OyHOZ/QJUKUJwxiiCCnUwm+Q==} + engines: {node: '>=12'} + hasBin: true + + d3-ease@3.0.1: + resolution: {integrity: sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==} + engines: {node: '>=12'} + + d3-fetch@3.0.1: + resolution: {integrity: sha512-kpkQIM20n3oLVBKGg6oHrUchHM3xODkTzjMoj7aWQFq5QEM+R6E4WkzT5+tojDY7yjez8KgCBRoj4aEr99Fdqw==} + engines: {node: '>=12'} + + d3-force@3.0.0: + resolution: {integrity: sha512-zxV/SsA+U4yte8051P4ECydjD/S+qeYtnaIyAs9tgHCqfguma/aAQDjo85A9Z6EKhBirHRJHXIgJUlffT4wdLg==} + engines: {node: '>=12'} + + d3-format@3.1.2: + resolution: {integrity: sha512-AJDdYOdnyRDV5b6ArilzCPPwc1ejkHcoyFarqlPqT7zRYjhavcT3uSrqcMvsgh2CgoPbK3RCwyHaVyxYcP2Arg==} + engines: {node: '>=12'} + + d3-geo@3.1.1: + resolution: {integrity: sha512-637ln3gXKXOwhalDzinUgY83KzNWZRKbYubaG+fGVuc/dxO64RRljtCTnf5ecMyE1RIdtqpkVcq0IbtU2S8j2Q==} + engines: {node: '>=12'} + + d3-hierarchy@3.1.2: + resolution: {integrity: sha512-FX/9frcub54beBdugHjDCdikxThEqjnR93Qt7PvQTOHxyiNCAlvMrHhclk3cD5VeAaq9fxmfRp+CnWw9rEMBuA==} + engines: {node: '>=12'} + + d3-interpolate@3.0.1: + resolution: {integrity: sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==} + engines: {node: '>=12'} + + d3-path@1.0.9: + resolution: {integrity: sha512-VLaYcn81dtHVTjEHd8B+pbe9yHWpXKZUC87PzoFmsFrJqgFwDe/qxfp5MlfsfM1V5E/iVt0MmEbWQ7FVIXh/bg==} + + d3-path@3.1.0: + resolution: {integrity: sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ==} + engines: {node: '>=12'} + + d3-polygon@3.0.1: + resolution: {integrity: sha512-3vbA7vXYwfe1SYhED++fPUQlWSYTTGmFmQiany/gdbiWgU/iEyQzyymwL9SkJjFFuCS4902BSzewVGsHHmHtXg==} + engines: {node: '>=12'} + + d3-quadtree@3.0.1: + resolution: {integrity: sha512-04xDrxQTDTCFwP5H6hRhsRcb9xxv2RzkcsygFzmkSIOJy3PeRJP7sNk3VRIbKXcog561P9oU0/rVH6vDROAgUw==} + engines: {node: '>=12'} + + d3-random@3.0.1: + resolution: {integrity: sha512-FXMe9GfxTxqd5D6jFsQ+DJ8BJS4E/fT5mqqdjovykEB2oFbTMDVdg1MGFxfQW+FBOGoB++k8swBrgwSHT1cUXQ==} + engines: {node: '>=12'} + + d3-sankey@0.12.3: + resolution: {integrity: sha512-nQhsBRmM19Ax5xEIPLMY9ZmJ/cDvd1BG3UVvt5h3WRxKg5zGRbvnteTyWAbzeSvlh3tW7ZEmq4VwR5mB3tutmQ==} + + d3-scale-chromatic@3.1.0: + resolution: {integrity: sha512-A3s5PWiZ9YCXFye1o246KoscMWqf8BsD9eRiJ3He7C9OBaxKhAd5TFCdEx/7VbKtxxTsu//1mMJFrEt572cEyQ==} + engines: {node: '>=12'} + + d3-scale@4.0.2: + resolution: {integrity: sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==} + engines: {node: '>=12'} + + d3-selection@3.0.0: + resolution: {integrity: sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==} + engines: {node: '>=12'} + + d3-shape@1.3.7: + resolution: {integrity: sha512-EUkvKjqPFUAZyOlhY5gzCxCeI0Aep04LwIRpsZ/mLFelJiUfnK56jo5JMDSE7yyP2kLSb6LtF+S5chMk7uqPqw==} + + d3-shape@3.2.0: + resolution: {integrity: sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA==} + engines: {node: '>=12'} + + d3-time-format@4.1.0: + resolution: {integrity: sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg==} + engines: {node: '>=12'} + + d3-time@3.1.0: + resolution: {integrity: sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q==} + engines: {node: '>=12'} + + d3-timer@3.0.1: + resolution: {integrity: sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==} + engines: {node: '>=12'} + + d3-transition@3.0.1: + resolution: {integrity: sha512-ApKvfjsSR6tg06xrL434C0WydLr7JewBB3V+/39RMHsaXTOG0zmt/OAXeng5M5LBm0ojmxJrpomQVZ1aPvBL4w==} + engines: {node: '>=12'} + peerDependencies: + d3-selection: 2 - 3 + + d3-zoom@3.0.0: + resolution: {integrity: sha512-b8AmV3kfQaqWAuacbPuNbL6vahnOJflOhexLzMMNLga62+/nh0JzvJ0aO/5a5MVgUFGS7Hu1P9P03o3fJkDCyw==} + engines: {node: '>=12'} + + d3@7.9.0: + resolution: {integrity: sha512-e1U46jVP+w7Iut8Jt8ri1YsPOvFpg46k+K8TpCb0P+zjCkjkPnV7WzfDJzMHy1LnA+wj5pLT1wjO901gLXeEhA==} + engines: {node: '>=12'} + + dagre-d3-es@7.0.14: + resolution: {integrity: sha512-P4rFMVq9ESWqmOgK+dlXvOtLwYg0i7u0HBGJER0LZDJT2VHIPAMZ/riPxqJceWMStH5+E61QxFra9kIS3AqdMg==} + + dayjs@1.11.20: + resolution: {integrity: sha512-YbwwqR/uYpeoP4pu043q+LTDLFBLApUP6VxRihdfNTqu4ubqMlGDLd6ErXhEgsyvY0K6nCs7nggYumAN+9uEuQ==} + debug@4.4.3: resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} engines: {node: '>=6.0'} @@ -1072,19 +1077,18 @@ packages: resolution: {integrity: sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==} engines: {node: '>=6'} + delaunator@5.1.0: + resolution: {integrity: sha512-AGrQ4QSgssa1NGmWmLPqN5NY2KajF5MqxetNEO+o0n3ZwZZeTmt7bBnvzHWrmkZFxGgr4HdyFgelzgi06otLuQ==} + dequal@2.0.3: resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==} engines: {node: '>=6'} - detect-libc@2.1.2: - resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==} - engines: {node: '>=8'} - devlop@1.1.0: resolution: {integrity: sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==} - electron-to-chromium@1.5.286: - resolution: {integrity: sha512-9tfDXhJ4RKFNerfjdCcZfufu49vg620741MNs26a9+bhLThdB+plgMeou98CAaHu/WATj2iHOOHTp1hWtABj2A==} + dompurify@3.4.2: + resolution: {integrity: sha512-lHeS9SA/IKeIFFyYciHBr2n0v1VMPlSj843HdLOwjb2OxNwdq9Xykxqhk+FE42MzAdHvInbAolSE4mhahPpjXA==} emoji-regex-xs@1.0.0: resolution: {integrity: sha512-LRlerrMYoIDrT6jgpeZ2YYl/L8EulRTt5hQcYjy5AInh7HWXKimpqx68aknBFpGL2+/IcogTcaydJEgaTmOpDg==} @@ -1101,15 +1105,6 @@ packages: engines: {node: '>=12'} hasBin: true - esbuild@0.25.12: - resolution: {integrity: sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==} - engines: {node: '>=18'} - hasBin: true - - escalade@3.2.0: - resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} - engines: {node: '>=6'} - estree-walker@2.0.2: resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==} @@ -1127,15 +1122,6 @@ packages: fastq@1.20.1: resolution: {integrity: sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==} - fdir@6.5.0: - resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==} - engines: {node: '>=12.0.0'} - peerDependencies: - picomatch: ^3 || ^4 - peerDependenciesMeta: - picomatch: - optional: true - fflate@0.8.2: resolution: {integrity: sha512-cPJU47OaAoCbg0pBvzsgpTPhmhqI5eJjh/JIu8tPj5q+T7iLvW/JAYUqmE7KOB4R1ZyEhzBaIQpQpardBF5z8A==} @@ -1156,10 +1142,6 @@ packages: engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} os: [darwin] - gensync@1.0.0-beta.2: - resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} - engines: {node: '>=6.9.0'} - get-east-asian-width@1.5.0: resolution: {integrity: sha512-CQ+bEO+Tva/qlmw24dCejulK5pMzVnUOFOijVogd3KQs07HnRIgp8TGipvCCRT06xeYEbpbgwaCxglFyiuIcmA==} engines: {node: '>=18'} @@ -1176,6 +1158,9 @@ packages: resolution: {integrity: sha512-mS1lbMsxgQj6hge1XZ6p7GPhbrtFwUFYi3wRzXAC/FmYnyXMTvvI3td3rjmQ2u8ewXueaSvRPWaEcgVVOT9Jnw==} engines: {node: ^12.22.0 || ^14.16.0 || ^16.0.0 || >=17.0.0} + hachure-fill@0.5.2: + resolution: {integrity: sha512-3GKBOn+m2LX9iq+JC1064cSFprJY4jL1jCXTcpnfER5HYE2l/4EfWSGzkPa/ZDBmYI0ZOEj5VHV/eKnPGkHuOg==} + hast-util-to-html@9.0.5: resolution: {integrity: sha512-OguPdidb+fbHQSU4Q4ZiLKnzWo8Wwsf5bZfbvu7//a9oTYoqD/fWpe96NuHkoS9h0ccGOTe0C4NGXdtS0iObOw==} @@ -1188,10 +1173,21 @@ packages: html-void-elements@3.0.0: resolution: {integrity: sha512-bEqo66MRXsUGxWHV5IP0PUiAWwoEjba4VCzg0LjFJBpchPaTfyfCKTG6bc5F8ucKec3q5y6qOdGyYTSBEvhCrg==} + iconv-lite@0.6.3: + resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==} + engines: {node: '>=0.10.0'} + ignore@7.0.5: resolution: {integrity: sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==} engines: {node: '>= 4'} + internmap@1.0.1: + resolution: {integrity: sha512-lDB5YccMydFBtasVtxnZ3MRBHuaoE8GKsppq+EchKL2U4nK/DmEpPHNH8MZe5HkMtpSiTSOZwfN0tzYjO/lJEw==} + + internmap@2.0.3: + resolution: {integrity: sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==} + engines: {node: '>=12'} + is-alphabetical@2.0.1: resolution: {integrity: sha512-FWyyY60MeTNyeSRpkM2Iry0G9hpr7/9kD40mD/cGQEuilcZYS4okz8SN2Q6rLCJ8gbCt6fN+rC+6tMGS99LaxQ==} @@ -1231,16 +1227,6 @@ packages: resolution: {integrity: sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==} hasBin: true - jsesc@3.1.0: - resolution: {integrity: sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==} - engines: {node: '>=6'} - hasBin: true - - json5@2.2.3: - resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==} - engines: {node: '>=6'} - hasBin: true - jsonc-parser@3.3.1: resolution: {integrity: sha512-HUgH65KyejrUFPvHFPbqOY0rsFip3Bo5wb4ngvdi1EpCYWUQDC5V+Y7mZws+DLkr4M//zQJoanu1SP+87Dv1oQ==} @@ -1252,9 +1238,25 @@ packages: resolution: {integrity: sha512-sZ4jqyEXfHTLEFK+qsFYToa3UZ0rtFcPGwKpyiRYh2NJn8obPWOQ+/u7ux0F6CAU/y78+Mksh1YkxTPXTh47TQ==} hasBin: true + khroma@2.1.0: + resolution: {integrity: sha512-Ls993zuzfayK269Svk9hzpeGUKob/sIgZzyHYdjQoAdQetRKpOLj+k/QQQ/6Qi0Yz65mlROrfd+Ev+1+7dz9Kw==} + + langium@4.2.3: + resolution: {integrity: sha512-sOPIi4hISFnY7twwV97ca1TsxpBtXq0URu/LL1AvxwccPG/RIBBlKS7a/f/EL6w8lTNaS0EFs/F+IdSOaqYpng==} + engines: {node: '>=20.10.0', npm: '>=10.2.3'} + + layout-base@1.0.2: + resolution: {integrity: sha512-8h2oVEZNktL4BH2JCOI90iD1yXwL6iNW7KcCKT2QZgQJR2vbqDsldCTPRU9NifTCqHZci57XvQQ15YTu+sTYPg==} + + layout-base@2.0.1: + resolution: {integrity: sha512-dp3s92+uNI1hWIpPGH3jK2kxE2lMjdXdr+DH8ynZHpd6PUlH6x6cbuXnoMmiNumznqaNO31xu9e79F0uuZ0JFg==} + linkify-it@5.0.0: resolution: {integrity: sha512-5aHCbzQRADcdP+ATqnDuhhJ/MRIqDkZX5pyjFHRRysS8vZ5AbqGEoFIb6pYHPZ+L/OC2Lc+xT8uHVVR5CAK/wQ==} + lodash-es@4.18.1: + resolution: {integrity: sha512-J8xewKD/Gk22OZbhpOVSwcs60zhd95ESDwezOFuA3/099925PdHJ7OFHNTGtajL3AlZkykD32HykiMo+BIBI8A==} + loose-envify@1.4.0: resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==} hasBin: true @@ -1262,9 +1264,6 @@ packages: loupe@3.2.1: resolution: {integrity: sha512-CdzqowRJCeLU72bHvWqwRBBlLcMEtIvGrlvef74kMnV2AolS9Y8xUv1I0U/MNAWMhBlKIoyuEgoJ0t/bbwHbLQ==} - lru-cache@5.1.1: - resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} - magic-string@0.30.21: resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==} @@ -1289,6 +1288,11 @@ packages: resolution: {integrity: sha512-UKybllYNheWac61Ia7T6fzuQNDZimFIpCg2w6hHjgV1Qu0w1TV0LlSgryUGzM0bkKQCBhy2FDhEELB73Kb0kAg==} engines: {node: '>=20'} + marked@16.4.2: + resolution: {integrity: sha512-TI3V8YYWvkVf3KJe1dRkpnjs68JUPyEa5vjKrp1XEEJUAOaQc+Qj+L1qWbPd0SJuAdQkFU0h73sXXqwDYxsiDA==} + engines: {node: '>= 20'} + hasBin: true + mdast-util-to-hast@13.2.1: resolution: {integrity: sha512-cctsq2wp5vTsLIcaymblUriiTcZd0CwWtCbLvrOzYCDZoWyMNV8sZ7krj09FSnsiJi3WVsHLM4k6Dq/yaPyCXA==} @@ -1299,6 +1303,9 @@ packages: resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} engines: {node: '>= 8'} + mermaid@11.14.0: + resolution: {integrity: sha512-GSGloRsBs+JINmmhl0JDwjpuezCsHB4WGI4NASHxL3fHo3o/BRXTxhDLKnln8/Q0lRFRyDdEjmk1/d5Sn1Xz8g==} + meshoptimizer@0.18.1: resolution: {integrity: sha512-ZhoIoL7TNV4s5B6+rx5mC//fw8/POGyNxS/DZyCJeiZ12ScLfVwRE/GfsxwiTkMYYD5DmK2/JXnEVXqL4rF+Sw==} @@ -1387,6 +1394,9 @@ packages: mitt@3.0.1: resolution: {integrity: sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw==} + mlly@1.8.2: + resolution: {integrity: sha512-d+ObxMQFmbt10sretNDytwt85VrbkhhUA/JBGm1MPaWJ65Cl4wOgLaB1NYvJSZ0Ef03MMEU/0xpPMXUIQ29UfA==} + ms@2.1.3: resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} @@ -1395,22 +1405,27 @@ packages: engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} hasBin: true - node-gyp-build-optional-packages@5.1.1: - resolution: {integrity: sha512-+P72GAjVAbTxjjwUmwjVrqrdZROD4nf8KgpBoDxqXXTiYZZt/ud60dE5yvCSr9lRO8e8yv6kgJIC0K0PfZFVQw==} - hasBin: true - - node-releases@2.0.27: - resolution: {integrity: sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA==} + non-layered-tidy-tree-layout@2.0.2: + resolution: {integrity: sha512-gkXMxRzUH+PB0ax9dUN0yYF0S25BqeAYqhgMaLUFmpXLEk7Fcu8f4emJuOAY0V8kjDICxROIKsTAKsV/v355xw==} oniguruma-to-es@3.1.1: resolution: {integrity: sha512-bUH8SDvPkH3ho3dvwJwfonjlQ4R80vjyvrU8YpxuROddv55vAEJrTuCuCVUhhsHbtlD9tGGbaNApGQckXhS8iQ==} + package-manager-detector@1.6.0: + resolution: {integrity: sha512-61A5ThoTiDG/C8s8UMZwSorAGwMJ0ERVGj2OjoW5pAalsNOg15+iQiPzrLJ4jhZ1HJzmC2PIHT2oEiH3R5fzNA==} + parse-entities@4.0.2: resolution: {integrity: sha512-GG2AQYWoLgL877gQIKeRPGO1xF9+eG1ujIb5soS5gPvLQ1y2o8FL90w2QWNdf9I361Mpp7726c+lj3U0qK1uGw==} + path-data-parser@0.1.0: + resolution: {integrity: sha512-NOnmBpt5Y2RWbuv0LMzsayp3lVylAHLPUTut412ZA3l+C4uw4ZVkQbjShYCQ8TCpUMdPapr4YjUqLYD6v68j+w==} + pathe@1.1.2: resolution: {integrity: sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==} + pathe@2.0.3: + resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==} + pathval@2.0.1: resolution: {integrity: sha512-//nshmD55c46FuFw26xV/xFAaB5HF9Xdap7HJBBnrKdAd6/GxDBaNA1870O79+9ueg61cZLSVc+OaFlfmObYVQ==} engines: {node: '>= 14.16'} @@ -1425,9 +1440,8 @@ packages: resolution: {integrity: sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==} engines: {node: '>=8.6'} - picomatch@4.0.3: - resolution: {integrity: sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==} - engines: {node: '>=12'} + pkg-types@1.3.1: + resolution: {integrity: sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ==} playwright-core@1.57.0: resolution: {integrity: sha512-agTcKlMw/mjBWOnD6kFZttAAGHgi/Nw0CZ2o6JqWSbMlI219lAFLZZCyqByTsvVAJq5XA5H8cA6PrvBRpBWEuQ==} @@ -1439,6 +1453,12 @@ packages: engines: {node: '>=18'} hasBin: true + points-on-curve@0.2.0: + resolution: {integrity: sha512-0mYKnYYe9ZcqMCWhUjItv/oHjvgEsfKvnUTg8sAtnHr3GVy7rGkXCb6d5cSyqrWqL4k81b9CPg3urd+T7aop3A==} + + points-on-path@0.2.1: + resolution: {integrity: sha512-25ClnWWuw7JbWZcgqY/gJ4FQWadKxGWk+3kR/7kD0tCaDtPPMj7oHu2ToLaVhfpnHrZzYby2w6tUA0eOIuUg8g==} + postcss@8.5.6: resolution: {integrity: sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==} engines: {node: ^10 || ^12 || >=14} @@ -1466,10 +1486,6 @@ packages: peerDependencies: react: ^18.3.1 - react-refresh@0.17.0: - resolution: {integrity: sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ==} - engines: {node: '>=0.10.0'} - react@18.3.1: resolution: {integrity: sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==} engines: {node: '>=0.10.0'} @@ -1490,24 +1506,32 @@ packages: rfdc@1.4.1: resolution: {integrity: sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==} + robust-predicates@3.0.3: + resolution: {integrity: sha512-NS3levdsRIUOmiJ8FZWCP7LG3QpJyrs/TE0Zpf1yvZu8cAJJ6QMW92H1c7kWpdIHo8RvmLxN/o2JXTKHp74lUA==} + rollup@4.54.0: resolution: {integrity: sha512-3nk8Y3a9Ea8szgKhinMlGMhGMw89mqule3KWczxhIzqudyHdCIOHw8WJlj/r329fACjKLEh13ZSk7oE22kyeIw==} engines: {node: '>=18.0.0', npm: '>=8.0.0'} hasBin: true + roughjs@4.6.6: + resolution: {integrity: sha512-ZUz/69+SYpFN/g/lUlo2FXcIjRkSu3nDarreVdGGndHEBJ6cXPdKguS8JGxwj5HA5xIbVKSmLgr5b3AWxtRfvQ==} + run-parallel@1.2.0: resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} + rw@1.3.3: + resolution: {integrity: sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ==} + + safer-buffer@2.1.2: + resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} + scheduler@0.23.2: resolution: {integrity: sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==} search-insights@2.17.3: resolution: {integrity: sha512-RQPdCYTa8A68uM2jwxoY842xDhvx3E5LFL1LxvxCNMev4o5mLuokczhzjAgGwUZBAmOKZknArSxLKmXtIi2AxQ==} - semver@6.3.1: - resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} - hasBin: true - shiki@2.5.0: resolution: {integrity: sha512-mI//trrsaiCIPsja5CNfsyNOqgAZUb6VpJA+340toL42UpzQlXpwRV9nch69X6gaUxrr9kaOOa6e3y3uAkGFxQ==} @@ -1550,6 +1574,9 @@ packages: resolution: {integrity: sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==} engines: {node: '>=12'} + stylis@4.4.0: + resolution: {integrity: sha512-5Z9ZpRzfuH6l/UAvCPAPUo3665Nk2wLaZU3x+TLHKVzIz33+sbJqbtrYoC3KD4/uVOr2Zp+L0LySezP9OHV9yA==} + superjson@2.2.6: resolution: {integrity: sha512-H+ue8Zo4vJmV2nRjpx86P35lzwDT3nItnIsocgumgr0hHMQ+ZGq5vrERg9kJBo5AWGmxZDhzDo+WVIJqkB0cGA==} engines: {node: '>=16'} @@ -1566,9 +1593,9 @@ packages: tinyexec@0.3.2: resolution: {integrity: sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==} - tinyglobby@0.2.15: - resolution: {integrity: sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==} - engines: {node: '>=12.0.0'} + tinyexec@1.1.2: + resolution: {integrity: sha512-dAqSqE/RabpBKI8+h26GfLq6Vb3JVXs30XYQjdMjaj/c2tS8IYYMbIzP599KtRj7c57/wYApb3QjgRgXmrCukA==} + engines: {node: '>=18'} tinypool@1.1.1: resolution: {integrity: sha512-Zba82s87IFq9A9XmjiX5uZA/ARWDrB03OHlq+Vw1fSdt0I+4/Kutwy8BP4Y/y/aORMo61FQ0vIb5j44vSo5Pkg==} @@ -1589,6 +1616,10 @@ packages: trim-lines@3.0.1: resolution: {integrity: sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg==} + ts-dedent@2.2.0: + resolution: {integrity: sha512-q5W7tVM71e2xjHZTlgfTDoPF/SmqKG5hddq9SzR49CH2hayqRKJtQ4mtRlSxKaJlR/+9rEM+mnBHf7I2/BQcpQ==} + engines: {node: '>=6.10'} + typescript@5.6.3: resolution: {integrity: sha512-hjcS1mhfuyi4WW8IWtjP7brDrG2cuDZukyrYrSauoXGNgx0S7zceP07adYkJycEr56BOUTNPzbInooiN3fn1qw==} engines: {node: '>=14.17'} @@ -1597,6 +1628,9 @@ packages: uc.micro@2.1.0: resolution: {integrity: sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==} + ufo@1.6.4: + resolution: {integrity: sha512-JFNbkD1Svwe0KvGi8GOeLcP4kAWQ609twvCdcHxq1oSL8svv39ZuSvajcD8B+5D0eL4+s1Is2D/O6KN3qcTeRA==} + undici-types@7.16.0: resolution: {integrity: sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==} @@ -1619,11 +1653,9 @@ packages: unist-util-visit@5.0.0: resolution: {integrity: sha512-MR04uvD+07cwl/yhVuVWAtw+3GOR/knlL55Nd/wAdblk27GCVt3lqpTivy/tkJcZoNPzTwS1Y+KMojlLDhoTzg==} - update-browserslist-db@1.2.3: - resolution: {integrity: sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==} + uuid@11.1.1: + resolution: {integrity: sha512-vIYxrBCC/N/K+Js3qSN88go7kIfNPssr/hHCesKCQNAjmgvYS2oqr69kIufEG+O4+PfezOH4EbIeHCfFov8ZgQ==} hasBin: true - peerDependencies: - browserslist: '>= 4.21.0' vfile-message@4.0.3: resolution: {integrity: sha512-QTHzsGd1EhbZs4AsQ20JX1rC3cOlt/IWJruk893DfLRr57lcnOeMaWG4K0JrRta4mIJZKth2Au3mM3u03/JWKw==} @@ -1636,11 +1668,6 @@ packages: engines: {node: ^18.0.0 || >=20.0.0} hasBin: true - vite-plugin-wasm@3.5.0: - resolution: {integrity: sha512-X5VWgCnqiQEGb+omhlBVsvTfxikKtoOgAzQ95+BZ8gQ+VfMHIjSHr0wyvXFQCa0eKQ0fKyaL0kWcEnYqBac4lQ==} - peerDependencies: - vite: ^2 || ^3 || ^4 || ^5 || ^6 || ^7 - vite@5.4.21: resolution: {integrity: sha512-o5a9xKjbtuhY6Bi5S3+HvbRERmouabWbyUcpXXUA1u+GNUKoROi9byOJ8M0nHbHYHkYICiMlqxkg1KkYmm25Sw==} engines: {node: ^18.0.0 || >=20.0.0} @@ -1672,45 +1699,11 @@ packages: terser: optional: true - vite@6.4.1: - resolution: {integrity: sha512-+Oxm7q9hDoLMyJOYfUYBuHQo+dkAloi33apOPP56pzj+vsdJDzr+j1NISE5pyaAuKL4A3UD34qd0lx5+kfKp2g==} - engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} - hasBin: true + vitepress-plugin-mermaid@2.0.17: + resolution: {integrity: sha512-IUzYpwf61GC6k0XzfmAmNrLvMi9TRrVRMsUyCA8KNXhg/mQ1VqWnO0/tBVPiX5UoKF1mDUwqn5QV4qAJl6JnUg==} peerDependencies: - '@types/node': ^18.0.0 || ^20.0.0 || >=22.0.0 - jiti: '>=1.21.0' - less: '*' - lightningcss: ^1.21.0 - sass: '*' - sass-embedded: '*' - stylus: '*' - sugarss: '*' - terser: ^5.16.0 - tsx: ^4.8.1 - yaml: ^2.4.2 - peerDependenciesMeta: - '@types/node': - optional: true - jiti: - optional: true - less: - optional: true - lightningcss: - optional: true - sass: - optional: true - sass-embedded: - optional: true - stylus: - optional: true - sugarss: - optional: true - terser: - optional: true - tsx: - optional: true - yaml: - optional: true + mermaid: 10 || 11 + vitepress: ^1.0.0 || ^1.0.0-alpha vitepress@1.6.4: resolution: {integrity: sha512-+2ym1/+0VVrbhNyRoFFesVvBvHAVMZMK0rw60E3X/5349M1GuVdKeazuksqopEdvkKwKGs21Q729jX81/bkBJg==} @@ -1749,6 +1742,26 @@ packages: jsdom: optional: true + vscode-jsonrpc@8.2.0: + resolution: {integrity: sha512-C+r0eKJUIfiDIfwJhria30+TYWPtuHJXHtI7J0YlOmKAo7ogxP20T0zxB7HZQIFhIyvoBPwWskjxrvAtfjyZfA==} + engines: {node: '>=14.0.0'} + + vscode-languageserver-protocol@3.17.5: + resolution: {integrity: sha512-mb1bvRJN8SVznADSGWM9u/b07H7Ecg0I3OgXDuLdn307rl/J3A9YD6/eYOssqhecL27hK1IPZAsaqh00i/Jljg==} + + vscode-languageserver-textdocument@1.0.12: + resolution: {integrity: sha512-cxWNPesCnQCcMPeenjKKsOCKQZ/L6Tv19DTRIGuLWe32lyzWhihGVJ/rcckZXJxfdKCFvRLS3fpBIsV/ZGX4zA==} + + vscode-languageserver-types@3.17.5: + resolution: {integrity: sha512-Ld1VelNuX9pdF39h2Hgaeb5hEZM2Z3jUrrMgWQAu82jMtZp7p3vJT3BzToKtZI7NgQssZje5o0zryOrhQvzQAg==} + + vscode-languageserver@9.0.1: + resolution: {integrity: sha512-woByF3PDpkHFUreUa7Hos7+pUWdeWMXRd26+ZX2A8cFx6v/JPTtd4/uN0/jB6XQHYaOlHbio03NTHCqrgG5n7g==} + hasBin: true + + vscode-uri@3.1.0: + resolution: {integrity: sha512-/BpdSx+yCQGnCvecbyXdxHDkuk55/G3xwnC0GqY4gmQ3j+A+g8kzzgB4Nk/SINjqn6+waqw3EgbVF2QKExkRxQ==} + vue@3.5.25: resolution: {integrity: sha512-YLVdgv2K13WJ6n+kD5owehKtEXwdwXuj2TTyJMsO7pSeKw2bfRNZGjhB7YzrpbMYj5b5QsUebHpOqR3R3ziy/g==} peerDependencies: @@ -1762,30 +1775,9 @@ packages: engines: {node: '>=8'} hasBin: true - yallist@3.1.1: - resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} - zod@4.3.6: resolution: {integrity: sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg==} - zustand@5.0.11: - resolution: {integrity: sha512-fdZY+dk7zn/vbWNCYmzZULHRrss0jx5pPFiOuMZ/5HJN6Yv3u+1Wswy/4MpZEkEGhtNH+pwxZB8OKgUBPzYAGg==} - engines: {node: '>=12.20.0'} - peerDependencies: - '@types/react': '>=18.0.0' - immer: '>=9.0.6' - react: '>=18.0.0' - use-sync-external-store: '>=1.2.0' - peerDependenciesMeta: - '@types/react': - optional: true - immer: - optional: true - react: - optional: true - use-sync-external-store: - optional: true - zwitch@2.0.4: resolution: {integrity: sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==} @@ -1903,144 +1895,43 @@ snapshots: dependencies: '@algolia/client-common': 5.46.2 - '@babel/code-frame@7.29.0': + '@antfu/install-pkg@1.1.0': dependencies: - '@babel/helper-validator-identifier': 7.28.5 - js-tokens: 4.0.0 - picocolors: 1.1.1 - - '@babel/compat-data@7.29.0': {} - - '@babel/core@7.29.0': - dependencies: - '@babel/code-frame': 7.29.0 - '@babel/generator': 7.29.1 - '@babel/helper-compilation-targets': 7.28.6 - '@babel/helper-module-transforms': 7.28.6(@babel/core@7.29.0) - '@babel/helpers': 7.28.6 - '@babel/parser': 7.29.0 - '@babel/template': 7.28.6 - '@babel/traverse': 7.29.0 - '@babel/types': 7.29.0 - '@jridgewell/remapping': 2.3.5 - convert-source-map: 2.0.0 - debug: 4.4.3 - gensync: 1.0.0-beta.2 - json5: 2.2.3 - semver: 6.3.1 - transitivePeerDependencies: - - supports-color - - '@babel/generator@7.29.1': - dependencies: - '@babel/parser': 7.29.0 - '@babel/types': 7.29.0 - '@jridgewell/gen-mapping': 0.3.13 - '@jridgewell/trace-mapping': 0.3.31 - jsesc: 3.1.0 - - '@babel/helper-compilation-targets@7.28.6': - dependencies: - '@babel/compat-data': 7.29.0 - '@babel/helper-validator-option': 7.27.1 - browserslist: 4.28.1 - lru-cache: 5.1.1 - semver: 6.3.1 - - '@babel/helper-globals@7.28.0': {} - - '@babel/helper-module-imports@7.28.6': - dependencies: - '@babel/traverse': 7.29.0 - '@babel/types': 7.29.0 - transitivePeerDependencies: - - supports-color - - '@babel/helper-module-transforms@7.28.6(@babel/core@7.29.0)': - dependencies: - '@babel/core': 7.29.0 - '@babel/helper-module-imports': 7.28.6 - '@babel/helper-validator-identifier': 7.28.5 - '@babel/traverse': 7.29.0 - transitivePeerDependencies: - - supports-color - - '@babel/helper-plugin-utils@7.28.6': {} + package-manager-detector: 1.6.0 + tinyexec: 1.1.2 '@babel/helper-string-parser@7.27.1': {} '@babel/helper-validator-identifier@7.28.5': {} - '@babel/helper-validator-option@7.27.1': {} - - '@babel/helpers@7.28.6': - dependencies: - '@babel/template': 7.28.6 - '@babel/types': 7.29.0 - '@babel/parser@7.28.5': dependencies: '@babel/types': 7.28.5 - '@babel/parser@7.29.0': - dependencies: - '@babel/types': 7.29.0 - - '@babel/plugin-transform-react-jsx-self@7.27.1(@babel/core@7.29.0)': - dependencies: - '@babel/core': 7.29.0 - '@babel/helper-plugin-utils': 7.28.6 - - '@babel/plugin-transform-react-jsx-source@7.27.1(@babel/core@7.29.0)': - dependencies: - '@babel/core': 7.29.0 - '@babel/helper-plugin-utils': 7.28.6 - - '@babel/template@7.28.6': - dependencies: - '@babel/code-frame': 7.29.0 - '@babel/parser': 7.29.0 - '@babel/types': 7.29.0 - - '@babel/traverse@7.29.0': - dependencies: - '@babel/code-frame': 7.29.0 - '@babel/generator': 7.29.1 - '@babel/helper-globals': 7.28.0 - '@babel/parser': 7.29.0 - '@babel/template': 7.28.6 - '@babel/types': 7.29.0 - debug: 4.4.3 - transitivePeerDependencies: - - supports-color - '@babel/types@7.28.5': dependencies: '@babel/helper-string-parser': 7.27.1 '@babel/helper-validator-identifier': 7.28.5 - '@babel/types@7.29.0': - dependencies: - '@babel/helper-string-parser': 7.27.1 - '@babel/helper-validator-identifier': 7.28.5 - - '@cbor-extract/cbor-extract-darwin-arm64@2.2.0': + '@braintree/sanitize-url@6.0.4': optional: true - '@cbor-extract/cbor-extract-darwin-x64@2.2.0': - optional: true + '@braintree/sanitize-url@7.1.2': {} - '@cbor-extract/cbor-extract-linux-arm64@2.2.0': - optional: true + '@chevrotain/cst-dts-gen@12.0.0': + dependencies: + '@chevrotain/gast': 12.0.0 + '@chevrotain/types': 12.0.0 - '@cbor-extract/cbor-extract-linux-arm@2.2.0': - optional: true + '@chevrotain/gast@12.0.0': + dependencies: + '@chevrotain/types': 12.0.0 - '@cbor-extract/cbor-extract-linux-x64@2.2.0': - optional: true + '@chevrotain/regexp-to-ast@12.0.0': {} - '@cbor-extract/cbor-extract-win32-x64@2.2.0': - optional: true + '@chevrotain/types@12.0.0': {} + + '@chevrotain/utils@12.0.0': {} '@docsearch/css@3.8.2': {} @@ -2072,174 +1963,100 @@ snapshots: '@esbuild/aix-ppc64@0.21.5': optional: true - '@esbuild/aix-ppc64@0.25.12': - optional: true - '@esbuild/android-arm64@0.21.5': optional: true - '@esbuild/android-arm64@0.25.12': - optional: true - '@esbuild/android-arm@0.21.5': optional: true - '@esbuild/android-arm@0.25.12': - optional: true - - '@esbuild/android-x64@0.21.5': - optional: true - - '@esbuild/android-x64@0.25.12': - optional: true - - '@esbuild/darwin-arm64@0.21.5': - optional: true - - '@esbuild/darwin-arm64@0.25.12': - optional: true - - '@esbuild/darwin-x64@0.21.5': - optional: true - - '@esbuild/darwin-x64@0.25.12': - optional: true - - '@esbuild/freebsd-arm64@0.21.5': - optional: true - - '@esbuild/freebsd-arm64@0.25.12': - optional: true - - '@esbuild/freebsd-x64@0.21.5': - optional: true - - '@esbuild/freebsd-x64@0.25.12': - optional: true - - '@esbuild/linux-arm64@0.21.5': - optional: true - - '@esbuild/linux-arm64@0.25.12': - optional: true - - '@esbuild/linux-arm@0.21.5': - optional: true - - '@esbuild/linux-arm@0.25.12': - optional: true - - '@esbuild/linux-ia32@0.21.5': - optional: true - - '@esbuild/linux-ia32@0.25.12': - optional: true - - '@esbuild/linux-loong64@0.21.5': - optional: true - - '@esbuild/linux-loong64@0.25.12': - optional: true - - '@esbuild/linux-mips64el@0.21.5': - optional: true - - '@esbuild/linux-mips64el@0.25.12': + '@esbuild/android-x64@0.21.5': optional: true - '@esbuild/linux-ppc64@0.21.5': + '@esbuild/darwin-arm64@0.21.5': optional: true - '@esbuild/linux-ppc64@0.25.12': + '@esbuild/darwin-x64@0.21.5': optional: true - '@esbuild/linux-riscv64@0.21.5': + '@esbuild/freebsd-arm64@0.21.5': optional: true - '@esbuild/linux-riscv64@0.25.12': + '@esbuild/freebsd-x64@0.21.5': optional: true - '@esbuild/linux-s390x@0.21.5': + '@esbuild/linux-arm64@0.21.5': optional: true - '@esbuild/linux-s390x@0.25.12': + '@esbuild/linux-arm@0.21.5': optional: true - '@esbuild/linux-x64@0.21.5': + '@esbuild/linux-ia32@0.21.5': optional: true - '@esbuild/linux-x64@0.25.12': + '@esbuild/linux-loong64@0.21.5': optional: true - '@esbuild/netbsd-arm64@0.25.12': + '@esbuild/linux-mips64el@0.21.5': optional: true - '@esbuild/netbsd-x64@0.21.5': + '@esbuild/linux-ppc64@0.21.5': optional: true - '@esbuild/netbsd-x64@0.25.12': + '@esbuild/linux-riscv64@0.21.5': optional: true - '@esbuild/openbsd-arm64@0.25.12': + '@esbuild/linux-s390x@0.21.5': optional: true - '@esbuild/openbsd-x64@0.21.5': + '@esbuild/linux-x64@0.21.5': optional: true - '@esbuild/openbsd-x64@0.25.12': + '@esbuild/netbsd-x64@0.21.5': optional: true - '@esbuild/openharmony-arm64@0.25.12': + '@esbuild/openbsd-x64@0.21.5': optional: true '@esbuild/sunos-x64@0.21.5': optional: true - '@esbuild/sunos-x64@0.25.12': - optional: true - '@esbuild/win32-arm64@0.21.5': optional: true - '@esbuild/win32-arm64@0.25.12': - optional: true - '@esbuild/win32-ia32@0.21.5': optional: true - '@esbuild/win32-ia32@0.25.12': - optional: true - '@esbuild/win32-x64@0.21.5': optional: true - '@esbuild/win32-x64@0.25.12': - optional: true - '@iconify-json/simple-icons@1.2.64': dependencies: '@iconify/types': 2.0.0 '@iconify/types@2.0.0': {} - '@jridgewell/gen-mapping@0.3.13': - dependencies: - '@jridgewell/sourcemap-codec': 1.5.5 - '@jridgewell/trace-mapping': 0.3.31 - - '@jridgewell/remapping@2.3.5': + '@iconify/utils@3.1.1': dependencies: - '@jridgewell/gen-mapping': 0.3.13 - '@jridgewell/trace-mapping': 0.3.31 - - '@jridgewell/resolve-uri@3.1.2': {} + '@antfu/install-pkg': 1.1.0 + '@iconify/types': 2.0.0 + mlly: 1.8.2 '@jridgewell/sourcemap-codec@1.5.5': {} - '@jridgewell/trace-mapping@0.3.31': + '@mermaid-js/mermaid-mindmap@9.3.0': dependencies: - '@jridgewell/resolve-uri': 3.1.2 - '@jridgewell/sourcemap-codec': 1.5.5 + '@braintree/sanitize-url': 6.0.4 + cytoscape: 3.33.3 + cytoscape-cose-bilkent: 4.1.0(cytoscape@3.33.3) + cytoscape-fcose: 2.2.0(cytoscape@3.33.3) + d3: 7.9.0 + khroma: 2.1.0 + non-layered-tidy-tree-layout: 2.0.2 + optional: true + + '@mermaid-js/parser@1.1.0': + dependencies: + langium: 4.2.3 '@nodelib/fs.scandir@2.1.5': dependencies: @@ -2257,8 +2074,6 @@ snapshots: dependencies: playwright: 1.57.0 - '@rolldown/pluginutils@1.0.0-beta.27': {} - '@rollup/rollup-android-arm-eabi@4.54.0': optional: true @@ -2369,26 +2184,122 @@ snapshots: '@tweenjs/tween.js@23.1.3': {} - '@types/babel__core@7.20.5': + '@types/d3-array@3.2.2': {} + + '@types/d3-axis@3.0.6': dependencies: - '@babel/parser': 7.28.5 - '@babel/types': 7.28.5 - '@types/babel__generator': 7.27.0 - '@types/babel__template': 7.4.4 - '@types/babel__traverse': 7.28.0 + '@types/d3-selection': 3.0.11 - '@types/babel__generator@7.27.0': + '@types/d3-brush@3.0.6': dependencies: - '@babel/types': 7.28.5 + '@types/d3-selection': 3.0.11 - '@types/babel__template@7.4.4': + '@types/d3-chord@3.0.6': {} + + '@types/d3-color@3.1.3': {} + + '@types/d3-contour@3.0.6': dependencies: - '@babel/parser': 7.28.5 - '@babel/types': 7.28.5 + '@types/d3-array': 3.2.2 + '@types/geojson': 7946.0.16 - '@types/babel__traverse@7.28.0': + '@types/d3-delaunay@6.0.4': {} + + '@types/d3-dispatch@3.0.7': {} + + '@types/d3-drag@3.0.7': dependencies: - '@babel/types': 7.28.5 + '@types/d3-selection': 3.0.11 + + '@types/d3-dsv@3.0.7': {} + + '@types/d3-ease@3.0.2': {} + + '@types/d3-fetch@3.0.7': + dependencies: + '@types/d3-dsv': 3.0.7 + + '@types/d3-force@3.0.10': {} + + '@types/d3-format@3.0.4': {} + + '@types/d3-geo@3.1.0': + dependencies: + '@types/geojson': 7946.0.16 + + '@types/d3-hierarchy@3.1.7': {} + + '@types/d3-interpolate@3.0.4': + dependencies: + '@types/d3-color': 3.1.3 + + '@types/d3-path@3.1.1': {} + + '@types/d3-polygon@3.0.2': {} + + '@types/d3-quadtree@3.0.6': {} + + '@types/d3-random@3.0.3': {} + + '@types/d3-scale-chromatic@3.1.0': {} + + '@types/d3-scale@4.0.9': + dependencies: + '@types/d3-time': 3.0.4 + + '@types/d3-selection@3.0.11': {} + + '@types/d3-shape@3.1.8': + dependencies: + '@types/d3-path': 3.1.1 + + '@types/d3-time-format@4.0.3': {} + + '@types/d3-time@3.0.4': {} + + '@types/d3-timer@3.0.2': {} + + '@types/d3-transition@3.0.9': + dependencies: + '@types/d3-selection': 3.0.11 + + '@types/d3-zoom@3.0.8': + dependencies: + '@types/d3-interpolate': 3.0.4 + '@types/d3-selection': 3.0.11 + + '@types/d3@7.4.3': + dependencies: + '@types/d3-array': 3.2.2 + '@types/d3-axis': 3.0.6 + '@types/d3-brush': 3.0.6 + '@types/d3-chord': 3.0.6 + '@types/d3-color': 3.1.3 + '@types/d3-contour': 3.0.6 + '@types/d3-delaunay': 6.0.4 + '@types/d3-dispatch': 3.0.7 + '@types/d3-drag': 3.0.7 + '@types/d3-dsv': 3.0.7 + '@types/d3-ease': 3.0.2 + '@types/d3-fetch': 3.0.7 + '@types/d3-force': 3.0.10 + '@types/d3-format': 3.0.4 + '@types/d3-geo': 3.1.0 + '@types/d3-hierarchy': 3.1.7 + '@types/d3-interpolate': 3.0.4 + '@types/d3-path': 3.1.1 + '@types/d3-polygon': 3.0.2 + '@types/d3-quadtree': 3.0.6 + '@types/d3-random': 3.0.3 + '@types/d3-scale': 4.0.9 + '@types/d3-scale-chromatic': 3.1.0 + '@types/d3-selection': 3.0.11 + '@types/d3-shape': 3.1.8 + '@types/d3-time': 3.0.4 + '@types/d3-time-format': 4.0.3 + '@types/d3-timer': 3.0.2 + '@types/d3-transition': 3.0.9 + '@types/d3-zoom': 3.0.8 '@types/debug@4.1.13': dependencies: @@ -2396,6 +2307,8 @@ snapshots: '@types/estree@1.0.8': {} + '@types/geojson@7946.0.16': {} + '@types/hast@3.0.4': dependencies: '@types/unist': 3.0.3 @@ -2422,16 +2335,14 @@ snapshots: undici-types: 7.16.0 optional: true - '@types/prop-types@15.7.15': {} - - '@types/react-dom@18.3.7(@types/react@18.3.28)': - dependencies: - '@types/react': 18.3.28 + '@types/prop-types@15.7.15': + optional: true '@types/react@18.3.28': dependencies: '@types/prop-types': 15.7.15 csstype: 3.2.3 + optional: true '@types/stats.js@0.17.4': {} @@ -2444,6 +2355,9 @@ snapshots: fflate: 0.8.2 meshoptimizer: 0.18.1 + '@types/trusted-types@2.0.7': + optional: true + '@types/unist@2.0.11': {} '@types/unist@3.0.3': {} @@ -2454,17 +2368,10 @@ snapshots: '@ungap/structured-clone@1.3.0': {} - '@vitejs/plugin-react@4.7.0(vite@6.4.1(@types/node@24.10.1))': - dependencies: - '@babel/core': 7.29.0 - '@babel/plugin-transform-react-jsx-self': 7.27.1(@babel/core@7.29.0) - '@babel/plugin-transform-react-jsx-source': 7.27.1(@babel/core@7.29.0) - '@rolldown/pluginutils': 1.0.0-beta.27 - '@types/babel__core': 7.20.5 - react-refresh: 0.17.0 - vite: 6.4.1(@types/node@24.10.1) - transitivePeerDependencies: - - supports-color + '@upsetjs/venn.js@2.0.0': + optionalDependencies: + d3-selection: 3.0.0 + d3-transition: 3.0.1(d3-selection@3.0.0) '@vitejs/plugin-vue@5.2.4(vite@5.4.21(@types/node@24.10.1))(vue@3.5.25(typescript@5.6.3))': dependencies: @@ -2612,6 +2519,8 @@ snapshots: '@webgpu/types@0.1.69': {} + acorn@8.16.0: {} + algoliasearch@5.46.2: dependencies: '@algolia/abtesting': 1.12.2 @@ -2637,42 +2546,14 @@ snapshots: assertion-error@2.0.1: {} - baseline-browser-mapping@2.9.19: {} - birpc@2.9.0: {} braces@3.0.3: dependencies: fill-range: 7.1.1 - browserslist@4.28.1: - dependencies: - baseline-browser-mapping: 2.9.19 - caniuse-lite: 1.0.30001769 - electron-to-chromium: 1.5.286 - node-releases: 2.0.27 - update-browserslist-db: 1.2.3(browserslist@4.28.1) - cac@6.7.14: {} - caniuse-lite@1.0.30001769: {} - - cbor-extract@2.2.0: - dependencies: - node-gyp-build-optional-packages: 5.1.1 - optionalDependencies: - '@cbor-extract/cbor-extract-darwin-arm64': 2.2.0 - '@cbor-extract/cbor-extract-darwin-x64': 2.2.0 - '@cbor-extract/cbor-extract-linux-arm': 2.2.0 - '@cbor-extract/cbor-extract-linux-arm64': 2.2.0 - '@cbor-extract/cbor-extract-linux-x64': 2.2.0 - '@cbor-extract/cbor-extract-win32-x64': 2.2.0 - optional: true - - cbor-x@1.6.0: - optionalDependencies: - cbor-extract: 2.2.0 - ccount@2.0.1: {} chai@5.3.3: @@ -2693,20 +2574,229 @@ snapshots: check-error@2.1.3: {} + chevrotain-allstar@0.4.3(chevrotain@12.0.0): + dependencies: + chevrotain: 12.0.0 + lodash-es: 4.18.1 + + chevrotain@12.0.0: + dependencies: + '@chevrotain/cst-dts-gen': 12.0.0 + '@chevrotain/gast': 12.0.0 + '@chevrotain/regexp-to-ast': 12.0.0 + '@chevrotain/types': 12.0.0 + '@chevrotain/utils': 12.0.0 + colortap@0.3.0: {} comma-separated-tokens@2.0.3: {} + commander@7.2.0: {} + commander@8.3.0: {} - convert-source-map@2.0.0: {} + confbox@0.1.8: {} copy-anything@4.0.5: dependencies: is-what: 5.5.0 + cose-base@1.0.3: + dependencies: + layout-base: 1.0.2 + + cose-base@2.2.0: + dependencies: + layout-base: 2.0.1 + csstype@3.2.3: {} + cytoscape-cose-bilkent@4.1.0(cytoscape@3.33.3): + dependencies: + cose-base: 1.0.3 + cytoscape: 3.33.3 + + cytoscape-fcose@2.2.0(cytoscape@3.33.3): + dependencies: + cose-base: 2.2.0 + cytoscape: 3.33.3 + + cytoscape@3.33.3: {} + + d3-array@2.12.1: + dependencies: + internmap: 1.0.1 + + d3-array@3.2.4: + dependencies: + internmap: 2.0.3 + + d3-axis@3.0.0: {} + + d3-brush@3.0.0: + dependencies: + d3-dispatch: 3.0.1 + d3-drag: 3.0.0 + d3-interpolate: 3.0.1 + d3-selection: 3.0.0 + d3-transition: 3.0.1(d3-selection@3.0.0) + + d3-chord@3.0.1: + dependencies: + d3-path: 3.1.0 + + d3-color@3.1.0: {} + + d3-contour@4.0.2: + dependencies: + d3-array: 3.2.4 + + d3-delaunay@6.0.4: + dependencies: + delaunator: 5.1.0 + + d3-dispatch@3.0.1: {} + + d3-drag@3.0.0: + dependencies: + d3-dispatch: 3.0.1 + d3-selection: 3.0.0 + + d3-dsv@3.0.1: + dependencies: + commander: 7.2.0 + iconv-lite: 0.6.3 + rw: 1.3.3 + + d3-ease@3.0.1: {} + + d3-fetch@3.0.1: + dependencies: + d3-dsv: 3.0.1 + + d3-force@3.0.0: + dependencies: + d3-dispatch: 3.0.1 + d3-quadtree: 3.0.1 + d3-timer: 3.0.1 + + d3-format@3.1.2: {} + + d3-geo@3.1.1: + dependencies: + d3-array: 3.2.4 + + d3-hierarchy@3.1.2: {} + + d3-interpolate@3.0.1: + dependencies: + d3-color: 3.1.0 + + d3-path@1.0.9: {} + + d3-path@3.1.0: {} + + d3-polygon@3.0.1: {} + + d3-quadtree@3.0.1: {} + + d3-random@3.0.1: {} + + d3-sankey@0.12.3: + dependencies: + d3-array: 2.12.1 + d3-shape: 1.3.7 + + d3-scale-chromatic@3.1.0: + dependencies: + d3-color: 3.1.0 + d3-interpolate: 3.0.1 + + d3-scale@4.0.2: + dependencies: + d3-array: 3.2.4 + d3-format: 3.1.2 + d3-interpolate: 3.0.1 + d3-time: 3.1.0 + d3-time-format: 4.1.0 + + d3-selection@3.0.0: {} + + d3-shape@1.3.7: + dependencies: + d3-path: 1.0.9 + + d3-shape@3.2.0: + dependencies: + d3-path: 3.1.0 + + d3-time-format@4.1.0: + dependencies: + d3-time: 3.1.0 + + d3-time@3.1.0: + dependencies: + d3-array: 3.2.4 + + d3-timer@3.0.1: {} + + d3-transition@3.0.1(d3-selection@3.0.0): + dependencies: + d3-color: 3.1.0 + d3-dispatch: 3.0.1 + d3-ease: 3.0.1 + d3-interpolate: 3.0.1 + d3-selection: 3.0.0 + d3-timer: 3.0.1 + + d3-zoom@3.0.0: + dependencies: + d3-dispatch: 3.0.1 + d3-drag: 3.0.0 + d3-interpolate: 3.0.1 + d3-selection: 3.0.0 + d3-transition: 3.0.1(d3-selection@3.0.0) + + d3@7.9.0: + dependencies: + d3-array: 3.2.4 + d3-axis: 3.0.0 + d3-brush: 3.0.0 + d3-chord: 3.0.1 + d3-color: 3.1.0 + d3-contour: 4.0.2 + d3-delaunay: 6.0.4 + d3-dispatch: 3.0.1 + d3-drag: 3.0.0 + d3-dsv: 3.0.1 + d3-ease: 3.0.1 + d3-fetch: 3.0.1 + d3-force: 3.0.0 + d3-format: 3.1.2 + d3-geo: 3.1.1 + d3-hierarchy: 3.1.2 + d3-interpolate: 3.0.1 + d3-path: 3.1.0 + d3-polygon: 3.0.1 + d3-quadtree: 3.0.1 + d3-random: 3.0.1 + d3-scale: 4.0.2 + d3-scale-chromatic: 3.1.0 + d3-selection: 3.0.0 + d3-shape: 3.2.0 + d3-time: 3.1.0 + d3-time-format: 4.1.0 + d3-timer: 3.0.1 + d3-transition: 3.0.1(d3-selection@3.0.0) + d3-zoom: 3.0.0 + + dagre-d3-es@7.0.14: + dependencies: + d3: 7.9.0 + lodash-es: 4.18.1 + + dayjs@1.11.20: {} + debug@4.4.3: dependencies: ms: 2.1.3 @@ -2717,16 +2807,19 @@ snapshots: deep-eql@5.0.2: {} - dequal@2.0.3: {} + delaunator@5.1.0: + dependencies: + robust-predicates: 3.0.3 - detect-libc@2.1.2: - optional: true + dequal@2.0.3: {} devlop@1.1.0: dependencies: dequal: 2.0.3 - electron-to-chromium@1.5.286: {} + dompurify@3.4.2: + optionalDependencies: + '@types/trusted-types': 2.0.7 emoji-regex-xs@1.0.0: {} @@ -2760,37 +2853,6 @@ snapshots: '@esbuild/win32-ia32': 0.21.5 '@esbuild/win32-x64': 0.21.5 - esbuild@0.25.12: - optionalDependencies: - '@esbuild/aix-ppc64': 0.25.12 - '@esbuild/android-arm': 0.25.12 - '@esbuild/android-arm64': 0.25.12 - '@esbuild/android-x64': 0.25.12 - '@esbuild/darwin-arm64': 0.25.12 - '@esbuild/darwin-x64': 0.25.12 - '@esbuild/freebsd-arm64': 0.25.12 - '@esbuild/freebsd-x64': 0.25.12 - '@esbuild/linux-arm': 0.25.12 - '@esbuild/linux-arm64': 0.25.12 - '@esbuild/linux-ia32': 0.25.12 - '@esbuild/linux-loong64': 0.25.12 - '@esbuild/linux-mips64el': 0.25.12 - '@esbuild/linux-ppc64': 0.25.12 - '@esbuild/linux-riscv64': 0.25.12 - '@esbuild/linux-s390x': 0.25.12 - '@esbuild/linux-x64': 0.25.12 - '@esbuild/netbsd-arm64': 0.25.12 - '@esbuild/netbsd-x64': 0.25.12 - '@esbuild/openbsd-arm64': 0.25.12 - '@esbuild/openbsd-x64': 0.25.12 - '@esbuild/openharmony-arm64': 0.25.12 - '@esbuild/sunos-x64': 0.25.12 - '@esbuild/win32-arm64': 0.25.12 - '@esbuild/win32-ia32': 0.25.12 - '@esbuild/win32-x64': 0.25.12 - - escalade@3.2.0: {} - estree-walker@2.0.2: {} estree-walker@3.0.3: @@ -2811,10 +2873,6 @@ snapshots: dependencies: reusify: 1.1.0 - fdir@6.5.0(picomatch@4.0.3): - optionalDependencies: - picomatch: 4.0.3 - fflate@0.8.2: {} fill-range@7.1.1: @@ -2831,8 +2889,6 @@ snapshots: fsevents@2.3.3: optional: true - gensync@1.0.0-beta.2: {} - get-east-asian-width@1.5.0: {} glob-parent@5.1.2: @@ -2850,6 +2906,8 @@ snapshots: graphql@16.11.0: {} + hachure-fill@0.5.2: {} + hast-util-to-html@9.0.5: dependencies: '@types/hast': 3.0.4 @@ -2872,8 +2930,16 @@ snapshots: html-void-elements@3.0.0: {} + iconv-lite@0.6.3: + dependencies: + safer-buffer: 2.1.2 + ignore@7.0.5: {} + internmap@1.0.1: {} + + internmap@2.0.3: {} + is-alphabetical@2.0.1: {} is-alphanumerical@2.0.1: @@ -2897,16 +2963,13 @@ snapshots: is-what@5.5.0: {} - js-tokens@4.0.0: {} + js-tokens@4.0.0: + optional: true js-yaml@4.1.1: dependencies: argparse: 2.0.1 - jsesc@3.1.0: {} - - json5@2.2.3: {} - jsonc-parser@3.3.1: {} jsonpointer@5.0.1: {} @@ -2915,20 +2978,34 @@ snapshots: dependencies: commander: 8.3.0 + khroma@2.1.0: {} + + langium@4.2.3: + dependencies: + '@chevrotain/regexp-to-ast': 12.0.0 + chevrotain: 12.0.0 + chevrotain-allstar: 0.4.3(chevrotain@12.0.0) + vscode-languageserver: 9.0.1 + vscode-languageserver-textdocument: 1.0.12 + vscode-uri: 3.1.0 + + layout-base@1.0.2: {} + + layout-base@2.0.1: {} + linkify-it@5.0.0: dependencies: uc.micro: 2.1.0 + lodash-es@4.18.1: {} + loose-envify@1.4.0: dependencies: js-tokens: 4.0.0 + optional: true loupe@3.2.1: {} - lru-cache@5.1.1: - dependencies: - yallist: 3.1.1 - magic-string@0.30.21: dependencies: '@jridgewell/sourcemap-codec': 1.5.5 @@ -2976,6 +3053,8 @@ snapshots: transitivePeerDependencies: - supports-color + marked@16.4.2: {} + mdast-util-to-hast@13.2.1: dependencies: '@types/hast': 3.0.4 @@ -2992,6 +3071,30 @@ snapshots: merge2@1.4.1: {} + mermaid@11.14.0: + dependencies: + '@braintree/sanitize-url': 7.1.2 + '@iconify/utils': 3.1.1 + '@mermaid-js/parser': 1.1.0 + '@types/d3': 7.4.3 + '@upsetjs/venn.js': 2.0.0 + cytoscape: 3.33.3 + cytoscape-cose-bilkent: 4.1.0(cytoscape@3.33.3) + cytoscape-fcose: 2.2.0(cytoscape@3.33.3) + d3: 7.9.0 + d3-sankey: 0.12.3 + dagre-d3-es: 7.0.14 + dayjs: 1.11.20 + dompurify: 3.4.2 + katex: 0.16.42 + khroma: 2.1.0 + lodash-es: 4.18.1 + marked: 16.4.2 + roughjs: 4.6.6 + stylis: 4.4.0 + ts-dedent: 2.2.0 + uuid: 11.1.1 + meshoptimizer@0.18.1: {} micromark-core-commonmark@2.0.3: @@ -3175,23 +3278,28 @@ snapshots: mitt@3.0.1: {} + mlly@1.8.2: + dependencies: + acorn: 8.16.0 + pathe: 2.0.3 + pkg-types: 1.3.1 + ufo: 1.6.4 + ms@2.1.3: {} nanoid@3.3.11: {} - node-gyp-build-optional-packages@5.1.1: - dependencies: - detect-libc: 2.1.2 + non-layered-tidy-tree-layout@2.0.2: optional: true - node-releases@2.0.27: {} - oniguruma-to-es@3.1.1: dependencies: emoji-regex-xs: 1.0.0 regex: 6.1.0 regex-recursion: 6.0.2 + package-manager-detector@1.6.0: {} + parse-entities@4.0.2: dependencies: '@types/unist': 2.0.11 @@ -3202,8 +3310,12 @@ snapshots: is-decimal: 2.0.1 is-hexadecimal: 2.0.1 + path-data-parser@0.1.0: {} + pathe@1.1.2: {} + pathe@2.0.3: {} + pathval@2.0.1: {} perfect-debounce@1.0.0: {} @@ -3212,7 +3324,11 @@ snapshots: picomatch@2.3.2: {} - picomatch@4.0.3: {} + pkg-types@1.3.1: + dependencies: + confbox: 0.1.8 + mlly: 1.8.2 + pathe: 2.0.3 playwright-core@1.57.0: {} @@ -3222,6 +3338,13 @@ snapshots: optionalDependencies: fsevents: 2.3.2 + points-on-curve@0.2.0: {} + + points-on-path@0.2.1: + dependencies: + path-data-parser: 0.1.0 + points-on-curve: 0.2.0 + postcss@8.5.6: dependencies: nanoid: 3.3.11 @@ -3243,12 +3366,12 @@ snapshots: loose-envify: 1.4.0 react: 18.3.1 scheduler: 0.23.2 - - react-refresh@0.17.0: {} + optional: true react@18.3.1: dependencies: loose-envify: 1.4.0 + optional: true regex-recursion@6.0.2: dependencies: @@ -3264,6 +3387,8 @@ snapshots: rfdc@1.4.1: {} + robust-predicates@3.0.3: {} + rollup@4.54.0: dependencies: '@types/estree': 1.0.8 @@ -3292,18 +3417,28 @@ snapshots: '@rollup/rollup-win32-x64-msvc': 4.54.0 fsevents: 2.3.3 + roughjs@4.6.6: + dependencies: + hachure-fill: 0.5.2 + path-data-parser: 0.1.0 + points-on-curve: 0.2.0 + points-on-path: 0.2.1 + run-parallel@1.2.0: dependencies: queue-microtask: 1.2.3 + rw@1.3.3: {} + + safer-buffer@2.1.2: {} + scheduler@0.23.2: dependencies: loose-envify: 1.4.0 + optional: true search-insights@2.17.3: {} - semver@6.3.1: {} - shiki@2.5.0: dependencies: '@shikijs/core': 2.5.0 @@ -3345,6 +3480,8 @@ snapshots: dependencies: ansi-regex: 6.2.2 + stylis@4.4.0: {} + superjson@2.2.6: dependencies: copy-anything: 4.0.5 @@ -3357,10 +3494,7 @@ snapshots: tinyexec@0.3.2: {} - tinyglobby@0.2.15: - dependencies: - fdir: 6.5.0(picomatch@4.0.3) - picomatch: 4.0.3 + tinyexec@1.1.2: {} tinypool@1.1.1: {} @@ -3374,10 +3508,14 @@ snapshots: trim-lines@3.0.1: {} + ts-dedent@2.2.0: {} + typescript@5.6.3: {} uc.micro@2.1.0: {} + ufo@1.6.4: {} + undici-types@7.16.0: optional: true @@ -3406,11 +3544,7 @@ snapshots: unist-util-is: 6.0.1 unist-util-visit-parents: 6.0.2 - update-browserslist-db@1.2.3(browserslist@4.28.1): - dependencies: - browserslist: 4.28.1 - escalade: 3.2.0 - picocolors: 1.1.1 + uuid@11.1.1: {} vfile-message@4.0.3: dependencies: @@ -3440,10 +3574,6 @@ snapshots: - supports-color - terser - vite-plugin-wasm@3.5.0(vite@6.4.1(@types/node@24.10.1)): - dependencies: - vite: 6.4.1(@types/node@24.10.1) - vite@5.4.21(@types/node@24.10.1): dependencies: esbuild: 0.21.5 @@ -3453,17 +3583,12 @@ snapshots: '@types/node': 24.10.1 fsevents: 2.3.3 - vite@6.4.1(@types/node@24.10.1): + vitepress-plugin-mermaid@2.0.17(mermaid@11.14.0)(vitepress@1.6.4(@algolia/client-search@5.46.2)(@types/node@24.10.1)(@types/react@18.3.28)(postcss@8.5.6)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(search-insights@2.17.3)(typescript@5.6.3)): dependencies: - esbuild: 0.25.12 - fdir: 6.5.0(picomatch@4.0.3) - picomatch: 4.0.3 - postcss: 8.5.6 - rollup: 4.54.0 - tinyglobby: 0.2.15 + mermaid: 11.14.0 + vitepress: 1.6.4(@algolia/client-search@5.46.2)(@types/node@24.10.1)(@types/react@18.3.28)(postcss@8.5.6)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(search-insights@2.17.3)(typescript@5.6.3) optionalDependencies: - '@types/node': 24.10.1 - fsevents: 2.3.3 + '@mermaid-js/mermaid-mindmap': 9.3.0 vitepress@1.6.4(@algolia/client-search@5.46.2)(@types/node@24.10.1)(@types/react@18.3.28)(postcss@8.5.6)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(search-insights@2.17.3)(typescript@5.6.3): dependencies: @@ -3549,6 +3674,23 @@ snapshots: - supports-color - terser + vscode-jsonrpc@8.2.0: {} + + vscode-languageserver-protocol@3.17.5: + dependencies: + vscode-jsonrpc: 8.2.0 + vscode-languageserver-types: 3.17.5 + + vscode-languageserver-textdocument@1.0.12: {} + + vscode-languageserver-types@3.17.5: {} + + vscode-languageserver@9.0.1: + dependencies: + vscode-languageserver-protocol: 3.17.5 + + vscode-uri@3.1.0: {} + vue@3.5.25(typescript@5.6.3): dependencies: '@vue/compiler-dom': 3.5.25 @@ -3564,13 +3706,6 @@ snapshots: siginfo: 2.0.0 stackback: 0.0.2 - yallist@3.1.1: {} - zod@4.3.6: {} - zustand@5.0.11(@types/react@18.3.28)(react@18.3.1): - optionalDependencies: - '@types/react': 18.3.28 - react: 18.3.1 - zwitch@2.0.4: {} From 08795222483a4cd959770176e6bbb720cddce2f7 Mon Sep 17 00:00:00 2001 From: James Ross Date: Mon, 4 May 2026 03:19:14 -0700 Subject: [PATCH 15/21] docs: define authenticated Wesley intent admission posture --- .../application-contract-hosting.md | 43 +++ .../design.md | 320 ++++++++++++++++++ ...ticated-wesley-intent-admission-posture.md | 70 ++++ 3 files changed, 433 insertions(+) create mode 100644 docs/design/0017-authenticated-wesley-intent-admission-posture/design.md create mode 100644 docs/method/backlog/up-next/PLATFORM_authenticated-wesley-intent-admission-posture.md diff --git a/docs/architecture/application-contract-hosting.md b/docs/architecture/application-contract-hosting.md index da7533ff..f120caa5 100644 --- a/docs/architecture/application-contract-hosting.md +++ b/docs/architecture/application-contract-hosting.md @@ -49,6 +49,7 @@ The design evidence for this boundary lives in these repo-local packets: - `docs/design/0014-eint-registry-observation-boundary-inventory/design.md` - `docs/design/0015-registry-provider-host-boundary-decision/design.md` - `docs/design/0016-wesley-to-echo-toy-contract-proof/design.md` +- `docs/design/0017-authenticated-wesley-intent-admission-posture/design.md` ## Ownership Split @@ -299,6 +300,48 @@ reserved control-op usage. Host-side generated-payload validation is deferred until a RED proves that Echo itself must reject malformed app payloads at the host boundary. +## Admission Security Ramp + +The registry handshake is compatibility evidence, not production security. + +Current EINT dispatch proves that Echo can accept canonical contract-shaped +bytes. It does not prove that the submitted intent came from an authenticated +session, that the generated artifact has the required trust posture, or that the +intent is authorized for a target coordinate. + +A production Wesley intent needs a stronger pre-tick admission boundary: + +```mermaid +sequenceDiagram + participant Gen as Wesley-generated client + participant Host as Echo host boundary + participant Policy as Observer/ingress policy + participant Echo as Echo runtime + + Gen->>Gen: canonicalize op vars + Gen->>Gen: bind op, vars, artifact, target, session + Gen->>Host: authenticated intent submission + Host->>Policy: verify artifact posture and session authority + Policy-->>Host: admission certificate or obstruction + Host->>Echo: certified canonical ingress only +``` + +The trust ramp should stay explicit: + +```text +local dev -> digest verified -> generated tests verified -> CI attested + -> BLADE certified production profile +``` + +Holmes, WATSON, Moriarty, generated tests, and BLADE are certification providers +for later production profiles. Echo should model the posture slots and policy +requirements first; it should not treat local development trust as equivalent +to production certification. + +Echo must not trust caller-supplied footprint claims. Footprints used for tick +admission must come from a verified Wesley artifact or another explicitly +trusted footprint authority. + ## Determinism Boundary Applications may observe nondeterministic host events. Echo must not let hidden diff --git a/docs/design/0017-authenticated-wesley-intent-admission-posture/design.md b/docs/design/0017-authenticated-wesley-intent-admission-posture/design.md new file mode 100644 index 00000000..ea114561 --- /dev/null +++ b/docs/design/0017-authenticated-wesley-intent-admission-posture/design.md @@ -0,0 +1,320 @@ + + + +# 0017 - Authenticated Wesley Intent Admission Posture + +_Name the missing security and artifact-trust boundary between +Wesley-generated contract helpers and Echo tick admission._ + +Legend: [PLATFORM](../../method/legends/PLATFORM.md) + +Depends on: + +- [0013 - Wesley Compiled Contract Hosting Doctrine](../0013-wesley-compiled-contract-hosting-doctrine/design.md) +- [0014 - EINT, Registry, And Observation Boundary Inventory](../0014-eint-registry-observation-boundary-inventory/design.md) +- [0015 - Registry Provider Host Boundary Decision](../0015-registry-provider-host-boundary-decision/design.md) +- [0016 - Wesley To Echo Toy Contract Proof](../0016-wesley-to-echo-toy-contract-proof/design.md) +- [Authenticated Wesley Intent Admission Posture](../../method/backlog/up-next/PLATFORM_authenticated-wesley-intent-admission-posture.md) + +## Status + +Proposed. + +## Hill + +A Wesley-compiled intent must not become tick-admissible merely because it is +well-formed EINT bytes. + +Before a submitted intent can enter a tick candidate set, Echo must be able to +prove three things: + +1. The submitted canonical intent bytes have the claimed cryptographic + identity. +2. The intent targets an operation from a registered Wesley contract artifact + whose trust posture satisfies local policy. +3. The authenticated session or capability is authorized to submit that + operation at the target coordinate under the active observer or ingress + policy. + +## Current Repo Truth + +Current EINT v1 is intentionally app-blind: + +```text +"EINT" || op_id:u32le || vars_len:u32le || vars +``` + +Current dispatch takes canonical bytes: + +```text +dispatch_intent(intent_bytes) +``` + +The installed `WarpKernel` parses EINT, computes a content-addressed +`intent_id`, wraps the bytes as `IngressEnvelope::local_intent`, and ingests +the envelope into the default writer inbox. + +That path is correct for the toy bridge but incomplete for production contract +hosting. It does not currently bind the submitted bytes to: + +- a certified Wesley artifact; +- a generated footprint authority; +- a session or subject; +- a capability or observer policy; +- a target-coordinate authorization claim; +- a replay window; +- a signed or MACed admission transcript; +- an encrypted request or response channel. + +The current default writer uses `InboxPolicy::AcceptAll`. Existing +`InboxPolicy` kinds are deterministic ingress filters and budgets. They are not +authentication, artifact certification, or transport security. + +## Doctrine + +Wesley exists to move footprint honesty out of runtime trust. + +Echo must not accept caller-supplied footprint claims for tick scheduling or +independence decisions. A client may submit canonical operation variables, but +the footprint authority must come from a registered, verified contract artifact +or another explicitly trusted footprint authority. + +The hard rule: + +```text +No verified artifact authority, no tick-admissible Wesley intent. +No authenticated session or capability, no tick-admissible Wesley intent. +No caller-supplied footprint trust. +``` + +## Artifact Versus Intent + +An intent instance should not register itself. + +A Wesley-compiled contract artifact registers operation identity, codec +identity, registry identity, and footprint authority. A submitted intent points +at that registered artifact and supplies canonical operation variables. + +The trust split is: + +```text +artifact trust: + Is this contract artifact the accepted output of the Wesley certification + pipeline? + +intent trust: + Did an authorized subject or session submit exactly these canonical bytes for + exactly this target under exactly this policy? +``` + +Both are required before tick admission. + +## Trust Ramp + +Echo should model artifact trust posture without pretending that every +production certification provider is implemented in this slice. + +Initial posture vocabulary should leave room for this ramp: + +```text +local_dev +local_digest_verified +generated_tests_verified +ci_attested +blade_certified +``` + +Exact names may change. The important rule is that each posture must be +explicit, and policy must be able to reject artifacts whose posture is too weak +for the requested observer or intent. + +Holmes, WATSON, Moriarty, generated tests, and BLADE are production-ramp +certification providers. They belong in the certification chain, not in the +normal deterministic tick execution path. + +For this slice, Echo should define the slots and policy vocabulary. It should +not implement those external certification systems. + +## Candidate Identity Chain + +The model needs separate identities for contract artifacts, intent bytes, and +admission. + +Candidate identities: + +```text +contract_artifact_id = + H("echo.contract-artifact.v1" || + schema_digest || + ir_digest || + registry_digest || + codec_id || + compiler_profile_digest || + artifact_trust_posture) + +intent_digest = + H("echo.intent.v2" || + contract_artifact_id || + op_id || + canonical_vars_digest) + +admission_id = + H("echo.intent-admission.v1" || + intent_digest || + target_coordinate || + session_id || + policy_id || + replay_counter_or_challenge_digest) +``` + +Those formulas are design sketches, not committed wire formats. The committed +requirement is domain separation and explicit scope: a digest must say what it +commits to. + +## Pre-Tick Admission Pipeline + +The secure production path should be: + +```text +Wesley-generated client + -> canonicalize operation variables + -> build inner EINT payload + -> compute intent digest + -> bind intent digest to contract artifact id + -> bind target coordinate and policy/session transcript + -> sign, MAC, or seal the submission + -> send authenticated intent submission + +Echo host boundary + -> verify artifact registration and trust posture + -> verify op id exists in the registered artifact + -> verify vars decode canonically under the registered codec + -> verify intent digest + -> verify session, capability, auth method, and policy + -> verify replay protection + -> resolve footprint through the trusted artifact authority + -> close footprint under policy + -> emit admission certificate or obstruction + +Echo runtime + -> admit only certified ingress into tick candidate selection + -> retain admission witness reference in tick receipt +``` + +Authentication, randomness, nonces, challenge material, and transport keys live +outside deterministic execution. If they affect admission, their digests or +verification results become explicit admission evidence. + +## Observer Policy Relationship + +Observer policies should eventually govern both reads and writes. + +An observer or ingress policy may require: + +- a minimum artifact trust posture; +- a specific certification profile; +- a session authentication method; +- step-up authentication for privileged operations; +- allowed operation ids; +- allowed target worldlines, strands, inboxes, or coordinates; +- allowed observation frames and projections; +- request and response protection; +- replay bounds; +- retention and audit behavior. + +This design does not require every policy field now. It names the direction so +future API choices do not bake in an unauthenticated toy boundary. + +## Request And Response Protection + +Encryption should protect the host/client request-response channel, not become +hidden runtime state. + +The future protected submission shape should wrap canonical payloads: + +```text +protected request: + authenticated/session-bound envelope over EINT or ObservationRequest bytes + +protected response: + authenticated/session-bound envelope over DispatchResponse or + ObservationArtifact bytes +``` + +The deterministic kernel should still receive canonical plaintext DTOs after +host-boundary verification. The host-boundary transcript, not hidden ambient +state, records the security facts that justified admission. + +## Failure Outcomes + +Security and artifact failures should lower to typed admission outcomes before +tick candidate selection. Candidate categories: + +- malformed payload; +- unknown artifact; +- artifact trust posture too weak; +- artifact digest mismatch; +- unknown operation id; +- canonical vars decode failure; +- policy denied; +- authentication required; +- authentication failed; +- replay detected; +- expired session; +- bad signature or MAC; +- footprint authority unavailable; +- footprint binding obstruction; +- policy closure over budget. + +Which of these become public error codes, retained obstruction artifacts, or +private audit records is a later API decision. The design rule is that failed +security checks must not silently become ordinary tick candidates. + +## RED Boundary + +Current Echo cannot yet prove this requirement. + +Focused REDs for the implementation slice should show: + +- a well-formed EINT can currently be dispatched without a contract artifact + id; +- a well-formed EINT can currently be dispatched without session or capability + proof; +- a well-formed EINT can currently be dispatched without artifact trust + posture; +- current dispatch has no replay counter, challenge, or signed transcript; +- current tick or ingress evidence cannot distinguish "well-formed bytes" from + "authenticated, artifact-verified, policy-admitted intent"; +- current `ReadingRightsPosture` cannot express policy-authorized observer + session posture beyond `KernelPublic`. + +## Non-Goals + +- Do not implement WebAuthn, passkeys, TOTP, or transport encryption in this + slice. +- Do not implement Holmes, WATSON, Moriarty, or BLADE. +- Do not require production certification for local development. +- Do not replace EINT v1 before a RED proves the exact missing wire field. +- Do not add application-specific nouns to Echo core. +- Do not import app domain Rust types into Echo core. +- Do not trust caller-supplied runtime footprint claims. +- Do not make deterministic runtime execution read wall clock, randomness, + environment, filesystem, or host session maps. + +## Acceptance Impact + +The next implementation cycle should start RED-only. + +It should add focused tests or design-level fixtures proving the absent +admission posture before changing production dispatch. The first GREEN should +be the smallest explicit posture model that can represent: + +- registered artifact identity; +- artifact trust posture; +- authenticated intent submission identity; +- policy/session admission result; +- no caller-supplied footprint trust. + +Full production cryptography remains a later ramp. The current slice is about +preventing the API from confusing "well-formed EINT" with "tick-admissible +certified intent." diff --git a/docs/method/backlog/up-next/PLATFORM_authenticated-wesley-intent-admission-posture.md b/docs/method/backlog/up-next/PLATFORM_authenticated-wesley-intent-admission-posture.md new file mode 100644 index 00000000..906351d3 --- /dev/null +++ b/docs/method/backlog/up-next/PLATFORM_authenticated-wesley-intent-admission-posture.md @@ -0,0 +1,70 @@ + + + +# Authenticated Wesley Intent Admission Posture + +Status: proposed security hardening. + +Depends on: + +- [Wesley to Echo toy contract proof](./PLATFORM_wesley-to-echo-toy-contract-proof.md) +- [Contract-aware receipts and readings](./KERNEL_contract-aware-receipts-and-readings.md) +- [0017 - Authenticated Wesley Intent Admission Posture](../../../design/0017-authenticated-wesley-intent-admission-posture/design.md) + +## Why now + +The toy contract proof showed that Wesley-generated helpers can produce +canonical EINT bytes and observation requests. That is a useful bridge, but it +is not a production admission boundary. + +A Wesley intent should not become tick-admissible merely because its EINT bytes +parse. It must be tied to a verified contract artifact, a trustworthy footprint +authority, and an authenticated session or capability accepted by local policy. + +## What it should look like + +Start RED-only. + +Prove the current gap before implementation: + +- `dispatch_intent(...)` admits well-formed EINT without a contract artifact id. +- `dispatch_intent(...)` admits well-formed EINT without session or capability + proof. +- Current ingress evidence cannot name artifact trust posture. +- Current ingress evidence cannot name authenticated admission posture. +- Current ingress evidence cannot bind replay protection. +- Current reading rights posture cannot express policy-authorized observer + sessions beyond `KernelPublic`. + +Then introduce the smallest posture model that can represent: + +- registered Wesley contract artifact identity; +- artifact trust posture; +- authenticated intent submission identity; +- policy/session admission result; +- no caller-supplied footprint trust. + +## Acceptance criteria + +- A design or RED test names the current unauthenticated EINT admission gap. +- The chosen model separates artifact trust from intent/session trust. +- Artifact trust posture can represent local-dev, generated-test, CI, and later + BLADE-certified ramps without treating them as equivalent. +- Intent admission identity binds op id, canonical vars bytes, target + coordinate, artifact id, session or policy id, and replay evidence. +- The docs state that caller-supplied footprint claims are not trusted for tick + scheduling or independence decisions. +- The docs state that Holmes, WATSON, Moriarty, and BLADE are later + certification providers, not dependencies of this first slice. +- No production crypto is implemented before the posture and RED boundary are + reviewed. + +## Non-goals + +- Do not implement WebAuthn, passkeys, TOTP, or transport encryption yet. +- Do not implement Holmes, WATSON, Moriarty, or BLADE. +- Do not add app-specific nouns to Echo core. +- Do not import application Rust types into Echo core. +- Do not replace EINT v1 without a specific RED. +- Do not make `dispatch_intent(...)` read ambient host auth state. +- Do not allow runtime-submitted footprint JSON to become a footprint authority. From 1baa426efb05c9f6be308cc2c82438fc94493a84 Mon Sep 17 00:00:00 2001 From: James Ross Date: Mon, 4 May 2026 07:46:33 -0700 Subject: [PATCH 16/21] fix: namespace Wesley generated helper types --- crates/echo-wesley-gen/src/main.rs | 197 +++++++++++++++------ crates/echo-wesley-gen/tests/generation.rs | 121 +++++++++++-- 2 files changed, 258 insertions(+), 60 deletions(-) diff --git a/crates/echo-wesley-gen/src/main.rs b/crates/echo-wesley-gen/src/main.rs index 09508eaf..bb4be975 100644 --- a/crates/echo-wesley-gen/src/main.rs +++ b/crates/echo-wesley-gen/src/main.rs @@ -157,30 +157,6 @@ fn generate_rust(ir: &WesleyIR, args: &Args) -> Result { use echo_registry_api::{ArgDef, EnumDef, ObjectDef, OpDef, OpKind, RegistryInfo, RegistryProvider}; }); - if ir.ops.iter().any(|op| op.kind == OpKind::Query) { - tokens.extend(quote! { - use echo_wasm_abi::kernel_port::{ - ObservationAt, ObservationCoordinate, ObservationFrame, ObservationProjection, - ObservationRequest, WorldlineId, - }; - }); - } - - if ir.ops.iter().any(|op| op.kind == OpKind::Mutation) { - tokens.extend(quote! { - use echo_wasm_abi::pack_intent_v1; - - /// Error produced while building a generated EINT intent. - #[derive(Debug)] - pub enum GeneratedIntentError { - /// Operation vars could not be encoded canonically. - EncodeVars(echo_wasm_abi::CanonError), - /// Encoded vars could not be packed into an EINT envelope. - PackEnvelope(echo_wasm_abi::EnvelopeError), - } - }); - } - let mut enum_defs: Vec<_> = ir .types .iter() @@ -268,13 +244,48 @@ fn generate_rust(ir: &WesleyIR, args: &Args) -> Result { }); } + let mut helper_prelude = TokenStream::new(); + let mut helper_tokens = TokenStream::new(); + let mut helper_exports = Vec::new(); + + if args.no_std { + helper_prelude.extend(quote! { + use alloc::string::String; + use alloc::vec::Vec; + }); + } + + if ir.ops.iter().any(|op| op.kind == OpKind::Query) { + helper_prelude.extend(quote! { + use echo_wasm_abi::kernel_port::{ + ObservationAt, ObservationCoordinate, ObservationFrame, ObservationProjection, + ObservationRequest, WorldlineId, + }; + }); + } + + if ir.ops.iter().any(|op| op.kind == OpKind::Mutation) { + helper_prelude.extend(quote! { + use echo_wasm_abi::pack_intent_v1; + + /// Error produced while building a generated EINT intent. + #[derive(Debug)] + pub enum GeneratedIntentError { + /// Operation vars could not be encoded canonically. + EncodeVars(echo_wasm_abi::CanonError), + /// Encoded vars could not be packed into an EINT envelope. + PackEnvelope(echo_wasm_abi::EnvelopeError), + } + }); + } + for op in &ops_sorted { let const_name = op_const_ident(&op.name, op.op_id); let helper_name = format_ident!("{}", to_snake_case(&op.name)); let vars_name = format_ident!("{}Vars", to_pascal_case(&op.name)); let vars_fields = op.args.iter().map(|a| { let field_name = safe_ident(&a.name); - let base_ty = map_type(&a.type_name, args); + let base_ty = map_helper_type(&a.type_name, args); let list_ty: TokenStream = if a.list { quote! { Vec<#base_ty> } } else { @@ -288,9 +299,10 @@ fn generate_rust(ir: &WesleyIR, args: &Args) -> Result { } }); let encode_fn_name = format_ident!("encode_{}_vars", helper_name); - tokens.extend(quote! { + helper_exports.push(encode_fn_name.clone()); + helper_tokens.extend(quote! { /// Canonical vars payload for this generated operation. - #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] + #[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)] pub struct #vars_name { #(#vars_fields),* } @@ -304,23 +316,27 @@ fn generate_rust(ir: &WesleyIR, args: &Args) -> Result { OpKind::Mutation => { let fn_name = format_ident!("pack_{}_intent", helper_name); let raw_fn_name = format_ident!("pack_{}_intent_raw_vars", helper_name); - tokens.extend(quote! { + helper_exports.push(fn_name.clone()); + helper_exports.push(raw_fn_name.clone()); + helper_tokens.extend(quote! { /// Encode this mutation's vars and pack them into an EINT v1 intent. pub fn #fn_name(vars: &#vars_name) -> Result, GeneratedIntentError> { let vars_bytes = #encode_fn_name(vars).map_err(GeneratedIntentError::EncodeVars)?; - pack_intent_v1(#const_name, &vars_bytes).map_err(GeneratedIntentError::PackEnvelope) + pack_intent_v1(super::#const_name, &vars_bytes).map_err(GeneratedIntentError::PackEnvelope) } /// Pack already-canonical vars bytes for this generated mutation into EINT v1. pub fn #raw_fn_name(vars: &[u8]) -> Result, echo_wasm_abi::EnvelopeError> { - pack_intent_v1(#const_name, vars) + pack_intent_v1(super::#const_name, vars) } }); } OpKind::Query => { let fn_name = format_ident!("{}_observation_request", helper_name); let raw_fn_name = format_ident!("{}_observation_request_raw_vars", helper_name); - tokens.extend(quote! { + helper_exports.push(fn_name.clone()); + helper_exports.push(raw_fn_name.clone()); + helper_tokens.extend(quote! { /// Encode this query's vars and build a frontier query-view observation request. pub fn #fn_name(worldline_id: WorldlineId, vars: &#vars_name) -> Result { let vars_bytes = #encode_fn_name(vars)?; @@ -336,7 +352,7 @@ fn generate_rust(ir: &WesleyIR, args: &Args) -> Result { }, frame: ObservationFrame::QueryView, projection: ObservationProjection::Query { - query_id: #const_name, + query_id: super::#const_name, vars_bytes: Vec::from(vars), }, } @@ -346,6 +362,22 @@ fn generate_rust(ir: &WesleyIR, args: &Args) -> Result { } } + tokens.extend(quote! { + /// Generated operation helper namespace. + /// + /// Helper-only types live here so user-controlled Wesley types can + /// use names such as `IncrementVars` or `GeneratedIntentError` + /// without colliding with generated plumbing. + pub mod __echo_wesley_generated { + #helper_prelude + #helper_tokens + } + + pub use __echo_wesley_generated::{ + #(#helper_exports),* + }; + }); + // OPS table (sorted by op_id). let ops_entries = ops_sorted.iter().map(|op| { let kind = match op.kind { @@ -433,6 +465,11 @@ fn op_const_name(name: &str, op_id: u32) -> String { format!("OP_{out}") } +/// Convert a Wesley operation name to a Rust PascalCase stem. +/// +/// Existing alphanumeric casing is preserved between separators so acronym-heavy +/// names such as `XMLParser` remain `XMLParser` instead of being normalized to +/// title case. fn to_pascal_case(name: &str) -> String { let mut out = String::new(); let mut capitalize_next = true; @@ -494,16 +531,21 @@ fn validate_version(ir: &WesleyIR) -> Result<()> { } fn validate_generated_item_names(ir: &WesleyIR) -> Result<()> { - let mut items = BTreeMap::new(); + let mut top_level_items = BTreeMap::new(); + let mut helper_items = BTreeMap::new(); record_generated_item( - &mut items, + &mut top_level_items, "SCHEMA_SHA256", "generated schema hash constant", )?; - record_generated_item(&mut items, "CODEC_ID", "generated codec id constant")?; record_generated_item( - &mut items, + &mut top_level_items, + "CODEC_ID", + "generated codec id constant", + )?; + record_generated_item( + &mut top_level_items, "REGISTRY_VERSION", "generated registry version constant", )?; @@ -512,25 +554,25 @@ fn validate_generated_item_names(ir: &WesleyIR) -> Result<()> { match type_def.kind { TypeKind::Enum => { record_generated_item( - &mut items, + &mut top_level_items, type_def.name.as_str(), format!("enum type `{}`", type_def.name), )?; record_generated_item( - &mut items, + &mut top_level_items, format!("ENUM_{}_VALUES", type_def.name.to_ascii_uppercase()), format!("enum `{}` values constant", type_def.name), )?; } TypeKind::Object | TypeKind::InputObject => { record_generated_item( - &mut items, + &mut top_level_items, type_def.name.as_str(), format!("object type `{}`", type_def.name), )?; if type_def.kind == TypeKind::Object { record_generated_item( - &mut items, + &mut top_level_items, format!("OBJ_{}_FIELDS", type_def.name.to_ascii_uppercase()), format!("object `{}` fields constant", type_def.name), )?; @@ -550,13 +592,19 @@ fn validate_generated_item_names(ir: &WesleyIR) -> Result<()> { ("GeneratedRegistry", "generated registry provider type"), ("REGISTRY", "generated registry provider value"), ] { - record_generated_item(&mut items, name, source)?; + record_generated_item(&mut top_level_items, name, source)?; } + + record_generated_item( + &mut top_level_items, + "__echo_wesley_generated", + "generated operation helper namespace", + )?; } if ir.ops.iter().any(|op| op.kind == OpKind::Mutation) { record_generated_item( - &mut items, + &mut helper_items, "GeneratedIntentError", "generated intent helper error", )?; @@ -568,50 +616,78 @@ fn validate_generated_item_names(ir: &WesleyIR) -> Result<()> { let helper_name = to_snake_case(&op.name); record_generated_item( - &mut items, + &mut top_level_items, const_name.as_str(), format!("{kind} operation `{}` id constant", op.name), )?; record_generated_item( - &mut items, + &mut top_level_items, format!("{const_name}_ARGS"), format!("{kind} operation `{}` args constant", op.name), )?; record_generated_item( - &mut items, + &mut helper_items, format!("{}Vars", to_pascal_case(&op.name)), format!("{kind} operation `{}` vars type", op.name), )?; record_generated_item( - &mut items, + &mut helper_items, format!("encode_{helper_name}_vars"), format!("{kind} operation `{}` vars encoder", op.name), )?; + record_generated_item( + &mut top_level_items, + format!("encode_{helper_name}_vars"), + format!("{kind} operation `{}` vars encoder re-export", op.name), + )?; match op.kind { OpKind::Mutation => { record_generated_item( - &mut items, + &mut helper_items, format!("pack_{helper_name}_intent"), format!("mutation operation `{}` EINT helper", op.name), )?; record_generated_item( - &mut items, + &mut helper_items, format!("pack_{helper_name}_intent_raw_vars"), format!("mutation operation `{}` raw EINT helper", op.name), )?; + record_generated_item( + &mut top_level_items, + format!("pack_{helper_name}_intent"), + format!("mutation operation `{}` EINT helper re-export", op.name), + )?; + record_generated_item( + &mut top_level_items, + format!("pack_{helper_name}_intent_raw_vars"), + format!("mutation operation `{}` raw EINT helper re-export", op.name), + )?; } OpKind::Query => { record_generated_item( - &mut items, + &mut helper_items, format!("{helper_name}_observation_request"), format!("query operation `{}` observation helper", op.name), )?; record_generated_item( - &mut items, + &mut helper_items, format!("{helper_name}_observation_request_raw_vars"), format!("query operation `{}` raw observation helper", op.name), )?; + record_generated_item( + &mut top_level_items, + format!("{helper_name}_observation_request"), + format!("query operation `{}` observation helper re-export", op.name), + )?; + record_generated_item( + &mut top_level_items, + format!("{helper_name}_observation_request_raw_vars"), + format!( + "query operation `{}` raw observation helper re-export", + op.name + ), + )?; } } } @@ -665,3 +741,24 @@ fn map_type(gql_type: &str, args: &Args) -> TokenStream { } } } + +/// Map a GraphQL base type name for use inside the generated helper module. +fn map_helper_type(gql_type: &str, args: &Args) -> TokenStream { + match gql_type { + "Boolean" => quote! { bool }, + "String" => quote! { String }, + "Int" => quote! { i32 }, + "Float" => quote! { f32 }, + "ID" => { + if args.no_std { + quote! { [u8; 32] } + } else { + quote! { String } + } + } + other => { + let ident = safe_ident(other); + quote! { super::#ident } + } + } +} diff --git a/crates/echo-wesley-gen/tests/generation.rs b/crates/echo-wesley-gen/tests/generation.rs index d313ac5c..b266bfc2 100644 --- a/crates/echo-wesley-gen/tests/generation.rs +++ b/crates/echo-wesley-gen/tests/generation.rs @@ -81,10 +81,10 @@ mod generated; #[cfg(test)] mod tests { use super::generated::{ + __echo_wesley_generated::{CounterValueVars, IncrementVars}, counter_value_observation_request, counter_value_observation_request_raw_vars, - encode_counter_value_vars, pack_increment_intent, CounterValueVars, IncrementInput, - IncrementVars, CODEC_ID, OP_COUNTER_VALUE, OP_INCREMENT, REGISTRY, REGISTRY_VERSION, - SCHEMA_SHA256, + encode_counter_value_vars, pack_increment_intent, IncrementInput, CODEC_ID, + OP_COUNTER_VALUE, OP_INCREMENT, REGISTRY, REGISTRY_VERSION, SCHEMA_SHA256, }; use echo_registry_api::{OpKind, RegistryProvider}; use echo_wasm_abi::kernel_port::{ @@ -264,6 +264,63 @@ mod tests { crate_dir } +fn write_basic_generated_crate(generated: &str, label: &str) -> PathBuf { + let workspace = workspace_root(); + let crate_dir = workspace + .join("target") + .join("echo-wesley-gen-basic-smoke") + .join(std::process::id().to_string()) + .join(label); + if crate_dir.exists() { + fs::remove_dir_all(&crate_dir).expect("failed to remove old generated crate"); + } + fs::create_dir_all(crate_dir.join("src")).expect("failed to create generated crate"); + + let registry_path = workspace.join("crates/echo-registry-api"); + let wasm_abi_path = workspace.join("crates/echo-wasm-abi"); + fs::write( + crate_dir.join("Cargo.toml"), + format!( + r#"[package] +name = "echo-wesley-gen-basic-smoke-{label}" +version = "0.0.0" +edition = "2021" +publish = false + +[workspace] + +[dependencies] +echo-registry-api = {{ path = "{}" }} +echo-wasm-abi = {{ path = "{}" }} +serde = {{ version = "1.0", features = ["derive"] }} +"#, + registry_path.display(), + wasm_abi_path.display() + ), + ) + .expect("failed to write generated Cargo.toml"); + fs::write(crate_dir.join("src/generated.rs"), generated) + .expect("failed to write generated module"); + fs::write(crate_dir.join("src/lib.rs"), "mod generated;\n") + .expect("failed to write generated lib.rs"); + crate_dir +} + +fn assert_generated_crate_checks(crate_dir: &Path) { + let output = Command::new("cargo") + .args(["check", "--manifest-path"]) + .arg(crate_dir.join("Cargo.toml")) + .output() + .expect("failed to run generated crate check"); + + assert!( + output.status.success(), + "generated crate check failed\nstdout:\n{}\nstderr:\n{}", + String::from_utf8_lossy(&output.stdout), + String::from_utf8_lossy(&output.stderr) + ); +} + #[test] fn test_generate_from_json() { let ir = r#"{ @@ -370,13 +427,14 @@ fn test_toy_contract_generates_eint_and_observation_helpers() { for required in [ "use echo_wasm_abi::pack_intent_v1;", + "pub mod __echo_wesley_generated", "pub struct IncrementVars", "pub struct CounterValueVars", "pub fn encode_increment_vars", "pub fn encode_counter_value_vars", "pub fn pack_increment_intent", "pub fn pack_increment_intent_raw_vars", - "pack_intent_v1(OP_INCREMENT", + "pack_intent_v1(super::OP_INCREMENT", "pub fn counter_value_observation_request", "pub fn counter_value_observation_request_raw_vars", ] { @@ -416,7 +474,7 @@ fn test_query_only_contract_does_not_import_intent_packer() { } #[test] -fn test_operation_vars_type_collision_fails_with_clear_diagnostic() { +fn test_operation_vars_type_collision_uses_helper_namespace() { let ir = r#"{ "ir_version": "echo-ir/v1", "schema_sha256": "abc123", @@ -438,12 +496,55 @@ fn test_operation_vars_type_collision_fails_with_clear_diagnostic() { let output = run_wesley_gen(ir); assert!( - !output.status.success(), - "generator should reject duplicate generated item names" + output.status.success(), + "CLI failed: {}", + String::from_utf8_lossy(&output.stderr) ); - let stderr = String::from_utf8_lossy(&output.stderr); - assert!(stderr.contains("generated Rust item name collision")); - assert!(stderr.contains("IncrementVars")); + let stdout = String::from_utf8_lossy(&output.stdout); + assert!(stdout.contains("pub struct IncrementVars")); + assert!(stdout.contains("pub mod __echo_wesley_generated")); + assert!(stdout.contains("pub use __echo_wesley_generated::")); + assert_generated_crate_checks(&write_basic_generated_crate( + stdout.as_ref(), + "vars-collision", + )); +} + +#[test] +fn test_generated_intent_error_user_type_does_not_collide_with_helper_error() { + let ir = r#"{ + "ir_version": "echo-ir/v1", + "schema_sha256": "abc123", + "codec_id": "cbor-canon-v1", + "registry_version": 1, + "types": [ + { + "name": "GeneratedIntentError", + "kind": "OBJECT", + "fields": [ + { "name": "message", "type": "String", "required": true } + ] + } + ], + "ops": [ + { "kind": "MUTATION", "name": "increment", "op_id": 111, "args": [], "result_type": "GeneratedIntentError" } + ] + }"#; + + let output = run_wesley_gen(ir); + assert!( + output.status.success(), + "CLI failed: {}", + String::from_utf8_lossy(&output.stderr) + ); + let stdout = String::from_utf8_lossy(&output.stdout); + assert!(stdout.contains("pub struct GeneratedIntentError")); + assert!(stdout.contains("pub enum GeneratedIntentError")); + assert!(stdout.contains("pub mod __echo_wesley_generated")); + assert_generated_crate_checks(&write_basic_generated_crate( + stdout.as_ref(), + "intent-error-collision", + )); } #[test] From dced3e7572021394ce3ec63f5d73ce027d42aa62 Mon Sep 17 00:00:00 2001 From: James Ross Date: Mon, 4 May 2026 07:50:36 -0700 Subject: [PATCH 17/21] docs: address contract hosting review feedback --- .../application-contract-hosting.md | 66 +++++++++++-------- .../design.md | 5 +- .../design.md | 35 +++++++--- ...continuum-contract-artifact-interchange.md | 22 ++++--- 4 files changed, 84 insertions(+), 44 deletions(-) diff --git a/docs/architecture/application-contract-hosting.md b/docs/architecture/application-contract-hosting.md index f120caa5..de8cb55a 100644 --- a/docs/architecture/application-contract-hosting.md +++ b/docs/architecture/application-contract-hosting.md @@ -109,8 +109,10 @@ Applications own: Use precise names at the boundary. -**Contract operation variables** are typed values generated from a contract -operation. Example: `IncrementVars { input: IncrementInput { amount: 42 } }`. +**Contract operation variables** are typed helper values generated from a +contract operation. Helper-only types live in the generated helper namespace so +they cannot collide with user contract types. Example: +`__echo_wesley_generated::IncrementVars { input: IncrementInput { amount: 42 } }`. **Canonical vars bytes** are the deterministic canonical-CBOR encoding of contract operation variables. @@ -168,7 +170,7 @@ mutation increment(input: IncrementInput): CounterValue the generated Rust shape is conceptually: ```rust -let intent = pack_increment_intent(&IncrementVars { +let intent = pack_increment_intent(&__echo_wesley_generated::IncrementVars { input: IncrementInput { amount: 42 }, })?; ``` @@ -176,7 +178,7 @@ let intent = pack_increment_intent(&IncrementVars { The generated helper performs the deterministic boundary work: ```text -IncrementVars +__echo_wesley_generated::IncrementVars -> encode_cbor(...) -> canonical vars bytes -> pack_intent_v1(OP_INCREMENT, &vars_bytes) @@ -187,9 +189,18 @@ Echo receives the EINT bytes. Echo does not need to know that the operation was called `increment` or that the payload contained an `IncrementInput`. That meaning belongs to the generated contract layer and the application. -## Dispatch Is Not A Function Call +## Dispatch Is Synchronous In Code, Not A Domain RPC -`dispatch_intent(...)` means: +`KernelPort::dispatch_intent` is a synchronous Rust trait method: + +```rust +fn dispatch_intent(&mut self, intent_bytes: &[u8]) -> Result +``` + +Implementations such as `WarpKernel` may handle reserved control intents inline +before returning a `DispatchResponse`. + +Its semantic boundary is still: ```text submit canonical causal input @@ -201,10 +212,10 @@ It does not mean: call this application method synchronously and mutate a hidden global state ``` -Echo returns a `DispatchResponse` that says whether the intent was newly -accepted, names the content-addressed intent id, and reports scheduler status. -The application should treat that response as ingress evidence, not as a -domain-specific result object. +The application should treat `DispatchResponse` as ingress evidence. It says +whether the intent was newly accepted, names the content-addressed intent id, +and reports scheduler status. It is not a domain-specific result object and it +must not hide app mutation in unrecorded global state. ## Read Path @@ -218,17 +229,13 @@ payload bytes according to the generated contract. sequenceDiagram participant UI as Application UI participant Gen as Wesley-generated client - participant ABI as echo-wasm-abi participant Echo as Echo KernelPort participant Runtime as Echo runtime UI->>Gen: request generated query - Gen->>ABI: encode_cbor(query variables) - ABI-->>Gen: canonical query vars bytes + Gen->>Gen: canonicalize query variables Gen->>Gen: build ObservationRequest - Gen->>ABI: encode_cbor(ObservationRequest) - ABI-->>Gen: request bytes - Gen->>Echo: observe(request bytes) + Gen->>Echo: observe(request) Echo->>Runtime: resolve coordinate, frame, projection Runtime-->>Echo: ObservationArtifact Echo-->>Gen: ReadingEnvelope + payload bytes @@ -434,12 +441,17 @@ A browser-hosted application should follow this shape: 6. Call `dispatch_intent(intent_bytes)`. 7. Decode `DispatchResponse`. 8. Use generated query helpers to build `ObservationRequest`. -9. Canonically encode the request. -10. Call `observe(request_bytes)`. -11. Decode `ObservationArtifact`. -12. Inspect the `ReadingEnvelope`. -13. Decode payload bytes into generated result types. -14. Render the UI. +9. Call `observe(request)`. +10. Decode `ObservationArtifact`. +11. Inspect the `ReadingEnvelope`. +12. Decode payload bytes into generated result types. +13. Render the UI. + +For a raw WASM export that accepts bytes, the browser adapter serializes the +`ObservationRequest` at the ABI boundary using its `Serialize` implementation +and canonical CBOR. That encoding is transport plumbing; the generated query +helper still produces an `ObservationRequest`, and the Echo read boundary is +`KernelPort::observe(request)`. The UI can be highly application-specific. The Echo calls remain generic. @@ -448,9 +460,11 @@ The UI can be highly application-specific. The Echo calls remain generic. A native Rust consumer can operate against `KernelPort` directly: ```rust -let intent = generated::pack_increment_intent(&generated::IncrementVars { - input: generated::IncrementInput { amount: 42 }, -})?; +let intent = generated::pack_increment_intent( + &generated::__echo_wesley_generated::IncrementVars { + input: generated::IncrementInput { amount: 42 }, + }, +)?; let response = echo_wasm_abi::kernel_port::KernelPort::dispatch_intent( &mut kernel, @@ -459,7 +473,7 @@ let response = echo_wasm_abi::kernel_port::KernelPort::dispatch_intent( let request = generated::counter_value_observation_request( worldline_id, - &generated::CounterValueVars {}, + &generated::__echo_wesley_generated::CounterValueVars {}, )?; let artifact = diff --git a/docs/design/0016-wesley-to-echo-toy-contract-proof/design.md b/docs/design/0016-wesley-to-echo-toy-contract-proof/design.md index 98f730df..6494ce9e 100644 --- a/docs/design/0016-wesley-to-echo-toy-contract-proof/design.md +++ b/docs/design/0016-wesley-to-echo-toy-contract-proof/design.md @@ -147,8 +147,9 @@ Result: passed. Implementation: -- `echo-wesley-gen` now emits per-operation vars structs such as - `IncrementVars` and `CounterValueVars`. +- `echo-wesley-gen` now emits per-operation vars structs in the generated + helper namespace, such as `__echo_wesley_generated::IncrementVars` and + `__echo_wesley_generated::CounterValueVars`. - Each generated operation receives a canonical vars encoder such as `encode_increment_vars(...)`. - Ergonomic mutation helpers now accept generated vars structs, encode them diff --git a/docs/design/0017-authenticated-wesley-intent-admission-posture/design.md b/docs/design/0017-authenticated-wesley-intent-admission-posture/design.md index ea114561..68f5f46e 100644 --- a/docs/design/0017-authenticated-wesley-intent-admission-posture/design.md +++ b/docs/design/0017-authenticated-wesley-intent-admission-posture/design.md @@ -149,14 +149,25 @@ contract_artifact_id = ir_digest || registry_digest || codec_id || - compiler_profile_digest || - artifact_trust_posture) + compiler_profile_digest) + +artifact_attestation = + { + contract_artifact_id, + artifact_trust_posture, + attesting_authority, + attestation_evidence_digest + } + +canonical_intent_bytes = + SerializeCanonicalIntent( + version, + contract_artifact_id, + op_id, + canonical_vars_bytes) intent_digest = - H("echo.intent.v2" || - contract_artifact_id || - op_id || - canonical_vars_digest) + H("echo.intent.v2" || canonical_intent_bytes) admission_id = H("echo.intent-admission.v1" || @@ -168,8 +179,16 @@ admission_id = ``` Those formulas are design sketches, not committed wire formats. The committed -requirement is domain separation and explicit scope: a digest must say what it -commits to. +requirements are domain separation, explicit scope, and stable identity: + +- `contract_artifact_id` names stable compiled artifact content only. Trust + posture, signer status, or certification evidence belongs in + `artifact_attestation` metadata so registry continuity survives posture + changes. +- `intent_digest` commits to the canonical submitted intent bytes, not an ad hoc + reconstruction from loose fields. If the future wire format uses a structured + envelope, `SerializeCanonicalIntent` must be the exact canonical byte + serialization for that envelope. ## Pre-Tick Admission Pipeline diff --git a/docs/method/backlog/cool-ideas/PLATFORM_continuum-contract-artifact-interchange.md b/docs/method/backlog/cool-ideas/PLATFORM_continuum-contract-artifact-interchange.md index 6e9b85c7..86697e3a 100644 --- a/docs/method/backlog/cool-ideas/PLATFORM_continuum-contract-artifact-interchange.md +++ b/docs/method/backlog/cool-ideas/PLATFORM_continuum-contract-artifact-interchange.md @@ -25,26 +25,32 @@ causal artifacts. Continuum artifacts should be able to name: - contract family -- schema hash +- schema codec, schema hash algorithm, and schema hash - intent or observer kind - basis and frontier -- payload hash -- receipt refs -- witness refs -- reading refs +- payload codec, payload hash algorithm, and payload hash +- receipt refs as codec/hash tuples +- witness refs as codec/hash tuples +- reading refs as codec/hash tuples - admission posture -- retained artifact hashes +- retained artifact codec/hash tuples Sibling runtimes should exchange protocol-shaped causal artifacts, not runtime internals. +Every encoded field that contributes to identity needs a canonical byte +serialization rule and stable interoperable codec/hash identifiers such as +multicodec and multihash labels. Semantic names like "schema hash" are not +enough for cross-runtime verification. + ## Acceptance criteria - One Echo contract receipt exports as a Continuum-shaped artifact. - A second runtime or verifier can inspect the artifact family identity without understanding Echo internals. -- Import uses witnessed suffix admission law instead of state snapshot sync. -- Missing contract family or schema support yields obstruction, not silent +- Import is not treated as generic state snapshot sync; it preserves contract + artifact identity and admission posture. +- Missing contract family or schema support is `obstructed`, not silent downgrade. ## Non-goals From 721e0efa6abe4b5e43eccafa77b190b295af08f1 Mon Sep 17 00:00:00 2001 From: James Ross Date: Mon, 4 May 2026 07:51:12 -0700 Subject: [PATCH 18/21] docs: update changelog for PR feedback --- CHANGELOG.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index b4071a8f..b8fc88da 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -43,6 +43,16 @@ ### Changed +### Fixed (PR #326 follow-up) + +- Fixed Wesley-generated helper output so helper-only vars and intent error + types live in a generated namespace instead of colliding with user contract + types, while preserving top-level helper function re-exports. +- Fixed contract-hosting docs to describe synchronous `KernelPort` dispatch + accurately, treat `ObservationRequest` as the read boundary, keep artifact + identity separate from trust posture, hash canonical submitted intent bytes, + and require codec/hash metadata for future Continuum artifact interchange. + ### Fixed (PR #313 follow-up) - The adaptive parallel-policy experiment follow-ups so benchmark/report rows From 0e3aa81b79b63b00040db111d87bdc9307ea5e5d Mon Sep 17 00:00:00 2001 From: James Ross Date: Mon, 4 May 2026 08:05:11 -0700 Subject: [PATCH 19/21] test: cover no-std Wesley helper output --- crates/echo-wesley-gen/tests/generation.rs | 76 +++++++++++++++++++--- 1 file changed, 68 insertions(+), 8 deletions(-) diff --git a/crates/echo-wesley-gen/tests/generation.rs b/crates/echo-wesley-gen/tests/generation.rs index b266bfc2..88915197 100644 --- a/crates/echo-wesley-gen/tests/generation.rs +++ b/crates/echo-wesley-gen/tests/generation.rs @@ -12,8 +12,14 @@ const TOY_COUNTER_IR: &str = include_str!("fixtures/toy-counter/echo-ir-v1.json" /// Spawns `cargo run -p echo-wesley-gen --`, pipes `ir` to stdin, and returns the output. fn run_wesley_gen(ir: &str) -> Output { + run_wesley_gen_with_args(ir, &[]) +} + +/// Spawns `cargo run -p echo-wesley-gen -- `, pipes `ir` to stdin, and returns the output. +fn run_wesley_gen_with_args(ir: &str, args: &[&str]) -> Output { let mut child = Command::new("cargo") .args(["run", "-p", "echo-wesley-gen", "--"]) + .args(args) .stdin(Stdio::piped()) .stdout(Stdio::piped()) .stderr(Stdio::piped()) @@ -264,7 +270,7 @@ mod tests { crate_dir } -fn write_basic_generated_crate(generated: &str, label: &str) -> PathBuf { +fn write_basic_generated_crate(generated: &str, label: &str, no_std: bool) -> PathBuf { let workspace = workspace_root(); let crate_dir = workspace .join("target") @@ -278,6 +284,33 @@ fn write_basic_generated_crate(generated: &str, label: &str) -> PathBuf { let registry_path = workspace.join("crates/echo-registry-api"); let wasm_abi_path = workspace.join("crates/echo-wasm-abi"); + let registry_dependency = if no_std { + format!( + r#"echo-registry-api = {{ path = "{}", default-features = false }}"#, + registry_path.display() + ) + } else { + format!( + r#"echo-registry-api = {{ path = "{}" }}"#, + registry_path.display() + ) + }; + let wasm_abi_dependency = if no_std { + format!( + r#"echo-wasm-abi = {{ path = "{}", default-features = false, features = ["alloc"] }}"#, + wasm_abi_path.display() + ) + } else { + format!( + r#"echo-wasm-abi = {{ path = "{}" }}"#, + wasm_abi_path.display() + ) + }; + let serde_dependency = if no_std { + r#"serde = { version = "1.0", default-features = false, features = ["derive", "alloc"] }"# + } else { + r#"serde = { version = "1.0", features = ["derive"] }"# + }; fs::write( crate_dir.join("Cargo.toml"), format!( @@ -290,19 +323,25 @@ publish = false [workspace] [dependencies] -echo-registry-api = {{ path = "{}" }} -echo-wasm-abi = {{ path = "{}" }} -serde = {{ version = "1.0", features = ["derive"] }} +{registry_dependency} +{wasm_abi_dependency} +{serde_dependency} "#, - registry_path.display(), - wasm_abi_path.display() ), ) .expect("failed to write generated Cargo.toml"); fs::write(crate_dir.join("src/generated.rs"), generated) .expect("failed to write generated module"); - fs::write(crate_dir.join("src/lib.rs"), "mod generated;\n") - .expect("failed to write generated lib.rs"); + let lib = if no_std { + r"#![no_std] +extern crate alloc; + +mod generated; +" + } else { + "mod generated;\n" + }; + fs::write(crate_dir.join("src/lib.rs"), lib).expect("failed to write generated lib.rs"); crate_dir } @@ -507,6 +546,7 @@ fn test_operation_vars_type_collision_uses_helper_namespace() { assert_generated_crate_checks(&write_basic_generated_crate( stdout.as_ref(), "vars-collision", + false, )); } @@ -544,6 +584,7 @@ fn test_generated_intent_error_user_type_does_not_collide_with_helper_error() { assert_generated_crate_checks(&write_basic_generated_crate( stdout.as_ref(), "intent-error-collision", + false, )); } @@ -595,6 +636,25 @@ fn test_toy_contract_generated_output_compiles_in_consumer_crate() { ); } +#[test] +fn test_toy_contract_no_std_generated_output_checks_in_consumer_crate() { + let output = run_wesley_gen_with_args(TOY_COUNTER_IR, &["--no-std"]); + assert!( + output.status.success(), + "CLI failed: {}", + String::from_utf8_lossy(&output.stderr) + ); + let generated = String::from_utf8_lossy(&output.stdout); + assert!(generated.contains("extern crate alloc;")); + assert!(generated.contains("pub mod __echo_wesley_generated")); + assert!(generated.contains("use alloc::vec::Vec;")); + assert_generated_crate_checks(&write_basic_generated_crate( + generated.as_ref(), + "toy-no-std", + true, + )); +} + #[test] fn test_generate_no_std_minicbor() { let ir = r#"{ From 2d6b3ea3e68153e86252acae455ee50269a90513 Mon Sep 17 00:00:00 2001 From: James Ross Date: Mon, 4 May 2026 08:05:27 -0700 Subject: [PATCH 20/21] docs: clarify generated query helper scope --- docs/architecture/application-contract-hosting.md | 7 ++++--- .../0016-wesley-to-echo-toy-contract-proof/design.md | 3 ++- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/docs/architecture/application-contract-hosting.md b/docs/architecture/application-contract-hosting.md index de8cb55a..ca725612 100644 --- a/docs/architecture/application-contract-hosting.md +++ b/docs/architecture/application-contract-hosting.md @@ -221,9 +221,10 @@ must not hide app mutation in unrecorded global state. Applications read from Echo by observing. -Generated query helpers should construct `ObservationRequest` values, call -`observe(...)`, verify enough of the returned `ReadingEnvelope`, and decode the -payload bytes according to the generated contract. +Generated query helpers construct `ObservationRequest` values. The application +adapter, or a future higher-level wrapper, calls `KernelPort::observe(...)`, +verifies enough of the returned `ReadingEnvelope`, and decodes the payload bytes +according to the generated contract. ```mermaid sequenceDiagram diff --git a/docs/design/0016-wesley-to-echo-toy-contract-proof/design.md b/docs/design/0016-wesley-to-echo-toy-contract-proof/design.md index 6494ce9e..3de5cd7d 100644 --- a/docs/design/0016-wesley-to-echo-toy-contract-proof/design.md +++ b/docs/design/0016-wesley-to-echo-toy-contract-proof/design.md @@ -29,7 +29,8 @@ GraphQL / Wesley IR -> generated op id and REGISTRY -> generated app-level EINT helper -> dispatch_intent(...) - -> generated read helper over observe(...) / ReadingEnvelope + -> generated ObservationRequest helper + -> consumer-owned KernelPort::observe(...) / ReadingEnvelope handling ``` ## Opening constraint From e45463b52602999fec9ac9471275485575f4c2f5 Mon Sep 17 00:00:00 2001 From: James Ross Date: Mon, 4 May 2026 08:05:56 -0700 Subject: [PATCH 21/21] docs: update changelog for follow-up review --- CHANGELOG.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b8fc88da..3cc77c3d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -47,7 +47,8 @@ - Fixed Wesley-generated helper output so helper-only vars and intent error types live in a generated namespace instead of colliding with user contract - types, while preserving top-level helper function re-exports. + types, while preserving top-level helper function re-exports, and added + no-std smoke coverage for op-bearing generated helpers. - Fixed contract-hosting docs to describe synchronous `KernelPort` dispatch accurately, treat `ObservationRequest` as the read boundary, keep artifact identity separate from trust posture, hash canonical submitted intent bytes,