Skip to content

Charging dashboard (Slack TUI) + reconcile main→dev keeping Constellation#71

Merged
haoruizhou merged 44 commits into
devfrom
pecan-dev-charging
Jun 4, 2026
Merged

Charging dashboard (Slack TUI) + reconcile main→dev keeping Constellation#71
haoruizhou merged 44 commits into
devfrom
pecan-dev-charging

Conversation

@wfr-data-acquisition
Copy link
Copy Markdown
Contributor

@wfr-data-acquisition wfr-data-acquisition commented Jun 4, 2026

What this is

Two things bundled because the feature is built on main and dev was ~20 commits behind:

  1. Charging dashboard feature (the actual new work)
  2. main → dev reconciliation — brings main's line onto dev while keeping all the Constellation work (merged origin/dev, clean auto-merge, no textual conflicts).

Heads-up for reviewers: this is large (~112 files) because it carries main's accumulated commits (installer, daily-report, dep bumps) onto dev. The charging feature itself is the focused part listed below.

Charging dashboard

A single self-updating Slack message (post once, chat.update every 5s, like the file-uploader) showing accumulator charge state while charging via the Kvaser bridge on the internal pecan-dev (VITE_INTERNAL) build, behind Cloudflare Zero Trust.

Bot (server/installer/slackbot/)

  • charge_dashboard.py — TUI renderer (SoC bar, pack/cell/temp/alert lines, per-module sparkline + stats), per-session manager, stdlib HTTP receiver (POST /charging/state, shared-token auth), heartbeat staleness.
  • soc_model.pydata-derived SOC/ETA from the wfr26 audit. Key finding: PackCurrent and BMS SOC are dead sentinels and PackVoltage is absent, so SOC is an OCV→SOC lookup on the limiting cell, ETA integrates a CV taper, and phase is inferred from the voltage trend.
  • Wired into slack_bot.py __main__; compose port/env (CHARGE_DASHBOARD_PORT, CHARGE_RELAY_TOKEN); Dockerfile.

Pecan

  • lib/chargingSnapshot.ts — pure, mockable snapshot builder mirroring the accumulator page; sentinel-guards the dead signals; derives pack voltage from the series-cell sum.
  • lib/useChargingDashboard.ts — 5s poster, gated on VITE_INTERNAL + live Kvaser source (:9081). Never broadcasts the demo relay or replay data.

Safety: no demo data to Slack

isKvaserSource() returns true only for the Kvaser bridge :9081, hard-excludes ws-demo.westernformularacing.org, and tick() bails on non-live (replay) data. Covered by tests.

Tests

  • 17 slackbot unittests (renderer, formatters, session post-then-update, HTTP auth, SOC/ETA model).
  • 15 Pecan vitest (aggregation, alert chips, dead-signal guards, broadcast gate).
  • Post-merge validation: tsc clean; charging + Constellation suites pass.

Follow-ups

  • Re-fit the CV taper / capacity once a real charge session is logged (none exist on-log today).
  • Fixing the PackStatus CAN decode (the -3276 / 0 sentinels) would unlock real coulomb counting + direct SOC.

haoruizhou and others added 30 commits May 2, 2026 16:46
Update status page to visually pulse the newest column when the health mosaic advances and add a unit test for the behavior.
DBC and Dynamic y axis selection
Overlay speed calculation updated to derive vehicle speed from wheel RPM using gear ratio and wheel radius (replaces naive rpm/500). Telemetry-store rpm/motor_speed signal aliases switched to INV_Fast_Motor_Speed. universal-telemetry-software: add missing_seq_seconds to track when gaps occurred, clear on sequence reset, cap removal of oldest missing entries, record recovery timestamps and use them to mark per-second status correctly, and use a robust TCP read loop that accumulates all chunks.
Add a Cloudflare Wrangler/Durable-Object relay backend under flight-recorder/relay-worker (package.json, src/index.ts, tsconfig.json, wrangler.toml) and a README describing deployment and usage as an optional public live-relay for remote viewers. Update flight-recorder documentation and top-level README to mark the app as internal (protected by Cloudflare Zero Trust), clarify store-and-forward behavior, relationship to the old lte-relay approach, optional live-relay semantics (public/tokenless worker, 1 Hz synthetic heartbeat, demo-source behavior), and DBC access/build notes. Also add a LiveRelayService and update WebSocketService and App.tsx to expose guarded controls for WS Relay vs DB forward so live relay can be used independently of database sync.
TelemetryHandler: treat both UTS (1999) and flight-relay (0x7FD) CAN IDs as diagnostic heartbeats and ingest them under DIAG_MSG_IDS.HEARTBEAT. RadioStatChips now uses the DIAG_MSG_IDS constant instead of a hardcoded '1999' string. Added TelemetryHandler tests to assert UTS and relay heartbeat frames are routed to the heartbeat diagnostic message. LiveRelayService: strip search and hash when building the /session URL to avoid stale query/hash data; updated its test to stub global fetch and ensure sessions can be created from older ingest URLs. Misc: test cleanup unstubs globals after each run.
Integrate Flight Recorder relay workflow
Introduce a unified system health endpoint and UI backed by an atomic health snapshot.

