Skip to content

ADR 0001: Multi-response observations and simulator results

  • Status: Accepted by PR #63; merging this amendment records the revised producer contract
  • Date: 2026-08-17
  • Amended: 2026-08-17
  • Owners: HSSM and ssm-simulators maintainers
  • Scope: HSSM model configuration and validation; ssm-simulators result metadata; cross-package adapters

Decision summary

HSSM will represent every non-reaction-time observation column with one authoritative response_domains mapping. Each entry carries its own kind and domain metadata. Existing global response_kind, response_bounds, and choices inputs remain a legacy homogeneous shorthand and are resolved once into the canonical mapping.

The ordered observation list remains separate and authoritative for array layout. Domain mappings identify columns by name but never define column order.

This is a generic HSSM capability. Its requirements are expressed entirely through observation domains and simulator-result contracts; no model-family-specific package import, model name, or coordinate formula belongs in the HSSM implementation.

ssm-simulators will own a versioned, ordered observation_schema for every stochastic scalar column and a canonical fixed-rank result view with observations plus an omission_mask. HSSM's non-RT response_domains is a lossless consumer projection, not the producer vocabulary. Existing rts/choices results and their historical singleton-axis behavior remain unchanged and are adapted only through an explicit source-to-schema projection.

Context

The experimental HSSM continuous/circular response work currently describes all response columns with one global response_kind. That can describe one non-RT domain, but not a schema that mixes domains or contains several response coordinates:

Observation archetype Ordered observations Non-RT domains
circular response rt, response circular [-pi, pi)
bounded continuous response rt, response continuous [0, pi]
mixed two-response rt, response1, response2 continuous [0, pi]; circular [-pi, pi)
mixed three-response rt, response1, response2, response3 continuous [0, pi]; continuous [0, pi]; circular [-pi, pi)

Adding only an obs_dim setting would fix array rank while leaving validation, serialization, and endpoint semantics ambiguous. Parallel dictionaries for kinds, bounds, and categorical values would also be vulnerable to missing or mismatched keys. One per-column specification is the smallest representation that removes those ambiguities.

Canonical observation contract

Ordered observations

The model config's response remains the ordered stochastic-observation list used by HSSM likelihoods, simulators, predictive coordinates, and saved model state.

  • An ordinary reaction-time model starts with the literal column "rt" and has one or more response columns after it.
  • A choice-only model has no "rt" entry and currently has exactly one observed response column.
  • response_domains contains every non-RT entry from the configured response exactly once and contains no other entries.
  • Dictionary insertion order has no array-layout meaning. Consumers always project the mapping through response order.
  • Duplicate observation names are invalid.

HSSM's existing deadline machinery may append a deadline covariate to the live formula response after config resolution. That auxiliary field is not a stochastic simulator observation, does not change obs_dim, and has no response-domain entry. Contract checks use the configured observation snapshot rather than the runtime-augmented formula list.

For example, a mixed two-response schema is ordered as follows:

response = ["rt", "response1", "response2"]
response_domains = {
    "response1": {"kind": "continuous", "bounds": (0.0, math.pi)},
    "response2": {"kind": "circular", "bounds": (-math.pi, math.pi)},
}

Domain specifications

The accepted in-memory shapes are:

{"kind": "categorical", "values": (-1, 1)}
{"kind": "continuous"}
{"kind": "continuous", "bounds": (0.0, math.pi)}
{"kind": "circular", "bounds": (-math.pi, math.pi)}

Every specification has exactly one kind. Other keys are kind-specific:

Kind Required metadata Forbidden metadata Endpoint semantics
categorical non-empty values bounds exact membership
continuous none values unbounded if bounds is absent; otherwise [lower, upper]
circular finite bounds values [lower, upper)

Common invariants:

  • A bounds pair has exactly two numeric endpoints with lower < upper.
  • Circular endpoints are finite. The declared interval defines the coordinate period; HSSM does not assume radians or require a 2*pi span.
  • Observed continuous and circular values must always be numeric and finite, even when a continuous domain is unbounded.
  • A model-specific likelihood may impose a narrower mathematical support, but its public response-domain metadata must not claim a wider valid coordinate range.

