Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -121,3 +121,19 @@ tool does not recognize the token and cannot expand the template.
consumer-side `ovos.mic.listen` row (defined in OVOS-AUDIO-1 §4.4).
- See-also — cross-references OVOS-AUDIO-1 §4.4 as the defining spec
for `ovos.mic.listen`.

## OVOS-BRIDGE-1 — Bus Bridge and Opaque Relay

### 2

- The bus bridge: a participant that terminates an external channel and
relays Messages between the internal bus and remote participants. §3 —
the normative core: inbound identity stamping (`source`), outbound
routing by `destination` / `session_id` / `site_id`, `site_id`
assignment, and the relaying vs managing session-preservation modes.
§4 — emergent patterns over MSG-1 + SESSION-1/2 + PIPELINE-1 +
TRANSFORM-1 + CONTEXT-1 + INTENT-4 at a bus boundary: policy injection,
multi-deployment topologies, out-of-utterance `ovos.session.sync`, and
satellite skill registration. §5 ordering guidance; §6 conformance.
- §3.3 — `site_id` assignment is owned here; OVOS-SESSION-1 §3.3 carries
the registry pointer and the orchestrator-pipeline consumer constraints.
52 changes: 39 additions & 13 deletions appendix/divergences.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,19 +63,18 @@ and needs no implementation change:
The following topics exist in current ovos-core but are **not
defined by any spec** and should be removed or replaced:

- **`ovos.session.sync` / `ovos.session.update_default`** —
emitted by `SessionManager` to broadcast the current default
session to interested components. SESSION-2 §6.4 acknowledges
that an orchestrator MAY emit default-session state on a
deployer-defined topic but assigns no normative name. These
ad-hoc topics should be retired: any component that needs the
default-session state can subscribe to `ovos.utterance.handled`
(PIPELINE-1 §9.5) and read the session it carries, or listen
to any other assistant-emitted Message on the default session.
A named sync topic adds an implicit state-broadcast contract
that the specs deliberately avoid; clients are expected to
track session from Message flow, not from dedicated sync
broadcasts.
- **`ovos.session.update_default`** —
emitted by `SessionManager` in legacy code to broadcast the
current default session. SESSION-2 §5.4 acknowledges that an
orchestrator MAY emit default-session state on a deployer-defined
topic but assigns no normative name. This ad-hoc topic should be
retired: any component that needs the default-session state can
subscribe to `ovos.utterance.handled` (PIPELINE-1 §9.5) and read
the session it carries, or listen to any other assistant-emitted
Message on the default session. See §5.7 for the migration mapping.
Note: `ovos.session.sync` serves a distinct purpose — explicit
out-of-utterance state sync — and is now formalized by
SESSION-2 §2.7; see §5.5 for its entry as a new topic.

### 5.3 Prescriptive shape changes

Expand Down Expand Up @@ -209,6 +208,13 @@ defined by any spec** and should be removed or replaced:
`reply` / `response` (MSG-1 §4.3). Formalizes a "MAY"
convenience for in-process subsystems; not currently
implemented but compatible with current behaviour.
- **`ovos.session.sync`** (SESSION-2 §2.7). Explicit
out-of-utterance session-state sync emitted by a component that
has mutated session state outside the normal utterance lifecycle
and needs the change propagated. No current spec-conformant
equivalent — `ovos.session.update_default` (now retired, see
§5.2.1) served an overlapping purpose for the default session
only. `ovos.session.sync` is generalised to any session.

### 5.6 Things the specs do *not* change

Expand Down Expand Up @@ -263,6 +269,7 @@ a number of legacy names. Implementer migration aid:
| `ovos.utterance.handled` | **unchanged** — kept as the universal end-marker. |
| `<skill_id>:<intent_name>` | **unchanged** — dispatch topic; a plugin-bundled handler has `skill_id == pipeline_id`. |
| `mycroft.skill.handler.start` / `.complete` / `.error` | renamed to `ovos.intent.handler.start` / `.complete` / `.error` |
| `ovos.session.update_default` | **retire** — subscribe to `ovos.utterance.handled` (PIPELINE-1 §9.5) to read updated default-session state; or to any assistant-emitted Message on the default session. See §5.2.1. |

