Parent: #1
Depends on: #16, #17, #26
Priority: nice-to-have; not a Rendezvous v1 release gate
Outcome
Provide two deliberately separate views of Rendezvous:
a thin read-only diagnostic web dashboard that exercises the same public session-browser and live-update APIs available to games;
provisioned Grafana dashboards for operators using privacy-safe service metrics.
This issue does not create a privileged administration web UI. Revocation, key management, tenant configuration, and other destructive operations remain in the authenticated operator CLI/API from #16.
Diagnostic dashboard
Build a minimal static web application with no game or server authority. Prefer plain standards-based HTML/CSS/JavaScript or another build-light static approach unless a heavier framework is justified.
Scope
Select configured game, environment, protocol, region, capacity, and visibility filters.
Fetch the bounded initial session snapshot and subscribe to the SSE stream from #26.
Display public session projection fields only: safe metadata, compatibility/build display, region, advisory capacity, visibility/freshness state, and last update age.
Apply session_upsert, session_remove, and reset deterministically.
Surface stream state: connected, reconnecting, polling fallback, cursor reset, service unavailable, and last successful update.
Permit deliberate reconnect/reset/polling-fallback diagnostics without exposing internal credentials.
Escape all server-provided metadata and never render it as trusted HTML, CSS, URL, or script.
Provide responsive, keyboard-accessible presentation with clear empty/loading/error states.
Keep joining and gameplay out of the page unless a future consumer-specific deep link is explicitly designed.
Deploy as optional static assets or a separate static container/profile; production operators may disable it completely.
Use an allow-listed configuration rather than accepting arbitrary backend URLs that could turn the page into an SSRF/open-proxy aid.
HTTP availability, request rate, latency, errors, timeouts, and rate-limit rejections;
active/awaiting/stale listings, lease renewal/expiry churn, and browser snapshot/SSE subscriber counts;
join issuance, active attempts, endpoint binding, pairing latency, introduction outcomes, reported direct outcomes, and typed failures;
UDP packets/bytes accepted and dropped, malformed/replay/limited traffic, response amplification budget, queue depth, and saturation;
process CPU, memory, GC, threads, sockets, and graceful-drain status;
shared-store health/latency only when a shared store is enabled;
key-expiry/configuration health and security/audit event rates;
supported/capacity profile overlays and recommended alert thresholds.
Use only low-cardinality tenant/environment/region/outcome dimensions approved by #16. Never use session IDs, attempt IDs, tokens, metadata, or raw IP addresses as labels.
Security and privacy boundaries
The diagnostic dashboard calls public read-only browse/SSE APIs only.
No operator credential, publisher credential, lease capability, punch capability, connection ticket, raw endpoint, or secret is stored in browser state or returned to it.
Apply a restrictive Content Security Policy, safe CORS policy, clickjacking protection, MIME-type protection, and dependency minimization.
Public dashboard enablement, allowed games/environments, and rate limits are explicit configuration.
Grafana access and datasource credentials remain operator-controlled and are not proxied through the public dashboard.
Diagnostic and Grafana logs/telemetry follow the retention/redaction policy from #2/#16.
Acceptance criteria
A user can open the diagnostic page, filter sessions, and see live add/update/remove changes without manual refresh.
Disconnect, SSE cursor gap, server restart, and unsupported streaming fall back or reset cleanly without leaving a false/stale “live” state.
The final client projection matches a fresh server snapshot after every tested event sequence.
Malicious metadata regression cases cannot inject markup/script/style/navigation or corrupt the page.
Cross-game/environment/protocol/visibility isolation is preserved.
The dashboard never receives or exposes raw endpoints or credentials.
Slow event bursts are coalesced/rendered without unbounded DOM growth, memory use, or flicker.
Keyboard navigation, focus visibility, semantic labels, contrast, loading, empty, and error states pass the chosen accessibility gate.
Grafana provisioning loads from a clean Compose/deployment environment with no manual panel construction.
Grafana panels populate during the three-party/TestClient scenario and abusive-load tests.
Dashboard queries and labels remain bounded/low-cardinality and contain no secrets or personal endpoint data.
Both dashboards are optional, documented, and independently disableable.
Security tests verify CSP/CORS/headers and prove the page has no privileged administration path.
Parent: #1
Depends on: #16, #17, #26
Priority: nice-to-have; not a Rendezvous v1 release gate
## Outcome
Provide two deliberately separate views of Rendezvous:
1. a thin read-only diagnostic web dashboard that exercises the same public session-browser and live-update APIs available to games;
2. provisioned Grafana dashboards for operators using privacy-safe service metrics.
This issue does not create a privileged administration web UI. Revocation, key management, tenant configuration, and other destructive operations remain in the authenticated operator CLI/API from #16.
## Diagnostic dashboard
Build a minimal static web application with no game or server authority. Prefer plain standards-based HTML/CSS/JavaScript or another build-light static approach unless a heavier framework is justified.
### Scope
- Select configured game, environment, protocol, region, capacity, and visibility filters.
- Fetch the bounded initial session snapshot and subscribe to the SSE stream from #26.
- Display public session projection fields only: safe metadata, compatibility/build display, region, advisory capacity, visibility/freshness state, and last update age.
- Apply `session_upsert`, `session_remove`, and `reset` deterministically.
- Surface stream state: connected, reconnecting, polling fallback, cursor reset, service unavailable, and last successful update.
- Permit deliberate reconnect/reset/polling-fallback diagnostics without exposing internal credentials.
- Escape all server-provided metadata and never render it as trusted HTML, CSS, URL, or script.
- Provide responsive, keyboard-accessible presentation with clear empty/loading/error states.
- Keep joining and gameplay out of the page unless a future consumer-specific deep link is explicitly designed.
- Deploy as optional static assets or a separate static container/profile; production operators may disable it completely.
- Use an allow-listed configuration rather than accepting arbitrary backend URLs that could turn the page into an SSRF/open-proxy aid.
## Grafana dashboards
Commit version-controlled provisioning/dashboard definitions covering:
- HTTP availability, request rate, latency, errors, timeouts, and rate-limit rejections;
- active/awaiting/stale listings, lease renewal/expiry churn, and browser snapshot/SSE subscriber counts;
- join issuance, active attempts, endpoint binding, pairing latency, introduction outcomes, reported direct outcomes, and typed failures;
- UDP packets/bytes accepted and dropped, malformed/replay/limited traffic, response amplification budget, queue depth, and saturation;
- process CPU, memory, GC, threads, sockets, and graceful-drain status;
- shared-store health/latency only when a shared store is enabled;
- key-expiry/configuration health and security/audit event rates;
- supported/capacity profile overlays and recommended alert thresholds.
Use only low-cardinality tenant/environment/region/outcome dimensions approved by #16. Never use session IDs, attempt IDs, tokens, metadata, or raw IP addresses as labels.
## Security and privacy boundaries
- The diagnostic dashboard calls public read-only browse/SSE APIs only.
- No operator credential, publisher credential, lease capability, punch capability, connection ticket, raw endpoint, or secret is stored in browser state or returned to it.
- Apply a restrictive Content Security Policy, safe CORS policy, clickjacking protection, MIME-type protection, and dependency minimization.
- Public dashboard enablement, allowed games/environments, and rate limits are explicit configuration.
- Grafana access and datasource credentials remain operator-controlled and are not proxied through the public dashboard.
- Diagnostic and Grafana logs/telemetry follow the retention/redaction policy from #2/#16.
## Acceptance criteria
- A user can open the diagnostic page, filter sessions, and see live add/update/remove changes without manual refresh.
- Disconnect, SSE cursor gap, server restart, and unsupported streaming fall back or reset cleanly without leaving a false/stale “live” state.
- The final client projection matches a fresh server snapshot after every tested event sequence.
- Malicious metadata regression cases cannot inject markup/script/style/navigation or corrupt the page.
- Cross-game/environment/protocol/visibility isolation is preserved.
- The dashboard never receives or exposes raw endpoints or credentials.
- Slow event bursts are coalesced/rendered without unbounded DOM growth, memory use, or flicker.
- Keyboard navigation, focus visibility, semantic labels, contrast, loading, empty, and error states pass the chosen accessibility gate.
- Grafana provisioning loads from a clean Compose/deployment environment with no manual panel construction.
- Grafana panels populate during the three-party/TestClient scenario and abusive-load tests.
- Dashboard queries and labels remain bounded/low-cardinality and contain no secrets or personal endpoint data.
- Both dashboards are optional, documented, and independently disableable.
- Security tests verify CSP/CORS/headers and prove the page has no privileged administration path.
Starting implementation on codex/issue-27-diagnostic-dashboards from verified issue #26. Scope will preserve the public read-only diagnostic/operator Grafana separation, use build-light static assets, add explicit security and low-cardinality boundaries, and verify WCAG 2.2 AA plus clean provisioning.
Starting implementation on `codex/issue-27-diagnostic-dashboards` from verified issue #26. Scope will preserve the public read-only diagnostic/operator Grafana separation, use build-light static assets, add explicit security and low-cardinality boundaries, and verify WCAG 2.2 AA plus clean provisioning.
Implemented and verified in 99885f8 (codex/issue-27-diagnostic-dashboards).
Delivered:
optional same-origin, read-only /diagnostics static dashboard using the public bounded browse + SSE contracts only;
explicit game/environment/protocol/region/capacity selection with fixed public visibility, safe public projection rendering, deterministic add/update/remove/reset handling, deliberate reconnect/reset/poll-only diagnostics, bounded DOM/projection state, and polling fallback;
restrictive CSP, clickjacking/MIME/referrer/browser-capability protections, no CORS relaxation, no privileged path or browser credential state, and disabled-by-default allowlisted configuration;
bearer-protected, disabled-by-default Prometheus exporter with bounded privacy-safe labels and store/SSE/HTTP/UDP/join/outcome/security/key/process/.NET metrics;
clean merged Compose startup provisioned Prometheus/Grafana without manual construction; unauthenticated /metrics returned 404, anonymous Grafana API returned 401, Prometheus had no published host port;
live target up=1, store available, and process metrics populated; Grafana rendered UP / AVAILABLE / ACCEPTING and the capacity panels;
real smoke-deployment.sh three-party scenario passed and populated registration, browse/join issuance, presence, waiting-for-peer, introduction, connected outcome, pairing latency, and UDP byte series;
bounded low-limit abusive burst populated rendezvous_limiter_drops_total{transport="udp",partition="rate-or-concurrency"}=860 while target health remained up=1;
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Parent: #1
Depends on: #16, #17, #26
Priority: nice-to-have; not a Rendezvous v1 release gate
Outcome
Provide two deliberately separate views of Rendezvous:
This issue does not create a privileged administration web UI. Revocation, key management, tenant configuration, and other destructive operations remain in the authenticated operator CLI/API from #16.
Diagnostic dashboard
Build a minimal static web application with no game or server authority. Prefer plain standards-based HTML/CSS/JavaScript or another build-light static approach unless a heavier framework is justified.
Scope
session_upsert,session_remove, andresetdeterministically.Grafana dashboards
Commit version-controlled provisioning/dashboard definitions covering:
Use only low-cardinality tenant/environment/region/outcome dimensions approved by #16. Never use session IDs, attempt IDs, tokens, metadata, or raw IP addresses as labels.
Security and privacy boundaries
Acceptance criteria
Starting implementation on
codex/issue-27-diagnostic-dashboardsfrom verified issue #26. Scope will preserve the public read-only diagnostic/operator Grafana separation, use build-light static assets, add explicit security and low-cardinality boundaries, and verify WCAG 2.2 AA plus clean provisioning.Implemented and verified in
99885f8(codex/issue-27-diagnostic-dashboards).Delivered:
/diagnosticsstatic dashboard using the public bounded browse + SSE contracts only;Observed acceptance evidence:
default-src 'none'/ same-origin connect/script/style,DENY,nosniff,no-referrer, COOP/CORP, permissions disabled,no-store;/metricsreturned 404, anonymous Grafana API returned 401, Prometheus had no published host port;up=1, store available, and process metrics populated; Grafana rendered UP / AVAILABLE / ACCEPTING and the capacity panels;smoke-deployment.shthree-party scenario passed and populated registration, browse/join issuance, presence, waiting-for-peer, introduction, connected outcome, pairing latency, and UDP byte series;rendezvous_limiter_drops_total{transport="udp",partition="rate-or-concurrency"}=860while target health remainedup=1;