Categorical values

Canonical categorical values are finite, integer-valued numeric labels. Strings, non-integral floats, booleans, NaN, and infinities are not supported in this version. Observed values are checked for exact membership without an integer cast. A pandas float column containing -1.0 and 1.0 remains valid for values (-1, 1), but 0.5 cannot be silently converted to 0.

This deliberately preserves the current HSSM and ssm-simulators public choice vocabulary instead of broadening categorical likelihood and simulator arrays as a side effect of the multi-response work. Non-integer categorical labels require a separate proposal.

Choice-only models

A choice-only model maps its single observed column exactly like any other response column:

response = ["response"]
response_domains = {
    "response": {"kind": "categorical", "values": (0, 1, 2)},
}

There is no synthetic RT column, and the categorical observation is not renamed to choice. Learning-model context columns such as feedback or condition remain extra fields, not response domains. A deadline covariate remains an auxiliary formula field under HSSM's existing deadline path; it is likewise not added to response_domains.

Legacy homogeneous inputs

The following existing fields remain accepted for backward compatibility:

  • response_kind
  • response_bounds
  • choices

They are input shorthands, not a second internal representation. Resolution follows these rules:

  1. Determine the non-RT stochastic response columns from the configured response before deadline or other formula auxiliaries are attached.
  2. For legacy categorical, apply the same choices tuple as values to every response column.
  3. For legacy continuous, apply a continuous specification to every response column; copy a column's bounds when supplied and otherwise leave it unbounded.
  4. For legacy circular, require and copy bounds for every response column.
  5. Deep-copy the result and validate it as canonical response_domains.

User input that explicitly supplies response_domains together with any legacy domain field is rejected as ambiguous. Implementations must track which fields the user supplied before filling defaults; a default categorical value must not create a false conflict. Registered model configurations use one representation or the other, never both.

Compatibility summaries

After resolution, validation uses only response_domains. Existing model attributes may remain as derived compatibility summaries:

  • response_kind is the common kind when every response column has the same kind and is "mixed" otherwise.
  • response_bounds is the mapping of all canonical entries that declare bounds.
  • choices is the common categorical values tuple only when every response domain is categorical and uses the same values; otherwise it is None.

"mixed" is not an accepted input kind. Code that needs validation or likelihood semantics must inspect the resolved per-column mapping rather than branch on the summary.

Validation order

HSSM validates response data in this order:

  1. verify that the ordered observation columns exist and the domain keys match;
  2. apply the existing reaction-time and declared missing/deadline handling without treating a deadline covariate as a response domain;
  3. exclude declared omission rows from response-domain checks;
  4. validate each remaining response column against its own kind and metadata;
  5. report the failing column, received values or range, and expected domain.

Validation never mutates or recodes the user's data. Existing categorical warnings about declared-but-unobserved values remain homogeneous-model behavior; a future multi-domain warning must name the affected column.

Serialization

Saved HSSM state includes response and the resolved response_domains. Tuples are encoded as JSON arrays and restored as immutable tuples. Mapping keys are serialized in response order for stable diffs, although consumers must not infer order from the JSON object.

HSSM serialization and ssm-simulators metadata are related but distinct contracts. HSSM saves its resolved non-RT response_domains. The package-native simulator schema below uses explicit one-sided endpoints rather than JSON infinities; an HSSM adapter must reject a producer schema it cannot project without loss.

Canonical simulator result contract

Result container

A new simulator that participates in the generic contract returns:

{
    "observations": observations,
    "omission_mask": omission_mask,
    "metadata": {
        # Required, reserved observation-contract metadata:
        "observation_schema_version": 1,
        "observation_schema": (
            {
                "name": "rt",
                "kind": "continuous",
                "lower": 0.0,
                "lower_inclusive": False,
            },
            {
                "name": "confidence",
                "kind": "continuous",
                "lower": 0.0,
                "upper": 1.0,
            },
        ),
        # Optional producer-owned extensions remain valid:
        "simulator": "example_model",
        "max_t": 20.0,
        "boundary": boundary,
        "trajectory": trajectory,
    },
}

