Skip to content

MAP Commands -- Phase 4 — Implement TypeScript MAP Commands internal wrapper layer #407

@evomimic

Description

@evomimic

MAP Commands -- Phase 4 — Implement Internal TypeScript MAP Command Layer

1. Summary (Required)

What is the enhancement?
Implement the internal TypeScript MAP command layer described by TypeScript MAP SDK — Implementation Specification as the authoritative implementation spec for this phase.

This phase delivers the full internal TS layer that sits between the public SDK and the Rust IPC boundary. It is responsible for:

  • defining internal wire-facing TypeScript types aligned with the MAP Commands spec
  • constructing structural MAP command objects
  • constructing MapIpcRequest
  • attaching request_id and RequestOptions
  • invoking the single Tauri IPC entrypoint
  • correlating and validating responses
  • decoding MapIpcResponse / MapResultWire
  • exposing internal command-layer functions used by the public SDK in Phase 5

This phase must provide exactly one IPC boundary function:

  • invokeMapCommand(request: MapIpcRequest): Promise<MapIpcResponse>

This phase is internal infrastructure for the SDK. It does not define the public ergonomic SDK surface.


2. Problem Statement (Required)

Why is this needed?
We want a strict separation between:

  • the internal TypeScript command layer: structural command construction, wire handling, transport, and result decoding
  • the public TypeScript SDK layer: ergonomic developer-facing objects and methods

Without this separation, public SDK semantics, request metadata, wire envelopes, response decoding, and IPC invocation details become entangled.

This phase establishes the TypeScript-side adapter layer corresponding to the host adapter role in the MAP Commands architecture.

It also establishes the only TS-side transport path to:

  • dispatch_map_command

3. Dependencies (Required)

Does this depend on other issues or features?

  • Phase 3 single Tauri command exists: dispatch_map_command
  • The Rust command, wire, and runtime pipeline is available end-to-end
  • MAP command and wire contracts are available to TypeScript in a form aligned with:

4. Proposed Solution (Required)

How would you solve it?

Create the internal TypeScript MAP command layer used by the public SDK in Phase 5.

This layer should include four responsibilities:

  1. internal structural and wire-facing TypeScript types
  2. transport boundary and IPC envelope handling
  3. internal command builders
  4. wire-result decoding and internal result mapping

A. Required transport boundary

Implement:

  • invokeMapCommand(request: MapIpcRequest): Promise<MapIpcResponse>

invokeMapCommand(request) must:

  • accept a fully formed MapIpcRequest
  • call Tauri invoke("dispatch_map_command", ...)
  • return MapIpcResponse on successful transport
  • reject on transport or IPC failure
  • perform request/response correlation: compare response.request_id with request.request_id and reject with MalformedResponseError if they do not match
  • fail clearly on other malformed or structurally invalid responses

invokeMapCommand must not:

  • infer scope
  • invent commands
  • perform business logic
  • batch commands
  • hide multi-command orchestration
  • implement runtime lifecycle policy

B. Internal wire-facing and structural types

Define the internal TS structures needed to mirror the current MAP Commands architecture, including equivalents in role to:

  • MapIpcRequest
  • MapIpcResponse
  • RequestOptions
  • MapCommandWire
  • SpaceCommandWire
  • TransactionCommandWire
  • TransactionActionWire
  • HolonCommandWire
  • HolonActionWire
  • ReadableHolonActionWire
  • WritableHolonActionWire
  • result wire variants needed to decode MapResultWire

These types must remain internal to the SDK package.

They must structurally align with the current Rust MAP Commands wire contract, including the JSON serialization format produced by serde.

C. Internal command builders

Implement internal command builder functions used by Phase 5 to perform one-command operations.

These functions must:

  • choose the correct structural scope
  • construct the matching internal command object
  • attach required wire-layer identifiers such as request_id, transaction identity, holon target, and RequestOptions
  • wrap the command in MapIpcRequest
  • call invokeMapCommand
  • decode MapIpcResponse
  • return decoded, typed results (e.g. TxId, HolonReferenceWire, string | null, number) rather than raw MapResultWire variants, so Phase 5 receives structured values it does not need to redispatch

This internal command layer should cover the command surface needed by the SDK implementation spec, including:

  • public-SDK-backed commands
  • internal-only command support needed for spec alignment

For this phase, dance() and query() should be supported in the internal layer for structural completeness, but they are not required to be exposed as public SDK APIs in Phase 5.

D. Request identity, options, result decoding, and error types

The internal layer must define and implement:

  • request_id generation and propagation behavior
  • RequestOptions attachment and defaulting behavior
  • explicit default handling for:
    • snapshot_after
    • gesture_id
    • gesture_label
  • total decoding over the MapResultWire variants used by the internal command layer
  • TypeScript error types — at minimum TransportError, MalformedResponseError, and DomainError (or equivalent) — providing enough structure for tests to assert on failure kind without string-matching error messages
  • clear distinction between:
    • transport failure → TransportError
    • malformed response / adapter failure → MalformedResponseError
    • domain failure returned as HolonErrorDomainError

