Skip to content

feat(dash): visual polish - verdict badges, mode header, empty state, dark theme (D5) - #136

Merged
fu351 merged 1 commit into
mainfrom
feat/dash/polish
Jul 20, 2026
Merged

feat(dash): visual polish - verdict badges, mode header, empty state, dark theme (D5)#136
fu351 merged 1 commit into
mainfrom
feat/dash/polish

Conversation

@fu351

@fu351 fu351 commented Jul 19, 2026

Copy link
Copy Markdown
Owner

Pull Request

Slice

  • Repo: doberman-core
  • Feature / Slice: D5 — Dashboard visual polish
  • Plan reference: doberman_core_plan.md (dashboard feature, slice D5)

What this PR does

Final polish pass on the doberman dash Starlette dashboard before recording a README hero GIF:

  • Verdict color badges in the live feed (PASS/AUTH/BLOCK — green/amber/red family).
  • A header bar showing current mode (light/balanced/strict/paranoid) + enforcement state
    (enforce/monitor/off), driven by build_stats()'s existing mode/enforcement fields
    (stats.py needed no changes).
  • A designed empty state for the live feed (previously blank until the first decision) and for
    the pending-approvals list (previously JS-toggled; now the same CSS-only pattern via
    :not(:empty) ~ sibling combinators, so a JS variable/toggle could be removed entirely).
  • Dark theme formalized as the default look via CSS custom properties (--bg, --surface,
    --border, --ink, --pass/--auth/--block/--neutral families), with a
    @media (prefers-color-scheme: light) override. Still fully self-contained: inline CSS in the
    existing HTML shell, system font stack, no external assets/CDNs/fonts.
  • Pending approve/deny cards now surface risk prominently (RISK: {risk} badge), mirroring the
    terminal's existing [RISK: {risk.upper()}] convention (src/doberman/auth/provider.py).

No new HTTP endpoints, no new dependencies, no auth/token-flow changes, no redaction or
decision-path changes. All row-derived fields are still rendered via .textContent only (never
innerHTML/markup interpolation).

Tests added (run in CI)

  • tests/unit/test_dash_polish.py (new, 10 tests): verdict/risk/enforcement badge-class lookup
    tables are present and exact-substring matchable; the header bar renders mode + enforcement
    from /api/stats; the feed and pending list both carry a CSS-only designed empty state (and the
    old JS pendingEmpty toggle is gone); the dark-theme custom-property palette is present with a
    light-mode media override; the pending-card risk badge mirrors the terminal's
    "RISK: " + risk.toUpperCase() convention; the served shell still never leaks the bearer token;
    no .innerHTML assignment appears anywhere in the shell.
  • Existing test_dash_serve.py, test_dash_feed_stats.py, test_dash_approve_deny.py (D1–D3)
    re-run unmodified and confirmed still green — they assert on JSON field contracts and element
    IDs/behavior, not on CSS class names, so the restyle doesn't touch their assertions.
  • Full dash suite: 47 passed, 0 failed (pytest tests/unit/test_dash* -q).

Public-release safety (doberman-core only)

  • Contains nothing from the "not allowed" list: no enterprise/hosted code, no proprietary detection, no customer data, no secrets, no commercial-license code
  • Core still builds/tests/runs with NO enterprise package installed

Security checklist

  • Fails closed on error / uncertainty (unchanged — no route/auth logic touched)
  • No secret, full file, or unredacted prompt logged or committed (bearer token still asserted absent from the served shell; every field still .textContent-only)
  • Any guardrail/learning change is raise-only (no silent loosening) — N/A, no guardrail/learning code touched
  • Every BLOCK/AUTH carries reason codes + a human explanation — unchanged, not touched by this slice
  • doberman-core does not import doberman_enterprise — unaffected, no imports changed

Edge cases covered / Deviations from plan / Risks introduced

  • Edge cases: empty feed before the first decision, empty pending-approvals list, both now have
    designed (not blank) states driven purely by CSS sibling-combinator rules — no JS timing/race
    possible since there's no JS toggle left to race.
  • Deviations: none from the original D5 scope. One self-caught test bug during authoring: an
    early assertion checked for the literal string "innerHTML" anywhere in the HTML, which
    false-failed against a JS comment documenting the textContent-only discipline; fixed to assert
    on the .innerHTML property-assignment form specifically.
  • Risks / tech debt: none identified. stats.py was re-confirmed to need no changes — it already
    exposed the mode and enforcement fields this slice's header bar reads.

… dark theme (D5)

Formalizes the dashboard's dark-by-default look into CSS custom properties,
adds verdict/risk/enforcement color badges to the live feed and pending
approval cards, a header bar surfacing current mode + enforcement state
(from build_stats(), no stats.py changes needed), and CSS-only designed
empty states for both the feed and pending-approvals list (replacing the
old JS-driven display toggle). Pending cards now surface risk prominently,
mirroring the terminal's "[RISK: {risk.upper()}]" convention. No new
endpoints, no auth/token-flow changes, no redaction/decision-path changes;
every row-derived field is still rendered via .textContent only.
@fu351
fu351 merged commit 2050bf1 into main Jul 20, 2026
6 checks passed
@fu351
fu351 deleted the feat/dash/polish branch July 20, 2026 00:00
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.

1 participant