fix(dashboard): repair busted render — stale CSS, dead cards, wrong status#128
Open
BrettKinny wants to merge 1 commit into
Open
fix(dashboard): repair busted render — stale CSS, dead cards, wrong status#128BrettKinny wants to merge 1 commit into
BrettKinny wants to merge 1 commit into
Conversation
…tatus Five dashboard defects fixed: 1. State-card ballooning sparkline / giant gaps. The vendored tailwind.min.css was stale (Apr 28) vs. later template edits, so `.h-6`, `.border-t`, `.py-1.5`, `.break-all` were absent. With `.h-6` missing the sound-balance SVG (viewBox 0 0 100 24, flex-1, no height bound) stretched to ~140px via its intrinsic aspect ratio. Rebuilt the CSS from current templates and updated the SRI integrity hash. 2. Robot status dot showed grey "offline" when the robot was online but simply hadn't had a voice turn today. Now treats a fresh (non-stale) perception device as online — perception liveness is the real connectivity signal; voice idleness is normal. 3. Version chip showed "vunknown" — the container has no .git checkout and the deploy never stamped a version. Added a BRIDGE_VERSION Docker build-arg (writes /app/.bridge-version); deploy-bridge-unraid.sh passes the HEAD short SHA. 4. Removed the Discord daemon card. It queried `systemctl zeroclaw-discord` locally — impossible inside the Unraid bridge container; ZeroClaw was retired in #36. Dropped the route, template, helper, and card section. 5. Smart Mode card advertised a model swap (claude-sonnet / mistral) that only fires on the retired tier1slim path. Relabeled to honest behaviour on the default PiVoiceLLM path ("Robot smart-mode pip … · model-swap pending (v2)"); still shows the swap on tier1slim deployments. Also switched the page to natural document scroll (was a single-screen overflow:hidden layout that pushed cards/feed below an unreachable fold); the feed now caps at 70vh and scrolls internally. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
This PR fixes several dashboard rendering and status issues in the dotty-bridge FastAPI dashboard, including stale CSS output, incorrect robot liveness display, missing deployed version metadata, and removal of a retired Discord daemon card.
Changes:
- Rebuilds vendored Tailwind CSS and updates the SRI hash.
- Removes the obsolete
/ui/discordcard/route/helper. - Updates dashboard layout, status-strip liveness logic, version stamping, and Smart Mode display behavior.
Reviewed changes
Copilot reviewed 6 out of 7 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
scripts/deploy-bridge-unraid.sh |
Passes the current short Git SHA into the Docker build. |
bridge/Dockerfile |
Writes the build-provided bridge version to /app/.bridge-version. |
bridge/dashboard.py |
Removes Discord status support and updates Smart Mode/status-strip context logic. |
bridge/templates/dashboard.html |
Updates CSS integrity, natural page scrolling, and removes Discord card markup. |
bridge/templates/smart_mode.html |
Shows different Smart Mode copy depending on whether model swap is active. |
bridge/templates/discord.html |
Deletes the retired Discord daemon partial. |
bridge/static/tailwind.min.css |
Rebuilt bundled Tailwind/DaisyUI stylesheet. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| # the swap is v2 scope (docs/cutover-behaviour.md) — toggling smart_mode | ||
| # only lights the robot's smart-mode LED pip + persists the flag. Mirror | ||
| # bridge.py's env so the card describes what actually happens. | ||
| VOICE_PROVIDER = os.environ.get("DOTTY_VOICE_PROVIDER", "pivoice") |
BrettKinny
added a commit
that referenced
this pull request
May 30, 2026
Adds DashboardRenderFixTests guarding the repairs from PR #128 against regression: /ui/discord now 404s (dead zeroclaw-discord card removed), the smart-mode partial still renders, and its card is honest about the live PiVoiceLLM path performing no model swap ("model-swap pending"). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
BrettKinny
added a commit
that referenced
this pull request
May 31, 2026
* fix(dashboard): repair busted render — stale CSS, dead cards, wrong status Five dashboard defects fixed: 1. State-card ballooning sparkline / giant gaps. The vendored tailwind.min.css was stale (Apr 28) vs. later template edits, so `.h-6`, `.border-t`, `.py-1.5`, `.break-all` were absent. With `.h-6` missing the sound-balance SVG (viewBox 0 0 100 24, flex-1, no height bound) stretched to ~140px via its intrinsic aspect ratio. Rebuilt the CSS from current templates and updated the SRI integrity hash. 2. Robot status dot showed grey "offline" when the robot was online but simply hadn't had a voice turn today. Now treats a fresh (non-stale) perception device as online — perception liveness is the real connectivity signal; voice idleness is normal. 3. Version chip showed "vunknown" — the container has no .git checkout and the deploy never stamped a version. Added a BRIDGE_VERSION Docker build-arg (writes /app/.bridge-version); deploy-bridge-unraid.sh passes the HEAD short SHA. 4. Removed the Discord daemon card. It queried `systemctl zeroclaw-discord` locally — impossible inside the Unraid bridge container; ZeroClaw was retired in #36. Dropped the route, template, helper, and card section. 5. Smart Mode card advertised a model swap (claude-sonnet / mistral) that only fires on the retired tier1slim path. Relabeled to honest behaviour on the default PiVoiceLLM path ("Robot smart-mode pip … · model-swap pending (v2)"); still shows the swap on tier1slim deployments. Also switched the page to natural document scroll (was a single-screen overflow:hidden layout that pushed cards/feed below an unreachable fold); the feed now caps at 70vh and scrolls internally. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs: add whole-repo vision alignment review (2026-05-29) + locked decisions Captures the multi-agent audit output: canonical vision ground-truth, 50 verified findings, cross-cutting drift patterns, and the six maintainer decisions (§0) that gate the remediation pass. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * Remove Tier1Slim provider entirely (vision review decision E) Tier1Slim was a two-tier voice provider whose tool escalation POSTed to the retired ZeroClaw bridge (/api/voice/escalate), non-functional since the #36 cutover. Per the 2026-05-29 vision review it is removed in full: - delete custom-providers/tier1_slim/, tests/test_tier1_slim.py, docs/tier1slim.md - drop the /xiaozhi/admin/set-tier1slim-model route + shared_llm plumbing (http_server.py, websocket_server.py, portal_bridge.py) - gut bridge.py's Tier1Slim hot-swap machinery: smart_mode is now toggle-only on the live PiVoiceLLM path (LED pip + flag); model-swap is v2 scope (decision D). Removes _dispatch_set_tier1slim_model, _tier1slim_target_for_smart_mode, TIER1SLIM_* env, DOTTY_VOICE_PROVIDER, and the startup voice-model reconcile. - dashboard: drop VOICE_PROVIDER/MODEL_SWAP_ACTIVE; smart_mode card + host-detail LLM row now always show 'PiVoiceLLM · model-swap pending (v2)' - remove the Tier1Slim block from .config.yaml.template; fix compose comment - refresh pi_voice docstrings/comments that referenced Tier1Slim as a live peer Functional no-op in production (live provider is PiVoiceLLM; the swap pushed to an unselected provider). 269 tests pass; ruff clean. Makefile LLAMA_SWAP wizard prompts (now orphaned) deferred to the operator-script batch. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * Remove dashboard self-update/restart/reboot actions (vision review decision F) The /ui Update, Restart, and Reboot-All actions invoked 'systemctl restart zeroclaw-bridge' (a unit that doesn't exist in the container) and git-pulled into the dead /root/zeroclaw-bridge install dir — they no-op'd while reporting success (findings M6/M7). restart-bridge and reboot-all were already UI-orphaned. Per decision F (remove the entire update apparatus): - delete _collect_update_preview, _fetch_latest_remote_sha, _fetch_remote_tags, _parse_tag_version, _build_chip_context, _pull_and_install_bridge, _ssh_restart_xiaozhi, BRIDGE_INSTALL_DIR, and the preview-update/update-bridge/ restart-bridge/reboot-all routes (~474 lines) - reduce the header version chip to a static 'Bridge vX.Y.Z' label linking to the built commit (new _static_chip_context); version_chip.html drops the update button - remove the #update-modal dialog from dashboard.html - delete update_preview/update_result/reboot_all_result/restart_result templates Deploys go through scripts/deploy-bridge-unraid.sh; restart:unless-stopped handles restarts. 46 tests pass; ruff clean. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * Fix operator tooling to the post-#36 four-container arch (H1, L20) make doctor/status and dotty_doctor.py extracted a host via the first 'url: http://' line and probed :8080 labelled 'Bridge health' — but post-#36 that line is the llama-swap endpoint, so the check silently probed the wrong service (finding H1). make setup prompted for a nonexistent ZeroClaw host; make audit SSHed dietpi@<ZEROCLAW_HOST> (a powered-off RPi). - doctor/status/dotty_doctor.py now derive the Docker host from the ws:// URL and health-check the dashboard (:8081) + dotty-behaviour (:8090) - make audit drops the retired 'Bridge host (ZeroClaw host)' SSH block (the bridge is now a container on XIAOZHI_HOST, covered by the server-host check) - make setup drops the ZEROCLAW_HOST/USER and now-orphaned LLAMA_SWAP_* prompts, validation, .env writes, sed substitutions, and WIZARD_PLACEHOLDERS entries (those placeholders left the templates with Tier1Slim) - dotty_doctor.py gains --behaviour-url; --bridge-url now means the dashboard - deploy-bridge-unraid.sh header: the legacy deploy-bridge.sh/install-bridge.sh are gone; flag the still-stale dotty-deploy-bridge skill All changed targets parse; doctor --help OK; ruff clean. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * H2: share kid/smart-mode state across the xiaozhi + bridge containers receiveAudioHandle.py (in the xiaozhi container) read kid/smart-mode from /root/zeroclaw-bridge/state/* with no env or volume set, while the bridge dashboard wrote them under /var/lib/dotty-bridge/state — disjoint, unshared paths, so the firmware kid/smart LED pips desynced from the dashboard on every reconnect (finding H2). - docker-compose.yml.template: set DOTTY_KID_MODE_STATE / DOTTY_SMART_MODE_STATE on the xiaozhi service and bind-mount the bridge's state dir read-only (${DOTTY_STATE_DIR:-/mnt/user/appdata/dotty-bridge/state} -> /var/lib/dotty-bridge/state); also drop the now-deleted tier1_slim provider mount - receiveAudioHandle.py + bridge.py: default the state paths to /var/lib/dotty-bridge/state (the bridge's dir) instead of the retired /root/zeroclaw-bridge, so reader and writer agree even without the env vars - compose.all-in-one.yml: fix the dashboard port comment 8080 -> 8081 Writer (bridge) and reader (xiaozhi) now resolve to the same files. Not verifiable until both containers redeploy. 49 tests pass; ruff clean. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs: dashboard port :8080 -> :8081 sweep + .env ZeroClaw cleanup (M1, L19, L27) The admin dashboard listens on :8081 (:8080 is the llama-swap LLM endpoint). Fix every dashboard reference across SETUP, quickstart, observability, COMPATIBILITY, and variant-port-guide (also drop its dead POST /api/message example — retired in #36). Strip the stale zeroclaw-bridge/ACP block from .env.example, set PORT=8081, repoint ~/.zeroclaw state paths. llama-swap :8080 left intact. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs: re-attribute perception to dotty-behaviour; 11 consumers; story/security pending (M2, L12, L13, M9, A, B) modes.md (authoritative) and architecture.md cited retired bridge.py _perception_* methods and wrong consumer counts. Re-attribute to dotty-behaviour class names + perception/state.py; adopt 11 consumer classes (running set config-gated); mark story_time AND security as Phase 7/8 PENDING (SecurityCycle is scaffolding, per decision A). dotty-behaviour README no longer claims to host the dashboard — it serves data consumed by bridge.py; drop the abandoned dashboard-port slice. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs: brain voice-tools 5 -> 7, drop nonexistent set_led, restore remember (H3, M8) dotty-pi/README listed a nonexistent set_led tool (LEDs are firmware-owned) and omitted the real remember. Canonicalize the 7 registered tools (memory_lookup, remember, recall_person, remember_person, think_hard, take_photo, play_song); refresh the dotty-pi-ext README table/status/layout; fix package.json description; update turn_logger.ts + index.ts comments to post-#36 (PiVoiceLLM is the live write path, not 'dormant pre-cutover'). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs: kid-safety/emoji/egress wording to live PiVoiceLLM reality (C, D, M3, M12, L18) The emoji/kid-safety docs described retired ZeroClaw bridge.py symbols (_ensure_emoji_prefix, _build_sandwich_prompt, _content_filter, _BLOCKED_WORDS_RE, ACPClient) as the live mechanism. Repoint to the persona prompt + .config.yaml prompt: + textUtils.build_turn_suffix. Per decision C: the kid-mode sandwich SHIPS on the live path; the gap (#22) is specifically the absent blocked-words content filter (now in no live code). voice-mode-entry: face-greeter is dotty-behaviour/consumers/face_greeter.py (not bridge.py); drop the removed Discord-daemon reference. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * cleanup: stale comments, dead code, mkdocs nav, broken link (L1,L2,L4,L6,L7,L9,L14,L15,L21,L22,M13) - textUtils/textMessageHandlerRegistry/ota_handler: repoint docstrings off the retired zeroclaw-bridge to dotty-behaviour (:8090) / current importers - remove dead code: SimpleHttpServer._get_websocket_url, openai_compat._ensure_emoji_prefix - pi_voice/README: drop stale 'not yet done' sandwich claims + Tier1Slim rollback/ see-also refs; fix the diagram flags (qwen3.5:4b, --thinking off, no --extensions) - household/registry.py: default doc ~/.zeroclaw -> STATE_DIR; perception.py: add head_pet_ended - style.md: fix ../protocols.md -> ./protocols.md; compose.local.override: drop undefined dotty network - mkdocs.yml: add modes/quickstart/wake-word/proactive-greetings/llama-swap-cookbook to nav (tier1slim.md was deleted) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs: finish Tier1Slim removal + post-#36 framing across hub docs (M11) Sweep the remaining Tier1Slim/ZeroClaw prose out of the canonical docs: - CLAUDE.md / README.md: one alternate provider (OpenAICompat), 7 voice tools, dashboard :8081, drop set-tier1slim-model/shared_llm, #115 dashboard rewire done - llm-backends/faq/voice-pipeline/quickstart/architecture/protocols: drop Tier1Slim as a current backend; PiVoiceLLM default + OpenAICompat alternate - brain.md (M11): smart-mode does NOT swap the backend model on the live path (v2 scope); the swap existed only on the removed Tier1Slim - ROADMAP/CONTRIBUTING/SECURITY/cookbook: drop Tier1Slim provider/dir refs; CONTRIBUTING dashboard port 8080 -> 8081; remove the deleted tier1slim.md links Remaining Tier1Slim mentions are explicit past-tense 'removed' history. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * cleanup: repoint stale /root/.zeroclaw + /root/zeroclaw-bridge code defaults (L11) bridge.py VOICE_MEMORY_DB / _ADMIN_WORKSPACE_DIR and dashboard.py LOG_DIR still defaulted to the retired RPi paths (env vars already override them in the container deploy). Repoint defaults to /var/lib/dotty-bridge/*; drop the dangling 'See bridge/MEMORY-INDEX.md' pointer (that file doesn't exist). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * changelog: document the 2026-05-29 vision-alignment pass Consolidate the [Unreleased] section into single Added/Changed/Removed blocks and record the alignment pass (Tier1Slim removal, dashboard self-update removal, :8081 port fixes, 11-consumer/7-tool corrections, shared state volume). Also fix the stale 'port 8080' in the prior post-#36 doc-reconcile entry. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * #105: instrument ASR with per-utterance metrics (logging only) Logs duration, RMS, peak, mean no_speech_prob / avg_logprob, language probability, and segment count per recognised utterance, so a reject gate separating close-talk speech from ambient TV/podcast audio can be tuned on measured distributions. Also materialises the faster-whisper segments generator to a list before it's consumed twice. No behaviour change; strip the ASR-METRICS block once gate thresholds are chosen. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * test(bridge): cover #128 dashboard render fixes Adds DashboardRenderFixTests guarding the repairs from PR #128 against regression: /ui/discord now 404s (dead zeroclaw-discord card removed), the smart-mode partial still renders, and its card is honest about the live PiVoiceLLM path performing no model swap ("model-swap pending"). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs: add YAML frontmatter to vision-alignment review (fix CI) The Frontmatter Check job requires every non-symlinked docs/*.md to start with a `---` YAML block. This file led with its `#` heading, failing CI on #129. Add a title/description block matching the convention in architecture.md / modes.md / brain.md. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes the "busted" dashboard render. Five defects + a layout change. Already deployed to the
dotty-bridgecontainer on Unraid (healthcheck green, md5s verified) and confirmed live.Fixes
tailwind.min.csswas stale (Apr 28) vs. later template edits, so.h-6/.border-t/.py-1.5/.break-allwere absent. With.h-6gone the sound-balance SVG (viewBox 0 0 100 24,flex-1, no height) stretched to ~140px via its intrinsic aspect ratio.integrityhashsensor_stale: false)vunknown.git; deploy never stamped a versionBRIDGE_VERSIONDocker build-arg writes/app/.bridge-version;deploy-bridge-unraid.shpasses HEAD short SHAsystemctl zeroclaw-discordlocally — impossible in the Unraid container; ZeroClaw retired in #36claude-sonnet-4-6/mistral-small, but the swap only fires on the retiredtier1slimpathPiVoiceLLMpath; still shows the swap ontier1slimdeploymentsAlso switched the page to natural document scroll (was a single-screen
overflow:hiddenlayout that pushed cards/feed below an unreachable fold); the activity feed now caps at70vhand scrolls internally.Notes
dotty-behaviouruntouched, single-container deploy.vd528643, the robot dot is green ("online — perception active, no voice yet today"),.h-6is present in the served CSS, and/ui/discordreturns 404.Test plan
pytest tests/test_bridge_routes.py tests/test_dashboard_csrf.py— 28 passed/ui/*partials render 200;/ui/discord→ 404🤖 Generated with Claude Code