This layer owns wire-result decoding and internal result mapping.

It does not own public SDK ergonomics.

Constraints:

  • no retries
  • no hidden sequencing
  • no transaction policy
  • no lifecycle policy
  • no local TS-side reference resolution
  • no public SDK ergonomics
  • no public export of wire or envelope types

This issue should treat map-ts-sdk-impl.md as the authoritative implementation source for this layer.


5. Scope and Impact (Required)

What does this impact?

  • Adds the internal TypeScript command layer used by the public SDK
  • Becomes the only TS-side integration point to MAP command IPC
  • Establishes the only TS call site for dispatch_map_command
  • Defines the internal TypeScript boundary for:
    • command construction
    • request metadata attachment
    • envelope handling
    • transport invocation
    • response correlation
    • result decoding

This layer is internal SDK infrastructure, not the final public ergonomic API surface.


6. Testing Considerations (Required)

How will this enhancement be tested?

  • Add a Rust test in map_commands_wire that serializes representative MapIpcRequest and MapIpcResponse values to JSON and records the output as fixtures. These fixtures are the ground-truth contract for the TypeScript wire type definitions and guard against serde serialization format drift.
  • Unit tests with mocked Tauri invoke
  • Tests for basic MapIpcRequest / MapIpcResponse transport behavior
  • Tests for request_id generation and propagation behavior
  • Tests for RequestOptions attachment and defaulting behavior
  • Tests for request/response correlation failure producing MalformedResponseError
  • Tests for malformed response failure behavior
  • Tests for domain error decoding from HolonError producing DomainError
  • Tests for representative structural command construction across:
    • Space
    • Transaction
    • Holon
  • Tests for representative result decoding across:
    • transaction creation
    • reference-returning commands
    • scalar-returning commands
    • collection/structure-returning commands
    • void-returning commands
  • Tests confirming the internal layer supports dance and query internally even if they are not publicly exported by Phase 5
  • Contract tests for representative wire request/response shapes
  • Optional runtime schema validation tests if adopted

7. Definition of Done (Required)

When is this enhancement complete?

  • invokeMapCommand(request: MapIpcRequest): Promise<MapIpcResponse> exists
  • It is the only IPC call site for MAP command execution in TypeScript
  • It invokes dispatch_map_command
  • It performs request/response correlation and rejects with MalformedResponseError on mismatch
  • Internal wire-facing request/response and command/result types are defined for the internal layer
  • request_id and RequestOptions handling are implemented
  • Internal command builder functions exist for the required MAP command surface
  • TypeScript error types (TransportError, MalformedResponseError, DomainError) are defined and used
  • Internal result decoders exist for the wire-result variants used by the internal command layer and return typed values, not raw MapResultWire
  • dance and query are supported internally as part of the structural/internal command layer
  • No public SDK business ergonomics or runtime policy logic is present in this phase
  • Rust JSON serialization fixture test exists in map_commands_wire
  • Tests cover representative command construction, request/response handling, transport failure, domain failure, and malformed response behavior

Optional Details (Expand if needed)

8. Alternatives Considered

  • Implement the public SDK directly over Tauri with no separate internal command layer
    Rejected: couples public SDK ergonomics and future API evolution directly to wire and IPC concerns.

  • Treat this phase as only a raw invoke() helper with no supporting command builders or result decoders
    Rejected: undershoots the current MAP Commands and TS SDK implementation specs, which require structural command construction, request metadata handling, and wire-result decoding at this layer.

  • Put result decoding in the public SDK layer
    Rejected: would leak wire concerns upward and blur the boundary between internal adapter logic and public SDK ergonomics.

9. Risks or Concerns

  • Type drift between Rust contracts and TS internal typings
  • Serde JSON serialization format drift: Rust enums and newtypes serialize in specific formats (externally-tagged enums, transparent newtypes, etc.) that must be matched exactly in TypeScript; a mismatch produces silently incorrect wire data
  • Drift between the internal TS command layer and the MAP Commands spec
  • Accidental leakage of wire concerns into the public SDK layer
  • Confusion between internal-only supported commands and publicly exported SDK methods

Mitigations:

  • Rust JSON fixture test in map_commands_wire establishes the serialization contract
  • Keep this issue aligned to map-ts-sdk-impl.md
  • Keep internal command/wire typings structurally aligned to commands.md
  • Confine wire-facing and envelope-facing types to the internal layer
  • Make public exports a separate Phase 5 concern
  • Verify in tests that internal support does not imply public export

10. Additional Context

This phase is intentionally internal and structural.

It includes:

  • wire-facing TypeScript types
  • transport boundary implementation
  • internal command construction
  • request metadata handling
  • response validation and decoding

Public SDK ergonomics belong in Phase 5.

Phase 5 should build on this layer rather than reconstructing envelopes, calling Tauri directly, or decoding raw wire results itself.

Metadata

Metadata

Assignees

Labels

enhancementNew feature or request

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions