Night-run report — observability + VM Edit Settings (2026-05-09)
Synced read-only from
/home/synnet/mirrors/synvirt-product/docs/NIGHT_RUN_REPORT.md. Edit at the source, not here.
Night-run report — observability + VM Edit Settings (2026-05-09)
Section titled “Night-run report — observability + VM Edit Settings (2026-05-09)”- Branch:
feature/observability - Base:
0.15.0(6fee23d) - HEAD:
f42d428 - Total observability commits: 4 (
7f54c4e,ad912b3,cacdefc,f42d428). Two interleaved WebRTC commits from the parallel agent also live in the chain (bf24201,f93f017); they were not authored by this run.
Commits since 0.15.0
Section titled “Commits since 0.15.0”f42d428 feat(web-ux-v2): observability surface + VM Edit Settings modalf93f017 fix(synvirt-webrtc): two host candidates per session for Chromium UDP/443 filtercacdefc feat(synvirt-observability): expand detector catalog to 30+ codesad912b3 feat(synvirt-observability): example /etc/synvirt/observability.yaml7f54c4e feat(synvirt-observability): scaffold crate with SQLite persistence and detector frameworkbf24201 feat(console-webrtc): per-session FPS + bitrate knobs and quality dropdownCoverage
Section titled “Coverage”Issues & Alarms — ✅ shipped
Section titled “Issues & Alarms — ✅ shipped”- New crate
synvirt-observabilityregistered in the workspace. - 30+ detector codes covering host CPU / memory / load / swap, ZFS pool usage / degraded / scrub / resilver, OVS bridge / uplink / VLAN / MTU, NTP / DNS / log error rate / kernel panic / cert expiry, BMC fan / temp / PSU / battery / IPMI SEL, and the full VM-side surface (heartbeat / agent / consolidation / snapshots / CPU / CPU ready / memory / disk latency / disk usage / drivers / tools / boot / migration / orphan disks).
- Full alarm state machine:
triggered → acknowledged → resolvedwith auto-resolve scan,Acknowledge(note + user), andReset to Greenoperator transitions wired through the registry →EventBusso every transition lands as an event. - Catalog list in
config::ALL_DETECTOR_CODESmatches the example/etc/synvirt/observability.yaml.
Tasks & Events — ✅ shipped (crate side)
Section titled “Tasks & Events — ✅ shipped (crate side)”TaskRegistry+TaskHandlefaçade with safe drop semantics (cancel-on-drop). Helper builders fortask_started,succeeded,failedevents.EventBusovertokio::sync::broadcastwith persisted history inevents. Retention purger spawnable from the daemon.- WebSocket subscriber + REST shape documented in
docs/OBSERVABILITY.md. Daemon REST and WS handlers are the remaining Priority-2 work — flagged below.
Edit Settings — ✅ UI shipped, ⚠️ backend pending
Section titled “Edit Settings — ✅ UI shipped, ⚠️ backend pending”EditSettingsModal.vuewith three tabs (Virtual Hardware / VM Options / Advanced Parameters), Save / Cancel footer, dirty diff detection, editability-matrix consumption, and PATCH wire format.- Full panels:
CpuPanel,MemoryPanel,DisksPanel. Per-VMNetworks,CD/DVD, andControllerspanels are placeholders with the data already plumbed and copy explaining the next iteration. - VM Options tab summarises boot order, firmware, secure boot, video.
- Advanced Parameters tab with whitelist-aware key/value editor;
whitelist evaluation lives in
synvirt_observability::config::EditSettingsConfig::allows_advanced_key. - All hot-plug rules, the matrix, and the audit table are
documented in
docs/EDIT_SETTINGS.md. The daemon-sidePATCH /api/v1/vms/{uuid}/settingsand theeditabilityGET are Priority-2 work, see below.
Tests Playwright — ⚠️ not implemented
Section titled “Tests Playwright — ⚠️ not implemented”Skipped per the night-run triage. Contracts the suites would assert
are documented in docs/OBSERVABILITY.md and docs/EDIT_SETTINGS.md
so the suites can be authored once the daemon endpoints land.
Migrations DB
Section titled “Migrations DB”0001_initial.sql—issues_catalog,alarms(partial unique on active rows),tasks,events,edit_settings_audit, plusschema_version.
Build & lint gates
Section titled “Build & lint gates”cargo check -p synvirt-observability: PASS.cargo test -p synvirt-observability: PASS (3 unit tests).cargo clippy -p synvirt-observability --tests -- -D warnings: PASS.npx vue-tsc --noEmit(web-ux-v2): PASS.cargo check --workspace: PASS after the parallel agent’sbf24201commit landed the missingsynvirt_webrtc::QualityOverridetype. Was failing at the start of the night-run, seedocs/HANDOFF_WEBRTC.md.- Workspace clippy / fmt / audit not run on the full workspace — the WebRTC area is parallel-agent territory and still in flux.
Outstanding Priority-2 work
Section titled “Outstanding Priority-2 work”These are intentionally deferred so the parallel WebRTC work and this observability work can both land cleanly without stepping on each other’s daemon-side changes.
- Daemon REST & WS routes. The dashboard already calls
/api/v1/observability/{alarms,tasks,events}and/api/v1/observability/events/stream; the daemon needs a newcrates/daemon/src/api/observability/module. Until then the store fails soft and surfaces a non-fatal warning toast — UI still renders empty. - VM Edit Settings backend.
GET /settings,GET /settings/editability, andPATCH /settingsneed to land incrates/daemon/src/api/vm_settings.rs(next to the existingvm_hardware.rs). The contract is fully documented indocs/EDIT_SETTINGS.md. - TaskRegistry plug-in. Wire
vm.start(and over time the rest of the lifecycle handlers) throughTaskRegistry::startso operator actions surface in/monitor/taskswith progress and Events. - Per-host scoped views.
/hosts/:id/issues|tasks|eventsand/vms/:uuid/issues|tasks|events. Trivial routing additions once the global views are validated against real data. - Playwright E2E suites.
tests/e2e/observability/—issues-alarms.spec.ts,tasks-events.spec.ts,vm-edit-settings.spec.tsper the original spec.
Reserved-area notes
Section titled “Reserved-area notes”The original spec called the WebRTC area off-limits. The parallel agent active during the run committed several WebRTC commits on top of the observability branch:
bf24201,c4b9611,d9b76ad,f93f017— WebRTC quality knobs, host-candidate fix, e2e test fixture.
These were left intact. Branch hygiene was restored twice during the run by:
git branch -f feature/observability HEADimmediately after each observability commit landed on the parallel branch.git branch -f feature/console-enterprise-night-batch <their_tip>to rewind their branch back off observability commits.
feature/observability now contains the four observability commits
plus the parallel agent’s WebRTC commits as parents (cherry-picked
forward). The observability files do not touch any reserved-area
file.
Branch state at the end of the run
Section titled “Branch state at the end of the run”feature/observability f42d428 ← my work + interleaved WebRTC parentsfeature/console-enterprise-night-batch d9b76ad ← parallel agent's tip0.15.0 6fee23dDecisions worth re-reviewing
Section titled “Decisions worth re-reviewing”- SQLite over sled for observability. The crate’s API is query-heavy (filters by severity / target / time window / category / since_id), and SQLite indexes / partial unique constraints are a much better fit than sled prefix scans. Existing service crates use sled; this is the first SynVirt feature to default to SQLite.
- Callback-driven detectors for everything that touches
daemon state. Each detector accepts a boxed-future closure that
the daemon supplies (pool health, OVS bridge status, BMC sensors,
VM telemetry, …). This keeps
synvirt-observabilityindependent fromsynvirt-libvirt/synvirt-network/ the daemon, but pushes some plumbing onto the daemon. The alternative — a thick D-Bus client surface — was deferred to keep the night-run focused on the observability data model and the dashboard surface. - Edit Settings hot-plug matrix in the daemon, not the client.
The dashboard reads
editabilityfrom the daemon and renders the resulting locked / unlocked state. The client never reasons about power state directly, so a future hot-plug rule update only touches the daemon. - Lossy event broadcast. The websocket fan-out drops messages
on subscribers that are too slow; the SQLite
eventstable is the source of truth and the client usessince_idto backfill.
Smoke tests REST/WS (2026-05-10)
Section titled “Smoke tests REST/WS (2026-05-10)”Daemon REST + WebSocket endpoints landed on top of the night-run
work in commits 90538e1, 6384f1e, 77f295f. Manual smoke run
on the dev box (Debian 13, no /etc/synvirt/observability.yaml,
no /etc/pam.d/synvirt-daemon) — confirms the wiring is alive.
$ /home/synvirt/dev/target/debug/synvirt-daemon --dev --port 18443…WARN synvirt.daemon.observability: observability config missing or invalid; falling back to compiled defaults, error: E_OBS_CONFIG_READ: failed to read configuration at /etc/synvirt/observability.yaml: No such file or directory (os error 2)INFO synvirt_observability::db: migration applied, version: 1INFO synvirt.daemon.observability: observability surface ready/var/lib/synvirt/observability.db is created with WAL +
foreign keys + the 0001_initial schema (issues_catalog, alarms,
tasks, events, edit_settings_audit, schema_version).
Route mount confirmation
Section titled “Route mount confirmation”PAM auth on this box defaults to login (the synvirt-daemon PAM
service is not installed); without valid root credentials each
endpoint correctly returns 401:
$ curl -sk -i https://127.0.0.1:18443/api/v1/issues | head -1HTTP/2 401$ curl -sk -i https://127.0.0.1:18443/api/v1/alarms | head -1HTTP/2 401$ curl -sk -i https://127.0.0.1:18443/api/v1/tasks | head -1HTTP/2 401$ curl -sk -i https://127.0.0.1:18443/api/v1/tasks/some-id | head -1HTTP/2 401$ curl -sk -i https://127.0.0.1:18443/api/v1/events/list?limit=10 | head -1HTTP/2 401$ curl -sk -i -H "Connection: Upgrade" -H "Upgrade: websocket" \ -H "Sec-WebSocket-Version: 13" -H "Sec-WebSocket-Key: dGVzdA==" \ https://127.0.0.1:18443/api/v1/events/stream | head -1HTTP/2 401POST endpoints behave the same:
$ curl -sk -i -X POST https://127.0.0.1:18443/api/v1/issues/abc/acknowledge \ -H "content-type: application/json" -d '{"note":"x"}' | head -1HTTP/2 401Behavioural smoke
Section titled “Behavioural smoke”PAM on this dev box does not have a valid root password configured,
so the positive happy path is exercised through
crates/daemon/tests/observability_smoke.rs instead — three
end-to-end tests (alarm lifecycle, task lifecycle + bus events,
event publish + filter):
$ cargo test -p synvirt-daemon --test observability_smoke
running 3 teststest events_publish_persist_and_filter ... oktest alarm_lifecycle_end_to_end ... oktest task_lifecycle_emits_events ... ok
test result: ok. 3 passed; 0 failed; 0 ignored; 0 measured; 0 filtered outAssumed-paths log
Section titled “Assumed-paths log”Path collisions and gaps surfaced during the wiring; flagging here so they get a second pass:
/api/v1/eventsis owned by the legacy SSE handler. The observability list lives at/api/v1/events/listand the websocket at/api/v1/events/stream. UI store + composable updated to match.- TaskRegistry list filters on
since,until,kindprefix: the crate’slist_tasksonly supports(target_type, target_id, state, limit). The daemon over-fetches up toMAX_LIMIT * 2and filters in-process. Asumido, validar después: extendTaskRegistry::listitself with the wider filter shape so the SQLite indexes can do the work. - Subtask discovery for
GET /v1/tasks/{id}similarly over-fetches and filters byparent_task_id. Asumido: a dedicatedlist_subtasks(parent_id)belongs in the crate. - Alarm
since_idcursor is not exposed onAlarmRegistry::list; the websocket reconnect path therefore cannot replay alarms before the cursor (events do replay viaEventRow.id, which is what the dashboard primarily consumes). - WebSocket pong is documented in the protocol but the current implementation is a no-op — axum already handles WebSocket-level ping/pong, and the dashboard relies on those, not the JSON-level pong frame. Asumido that this is acceptable until the dashboard actively uses the application-level keep-alive.
- DetectorRegistry tick loop is not spawned. Detectors all require host-side callbacks (pool health, BMC sensors, VM telemetry) the daemon does not expose yet. Wired in a follow-up.
What to pick up next
Section titled “What to pick up next”- Land the daemon-side
crates/daemon/src/api/observability/module (REST + WS) — straightforward axum work given the contracts indocs/OBSERVABILITY.md. - Land
crates/daemon/src/api/vm_settings.rswith the editability matrix builder and the PATCH applier (plus rollback on partial failure). Audit rows go intoedit_settings_auditvia the observability database handle. - Wire one or two daemon lifecycle handlers (
vm.start,vm.snapshot.create) throughTaskRegistry::startend-to-end so the dashboard’s/monitor/tasksshows live progress against a real backend. - Author the Playwright suites, anchored on the contracts the daemon now fulfils.