Skip to content

Neuromodulators Contract

This reference describes the target Neuromodulators runtime boundary: the mediation layer where RAS sends signals and receives replies, plus the later runtime collection where synthesized modulator instances are stored for retrieval.

The currently implemented work in this area is the orchestrator mediation flow. The registry and direct artifact lookup API are documented here as the future boundary they are meant to support.

Neuromodulators is the domain name of the registry. Avoid technical alternatives such as service-oriented naming.

Implementation invariant: ModulatorRelay is a boundary wrapper around a dedicated NeuralRelay instance. The wrapper defines neuromodulator-specific interfaces, while transport behavior remains standard NeuralRelay routing.

Neuromodulators exists to separate two concerns:

  1. Mediation boundary between RAS and synthesizers over NeuralRelay.
  2. In-process runtime object handoff using artifact-ref pointers.

A ModulatorResult carries the outcome of synthesis transmissions, and a successful child result carries an artifact-ref pointer rather than the object instance itself. RAS dereferences that pointer in Neuromodulators.

These defaults are normative unless a future contract explicitly overrides them.

  1. All communication across this boundary MUST traverse NeuralRelay channels.
  2. Modulation traffic is asynchronous and transmission-driven; the boundary delegates and reacts instead of synchronous waiting.
  3. Broadcast fanout has a null default outcome per receiver unless that receiver takes explicit action.
  4. Silent synthesizers are expected by default and MUST NOT be treated as errors.
  5. A result is emitted only when an explicit action produces a transmission.

Canonical format:

  • neuromodulators/{artifact-key}

Rules:

  1. artifact-key MUST be unique within the active runtime scope.
  2. Producers MAY choose deterministic or random keys.
  3. Consumers MUST treat artifact-ref as opaque and MUST NOT infer subtype semantics from key fragments.

Each stored modulator artifact SHOULD be modeled with an explicit lifecycle state:

  1. published: artifact was added and is resolvable.
  2. consumed: artifact was resolved at least once by RAS.
  3. expired: artifact retention window elapsed and it is no longer resolvable.
  4. removed: artifact was explicitly deleted by policy or cleanup.

State invariants:

  1. published must transition only to consumed, expired, or removed.
  2. consumed may remain resolvable or transition to expired or removed based on retention policy.
  3. expired and removed are terminal for resolution purposes.

These methods describe the future public boundary around the orchestrator flow.

RAS uses this interface to submit a single modulator signal, consume explicit synthesis outcomes when they are emitted, and resolve the resulting artifact.

from typing import Protocol
class NeuromodulatorsForRAS(Protocol):
def signal(self, signal: "ModulatorSignal") -> None:
"""
Accept a single modulator signal from RAS, fan out to registered synthesizers,
and delegate on asynchronous relay channels.
"""
def subscribe_results(self, handler: "ModulatorResultHandler") -> None:
"""
Subscribe to explicit modulation outcome transmissions emitted by Neuromodulators.
"""
def get(self, artifact_ref: str) -> "Modulator":
"""
Resolve an artifact-ref to a concrete modulator instance.
Raises:
KeyError (or domain equivalent) when the artifact-ref cannot be resolved.
"""
def remove(self, artifact_ref: str) -> None:
"""
Remove a previously published modulator instance when retention policy requires cleanup.
"""

Behavior requirements:

  1. signal MUST preserve link correlation across the originating signal and subsequent synthesis outcomes.
  2. Emitted results MUST be resolvable through get when the synthesizer succeeds.
  3. signal MUST ignore silent synthesizers and MUST NOT require every registered synthesizer to reply.
  4. signal MUST treat null broadcast outcomes as default and MUST react only to explicit reply transmissions.
  5. get MUST return the same concrete object instance published by synthesizer add.
  6. get MUST fail clearly for missing, malformed, or expired references.
  7. remove SHOULD be idempotent.

Optional policy extension:

  1. get MAY support a consume-on-read policy that transitions published to consumed atomically.

These methods describe the future synthesizer-side registry boundary.

Synthesizers use this interface to publish produced modulators.

from typing import Protocol
class NeuromodulatorsForSynthesizer(Protocol):
def add(self, artifact_key: str, modulator: "Modulator") -> str:
"""
Store a concrete modulator instance and return its artifact-ref.
Returns:
A stable pointer in the form "neuromodulators/{artifact_key}".
"""
def register_synthesizer(self, synthesizer: "Synthesizer") -> None:
"""
Register a synthesizer for signal fanout.
"""

Behavior requirements:

  1. add MUST store the exact runtime instance passed by the synthesizer.
  2. add MUST return an artifact-ref that RAS can resolve later in the same runtime scope.
  3. On key collision, implementations MUST either fail fast or replace atomically based on package policy; behavior MUST be documented per runtime.
  4. register_synthesizer MUST include the synthesizer in subsequent signal fanout.