The three top-level keys and the two reserved metadata entries are required. The outer metadata mapping is an open producer-extension container: validators accept and preserve every non-reserved key without interpreting it. Current and future simulator identity, configuration, possible_choices, parameter, boundary, trajectory, NDT, timing-limit, and model-specific fields remain valid.

Only observation_schema_version and observation_schema are reserved by this contract. An adapter may add them to a shallow copy of legacy metadata, preserving extension-value identity, but must reject a pre-existing conflicting value rather than overwrite producer data. Validation never mutates a source mapping, array, or metadata value.

Version 1 observation schema

observation_schema is an ordered tuple of plain mappings. Its order defines the final axis of observations; it describes every stochastic scalar column symmetrically and has no special case for a literal "rt". Every entry has one unique non-empty name, one kind, and only the keys permitted for that kind.

Kind Required keys Optional keys Support semantics
categorical name, kind, non-empty values none exact membership in finite integer-valued numeric labels
continuous name, kind lower, upper, and the matching *_inclusive flags unbounded or one/two-sided scalar interval
circular name, kind, finite lower, finite upper none lower-inclusive, upper-exclusive [lower, upper)

For continuous, an endpoint must be finite when present. Its inclusion flag defaults to True; a flag is forbidden when the corresponding endpoint is absent. When both endpoints are present, lower < upper. Circular bounds also require lower < upper and do not accept configurable inclusion flags. Categorical values follow the same finite, integer-valued numeric contract as HSSM's canonical categorical domains.

Version 1 schema entries are closed to unknown keys. This catches misspellings and prevents new observation semantics from appearing without a schema-version decision. That closed entry vocabulary does not close the outer metadata extension namespace. Unknown schema versions fail explicitly.

Array shape and values

observations is a numeric NumPy array with the fixed shape:

(n_samples, n_trials, obs_dim)
  • n_samples is the number of replica datasets requested for every parameter row.
  • n_trials is the number of parameter rows supplied to the simulator.
  • obs_dim equals len(metadata["observation_schema"]) and is at least one.
  • All three axes remain present when their length is one. A producer never calls squeeze() on the canonical array.
  • Columns appear in exact schema order. The native validator does not require "rt", place it first, or infer semantics from its name.
  • Every non-omitted circular value is already in its declared lower-inclusive, upper-exclusive interval. Adapters do not wrap or repair producer output.
  • Every non-omitted value is validated against its own schema entry. Integer, object, and structured observation tensors are rejected; a floating NumPy dtype is the portable representation that permits mixed categorical and continuous fields plus all-NaN omitted rows.

A choice-only result therefore has shape (n_samples, n_trials, 1) and metadata such as:

{
    "observation_schema_version": 1,
    "observation_schema": (
        {"name": "response", "kind": "categorical", "values": (0, 1, 2)},
    ),
}

Omissions

omission_mask is a boolean array with shape (n_samples, n_trials). It is authoritative:

  • False means every observation component in that row is finite and domain-valid.
  • True means the complete observation row is unavailable; every component in the canonical observations row is NaN.
  • Partial-NaN rows are invalid. A multi-angle response is one joint observation and is never partially omitted by this contract.
  • The mask is a sidecar, not an observed response column and not a likelihood parameter.
  • Consumers must not drop, resample, or replace omitted rows silently.

An HSSM model config decides whether omissions are supported. A model without an explicit omission policy raises before returning predictive draws. A future HSSM bridge may use the mask to validate an all-NaN predictive row, but the mask does not by itself enable fitting missing observations or change HSSM's existing -999 observed-data convention.

HSSM projection and metadata agreement

The simulator schema and HSSM config describe the same ordered observations in their own package vocabularies. At adapter construction or first use, HSSM checks:

  1. obs_dim == len(observation_schema);
  2. the ordered schema names equal the configured stochastic response snapshot, before any deadline auxiliary is appended to the formula;
  3. a literal "rt", when configured by HSSM, has the supported positive continuous RT schema and remains governed by HSSM's RT validation rather than response_domains;
  4. every remaining schema entry projects exactly to the resolved HSSM domain for that named response column.

HSSM's first projection supports its existing categorical values, unbounded or closed two-sided continuous responses, and lower-inclusive/upper-exclusive circular responses. A future one-sided or exclusive continuous non-RT schema that HSSM cannot express is rejected rather than weakened. A mismatch names the model and differing field. HSSM never repairs producer metadata, and ssm-simulators never imports HSSM config types.

HSSM needs output rank before simulation to construct the PyTensor random-variable signature. ssm-simulators therefore exposes an additive package-native accessor with the schema version, ordered schema, and derived obs_dim. Existing callable/registry fields such as model name, choices, and model-specific metadata remain compatibility extensions; the generic contract does not replace them with HSSM fields.

HSSM validates the package-native result first and only then projects it into PyMC's leading dimensions and its own non-RT response_domains. A choice-only random variable may remove its final singleton support dimension at that consumer boundary. Such projections do not alter the canonical simulator result.

Predictive support coordinates remain np.arange(obs_dim) initially, preserving the existing two-column values [0, 1]. Semantic column names remain available through the model's ordered response; changing xarray coordinate labels is a separate compatibility decision.

Legacy rts/choices adaptation

The current ssm-simulators API returns rts, choices, and metadata and intentionally squeezes different singleton axes. It has many consumers in dataset generation, KDE estimation, LANfactory integration, and HSSM. F0-C does not change that API.

ssm-simulators will instead own an additive normalizer that returns a new canonical view:

normalize_simulator_result(
    result,
    *,
    expected_n_samples,
    expected_n_trials,
    observation_schema,
    source_projection=(("rts", "rt"), ("choices", "response")),
)

The exact public name may change during package review, but its behavior may not:

  • it does not mutate, delete, or reshape the input dictionary's public arrays;
  • it uses the expected sample/trial counts from the simulator call to reverse legacy singleton-axis squeezing without guessing;
  • it maps only caller-declared source keys to schema names and never infers semantic roles from values, names, or the mere presence of an rts array;
  • an RT-based legacy adapter explicitly stacks rts and choices; a choice-only adapter maps only choices and ignores its implementation placeholder rts=-1;
  • consistent legacy omission sentinels become one complete all-NaN observation row; partial or contradictory encodings fail;
  • it validates rank, element count, metadata, and schema domains before returning;
  • it shallow-copies legacy metadata, preserves every extension and extension-value identity, adds only non-conflicting reserved schema keys, and returns a newly validated plain mapping;
  • three-or-more-column legacy results are not guessed; those producers return the native contract directly.

Existing simulators continue returning their legacy keys and shapes by default. New continuous or multi-response simulators use the canonical result directly rather than inventing a categorical choices array. The categorical KDE and LAN data-generation paths continue consuming rts/choices; the new container does not claim that those algorithms support continuous responses.

RLSSM projection

For ssms.rl, only the stochastic fields declared by ModelConfig.response participate in the observation schema:

  • an ordinary RT-based RLSSM projects to ("rt", "response");
  • a choice-only RLSSM projects to ("response",) and never promotes dummy rt=-1 into an observation or omission;
  • participant/trial identifiers, context_fields, feedback/condition/block columns, derived zero-based learning choice, latent learning state, and computed SSM parameters remain auxiliary panel/history data;
  • response_to_choice remains the explicit raw-response-to-learning-action mapping and is never inferred from categorical schema order.

The stateful ssms.rl.Simulator.simulate() panel/DataFrame API is unchanged. A normalized view must preserve panel row order, participant boundaries, learning recursion, observed-history posterior-predictive semantics, and RNG advancement. Version 1 supports the existing discrete RT-based and choice-only RLSSMs; continuous or circular learning actions require a separate RLSSM proposal.

Version 1 boundary

Version 1 covers dense fixed-width numeric scalar observations and complete-row omissions. It does not encode ragged event streams, trajectories, partially observed vectors, array-valued fields, string categories, joint support such as a simplex or unit-vector manifold, auxiliary task/model state, or likelihood density measures. Trajectories, boundaries, latent learning state, task covariates, and training labels remain in their existing producer-owned result or metadata locations and do not become observations merely because they are numeric.

