Proposal 082: Sensorium Interfaces¶
Based on:
doc/project/40-proposals/024-capability-passports-and-network-ledger-delegation.mddoc/project/40-proposals/042-inter-node-artifact-channel.mddoc/project/40-proposals/045-sensorium-local-enaction-stratum.mddoc/project/40-proposals/047-classification-label-propagation.mddoc/project/40-proposals/066-inquirium-assistant-channel.mddoc/project/40-proposals/070-room-primitive.mddoc/project/40-proposals/071-sensorium-workbench.mddoc/project/40-proposals/072-capability-registry.mddoc/project/40-proposals/075-matrix-homeserver-runtime-profile.mddoc/project/40-proposals/080-multiplexed-middleware-channel-executor.mddoc/project/40-proposals/081-horizontal-protocol-primitives.mddoc/project/60-solutions/020-scheduler/020-scheduler.mddoc/project/60-solutions/023-artifact-delivery/023-artifact-delivery.mddoc/project/60-solutions/029-bounded-deferred-operations/029-bounded-deferred-operations.mddoc/project/60-solutions/030-sensorium/030-sensorium.mddoc/project/60-solutions/035-interaction-broker/035-interaction-broker.mddoc/project/60-solutions/042-sensorium-workbench/042-sensorium-workbench.md
Status¶
Implemented / promoted to Solution 046
The frozen V1 contract is implemented in Node and promoted to Solution 046: Sensorium Interfaces. This proposal remains the rationale, decision record, named-invariant catalog, and implementation tracker. It is an explicit hard-MVP release blocker whose implementation gate is satisfied.
Date¶
2026-07-16
Executive Summary¶
A Sensorium Interface is a host-owned, explicitly published projection of an enacted representation. It allows an authorized consumer to obtain that representation either:
- on demand, as one bounded read result; or
- over time, as a bounded cursor-based subscription.
The interface is not a connector, a capability, a store, a transport, or a new
organ. It is a resource governed by a small contract family. Capabilities authorize
operations on that resource; Sensorium, Workbench, and Artifact Delivery
providers produce or admit domain values; the Interaction Broker supplies bounded
probe/watch mechanics; and HTTP,
channel_json, authenticated peer sessions, Room live transport, and Artifact
Delivery remain interchangeable edge adapters with different delivery properties.
V1 has one canonical delivery contract: bounded cursor-based pull-batch. A live SSE, WSS, or Room view is a thin carrier projection whose bounded adapter loop repeatedly invokes read-next. It is not a second provider-push protocol.
This distinction is the central design rule:
environment
-> connector or Workbench provider
-> domain admission and projection
-> Sensorium Interface resource
-> authorized read or subscription
-> selected carrier adapter
-> consumer
No consumer reaches a connector directly. No carrier grants authority. No stream creates a second source of truth.
This proposal owns publication, delegated read, subscription lifecycle, and carrier-neutral flow control across Sensorium-backed views. Proposal 045 continues to own local Sensorium admission and actuation. Proposal 071 and Room are first consumers rather than alternate homes for the same semantics.
Basis and Existing Substrate¶
This proposal refines and composes existing contracts rather than defining an independent observation stack:
- Proposal 045: Sensorium Local Enaction Stratum owns connector lanes, observation admission, local query/get, directives, and Sensorium policy;
- Solution 030: Sensorium records local observation/query runtime as implemented, local Agora publication as partial, and cross-node read-through as deferred;
- Proposal 071: Sensorium Workbench and Solution 042: Sensorium Workbench already define bounded terminal events, screen snapshots, cursors, and Interaction Broker providers;
- Proposal 070: Room Primitive owns collaborative membership, grants, and best-effort live transport;
- Proposal 024: Capability Passports owns signed cross-node capability delegation;
- Proposal 080: Multiplexed Middleware Channel owns bounded host-to-middleware request/reply and observer transport;
- Proposal 081: Horizontal Protocol Primitives owns canonical causal context and immutable execution receipts;
- Proposal 047: Classification Label Propagation
owns
classification.v1propagation and no-broadening rules; - Solution 020: Replay Scheduler, Solution 029: Bounded Deferred Operations, and Solution 023: Artifact Delivery remain the host-owned primitives for polling, long-lived control operations, and large or store-and-forward artifacts.
The implementation should also follow node/DEV-GUIDELINES.md, especially its
rules for protocol/core/runtime stratification, schema-gating at boundaries, bounded
external work, explicit lifecycle state machines, and reuse of host-owned runtime
primitives.
Context and Problem Statement¶
Sensorium can currently admit and query observations locally. Workbench can expose a bounded terminal snapshot or event batch through the Interaction Broker. What is missing is one shared contract for deliberately making such a view available to another authorized local component or remote node.
Without that contract, each producer is likely to invent a different combination of:
- resource naming and discovery;
- read and stream APIs;
- grants and caller binding;
- cursors, replay, backpressure, and overflow;
- classification and redaction;
- revocation and stream closure;
- retention and capture;
- transport-specific envelopes.
The result would be three semantically different implementations for a terminal view, a temperature sensor, and a camera, even though all three need the same publication and subscription mechanics.
Goals¶
- Define one host-owned resource representing an explicitly published view.
- Give on-demand reads and subscriptions the same payload and cursor semantics.
- Make the first implementation possible with existing Sensorium, Workbench,
Interaction Broker, Replay Scheduler,
channel_json, Room, and Artifact Delivery machinery. - Keep authorization, classification, retention, and transport as separate strata.
- Support local components, direct authenticated peers, and collaborative Room use without making any one carrier canonical.
- Make queue, batch, byte, lease, deadline, replay, and retention bounds explicit.
- Preserve P081 causal context and receipt semantics across publication, read, subscription, revocation, and terminal outcomes.
Non-Goals¶
- A general remote connector API.
- Direct consumer access to devices, terminals, or connector credentials.
- A lossless universal event bus.
- Global discovery of available sensors or interfaces.
- Automatic persistence of streams in Memarium.
- Moving Sensorium observations into Room, Matrix, or Agora as a new source of truth.
- Treating Room membership, Matrix membership, a transport session, or possession of an interface id as authorization.
- Adding actuation commands to the read/subscribe contract. Commands remain in separate Sensorium directive and Workbench tool-request lanes; their future interface-level authority and coordination contract is defined separately by Proposal 083: Sensorium Interactive Interfaces.
- Promising erasure of information already received by an authorized consumer.
Surveillance Is a Relationship, Not an API Shape¶
Surveillance is observation without adequate knowledge, consent, authority, or scope. The same camera or terminal view can participate in care, collaboration, operations, coercion, or surveillance. A schema cannot infer that relationship, but the host can enforce structural preconditions:
- no interface becomes externally readable until an authorized source-side actor publishes it;
- interfaces are local-only and undiscoverable by default;
- the source operator can enumerate active interfaces, grants, subscriptions, and recent closures;
- grants bind a canonical namespaced authenticated subject ref, interface id, operations, classification ceiling, expiry, and rate/volume limits; bare ids are invalid because they cannot distinguish principal kinds;
- every emitted value passes source policy, redaction, and egress classification;
- revocation stops new reads and emissions within host-owned pull-loop and revocation-view freshness budgets; tests prove refusal before the next authorized emission without presenting durable-write latency as that bound;
- data already delivered is outside technical revocation and must not be described as retractable;
- representations involving third parties carry the appropriate
classification.v1.bound_subjectsprojection and may require consent beyond the source operator.
The prohibited design is therefore an ambient, invisible, unbounded, or unauthorized observation surface. The contract does not preclude a narrow interface that affected parties knowingly and legitimately choose to share.
Proposed Model¶
1. Interface Is a Resource; Capability Is an Operation Class¶
The phrase "interface = published capability" is rejected. It couples a resource instance to an authorization vocabulary and would grow the capability registry for every sensor, terminal session, or view.
Instead:
sensorium-interface:<id>identifies one published view;sensorium.interface.readauthorizes bounded on-demand reads;sensorium.interface.subscribeauthorizes creation and use of a bounded subscription;sensorium.interface.manageauthorizes publication, suspension, withdrawal, and grant administration on the source node.
The V1 registry posture is frozen with the operation classes:
| Capability id | wire/name |
Surfaces | Dispatchable | Advertisable | Passport eligible | Signing domain | Host route | Federated discovery |
|---|---|---|---|---|---|---|---|---|
sensorium.interface.read |
sensorium/interface.read |
host-local, federated |
true | true | true | false | true | true |
sensorium.interface.subscribe |
sensorium/interface.subscribe |
host-local, federated |
true | true | true | false | true | true |
sensorium.interface.manage |
sensorium/interface.manage |
host-local |
true | false | false | false | true | false |
Advertising read or subscribe declares protocol support only. It never advertises
an interface descriptor, source binding, grant, or active subscription. A grant or
Passport scope narrows a generic operation to one interface resource. Possession of
a valid Passport is evidence; the source node still performs local admission and
current restriction checks on every operation. The machine registry and its
authorization-policy sidecar MUST carry these flags explicitly; implementation
defaults may not infer them from the capability name.
read and subscribe remain separate because they grant different authority and
create different state. read authorizes one bounded stateless result. subscribe
authorizes creation, renewal, bounded consumption, and closure of one caller-bound
lease; it permits reads only through that lease and does not imply arbitrary
one-shot access. The initial manage capability is source-local and MUST NOT be
delegated through a cross-node Passport. Whether later local policy splits it into
publication and grant-administration capabilities is an explicit post-V1 policy
decision, not a wire concern hidden in the request body.
One interface has one projected meaning and one primary output schema. A terminal screen and a terminal event feed should therefore be separate interface resources, even if they share the same underlying Workbench session. This avoids conditionals inside a supposedly stable interface and lets the more revealing event feed carry a stricter policy.
2. Publication Is Explicit and Local by Default¶
Publishing creates a descriptor and a private source binding in host-owned storage. The descriptor is safe to reveal only to an already authorized consumer; the source binding remains local and may contain connector, terminal-session, topic, or provider details that must not cross the boundary.
Conceptual descriptor:
{
"schema": "sensorium-interface-descriptor.v1",
"schema/v": 1,
"interface/id": "sensorium-interface:01K0EXAMPLE",
"interface/name": "workbench-current-screen",
"publisher/node-ref": "node:did:key:z6MkPublisherExample",
"output/schema-ref": "urn:orbiplex:schema:sensorium-terminal-screen-snapshot:v1",
"delivery/semantics": "latest-state",
"access/modes": ["read", "subscribe"],
"classification/max-tier": "Personal",
"classification/topic-class": "sensorium-interface/workbench-visible-viewport",
"redaction/profile-ref": "redaction:terminal-visible-viewport-v1",
"limits": {
"frame/max-bytes": 65536,
"batch/max-frames": 32,
"batch/max-bytes": 262144,
"lease/max-seconds": 900
},
"overflow/policy": "coalesce-latest",
"expires/at": "2026-07-13T13:00:00Z"
}
Lifecycle and health are a separate rebuildable projection:
{
"schema": "sensorium-interface-status.v1",
"schema/v": 1,
"interface/id": "sensorium-interface:01K0EXAMPLE",
"lifecycle/status": "published",
"health/status": "ready",
"status/at": "2026-07-13T12:00:00Z"
}
The descriptor is an immutable publication contract. Limits remain nested because
they are security and delivery semantics that must be authorized together with the
output schema; they are not an independently swappable tuning profile. Lifecycle
and health are separated because they change over time. Changing the descriptor's
source projection, output schema, classification ceiling, or limits withdraws the
old interface and publishes a new interface/id rather than mutating its meaning in
place. A grant or current host policy may always narrow effective limits without
changing the descriptor; it cannot widen them.
P082-003 will materialize this descriptor as JSON Schema. The following semantic invariants are frozen now:
delivery/semanticsis a closed enum:latest-stateorordered-eventsin v1;latest-staterequiresoverflow/policy = coalesce-latest;latest-stateforbidsreplay/max-framesandreplay/max-seconds; it retains exactly one current complete snapshot per source generation, and its cursor is a change detector rather than a history promise;ordered-eventspermitsemit-gaporclose-subscription, never silent loss;ordered-eventsrequires positivereplay/max-framesandreplay/max-seconds; effective replay retention is their intersection, so reaching either bound may evict the oldest event;- all numeric bounds are positive and capped by host policy;
frame/max-bytescaps each allocation and serialized frame, whilebatch/max-bytesindependently caps their aggregate plus envelope overhead; a value above the frame cap becomes an Artifact Delivery reference, not an automatically fragmented frame;- an expired, suspended, or withdrawn interface cannot admit new reads or subscriptions;
- the externally visible descriptor never contains connector credentials, local filesystem paths, middleware launch credentials, or the private source binding;
- interface publication does not create Seed Directory, Agora, or federation-root advertisement state.
2.1 Operational Impact Is Published Context, Not Authority¶
A published interface may expose a representation of a disposable experiment, a test environment, a live production service, or safety-critical infrastructure. That property belongs to the enacted resource and its exact interface publication; it is not knowledge that Corpus, Room, Agent, or Inquirium should infer from natural language. The planned shared value is:
{
"schema": "sensorium-operational-context.v1",
"schema/v": 1,
"impact/class": "test",
"context/summary": "Controlled mail-server fixture without customer data."
}
impact/class is a closed, ordered vocabulary:
| Class | Meaning of the enacted source |
|---|---|
research |
Detached exploratory material or a source with no intended live operational effect. |
experimental |
A disposable or explicitly unstable environment in which failure is expected and contained. |
test |
A controlled validation environment with no live users or production authority. |
production |
A live service, live user workflow, or source representing real operational state. |
critical |
A production environment whose disruption may cause safety, essential-service, major legal, or major economic harm. |
The order above is a conservative caution lattice, not a reputation score. It is
orthogonal to classification.v1: classification governs who may see data, while
operational impact describes the consequences of acting on or reasoning about the
represented environment. It is also orthogonal to read, subscribe, invoke, Room,
and Passport authority. No class grants access or authorizes an effect.
context/summary is optional untrusted descriptive data. When present, its UTF-8
encoding is limited to 512 bytes; schema validation should also apply
maxLength = 512, while the semantic boundary enforces the byte cap. Control
characters other than ordinary JSON whitespace are refused. P082-021 must include
negative fixtures for both code-point and UTF-8 byte overflow. The limit is part of
the V1 contract, not an adapter default.
An adapter instance may provide an operator-configured default, but an exact source
resource or environment pins the candidate value. This matters because one adapter
may expose both test and production resources. The publishing host validates that
candidate against local policy and may raise it, never lower it. Changing the
published class creates a new immutable interface publication rather than mutating
the meaning of an existing interface/id.
P082-021 freezes freshness as an identity and lifecycle predicate, not a
wall-clock-age heuristic. The shared resource envelope and every context-bearing
result carry source/generation-ref beside operational/context. The source host
also maintains one current effective publication for the host-private slot:
(source/kind, source/ref, projection/profile-ref, interface/kind)
Operational context is stale exactly when either:
- the publication-bound
source/generation-refdiffers from the source adapter's current generation; or interface/idis no longer the current effective publication for that slot because a newer publication superseded it.
Suspension, withdrawal, and expiry retain their existing typed lifecycle refusals;
they also make the context unusable but are not alternative meanings of stale.
Source freshness, frame age, Room relay epoch, grant freshness, and revocation-view
freshness remain separate predicates. A consumer must not invent a duration-based
operational-context TTL.
When an environment's candidate context changes, including test -> production,
the source host serializes publication replacement: it activates the new immutable
descriptor and terminally withdraws the old one as superseded, recording
supersedes/interface-id on the replacement and replacement/interface-id on the
old publication status. Every replacement requires an operator-facing
replacement/reason that is non-empty, trimmed, NUL-free, and limited to 512 UTF-8
bytes; an initial publication refuses that field rather than silently discarding it.
Existing subscriptions to the old publication close. If the source generation or
current context changes before replacement commits, the old publication is
immediately stale and reads fail closed; temporary
unavailability is safer than continuing under the old class. A running Room
projection that observes this refusal emits a recipient-filtered, transient
suspended / degraded interface status with the exact typed generation or
context error before closing. This carrier evidence does not mutate the durable
publication lifecycle; immutable replacement remains the only operation that
changes the effective publication identity.
The same auditable replacement path corrects an accidentally overclassified source,
for example critical -> test. "Raise, never lower" means that one consuming host's
effective class may never be below the current source publication; it does not
make historical source declarations or local policy overlays irreversible. A lower
replacement requires explicit operator action and a reason in the publication audit.
The extension adds operational/context to the shared
sensorium-interface-resource.v1 envelope and both directional descriptors as a
universally required V1 field. The earlier additive-rollout option that would have
kept it wire-optional was deliberately not used: every profile fails closed when the
value is absent, malformed, or inconsistent. Implementations must not reintroduce
wire optionality as compatibility behavior, because missing metadata must never be
interpreted as low risk.
Every P082 data result from a context-bearing interface repeats the exact validated
source/generation-ref and operational/context from its immutable descriptor. A
Room adapter transports the complete read-result value unchanged; it does not
interpret the class or decide freshness. A receiving host verifies structural
equality with the disclosed descriptor, rejects a superseded publication or source-
generation mismatch under the frozen predicate above, and otherwise binds the value
to the immutable interface/id. The optional context/summary remains untrusted
data and is never promoted directly into a system or developer instruction. This
gives downstream resolvers the class before they expose frame payloads while keeping
the carrier authority-neutral.
3. Source Binding Is Polymorphic and Host-Private¶
The host binds an interface to a provider through data, then selects behavior through a narrow provider trait. The interface runtime must not grow one transport or daemon branch for every sensor type.
Conceptual local value:
{
"interface/id": "sensorium-interface:01K0EXAMPLE",
"source/kind": "workbench-terminal-screen",
"source/ref": "terminal-session:01JZEXAMPLE",
"projection/profile-ref": "projection:terminal-visible-viewport-v1"
}
Illustrative core boundary:
pub trait SensoriumInterfaceSource: Send + Sync {
fn source_kind(&self) -> &'static str;
fn ready(&self) -> bool;
fn validate_binding(
&self,
descriptor: &InterfaceDescriptor,
binding: &InterfaceSourceBinding,
) -> Result<(), InterfaceSourceError>;
fn next_batch(&self, context: InterfaceSourceWatchContext)
-> Result<SourceBatch, InterfaceSourceError>;
}
The first runtime should adapt this boundary to the existing Interaction Broker
provider registry rather than implement another wait/watch engine. One
ObservationSource::SensoriumInterface { interface_id } variant can route all
interface watches to one registered domain provider; that provider then dispatches
by the private source/kind. This adds one broker integration point, not a new
source-specific match arm for every adapter.
Initial source adapters:
| Source kind | Existing producer | Initial projection |
|---|---|---|
sensorium-observation-query |
Sensorium Core sensorium.observe.query / sensorium.observation.get |
admitted observation or bounded latest value |
workbench-terminal-screen |
Workbench terminal provider | sensorium-terminal-screen-snapshot.v1 |
workbench-terminal-events |
Workbench terminal provider | bounded sensorium-terminal-event.v1 batch |
artifact-snapshot |
Artifact Delivery object pointer | immutable by-reference payload |
The implemented daemon persists a generic, closed source/binding value with a
bounded private source/config, dispatches it through a registry of at most 64
adapters, and revalidates the adapter and binding on every read after restart.
Adding an adapter therefore extends the registry rather than a central source
match. The initial four adapters above are registered through that boundary.
Startup fails unless all four built-in adapters are registered. Unknown,
duplicate, unavailable, malformed, or excess adapters fail closed. Registry
ready state is a point-in-time operator signal; next_batch remains the
authoritative operation and may still fail closed when source readiness changes
after the snapshot. Registry snapshots clone adapter handles before invoking
ready(), so neither provider readiness nor source I/O runs under the registry
lock.
Source Policy and Interface Authority Compose¶
Sensorium Core currently emits sensorium.read.local as the default value in an
admitted observation's admission.consumer_scopes. It is a source-domain policy
scope, not a registered host-dispatch capability and not remote authority.
For source/kind = sensorium-observation-query, the two layers compose
conjunctively:
- the host-local source adapter may query only observations whose Sensorium consumer-scope policy permits that local projection;
sensorium.interface.readorsensorium.interface.subscribeindependently authorizes the bound caller to cross the published interface boundary;- the interface grant may narrow the source result but can never widen its consumer scopes, classification, redaction, retention, or query bounds.
A remote caller is never granted or asked to present sensorium.read.local. The
source node exercises that local scope internally, then performs interface admission
and egress checks. Neither layer replaces the other, and failure at either layer
fails the read closed.
4. Read and Subscribe Share One Batch Contract¶
An on-demand read returns one bounded result batch. A subscription returns a sequence of the same result batches. The batch, not an individual frame, is the unit of cursor progress, P081 causality, diagnostics, and carrier projection. Frames remain small domain values inside that envelope.
Conceptual read request:
{
"schema": "sensorium-interface-read-request.v1",
"schema/v": 1,
"interface/id": "sensorium-interface:01K0EXAMPLE",
"delivery/kind": "one-shot",
"cursor/after": "opaque:provider-bound-cursor",
"batch": {
"frames/max": 16,
"bytes/max": 131072,
"wait/max-ms": 5000
},
"deadline/at": "2026-07-13T12:00:05Z",
"causal/context": {
"schema": "causal-context.v1",
"schema/v": 1,
"context/id": "causal-context:01K0EXAMPLE",
"correlation/id": "corr:sensorium-read:01K0EXAMPLE",
"operation/id": "operation:01K0EXAMPLE",
"causation/refs": [],
"origin/actor-ref": "component:arca",
"created/at": "2026-07-13T12:00:00Z"
}
}
For a one-shot read, delivery/kind = one-shot and subscription/id is absent. For
the next batch of an active subscription, the same request uses
delivery/kind = subscription and carries subscription/id. The schema makes this
a conditional invariant rather than using null. The host verifies that the
authenticated caller, interface id, cursor, and live lease all refer to the same
subscription. A cursor is never a subscription bearer token.
Conceptual subscription result:
{
"schema": "sensorium-interface-read-result.v1",
"schema/v": 1,
"interface/id": "sensorium-interface:01K0EXAMPLE",
"delivery/kind": "subscription",
"subscription/id": "sensorium-subscription:01K1EXAMPLE",
"batch/outcome": "data",
"cursor/next": "opaque:provider-bound-cursor-42",
"frames": [
{
"schema": "sensorium-interface-frame.v1",
"schema/v": 1,
"frame/kind": "snapshot",
"observed/at": "2026-07-13T12:00:01Z",
"emitted/at": "2026-07-13T12:00:02Z",
"payload/schema-ref": "urn:orbiplex:schema:sensorium-terminal-screen-snapshot:v1",
"payload": {
"schema": "sensorium-terminal-screen-snapshot.v1",
"schema/v": 1,
"terminal.session/ref": "terminal-session:01JZEXAMPLE",
"from.seq/no": 40,
"to.seq/no": 42,
"viewport": {
"rows": 24,
"cols": 80,
"cursor.row": 3,
"cursor.col": 12,
"text": "running tests..."
},
"classification": {
"schema": "classification.v1",
"source_tier": "Personal",
"effective_tier": "Personal",
"provenance": {
"kind": "local-space",
"space": "Personal"
},
"bound_subjects": {
"personal_or_community": [
{
"kind": "nym",
"id": "nym:did:key:z6MkWorkbenchOwner"
}
]
},
"declassify_trail": []
}
},
"classification": {
"schema": "classification.v1",
"source_tier": "Personal",
"effective_tier": "Personal",
"provenance": {
"kind": "local-space",
"space": "Personal"
},
"bound_subjects": {
"personal_or_community": [
{
"kind": "nym",
"id": "nym:did:key:z6MkWorkbenchOwner"
}
]
},
"declassify_trail": []
}
}
],
"delivery/diagnostics": {
"coalesced/count": 0,
"gap/count": 0
},
"causal/context": {
"schema": "causal-context.v1",
"schema/v": 1,
"context/id": "causal-context:01K2EXAMPLE",
"correlation/id": "corr:sensorium-subscription:01K1EXAMPLE",
"operation/id": "operation:01K2EXAMPLE",
"causation/refs": ["execution-receipt:01K1EXAMPLE"],
"origin/actor-ref": "node:did:key:z6MkPublisherExample",
"created/at": "2026-07-13T12:00:02Z"
}
}
Batch and frame rules:
delivery/kindis an explicit discriminator:one-shotforbidssubscription/id, whilesubscriptionrequires it;- a subscription result requires
cursor/next; a direct one-shot result may return it for later change detection, while a carrier projection that owns the source cursor locally may omit it; cursor/afterandcursor/nextare opaque, bounded, provider-defined progress tokens bound to the interface and source generation; frames carry no second cursor and no interface-local sequence number;- for
latest-state, a cursor lets long-poll express "wait until the projected state changes" instead of repeatedly returning the same snapshot; - for
ordered-events, array order defines order inside one batch andcursor/nextadvances past the complete batch; source payloads preserve stable domain ids or digests so replaying a partially consumed batch is idempotent; frame/kindis one ofsnapshot,event,gap, orend;batch/outcomeis one ofdata,no-change, orterminal; failures use the typed error contract rather than a fourth pseudo-success outcome;- a
snapshotoreventcarries exactly one inlinepayloador oneartifact/ref, never both; - inline payloads pass the schema gate against the descriptor's
output/schema-refand byte cap before becoming typed values; - large, binary, or durable values use an Artifact Delivery pointer rather than a larger frame;
- a
gapidentifies the lost or unavailable cursor interval and the recovery action; it cannot masquerade as an empty successful batch; - a successful long-poll timeout is
batch/outcome = no-changewith an emptyframes[]; it proves the request completed but is neither a heartbeat nor a gap; - an
endcarries a typed terminal reason and no domain payload, closes the subscription, and MUST be the final frame in the final batch accepted for thatsubscription/id; batch/outcome = terminalis valid only for subscription delivery and requires exactly one finalendframe;- every value carries effective
classification.v1; the consumer may narrow but never broaden it; - when the domain payload already embeds
classification.v1, its value must be structurally equal to the frame classification; a mismatch fails closed rather than asking the carrier to choose one; - P081 context is batch metadata, never authorization. A receiving host derives a local context and preserves the accepted upstream context as evidence. Selective receipts describe read admission, delivered batches when they are external effects, and terminal transitions; the protocol does not emit a receipt or repeat full context for every frame. Adapter-owned read-next operations identify their actual carrier, such as SSE or Room projection, in correlation and operation ids.
The result contains a bounded frames[], cursor/next, a typed batch outcome,
bounded delivery diagnostics, P081 context, and retry advice. A latest-state read
normally returns one snapshot. An ordered-events read may return several events up
to both requested and host caps. A consumer advances cursor/after only after it
has accepted the complete batch; otherwise the batch may be replayed.
5. Subscription Is a Lease, Not an Infinite Promise¶
Conceptual subscription request:
{
"schema": "sensorium-interface-subscribe-request.v1",
"schema/v": 1,
"interface/id": "sensorium-interface:01K0EXAMPLE",
"cursor/after": "opaque:optional-resume-cursor",
"lease/requested-seconds": 300,
"batch": {
"frames/max": 16,
"bytes/max": 131072,
"wait/max-ms": 5000
},
"deadline/at": "2026-07-13T12:00:05Z",
"causal/context": {
"schema": "causal-context.v1",
"schema/v": 1,
"context/id": "causal-context:01K1EXAMPLE",
"correlation/id": "corr:sensorium-subscription:01K1EXAMPLE",
"operation/id": "operation:01K1EXAMPLE",
"causation/refs": [],
"origin/actor-ref": "nym:did:key:z6MkSubscriberExample",
"created/at": "2026-07-13T12:00:00Z"
}
}
The host returns a subscription id, granted lease, effective caps, starting cursor, and current state. Renewal is an explicit authorized operation. Expiry closes the subscription even if the carrier remains connected.
sensorium-interface-subscription-command.v1 carries the bound subscription/id,
an action closed to renew or close, deadline, and P081 causal context. renew
also carries lease/requested-seconds; it cannot extend beyond the descriptor,
grant, or host-policy expiry. close is idempotent. Neither operation accepts a
caller identity in its payload.
Publication state machine:
published <-> suspended
published | suspended -> withdrawn
published | suspended -> expired
There is no protocol-visible draft. Publication atomically appends the immutable
descriptor and its initial published fact. withdrawn and expired are terminal;
resuming either requires a new interface id.
Subscription state machine:
requested -> active -> closing -> closed
requested ---------------------> closed
active ------------------------> closed
The direct requested -> closed transition covers refusal. Expiry, revocation,
interface withdrawal, terminal source completion, or exhausted source failure may
close an active subscription directly. degraded is not a lifecycle state:
sensorium-interface-subscription-status.v1 carries an orthogonal
health/status = ready | degraded plus a bounded typed reason while lifecycle state
remains active. A closed status carries exactly one terminal reason.
Every transition has an actor, timestamp, reason, causal context, and immutable
execution receipt where P081 requires one. Descriptor and lifecycle facts are
durable host-owned metadata. Live frames and cursors are ephemeral unless a source
contract explicitly gives them a bounded replay window. After an end frame, the
same subscription id returns the immutable closed status and cannot become active
again.
6. Pull-Batch Is the Mandatory V1 Flow-Control Profile¶
The semantic core defines exactly one v1 delivery profile: bounded cursor-based pull or long-poll. It does not promise a permanently open lossless socket:
- the consumer requests the next batch with frame, byte, and wait caps;
- the provider returns immediately when data exists or waits only up to
wait/max-ms; - the result offers
cursor/nextas the resume point after the complete batch; - after accepting the complete batch, the next request supplies the subscription
id, that value as
cursor/after, and fresh caps; this step acknowledges progress; - no request means no producer-side accumulation beyond the declared replay or latest-state buffer.
This is natural backpressure and maps directly to the existing Interaction Broker watch contract. HTTP long-poll and authenticated peer calls expose it directly. An SSE, WSS, or Room adapter may present results as a stream, but the adapter owns a bounded loop that repeatedly calls the same read-next operation, retains the current cursor, and stops with the lease. It does not introduce provider push, a second subscription state machine, or a second recovery contract.
channel_json observer events remain source-side ingress hints from supervised
adapters to the host. They are not a Sensorium Interface egress profile. A future
acknowledged provider-to-consumer push protocol requires measured latency evidence
and a separate proposal.
The first Room projection is WSS-backed and restricted to latest-state. A shared
best-effort fan-out cannot maintain an independent ordered-event cursor for each
member. Ordered events therefore use direct pull-batch until a future carrier owns
per-consumer acknowledgement. A WSS Room pump may coalesce intermediate snapshots;
the next complete snapshot repairs presentation without pretending that a dropped
carrier event was delivered.
P070's implemented Phase 6A relocatable relay does not change that semantic boundary. Its
(relay/epoch, relay/seq-no) cursor belongs to the carrier and may replay a bounded
recent delivery or detect that the carrier window was lost. It is never the private
Sensorium source cursor. After relay failover or cursor-expired, the P082 adapter
opens or continues its host-owned source subscription and emits the current complete
latest-state snapshot; it does not claim ordered Sensorium replay.
No v1 carrier is lossless. If lossless retention is a domain requirement, the source must create an explicit durable artifact or admitted fact under its own policy.
7. Cursor, Overflow, and Diagnostics¶
The opaque cursor is intentionally batch-level. It reuses Interaction Broker source
semantics and supports provider-side coalescing, downsampling, and source-generation
changes without exposing implementation offsets. It is useful for both delivery
semantics, but with different promises: latest-state uses it only for change
detection, while ordered-events uses it for bounded replay. frame/seq and
per-frame cursors would duplicate that contract and are therefore absent in v1.
latest-state and ordered-events have different correct behavior:
| Semantics | Buffer | On pressure | Resume |
|---|---|---|---|
latest-state |
exactly one current complete snapshot per source generation | replace the prior state and increment coalesce count | return the latest snapshot; no historical replay |
ordered-events |
bounded event window | emit a typed gap or close; never silently skip | replay from cursor if retained, otherwise report cursor-expired |
For latest-state, a cursor matching the current snapshot produces no-change
until the wait bound expires or the value changes. An older cursor from the same
source generation returns the current complete snapshot. A cursor from another
source generation returns cursor-mismatch; cursor-expired is reserved for an
ordered-events replay point that has left the retained window.
Examples:
- current temperature and current terminal screen are
latest-state; - terminal lifecycle events and threshold-crossing sensor events are
ordered-events; - a high-frequency raw sample stream should usually be aggregated in its adapter and exposed as latest state or bounded summaries, not pushed through Agora or Room as every raw sample.
Overflow policy remains explicit rather than using an ambiguous gap-or-close:
coalesce-latest is valid only for latest state; emit-gap and
close-subscription are valid only for ordered events. The descriptor fixes the
choice so two implementations cannot react differently to the same pressure.
Each read result carries bounded source diagnostics such as coalesced/count and
gap/count. Carrier adapters separately expose operator counters for queue depth,
dropped/count, and last-drop/at, because a drop after result creation is not a
source fact and must not be forged into the batch. Diagnostics contain counts,
timestamps, and typed reasons, never payload fragments or subject identities.
8. Authorization and Caller Binding Stay Above Transport¶
Authorization uses the authenticated caller established by the host, never an id from the request body, URL, Matrix sender, or Room frame.
Local access:
- a supervised module receives a host-owned capability grant bound to its module identity;
channel_jsonsession attachment authenticates the module process but grants no Sensorium capability by itself;- an operator control token authorizes only the operator surfaces defined by local policy, not arbitrary participant or remote-subject impersonation.
Cross-node access:
- a signed Capability Passport or equivalent source-authorized grant binds the
remote subject, capability id,
interface/id, operations, expiry, classification ceiling, and rate/volume caps; - the source node verifies current issuer authority, signature, revocation, participant restrictions, and local egress policy at admission and re-checks revocation at every bounded batch;
- a Passport does not make the interface globally discoverable and does not bypass source-side policy.
Room access:
- current Room membership and the
observeright are necessary but not sufficient; - the caller must also hold an interface-scoped grant;
RoomLiveTransport::subscribe(room_id)is a carrier call and must occur only after host authorization;- member removal updates the pump's authorized recipient set before the next batch emission and prevents further projection to that subject; the pump's source lease remains host-owned until Room/session closure or the recipient set becomes empty;
- until Proposal 075 P075-011 provides Matrix-side kick/ban, Matrix-backed Room live transport must not carry private or high-sensitivity interfaces for which a stale Matrix member could continue receiving frames.
Session-delegated collaboration grants may be minted only inside a source-operator pre-authorization envelope. Such a grant binds the interface, collaboration/session, allowed member set or membership predicate, classification ceiling, limits, and expiry. Room creation or Agent participation never self-authorizes an interface.
9. Classification and Redaction Apply Before Carrier Selection¶
An interface is an egress surface even when the carrier is local. The source projection computes effective classification and redaction before any frame enters a carrier queue.
Required rules:
- the descriptor defines a maximum classification ceiling and redaction profile;
- the descriptor carries a stable bounded
classification/topic-classused to bind any interface-specific declassification authority; - each frame carries the actual effective
classification.v1value; - the grant may narrow the ceiling but cannot widen the descriptor or source value;
- terminal sharing defaults to the bounded visible viewport snapshot; a full transcript requires the existing explicit classified capture path;
- invasive connectors retain their existing active-status, consent, and UI visibility preconditions;
- a carrier adapter never strips, rewrites, or infers classification;
- redaction or transformation evidence alone never lowers
effective_tier; - public projection must satisfy
bound_subjectspublic-projection rules before serialization; - wider-than-federation exposure follows the escalation discipline in Swarm Communication Exposure Modes, not a transport shortcut.
Interface Is a P047 Declassification Surface¶
Before the P082 schemas are frozen, Proposal 047 and the shared classification core
MUST extend the closed DeclassifyFact.surface vocabulary with wire value
interface (Surface::Interface in the Rust projection). Reusing bus, export,
or the selected carrier surface would couple classification authority to transport
and would let an act intended for another boundary authorize an interface
accidentally.
An emitted frame may carry effective_tier lower than source_tier only when its
trail contains a currently valid DeclassifyFact whose:
surfaceisinterface;topic_classequals the immutable descriptor'sclassification/topic-class;- subject, step, mode, expiry, revocation, and one-shot consumption satisfy P047;
- caller and capability evidence pass the existing
memarium.declassifygate.
The interface guard re-evaluates that fact for every bounded batch before carrier
selection. A fact for Agora, Whisper, INAC, export, or bus does not match. Without a
matching interface fact, the frame keeps effective_tier = source_tier; a redaction
profile may still remove content, but it cannot silently declassify it.
10. Retention and Capture Are Separate Decisions¶
Watching a stream does not archive it. Interface runtime persists only:
- descriptor and private source binding;
- grants and revocations;
- subscription lifecycle facts;
- bounded counters and terminal diagnostics;
- P081 execution receipts and references to domain outcomes.
Payload frames remain ephemeral unless the source domain already retains them for a declared replay window. Explicit capture follows an existing domain path:
- Workbench creates a classified capture artifact;
- Sensorium admits a selected observation or summary;
- Artifact Delivery moves a large immutable value by reference;
- Memarium admission is a separate, auditable policy decision.
The read-only interface cannot silently turn observation into durable capture.
Carrier Adapters¶
The contract family is transport-neutral, but the first implementation is staged so the adapter inventory does not become the acceptance scope accidentally.
| Surface | Role | V1 posture | Important boundary |
|---|---|---|---|
| host capability call | local read and pull-batch | core | authenticated module/actor binding comes from the host |
| authenticated peer session | direct node-to-node read and pull-batch | core remote | remote context and actor claims remain evidence until locally bound |
| HTTP long-poll or SSE | local UI projection | thin V1 adapter | adapter loops over read-next; SSE is not a second protocol |
| WSS-backed Room | collaborative latest-state fan-out | first live adapter; relocatable relay is post-MVP P070 work | membership plus interface grant; ordered events are refused; relay cursor never exposes source cursor |
| Matrix-backed Room | optional Room bridge | deferred for private/high-sensitivity data | requires P075-011 carrier-side eviction before sensitive use and imports no Matrix history/state semantics |
channel_json RPC |
supervised middleware caller | reuse when needed | invokes the same host capability dispatch; attachment grants no interface authority |
channel_json event |
source-side ingress hint | not an interface carrier | drop-and-count belongs to observation admission diagnostics |
| Artifact Delivery | large immutable payload indirection | reuse by reference | not a stream and not interface authority |
For WSS-backed Room, the payload is the canonical JSON serialization of one
sensorium-interface-read-result.v1 under the registered content type
application/vnd.orbiplex.sensorium-interface-read-result+json. The pump projects
its internal subscription result as delivery/kind = one-shot and omits the source
subscription/id and cursor. Room sequence numbers remain carrier sequence. Room
consumers neither observe nor advance the host-owned source cursor.
The pump does not rewrite a source batch/outcome = terminal into a one-shot
terminal result, because that would violate the read-result discriminator. Instead,
it closes the dedicated interface-projection carrier session with the bounded typed
terminal reason from the source subscription. The durable Room remains open. A
no-change batch keeps the projection session open, so consumers distinguish
quiescence from termination by carrier-session closure. Reopening the view creates a
new source subscription. A Room carrier that cannot close only the projection
session MUST fail readiness rather than stop emitting silently or close an unrelated
Room.
Vendor Media Type Registration¶
The repository already uses Orbiplex vendor media types for Inquirium transcript
facts and Sensorium virtual-environment exports, so this is not the first
application/vnd.orbiplex.* value. It is, however, the point at which their naming
must stop being ad hoc.
Before the first P082 carrier ships, Protocol ownership MUST provide one checked-in, machine-validated vendor media-type inventory. Each entry binds a unique media type to a schema ref, encoding, and owning proposal/component. The initial P082 entry is:
application/vnd.orbiplex.sensorium-interface-read-result+json
schema/ref: urn:orbiplex:schema:sensorium-interface-read-result:v1
encoding: canonical-json
owner/ref: P082
This inventory is build-time protocol data, not network authority and not a ninth Sensorium envelope. Duplicate names or one name bound to multiple schemas fail validation. Existing Orbiplex vendor media types should be backfilled into the same inventory rather than preserved as parallel conventions.
Host-Owned Runtime Reuse¶
Interaction Broker¶
Use Interaction Broker probe/watch as the first read and subscription engine. It already owns source-bound opaque cursors, event and byte caps, deadlines, wait/watch lifecycle, replay bounds, and source-provider dispatch. Sensorium Interfaces should add a source provider and projection policy, not another watch registry. The broker owns bounded source reads; the interface runtime owns publication and subscription authority. Their states are composed rather than copied.
Replay Scheduler¶
Use Replay Scheduler only when the underlying adapter is pull-only and the host must periodically enact a new observation. The scheduled job invokes a bounded adapter operation and submits the result through Sensorium admission. It does not own subscriptions and does not write interface frames directly.
Bounded Deferred Operations¶
Use Bounded Deferred Operations for publication, remote subscription setup, capture, or cleanup that may legitimately outlive one request. Do not create one deferred operation per frame. A subscription is its own leased state machine, while a deferred operation may own a bounded transition that creates or closes it.
channel_json¶
Use channel_json for supervised adapter-to-host observation events and
host-to-module bounded calls. Its outer frame is executor transport, not the
Sensorium Interface domain envelope. Embedded payloads remain schema-gated. Observer
queue loss must surface as source-ingress diagnostics and must not be mistaken for
an ordered interface stream or repaired by inventing an interface cursor.
Artifact Delivery¶
Use Artifact Delivery for values that exceed inline caps, require asynchronous delivery, or must be immutable and independently admitted. The interface frame carries an artifact ref and classification, while Artifact Delivery retains route, transport, and recipient admission semantics.
The implemented artifact-snapshot adapter accepts only a read-only
latest-state interface bound to an admitted artifact-object-pointer.v1. Each
read pins the requested admission id to the returned accepted admission record,
requires its artifact ref, and includes the admission schema, digest, receipt time,
and source generation in cursor change detection. The interface publisher supplies
the explicit frame classification, which is still checked against descriptor and
current declassification constraints; the interface frame does not grant Artifact
Delivery fetch authority. The private admission id is selected by the local
sensorium.interface.manage publisher, not supplied by a reader. Publication is
therefore an explicit local reprojection of an accepted pointer; Artifact Delivery
does not need a second admission-to-interface binding, while consumers still need
the exact interface grant and separate Artifact Delivery fetch authority where
dereferencing is allowed.
Temporal Storage and P081¶
Append publication, grant, subscription, revocation, and terminal facts through the Temporal Storage Convention. Use canonical P081 contexts and selective receipts at authority boundaries, delivered result batches when they are external effects, retries/cancellations, and terminal states. Do not create a global interface event log, per-frame receipt stream, or duplicate source-domain facts.
End-to-End Examples¶
Temperature Sensor: On Demand¶
1. A supervised adapter reads the physical sensor through its connector.
2. The adapter submits a bounded sensorium-observation.v1 through channel_json.
3. Sensorium Core validates, classifies, and admits the observation.
4. The source operator publishes a latest-state interface bound to that query.
5. An authenticated consumer calls sensorium.interface.read with interface id,
deadline, and caps.
6. The host verifies the resource-scoped grant and egress policy.
7. The interface provider queries Sensorium Core and returns one classified result
batch.
8. The host appends the selective P081 receipt and returns the result.
No remote party calls the sensor connector. If the sample is stale, the response contains freshness and a typed stale/source-unavailable outcome according to source policy; it does not silently perform unbounded external work.
Temperature Sensor: Continuous Updates¶
1. A push-capable adapter emits observation candidates as values change and
Sensorium admits them; or a Replay Scheduler job polls a pull-only sensor at a
bounded interval and submits each candidate through the same admission path.
2. The interface projection coalesces observations into latest state.
3. The consumer creates a five-minute pull-batch subscription.
4. Repeated bounded long-polls return only new snapshots and batch cursor progress.
5. A local SSE adapter owns that read-next loop and projects each result batch as an
SSE event; a peer session can expose the pull contract directly.
6. Missing demand causes no unbounded queue; the provider retains only latest state.
7. Expiry or revocation closes the subscription and emits a terminal receipt.
Workbench Terminal: Collaborative Live View¶
1. Workbench owns the PTY and produces bounded screen snapshots.
2. The operator publishes a latest-state interface for the visible viewport only.
3. A collaboration session instantiates temporary interface grants for authorized
Room members inside the operator's pre-authorized envelope.
4. Interaction Broker watches the Workbench terminal provider with bounded caps.
5. One bounded WSS Room pump repeatedly pulls the latest-state interface and
projects each batch as a cursor-free one-shot result in room-live-message.v1.
6. Slow consumers receive coalesced current screen state, not an unbounded backlog.
7. Reconnect receives the next complete snapshot emitted by the pump; Room members
do not own the pump's source cursor.
8. Member removal revokes that member's projected access. The host-owned pump closes
when its source subscription terminates, the Room/session ends, or no authorized
recipients remain. Source termination closes the dedicated projection carrier
session without closing the durable Room; carrier eviction follows independently.
Keyboard input is not sent through this observation stream. It remains a separately
authorized sensorium-workbench-tool-request.v1 directive in the implemented V1
path. Proposal 083 preserves that
observation/action boundary while defining a future, separately granted and fenced
actuation interface for collaborative terminal control.
Error Contract¶
This proposal freezes a small transport-neutral error vocabulary:
| Code | Meaning | Retry posture |
|---|---|---|
interface/not-found |
resource absent or leak-minimal unauthorized lookup | no, unless descriptor may appear later |
interface/not-published |
suspended, withdrawn, or expired | no until state changes |
interface/unauthorized |
bound caller lacks current scoped authority | no without new authority |
interface/classification-denied |
egress or grant ceiling refuses the value | no without narrower projection/policy change |
interface/source-unavailable |
provider is unavailable or not ready | bounded retry with backoff |
interface/deadline-exceeded |
read/watch exceeded caller or host deadline | retryable when policy allows |
interface/cursor-expired |
requested replay point is outside retention | request a fresh snapshot or close |
interface/cursor-mismatch |
cursor belongs to another interface/source epoch | no; caller must discard cursor |
interface/overloaded |
bounded admission or worker capacity is full | retry after supplied delay |
interface/schema-mismatch |
provider output violates declared schema | no automatic retry; operator fault |
interface/operational-context-invalid |
required context is absent, malformed, or oversized | no automatic retry; repair or replace the publication |
interface/operational-context-stale |
the current source context differs from the immutable descriptor or request | resolve and authorize a replacement publication; never reuse the old result |
interface/source-generation-mismatch |
the current source generation differs from the descriptor, request, or result | resolve the current generation and replacement publication; never reuse the old result |
interface/superseded |
a newer immutable publication replaced this interface/id in its source slot |
resolve and authorize replacement/interface-id; do not retry against the old id |
interface/revoked |
grant or collaboration authority was withdrawn | no without new grant |
interface/subscription-closed |
the lease is terminal and its immutable status is available | no; create a new subscription when authorized |
These detailed reasons are internal machine and audit vocabulary. A remote boundary
may project not-published, operational-context-stale,
source-generation-mismatch, or superseded to not-found, and
classification-denied or revoked to unauthorized, when disclosure would reveal
protected state. The trace retains the detailed local reason. Carrier failures are
normalized separately and never replace domain errors.
Trade-offs¶
- Pull-batch is less visually immediate than a raw firehose, but it provides natural backpressure, cursor recovery, and transport portability. SSE or WSS Room can restore low-latency presentation through an adapter-owned pull loop without changing the core contract.
- A provider-defined opaque cursor is less transparent than a numeric sequence, but it directly reuses Interaction Broker, supports aggregation and source epochs, and eliminates per-frame delivery counters.
- One interface per projected meaning creates more descriptors, but avoids optional mode matrices and permits precise grants and classification. UI may group related interfaces without turning that grouping into authority or a multi-output wire contract.
- Explicit publication and grants add operator work, but make observation visible, revocable, auditable, and explainable.
- Descriptor immutability includes
expires/at. Extending an interface therefore publishes a newinterface/id, invalidates the old subscriptions, and requires fresh grants. This creates deliberate identity churn and operator work, but prevents routine renewal from becoming an invisible path to indefinite observation. A future stable-id renewal profile would require a separate bounded lease contract and must not be smuggled in as descriptor mutation. - Best-effort live carriers cannot promise lossless delivery. The alternative would be a durable event platform whose retention and authority semantics are far larger than this feature.
- Reusing Interaction Broker may require one new source variant and provider adapter, but avoids a second cursor, watch, and timeout subsystem.
Failure Modes and Mitigations¶
| Failure mode | Consequence | Mitigation |
|---|---|---|
| Interface id treated as a secret bearer token | unauthorized observation | authenticated caller binding plus resource-scoped authorization |
| Connector exposed directly | policy and classification bypass | host-private source binding and provider-only access |
| Capability id minted per sensor | registry explosion and coupled policy | generic operation capabilities scoped to interface resources |
| Room or Matrix membership treated as authority | carrier controls access | host checks current Room and interface grants before subscription |
| Slow consumer creates unbounded backlog | memory exhaustion and stale view | pull-batch default, explicit caps, coalesce/gap/close policy |
| Carrier projection treated as a second stream protocol | divergent lifecycle and recovery | adapter owns one bounded loop over canonical read-next |
| P047 declassification for another surface reused by an interface | unintended disclosure | require surface = interface and exact descriptor topic-class binding per batch |
sensorium.read.local treated as caller authority |
source-policy bypass or duplicate grants | keep it inside the Sensorium source adapter and compose it with interface authorization |
| Room pump stops without a terminal signal | consumers confuse termination with quiescence | close only the dedicated projection carrier session with a typed reason |
| Vendor media type coined ad hoc | incompatible carrier dispatch | validate one checked-in unique media-type inventory |
Source observation event dropped in channel_json |
stale admitted source view | source-ingress drop counter and freshness diagnostics; no forged delivery gap |
| Cursor reused after source restart | wrong replay or reordered data | bind opaque cursor to interface and source generation |
| Operational context is absent, malformed, or oversized on a collaborative-live or Workbench-backed interface | agents reason about a live system without a reliable caution baseline | require a valid sensorium-operational-context.v1 value before publication, enforce the 512-byte summary cap, and fail resolution closed |
| Descriptor, source, and read-result operational contexts disagree | a lower-impact label can be substituted after publication | bind the value to the immutable resource generation, repeat it in exact read results, and permit the host to raise but never lower the current source class |
| Source generation or impact changes while an old publication remains live | consumers continue under obsolete operational assumptions | treat generation mismatch or slot supersession as stale; serialize replacement, close old subscriptions, and refuse the old interface |
| Publisher-controlled context summary is treated as an instruction | remote prompt injection through descriptive metadata | keep the summary bounded and inert; derive privileged caution text only from the closed impact class through host-owned P064 policy |
| Revocation described as retracting old data | false safety guarantee | stop only future emissions; document delivered-data boundary |
| Stream silently becomes durable | privacy and retention drift | explicit capture/admission operation only |
| Large frame blocks shared transport | head-of-line pressure | strict inline cap and Artifact Delivery ref |
| Interface runtime duplicates domain store | divergent facts | retain only descriptor/lifecycle metadata; source domain owns values |
| Adapter-specific code accumulates in daemon | closed and fragile architecture | one interface provider registry and source-specific adapters |
Implementation Strata¶
protocol contracts
immutable descriptor, interface/subscription status, read result batches,
subscribe/command requests, frames, typed errors
sensorium-interface core
pure validation, lifecycle transitions, batch cursor/source binding,
delivery-policy decisions, classification no-broadening checks
domain source adapters
Sensorium observation query, Workbench terminal screen/events,
Artifact snapshot; no transport knowledge
host runtime
authenticated caller binding, grant verification, provider registry,
Interaction Broker composition, lease state, temporal facts, receipts
carrier adapters
host capability and peer pull-batch; HTTP/SSE and WSS Room projections;
channel_json source ingress and AD payload indirection; no domain authority
UI and operator surfaces
publish/suspend/withdraw, grant/revoke, list active subscriptions,
inspect bounds, gaps, drops, and terminal reasons
The schema gate validates ingress and egress contracts. The pure core must not depend on daemon, HTTP, WebSocket, Matrix, SQLite, async runtime, or a concrete Sensorium provider. Runtime stores may use SQLite/Temporal Storage, but the protocol does not encode that choice.
Named Acceptance Invariants¶
inv-sif-single-delivery-contract: providers expose only bounded read-next; SSE, WSS, and Room presentation is implemented by adapter-owned pull loops, not a second push protocol.inv-sif-batch-cursor-only: only requests and result batches carry interface cursors; frames carry neither a cursor nor an interface-local sequence number.inv-sif-cursor-not-authority: cursor possession without an authenticated caller, matching interface, live lease where required, and current grant is refused.inv-sif-end-is-terminal:endis the final frame of the final batch; the subscription remains closed and returns its immutable terminal status afterward.inv-sif-latest-state-has-no-replay: alatest-statedescriptor rejects replay bounds, retains one current complete snapshot, and uses its cursor only for change detection.inv-sif-classification-match: every emitted frame carriesclassification.v1; when its payload also embeds the label, the two values are structurally equal.inv-sif-interface-declassification-only: a frame whose effective tier is lower than its source tier has a currently valid P047 fact bound tosurface = interfaceand the descriptor's exact classification topic class.inv-sif-source-policy-composes:sensorium.read.localsource admission and interface caller authorization are both required for an observation-query source; neither grant satisfies the other.inv-sif-independent-byte-caps: every frame satisfiesframe/max-bytesand every complete result satisfiesbatch/max-bytes; neither cap is inferred from the other.inv-sif-carrier-not-authority: transport attachment, Room membership, Matrix identity, and interface id possession never replace resource-scoped admission.inv-sif-room-v1-latest-state-only: the first WSS Room adapter refusesordered-eventsinterfaces and never exposes a per-member source cursor.inv-sif-room-terminal-visible: source subscription termination closes the dedicated Room projection carrier session with a typed reason;no-changedoes not close it, and the durable Room is not closed as a side effect.inv-sif-revocation-lag-bounded: revocation prevents new source reads and carrier emission within configured local pull-loop and peer revocation-freshness budgets, without claiming that revoke transaction duration measures that lag or that previously delivered data can be erased.inv-sif-registered-media-type: every Orbiplex vendor media type used by a P082 carrier has one unique checked-in binding to its schema and encoding.inv-sif-source-adapter-open: source-specific validation and batch production live behind the bounded adapter registry; persisted bindings are revalidated on every read, and an unknown or unavailable adapter cannot be bypassed after restart.inv-sif-operator-evidence-bounded: read metrics use only bounded source-kind, carrier, and delivery-kind dimensions; flat revoke-commit and resource-count metrics never carry caller, grant, subscription, or interface ids.inv-sif-operational-context-monotone(P082-021): every publication carries one exact operational-context value; source, descriptor, and result agree, while host policy and downstream consumers may only raise the current source caution class.inv-sif-operational-context-current(P082-021): a context-bearing result is admissible only while its source generation is current and itsinterface/idis the effective publication for the host-private source/projection/direction slot; replacement makes old results stale without relying on clock age.
Frozen Initial Decisions¶
The design questions are resolved as of 2026-07-17. Decisions 1-6 freeze the V1 baseline; decisions 7-10 close the evidence-gated follow-up review:
- P082 is the dedicated home for Sensorium Interface semantics; P045 retains local Sensorium admission and actuation.
- Implementation order is authenticated direct pull-batch, then local SSE and WSS-backed Room latest-state projection. Provider push is not a V1 protocol.
- Cross-node authority reuses Capability Passport with interface-specific scope;
for direct pull,
node_idnames the authenticated remote consumer andissuer/node_idnames the local source node. Local grants remain host-owned runtime facts. - Remote descriptors are disclosed only through a direct grant/invitation or an authorized collaboration context. There is no federation-wide catalog in V1.
- Every frame carries
classification.v1; a payload copy, when present, is structurally equal. Generic carriers do not learn schema-specific JSON pointers. - V1 has one source-local
sensorium.interface.managecapability with action-specific policy and distinct publish/grant/revoke/withdraw facts. It is never remotely delegated. - Bounded pull-batch remains the only data-delivery protocol. No separately acknowledged provider-push or push-hint profile is added. If operational evidence later justifies readiness hints, P082 data readiness and P083 claim readiness must reuse one authority-neutral, disclosure-bounded notification substrate rather than define two push mechanisms. Each hint audience must pass the same current grant and applicable collaboration-policy checks as the corresponding read or claim; a hint neither confers authority nor reveals resource activity to an unauthorized recipient.
- There is no searchable descriptor catalog. Listing resources already disclosed by
the caller's own current grants, invitations, or collaboration context is
authority inspection, not existence discovery, and must preserve leak-minimal
not-foundbehavior. A searchable inventory that reveals otherwise undisclosed resources is a separate disclosure oracle and requires a new decision. sensorium.interface.manageremains one source-local, non-delegable capability. Current runtime dispatch and capability-authorization policy enumerate the closed observation and P083 actuation action vocabulary, includingcontrol.preempt; wildcard or capability-only admission cannot acquire preemption authority.- Operational impact is source-owned, host-validated metadata on the exact enacted
resource. It is ordered
research < experimental < test < production < critical, is separate from classification and authority, and reaches consumers through the existing descriptor/result contracts rather than a Room-, Corpus-, Agent-, or Inquirium-owned field. A consuming host may raise but never lower the current source declaration. Freshness is determined only by current source generation plus the current effective publication for the source/projection/direction slot. Source-side correction uses audited immutable replacement;context/summaryis optional inert text capped at 512 UTF-8 bytes.
Implementation Tracker¶
| Id | Work item | Status | Acceptance boundary |
|---|---|---|---|
| P082-001 | Freeze the proposal architecture, V1 decisions, bounds, named invariants, and implementation order | done | This document records the frozen resource/capability split, one pull-batch contract, direct-only descriptor disclosure, Passport reuse, classification placement, and local management posture. |
| P082-002 | Extend P047 and the shared classification core with Surface::Interface plus exact descriptor topic-class matching |
done | orbiplex-node-classification implements Surface::Interface; tests reject other surfaces, topic mismatch, expiry, revocation, and consumed one-shot facts. |
| P082-003 | Freeze descriptor/interface-status, read request/result, subscribe request/status/command, frame schemas, and typed errors | done | Eight closed schemas plus core semantic validation cover terminal, latest-state no-replay, ordered replay bounds, byte caps, classification equality, conflicting frame payload sources, and unknown-field refusal. |
| P082-004 | Register read, subscribe, and local manage with the exact flags and authorization-policy posture frozen above |
done | Machine registry, Rust constants, policy sidecar, and human registry agree; only read/subscribe are Passport-eligible and generic advertisement exposes no descriptor. |
| P082-005 | Seed a shared checked-in Orbiplex vendor media-type inventory and register the P082 read-result type | done | vendor-media-types.v1 binds the P082 read-result media type uniquely and is validated by protocol/schema-gate tests. |
| P082-006 | Implement the pure lifecycle, batch-cursor binding, delivery-policy, classification, and limit core | done | sensorium-interface-core has no daemon, transport, SQLite, async-runtime, or concrete provider dependency and proves the named semantic invariants. |
| P082-007 | Add schema-gate families and positive/negative fixtures | done | Schema-gate embeds all eight schemas and validates positive, cross-field-negative, and unsupported-boundary fixtures. |
| P082-008 | Add one Sensorium Interface source to Interaction Broker and its provider registry | done | The daemon registers the sensorium-interface source kind and reuses broker watch cursors, deadlines, and caps. |
| P082-009 | Adapt admitted Sensorium observations with conjunctive sensorium.read.local and interface authority checks |
done | Sensorium observation binding preserves source admission and independently checks interface authority; temperature one-shot and subscription tests pass. |
| P082-010 | Adapt Workbench terminal screen snapshots and ordered event batches | done | Workbench screen latest-state and terminal ordered-events are separate source bindings with separate descriptor semantics. |
| P082-011 | Add host publication, grant, subscription, revocation, and inspection surfaces | done | The daemon runtime persists immutable management facts, idempotency, grants, subscriptions, terminal states, and restart-rebuildable projections. Grants require canonical namespaced grantee refs; cursor advancement is serialized per subscription, while independent subscriptions may read concurrently; verified Passport admission is one immediate atomic transaction with explicit revoked-replay diagnostics. |
| P082-012 | Add local host-capability and authenticated direct-peer pull-batch surfaces | done | Host dispatch and peer message-chain tests verify caller binding, signed sensorium-interface@v1 Passport scope, exact remote target and local source issuer, resource limits, and current revocation. |
| P082-013 | Add local SSE and WSS-backed Room latest-state adapters | done | Loopback module-authenticated SSE and WSS Room projection use adapter-owned read-next loops with carrier-specific causal ids, current grant checks, typed close, ordered-event refusal, and no durable Room close. Room recipients match canonical stable subject keys only; the adapter caps active pumps at 64 and reaps terminal pump and carrier state together. Pump intent is process-local: a source-host restart requires the local authority to recreate the projection, while recipient restart refreshes from the relay's bounded current-state view. |
| P082-014 | Add named-invariant tests plus temperature and Workbench end-to-end acceptance flows | done | Focused core/runtime tests cover temperature one-shot and continuous flows, restart, revocation, concurrent and revoked Passport replay, canonical grantee refs, tier-vocabulary alignment, frame schema negatives, carrier-specific traces, and subscription lock isolation; peer, SSE, and real WSS tests cover signed remote target binding and collaborative terminal view. |
| P082-015 | Synchronize P024, P042, P045, P047, P066, P070, P071, P072, P075, P080, P081, Solutions 030/035/042, Node ledgers, and applicable readiness tracking | done | Solution 046 owns the implemented boundary. P024/P045/P047/P069/P070/P071/P072/P081 and Solutions 030/035/036/042 carry the applicable explicit cross-links; P042/P066/P075/P080 were reviewed and retain non-competing owner semantics. Node MVP/implementation ledgers, capability registries, generated solution/schema views, and the readiness snapshot are synchronized. |
| P082-016 | Replace the closed source-binding enum with an open, bounded source-adapter registry and migrate the Sensorium and Workbench adapters | done | Generic host-private bindings are shape-bounded and revalidated after restart; duplicate, unknown, unready, and excess adapters fail closed, daemon startup requires all four built-ins, and point-in-time readiness never replaces authoritative next_batch refusal. |
| P082-017 | Add the Artifact Delivery-backed immutable snapshot adapter | done | artifact-snapshot emits only an accepted artifact-object-pointer.v1 ref through a read-only latest-state interface, pins admission identity, redacts AD-host failures, preserves classification checks, and uses stable digest-bound cursor change detection; local manage authority deliberately selects the private admission binding. |
| P082-018 | Expose bounded operator evidence for source readiness, carrier reads, occupancy, no-change, errors, active leases, Room pumps, and local revoke commit duration | done | The host-local manage metrics action reports no actor, interface, grant, or subscription identifiers; read dimensions are capped by 64 registered source kinds, four carrier classes, and two delivery kinds, while revoke-commit-us remains flat. Source-registry, active-subscription, metric-accumulator, and Room failures degrade independently; counters are process-local and reset on restart. |
| P082-019 | Add and run the host/direct-peer/SSE/Room conformance and load harness, then synchronize solution and readiness artifacts | done | node:tools/conformance/sensorium_interfaces_conformance.py prebuilds daemon/core plus the required Workbench contract bridge with a separate build timeout, uses exact full Rust test names with one test thread, fails fast by default, distinguishes build/test timeouts and unrecognized libtest output, emits only output digests on failure, and now extends the original bounded host, signed peer, SSE, and Room observation checks with the P083 load, restart, partial-failure, Room baton, and real Workbench PTY matrix. |
| P082-020 | Make the Room latest-state adapter relay-epoch-aware after P070 Phase 6A | done | An active Room projection publishes one schema-gated sensorium-interface-read-result.v1 containing a single inline cursor-free latest-state snapshot into the current bounded relay epoch after rechecking Room and interface authority. Reconnect uses only (relay/epoch, relay/seq-no) carrier state, never a source cursor; epoch change or expired replay yields a typed refresh boundary and a fresh subscription returns the current bounded latest-state view. Relay publication failure closes the pump and records a payload-free degraded reason. The resource-bound result is also the ingress unit for the bounded Room Sensorium Interface Broker source consumed by Story 012's daemon-owned resolver. agent-core carries only an opaque observation source ref, generic bounds, and the horizontal P081 causal context preserved from the read result; it has no Sensorium Interface or Room semantics. |
| P082-021 | Add operational-impact publication and propagation for enacted resources | done | sensorium-operational-context.v1 is schema-gated with a 512-byte UTF-8 summary cap and is universally required beside source/generation-ref in the common resource, observation descriptors, and read results; the proposed wire-optional rollout was not used. P083 reuses the same pair in actuation descriptors, statuses, invoke admission, and receipts. The observation lifecycle status remains a metadata-only publication signal rather than duplicating the descriptor context. The daemon maintains one current publication per normalized source/projection/direction slot, serializes immutable replacement with actuation and read admission, requires a bounded trimmed replacement reason, withdraws the prior publication, closes its subscriptions, and returns typed invalid-context, generation-mismatch, and superseded-publication failures without a TTL heuristic. Host policy can only raise the class while preserving source-owned summary provenance. Bounded operator inspection exposes replacement reasons and counts. Core, schema-gate, runtime race, multibyte, stale-generation, supersession, terminal relay-ordering, and Story 012 tests cover the positive and refusal paths. |
Open Questions¶
No unresolved design questions remain. The former provider-push, descriptor-catalog, and management-capability questions are resolved by decisions 7-9. Any later change requires operational evidence and an explicit contract revision.
Next Actions¶
- Collect representative local and federated snapshots from the implemented
metricsaction and compare read-next latency, occupancy, and no-change rate by carrier, delivery kind, and source kind. Inspect the flatrevoke-commit-uscost separately; measure end-to-end enforcement at carrier and peer authority boundaries rather than inferring it from durable-write latency. - Add another producer adapter only through the implemented source-provider and classification contracts.
- Keep pull-batch, direct disclosure, and one source-local manage capability as the baseline. Treat any future push, existence-discovery, or authority-split proposal as an explicit contract revision with operational evidence.
- Collect relay latency, cursor-expiry, and failover evidence through P070 Phase 6A; do not add an Interface-specific relay, membership service, or failover protocol.