MAP Design Spec: Dance Types, Implementation & Dispatch¶
Status: Draft
Author: MAP Core / Steve Melville
Intent: Specify how types declare dances, how implementations are bound, and how the host dispatches calls safely and dynamically.
Scope: Type system extensions, import format, governance/validation, runtime dispatch, security, caching, and compatibility with existing MAP/Holochain patterns.
0) Foundations & Assumptions¶
-
Self‑describing types
- All MAP types are holons described by TypeDescriptor holons.
InstancePropertiesandInstanceRelationshipsdeclare expectations for instances.- The metaschema already supports declaring new PropertyTypes and RelationshipTypes.
-
Holon identity & immutability
- Instances are immutable; newer versions create new holons.
- References are stable and do not “go stale”; caches can safely retain instances until memory pressure requires eviction.
-
Import format conventions
- Holon JSON import files use the unified
holonsarray, with relationships and properties defined on each holon. $refresolution is strict within the provided file set (no implicit global context).keyMUST appear beforetypein each holon definition.typeis shorthand for aDescribedByrelationship and should not be duplicated unless rules require exact match.
- Holon JSON import files use the unified
-
Key rules
- Some holons are keyed, some are keyless, per existing KeyRuleType semantics.
- Enum Variant holons are keyed and top-level (not embedded).
-
Governance membranes
- Spaces (I‑Spaces / We‑Spaces) enforce admission, attestation, and activation policies for new descriptors and modules.
- Provenance and attestations are recorded as holons and/or signatures on content hashes.
-
Runtime execution
- Host supports WASM/WASI execution and may optionally support:
- Process (spawned executable with stream protocol),
- Rust dylib (FFI with stable ABI),
- Builtin (host-registered functions).
- Single-threaded isolation for WASM execution is assumed.
- Modules are addressed by content hash and may be fetched via membrane-authorized channels.
- Host supports WASM/WASI execution and may optionally support:
1) Conceptual Model¶
At its heart, the MAP type system implements a dynamic dispatch model in which every type — not just HolonType — can advertise the behaviors it supports via fine-grained dispatch tables. These tables are essentially the per-type registries of “what this type can do,” expressed as relationships from the type descriptor to a set of DanceTypes.
In our new terminology, we’re formalizing this as:
<TypeDescriptor> —AFFORDS→ <DanceType>
Dynamic Dispatch Tables¶
-
One per type:
EveryTypeDescriptorcan have its own dispatch table — a set ofAffordsrelationships that point to theDanceTypes it supports. This allows dispatch to be as fine-grained as needed: even closely related types can differ in the set of dances they afford. -
Any type can afford dances:
We don’t limit affordances toHolonTypes.ValueTypes,RelationshipTypes, evenDanceTypes themselves can haveAffordslinks to other dances, enabling compositional and meta-level behaviors. -
Behavior resolution:
When the system receives aDanceRequestfor a specific target, the dispatch mechanism:- Identifies the type of the target holon.
- Looks up that type’s
Affordsrelationships. - Matches the requested dance against the list.
- Routes execution to the handler bound to that dance for this type.
Affordances as First-Class Relationships¶
Affordsis itself a RelationshipType holon (like all type descriptors in MAP).- Concrete instances of
Affordsare smartlinks between a type and a dance type. - Because
Affordsis part of the schema, it can carry metadata — version constraints, capability conditions, or even parameter hints — making affordances declarative, inspectable, and extensible.
Why This Matters¶
- Granularity: Instead of large, monolithic capability declarations, we get fine-grained, composable affordances that can evolve per type.
- Flexibility: Adding a new dance is a matter of creating a
DanceTypeand linking it viaAffords; no core code needs changing for schema-driven dispatch. - Uniformity: All affordances are modeled the same way, whether they’re about creating a holon, validating a property, or triggering a real-world workflow.
- Extensibility: The dispatch model is naturally open to extension in downstream schemas or spaces without schema rewrites — just add new
Affordslinks.
2) New/Updated Descriptors & Relationships¶
2.1 Descriptors¶
-
DanceType (HolonType, abstract)
The DanceType defines the interface for a single dance. This includes the dance name (by convention, this should be a verb) (e.g.,Render,Validate,SyncOut).- Properties (examples):
display_name,description,abi_id(optional if polymorphic). - Relationships:
Request-- to a HolonType that bundles the input parameters to the DanceRequest.
- Properties (examples):
-
DanceImplementation (Holon)
A concrete binding of aDanceTypefor a specificTypeDescriptor.- Properties (required unless noted):
Engine(Enum):WasmWasi|Process|RustDylib|BuiltinModuleRef(String): content address (e.g.,b3:…multihash, URL with hash, capability address)Entrypoint(String): export/function name (WASM symbol, FFI symbol, command name)ABI(String): stable ABI signature id the host supports (e.g.,map.dance.v1)Version(String): semver or content-hash pinCompatRange(String, optional): semver range allowedActivationStatus(Enum):proposed|active|disabledScope(Enum):Builtin|SchemaDefault|SpaceOverrideModuleHash(String): cryptographic hash of the content (if not implicit in ModuleRef)
- Relationships:
DanceType->DanceType -- The Dance being implemented.AffordingType-> TypeDescriptor (?) the type on whose behalf this dance is being implemented
- Properties (required unless noted):
-
(optional) DanceParameterSchema (Holon)
Describes structured inputs/outputs for ABI validation.
2.2 Relationships¶
-
Affords (DeclaredRelationshipType)
(TypeDescriptor) -[Affords]-> (DanceType)
Declares that instances of the type afford/expose the dance. -
ImplementsDance (DeclaredRelationshipType)
(TypeDescriptor) -[ImplementsDance]-> (DanceImplementation)
Binds concrete implementations available to the dispatcher. -
ForDance (DeclaredRelationshipType)
(DanceImplementation) -[ForDance]-> (DanceType)
The interface this implementation satisfies. -
(optional) ParametersSchema (DeclaredRelationshipType)
(DanceType) -[ParametersSchema]-> (DanceParameterSchema)
All descriptors follow the foundational rule:
type: "#TypeDescriptor"withExtendspointing at the appropriate meta-type, and they adopt MAP import conventions (key before type, unified relationships block, etc.).
3) Import File Additions & Examples (Illustrative)¶
Note: Examples are schematic and omit boilerplate. Use your established keys/type shorthands and naming patterns. (No code fences here; the following is raw markdown text with indentation.)
Example A: Declaring a DanceType and parameter schema
- key: Render.DanceType
- type: #DanceType
- properties: display_name="Render", description="Produce a representation"
- relationships: ParametersSchema -> #Render.Params.Schema (optional)
Example B: A TypeDescriptor that supports and implements a dance
- key: BookType.TypeDescriptor
- type: #TypeDescriptor
- relationships:
- Affords -> #Render.DanceType
- ImplementsDance -> #BookType.Render.WasmImpl (below)
Example C: A DanceImplementation bound to BookType for Render
- key: BookType.Render.WasmImpl
- type: #DanceImplementation
- properties:
- Engine="WasmWasi"
- ModuleRef="b3hash:Qm..."
- Entrypoint="render_book"
- ABI="map.dance.v1"
- Version="1.2.0"
- CompatRange="^1.0.0"
- ActivationStatus="active"
- Scope="SchemaDefault"
- ModuleHash="sha256:abcd..."
- relationships:
- ForDance -> #Render.DanceType
Space-scoped override
A We‑Space can introduce a second implementation with Scope="SpaceOverride" and ActivationStatus="active". Resolution rules (Section 5) ensure overrides take precedence without mutating the schema default.
4) ABI (Application Binary Interface)¶
4.1 Goals¶
- Stable contract between host and implementation irrespective of engine.
- Enable content-addressed modules to be swapped/upgraded safely.
- Keep functions stateless and deterministic (inputs → outputs), with side effects routed through explicit host calls (capability-gated).
4.2 Core shape (map.dance.v1)¶
- Inputs
dance_type_id(ref)type_descriptor_id(ref)instance_refs(list of holon ids or $ref proxies)parameters(bytes or canonical JSON/CBOR)context(agent id, space id, capability token, call chain, clock)
- Outputs
status(OK | Error(code))result(bytes or canonical JSON/CBOR)emitted_events(optional; for telemetry)
- Host imports
holon_fetch(id)→ bytesrelationship_query(query)→ idsattest(proof)→ receiptemit(event)→ ack- (All host functions are capability-gated and audited.)
4.3 Serialization & determinism¶
- Canonical encoding (CBOR or JSON Canonical Form).
- No host clock access except via provided
context. - No ambient I/O except via host-imported capabilities.
5) Dispatch Algorithm (Host)¶
Given a request (T, D, ctx):
- Affordance check: Ensure
T Affords D; otherwise fail withNotSupported(T,D). - Collect candidates:
C = { impl | T ImplementsDance impl ∧ impl ForDance = D ∧ impl ActivationStatus=active }. - Select binding (deterministic precedence):
- Prefer
Scope="SpaceOverride"inctx.space>SchemaDefault>Builtin. - Prefer exact
Versionpin > satisfiedCompatRange> latest compatible by semver. - Optional: apply policy filter (agent role, license/flowshare rules, allowlist).
- If multiple remain, choose lexicographically by
(Version, ModuleHash)or policy-defined tiebreaker.
- Prefer
- Load & cache:
- Fetch module by
ModuleRef(verifyModuleHash, signatures, provenance). - Instantiate per engine; reuse cached instance if ABI/spec allows (see lifecycle).
- Fetch module by
- Invoke:
- Marshal inputs to ABI.
- Call
Entrypoint. - Enforce time/memory fuel limits and capability quotas.
- Validate & return:
- Check ABI contract on outputs.
- Apply membrane “exfiltration filter” (response validation & redaction as promised).
- Return
DanceResponse.
Error handling: Produce structured errors: NotSupported, NoActiveImpl, ABIIncompatible, ModuleFetchFailed, SignatureInvalid, PolicyDenied, EngineError, Timeout, MemoryLimit, ResultValidationFailed.
6) Module Lifecycle, Caching, Eviction¶
- Cache keys:
(Engine, ModuleHash, ABI); instance-specific caches may include(SpaceId)when overrides alter host imports. - Warm: LRU or LFU for frequently used modules; prewarm on activation if policy allows.
- Evict: Under memory pressure, evict least-recently-used; keep provenance index regardless.
- Isolation: WASM instances single-threaded; no shared mutable state across invocations.
- Pure-function posture: Dances are stateless; all state arrives as inputs or accessed through explicit host capabilities.
7) Governance, Licensing, and Flowshare Hooks¶
-
Activation workflow:
- A
DanceImplementationarrives withActivationStatus="proposed". - Membrane policy may require two-key attest (Steward of
T+ Space Admin) and automated checks (hash, signature, license). - On success, flip to
active(space-scoped or schema default).
- A
-
Flowshare attachment:
- Implementations/Types may declare a ValueFlowPolicy holon that expresses revenue/reciprocity terms (e.g., non-extractive use-permitted; reciprocal flowshare when vital capitals exchanged).
- Dispatcher records
(T, D, impl_id)in telemetry for downstream settlement.
-
Non-extractive licensing posture:
- Free use in non-commercial/gift contexts remains unaffected.
- When reciprocal value flows are detected (per policy integration), contributors participate according to warrants/agreements.
8) Validation Rules (Import-time and Activation-time)¶
Import-time (schema-level)
- supports-impl-consistency: If (T ImplementsDance impl) then (impl ForDance) ∈ (T Affords). Error otherwise.
- single-active-impl: For each (T, D, scope), at most one ActivationStatus="active". Error otherwise.
- engine-fields-required: Property presence by engine:
- WasmWasi ⇒ ModuleRef, Entrypoint, ABI
- Process ⇒ ModuleRef, ABI (and Entrypoint if multiplexed)
- RustDylib ⇒ ModuleRef, Entrypoint, ABI
- Builtin ⇒ Entrypoint, ABI
- instance-type-kind-matches-extended-meta-type-name: Continue enforcing your existing meta/type-kind rules.
Activation-time (runtime policy)
- abi-compat: impl.ABI supported by host.
- module-integrity: ModuleHash matches fetched bytes; signatures and attestations verified.
- policy-eligibility: Space policy permits activation (governance roles, allowlists, flowshare acceptance).
- parameters-schema-match (optional): parameters conform to DanceParameterSchema.
9) Security, Provenance, and Audit¶
- Content addressing:
ModuleRefandModuleHashcryptographically bind code identity. - Signatures: Contributors sign module manifests; Spaces countersign activation.
- Reproducibility: Prefer reproducible builds; include build-info holon.
- Supply chain: Maintain provenance graph from source → build → artifact; store as holons.
- Audit trail: Every dispatch logs
(timestamp, agent, space, T, D, impl_id, module_hash, status, duration, fuel_used).
10) Engines & Host Integrations¶
-
WASM/WASI (preferred):
- Deterministic execution with resource caps (fuel, memory).
- Host imports expose capability-guarded functions.
- Versioned ABI adapters
map.dance.v1,v2, … allow evolution.
-
Process:
- IPC over stdin/stdout with canonical envelope.
- Strong isolation; higher overhead.
-
Rust dylib:
- Stable FFI surface identical to ABI envelope.
- Platform coupling; reserved for controlled deployments.
-
Builtin:
- Registered host handlers for critical hot paths.
- Still declared as
DanceImplementationwithScope="Builtin"for traceability.
11) Performance Considerations¶
- Cold-start: Prewarm frequently-used
(T,D)in background when allowed by policy. - Batching: Allow vectorized invocation (
Renderfor many instances) when ABI supports arrays. - Streaming: Optional chunked results for large outputs (with exfiltration filter applied per chunk).
- Caching: Separate caches for (a) holons (state), (b) modules (code), (c) relationships (indices).
12) Compatibility & Migration¶
-
Holochain conductor:
- Aligns with zome WASM loading (single-threaded WASM, dynamic dispatch).
- This spec generalizes beyond zomes by attaching behavior to any TypeDescriptor.
-
Incremental rollout: 1) Introduce descriptors/relationships with validators, no runtime usage. 2) Implement host-side dispatcher with
WasmWasionly. 3) Add governance activation path and telemetry. 4) Add overrides (SpaceOverride) and precedence rules. 5) (Optional) AddProcess/RustDylibengines.
13) Open Questions¶
- ABI evolution: Which fields must be strictly stable vs. adapter-shimmed?
- Parameter schemas: Standardize on JSON Schema vs. ValueType holons?
- Multi-impl composition: Should a dance support ordered pipelines/compose-many?
- Sandbox capability surface: Minimum viable host imports per dance category?
- Flowshare metering: Best trigger points to detect “reciprocal value” reliably and fairly?
14) Acceptance Criteria¶
- Types can declare
Affordsand bind one or moreDanceImplementations. - Host can resolve
(T,D)to an active implementation deterministically and execute it throughmap.dance.v1ABI. - Import-time validators catch misconfigurations; activation-time checks enforce integrity and policy.
- Telemetry records every dispatch with provenance, enabling governance and (optional) flowshare settlement.
15) Risks & Mitigations¶
- Complexity creep → Keep dispatcher minimal; push variability to data + ABI.
- Security of third-party code → Content hashing, signatures, sandboxing, capability gates, resource caps.
- Version skew → Semantic ranges with explicit pins; strong precedence rules; safe fallbacks.
- Memory growth → LRU/LFU eviction, per-engine instance pooling, prewarm limits.
16) Next Steps¶
- Add new descriptors and relationships to the metaschema & base-core import files.
- Implement import-time validation rules listed above.
- Define
map.dance.v1ABI envelope precisely (field names, encoding, error codes). - Build the host dispatcher (WASM/WASI path first) + module cache.
- Implement governance activation flows and attest capture.
- Instrument telemetry and add audit holons.
- Ship example:
BookTypewithRenderdance (schema default) and a Space-scoped override.