The broker boundary has two distinct naming layers:

Scope Canonical names Meaning
External (RAS ↔ Neuromodulators) ModulatorSignal, ModulatorSuccess, ModulatorFailure Signal/reply vocabulary seen by callers and runtime boundary consumers.
Internal (Neuromodulators ↔ Synthesizer) SynthesisBroadcast, SynthesisReply Broadcast delegation and explicit reply reporting on relay channels.

External names describe the modulator signal being delegated. Internal names describe the synthesis work being performed.

  1. RAS submits a single ModulatorSignal transmission to Neuromodulators via signal.
  2. Neuromodulators broadcasts a SynthesisBroadcast to all registered synthesizers.
  3. Synthesizers that cannot satisfy the signal remain silent.
  4. Eligible synthesizers return explicit SynthesisReply transmissions with produced artifact metadata or explicit failure diagnostics.
  5. Neuromodulators converts explicit synthesis outcomes into external ModulatorSuccess or ModulatorFailure transmissions on the relay channel.
  6. RAS resolves the returned artifact-ref via get, receives the resolved instance through a terminal registered to NeuralRelay, and injects it into ModulatorCocktail.
  7. Any later responses from other synthesizers are processed according to explicit result policy on the relay channel; silence remains a null default.

Broadcast and reply clarification:

  1. SynthesisBroadcast does not require receivers to respond.
  2. The default outcome of a SynthesisBroadcast for non-responsible receivers is null (silence).
  3. SynthesisReply is emitted only by components that take explicit action on the relay channel.

Minimum expected failures:

  1. Invalid reference format.
  2. Missing artifact.
  3. Expired artifact due to cleanup policy.
  4. Cross-runtime reference leak.
  5. Fanout dispatch failure.
  6. Reply emission failure.

Canonical error codes:

  1. NM_INVALID_REF_FORMAT
  2. NM_NOT_FOUND
  3. NM_EXPIRED
  4. NM_REMOVED
  5. NM_RUNTIME_SCOPE_MISMATCH
  6. NM_KEY_COLLISION
  7. NM_FANOUT_DISPATCH_FAILED
  8. NM_RESPONSE_EMIT_FAILED
  9. NM_NO_MATCHING_SYNTHESIZER

Prefix convention:

  1. The NM_ prefix is the canonical namespace for Neuromodulators error codes.
  2. NM_ is an explicitly approved abbreviation in this context and MUST be used consistently.
  3. New Neuromodulators error codes MUST use upper-snake-case with the NM_ prefix.

When resolution fails, RAS SHOULD emit diagnostics tied to link and fail the affected modulation path explicitly.

Recommended diagnostic shape:

  1. code: one of the canonical error codes.
  2. artifact-ref: failing reference.
  3. link: signal-reply correlation id.
  4. synthesizer-id: origin synthesizer when known.
  5. message: human-readable summary.

The contract is ready for strict Pydantic validation with the following minimum DTOs:

  1. ArtifactRefDTO with regex validation for neuromodulators/{artifact-key}.
  2. NeuromodulatorRecordDTO with lifecycle state enum and timestamps.
  3. NeuromodulatorResolutionErrorDTO with canonical error code enum.

Example DTO sketch:

from datetime import datetime
from typing import Literal
from pydantic import BaseModel, ConfigDict, Field
class ArtifactRefDTO(BaseModel):
model_config = ConfigDict(extra="forbid")
artifact_ref: str = Field(alias="artifact-ref", pattern=r"^neuromodulators/[A-Za-z0-9._:-]+$")
class NeuromodulatorRecordDTO(BaseModel):
model_config = ConfigDict(extra="forbid")
artifact_ref: str = Field(alias="artifact-ref", pattern=r"^neuromodulators/[A-Za-z0-9._:-]+$")
state: Literal["published", "consumed", "expired", "removed"]
published_at: datetime = Field(alias="published-at")
consumed_at: datetime | None = Field(default=None, alias="consumed-at")
expired_at: datetime | None = Field(default=None, alias="expired-at")

Implementations SHOULD log:

  1. inbound signal envelope metadata (link, message-id, source).
  2. fanout dispatch and synthesizer selection outcomes.
  3. reply emission events back to RAS.
  4. artifact-ref issuance and resolution events.
  5. Producer synthesizer identity.
  6. Signal chain correlation ids.
  7. Cleanup and expiration events.

This enables deterministic tracing from ModulatorSignal ingress through reply mediation and runtime injection.

  1. NeuralRelay Modulator Messages: message envelope and payload fields for RAS-to-Neuromodulators signals and mediated replies.
  2. RAS Bridge Contract: launch handoff boundary where modulation is orchestrated.
  3. Substrate Package Requirements: package-level obligations for modulation behavior.