yuzu

Fleet Visualization

The 3D fleet visualizer is built as an 11-PR ladder on feat/viz-engine. Each PR layers on the previous one, and each round of governance hardening adds invariants that successor PRs must respect. This doc collects those invariants so they outlive any single PR description.

Triggers for this doc: any change touching viz_routes.{hpp,cpp} / fleet_topology_store.{hpp,cpp} / viz_page_ui.cpp / static/yuzu-viz.js / --viz-disable / Config::viz_disable / McpServer::set_viz_deps / the get_fleet_topology and get_host_topology MCP tool handlers in mcp_server.cpp (api-parity #2146 Batch B3 - a second implementation site for these same invariants: kill-switch-before-RBAC ordering, the machines_max DoS cap, the offline-merge rule). Loaded by security-guardian + docs-writer during governance.

MCP surface

get_fleet_topology/get_host_topology (mcp_server.cpp) are the MCP twins of the REST endpoints below, wired via McpServer::set_viz_deps() (passes the SAME fleet_topology_store_/viz_disabled_ instances and the same OfflineEndpointStore (via an OfflineRosterFn closure) REST’s VizRoutes registration uses, so the two surfaces cannot disagree about cache state). Every invariant in this doc (kill-switch ordering, the DoS cap, the offline-merge rule) applies identically to both surfaces - a change to one that doesn’t preserve parity with the other is a regression, not a stylistic difference. That equal treatment does not extend to confinement: neither surface confines results to the caller’s management-group scope - a caller with Response:Read sees every connected agent’s process/connection/listener data fleet-wide on both REST and MCP alike (#4313, tracked parallel to #3526’s gap on the execution/fleet-statistics tools, which is closed for the per-agent rollup GET /api/v1/execution-statistics/agents and its MCP twin only; the fleet-summary and by-definition aggregates are unconfined by design).

REST and routing surface

Kill switch and DoS cap

Audit

Fragment / JSON escape

Metrics

Page-shell invariants (viz_page_ui.cpp)

Renderer invariants — PR 6 (static/yuzu-viz.js)

The renderer bundle is built via embed_js.py rather than a hand-written TU — it crossed the MSVC 16,380-byte raw-string literal limit at PR 6. Standing rules:

Edge invariants — PR 8 (intra-cube localhost edges)

Process-layer invariants — PR 7

Listener-socket invariants — PR 9

Three-tier stacked layout — PR 12

Talking-socket primitive — PR 12

Tube-wire geometry — PR 12

Push-ingestion invariants — PR 10

Durable offline-host invariants — #1320 PR 3 (Postgres substrate)

The flip wired the born-on-Postgres OfflineEndpointStore (schema endpoint_state) into /viz/fleet so a host that ages out of the in-memory 60 s topology cache renders stale-flagged instead of vanishing. Standing rules for the viz_routes.cpp::handle_topology merge:

Cross-references