Wildcard the backend notification-acks projector consumes on
STREAM_EVENTS. Narrow (events.notifications.acked.>) rather
than the whole events.> so the projector only wakes for ack
events and not the high-volume events.started.* lifecycle
traffic (which the events projector handles separately).
NOTE: since unack landed, the backend projector consumes the broader
EVENTS_NOTIFICATIONS_FILTER (ack + unack on one ordered consumer), so
this narrower acked.> filter is no longer the active consumer filter.
Kept as a named constant for the ack-only subject shape (docs + tests).
Wildcard the backend notification-acks projector consumes on
STREAM_EVENTS once it handles both ack and unack. Broader than
EVENTS_NOTIFICATIONS_ACKED_FILTER (acked.>) so a single durable
consumer sees both events.notifications.acked.* and
events.notifications.unacked.* in stream-sequence order — the only
way ack → unack → re-ack stays correctly serialised (a second
consumer would race the DELETE past a later INSERT). Still a strict
subset of events.> so STREAM_EVENTS retains it without a config
change, and still narrower than the high-volume events.started.*
traffic the events projector owns.
Wildcard the backend events projector consumes on STREAM_EVENTS.
Narrow (events.started.>) rather than the whole events.> so
future event types can carry their own filters without rerouting
the started subset.
notifications.all — broadcast end-user notification (SPEC
§2.2.1 / Phase E). Mirrors COMMANDS_ALL but on the
notification fan-out plane: the backend publishes here, the
NOTIFICATIONS stream retains it, and every agent forwards it to
the Client Apps in matching user sessions.
notif-amend — ephemeral fleet-wide control channel for post-send
operations on a notification (currently: recall). Deliberately NOT
under notifications.> so the NOTIFICATIONS JetStream stream doesn’t
retain it (these are live control pushes, not history). Published via
core NATS (fire-and-forget); every agent subscribes and forwards a
notifications.amended push to its clients, each of which applies it
only if it holds the referenced id — so a single broadcast needs no
per-audience routing (an id a client doesn’t have is a no-op). The
durable half of a recall is the stream message deletion; this is just
the “remove it from screens that are showing it now” half.
Subject prefix for notifications_group. Exposed so callers that
parse a subject back into its group name (the backend’s notification
audience resolver) strip against the same string the builder emits —
if the format ever changes, both move together instead of the parser
silently failing to match.
obs.> — filter the backend projector subscribes to so a new
PC starts flowing into the timeline without any per-PC SUB
registration. Pairs with obs for publish.
events.notifications.acked.{pc_id}.{user_sid}.{notif_id} — the
agent publishes this when a user clicks “確認” on a notification
(SPEC §2.2.2 / Phase E). The {user_sid} segment distinguishes
concurrent users on a shared PC (Fast User Switching / RDP). Lives
under events.> so the existing EVENTS stream retains it; the
backend’s notification-acks projector consumes the narrowed
EVENTS_NOTIFICATIONS_ACKED_FILTER to build the SPA’s
per-recipient confirmation view.
events.notifications.unacked.{pc_id}.{user_sid}.{notif_id} — the
agent publishes this when a user retracts a prior “確認” (the
read↔unread toggle). Mirror of events_notifications_acked; the
backend’s notification-acks projector consumes it on the same
consumer (see EVENTS_NOTIFICATIONS_FILTER) so ack and unack for
one recipient stay strictly ordered on the EVENTS stream. Layer
split: the agent tombstones the notifications_read KV (so the
user’s own notifications.list goes back to unread); this event is
the projector’s half — it stamps unacked_at on the read-model
row and appends the revoke to the audit log. Same retention caveat as
the acked subject: the durable source of truth is SQLite, the stream
only bounds re-projection after a -WipeDb.
events.started.<exec_id>.<pc_id> — v0.30 / PR α’ lifecycle
event published by the agent just before spawning a script’s
child process. Lets the backend project an in-flight row into
execution_results (with finished_at = NULL) so the SPA
Activity table can show running rows alongside finished ones.
Backend subscribes via EVENTS_STARTED_FILTER.
host_perf.<pc_id> — Phase 1 of the perf telemetry pipeline. The
agent publishes a whole-host CPU / Memory / Disk I/O / Network
snapshot here on the cadence set by host_perf_interval in
agent_config (default 60 s). Distinct subject from heartbeat.<pc_id>
so the periodic heartbeat publisher stays untouched and pre-host_perf
backends that don’t subscribe simply ignore the new traffic.
job.tail.<pc_id> — request/reply for the live tail of a
still-running job’s stdout/stderr. The operator (or backend, on
the SPA’s behalf) sends a crate::wire::JobTailRequest carrying
the result_id; the addressed agent replies with the current
ring-buffer tail from its in-memory live registry. On-demand only,
no stream — the SPA polls this every few seconds (same shape as
logs.fetch.<pc_id>) while a job is in flight. Distinct subject
from logs.fetch.<pc_id> (whole-agent log file) because this is
scoped to a single job’s captured output, not the agent’s log.
kill.<exec_id> — Spec §2.6 Layer 3 abort signal. The exec_id is
the deployment / scheduler-fire UUID (formerly named job_id
pre-v0.29; renamed for accuracy — every Command.exec_id is a
per-deploy UUID, not a job-catalog id).
logs.fetch.<pc_id> — request/reply: operator (or backend) sends
a LogsRequest; the addressed agent replies with the tail of its
local log file. On-demand only, no stream.
agents.<pc_id>.ping — v0.38 / #133 request/reply for the
active “ping” round-trip. The agent answers with a fresh
Heartbeat on demand instead of the backend waiting up to ~30 s
for the next periodic heartbeat tick to land. Distinct subject
from heartbeat.<pc_id> so the periodic publisher is unaffected
and old agents that don’t subscribe simply time the request out.
process_perf.<pc_id> — Phase 2: top-N per-process snapshot
published only while process_perf_enabled is true AND the
process_perf_expires_at deadline is in the future. Separate
subject from host_perf.<pc_id> because process-perf is an
opt-in investigation mode — having its own subject lets the
projector skip the heavy table entirely for hosts that never
turn it on.