Adding unrelated producer metadata does not require an observation-schema version bump. Adding a new stochastic-observation semantic that version 1 cannot express does. Such an extension must define a new version rather than smuggle interpretation into an open metadata key.

RNG behavior

The outer public simulator boundary accepts an integer seed or NumPy Generator and normalizes it once per request.

  • Equal integer seeds reproduce within the same backend and execution mode.
  • Reusing a Generator advances that generator rather than replaying samples.
  • One request advances one stream across all samples and trials; helpers do not create a fresh unseeded generator per trial.
  • Global NumPy RNG state is not mutated.
  • A compiled backend may derive compatible bounded integer seeds from the request stream.
  • Thread count is part of a backend's execution mode when its RNG algorithm differs.
  • Exact sample equality is not required across Python, NumPy, Cython, sequential, or threaded backends. Cross-backend claims use calibrated distributional conformance.

HSSM continues to own the PyMC-side Generator. If a backend needs an integer, HSSM draws one within that backend's declared safe range and forwards it; it never assumes identical streams across backends.

Ownership

The ADR coordinates semantics but creates no importable spine package.

Repository Owns Must not own
HSSM public response_domains config, legacy resolution, per-column data validation, random-variable dimensions, predictive coordinates, serialization, and omission policy model-family-specific formulas or a second simulator-result implementation
ssm-simulators versioned observation schemas, canonical result validation/normalization, callable and registry metadata, RNG and termination behavior, omission encoding, and accelerated kernels HSSM config classes, response_domains, or model-specific likelihood ownership
HSSMSpine this decision, dependency order, and cross-repository review context runtime classes, validators, or compatibility shims
LANfactory and LAN_pipeline_minimal continued consumption of legacy categorical training outputs implied support for continuous/mixed observations from this ADR

Each runtime repository carries its own focused fixtures and tests. Matching field names in two packages do not justify a runtime dependency in either direction.

Implementation order

The contract separates early interface work from later simulator optimization:

  1. ssm-simulators 6A1, native contract: add versioned observation-schema and native result validation without adapting a legacy result, attaching metadata to a registered simulator, or changing any default output.
  2. ssm-simulators 6A2, legacy projection: add the explicit source-to-schema adapter with expected sample/trial counts, complete-row omission conversion, and shallow extension-metadata preservation. Keep every existing consumer on legacy keys.
  3. ssm-simulators 6A3, additive producer metadata: add package-native schema/obs_dim accessors, the named legacy RT/choice profile, explicit choice-only and continuous/mixed producer metadata, and the full downstream compatibility matrix. Do not change the existing validate_simulator_fun return contract.
  4. HSSM domain schema: add typed domain specifications and legacy-to-canonical resolution, then migrate validation to the resolved mapping.
  5. HSSM observation dimensions: derive PyTensor/PyMC support dimensions from ordered observation metadata and test dependency-free synthetic models at dimensions one through four.
  6. HSSM end-to-end substrate: prove mixed-domain likelihood, predictive, and save/load behavior entirely through generic modules.
  7. Accelerated pilot: implement and benchmark one eligible ssm-simulators kernel only after its package-owned scientific and performance gates pass.

No HSSM dependency floor is raised until a released ssm-simulators feature is actually consumed. Development branches may temporarily pin an immutable producer commit, with that dependency called out in both PRs.

Documentation acceptance

The package contract is not accepted through tests and type signatures alone. Every ssm-simulators substrate PR carries the user-facing and contributor-facing documentation for the exact surface it introduces, using the package's existing Diátaxis structure.

6A1 documentation gate

  • docs/explanations/structured_observations.md explains the problem, fixed-width v1 scope, observation-versus-auxiliary boundary, and why default legacy results remain.
  • docs/reference/observation_result_contract.md is the normative schema/version, array, domain, omission, metadata-extension, validation, and unsupported-case reference.
  • The public validator appears in docs/api/basic_simulators.md; the explanation and reference are linked from package navigation and the relevant landing page.
  • Runnable examples live under docs/snippets/observation_results/, are included by the documentation, and are executed verbatim by tests/test_observation_result_docs.py.

6A2 documentation gate

  • docs/how_to/normalize_simulator_results.md shows explicit legacy RT/choice, response-only, omission, and native multi-field cases.
  • The guide states which consumers should remain on legacy keys and documents expected counts, source projections, reserved-key conflicts, and shallow metadata preservation.
  • Its snippets use the same executable-example test rather than a second copied example.

6A3 documentation gate

  • The existing contributor model-addition guide gains a decision table for legacy versus native output, a complete schema checklist, auxiliary-output rules, versioning policy, and required tests.
  • Contributor guidance separates package-native callable/registry introspection from HSSM's consumer projection and includes the consumer-support matrix.
  • A dedicated RLSSM section distinguishes stochastic response fields, context/history, raw-response/action mapping, dummy RT, omissions, and the unchanged panel API.
  • Documentation states that new producer extension metadata does not require a schema version bump, while new stochastic-observation semantics do.

Every documentation PR builds the complete site, runs a link check, and executes its published snippets. A page that is not in navigation/API reference or an example that is not test-backed does not satisfy the gate.

The later HSSM substrate documents how it projects ordered package schemas into its own response plus non-RT response_domains; it must not present HSSM vocabulary as the ssm-simulators native contract.

Conformance cases

The reusable abstraction is an ordered dense numeric observation vector, not a model-family-specific result or a special continuous-response container. It can describe current RT/choice and response-only models as well as future confidence, force, endpoint, movement-angle, multi-latency, and multi-coordinate models when their stochastic output is a fixed-width vector of scalar numeric fields. Package tests use observation archetypes rather than model-family names as their primary fixtures:

Archetype Ordered schema names Required evidence
RT plus categorical choice rt, response positive open RT support, exact choice membership, native shape (S, T, 2)
response-only categorical response no synthetic RT, native shape (S, T, 1), dummy legacy RT ignored
RT plus bounded measurement rt, confidence positive RT and independent closed [0, 1] measurement validation
multiple continuous measurements latency, force, confidence independent unbounded, one-sided, and two-sided interval checks in schema order
mixed continuous/circular coordinates rt, polar, azimuth closed continuous and half-open circular validation without name-based inference
four scalar observations rt, x, y, z stable order and width across one/many sample and trial axes
complete-row omission any fixed-width schema boolean mask and all-NaN row agree exactly; partial omission rejected
open extension metadata any schema arbitrary non-reserved fields and value identity survive validation/projection

Model-family-specific mixed-domain fixtures may supplement those archetypes, but cannot be the only evidence that the package-level contract is generic. Likewise, schema order must drive validation even when field names do not use rt or response.

RLSSM conformance

The cross-package matrix includes both existing RLSSM shapes:

RLSSM case Stochastic schema Auxiliary state that must remain outside it
RT-based rt, response participant/trial IDs, context, learning choice, latent state, computed SSM parameters
choice-only response dummy rt=-1 plus the same panel/history fields

Tests protect ModelConfig.response, context_fields, response_to_choice, assembled participant input order, panel columns/order, learning updates, observed-history posterior-predictive behavior, and seeded stream advancement. Representative response-only presets include two, three, and four choices. A consistent RT/response omission becomes a complete omitted row; a choice-only dummy RT never does.

Known consumer compatibility matrix

The new view is opt-in. Every known direct and indirect consumer has an explicit boundary; unknown external callers are covered by exact preservation of the default legacy API.

Consumer Current dependency Required compatibility evidence
ssm-simulators functional/class APIs and unknown callers rts, choices, singleton squeezing, return_option, model metadata default signatures, keys, shapes, values, and metadata remain unchanged
ssm-simulators dataset, KDE/LogKDE, CPN/OPN paths legacy arrays, possible_choices, OMISSION_SENTINEL, choice probabilities, binned RT labels stay on the legacy categorical path; no continuous/mixed training claim
ssms.rl scalar trial extraction, stateful panel history, response mapping, dummy RT for choice-only both RLSSM schema cases above pass without changing the panel API
HSSM legacy simulator bridge, simulate_data, plotting, PyMC RNG, predictive dimensions, trajectory/boundary metadata no existing path opts into the view until a later HSSM projection PR
LANfactory direct simulators, dataset generation, LogKDE, network-inspector tests generated categorical training rows remain byte/shape compatible
LAN_pipeline_minimal data-generation CLI plus validation/recovery flattening of rts/choices files, labels, and recovery inputs remain unchanged
ssms-gui Simulator.simulate, choices, sample/trial metadata, trajectories, boundaries, NDT summary/variability behavior and all relied-on extension metadata survive
HSSMSpine ecosystem tutorial direct squeezing into [rt, choice] rows executed tutorial retains the historical shape
BayesFlow/SBI integrations and Hugging Face artifacts indirect categorical [parameters, rt, choice] training rows unchanged legacy producers preserve training and artifact semantics