#### Out of scope

Expand All @@ -280,3 +287,22 @@ a number of legacy names. Implementer migration aid:
| `recognizer_loop:record_end` | `ovos.listener.record.ended` | Capture end; pairs with the start signal. |
| `recognizer_loop:sleep` | `ovos.listener.sleep` | Controller-to-listener sleep request. |
| `mycroft.awoken` | `ovos.listener.awoken` | Sleep→awake transition; moved into the `ovos.listener.*` namespace. |

### 5.8 Bus bridge (BRIDGE-1)

- **BRIDGE-1 defines source-stamping and destination-based routing;
current HiveMind bridges route primarily by session_id.**
HiveMind groups messages by `session_id` and delivers them to the
peer that owns that session. BRIDGE-1 prescribes `destination` as
the primary signal because two peers sharing the same `session_id`
(including `"default"`) cannot be distinguished by session_id
alone. HiveMind deployments that use per-peer `session_id`s are
conformant with either model; deployments that share the
`"default"` session across multiple peers must migrate to
destination-based routing for client isolation.
- **OVOS-BRIDGE-1 is new — no existing implementation fully
conforms.** The bridge spec formalizes a role that exists today
(the HiveMind gateway, the bus client, any inbound message
fan-in) but with a tighter normative core. Current
implementations are expected to adopt the source-stamping and
session-preservation requirements incrementally.
55 changes: 55 additions & 0 deletions appendix/gaps.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,3 +55,58 @@
format, and `ovos-localize` (§1.4) provides the
operations layer; what remains is the *scale* of the
translated corpus.

### Bridge-specific gaps (OVOS-BRIDGE-1)

- **Multi-hop bridge cascading.** BRIDGE-1 §4.2 describes
peer-to-peer topology between two deployments, but does not
address cascaded bridges (deployment A ↔ bridge ↔ deployment B
↔ bridge ↔ deployment C). Each bridge stamps source
independently; outer-deployment participant identity is lost
at each inner boundary unless propagated as opaque metadata.
- **Bridge-to-bridge wire format.** The spec does not prescribe
whether messages between peer bridges remain in MSG-1 envelope
form or may use a different serialization. The intent is that
they stay in MSG-1 form (per §4.2 "relays native bus messages"),
but the transport encoding is left as a deployment concern.
- **Bridge health / heartbeat.** No `ovos.bridge.ping` /
`ovos.bridge.pong` surface is defined. The orchestrator has no
spec-level way to know whether a remote participant is
reachable. Deferred to a future observability specification if
needed.
- **Audio transmission over the bus.** BRIDGE-1 §4.2.1 describes
two audio-stack placements — local (satellite runs STT and its
own audio-output layer) and hub-side (hub runs the full audio
stack, satellite transmits raw audio inbound and receives final
audio outbound). STT placement and audio-output placement are
symmetric and independent: each can live on the satellite or the
hub, giving four possible combinations. The hub-side model
requires transmitting audio as bus Message payloads (e.g.
base64-encoded PCM or compressed frames). The bus surface for
any audio transmission — topic names, payload shape, session
fields for codec and audio preferences — is not defined by any
current specification. Deferred to OVOS-AUDIO-1.
- **Session-scoped pipeline plugin registration.** BRIDGE-1 §4.4
and INTENT-4 §11 cover session-scoped intent registration for
satellite-side skills. A satellite that implements a pipeline
plugin (not an intent-based skill) cannot register that plugin
on the hub; no bus surface exists for session-scoped plugin
loading. If needed, this requires a new specification or an
extension to OVOS-PIPELINE-1.
- **Managing mode concurrent utterance race.** BRIDGE-1 §3.4.2
says the bridge SHOULD apply `ovos.utterance.handled` session
updates before injecting the next utterance, but makes no
guarantee when both arrive simultaneously. The handling of
overlapping utterance rounds in managing mode — whether to
queue, drop, or process with a stale session — is left as a
deployment concern. A future revision may define a normative
queuing policy.
- **NAT bijection and hub-side session cleanup.** When a bridge
using `session_id` NAT (§3.2) disconnects a participant, the
hub-side `session_id` may remain in the orchestrator's
default-session store (SESSION-2 §5). BRIDGE-1 §3.2 says the
bridge SHOULD emit cleanup events using the hub-side `session_id`
before dropping the bijection, but does not define a complete
cleanup protocol for hub-side state created during the session's
lifetime (e.g. cross-utterance context, active handlers).
Deferred to a future session-lifecycle specification.
65 changes: 64 additions & 1 deletion appendix/rationale.md
Original file line number Diff line number Diff line change
Expand Up @@ -381,7 +381,70 @@ the normative sections.
signals; consolidation is the consumer's decision per
SESSION-1 §3.2.7.