- README and MACBOOK_DEPLOY: document the new /health endpoint and troubleshooting steps.
- src/data.py: add HEALTH_FILE env var; compute detailed health snapshot (components, timescale, redis, UDP listener, car state, version, clock, stats); perform Redis ping and timescale parsing; record uptime and UDP listener bound state; write snapshot atomically to HEALTH_FILE.
- src/status_server.py: add /health handler, helpers to load, finalize and synthesize unknown/stale health payloads, and mark stale snapshots when producer_ts is old; introduce HEALTH_STALE_SECONDS config.
- status/index.html: replace pipeline WebSocket-driven status with polling /health, add system health UI (CSS/JS) and rendering logic, update metrics/status text and polling cadence.
- tests/test_status_server.py: add tests for loading valid, missing, malformed and stale health snapshots and retain 404 test for unknown endpoints.

This change enables a simple JSON health probe for monitoring and makes the status page reflect aggregated infrastructure state even when the car is powered off.
Switch MacBook deployment to use the committed deploy/.env.macbook via --env-file and make TimescaleDB, media, and cloudflared optional Docker Compose profiles. Add ENABLE_TIMESCALE_LOGGING (default false) to the env file and update docker-compose.macbook-base.yml to honor the env file and include profiles for timescale/media/tunnel. Update docs (top-level README, universal-telemetry-software/README.md, MACBOOK_DEPLOY.md, WHICH_ONE.md, and offline README) to describe the new minimal default stack, show example profile commands, and note which images are optional for offline saves.
Introduce an "auto" mode for ENABLE_TIMESCALE_LOGGING so the service will probe the configured POSTGRES_DSN and enable the Timescale writer only when the DB is reachable.
…version before notifyAll so subscribers see correct version. (#68)
Track WebSocket bridge client counts through Redis as total, internal, and external clients. Treat loopback connections such as the local relay upstream as internal so the status page does not count them as dashboard viewers.

Refresh the count periodically while the bridge is running, preventing the health snapshot from falling back to "Client count unavailable" after the Redis key expires. Update the status UI to show external/internal counts and add focused regression coverage.
Add a new GitHub Actions job (macbook-lan-sender) to smoke-test the MacBook one-click stack using deploy/docker-compose.macbook-base.yml. The job loads built Docker images, pulls base images, sets up Python, brings up the MacBook stack, starts lan_sender inside the telemetry container, runs pytest against a new test file, and collects/logs artifacts on failure. Also add tests/universal-telemetry-software/tests/test_macbook_base_lan_sender.py which exercise container health, status page, PECAN, telemetry logs, WebSocket CAN messages, and health metrics. Update CI compose validation to include the macbook compose file and add the new job as a dependency for publish-telemetry.
Add full Linux support and an interactive --hotspot mode to the one-line base-station installer; keep macOS support. The installer now bootstraps git and Docker on Debian/Ubuntu/Raspberry Pi OS, can enable a NetworkManager-based Wi‑Fi AP (wfr-hotspot) and installs a systemd unit for it. CI workflow updated to validate compose from the repo root and run a linux e2e job that syntax-checks the script, validates compose, runs the installer, asserts core containers, checks service ports, verifies idempotency, and ensures non-interactive hotspot behaviour. Documentation (README and MACBOOK_DEPLOY.md) and WHICH_ONE.md updated with Linux/RPi instructions and hotspot notes. Fix .env macbook DBC_HOST_PATH to be repo-root relative and add wfr-hotspot.service file.
haoruizhou and others added 11 commits May 29, 2026 00:36
Adds !stats command and a 9 AM ET daily auto-post showing rows logged,
CAN message count, and testing duration for yesterday and the past 7
days. Pulls from TimescaleDB wfr26 and monitoring tables directly.
Also adds psycopg2-binary to slackbot requirements.
…-branch slicks API

- Use generic placeholders (<season_table>, <signal_1>, etc.) instead of
  team-specific table and signal names so the example is shareable.
- Drop the 'monitoring table holds infra metrics' note (team-internal).
- Drop the verified Grafana query patterns section (team-internal sensor
  lists and table names).
- Update env-var references: TIMESCALE_TABLE (with TIMESCALE_SEASON
  fallback) replaces POSTGRES_TABLE; remove INFLUX_* references.
- Update slicks examples to match the merged main API:
    * discover_sensors() now requires start_time and end_time
    * connect_timescaledb() now has (dsn, schema, table) signature
    * env-var auto-connect note uses POSTGRES_DSN + TIMESCALE_TABLE
- Same overall structure as the active (gitignored) prompt-guide.txt,
  but generic.
Sandbox slicks wiring (matches the slicks v0.3.0 TimescaleDB backend on
the timescaledb-migration branch that was merged to main):

- server/installer/sandbox/Dockerfile.sandbox: install uv, then use it
  for both requirements-docker.txt and the editable slicks install from
  /slicks_src (a docker compose additional_context pointing at the
  sibling slicks checkout). uv keeps the image layer smaller than pip
  and the install deterministic. Added a build-time smoke test that
  imports slicks to catch future regressions early.

- server/installer/docker-compose.yml:
  * sandbox service: pass slicks source as a build-time additional_context
    and bind-mount the same path at runtime so live source edits are
    picked up on the next container recreate without an image rebuild
    (controlled by SLICKS_HOST_PATH env var, default points at
    /home/ubuntu/projects/slicks).
  * sandbox service: export POSTGRES_DSN, TIMESCALE_TABLE,
    TIMESCALE_SEASON, and POSTGRES_TABLE so slicks auto-connects on
    import. The published PyPI slicks (0.2.3) is the InfluxDB backend
    and would not be importable as TimescaleDB-aware code; install from
    local source instead.

- server/installer/sandbox/requirements-docker.txt: drop the
  'slicks>=0.2.0' PyPI pin. Slicks is now installed editable from the
  local source above; the pin was pulling the InfluxDB-only release.

- server/installer/sandbox/requirements.txt: add psycopg2-binary
  (slicks depends on it; listing explicitly so the layer order is
  stable across slicks extras changes).

Code-generator Dockerfile fix:

- server/installer/sandbox/Dockerfile: the previous version only COPY'd
  prompt-guide.txt.example, so the active (gitignored) prompt-guide.txt
  was silently being ignored at every build. Switched to COPY
  prompt-guide.txt* ./ (with the existing fallback to copy the example
  when the active file is missing). This restores the team's
  customization workflow where the active prompt-guide lives in the
  build context and gets shipped to the container.

Model bump:

- server/installer/.env.example: ANTHROPIC_MODEL default MiniMax-M2.7
  -> MiniMax-M3.
- server/installer/sandbox/code_generator.py: same bump in the
  os.getenv default so a missing env var falls back to M3.

Tested end-to-end: code-generator /api/generate-code returns
result.status=success with a PNG, slicks.fetch_telemetry() returns
407k rows from a real TimescaleDB window, and the slackbot -> code-gen
-> sandbox chain still works.
Adds an npm 'overrides' block to the root package.json to force
patched versions of five transitive dependencies that had
Dependabot alerts:

  lodash               -> ^4.18.0   (CVE-2026-4800, CVE-2026-2950)
  qs                   -> ^6.15.2   (CVE-2026-8723)
  picomatch            -> ^2.3.2    (CVE-2026-32233)
  fast-uri             -> ^3.1.2    (CVE-2026-6321, CVE-2026-6322)
  serialize-javascript -> ^7.0.5    (CVE-2026-34043)

Regenerated package-lock.json with 'npm install --package-lock-only'
(no node_modules write, no network risk beyond what 'install' needs
to resolve). Verified the lock now pins:
  picomatch 2.3.2
(remaining 4 packages aren't pulled into this lock).
…in CVEs

react-router was a direct dep pinned at ^7.9.3; multiple CVEs (DoS via
path expansion, RCE via turbo-stream, XSS via redirects) require
>= 7.15.0. Bumping the direct dep range is cleaner than an override
(npm errors out on an override that conflicts with a direct dep).

Also adds an npm 'overrides' block to force patched transitive deps:

  lodash               -> ^4.18.0
  qs                   -> ^6.15.2
  picomatch            -> ^2.3.2
  fast-uri             -> ^3.1.2
  serialize-javascript -> ^7.0.5

Regenerated package-lock.json. Verified the lock now pins:

  lodash                4.18.1
  qs                    6.15.2
  picomatch             2.3.2
  fast-uri              3.1.2
  serialize-javascript  7.0.5
  react-router          7.16.0
react-router-dom was a direct dep pinned at ^7.9.3; same CVE class as
pecan's react-router (DoS, RCE, XSS via redirects) requires >= 7.15.0.
Bumped the direct dep range.

Also adds an npm 'overrides' block to force patched transitive deps:

  lodash               -> ^4.18.0
  qs                   -> ^6.15.2
  picomatch            -> ^2.3.2
  fast-uri             -> ^3.1.2
  serialize-javascript -> ^7.0.5

Regenerated package-lock.json. Verified the lock now pins:

  lodash                4.18.1
  picomatch             2.3.2
  fast-uri              3.1.2
  serialize-javascript  7.0.5
  react-router-dom      7.16.0
grafana-bridge is a minimal Express app (single dep) but still pulls
in the same vulnerable transitive packages. Adds an 'overrides'
block to force patched versions:

  lodash               -> ^4.18.0
  qs                   -> ^6.15.2
  picomatch            -> ^2.3.2
  fast-uri             -> ^3.1.2
  serialize-javascript -> ^7.0.5

Regenerated package-lock.json. Verified qs pinned at 6.15.2.
wfr-data-acquisition and others added 2 commits June 4, 2026 15:57
Adds a charging dashboard that posts one self-updating Slack message
(post once, chat.update every 5s, like the file-uploader) while charging
the accumulator via the Kvaser bridge on the internal (pecan-dev) build.

Bot (server/installer/slackbot):
- charge_dashboard.py: TUI renderer (SoC bar, pack/cell/temp/alert lines,
  per-module sparkline + stats), per-session manager, stdlib HTTP receiver
  (POST /charging/state behind CF Zero Trust + shared-token auth), heartbeat
  staleness.
- soc_model.py: data-derived SOC/ETA from the wfr26 audit. PackCurrent/BMS
  SOC are dead sentinels and PackVoltage is absent, so SOC is an OCV->SOC
  lookup on the limiting cell and ETA integrates a CV taper; phase is from
  the voltage trend.
- Wired into slack_bot.py __main__; compose port/env; Dockerfile.
- unittests: 17 (renderer, formatters, session updates, HTTP auth, model).

Pecan:
- chargingSnapshot.ts: pure, mockable snapshot builder mirroring the
  accumulator page; sentinel-guards the dead signals; derives pack voltage
  from the series-cell sum.
- useChargingDashboard.ts: 5s poster, gated on VITE_INTERNAL + live Kvaser
  source (:9081). Never broadcasts the demo relay or replay data.
- vitest: 15 (aggregation, alert chips, dead-signal guards, broadcast gate).

Co-authored-by: Haorui Zhou <[email protected]>
Reconciles main's line + the charging-dashboard feature with dev's
Constellation work, keeping the Constellation changes. Clean auto-merge
(no textual conflicts); validated post-merge: tsc clean, 34 tests pass
(17 slackbot + 15 charging + 2 constellation).

Co-authored-by: Haorui Zhou <[email protected]>
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR introduces an internal-only “charging dashboard” that relays accumulator charging snapshots from Pecan to a Slackbot-rendered, self-updating Slack message, while also bringing dev up to date with main (plus a broad set of deployment/health/testing improvements across UTS, server stack, and tooling).

Changes:

  • Adds a Pecan → Slackbot charging snapshot pipeline (5s posting loop, snapshot builder, Slack TUI renderer/HTTP receiver, and tests), gated to internal builds and live Kvaser data only.
  • Implements/extends unified health reporting for UTS (new /health endpoint consumer + WS client counting + Timescale status publishing) and adds LAN-sender based integration tests and compose targets.
  • Updates deployment docs/compose files/workflows across UTS + server installer, and adds Flight Recorder live relay (Cloudflare Worker + client relay service).

Reviewed changes

Copilot reviewed 104 out of 112 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
WEBSOCKET_PROTOCOL.md Updates protocol documentation for role-specific uplink paths and statuses.
universal-telemetry-software/WEBSOCKET_RUNTIME_NOTES.md Adds runtime/deployment-only notes to keep protocol spec canonical.
universal-telemetry-software/tests/test_websocket_client_count_health.py Adds unit tests for WS client count snapshot + Redis encoding.
universal-telemetry-software/tests/test_status_server.py Adds tests for health snapshot loading/staleness behavior.
universal-telemetry-software/tests/test_status_mosaic.py Adds JS-level test for status page mosaic timer behavior.
universal-telemetry-software/tests/test_macbook_base_lan_sender.py Adds smoke tests for the MacBook base stack using LAN sender traffic.
universal-telemetry-software/tests/test_lan_sender.py Adds base-only integration tests using lan_sender.py fake car.
universal-telemetry-software/src/websocket_bridge.py Publishes WS client counts to Redis for health reporting; adds periodic refresher.
universal-telemetry-software/src/timescale_bridge.py Publishes periodic Timescale status into Redis with a shared payload helper.
universal-telemetry-software/src/status_server.py Adds /health endpoint backed by a health snapshot file + staleness logic.
universal-telemetry-software/src/redis_utils.py Adds Redis connection retries with exponential backoff.
universal-telemetry-software/src/lan_sender.py Adds fake-car UDP sender for stack testing without hardware.
universal-telemetry-software/src/config.py Adds REDIS_WS_CLIENTS_KEY constant.
universal-telemetry-software/README.md Updates architecture/deploy/monitoring docs including /health.
universal-telemetry-software/main.py Adds Timescale “auto” enable mode with DSN reachability probe.
universal-telemetry-software/lan_sender.sh Adds wrapper script to run LAN sender without venv activation.
universal-telemetry-software/Dockerfile Adds lan_sender.sh into the image.
universal-telemetry-software/deploy/WHICH_ONE.md Updates guidance on which deploy targets to use (car systemd vs base compose).
universal-telemetry-software/deploy/wfr-hotspot.service Adds systemd unit to enable a base-station Wi-Fi hotspot.
universal-telemetry-software/deploy/offline/README.md Updates offline bundle instructions/images for new repo naming and profiles.
universal-telemetry-software/deploy/MACBOOK_DEPLOY.md Refactors base station setup docs; adds installer + /health guidance.
universal-telemetry-software/deploy/docker-compose.staging.yml Updates GHCR image paths for staging.
universal-telemetry-software/deploy/docker-compose.rpi-base.yml Updates GHCR image paths for RPi base.
universal-telemetry-software/deploy/docker-compose.macbook-base.yml Refactors MacBook base stack into profiles; updates GHCR image paths.
universal-telemetry-software/deploy/docker-compose.lan-sender-test.yml Adds compose stack for LAN sender integration testing.
universal-telemetry-software/deploy/ci-validate-compose.py Adds CI validation to ensure compose structure + no local build: directives.
universal-telemetry-software/deploy/CAR_DEPLOY.md Updates car deployment docs for new repo pathing.
universal-telemetry-software/deploy/.env.macbook Commits safe MacBook LAN defaults and profile guidance.
universal-telemetry-software/conftest.py Adjusts pytest pathing for cone-detection dependency.
universal-telemetry-software/checklist/SETUP_CARD.tex Updates setup card paths to new repo naming.
server/installer/VPS_RECOVERY.md Updates recovery paths and clarifies lap-detector status.
server/installer/slackbot/test_soc_model.py Adds unit tests for derived SOC/ETA model.
server/installer/slackbot/test_charge_dashboard.py Adds unit tests for Slack charging dashboard renderer/session/HTTP auth.
server/installer/slackbot/slack_bot.py Wires in charge dashboard HTTP receiver + new stats reporting + daily scheduler.
server/installer/slackbot/requirements.txt Adds psycopg2-binary for DB-backed stats reporting.
server/installer/slackbot/Dockerfile Copies charge dashboard + SOC model sources into the image.
server/installer/sandbox/requirements.txt Adds psycopg2-binary to sandbox deps.
server/installer/sandbox/requirements-docker.txt Adjusts sandbox deps/comments; makes DB deps explicit.
server/installer/sandbox/rag_viz.py Adds RAG vector visualization script.
server/installer/sandbox/Dockerfile.sandbox Switches to uv, supports editable slicks install via additional context.
server/installer/sandbox/Dockerfile Ensures prompt-guide customization is copied correctly; adds anomaly_scan.py.
server/installer/sandbox/code_generator.py Updates default model to MiniMax-M3.
server/installer/README.md Minor wording updates (lap-detector status).
server/installer/LOCAL_STACK.md Updates backup script path references.
server/installer/grafana-bridge/package.json Adds dependency overrides for transitive security bumps.
server/installer/grafana-bridge/package-lock.json Updates locked transitive versions (e.g., qs).
server/installer/docker-compose.yml Adds charge dashboard port/token env + sandbox slicks additional context + model update.
server/installer/data-downloader/frontend/src/components/data-download.tsx Adds theme-aware Plotly styling.
server/installer/data-downloader/frontend/src/App.tsx Adds theme toggle + persists theme selection; wires theme into chart.
server/installer/data-downloader/frontend/index.html Applies theme pre-paint to avoid flash.
server/installer/data-downloader/backend/services.py Adds Timescale lag freshness check for newest season table.
server/installer/data-downloader/backend/app.py Adds /api/timescale-health endpoint; extends base healthcheck fields.
server/installer/backup-dashboards.py Updates backup script path references.
server/installer/.env.example Updates default AI model name.
server/docs/containers/lap-detector.md Marks lap-detector as intentionally disabled/tabled.
pecan/test-gh-pages.js Updates GH Pages base path to new repo name.
pecan/src/vite-env.d.ts Adds env vars for charge relay URL/token.
pecan/src/services/WebSocketService.ts Prefers localhost WS on localhost pages; improves failover ordering.
pecan/src/services/WebSocketService.test.ts Adds test for localhost-first WS candidate ordering.
pecan/src/services/TelemetryHandler.ts Treats relay heartbeat CAN ID as diagnostic heartbeat (not telemetry).
pecan/src/services/TelemetryHandler.test.ts Adds tests for heartbeat routing for both UTS + relay heartbeat IDs.
pecan/src/pages/Trace.tsx Removes redundant memoization in trace enrichment path.
pecan/src/pages/Accumulator.tsx Starts charging dashboard relay hook on accumulator page.
pecan/src/lib/useDataStore.ts Adds version-based gating for map rebuild + batches cold-state updates.
pecan/src/lib/useChargingDashboard.ts Adds internal-only charging snapshot poster (Kvaser/live-gated).
pecan/src/lib/useChargingDashboard.test.ts Adds tests for demo-host exclusion + Kvaser-only gating.
pecan/src/lib/DataStore.ts Adds version counter + reduces allocations when rounding is a no-op.
pecan/src/lib/DataStore.test.ts Adds tests for version counter and rounding/immutability expectations.
pecan/src/lib/chargingSnapshot.ts Adds snapshot builder with sentinel guards + derived pack voltage.
pecan/src/lib/chargingSnapshot.test.ts Adds tests for aggregation, alerts, sentinel guards.
pecan/src/components/SettingsModal.tsx Adds setting for plot axis range source selection (DBC vs dynamic).
pecan/src/components/PlotManager.tsx Uses the stored plot axis range source to enable/disable DBC ranges.
pecan/src/components/comms/RadioStatChips.tsx Switches heartbeat tracking to diagnostic heartbeat ID constant.
pecan/README.md Updates connection defaults (localhost WS on localhost).
pecan/package.json Bumps react-router; adds dependency overrides.
pecan/package-lock.json Updates lockfile for dependency bumps/overrides.
package.json Adds dependency overrides at repo root.
package-lock.json Updates root package name + dependency lock changes.
livestream/src/widgets.jsx Removes motor-temp warning chip.
livestream/src/telemetry-store.jsx Updates signal aliases and adds additional telemetry signals.
livestream/src/overlays.jsx Updates overlay stats (dc bus/temps) and improves speed calculation.
flight-recorder/src/services/WebSocketService.ts Emits raw “wire” frames to listeners (for relay forwarding).
flight-recorder/src/services/LiveRelayService.ts Adds best-effort live relay forwarding + synthetic heartbeat injection.
flight-recorder/src/services/LiveRelayService.test.ts Adds tests for session creation, heartbeat, and demo-source blocking.
flight-recorder/relay-worker/wrangler.toml Adds Wrangler config for relay worker + DO binding/migration.
flight-recorder/relay-worker/tsconfig.json Adds strict TS config for the worker.
flight-recorder/relay-worker/src/index.ts Implements Worker + Durable Object WS relay with session creation endpoint.
flight-recorder/relay-worker/README.md Documents relay worker usage, URLs, and security model.
flight-recorder/relay-worker/package.json Adds Wrangler/TS dev setup for the worker.
flight-recorder/README.md Documents Flight Recorder workflow and optional live relay architecture.
flight-recorder/package.json Adds test script; bumps react-router-dom; adds overrides.
AGENTS.md Adds repo-wide agent orientation + canonical docs pointers.
.hermes/plans/2026-05-21_124500-unified-health-endpoint.md Adds design plan for unified health endpoint rollout.
.gitignore Updates workspace ignore name and server section header.
.github/workflows/telemetry-ci.yml Adds macbook compose validation + LAN sender test jobs and gating.
.github/workflows/slackbot-ci.yml Adds Slackbot CI (ruff + import smoke test + docker build).
.github/workflows/package-cleanup.yml Expands GHCR package cleanup targets.
.github/workflows/offline-bundle.yml Updates offline bundle image names to new GHCR paths.
.github/workflows/macbook-installer-ci.yml Adds installer CI (shellcheck, macOS logic smoke test, Linux e2e).
Files not reviewed (4)
  • flight-recorder/package-lock.json: Language not supported
  • flight-recorder/relay-worker/package-lock.json: Language not supported
  • pecan/package-lock.json: Language not supported
  • server/installer/grafana-bridge/package-lock.json: Language not supported

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +65 to +82
async def _publish_client_count() -> None:
"""Publish the current WebSocket client count for the HTTP health snapshot."""
try:
r = redis.from_url(REDIS_URL)
await r.set(REDIS_WS_CLIENTS_KEY, json.dumps(_client_count_snapshot()), ex=10)
await r.aclose()
except Exception as e:
logger.debug("Could not publish WebSocket client count: %s", e)


async def _client_count_publisher() -> None:
"""Keep the health snapshot client count fresh even when no clients churn."""
while not shutdown_event.is_set():
await _publish_client_count()
try:
await asyncio.wait_for(shutdown_event.wait(), timeout=2.0)
except asyncio.TimeoutError:
pass
Comment on lines +18 to +25
"""Return a connected synchronous Redis client, retrying on failure.

Args:
url: Redis connection URL.
retries: Maximum connection attempts before giving up (default 10).
backoff: Seconds to wait between retries, multiplied by 1.5 each attempt.
With default values: ~25s total (1+1.5+2.25+3.375+...).
"""
Comment on lines +16 to +24
environment:
- ROLE=base
- REMOTE_IP=127.0.0.1 # Will be overridden by lan_sender — base listens on all interfaces
- UDP_PORT=5005
- TCP_PORT=5006
- REDIS_URL=redis://base-redis:6379/0
- TIMESCALE_TABLE=wfr26
- ENABLE_TIMESCALE_LOGGING=true
depends_on:
Comment on lines +849 to +856
from charge_dashboard import ChargeDashboard, start_http_server
_charge_dash = ChargeDashboard(web_client, DEFAULT_CHANNEL)
start_http_server(
_charge_dash,
port=int(os.environ.get("CHARGE_DASHBOARD_PORT", "9099")),
token=os.environ.get("CHARGE_RELAY_TOKEN") or None,
)
except Exception as e:
- slackbot-ci: stub SocketModeRequest/Response on the slack_sdk stub modules
  (import was failing with 'cannot import name SocketModeRequest') and
  provision /app/logs so the module-level mkdir doesn't fail on the runner.
- slack_bot: require CHARGE_RELAY_TOKEN before starting the charge-dashboard
  receiver; the port is host-published and must not accept unauthenticated POSTs.
- docker-compose.lan-sender-test: set POSTGRES_DSN to the timescaledb service
  (default DSN points at localhost, which is the base container here).
- websocket_bridge: aclose the Redis client via try/finally so a failing set
  doesn't leak the connection.
- redis_utils: correct get_sync_client docstring (default retries=5, ~8s).
@haoruizhou haoruizhou merged commit 726ac36 into dev Jun 4, 2026
10 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants