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_domainscontains every non-RT entry from the configuredresponseexactly once and contains no other entries.- Dictionary insertion order has no array-layout meaning. Consumers always project the
mapping through
responseorder. - 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*pispan. - 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_kindresponse_boundschoices
They are input shorthands, not a second internal representation. Resolution follows these rules:
- Determine the non-RT stochastic response columns from the configured
responsebefore deadline or other formula auxiliaries are attached. - For legacy
categorical, apply the samechoicestuple asvaluesto every response column. - For legacy
continuous, apply a continuous specification to every response column; copy a column's bounds when supplied and otherwise leave it unbounded. - For legacy
circular, require and copy bounds for every response column. - 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_kindis the common kind when every response column has the same kind and is"mixed"otherwise.response_boundsis the mapping of all canonical entries that declare bounds.choicesis the common categorical values tuple only when every response domain is categorical and uses the same values; otherwise it isNone.
"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:
- verify that the ordered observation columns exist and the domain keys match;
- apply the existing reaction-time and declared missing/deadline handling without treating a deadline covariate as a response domain;
- exclude declared omission rows from response-domain checks;
- validate each remaining response column against its own kind and metadata;
- 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_samplesis the number of replica datasets requested for every parameter row.n_trialsis the number of parameter rows supplied to the simulator.obs_dimequalslen(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:
Falsemeans every observation component in that row is finite and domain-valid.Truemeans the complete observation row is unavailable; every component in the canonicalobservationsrow 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:
obs_dim == len(observation_schema);- the ordered schema names equal the configured stochastic
responsesnapshot, before any deadline auxiliary is appended to the formula; - a literal
"rt", when configured by HSSM, has the supported positive continuous RT schema and remains governed by HSSM's RT validation rather thanresponse_domains; - 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
rtsarray; - an RT-based legacy adapter explicitly stacks
rtsandchoices; a choice-only adapter maps onlychoicesand ignores its implementation placeholderrts=-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 dummyrt=-1into 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_choiceremains 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
Generatoradvances 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:
- 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.
- 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.
- ssm-simulators 6A3, additive producer metadata: add package-native
schema/
obs_dimaccessors, the named legacy RT/choice profile, explicit choice-only and continuous/mixed producer metadata, and the full downstream compatibility matrix. Do not change the existingvalidate_simulator_funreturn contract. - HSSM domain schema: add typed domain specifications and legacy-to-canonical resolution, then migrate validation to the resolved mapping.
- HSSM observation dimensions: derive PyTensor/PyMC support dimensions from ordered observation metadata and test dependency-free synthetic models at dimensions one through four.
- HSSM end-to-end substrate: prove mixed-domain likelihood, predictive, and save/load behavior entirely through generic modules.
- 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.mdexplains the problem, fixed-width v1 scope, observation-versus-auxiliary boundary, and why default legacy results remain.docs/reference/observation_result_contract.mdis 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 bytests/test_observation_result_docs.py.
6A2 documentation gate¶
docs/how_to/normalize_simulator_results.mdshows 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_outliermixtures 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.