Wanderland

Wanderland Core: Envelope Schema

The declared shape of a boundary's input. lib/wanderland/envelope.rb catalogues every framework key in every stage of input — what type it is, which writer puts it there, whether it's optional. The same catalogue is queryable at /inspect/framework-schema, enforced at write time by Envelope.build, and consulted by BoundaryInput to decide which keys bypass per-boundary input_shape validation.

Overview

A boundary's input is the per-call envelope built by the framework before #call(input) runs. Three stages, each with its own writer:

Each stage's keys are declared as Entry records.

Entry shape

Entry = Struct.new(
  :key, :type, :stage, :written_by, :optional, :description,
  keyword_init: true
)

Fields:

Stages

:request

Eleven keys. Built by Dispatch.build_input; context and args added by the chain dispatcher.

key type written_by optional
runtime Wanderland::Runtime Dispatch.build_input no
config Hash Dispatch.build_input no
params Hash Dispatch.build_input no
query Hash Dispatch.build_input no
headers Hash Dispatch.build_input no
path String Dispatch.build_input no
route Hash Dispatch.build_input no
adapter String Dispatch.invoke yes
context Wanderland::Context Dispatcher::Chain#execute yes
args Hash Dispatcher::Chain#execute yes
identity caller-provided yes

:boot

Four keys. Built by Runtime#boot_from_config per archetype slot.

key type written_by optional
runtime Wanderland::Runtime Runtime#boot_from_config no
config_dir String Runtime#boot_from_config no
context Wanderland::Context Runtime#boot_from_config no
args Hash Runtime#boot_from_config no

:scenario

Four keys. Built by Wanderland::Scenario#run.

key type written_by optional
runtime Wanderland::Runtime Wanderland::Scenario#run no
context Wanderland::Context Wanderland::Scenario#run no
params Hash Wanderland::Scenario#run yes
headers Hash Wanderland::Scenario#run yes

Module surface

Wanderland::Envelope.schema(:request)        # => [Entry, Entry, ...]
Wanderland::Envelope.keys(:request)          # => ["runtime", "config", ...]
Wanderland::Envelope.required(:request)      # => keys minus optional
Wanderland::Envelope.framework_keys          # => union across all stages
Wanderland::Envelope.entry(:request, "runtime")
Wanderland::Envelope.to_h                    # => stages hash for JSON

framework_keys is the source BoundaryInput reads when deciding which keys bypass the per-boundary input_shape check.

Envelope.build

Constructs an envelope for a stage. The block yields a Builder; set and build enforce the schema.

input = Wanderland::Envelope.build(:request) do |env|
  env.set("runtime", runtime)
  env.set("config",  runtime.config&.domain || {})
  env.set("params",  params)
  env.set("query",   params)
  env.set("headers", headers)
  env.set("path",    path || route[:path])
  env.set("route",   route[:spec] || {})
  env.set("adapter", adapter.to_s) if adapter
end

Two failure modes raise Envelope::SchemaError:

/inspect/framework-schema

Two routes mounted in Engine::CORE_ROUTES.

GET /inspect/framework-schema

Full catalogue, grouped by stage.

{
  "stages": {
    "request":  [{ "key": "runtime", "type": "Wanderland::Runtime", ... }, ...],
    "boot":     [...],
    "scenario": [...]
  }
}

GET /inspect/framework-schema/:stage

One stage's entries.

{
  "stage": "request",
  "entries": [
    {
      "key": "runtime",
      "type": "Wanderland::Runtime",
      "stage": "request",
      "written_by": "Dispatch.build_input",
      "optional": null,
      "description": "Booted runtime — config, registries, engine."
    },
    ...
  ]
}

Error shape

Unknown stage returns 404 with the legal list:

{
  "error": "unknown stage: \"frob\"",
  "available": ["request", "boot", "scenario"]
}

:early tag resolution in user config

Config.load runs an :early-phase TemplateEngine pass over user config. :early tags (!Env, !UserConfig) resolve at config-load time. :late tags (!Fixture, !Oculus, !Task) survive untouched and resolve at request time when boundaries reach them.

strict_input: !Env { name: WANDERLAND_STRICT_INPUT, default: false }

strict_input

Wanderland::BoundaryInput raises Wanderland::BoundaryInput::UndefinedInputError on access to undeclared non-framework keys when runtime.strict_input? is true. Default false; undeclared keys fall back to the raw hash.

Three sources, in precedence order:

Wanderland.boot("config.yml", strict_input: true)
strict_input: true

strict_input: !Env { name: WANDERLAND_STRICT_INPUT, default: false }

The kwarg on Wanderland.boot wins. Config falls back. Default off.

The flag is read once at request entry by Wanderland::Boundary.execute_registration and rides per invocation in BoundaryInput.

input_shape and output_shape

Each boundary declares its read surface and write surface in its registration.

boundary :echo,
  input_shape:  { "params" => true },
  output_shape: { "echoed" => true },
  ...

Three shapes for the chain that runs every request.

Terminal

Both shapes declared. The boundary owns the read surface and the write surface.

boundary :echo,
  input_shape:  { "params" => true },
  output_shape: { "echoed" => true }

boundary :json_formatter,
  input_shape:  { "target" => true },
  output_shape: { "body" => true, "content_type" => true }

echo and the four formatters (json_formatter, html_formatter, markdown_formatter, text_formatter) declare both.

Passthrough

input_shape: {} (only framework keys read). output_shape: nil because the boundary re-emits the prior crossing's payload with one augmentation key, and prior keys vary per route.

boundary :verify_route,
  capabilities: [:verify, :passthrough],
  input_shape: {}

boundary :trace_emit,
  capabilities: [:trace, :passthrough],
  input_shape: {}

verify_route adds _verify. trace_emit adds _trace. format dispatches to a formatter and stamps body, content_type, formatter_used. seal adds _seal.

The :passthrough capability flag declares the dynamic-output contract.

Gate

input_shape: {}. output_shape declares both success and halt payload keys.

boundary :enforce_denials,
  input_shape: {},
  output_shape: {
    "ok" => true,
    "status" => true,
    "error" => true,
    "failed_requirement" => true
  }

Flow control covers the halt mechanics.

The Path to JSON Schema

Each key => true in a shape is the lazy floor: present, any value. The same field accepts the full ShapeMatcher vocabulary — matches, contains, keys, gte/lte, count, first, any, not, empty, prefix, plus the nested-hash form. Tightening:

input_shape: { "params" => true }

input_shape: { "params" => { "message" => true } }

input_shape: { "params" => { "message" => { matches: ".+" } } }

The introspection surface then carries enough to synthesise JSON Schema for two artefacts:

The synthesiser reads through /inspect/framework-schema and /inspect/boundary/:name. Both endpoints expose the full manifest as JSON; a generator fetches once and emits .json files an editor can validate against.

Source

Site Audit

wanderland.dev

oculus-view: fence: fence execute HTTP 404