pub enum SessionUpdate {
Show 82 variants
Spawning {
key: SessionSlot,
project_name: String,
cwd: String,
display_name: String,
},
Connected {
key: SessionSlot,
session_id: SessionId,
cwd: String,
current_model: CurrentModel,
available_models: Vec<AvailableModel>,
mode: Option<ModeState>,
history: Vec<Message>,
dropped: usize,
compaction_count: u32,
},
CallOutput {
key: SessionSlot,
call_id: String,
output: CallOutput,
},
SessionReplaced {
key: SessionSlot,
session_id: SessionId,
cwd: String,
current_model: CurrentModel,
available_models: Vec<AvailableModel>,
mode: Option<ModeState>,
history: Vec<Message>,
dropped: usize,
compaction_count: u32,
},
Handoff {
key: SessionSlot,
handoff: HandoffRecord,
},
MachineTurn {
key: SessionSlot,
machine: Option<MachineTurn>,
},
ConnectionFailed {
key: SessionSlot,
message: String,
fatal: bool,
},
Releasing {
key: SessionSlot,
},
Notice {
key: SessionSlot,
severity: NoticeSeverity,
text: String,
},
SetModeFailed {
key: SessionSlot,
mode: PermissionMode,
message: String,
},
SetModelFailed {
key: SessionSlot,
model: String,
message: String,
},
PermissionRequest {
key: SessionSlot,
tool_id: String,
request: PermissionRequest,
},
QuestionRequest {
key: SessionSlot,
tool_id: String,
request: QuestionRequest,
},
PendingInteractionResolved {
key: SessionSlot,
tool_id: String,
question_index: Option<u64>,
answered_with: Option<String>,
},
McpOperationError {
key: SessionSlot,
error: McpOperationError,
},
TurnComplete {
key: SessionSlot,
terminal_reason: Option<TerminalReason>,
},
TurnCancelled {
key: SessionSlot,
},
TurnError {
key: SessionSlot,
message: String,
class: Option<TurnErrorClass>,
terminal_reason: Option<TerminalReason>,
},
ChatAppended {
key: SessionSlot,
msg: Message,
source: Option<PromptSource>,
},
HookObservation {
key: SessionSlot,
tool_use_id: Option<String>,
permission_mode: Option<String>,
effort: Option<String>,
agent_id: Option<String>,
agent_type: Option<String>,
},
ForgeAccountIdentity {
key: SessionSlot,
display_name: String,
},
DictateOverrides {
key: SessionSlot,
overrides: DictateOverrides,
},
ContextUsageSnapshot {
key: SessionSlot,
percentage: Option<u8>,
max_tokens: Option<u64>,
},
McpSnapshot {
key: SessionSlot,
servers: Vec<McpServerStatus>,
error: Option<String>,
},
ProcessesChanged {
key: SessionSlot,
snapshot: ProcessSnapshot,
},
MonitorsChanged {
key: SessionSlot,
monitors: Vec<MonitorRecord>,
},
BackgroundTasksChanged {
key: SessionSlot,
tasks: Vec<BackgroundTask>,
},
WorkChanged {
key: SessionSlot,
work: WorkState,
git: GitWorkView,
pr: Option<GitPrInfo>,
closes: Vec<GitIssueRef>,
},
TasksChanged {
key: SessionSlot,
tasks: Vec<Task>,
},
CronSchedulesChanged {
key: SessionSlot,
crons: Vec<CronEntry>,
},
ConnectorSubscriptionsChanged {
key: SessionSlot,
gotify: Vec<GotifySubscription>,
slack: Vec<SlackSubscription>,
},
SlashCommandsChanged {
key: SessionSlot,
commands: Vec<AvailableCommand>,
},
SubagentsChanged {
key: SessionSlot,
subagents: Vec<AvailableAgent>,
},
SubagentCardsChanged {
key: SessionSlot,
cards: Vec<SubagentCard>,
},
FileIndexChanged {
key: SessionSlot,
index: Arc<FileIndex>,
},
ServiceStatus {
severity: ServiceSeverity,
message: String,
},
CatalogLoaded,
CliVersionChanged,
AccountsChanged {
accounts: AccountPoolView,
},
PluginsInventoryUpdated {
cwd_raw: String,
snapshot: PluginsInventorySnapshot,
claude_path: PathBuf,
},
PluginsInventoryRefreshFailed {
cwd_raw: String,
message: String,
trigger: PluginUpdateTrigger,
},
PluginsCliActionSucceeded {
cwd_raw: String,
result: PluginsCliActionSuccess,
dispatch_id: Option<u64>,
},
PluginsCliActionFailed {
cwd_raw: String,
message: String,
dispatch_id: Option<u64>,
},
PluginsUpdateRunProgress {
cwd_raw: String,
run: PluginUpdateRun,
},
PluginsUpdateRunFinished {
cwd_raw: String,
run: PluginUpdateRun,
snapshot: Option<PluginsInventorySnapshot>,
claude_path: Option<PathBuf>,
},
PluginsRollbackSucceeded {
cwd_raw: String,
plugin_id: String,
scope: String,
message: String,
snapshot: PluginsInventorySnapshot,
claude_path: PathBuf,
},
PluginsRollbackFailed {
cwd_raw: String,
plugin_id: String,
message: String,
snapshot: Option<PluginsInventorySnapshot>,
},
WorkerStatusChanged {
project_key: ProjectKey,
action: WorkerStatusAction,
status: WorkerStatus,
worktree: WorktreeDisposition,
},
PeerEnvelopeAppended {
key: SessionSlot,
wrapped: WrappedPrompt,
uuid: String,
},
GotifyNotificationAppended {
key: SessionSlot,
notification: GotifyNotification,
uuid: String,
},
CronPromptAppended {
key: SessionSlot,
text: String,
uuid: String,
cron_id: String,
description: Option<String>,
},
SlackMessageAppended {
key: SessionSlot,
prose: String,
uuid: String,
},
SlackPostPending {
key: SessionSlot,
draft: SlackDraft,
},
SlackDraftResolved {
key: SessionSlot,
id: Uuid,
ending: SlackDraftEnding,
},
BrowserHandOffPending {
key: SessionSlot,
handoff: HandOff,
},
BrowserHandOffResolved {
key: SessionSlot,
id: Uuid,
answer: HandOffAnswer,
},
TerminalHandOffPending {
key: SessionSlot,
handoff: TerminalHandOff,
},
TerminalHandOffResolved {
key: SessionSlot,
id: Uuid,
answer: TerminalHandOffAnswer,
},
TerminalChanged {
key: SessionSlot,
terminal: Option<TerminalSummary>,
},
PromptQueued {
key: SessionSlot,
uuid: String,
source: PromptSource,
text: String,
},
PromptLifecycle {
key: SessionSlot,
uuid: String,
state: String,
},
PromptCancelResolved {
key: SessionSlot,
uuid: String,
cancelled: bool,
},
ReviewActivityNotice {
key: SessionSlot,
branch: String,
waiting: usize,
message: String,
},
DictateAvailability,
DictateStarted {
key: SessionSlot,
floor_db: f32,
generation: u64,
initiator: Option<u64>,
},
DictateLevel {
key: SessionSlot,
peak_db: f32,
generation: u64,
initiator: Option<u64>,
},
DictateTranscribing {
key: SessionSlot,
generation: u64,
initiator: Option<u64>,
},
DictateProgress {
key: SessionSlot,
generation: u64,
done: usize,
total: Option<usize>,
initiator: Option<u64>,
},
DictateEnded {
key: SessionSlot,
outcome: DictateOutcome,
generation: u64,
surface: Option<String>,
initiator: Option<u64>,
},
FatalError {
error: AppError,
message: String,
},
DictateModelsChanged {
models: DictateModelsSnapshot,
},
DocumentHandOffPending {
key: SessionSlot,
id: Uuid,
path: String,
reviewable: bool,
},
DocumentHandOffResolved {
key: SessionSlot,
id: Uuid,
ending: DocumentHandOffEnding,
},
SettingsWritePending {
key: SessionSlot,
ask: SettingsWriteAsk,
},
SettingsWriteResolved {
key: SessionSlot,
id: Uuid,
ending: SettingsWriteEnding,
},
VaultAskPending {
key: SessionSlot,
draft: VaultDraft,
},
VaultAskResolved {
key: SessionSlot,
id: Uuid,
ending: VaultAskEnding,
},
BiometricEnrolmentsChanged {
enrolments: Vec<BiometricEnrolment>,
},
VaultRotated {
refresh_token: String,
},
VaultLockChanged {
locked: bool,
},
VoiceAudio {
key: SessionSlot,
seq: u32,
sample_rate: u32,
pcm: Vec<i16>,
},
VoiceModeState {
key: SessionSlot,
listeners: u32,
},
}Expand description
Update envelope: forge-workspace -> a view.
Permission/Question variants do NOT carry response oneshots -
responses flow back via Command::Respond*. The workspace stores
the oneshot in DomainSession.pending_interactions when emitting
these variants.
Clone is what lets the fan-out hand one emit to more than one
subscriber, so every variant’s payload must stay cloneable.
Variants§
Spawning
Workspace is spawning a session (in response to
Command::SpawnProject). A view creates a placeholder
under key and shows the “Waking {display_name}…” message. The
matching Connected lands soon after, under the same key.
Connected
Fields
key: SessionSlotcurrent_model: CurrentModelavailable_models: Vec<AvailableModel>dropped: usizeMessages the read carried that history’s window left behind its
front, which is the floor a page cursor below the window is
measured against.
Carried because the window cannot say it. The read is windowed before it crosses - a resume’s whole transcript is gigabytes - so a consumer holding the window alone reads it as the conversation’s front, and a walk below it would stop there instead of crossing into the transcript. Additive on the wire, and zero for a read the window holds whole.
CallOutput
A call’s own output, asked for by Command::ReadCallOutput: the tail
of the file the CLI streamed the call’s output to, or a named reason
there is none.
Emitted by the transport from its held copy of the seat’s
conversation, which carries the frame naming the call’s output_file.
SessionReplaced
The slot’s occupant changed under it - a /new, a /resume, a
login or a logout. The slot keeps its bucket, in its place on
screen; its contents reset, meaning the rendered conversation,
the history, the per-session overrides and any waiter holding a
tool call that is never coming back. session_id is the new
occupant.
Fields
key: SessionSlotcurrent_model: CurrentModelavailable_models: Vec<AvailableModel>Handoff
The seat’s occupant was replaced by a handoff rather than by a person asking for one, and this is the record of it - emitted before any frame from the new occupant, so the seat learns the swap before the successor’s transcript starts. No view draws a row from it: the successor’s own procedure row carries the handoff.
MachineTurn
The machine turn running on this seat changed: a handoff beginning or
ending, and None for a seat taking input.
A record read is not pushed. The record carries the same fact for a page that attaches mid-turn, but a page already open learns it here - and its composer stands down for exactly that span.
ConnectionFailed
Releasing
The seat’s release has begun: its session is being taken down, and a view draws the seat as going to sleep until the roster lands it asleep or gone.
Announced at the START of the release, not when the handles drop. The teardown is what takes the seconds, so a viewer that hears only the end keeps the row reading as working through the whole gesture - and a close made from another view is heard by no one at all without this.
Fields
key: SessionSlotNotice
One line the core has for a view about key, which nothing else
carries.
A command answered where both views dispatch has no other way to say anything: the CLI emits no frame for a command it never saw, and the line is the core’s own answer rather than a view’s opinion - what a command found, or why it refused.
Live only, and that is intended. The CLI writes no transcript row for a line it never produced, so a view draws this on arrival and a page that attaches afterwards has nothing to read it from. It is a statement about the moment a command ran, not a record of the conversation.
SetModeFailed
The CLI refused (or failed) a set_permission_mode control
request for key. message carries the underlying error text;
the view rolls the optimistic mode chip back and surfaces it.
SetModelFailed
The CLI refused (or failed) a set_model control request for
key. message carries the underlying error text; the view
rolls the optimistic model change back and surfaces it.
PermissionRequest
Permission prompt. No response_tx - a view replies via
Command::RespondPermission { tool_id, outcome }.
QuestionRequest
AskUserQuestion prompt. Same shape; reply via
Command::RespondQuestion { tool_id, outcome }.
PendingInteractionResolved
The interaction tool_id was answered, so every view holding the
prompt can drop it. Answering leaves the pending set either way,
and this is the only thing that says so on the stream: without it a
second view keeps drawing a prompt that is already settled. A lone
view never meets that, because it is the only one.
A question names its round as well as its call. A batch reuses
one tool call id and advances question_index, and the next round’s
request can land before this round’s resolution - so a clear keyed
on the id alone dropped the ask that had just parked, and every
round after the first lost its opening question (Ved’s live find;
#1717). None on every interaction that is not a question, and on
the frames of a core older than this field.
Fields
key: SessionSlotMcpOperationError
TurnComplete
TurnCancelled
Fields
key: SessionSlotTurnError
Fields
key: SessionSlotclass: Option<TurnErrorClass>The failure’s class, where the producer that built the event could
name one. None is “not classified here” rather than “not
auth”: a producer that never classified and an auth failure are
different facts, and a reader that folds them together holds a
session on /login for an error that was never about login.
terminal_reason: Option<TerminalReason>ChatAppended
Fields
key: SessionSlotsource: Option<PromptSource>Who dispatched the prompt this frame writes as a user turn: the
same PromptSource the queue’s own row carries.
This is the arm a reader’s follow reads, because the words’
shape cannot say it: forge’s own machinery - an auto-continue, a
worker kick, a board notice - forges prose as the reader’s own row
on this frame, and arming for one carries a parked reader to the
foot for words that are nobody’s (#2198). Only you is a person’s
send.
None on every frame the CLI sent; the turns a delivery forges
carry the delivery’s own kind, since their envelope row is not the
reader’s either.
HookObservation
Fields
key: SessionSlotForgeAccountIdentity
DictateOverrides
The full override set a session holds after a /dictate edit
landed. Sent after every SetDictateOverride and
ResetDictateOverrides so the dialog’s markers and its reset
row read from this, not from a view-side copy.
ContextUsageSnapshot
Fields
key: SessionSlotMcpSnapshot
ProcessesChanged
The seat’s process tree moved, as the whole walk the core holds.
Pushed rather than read. The walk is a sysinfo refresh; the
core runs it once a second for every seat a view is showing, and this
carries the answer to whoever is drawing it. Emitted only when the
tree’s own entries moved - a walk that found the same processes says
nothing.
MonitorsChanged
The seat’s monitors moved, as the whole set the core holds.
Pushed rather than read. The set changes on discrete task frames -
a Monitor call entering, a task stamping its id, a frame settling
one, the drain that empties it - and never per output chunk, so the
frame that moved it announces it and a frame that moved nothing says
nothing.
BackgroundTasksChanged
The seat’s live task set moved, as the whole set.
Both halves move it: the CLI announces its background registry whole on
each change, and a long foreground call enters on its task_started
and leaves on its task_notification, a terminal task_updated, or
the end of the turn that ran it. So this mirrors a task entering,
leaving or being cleared by a dead connection.
WorkChanged
The seat’s working tree moved, as the row a view draws it.
Pushed rather than read. The three fields are the record’s own - the branch and count, the open PR on the pushed sha, and the issues it closes - so a client applies them to the fields it already narrows. A seat nobody is showing is not scanned, so this is only sent for a seat somebody holds.
Fields
key: SessionSlotgit: GitWorkViewThe tree behind the row’s depth: the uncommitted files with their marks and counts, the branch’s chain ahead of its default, and which branch that is.
closes: Vec<GitIssueRef>TasksChanged
The project’s task list moved, as the whole set the core holds.
Pushed rather than read. The tasks__* writes are the only movers
and the section a view draws sits on the board’s project row - keyed by
the project’s lead seat, which exists for every declared project - so
the write announces the set rather than leaving the row to the next
unrelated read.
CronSchedulesChanged
The project’s schedules moved, as the whole set the core holds.
Pushed rather than read. Three doors move it - the cron__*
writes, a fire that advances or removes an entry, and a worker’s
teardown - and the section draws the countdown, so each announces the
set it left. key is the project’s lead seat.
ConnectorSubscriptionsChanged
The project’s inbound connector subscriptions moved, as the two sets the core holds.
Pushed rather than read. The gotify__* / slack__* writes move
them, and so do the doors no tool call reaches: a mention’s
auto-subscribe, a watched conversation’s name healing on its first
message, and a worker’s teardown taking its own with it. One update
carries both connectors because they are one section of the board’s
project row, and a reader that patches it needs the pair. key is the
project’s lead seat.
SlashCommandsChanged
The / menu’s catalogue moved, as the whole list the core holds.
Pushed rather than read. The CLI advertises it on a turn’s init and
re-sends it when a plugin changes it (commands_changed), so the frame
that moved it announces it and a turn’s init repeating the same list
says nothing.
SubagentsChanged
The agent-type catalogue moved, as the whole list the core holds.
Pushed rather than read. The CLI advertises it on a turn’s init, once per turn, so this is that one frame - and an init that repeats the list the last turn advertised says nothing.
SubagentCardsChanged
The session’s sub-agent instances moved, as the whole list the core folds from the frames it has seen.
Pushed rather than read. The join lives in
forge_workspace::subagent_cards and folds a frame at a time, so a
live session announces the list it now holds rather than re-walking
its conversation per frame. A client draws the instances from this -
the raw frames stay on the conversation for whoever folds something
else - and a page attaching later reads the same list off the record.
FileIndexChanged
The tree’s file index moved, as the whole index the core holds.
Pushed rather than read, and throttled here rather than by the
socket. The socket’s batch folds only consecutive token appends, so
a burst of index frames would go out one per change: the walk runs at
most once per poke while the watch says the tree is moving - so a
build’s writes inside one poke become one walk - and once per
INDEX_STALENESS when it is still. The frame goes out only when the
index actually differs from the one last announced.
ServiceStatus
CatalogLoaded
The background catalog scan finished and Workspace’s project
catalog is populated. A view reads the roster itself, so nothing
needs carrying: the event exists to wake the render loop so
session counts appear when the scan lands rather than on the next
unrelated frame.
CliVersionChanged
A claude version probe landed and moved what the views draw. The
snapshot itself is not carried, so this is only the wake-up: a view
re-reads through the surface’s cli_version verb.
AccountsChanged
The account pool moved: an account’s loading state, its last probe failure, its cached usage snapshot, or the gateway listener’s readiness.
The frame carries the pool’s drawn state, flattened so its fields
are the ones HomeWire::accounts states - the same values, built by
crate::Workspace::account_pool_view, so a client that folds the frame
and a client that reads the snapshot cannot disagree (rule 25). That
is what lets a usage move reach the badge without a home read.
It carries no seat because the pool belongs to none, which is also what routes it to a home subscriber and to nobody else.
Fields
accounts: AccountPoolViewPluginsInventoryUpdated
PluginsInventoryRefreshFailed
Fields
trigger: PluginUpdateTriggerWhether the failed refresh served a boot auto-update run - app-scoped, so its failure bypasses the cwd gate.
PluginsCliActionSucceeded
Fields
result: PluginsCliActionSuccessPluginsCliActionFailed
Fields
PluginsUpdateRunProgress
A section-level update run or check moved: one or more rows changed state. Carries the whole run so the pane replaces its copy wholesale.
PluginsUpdateRunFinished
The run (or check) is over. The record batch is persisted by the run task itself; this event is reporting only.
PluginsRollbackSucceeded
Fields
snapshot: PluginsInventorySnapshotPluginsRollbackFailed
Fields
snapshot: Option<PluginsInventorySnapshot>The refreshed inventory when the rollback ran but did not verify, so the pane still reflects the real state.
WorkerStatusChanged
Workspace pushed a change to live_workers[project_key]. A
view’s reducer updates the projects pane’s tree-children based
on action. status is the snapshot at the moment of the
change (relevant for Added and StatusChanged; ignored for
Removed but carried for symmetry). worktree is what has
become of the worker’s worktree, read on Removed events
(after which the WorkerEntry is gone from live_workers, so a
lookup-by-label would fail).
Fields
project_key: ProjectKeyaction: WorkerStatusActionstatus: WorkerStatusworktree: WorktreeDispositionPeerEnvelopeAppended
A peer-coordination envelope arrived at key.
Carries the typed WrappedPrompt so a view’s reducer can build
the chat-side echo from real fields instead of having the
workspace forge a Message::User carrying prose for a view to
re-parse (audit I11). The recipient’s LLM still receives the
prose via a separate Command::Prompt dispatch - that’s the
CLI’s input channel and stays text-shaped.
GotifyNotificationAppended
A matched Gotify notification arrived at key.
Carries the typed GotifyNotification so a view’s reducer builds
the chat-side echo from real fields (mirrors PeerEnvelopeAppended).
The session’s LLM receives the same prose via a separate
Command::Prompt - this update only drives the visible echo.
CronPromptAppended
A due cron fired into key. Carries the fired
prompt text so a view’s reducer builds the chat-side echo (mirrors
GotifyNotificationAppended). The session’s LLM receives the same
text via a separate Command::Prompt - this update only drives
the visible echo.
Fields
key: SessionSlotuuid: StringThe id the delivered prompt was dispatched under, which the drawn
row carries - see PeerEnvelopeAppended.
SlackMessageAppended
A matched Slack message arrived at key. Carries the
prose rather than the typed message: the prose builder is pub(crate)
to forge-workspace, so a typed message would force a view to rebuild
the very format it parses. The session’s LLM receives the same prose
via a separate Command::Prompt - this update only drives the visible
echo (mirrors GotifyNotificationAppended).
Fields
key: SessionSlotSlackPostPending
A composed Slack message is waiting for the user’s decision in the
dock prompt. The authoring tool handler is blocked on a oneshot
until Command::RespondSlackPost answers it, so nothing posts
while this is outstanding.
SlackDraftResolved
A held Slack draft left the core’s registry: answered in some view,
or its asking session gone. Each view keeps its own copy of the
parked draft, so this is the only update that clears it - and
ending is what a view that did not answer it says happened.
BrowserHandOffPending
A browser hand-off waits for the person at a client: the session asked
them to act in a browser tab, and its tool handler is blocked on a
oneshot until Command::RespondBrowserHandOff answers it.
No timeout rides this one. The ask dock’s own timelines say a held prompt sits for hours, and the session is meant to wait as long as it takes; the handler’s drop, not a clock, is what ends the wait.
BrowserHandOffResolved
A browser hand-off left the core’s registry: answered in some view, or
its asking session gone. answer is the ending, the door that sent it
and the connection that carried it - what a view that did not answer it
reads, and what the log names.
TerminalHandOffPending
A terminal hand-off waits for the person at a client: the session asked
them to type into the seat’s terminal, and its tool handler is blocked
on a oneshot until Command::RespondTerminalHandOff answers it.
No timeout rides this one, and the agent is blind while it is
parked: terminal__read and terminal__write are refused.
TerminalHandOffResolved
A terminal hand-off left the core’s registry: answered in some view, or
its asking session gone. answer is the ending, the door that sent it
and the connection that carried it.
TerminalChanged
A seat’s terminal opened, changed or closed, as the strip and the
session record read it. None means the terminal is gone.
PromptQueued
A prompt entered the CLI’s queue: the row a view draws as waiting, with the words and the sender the lifecycle frames do not carry.
Emitted where the prompt is dispatched, keyed by the uuid it was sent under - so a view keys its own optimistic row to this one by id rather than by order or text.
PromptLifecycle
Where one prompt is in the CLI’s queue, as the CLI itself reports it:
queued, started, completed and the terminal states
(cancelled, discarded, refused). Keyed by the uuid the prompt was
sent under, which is what lets a view key its queued row to its own
send by id rather than by order or text.
state stays a free-form string so a state this build has not seen
reaches a view rather than being dropped.
PromptCancelResolved
The CLI answered a cancel_async_message: cancelled: false means the
prompt was already dequeued for execution, so a reader that asked to
drop it has to say it is on its way instead.
ReviewActivityNotice
A worker’s review turn addressed review comments; key is the
session that authored the review (the submit origin). A view drops
message as a system line into that session’s chat so the reviewer
sees the batched tally, and parks waiting - how many threads on
branch now await a reviewer turn - as the persistent signal both
the Inspector GIT badge and the NEEDS ATTENTION band read.
DictateAvailability
Dictation models are loaded and the composer may offer to
dictate. App-global (no key): the engine is process-wide and
every session’s composer shares the availability; the event’s
existence is the signal. Never emitted when [dictate] is
disabled, so sessions that cannot dictate render nothing.
DictateStarted
A recording started for the composer at key. floor_db is the
silence floor the level meter maps onto its zero glyph, so the
bar and the NoAudio verdict agree by construction. generation
identifies this take among the key’s takes: a resolver that
arrives after a newer take started carries a stale one, and the
composer resets on its own generation only.
initiator names the connection the take belongs to, as its
dictate_stream carried it: every Dictate* update about a take
goes to that connection alone, so no other subscriber draws its
meter, its phases or its words. None is this process’s own
take.
DictateLevel
One level reading for the recording at key: the peak over the
window since the previous reading, in dBFS. Emitted on the
meter clock, not the repaint clock.
A window with no signal reads as null on the wire, and null
reads back as negative infinity. A peak that heard nothing is
exactly zero, whose dBFS is negative infinity, and serde writes a
non-finite float as null - so a reader that takes the field as an
f32 cannot decode the message at all, which is the state this
tolerance exists to close. Nothing about the value a view draws
changes: the client narrows null itself, and this only lets a
Rust reader do the same.
Fields
key: SessionSlotgeneration: u64The take’s own, as SessionUpdate::DictateStarted announced it:
a reading that arrives after a newer take started is the older
one’s and belongs in no live meter.
initiator: Option<u64>The take’s own, as SessionUpdate::DictateStarted announced
it.
DictateTranscribing
The take from key was submitted and a transcript is in flight.
Fields
key: SessionSlotgeneration: u64The take’s own, as SessionUpdate::DictateStarted announced it:
a stale one must not move a newer take to transcribing while its
microphone still records.
initiator: Option<u64>The take’s own, as SessionUpdate::DictateStarted announced
it.
DictateProgress
A take from key has settled done segments of its
transcription. total is None while the recording is still
open, because a live take cannot know how many segments it will
produce, and the final count once the take was stopped and its
tail submitted. Single-segment takes report at stop only; a
composer renders only what it wants to. generation is the
take’s own, as handed out by SessionUpdate::DictateStarted.
Fields
key: SessionSlotinitiator: Option<u64>The take’s own, as SessionUpdate::DictateStarted announced
it.
DictateEnded
A take from key is done: insert, notice or reset per
DictateOutcome. generation is the take’s own, as handed
out by SessionUpdate::DictateStarted.
Fields
key: SessionSlotoutcome: DictateOutcomesurface: Option<String>The surface whose own capture began the take, as
Command::DictateStream carried it: the landed words are that
surface’s to place, and no other’s. None for a take
begun in process or by a client older than the field.
FatalError
The core’s fatal: the app is going away. message is what a
view draws on exit - AppError::user_message() - so a view that
draws the line words it the same way without a second copy.
DictateModelsChanged
The catalogue check landed: the models page’s whole view, re-read. Carries no slot - the feed belongs to the machine, not a seat - and a session page ignores it. Sentinel rows the page draws (the check’s freshness, every candidate row, the per-model updates) are all here, so a subscriber that was already attached never has to ask again for what this frame just changed.
Fields
models: DictateModelsSnapshotDocumentHandOffPending
A session handed the reader a document: the ask a client draws - open or not now - with the resolved path it opens at.
The call parks on this, like the browser hand-off: id names the
parked call, and the reader’s answer releases it - NotNow here, or
Approve / Feedback when the viewer’s finish files the reading.
path is the
resolved absolute path, the viewer’s stable address; reviewable is
what the hand-off asked for - the ask’s own fact rather than the
document’s, because a readable document offers its review either way.
DocumentHandOffResolved
A document hand-off left the core’s registry: finished in some view,
declined, or its asking session gone. ending is what a view that
did not answer it says happened.
SettingsWritePending
A configuration write waits for the reader’s approval in the dock:
the session’s settings__set / settings__unset handler is blocked
on a oneshot until Command::RespondSettingsWrite answers it, so
nothing reaches forge.toml while this is outstanding.
SettingsWriteResolved
A held configuration write left the core’s registry: answered in some
view, or its asking session gone. ending is what a view that did
not answer it says happened.
VaultAskPending
A vault call waits for the reader’s approval in the dock: the family’s
tool handler is blocked on a oneshot until Command::RespondVaultAsk
answers it, so no operation runs in the vault while this is outstanding.
needs_unlock on the draft is stamped from the live session as the
card is built, so a sibling that unlocked first re-bases this one.
VaultAskResolved
A held vault call left the core’s registry: answered in some view, or
its asking session gone. ending is what a view that did not answer
it says happened; the tool result carries the operation’s own outcome.
BiometricEnrolmentsChanged
The device enrolments moved, as the whole set the core holds. Pushed
rather than read: an enrol, a release’s stamp and a revoke each leave a
set the settings page draws, and the card reads the same set - so a
second client redraws without asking. No wrapped blob rides here; see
forge_primitives::biometric::BiometricEnrolment.
Fields
enrolments: Vec<BiometricEnrolment>VaultRotated
The shared vault session rotated its refresh token, so the copy an enrolment blob holds is spent. A client that holds the material from its last release rewrites its blob with this one (decision 15); one that cannot falls back to the password on its next start.
Slot-less: the session is process-wide, and only the client that
owns the enrolment acts on it. The token is a secret on the socket -
it never reaches a transcript or the live fold, and the manual Debug
redacts it.
VaultLockChanged
The shared vault session locked or unlocked outside a held card - the idle bound passed, a refresh or a decryption failed, or an unlock landed. Slot-less like the rotation: the session is process-wide, and the settings page’s vault card is what redraws.
VoiceAudio
One rendered clip of the seat’s speech, mono 16-bit samples at
sample_rate. Chunks arrive in seq order and every client with
voice on for the seat plays them; a client with voice off receives
them and stays silent.
VoiceModeState
The seat’s voice state: how many clients are listening, which is what the control draws and what a listener note is injected on.
Implementations§
Source§impl SessionUpdate
impl SessionUpdate
Sourcepub fn slot(&self) -> Option<&SessionSlot>
pub fn slot(&self) -> Option<&SessionSlot>
The SessionSlot this update routes to, or None for
updates that target App-level state (ServiceStatus, catalog,
plugin, fatal-error). Every identity-carrying variant names a
slot, so nothing is synthesized here.
Trait Implementations§
Source§impl Clone for SessionUpdate
impl Clone for SessionUpdate
Source§impl Debug for SessionUpdate
impl Debug for SessionUpdate
Source§impl<'de> Deserialize<'de> for SessionUpdate
impl<'de> Deserialize<'de> for SessionUpdate
Source§fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>where
__D: Deserializer<'de>,
fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>where
__D: Deserializer<'de>,
Auto Trait Implementations§
impl Freeze for SessionUpdate
impl RefUnwindSafe for SessionUpdate
impl Send for SessionUpdate
impl Sync for SessionUpdate
impl Unpin for SessionUpdate
impl UnsafeUnpin for SessionUpdate
impl UnwindSafe for SessionUpdate
Blanket Implementations§
§impl<T> AnySync for T
impl<T> AnySync for T
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> DeserializeOwned for Twhere
T: for<'de> Deserialize<'de>,
impl<S, T> Duplex<S> for Twhere
T: FromSample<S> + ToSample<S>,
§impl<S> FromSample<S> for S
impl<S> FromSample<S> for S
fn from_sample_(s: S) -> S
§impl<T> Instrument for T
impl<T> Instrument for T
§fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more