Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
610dc56
docs(planning): lock Phase 3.2 → 3.5 implementation plan
Artic0din May 17, 2026
94720dc
feat(cdr): Phase 3.2 commit 1/4 — pure-logic HA history replay module
Artic0din May 17, 2026
b3a787b
feat(backfill): Phase 3.2 commit 2/4 — rewrite backfill.py as HA-side…
Artic0din May 17, 2026
0f35c1f
feat(coordinator): Phase 3.2 commit 3/4 — async_run_backfill + auto-k…
Artic0din May 17, 2026
651840d
feat(sensor): Phase 3.2 commit 4/4 — BackfillStatusSensor + service o…
Artic0din May 17, 2026
7260892
fix(backfill): type-annotate target dict union for pyright
Artic0din May 17, 2026
b273e79
fix(backfill): docstring accuracy on plan-set composition + recorder …
Artic0din May 17, 2026
0f3c478
fix(backfill): days-loaded delta + test type hints + defang plan-doc
Artic0din May 17, 2026
2ddf01d
fix(backfill): defang plan-doc + double-check status before lock
Artic0din May 17, 2026
5e9a67d
fix(backfill): repo-relative plan path + arithmetic + failure-path me…
Artic0din May 18, 2026
9f6e160
docs(plan): MD040 fence langs + accurate kW description + named-provi…
Artic0din May 18, 2026
e9687ba
feat(cdr): Phase 3.3 commit 1/3 — pure-logic rollup module
Artic0din May 17, 2026
7f85ed4
feat(sensor): Phase 3.3 commit 2/3 — PeriodRollupSensor + 15 registra…
Artic0din May 17, 2026
9319917
feat(strings): Phase 3.3 commit 3/3 — entity translations + CHANGELOG
Artic0din May 17, 2026
c2ee0a0
fix(rollup): defensive type guards on filter_window + sensor provider…
Artic0din May 17, 2026
bbe970c
fix(rollup): drop unsupported strings.json description + provider-gua…
Artic0din May 17, 2026
99ff449
fix(rollup): empty-plan-id guard + negative-value sum test
Artic0din May 17, 2026
24e4be1
feat(coordinator): Phase 3.4 commit 1/2 — named comparator wiring
Artic0din May 17, 2026
d455c71
feat(sensor): Phase 3.4 commit 2/2 — NamedComparatorRollupSensor × 5
Artic0din May 17, 2026
507db8b
fix(named): persist provider across restart + skip unique_id collision
Artic0din May 17, 2026
b088165
feat(dashboard): Phase 3.5 commit 1/3 — strip Amber chrome, scaffold …
Artic0din May 17, 2026
7e0f3b0
feat(dashboard): Phase 3.5 commit 2/3 — wire rollup + ranked + backfi…
Artic0din May 17, 2026
a29cc2c
feat(dashboard): Phase 3.5 commit 3/3 — design-spec divergence + CHAN…
Artic0din May 17, 2026
0e1ba0e
fix(docs): add css language to design-spec fenced code block
Artic0din May 17, 2026
e740926
chore: merge dev into phase-3.5 to absorb #73 + #80 squash merges
Artic0din May 18, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
96 changes: 96 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,102 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).

## [Unreleased]

### Phase 3.5 — Dashboard rewrite (multi-plan ranked view)

Throws away the Amber-vs-current-plan two-comparator dashboard
(2447 LOC) and rebuilds it as a multi-plan ranked-alternatives view
keyed off the Phase 3.2 / 3.3 / 3.4 sensors. Visual seed lifted from
`assets/dashboard-v3-apple.html` — dark default, Outfit + IBM Plex
Mono, ambient radial bg, semantic accent tokens (no per-provider
colours).

#### Added

