Optional ReadonlyadapterPre-built adapter (skips loadAdapter). Used by tests to inject the mock and by embedders that already hold an adapter instance.
Optional ReadonlyadaptersThe declarative adapter framework. When supplied, the server runs an
AdapterManager (loads config/adapters.{yaml,json}, instantiates enabled
adapters, persists runtime changes) and serves the /adapter* REST entities
(adapter-admin-rows.ts) off it.
ReadonlyconfigPath: stringPath to the adapter config file.
Optional Readonlyregistrations?: readonly AdapterTypeRegistration[]Registered adapter types (factory + label + settingsSchema).
Optional ReadonlywatchPresence?: boolean | { intervalMs?: number; retryBackoffMs?: number }The control-surface presence watchdog (SurfaceWatchdog): probes every
probeable entry (~2 s) so an enabled surface auto-connects when its device
appears and detaches cleanly when it vanishes. On by default when any
registration carries a probe; false disables it, an object tunes it.
Optional ReadonlyalignThe SMART ALIGNMENT measurement door (2026-08-31-smart-alignment.md): the PAIRED complex
spectra two lanes give up in one snapshot pass. Its own option rather than a field of
rta because it is a different reading — complex, of a PAIR, at one tap — even
though it shares the analyser's rings and its demand ledger. A console without it still
serves the /align row and the panel; the measurement simply refuses no-capture, which
is the honest answer and a visible one.
Optional Readonlyhz?: numberMeasurement rate in Hz. Default 2 (spec §4).
Readonlysource: AlignPairSourceOptional ReadonlyautosaveDebounce window (ms) for the live-session autosave (operator #51): a console-mutating commit schedules a write of the live console under the store's reserved live-autosave id; further mutations within the window collapse into the same write (timed from the last one). Also written once, synchronously, on MixerServer.stop so a graceful shutdown never loses the tail of a show. Only relevant when persistence is configured. Default AUTOSAVE_DEBOUNCE_MS.
Optional ReadonlycatalogThe console's plugin CATALOG — what it can rack, whether or not anything is attached to
rack it with. /plugins and /plugins/{uri} are rows over this, and the rack door's
plugins.values narrows it; a console that loads a catalog but has no plugin host still
knows what it holds, and says so. plugins supplies it too, for a console whose host
and catalog arrive together; this option wins where both are given.
Optional ReadonlyclipClip capture poll period (ms): how often the adapter's read-and-clear over flags are read
into the /channel/{kind}/{index}/clip latches (2026-08-29-clip-latch.md §6.4). Runs
regardless of demand — a latch catches what nobody is metering. Default
CLIP_CAPTURE_INTERVAL_MS; 0 disables the poll.
Optional ReadonlyclockClock control for the clock.set verb (the config-zone quantum + sample-rate lever).
Explicit injection always wins (tests inject a fake so the suite never touches the real
system clock). Left unset, this resolves to a REAL PwMetadataClock — which shells
out to pw-metadata -n settings 0 clock.force-quantum|force-rate and can re-clock the
running graph — only when realHardwareDefaults is true; otherwise it resolves to
NULL_CLOCK, which touches nothing.
Optional ReadonlyclockLive-clock poll period (ms) for the honest-rate reflection (issue #159): every this-often
the server re-reads the graph's LIVE clock.rate / quantum via the clock control's
ClockControl.refreshLive and re-broadcasts clock.state when it changed — so a
rate change made out-of-band (a PipeWire restart into a new persistent default.clock.rate)
shows up in the UI without an operator action. Default CLOCK_POLL_INTERVAL_MS;
0 disables the poll (tests that don't want a background timer). The one-shot boot seed
(which reads the live rate before the first client connects) runs regardless.
ReadonlyconfigValidated configuration.
Optional ReadonlyconfiguredThe box model the rig's reac adapter entry PINS (boxModel: s0808), for the reconciliation that
says so when the wire disagrees with it.
A pin is the one thing here that is neither observed nor a preference: it is a stored copy of
a fact the box states about itself, and on 2026-08-05 the copy said s1608 while an S-0808
was attached, with nothing anywhere comparing the two. Read once at start; a failed read is
"nothing pinned", never a guess. Absent by default, so a server without it simply has nothing
to contradict.
Optional ReadonlyconfiguredWhat the RIG is configured for, independent of any session — read fresh on each
missing-hardware diff (the composition root reads the operator's reac adapter entries,
which is where a box expectation is authored).
This is the seam behind the rig defect: every other expectation is scoped to the RESTORED SESSION, so a box the operator had configured — with reac-pw actively probing for it — went missing in silence whenever the show happened not to patch it. Absent by default: a server without this option keeps the pre-change, session-only behaviour. Must never throw; a failed read reports "nothing configured", never a phantom box.
Optional ReadonlyconvergenceThe convergence instrument (task #48): the console-wide revision counter every frame and
REST body is stamped with, the /telemetry/convergence heartbeat row published while
watched, and the corrections log clients report their heals into. Always on when the
console has a resource registry; this option only tunes it.
Optional ReadonlyheartbeatMs?: numberHeartbeat publish period, ms. One default: 1000 (~1 Hz). 0 disables the pump
(the counter and the rows stay live — only the periodic publish stops).
Optional ReadonlycoreCore-lost watchdog poll period (ms) for engine reconnect-on-disconnect. Every this-often
the server asks coreLostProbe whether the shared native PipeWire client has lost
its daemon connection; on the first true it fires onCoreLost exactly once (and
stops polling). Default CORE_LOST_POLL_INTERVAL_MS (~0.5 s → exit within ~1 s of
the daemon going away); 0 disables the watchdog (tests that don't want a background
timer, non-PipeWire deployments).
Optional ReadonlycoreThe connection-health probe the core-lost watchdog polls. Defaults to the native
nativeCoreLost (reads the atomic latched by mix_host.c on a core -EPIPE).
Tests inject a fake to drive the watchdog without a real daemon disconnect.
Optional ReadonlydeviceThe native device-profile door (amendment 2026-09-15, later the same evening) — the LIVE
half of the device-exclusivity policy, beside the drop-in's boot half. Defaults to
deviceProfileDoor over loadPwGraph, which answers NO_BACKEND with no addon.
Tests inject a fake card so the actuation and its read-back are exercised with no daemon.
Optional ReadonlydeviceThe per-device native-rate probe (amendment 2026-09-15): every ALSA device the exclusivity
policy currently sees, each with its own rate menu. Defaults to probeDeviceRates.
Sampled on the SAME cadence writeDriverPolicyConfigs already regenerates the drop-
ins on (device-set change, not a bare timer) — tests inject a fake so a bare MixerServer
never shells out.
Optional ReadonlydiscoveryNetwork discovery. Requires adapters (so addAsAdapter has a manager).
The provider is consumed through the core DiscoveryProvider interface so
the server builds before @freemixer/discovery lands.
Optional ReadonlyautoStart?: booleanBegin scanning on start. Default false (UI triggers discovery.scan).
Readonlyprovider: DiscoveryProviderOptional ReadonlyfollowerThe follower-rate probe (2026-09-14): every actively-running sink's own native rate set. Defaults to probeFollowerRates. Sampled on the SAME cadence as xrunProbe — tests inject a fake so the suite never touches the real system graph.
Optional ReadonlygraphThe graph-patchbay GraphSource behind the REST /patchbay/* routes the
web-ui Graph tab reads. Defaults to a PipeWireGraphSource (live pw-dump /
pw-link), constructed lazily on first request so a host without PipeWire pays
nothing at startup. Tests inject a fake to avoid shelling out.
Optional ReadonlyinsertRole-aware insert-suitability configuration (issue #339) — the per-role latency budgets,
their enforcement, and any per-bus role/budget override. Unset roles fall back to the
documented defaults in @freemixer/core (DEFAULT_LATENCY_BUDGET_MS), so a deployment
that says nothing still gets a monitor bus that refuses what would ruin it.
Optional ReadonlyioOptional live-I/O enumerator for the patchbay (patchbay.list). Defaults to a
PipeWireGraphProvider (a pw-dump graph read: every audio node — external apps,
DAWs, ALSA devices — with friendly names) whenever a structural surface is present. Tests
inject a fake to avoid shelling out.
Optional ReadonlyjournalHow many gestures the undo JOURNAL holds before the oldest drops off the bottom. Default JOURNAL_BOUND (512, argued there). Configurable because a bound is a judgement about a show's length, and because an arm that proves the ring is bounded must be able to reach the bound without making 512 gestures.
Optional ReadonlyloggerInject a logger setting; defaults to Fastify's default logger off.
Optional ReadonlymanualWhere to look for the prerendered documentation site, in order. Defaults to
defaultManualSiteCandidates — the packaged install, then the workspace build.
A layout seam, not a knob: it is what lets a test exercise the INSTALLED branch of the
derivation without a real /usr/share/openmixer/manual on the machine.
Optional ReadonlymeasurementThe local plugin analysis (issue #342). Every field is a seam for tests or an unusual
layout; a normal deployment sets none of them and the paths resolve from the installed
@freemixer/catalog package.
Optional ReadonlycatalogPath?: stringThe shipped catalog to merge under local measurements. Default: the package's.
Optional ReadonlynodeBin?: stringThe Node binary that runs it. Default: this process's.
Optional Readonlyspawn?: MeasurementSpawnSubprocess seam, so tests can drive a run without spawning anything.
Optional ReadonlytoolPath?: stringlv2-measure.mjs. Default: next to the installed catalog package's data/.
Optional ReadonlynativeThe native door /patchbay/link and /patchbay/unlink dispatch through
(patchbay-native-link.ts, nativeLinkDoor). Defaults to the real
@freemixer/pipewire-native client. Tests inject a fake so the resolve/create/destroy
seam is exercised with no daemon — a test that touches the real one belongs in that
module's own private-daemon suite, never a plain unit test (lane-discipline §4).
Optional ReadonlynetworkRuntime-network settings surface (the Setup menu's Network panel): where config.set
persists overrides, plus the per-field provenance the boot-time resolver computed
(network-config.ts). Without a settingsFile (and no persistence dir to
derive one from) config.set is rejected; config.get always works.
Optional ReadonlysettingsFile?: stringThe network-settings JSON file (default <persistence.dir>/network-settings.json).
Optional Readonlysources?: NetworkValueSourcesWhich layer won each field at boot (persisted/cli/env/default), for the Setup panel.
Optional ReadonlynodeThe per-node xrun probe (2026-09-14): pw-top's ERR column, kept per node rather than
summed. Defaults to probeNodeXruns. Sampled on the same cadence as xrunProbe.
Optional ReadonlynowThe clock the server reads for timestamps that BECOME STATE — today the tap-tempo
detector, whose taps are differenced into a tempo the console then holds. Defaults to
Date.now; the six-site convention (telemetry-rows.ts, rta-rows.ts,
clock-drift-probe.ts, core's convergence.ts) is the same shape.
Time that MEASURES is deliberately not routed through here: performance.now() around a
request, the perf histograms. Those observe the machine and should
keep observing the real one. Only time whose value the console goes on to SERVE needs a
seam, and it needs one because otherwise the test of a derivation is a test of the
scheduler — which is how a 400 ms sleep that took 683 ms was reported as a wrong tempo
(#153).
Optional ReadonlyonWhat to do when the core-lost watchdog detects the daemon connection is gone. Defaults to
a clean process.exit(1) so systemd restarts the engine into a fresh connection (we do
NOT attempt an in-process reconnect+re-export — too risky mid-graph). Tests inject a fake
to observe the trigger without exiting the test runner.
Optional ReadonlypatchbayOptional ReadonlyappStreams?: "strip" | "park"The SEED of the app-stream policy (/patchbay/exclusive appStreams) on a console with no
persisted settings. Default 'park' — safe mode, the operator's "by default do not patch"
(spec 2026-09-15 §6). Where a settings file exists, the file wins.
Optional Readonlyexclusive?: booleanThe SEED of the exclusive-takeover preference (/patchbay/exclusive wanted) on a
console with no persisted settings — a test desk, or a first boot with no state dir.
Default true (coexistence spec, amendment 2026-08-28: the console takes the sound card
when it comes up, and the operator switches it off from Setup). Where a settings file
exists, the file wins: this is a default, never an override.
Optional Readonlyhotplug?: booleanDisable the hot-plug poll (default enabled).
Optional ReadonlyhotplugMs?: numberPoll period in ms (default 2000).
Optional ReadonlypdcPlugin-delay-compensation control for /console/pdc. Defaults — for the built-in
software adapter — to the live SoftwareMixer recorded at build time, so a
plain software deployment can toggle PDC without extra wiring. Tests inject a fake.
Absent (and no software mixer), the row registers no instance.
Optional ReadonlyperfEngine-seam performance telemetry (task #72): count + latency histograms for every
REST resource GET/PATCH/watch (also the meter/telemetry/rta SSE fan-out) and
the /patchbay/* routes, exposed at GET /telemetry. Recording is a single
performance.now() pair plus an allocation-free PerfHistogram.record per
seam call. MEASURED (not guessed) with packages/server/bench/perf-telemetry-overhead.mjs:
the raw record() call costs ~25 ns, and enabling it end-to-end (REST dispatch +
SSE fan-out, headless mock rig) moved the p50 of a 2000-request burst by less than 1% —
within run-to-run noise, well under the task's ">1% → OFF by default" gating rule.
Default disabled anyway: this is a deliberate opt-in (new + unproven in a live
show), not a response to a measured cost — a disabled registry's record() is one
boolean check regardless.
Optional ReadonlypersistenceOptional ReadonlychannelConfigsDir?: stringExplicit channel-config dir (overrides the dir-derived default).
Optional Readonlydir?: stringParent dir; sessions go in <dir>/sessions, scenes in <dir>/scenes, patches in
<dir>/patches, configs in <dir>/channel-configs.
Optional ReadonlypatchesDir?: stringExplicit standalone-patch dir (overrides the dir-derived default).
Optional ReadonlyscenesDir?: stringExplicit scene dir (overrides the dir-derived default).
Optional ReadonlysessionsDir?: stringExplicit session dir (overrides the dir-derived default).
Optional ReadonlysettingsFile?: stringExplicit patchbay-settings file (the persisted ignore set, operator #83). Defaults to
<dir>/patchbay-settings.json. When neither this nor dir is set the ignore set is
in-memory only (session-scoped) — it will not survive a restart.
Optional ReadonlyshippedSessions?: booleanWhether an EMPTY session store is seeded with the shipped sessions (session-templates.ts)
so a console with no history comes up as a real minimal show rather than a bare allocation.
Default true — that is the product's answer to a first boot (task #33).
Set false where the composition DECLARES ITS OWN SHOW and a shipped one would overwrite
what it just said: the engine↔UI matrix's probe console dimensions itself deliberately (see
__conformance__/engine-ui-matrix/facts.ts), and a suite whose subject is "a console with
nothing saved" needs nothing saved to mean exactly that.
Optional ReadonlypluginsReadonlycatalog: CatalogInstalled-plugin catalog for URI + param validation.
Readonlyhost: PluginHostConnected mod-host client (shared with the audio-engine adapter, ideally).
Optional ReadonlyinsertPointFor?: InsertPointResolverPer-strip insert-point resolver (defaults to the stereo capture/playback seam).
Optional ReadonlyportConnector?: PortConnectorOptional pw-link-backed port connector for PipeWire-named ports.
Optional ReadonlyquantumQuantum control for /console/quantum (the latency lever). Defaults — for the
built-in software adapter — to the live SoftwareMixer recorded at build time,
so a plain software deployment can drive live/floor quantum without extra wiring. Tests
inject a fake. Absent (and no software mixer), the row registers no instance.
Optional ReadonlyreacRemote head-amp scene-watch poll period (ms). Every this-often the server refreshes the
adapter's remote head-amp fingerprint (MixerAdapter.refreshSourceCapsSignature);
on a change — a reac-pw restart, a stagebox swap, a box width/capability change — it
re-advertises capabilities to every open surface AND re-applies the recorded head-amp
scene (phantom / pad / SENS) so the device always matches what the UI shows (the scene
restore: "if we have phantom on, send phantom"). Default
DEFAULT_FABRIC_POLL_MS; 0 disables (tests without a background timer);
inert on an adapter without the refresh seam (no REAC fabric).
Optional ReadonlyreacFollow-up scene re-apply delays (ms after a fabric change). Defaults to
DEFAULT_SETTLE_REPLAY_MS — the settle window a power-cycled box needs before it
accepts head-amp records (rig 2026-08-19). [] disables the follow-ups; tests inject short
delays to observe the retry without waiting out the real window.
Optional ReadonlyrealEXPLICIT opt-in, THE ONE SWITCH: whether the device-global controls this server always
carries — clock and rmeTotalMix — default to their REAL, hardware-touching
ACTUATORS (PwMetadataClock: pw-metadata/pw-dump reads and a live re-clock;
AmixerRmeTotalmix: amixer cset against ALSA card 0) when the caller injects neither.
Default false/absent: an unconfigured boot gets NULL_CLOCK (fully inert — the
clock control has no separable actuator) for clock, and a REAL RmeTotalMixController over the inert NULL_RME_TOTAL_MIX_ACTUATOR for rmeTotalMix
— its in-memory intent tracking (owned/trims/cells) still moves on a PATCH, so a desk that
injects nothing still answers a broadcast battery honestly; only the amixer exec is gated.
Audit item 8 (2026-09-14/15): wireClock() used to construct a real PwMetadataClock()
UNCONDITIONALLY whenever options.clock was absent, and start()'s seedClockState() runs
on every boot with no test action required — its drift-recovery legs
(reassertPersistedRate/reassertPersistedQuantum) call the real setRate/requestQuantum
the instant a stale managed drop-in disagreed with the live driver, i.e. a PLAIN SERVER TEST
RE-CLOCKED THE OPERATOR'S DESK with no clock.* verb ever invoked. Only console-rig.ts's
real startConsole sets this true; every conformance desk and unit test leaves it off, so
the class of incident that also wrote the operator's real WirePlumber drop-ins (below) cannot
recur from an ordinary test boot — see test-harness-fake-by-default-conformance.test.ts.
Optional ReadonlyrecordMULTITRACK RECORD (2026-07-16-recording-vsc.md §2): the native node a take is captured
from. Supplied exactly as rtLoad's source is — the console owns what to record and
where it lands, the node owns the capture. Absent means no transport: /record has no
instance, which is the honest way to say a console with no engine cannot record.
ReadonlylaneOf: (channel: ChannelId) => number | undefinedA channel's lane on that node. Supplied by the composition rather than resolved here,
because the composition ALREADY owns that rule (console-rig.ts's laneIndexOf) and a
take that captured a different lane from the one the console's own EQ and dynamics write
would be a file of somebody else's audio with nothing about it looking wrong.
Readonlynode: () => RecordNode | undefinedOptional ReadonlyresourcesThe console's resource layer (epic #436): the ONE ResourceRegistry its entities were registered into, served over HTTP by a RestRouter this server mounts.
The registry arrives already populated because the composition root is the only place that can build the entities — the native mixer stages a projection writes to live there, not here. Mounting is this server's job for the mirror-image reason: it owns Fastify and the client fan-out, so it is the only place a REST write can reach every open surface.
Absent leaves no /api surface at all rather than an empty one, which is the honest answer
for an embedding that declared no entities.
Optional Readonlycapability?: ChannelCapabilityReaderThe channel's LIVE capability row — the authority on what a channel can carry. The clipboard's paste asks it per target (#57); absent, a paste falls back to the contract's kind column, which is the same table this row's own features derive from.
Optional Readonlychain?: ResourceHandle<ChainOrder>The processor-CHAIN entities' typed handles. When present, chain.reorder,
chain.swapEqDyn, chain.processor.enable and chain.processor.plugin write through
them — one engine door, one declared order — and each verb still answers its own
chain.processors dialect, read back from that same store. Absent, the verbs keep the
structural path: a desk without the entities loses nothing.
Optional ReadonlychainProcessor?: ResourceHandle<ChainProcessorState>Optional Readonlychannels?: () => readonly ChannelId[]Every channel the console holds a strip for — what a composition change re-projects.
Optional ReadonlydcaMembers?: ResourceHandle<DcaMembers>The DCA MEMBERS entity's typed handle (VCA nesting: members + parents). When present,
dca.members writes through it — the same structural runtime dca.fader already
reads/writes. Absent, the verb keeps the structural path.
Optional ReadonlydirectPath?: ResourceHandle<SourceDirectPaths>The /directPath/{source} entity's typed handle — ONE source's open direct outputs. When
present, directPath.add/directPath.remove still await the engine call directly (as
before), then patch the row of the source they named: the diff the row computes against
that same settled state is empty, so the entity's own broadcast is exact, no path is
opened or closed twice, and no other source's row is touched.
Optional ReadonlyheadAmp?: ResourceHandle<HeadAmpRowOrAbsent>The head-amp entity's typed handle — the SENS-capable GAIN door (headAmpDoor)
and the session-capture reads go through it. The phantom/pad/sens verbs patch the
registry by path instead: one record, one projection queue, and a refusal (no patched
input, a control the input does not declare) THROWN back to the client rather than
falling to MixerEngine.setPhantom/setPad/setSens — the engine's adapter write is
a second, independently-ordered queue onto the same preamp, and on a registry console
its strip write is a fact no hardware honours. With no resources at all the engine
path stands: it is the demo/mock console's one store.
Optional ReadonlyheadAmpKnownFields?: (id: ResourceId) => ReadonlySet<keyof HeadAmp> | undefinedThe KNOWN-set read beside the handle (phase D2): which of the three head-amp fields the
entity actually knows for a channel's physical input — undefined where the channel
resolves to no instance. Session capture persists exactly this set, so a never-touched
preamp persists nothing and a restore has nothing to assert onto it. Wired together
with headAmp, from the same entity.
Optional ReadonlyheadAmpPort?: (id: ResourceId) => string | undefinedThe PHYSICAL INPUT a channel's head-amp resolves to — the identity of the ONE record, read beside the handle from the same entity (audit D4). A head-amp belongs to the port, so a write on one channel IS a write on every channel that splits that port: this is how the fan-out finds the other legs and publishes the owner's value for each of them. Absent, only the addressed channel is published — what a desk with no splits, and a console with no entity, do anyway.
Optional ReadonlyheadAmpResource?: HeadAmpResourceThe head-amp entity's CONCRETE instance — beside headAmp's erased handle, for the
one caller that needs more than read/patch-by-channel: /source/{id}/headAmp
(source-rows.ts) resolves a source to whichever channel currently sources its physical
input, which needs HeadAmpResource.portOf and HeadAmpResource.capabilities,
neither of which a ResourceHandle carries. The row still reaches audio through this SAME
object's own patch/project — a second address, never a second store. Absent wherever
headAmp is, for the same reason.
Optional ReadonlymatrixPoint?: ResourceHandle<MatrixPointRowState>The matrix-crosspoint entity's typed handle. matrix.point writes through it when present.
Optional ReadonlymigrateHeadAmpPort?: (from: SourcePatch, to: SourcePatch, capability: HeadAmpCapability) => booleanThe port-identity drift rescue (HeadAmpResource.migrateKeptPort, §6d amendment, #836/#835) — carry a KEPT value from a box's old port name onto its new one on the rejoin edge, before the masked sweep drives it. Absent, no console this old builds ever migrated one: no entity layer, nothing to carry.
Optional ReadonlymixMinus?: ResourceHandle<MixMinusExcluded>The mix-minus exclude entity's typed handle. mixminus.exclude writes through it when present.
Optional ReadonlymuteGroupActive?: ResourceHandle<MuteGroupActiveState>The mute-group's HOLD handle. When present, muteGroup.set patches through it instead
of calling the structural door directly; absent, the verb keeps the structural path.
The group's LABEL needs no handle here — its only door is /channel/muteGroup/{index}/name.
Optional ReadonlymuteGroupMembers?: ResourceHandle<MuteGroupMembers>The mute-group MEMBERS entity's typed handle. When present, muteGroup.assign writes
membership through it — the engine's one runtime, with the row's declared ripples
re-projecting exactly the entering/leaving members' composed mutes — and muteGroup.set
reads the group's members from it to scope its re-projection to the held set. Absent,
both verbs keep the structural path: a desk without the entity loses nothing.
Optional ReadonlynativeReadback?: NativeReadbackSourceThe ?verify=1 reading — §6c query-and-compare made available to a rig operator with
curl. Present only where there is a native node to ask (native-lane-readback.ts);
absent on the software, mock and demo paths, and then a ?verify=1 GET answers the
ordinary row body with no native in it. Absence is a fact, never a fabricated reading.
Optional ReadonlypatchInput?: ResourceHandle<PatchInputState>The patch-EDGE entities' typed handles — a channel's input source set and a bus's output
destination set. When present, every patchbay.* crosspoint verb still writes the engine's
ONE ledger through the structural controller (which is what settles the graph and returns
the frame), and then REPROJECTS the row: the entity re-reads that same settled ledger and
its fan-out speaks both dialects. Absent, the verbs broadcast their own frames as before.
Optional ReadonlypatchOutput?: ResourceHandle<PatchOutputState>Optional ReadonlypatchOutputLeg?: ResourceHandle<PatchOutputLegState>Optional Readonlyprefix?: stringMount prefix. Default /api.
Optional Readonlyprofile?: () => ConsoleProfileThe declared appliance this console runs as — the CEILING every allocation, live or proposed, narrows through. Absent where the deployment declared none, which reads as the unrestricted OPENMIXER_PROFILE: a profile is a restriction, so "none declared" is honestly "nothing narrowed", never "unknown".
Optional ReadonlyprojectHeadAmpPort?: (patch: SourcePatch, fields?: ReadonlySet<keyof HeadAmp>) => ProjectionResultDRIVE the head-amp a physical input already holds onto the box, with no channel in the path (HeadAmpResource.projectPort) — how a determination reaches metal and how an already-known box's appearance gets the DESK's values back (spec §8). Channel-keyed projection cannot do this job: it enumerates strips, and the ports a sixteen-input box exposes to nothing are exactly the preamps still holding someone else's phantom.
Optional ReadonlyreacDesired?: ReacDesiredConfigThe REAC segments' DESIRED config store (reac-desired-config.ts) — the ONE home of what
the operator asserted on /reac/segment/{name} (2026-08-26-reac-runtime-config.md §3,
"the SESSION owns desired config… the daemon persists nothing"). Composed in the rig
beside the member row that writes it, and handed here so the session snapshot carries it.
Absent on a console with no REAC fabric — nothing to remember.
Optional ReadonlyrecallSafeMask?: () => RecallSafeMaskThe console-wide recall-safe mask, DERIVED from the per-channel /recallSafe rows. Handed
to the scene store, which asks it on every recall and holds no copy. Absent on a console
built without the rows: nothing is safed, and a recall applies whole.
Optional ReadonlyrefusedRivalMasters?: () => ReadonlyMap<string, RefusedRivalMaster>Every currently-refused rival master, keyed by the recognition key its OWN mac would build
(reac-segment-row.ts's refusedRivalKeyOf, over the same native graph scan every other
reacSegments accessor in console-rig.ts reads). Forwarded to /stagebox's roster
(buildStageboxRosterRow) so a bound entry can say WHY it reads absent, rather than the
composition root reaching into the registry a second time. Absent on a console with no
native PipeWire graph, which answers no refusedRivalMaster field on any entry.
Readonlyregistry: ResourceRegistryOptional ReadonlyrestoreChannelHeadAmp?: (id: ResourceId, values: Partial<HeadAmp> | undefined) => voidHOLD a restored trio the entity could not place, because the channel resolved to no
physical input when the show landed — HeadAmpResource.restoreChannelHeadAmp. Wired from
the same entity as the two above, and for the same reason they are: a show restores in one
pass and a stagebox arrives on its own clock, so without it the port a box-fed channel
lands on is first touched by a projection and seeded with the HOUSE FLOOR (#673).
Optional ReadonlyseedHeadAmpPort?: (patch: SourcePatch, value: HeadAmp, capability: HeadAmpCapability) => booleanDETERMINE a physical input's head-amp before any channel has patched to it (HeadAmpResource.seedPort) — the door a never-seen stagebox's arrival writes through (spec §8: a preamp param is never undetermined). Absent, no console this old builds ever seeded a port this way, and HeadAmpLifecycleController.adopt skips it: no entity layer, nothing to determine.
Optional Readonlysend?: ResourceHandle<SendRowState>The send entity's typed handle. When present, send.set / send.remove / send.tap
and the send row's assign door all write membership through it — one
ledger, the row's existence-by-value at level 0 standing in for send.remove. Absent,
every one of those verbs keeps the structural path.
Optional ReadonlyrmeRME Babyface Pro TotalMix ownership control for the rme.* verbs (the config-zone RME
routing menu). Explicit injection always wins (tests inject a fake so the suite never shells
out to amixer). Left unset, this resolves to a REAL RmeTotalMixController — full
in-memory intent tracking, persisting to <stateDir>/rme-totalmix.json when persistence names a dir — wrapping a real AmixerRmeTotalmix actuator (amixer cset
against ALSA card 0) only when realHardwareDefaults is true; otherwise the
controller wraps the inert NullRmeTotalMixActuator, so the SAME state-tracking behaviour
(a PATCH still moves an observable fact) runs with zero real hardware I/O. Always present
(the lever is device-global — it drives the RME card directly, not the adapter).
Optional ReadonlyrtaReal-time analyzer (RTA / spectrum). When supplied, the server polls the engine's
RtaSource while clients are subscribed and broadcasts a spectrum frame (raw
FFT bins, for the standalone panel) + an rta frame (compact 0..1 log-bins, for the
EQ-curve overlay) per channel each poll — the channels the operator ARMED
(/channel/{kind}/{index}/rta's armed) plus whatever any surface is DISPLAYING, MAIN
among them like any other lane. Handles rta.subscribe/unsubscribe.
Optional Readonlyhz?: numberPoll rate in Hz. Default 10.
Readonlysource: RtaSourceOptional ReadonlyrtThe engine's RT load meter (task #121): the native mixer's own measured
busy-per-quantum reading. When supplied, GET /telemetry carries an rt section,
GET /telemetry/rt answers the same one-shot reading (rt-load-resource.ts), and
GET /telemetry/rt?watch=1 rides it live. Each surfaced reading also carries the
core headroom verdict (level + the honest 'engine at N% of its real-time budget'
message) assessed with headroom (defaults: warn > 60%, refuse non-essential DSP
adds > 80% — see core RT_HEADROOM_*).
Optional Readonlyheadroom?: RtHeadroomConfigThreshold overrides for the headroom verdict.
Readonlysource: RtLoadSourceOptional ReadonlystructuralThe structural-DSP surface — the live software mixer's buses / sends / DCA /
matrix / output layer. When supplied, the server serves the send (send-row.ts),
DCA-membership (dca-members-row.ts) and matrix-point (matrix-point-row.ts) REST
entities off it (driving it + re-projecting on every change), and the session
capture/restore round-trips that state; otherwise those entities are unavailable and
the session keeps them empty. The software adapter exposes it; hardware-console
adapters do not.
Optional ReadonlytalkbackTalkback / test-signal generators. When a structural surface is present the server
runs a TalkbackGeneratorManager (the built-in oscillator + white/pink noise,
published as patchable NATIVE PipeWire source nodes — never subprocesses) and serves
the /talkback/* REST entities (talkback-rows.ts) off it. The backend is injected
at the server boundary (NativeGeneratorHost from @freemixer/pipewire-native in
production, a fake in tests); omitted — the addon absent / non-native host — the
generators degrade to not-running without ever crashing.
Optional Readonlygenerators?: TalkbackGeneratorBackendThe native generator-node backend (default: none — generators report not-running).
Optional ReadonlytelemetryLatency telemetry. When supplied, /telemetry/latency exists and the telemetry tick polls
the engine's LatencyReportSource on each tick (telemetry-rows.ts). The tick
itself runs on every console, for as long as a stream declares any of its rows
(/telemetry/latency, /telemetry/rt, /telemetry/process); this option only adds the
latency row to it.
Optional Readonlyhz?: numberThe tick's rate in Hz. Default TELEMETRY_HZ.
Readonlysource: LatencyReportSourceOptional ReadonlytouchedThe ephemeral fader-touch ledger — shared with the resource layer's /surface/touch/{kind}/ {index} row (surface-touch-row.ts), which is composed BEFORE this server (same reason
every other row's engine door is a call-time accessor). Absent = this server owns its own
(the pre-resource-layer default, and every bare test server).
Optional ReadonlyvscVIRTUAL SOUNDCHECK (2026-07-16-recording-vsc.md §3): the native node a take is REPLAYED
through. The recorder's block read backwards, and deliberately the same shape — the console
decides which take and which channels, the node owns the playback. Absent means no
soundcheck: /vsc has no instance, which is the honest way to say a console with no engine
cannot replay one.
laneOf is the SAME resolver record is given, and it has to be: a take is played back
into the lanes it was captured from, and a soundcheck feeding channel 4's recording into
channel 5's strip would be somebody else's audio with nothing about it looking wrong.
Optional ReadonlywriteEXPLICIT opt-in: write the generated WirePlumber drop-ins (driver ring depth + device
exclusivity, driver-ring-policy.ts) into the REAL ~/.config/wireplumber/ wireplumber.conf.d/ whenever the graded clock candidates move. Default false/absent —
every conformance desk and unit test boots with this OFF, mirroring realHardwareDefaults
(a separate switch: a desk could in principle want a real, moving clock reading without also
writing config — the incident that forced this flag needed both off). Only console-rig.ts's
real startConsole sets this true — see an internal spec
§"the fix" and the 2026-09-14 23:25 device-exclusivity ruling.
Optional ReadonlyxrunXrun-health poll period (ms) — how often xrunProbe is sampled into the delta
/clock/warnings judges (issue #657). Default XRUN_POLL_INTERVAL_MS; 0 disables
the poll (tests that don't want a background timer).
Optional ReadonlyxrunThe xrun-health probe (issue #657): pw-top's ERR column, the effective quantum/rate, and
who is asking for the largest buffer on the graph. Defaults to probeXrunHealth
(shells out through the hardened exec runner). Tests inject a fake so the suite never
touches the real system graph.
Options for MixerServer. Either supply an
adapteror let it be loaded from config.