### 4.8 Stop pipeline plugin (STOP-1)
### 4.9 Bus bridge (BRIDGE-1)

- **Normative minimalism is design intent.** The bridge could have
been an auth spec, a topology spec, a wire-protocol spec. By
limiting normative weight to source stamping, session preservation,
and destination-based relay (3 MUSTs in §6), the spec correctly
identifies that session fields do the heavy lifting — the bridge
just carries them. Everything else (policy injection, topology
patterns) emerges from composing existing lifecycle,
state-ownership, and session-field specifications at the bus
boundary.
- **Destination-based routing provides client isolation.**
Session-id-only routing lets one participant claim another's
`session_id` and receive messages intended for the other (§3.2).
Destination-based routing fixes this because the orchestrator uses
`.reply()` to set `destination` to the original `source`. Two
participants sharing the same `session_id` (especially
`"default"`) cannot impersonate each other — their `source` values
differ, and each receives only messages whose `destination`
matches its own identifier. The OVOS-MSG-1 §5 derivation chain
preserves routing metadata through every emission, so the bridge
never sees a message without sufficient routing information.
- **Session_id matching is a MAY convenience.** The OVOS-MSG-1 §5
derivation chain preserves `destination` across every `forward` /
`reply` / `response` hop, so all bus messages that carry
conversation progress carry a `destination` the bridge can route
on. `session_id` matching exists for the narrow case of topic-level
subscriptions a bridge explicitly opts into, not for correctness.
- **Layer-2 systems inject policy via session fields, not bridge
protocol.** A layer-2 system (MSG-1 §3.4) mutates the session at
the bridge boundary before the message enters the bus. No
bridge-specific protocol is needed — the session fields do the
work. This is the same pattern as SESSION-2 §2.4's
SHOULD-project pathway, but with the bridge as the enforcement
point rather than the component itself.
- **The hardened minimum topic set is a deployer choice.** A bridge
MAY subscribe to everything (default, simpler, compatible with
future lifecycle additions) or restrict to the utterance-lifecycle
topic set (hardened, reduced attack surface). The trade-off is by
design, not prescribed.
- **`site_id` enables bridge-side physical grouping without
requiring skills to understand topology.** The bridge is the
natural point to assign `site_id` because it is the only
component that has visibility into both the physical deployment
and the internal bus. A concrete example: a bridge that receives
Wi-Fi or Bluetooth scan data from participants can resolve that
signal to a physical location and stamp the appropriate `site_id`
before injecting the message; a bridge that integrates with a
home-automation system can use the canonical area name from that
system (e.g. `"living_room"`, `"kitchen"`) directly as the
`site_id`, giving skills a stable identifier that is already
meaningful in the user's home model. In either case, participants
need not know their own location, and skills need not understand
network topology.
The `site_id` then travels with the session, giving any downstream
pipeline plugin or skill a stable, location-derived grouping key
for context (e.g. applying room-specific TTS voices, routing
media to the nearest speaker, or gating location-aware intents).
This is why the spec mandates `site_id` for group routing rather
than enumerating participants: the bridge encapsulates the mapping
from physical signal to logical group, and everything downstream
consumes an opaque string.

### 4.10 Stop pipeline plugin (STOP-1)

The most common reader question on first encountering STOP-1 is
*why a pipeline plugin and not a skill*. Stop sounds like an
Expand Down
Loading