- **Full rewrite of `custom_components/pricehawk/www/dashboard.html`**
(~1250 LOC, down from 2447). New card hierarchy per plan section 5.1:
- NAV bar (brand + connection status pill + clock + theme toggle).
- HERO row: current-cost card + savings-vs-best-alt card (with
projected-annual extrapolation).
- PERIOD TABS: `[Today][Week][Month][3 Month][Year]` — clicking a
tab swaps the entity binding for every rollup card to the matching
`_today` / `_week` / `_month` / `_3month` / `_year` sensor in
one tick. Active tab persists to `localStorage['pricehawk-window']`
so re-opens land on the user's last view.
- RANKED ALTERNATIVES table rendered from
`sensor.pricehawk_ranked_alternatives.attributes.alternatives[]`
(already sorted by cheap-rank score in `summarize_for_sensor`).
Click a row → drill-in card slides up below.
- DRILL-IN CARD: peak rate / daily supply / customer type / plan ID
/ cheap-rank score, plus a "Pin as Named Comparator" button that
deep-links to `/config/integrations/integration/pricehawk` (HA
doesn't support per-step deep-linking; locked in plan section 9
REVISIT 4).
- DATA HEALTH FOOTER: `sensor.pricehawk_backfill_status` state
(state-coloured: green=complete, amber=running, red=failed) +
`days_loaded` + `ranked_alternatives.last_run` as relative +
absolute time + alternatives count.
- **Empty-state UI for first-run users** (plan section 5.3 surprise #3):
when `backfill_status.days_loaded < 7`, hero rollup values are
replaced with an "Accruing… [n/365]" pill instead of showing a
misleading `$0.00`. Surfaces clearly that we don't have enough
history yet.
- **CSP `connect-src` extended** to include `ws://*.local:*` +
`wss://*.local:*` so the dashboard works on Ryan's HA Green at
`homeassistant.local` (plan section 5.3 surprise #1). Existing
`localhost` + `*.ui.nabu.casa` entries preserved.
- **`assets/DESIGN.claude.md` — new PriceHawk Dashboard section**
noting divergence: PriceHawk is a dark data-dashboard inside HA's
sidebar, not a warm-canvas editorial site. Inherits typographic
rationale (humanist sans + mono numerics) and the card-as-surface
model + accent-discipline rule, but uses its own token palette.
The rest of the Claude marketing-site spec stays intact.

#### Changed

- **WebSocket auth + URL detection preserved verbatim** from the prior
dashboard:
- `location.protocol === 'https:' ? 'wss://' : 'ws://'` for the WS
URL (AEGIS rule: never hardcode `ws://`).
- Token sourced from URL params first, then `window.parent
.hassConnection`, then `localStorage.hassTokens`, then
`window.parent.localStorage.hassTokens` (AEGIS rule: never
hardcode the token).
- **Per-provider colour tokens deleted** (`--amber-primary`,
`--globird-primary`). Replaced with `--accent-positive` /
`--accent-negative` / `--accent-neutral` / `--accent-warn` — matches
the Phase 3.0 pivot away from provider-specific branding.
- **`dashboard_config.setup_panel_iframe` cache-busting unchanged** —
the existing `?v=<version>.<epoch>` query param survives the
rewrite (it's appended to the URL, doesn't touch dashboard.html
itself). Verified by smoke test; no code change.

#### Removed

- CSV import card, backfill-trigger button, Amber-API winner card,
GloBird TOU strip, Amber forecast strip, sparkline chart, grid-power
gauge, two-provider rate chart, ZeroHero status card — all replaced
by the ranked-alternatives + rollup-sensor model.

#### Notes

- **No new JS framework, no build step.** Vanilla JS only, same
constraint as the prior dashboard. All CSS + JS inlined; no CDN
fetches beyond the Google Fonts stylesheet that the prior dashboard
already used.
- **30s setInterval re-render** for the ranked + footer cards so
relative timestamps ("ran 27s ago / 3h ago") tick forward without
waiting on a state_changed event. Cheap (<1ms per tick on HA Green).
- **XSS hardening**: all CDR-sourced strings (plan_id, display_name,
brand, customer_type) pass through `escapeHtml()` before innerHTML
insertion. Defensive — current registry payloads don't contain
HTML-ish characters, but future ones might.
- **Manual UAT only** for this commit (per plan section 6.3 table —
`3.5 | none | manual on Ryan's HA + JS console`). Local smoke test:
HTML parses cleanly via `html.parser`; JS extracted + run under
Node `--check` + mock-DOM render harness exercising all 5 period
windows + accruing branch + empty-ranked branch + drill render
without throwing.

### Phase 3.4 — Named comparator drill-in

Lets the user pin ONE CDR plan from the ranked alternatives list as a
Expand Down
85 changes: 85 additions & 0 deletions assets/DESIGN.claude.md
Original file line number Diff line number Diff line change
Expand Up @@ -587,3 +587,88 @@ When photography is used (rare — mostly testimonials), avatars crop to perfect
- Form validation states beyond `{component.text-input-focused}` are not extracted — error / success states would need a sign-up or feedback flow to confirm.
- The actual Claude product surface (claude.ai chat interface) shares some tokens with the marketing site but adds many product-specific components (chat bubbles, message tools, file upload chips, conversation history sidebar) that are out of scope for this marketing-surface document.
- The "agent" / "computer use" demo cards on certain pages display animated Claude controlling a browser — the static screenshot doesn't fully capture the animation chrome.

---

## PriceHawk Dashboard (divergence from this spec)

The PriceHawk HA integration dashboard at
`custom_components/pricehawk/www/dashboard.html` deliberately does NOT
follow the Claude marketing-site spec above. PriceHawk is a dark
**data-dashboard** surfaced inside the Home Assistant sidebar iframe,
not a warm-canvas editorial site, and its visual language is
incompatible with the cream/coral/dark-navy trinity documented in this
file.

### Why divergence

- **Surface context**: PriceHawk renders inside HA's chrome alongside
other dark dashboards (Lovelace, Energy, Logbook). A warm-cream canvas
would look broken next to those panels. Most HA users run dark mode
by default; cream-on-cream would be uncomfortable late at night
during high-tariff windows when the dashboard is actually consulted.
- **Information density**: a data-dashboard with 16+ live entity reads
+ a ranked alternatives table needs tabular numerals, mono digits,
and high-contrast accent colours. The editorial typography stack
(serif display + humanist sans) doesn't suit dense tabular layouts.
- **Brand independence**: PriceHawk is an open-source HACS integration,
not an Anthropic product. The Anthropic coral / radial-spike mark
doesn't apply here. PriceHawk has its own logo (orange hawk-head
glyph at `custom_components/pricehawk/icon.png`).

### What PriceHawk DOES inherit from this spec

- **Typographic rationale**: humanist sans (Outfit, here, vs StyreneB)
for UI text; mono with tabular numerics (IBM Plex Mono, here, vs no
mono in the Claude spec) for all money + rate values. The "use mono
for numbers users compare against each other" rule is unbreakable.
- **Card-as-surface model**: rounded `border-radius` (12-16px),
subtle border, optional 1px gradient top-stroke on hover for
affordance. PriceHawk uses `--card-radius: 16px` matching the Claude
spec's `r-lg: 18px` ballpark.
- **Accent-colour discipline**: ONE positive, ONE negative, ONE
neutral. Don't introduce a fourth accent. Claude uses
primary-coral as its single accent; PriceHawk uses
`--accent-positive` (savings green) + `--accent-negative` (loss red)
+ `--accent-neutral` (info blue) + `--accent-warn` (accruing amber)
— four because the dashboard surfaces four distinct semantic states,
not as decoration.

### PriceHawk token map (for reference)

```css
--bg-base: #070B14 // OLED-friendly true black
--bg-surface: #0C1220
--bg-card: rgba(15,23,42,0.6)
--text-primary: #F1F5F9
--text-secondary: #94A3B8
--text-muted: #64748B
--accent-positive: #10B981 // savings, "you save"
--accent-negative: #EF4444 // loss, "you lose"
--accent-neutral: #38BDF8 // info, current plan / pinned baseline
--accent-warn: #F59E0B // accruing, < 7 days of backfill history
--card-radius: 16px
--card-blur: 20px
```

Light theme inverts via `[data-theme="light"]` selector overriding the
same tokens (canvas: `#F5F6FA`, card: `rgba(255,255,255,0.78)`, accents
shift one stop darker for contrast). Theme persists to
`localStorage['pricehawk-theme']`; first-visit defaults to OS
`prefers-color-scheme`.

### Where to look for PriceHawk's full visual treatment

- `assets/dashboard-v3-apple.html` — the v3 visual seed (1478 LOC
dark-theme mockup; ambient radial bg, noise overlay, Outfit + IBM
Plex Mono). Not the deployed dashboard, but the design-language
source-of-truth.
- `custom_components/pricehawk/www/dashboard.html` — the actual
deployed dashboard at `/local/pricehawk/dashboard.html`. Hierarchy:
nav / hero row (current cost + savings) / period tabs
(today|week|month|3month|year) / ranked alternatives table /
drill-in card / data-health footer.

Don't try to reconcile PriceHawk back into the Claude spec.
They are different products and the visual languages are
deliberately separate.
Loading
Loading