HSSMCortex and EMC2 have no runtime ssm-simulators result dependency and therefore need no projection fixture. Public consumers outside the managed workspace cannot be enumerated; that uncertainty is why default legacy output preservation, rather than a best-effort consumer list, is the compatibility boundary.

Representative metadata snapshots cover simulator identity, possible_choices, sample and trial counts, max_t, parameters/configuration, boundary_fun_type, boundary arrays, trajectories, and choice-only placeholder information. Adding the two reserved schema keys must not rename, remove, deeply copy, or reinterpret those extension fields.

HSSM additionally protects all existing categorical, deadline, missing-data, choice-only RL, and two-column predictive tests. Deadline columns remain formula auxiliaries and do not alter simulator obs_dim. ssm-simulators protects byte/shape compatibility for legacy rts and choices, categorical dataset generators, RNG reproducibility, and single/multi-thread behavior.

Cross-repository scientific tests compare direct producer output with the HSSM adapter and compiled model. Cross-backend simulators are compared through RT quantiles, omission rates, and coordinate-appropriate unit-vector summaries rather than exact seeded draws.

Explicit exclusions

This decision does not provide or imply:

  • categorical string, boolean, or non-integral numeric labels;
  • automatic HSSM acceptance of one-sided or exclusive non-RT continuous schemas it cannot represent without loss;
  • continuous or mixed-response KDE, LAN, CPN, OPN, or training-data support;
  • lapse or p_outlier mixtures for continuous, circular, or mixed observations;
  • fitting of simulator omissions or a new missing-data likelihood;
  • automatic angular plotting or raw-angle averaging across circular wraps;
  • custom or collapsing model-family thresholds, estimated diffusion scale, or drift/NDT variability;
  • a model-family-specific HSSM subclass;
  • exact RNG equality across backends or thread modes;
  • an accelerated simulator port before the separate scientific and performance gates.

These exclusions are promotion boundaries, not placeholders that implementations may silently fill inside the substrate PRs.

Alternatives considered

Keep one global response kind

Rejected because it cannot represent a model containing both polar and azimuthal coordinates. Adding special cases for named model families would make generic validation depend on model names.

Add parallel per-column kind, bounds, and values mappings

Rejected because their key sets can drift independently. One discriminated domain entry keeps the kind and its legal metadata together.

Infer domains from column names or observed ranges

Rejected because the same numeric sample can be compatible with several measures. Endpoint and wrap semantics are properties of the model, not properties inferred from a finite dataset.

Replace rts/choices with the new result everywhere

Rejected because the legacy output is consumed broadly by ssm-simulators dataset generation, KDE utilities, LANfactory, and HSSM. An additive canonical view isolates the new capability and permits deliberate later migrations.

Put model-specific likelihoods or geometry in ssm-simulators

Rejected because simulator acceleration does not transfer mathematical ownership. Any promoted implementation needs explicit package ownership and separate scientific gates.

Consequences

The decision makes mixed-response configuration, validation, predictive dimensions, and serialization implementable without a model-specific HSSM class. It also gives a future compiled simulator one unambiguous output and omission contract.

The cost is an additional normalization layer while legacy outputs remain supported. Compatibility summaries such as response_kind == "mixed" are intentionally too coarse for validation, so internal code must migrate to the canonical mapping instead of continuing to branch on legacy attributes.

The fixed-rank result uses more explicit singleton axes than existing simulator output. That small verbosity is the mechanism that removes sample-versus-trial ambiguity and makes multi-column adapters auditable.