Analytics: cards not glass (opaque slabs) and the chart hover tooltip is broken — port calternal.js analytics look #504

Closed
opened 2026-09-30 09:00:45 +00:00 by kayg · 17 comments
Owner

Owner report (2026-09-30, screenshot of calternal.cloud Analytics): "i asked for analytics cards to be transparent and blurred? WTF IS THIS? and what even is the hover preview? calternal.js did it beautifully!"

Seen on the screenshot:

  1. Cards are opaque cream slabs. The stat cards (Total tracked, Per active day, ...), the Added, By category and Habits cards, and the inner mini-cards all have NO translucency and NO backdrop blur, with heavy drop shadows. The owner asked for transparent, blurred cards long ago (2026-09-25 feedback: more translucency and blur everywhere).
  2. The chart hover tooltip is broken: unstyled text ("dailyiiving / 1h 15m / 5% of tracked time") spills across the edge of a pale box with no padding, no hierarchy and no colour key. It overlaps the bars.
  3. The "Added" and "Habits" mini-cards are also plain boxes.

Fix: PORT, do not reinvent (CLAUDE.md: never invent basic UI; port calternal.js first)

  • Reference: /home/kayg/Developer/calternal.js/packages/web/src/lib/components/analytics/: Dashboard.svelte, DistributionCard.svelte, StackedBarCard.svelte, BklitChart.svelte, BklitAnalytics.tsx, BklitTooltipMaterial (and its test), RangeBar, TimeOfDayHeatmap, CalendarHeatmap, PeriodSelector. Run calternal.js locally (or read its code and screenshots) and match its tooltip material and card look exactly, adapted to calternal's tokens.
  • Cards use the ONE glass recipe from #436 (merged 6c87f5ff9: .glass-overlay and Settings inner-card tokens), not new values. Remove the heavy shadows. Check readability over photo backgrounds and all themes, and the reduced-transparency fallback.
  • The tooltip uses the calternal.js tooltip material: a padded glass card, a colour swatch, the category name, the duration and share with a clear hierarchy, kept inside the viewport, never overlapping its own bar, following the pointer smoothly, and keyboard accessible.
  • Also check the category label typo in the data ("dailyiiving" vs "dailyliving"). If it is real User data, leave it; do not "fix" data.
    Proof: a before/after screenshot matrix (390/820/1440 × light/dark × colour background and photo background) plus a hover crop at 3×, all viewport-sized from a production build, with a side-by-side against calternal.js. Zoom in on every row. Gates: bun run check, bun run test, and the analytics e2e.
## Owner report (2026-09-30, screenshot of calternal.cloud Analytics): "i asked for analytics cards to be transparent and blurred? WTF IS THIS? and what even is the hover preview? calternal.js did it beautifully!" Seen on the screenshot: 1. **Cards are opaque cream slabs.** The stat cards (Total tracked, Per active day, ...), the Added, By category and Habits cards, and the inner mini-cards all have NO translucency and NO backdrop blur, with heavy drop shadows. The owner asked for transparent, blurred cards long ago (2026-09-25 feedback: more translucency and blur everywhere). 2. **The chart hover tooltip is broken:** unstyled text ("dailyiiving / 1h 15m / 5% of tracked time") spills across the edge of a pale box with no padding, no hierarchy and no colour key. It overlaps the bars. 3. The "Added" and "Habits" mini-cards are also plain boxes. ## Fix: PORT, do not reinvent (CLAUDE.md: never invent basic UI; port calternal.js first) - Reference: `/home/kayg/Developer/calternal.js/packages/web/src/lib/components/analytics/`: Dashboard.svelte, DistributionCard.svelte, StackedBarCard.svelte, BklitChart.svelte, BklitAnalytics.tsx, BklitTooltipMaterial (and its test), RangeBar, TimeOfDayHeatmap, CalendarHeatmap, PeriodSelector. Run calternal.js locally (or read its code and screenshots) and match its tooltip material and card look exactly, adapted to calternal's tokens. - Cards use the ONE glass recipe from #436 (merged 6c87f5ff9: `.glass-overlay` and Settings inner-card tokens), not new values. Remove the heavy shadows. Check readability over photo backgrounds and all themes, and the reduced-transparency fallback. - The tooltip uses the calternal.js tooltip material: a padded glass card, a colour swatch, the category name, the duration and share with a clear hierarchy, kept inside the viewport, never overlapping its own bar, following the pointer smoothly, and keyboard accessible. - Also check the category label typo in the data ("dailyiiving" vs "dailyliving"). If it is real User data, leave it; do not "fix" data. **Proof:** a before/after screenshot matrix (390/820/1440 × light/dark × colour background and photo background) plus a hover crop at 3×, all viewport-sized from a production build, with a side-by-side against calternal.js. Zoom in on every row. Gates: `bun run check`, `bun run test`, and the analytics e2e.
Author
Owner

Starting analytics glass and tooltip repair on branch job/analytics-504, based on 6c87f5ff94. I have read CLAUDE.md, CONTEXT.md and the Analytics and shared glass decisions in docs/DESIGN.md. I am tracing the rendered app and comparing its widgets with calternal.js before editing.

Starting analytics glass and tooltip repair on branch job/analytics-504, based on 6c87f5ff9442cd658572139bc536d018fd5222a4. I have read CLAUDE.md, CONTEXT.md and the Analytics and shared glass decisions in docs/DESIGN.md. I am tracing the rendered app and comparing its widgets with calternal.js before editing.
Author
Owner

Finding (source trace): Analytics page cards use the shared .glass-card role, which intentionally has no backdrop blur and applies --glass-shadow. The tooltip portal is mounted under [data-calternal-overlay-layer], while BKLIT_CSS scopes its .bklit-readout layout rules under .bklit-analytics; therefore padding, type hierarchy and colour keys do not match the portal DOM. TooltipBox already has viewport clamping and horizontal-bar clearance logic, with placement tests; the coverage gap is portal styling and the cards' selected material.

Finding (source trace): Analytics page cards use the shared .glass-card role, which intentionally has no backdrop blur and applies --glass-shadow. The tooltip portal is mounted under [data-calternal-overlay-layer], while BKLIT_CSS scopes its .bklit-readout layout rules under .bklit-analytics; therefore padding, type hierarchy and colour keys do not match the portal DOM. TooltipBox already has viewport clamping and horizontal-bar clearance logic, with placement tests; the coverage gap is portal styling and the cards' selected material.
Author
Owner

Owner (2026-09-30, second screenshot on the new deploy 6c87f5ff9): "the hover preview in analytics is still fucked? calternal.js man please!" plus: the hover preview appears ONLY when the cursor is directly over a bar, never over the empty track to the right of a bar or in the gaps between bars. (Earlier owner feedback: the tooltip sits just below the cursor, not at a fixed spot.)
The screenshot still shows: text flush against the tooltip's left edge (no padding), no colour swatch, no hierarchy, a plain three-line stack, and a trigger over empty space after the bar. Port calternal.js's tooltip material and its hit-testing exactly; the tests must assert "no tooltip over empty track" and "tooltip over the bar".

**Owner (2026-09-30, second screenshot on the new deploy 6c87f5ff9):** "the hover preview in analytics is still fucked? calternal.js man please!" plus: **the hover preview appears ONLY when the cursor is directly over a bar**, never over the empty track to the right of a bar or in the gaps between bars. (Earlier owner feedback: the tooltip sits just below the cursor, not at a fixed spot.) The screenshot still shows: text flush against the tooltip's left edge (no padding), no colour swatch, no hierarchy, a plain three-line stack, and a trigger over empty space after the bar. Port calternal.js's tooltip material and its hit-testing exactly; the tests must assert "no tooltip over empty track" and "tooltip over the bar".
Author
Owner

E2E finding: the Analytics card/tooltip material checks pass on the production bundle. The full run then timed out waiting for .mh-switch in the desktop keyboard flow. ModeHeader hides that title menu while the wide sidebar is visible because the sidebar owns subviews (DESIGN §34); the existing test entered this keyboard path with the sidebar expanded. I updated only the setup to collapse the sidebar through its keyboard control before testing the title menu, keeping the original navigation expectation unchanged. I am rerunning the Analytics e2e and screenshot capture.

E2E finding: the Analytics card/tooltip material checks pass on the production bundle. The full run then timed out waiting for `.mh-switch` in the desktop keyboard flow. `ModeHeader` hides that title menu while the wide sidebar is visible because the sidebar owns subviews (DESIGN §34); the existing test entered this keyboard path with the sidebar expanded. I updated only the setup to collapse the sidebar through its keyboard control before testing the title menu, keeping the original navigation expectation unchanged. I am rerunning the Analytics e2e and screenshot capture.
Author
Owner

E2E finding: after the keyboard setup correction, the card and tooltip checks passed: 10/10 cards reported the shared 16px blur with no shadow; 10 inner cards had the shared tint; the keyboard readout reported a 12×3 colour key, duration, share, viewport containment, mark clearance and an accessible name. The Weekly→Monthly keyboard navigation, chart keyboard marks, empty state, 320px/200% overflow checks and RTL overflow check also passed.

The chart trace reported CPU tasks over its 50ms threshold: year→quarter 233ms worst, quarter→month 71ms, week→year 69ms; month→week passed at 46ms. I did not change the existing performance expectation. The run also timed out in the extra whole-page RTL screenshot while waiting for the theme root; the local server logged SQLite acquire delays up to 10.47s during other shared-host builds. Matrix mode now omits that unrelated full-page capture, retains the RTL check, and validates the requested matrix theme before each viewport capture. The screenshot-only after matrix is running. Treat the trace and SQLite delays as SLOW evidence for this shared-host run.

E2E finding: after the keyboard setup correction, the card and tooltip checks passed: 10/10 cards reported the shared 16px blur with no shadow; 10 inner cards had the shared tint; the keyboard readout reported a 12×3 colour key, duration, share, viewport containment, mark clearance and an accessible name. The Weekly→Monthly keyboard navigation, chart keyboard marks, empty state, 320px/200% overflow checks and RTL overflow check also passed. The chart trace reported CPU tasks over its 50ms threshold: year→quarter 233ms worst, quarter→month 71ms, week→year 69ms; month→week passed at 46ms. I did not change the existing performance expectation. The run also timed out in the extra whole-page RTL screenshot while waiting for the theme root; the local server logged SQLite acquire delays up to 10.47s during other shared-host builds. Matrix mode now omits that unrelated full-page capture, retains the RTL check, and validates the requested matrix theme before each viewport capture. The screenshot-only after matrix is running. Treat the trace and SQLite delays as SLOW evidence for this shared-host run.
Author
Owner

Production finding for #504: the 3× phone tooltip crop showed the fixed mode tray painting across the readout. TooltipBox portals outside .bklit-analytics, so the chart-local .z-50 rule did not set its stacking order. The portal now uses the shared --layer-tooltip token from DESIGN §34. The regression test reproduced the missing layer, then passed after the fix (12/12); the rebuilt production crop is in artifacts/analytics-504/after-verified/analytics-tooltip-photo-light-390-3x.png.

Production finding for #504: the 3× phone tooltip crop showed the fixed mode tray painting across the readout. TooltipBox portals outside `.bklit-analytics`, so the chart-local `.z-50` rule did not set its stacking order. The portal now uses the shared `--layer-tooltip` token from DESIGN §34. The regression test reproduced the missing layer, then passed after the fix (12/12); the rebuilt production crop is in `artifacts/analytics-504/after-verified/analytics-tooltip-photo-light-390-3x.png`.
Author
Owner

Performance finding for #504: the extended local large Home profile wrote 10,000 Log entries across 273 Daily Notes, but its one 15-minute index window ended before measurement with AssertionError: every photo is in the timeline (0/1). The local host load average observed during the run was 47.76, 44.42, 40.66. No Analytics render or tooltip latency samples were produced. Treat this as shared-host SLOW load; the one time-boxed profile is not being repeated. The profile now records Analytics glass-card material and tooltip latency when the 10k Home indexes successfully.

Performance finding for #504: the extended local large Home profile wrote 10,000 Log entries across 273 Daily Notes, but its one 15-minute index window ended before measurement with `AssertionError: every photo is in the timeline (0/1)`. The local host load average observed during the run was 47.76, 44.42, 40.66. No Analytics render or tooltip latency samples were produced. Treat this as shared-host SLOW load; the one time-boxed profile is not being repeated. The profile now records Analytics glass-card material and tooltip latency when the 10k Home indexes successfully.
Author
Owner

Forgejo #504 — final report

Built

  • Reused the shared #436 glass overlay material for Analytics cards and their portaled chart tooltip. Cards now use the shared 16px blur and saturation without box or text shadows. Inner mini-cards use the shared inner-card tint.
  • Ported the chart readout hierarchy: colour key, category, duration, and share. The readout stays within the viewport, clears its chart mark, sits above bottom chrome, and works from the keyboard.
  • Added production-build screenshot capture for the requested 390/820/1440 × light/dark × colour/photo matrix, plus a 3× tooltip crop. Extended the existing 10k-Log performance profile to record card material and tooltip visibility/layering.
  • Left category data unchanged. The source does not contain either dailyiiving or dailyliving.

Files

apps/web/e2e/analytics.mjs, apps/web/e2e/photos-perf.mjs, apps/web/src/lib/components/analytics/{ActivityCard.svelte,BklitAnalytics.tsx,BklitTooltipMaterial.test.ts,CalendarHeatmap.svelte,Dashboard.svelte,DistributionCard.svelte,HabitsCard.svelte,StackedBarCard.svelte,TimeOfDayHeatmap.svelte}, and apps/web/src/lib/components/analytics/widgets/StatRow.svelte.

Commits

562c7e4c0 glass material; 5def53e92 tooltip above bottom chrome; 3009f6dd8 screenshot matrix and tooltip crop; 54552a888 10k-Log profile; 0e24ff279 merge origin/dev; ade9dd793 remove card text halo; d0c36fbfa shared chrome token in profile; ca0a49f6bd00718919a1373a4b1a68a79323ebe5 clarify shared Card use.

Head: ca0a49f6bd00718919a1373a4b1a68a79323ebe5.

Screenshot evidence

  • Before matrix: artifacts/analytics-504/before/
  • Final 12-screen matrix: artifacts/analytics-504/after-merged/
  • 3× photo/light tooltip crop: artifacts/analytics-504/after-verified/analytics-tooltip-photo-light-390-3x.png

The artifacts are local and ignored; they were not committed. scripts/fj issue has no attachment operation, and no Forgejo attachment tool is available here, so I could not attach these files to this comment. I also could not produce a screenshot side-by-side against calternal.js: that checkout has the reference source but no ready preview build or reference screenshots in this environment.

Gates

bun run check:

$ node scripts/check-type-tokens.mjs && svelte-kit sync && svelte-check --tsconfig ./tsconfig.json
Text sizes and UI shape values use shared role tokens.
Loading svelte-check in workspace: /home/kayg/Developer/calternal-wt/analytics-504/apps/web
Getting Svelte diagnostics...

svelte-check found 0 errors and 0 warnings

Final bun run test:

Test Files  137 passed (137)
      Tests  894 passed (894)
   Start at  14:43:19
   Duration  90.16s (transform 48%, environment 21%, import 15%, tests 12%, setup 4%)

Focused StatRow test after its source-text assertion initially rejected the attributed Card tag:

Test Files  1 passed (1)
      Tests  13 passed (13)
   Start at  14:42:53
   Duration  12.19s (transform 74%, environment 8%, tests 8%, import 6%, setup 3%)

Production build passed: ✓ built in 174s, ✔ done.

Analytics E2E: all functional checks passed, including the 10 cards, 10 mini-cards, keyboard tooltip, responsive layouts, links, empty states, chart marks, and RTL. The process exited 1 on its four CPU timing checks:

FAIL switching year → quarter renders the charts with no task over 50 ms of CPU (worst 195 ms)
FAIL switching quarter → month renders the charts with no task over 50 ms of CPU (worst 80 ms)
FAIL switching month → week renders the charts with no task over 50 ms of CPU (worst 63 ms)
FAIL switching week → year renders the charts with no task over 50 ms of CPU (worst 58 ms)

4 check(s) failed:
- switching year → quarter renders the charts with no task over 50 ms of CPU (worst 195 ms)
- switching quarter → month renders the charts with no task over 50 ms of CPU (worst 80 ms)
- switching month → week renders the charts with no task over 50 ms of CPU (worst 63 ms)
- switching week → year renders the charts with no task over 50 ms of CPU (worst 58 ms)

These are load-sensitive SLOW checks. The host was running concurrent jobs and the E2E needed 581 seconds to seed and index 378 Log entries. I did not change the existing threshold. No Rust source changed, so no Rust crate gates were run. cargo clean removed 7,067 files / 4.4 GiB; web build output was removed after gates.

Performance profile and known gaps

The extended local analyticsYear profile loaded 10,000 Log entries across 273 daily notes, but timed out before measurement with AssertionError: every photo is in the timeline (0/1). It recorded no p50/p95, CPU, or RSS result. I did not rerun it. The profile needs a later successful run before comparison with docs/perf/baseline.json.

The screenshot matrix is present locally, but this job could not attach it or make the requested calternal.js side-by-side. The E2E has four SLOW CPU threshold failures as listed above.

Decisions not specified by DESIGN

  • Used the Mono light and Noir dark palettes for the matrix because the screenshot harness restored its saved theme family to Mono when it booted Paper; these palettes still provide the requested light/dark coverage over both theme and photo backgrounds.
  • The tooltip assertion compares against shared --layer-bottom-chrome, because the tooltip is portaled and the .tabbar-shell element is absent in the crop context.
# Forgejo #504 — final report ## Built - Reused the shared #436 glass overlay material for Analytics cards and their portaled chart tooltip. Cards now use the shared 16px blur and saturation without box or text shadows. Inner mini-cards use the shared inner-card tint. - Ported the chart readout hierarchy: colour key, category, duration, and share. The readout stays within the viewport, clears its chart mark, sits above bottom chrome, and works from the keyboard. - Added production-build screenshot capture for the requested 390/820/1440 × light/dark × colour/photo matrix, plus a 3× tooltip crop. Extended the existing 10k-Log performance profile to record card material and tooltip visibility/layering. - Left category data unchanged. The source does not contain either `dailyiiving` or `dailyliving`. ## Files `apps/web/e2e/analytics.mjs`, `apps/web/e2e/photos-perf.mjs`, `apps/web/src/lib/components/analytics/{ActivityCard.svelte,BklitAnalytics.tsx,BklitTooltipMaterial.test.ts,CalendarHeatmap.svelte,Dashboard.svelte,DistributionCard.svelte,HabitsCard.svelte,StackedBarCard.svelte,TimeOfDayHeatmap.svelte}`, and `apps/web/src/lib/components/analytics/widgets/StatRow.svelte`. ## Commits `562c7e4c0` glass material; `5def53e92` tooltip above bottom chrome; `3009f6dd8` screenshot matrix and tooltip crop; `54552a888` 10k-Log profile; `0e24ff279` merge `origin/dev`; `ade9dd793` remove card text halo; `d0c36fbfa` shared chrome token in profile; `ca0a49f6bd00718919a1373a4b1a68a79323ebe5` clarify shared Card use. Head: `ca0a49f6bd00718919a1373a4b1a68a79323ebe5`. ## Screenshot evidence - Before matrix: `artifacts/analytics-504/before/` - Final 12-screen matrix: `artifacts/analytics-504/after-merged/` - 3× photo/light tooltip crop: `artifacts/analytics-504/after-verified/analytics-tooltip-photo-light-390-3x.png` The artifacts are local and ignored; they were not committed. `scripts/fj issue` has no attachment operation, and no Forgejo attachment tool is available here, so I could not attach these files to this comment. I also could not produce a screenshot side-by-side against calternal.js: that checkout has the reference source but no ready preview build or reference screenshots in this environment. ## Gates `bun run check`: ```text $ node scripts/check-type-tokens.mjs && svelte-kit sync && svelte-check --tsconfig ./tsconfig.json Text sizes and UI shape values use shared role tokens. Loading svelte-check in workspace: /home/kayg/Developer/calternal-wt/analytics-504/apps/web Getting Svelte diagnostics... svelte-check found 0 errors and 0 warnings ``` Final `bun run test`: ```text Test Files 137 passed (137) Tests 894 passed (894) Start at 14:43:19 Duration 90.16s (transform 48%, environment 21%, import 15%, tests 12%, setup 4%) ``` Focused StatRow test after its source-text assertion initially rejected the attributed Card tag: ```text Test Files 1 passed (1) Tests 13 passed (13) Start at 14:42:53 Duration 12.19s (transform 74%, environment 8%, tests 8%, import 6%, setup 3%) ``` Production build passed: `✓ built in 174s`, `✔ done`. Analytics E2E: all functional checks passed, including the 10 cards, 10 mini-cards, keyboard tooltip, responsive layouts, links, empty states, chart marks, and RTL. The process exited 1 on its four CPU timing checks: ```text FAIL switching year → quarter renders the charts with no task over 50 ms of CPU (worst 195 ms) FAIL switching quarter → month renders the charts with no task over 50 ms of CPU (worst 80 ms) FAIL switching month → week renders the charts with no task over 50 ms of CPU (worst 63 ms) FAIL switching week → year renders the charts with no task over 50 ms of CPU (worst 58 ms) 4 check(s) failed: - switching year → quarter renders the charts with no task over 50 ms of CPU (worst 195 ms) - switching quarter → month renders the charts with no task over 50 ms of CPU (worst 80 ms) - switching month → week renders the charts with no task over 50 ms of CPU (worst 63 ms) - switching week → year renders the charts with no task over 50 ms of CPU (worst 58 ms) ``` These are load-sensitive SLOW checks. The host was running concurrent jobs and the E2E needed 581 seconds to seed and index 378 Log entries. I did not change the existing threshold. No Rust source changed, so no Rust crate gates were run. `cargo clean` removed 7,067 files / 4.4 GiB; web build output was removed after gates. ## Performance profile and known gaps The extended local `analyticsYear` profile loaded 10,000 Log entries across 273 daily notes, but timed out before measurement with `AssertionError: every photo is in the timeline (0/1)`. It recorded no p50/p95, CPU, or RSS result. I did not rerun it. The profile needs a later successful run before comparison with `docs/perf/baseline.json`. The screenshot matrix is present locally, but this job could not attach it or make the requested calternal.js side-by-side. The E2E has four SLOW CPU threshold failures as listed above. ## Decisions not specified by DESIGN - Used the Mono light and Noir dark palettes for the matrix because the screenshot harness restored its saved theme family to Mono when it booted Paper; these palettes still provide the requested light/dark coverage over both theme and photo backgrounds. - The tooltip assertion compares against shared `--layer-bottom-chrome`, because the tooltip is portaled and the `.tabbar-shell` element is absent in the crop context.
Author
Owner

Part 1 merged into dev at 5d6d22e60 (merged-tree web gates 0 errors, 894/894). Part 2 (hover only over marks, tooltip below the cursor) is queued.

Part 1 merged into dev at 5d6d22e60 (merged-tree web gates 0 errors, 894/894). Part 2 (hover only over marks, tooltip below the cursor) is queued.
Author
Owner

Starting part 2 on job/analytics-504 after merging origin/dev at 5d6d22e604. I’m tracing the current Bklit hover handlers and calternal.js delay/motion before adding mark-only hit tests for bar, donut, hour and heatmap, plus keyboard anchor and viewport-bound tooltip checks.

Starting part 2 on job/analytics-504 after merging origin/dev at 5d6d22e6047e902213980f88df8c77bba463fe10. I’m tracing the current Bklit hover handlers and calternal.js delay/motion before adding mark-only hit tests for bar, donut, hour and heatmap, plus keyboard anchor and viewport-bound tooltip checks.
Author
Owner

Finding in the merged part 1 implementation: bar-chart pointermove resolved a full category band, so empty space to the right of a short bar could still show its tooltip. Heatmap keyboard overlays also covered the full cell pitch, including the visible gap. Part 2 now routes bar hover through painted SVG marks, sizes the keyboard overlays to painted cells, and adds real-server checks for marks and empty points.

Finding in the merged part 1 implementation: bar-chart pointermove resolved a full category band, so empty space to the right of a short bar could still show its tooltip. Heatmap keyboard overlays also covered the full cell pitch, including the visible gap. Part 2 now routes bar hover through painted SVG marks, sizes the keyboard overlays to painted cells, and adds real-server checks for marks and empty points.
Author
Owner

Production analytics E2E evidence: all four new mark/empty-point checks passed (bar, donut, hour cell, calendar heatmap cell), with readouts inside the viewport. The existing Year “Time of day draws marks when hourly data exists” check reported 0 data, 0 painted after seeding 378 Log entries. Its expectation is unchanged; I am checking the period/data setup separately.

Production analytics E2E evidence: all four new mark/empty-point checks passed (bar, donut, hour cell, calendar heatmap cell), with readouts inside the viewport. The existing Year “Time of day draws marks when hourly data exists” check reported `0 data, 0 painted` after seeding 378 Log entries. Its expectation is unchanged; I am checking the period/data setup separately.
Author
Owner

Local #504 performance profile finding: while seeding the 10,220-Log, 365-Day workload, Files returned 503 Service Unavailable: Index is busy; retry shortly for the 2025-07-07 Daily Note. The local server logged SQLite pool-acquire waits up to 14.67 seconds; host load was 41.27 / 37.04 / 32.90. That first attempt stopped before hover measurements. The Analytics profile now retries only this exact seed response with bounded backoff, while retaining the 201 expectation. The measured run is in progress. This is load-sensitive (SLOW) evidence; no API or product assertion changed.

Local #504 performance profile finding: while seeding the 10,220-Log, 365-Day workload, Files returned `503 Service Unavailable: Index is busy; retry shortly` for the 2025-07-07 Daily Note. The local server logged SQLite pool-acquire waits up to 14.67 seconds; host load was 41.27 / 37.04 / 32.90. That first attempt stopped before hover measurements. The Analytics profile now retries only this exact seed response with bounded backoff, while retaining the 201 expectation. The measured run is in progress. This is load-sensitive (`SLOW`) evidence; no API or product assertion changed.
Author
Owner

Second local #504 profile finding: the 10,220-entry year indexed successfully. The existing warm Analytics API probe measured median 666.2 ms and p90 744.2 ms, so its unchanged 200 ms check failed. The server also logged SQLite pool waits above 2 seconds and a 10,220-row query taking 1.07 seconds. Host load reached 47.05 / 42.16 / 38.04 during the run. The hover sampler then stopped before taking tooltip samples because its bar locator matched six marks and its renderer PID was captured before navigation. I fixed the mark selection and now start sampling after the production year charts mount (commit a44d4c48a65f6081523dbd29a45f6bee1aa2d5d5). No hover metrics were written by this attempt.

Second local #504 profile finding: the 10,220-entry year indexed successfully. The existing warm Analytics API probe measured median 666.2 ms and p90 744.2 ms, so its unchanged 200 ms check failed. The server also logged SQLite pool waits above 2 seconds and a 10,220-row query taking 1.07 seconds. Host load reached 47.05 / 42.16 / 38.04 during the run. The hover sampler then stopped before taking tooltip samples because its bar locator matched six marks and its renderer PID was captured before navigation. I fixed the mark selection and now start sampling after the production year charts mount (commit `a44d4c48a65f6081523dbd29a45f6bee1aa2d5d5`). No hover metrics were written by this attempt.
Author
Owner

The 10,220-Log profile confirmed an existing Year-view gap: the Year page has no hourly mark buttons after the full index is ready, so the profile cannot collect an hour-cell latency sample there. This matches the earlier unchanged E2E check Time of day draws marks when hourly data exists reporting 0 data, 0 painted. The requested hour hover and empty-gap checks pass on the Week view with real API data. I kept the expectation unchanged. The benchmark now measures Year marks that exist and the 365-cell heatmap burst; the profile README records why it has no separate Year-hour sample.

The 10,220-Log profile confirmed an existing Year-view gap: the Year page has no hourly mark buttons after the full index is ready, so the profile cannot collect an hour-cell latency sample there. This matches the earlier unchanged E2E check `Time of day draws marks when hourly data exists` reporting `0 data, 0 painted`. The requested hour hover and empty-gap checks pass on the Week view with real API data. I kept the expectation unchanged. The benchmark now measures Year marks that exist and the 365-cell heatmap burst; the profile README records why it has no separate Year-hour sample.
Author
Owner

Completed: Analytics tooltip hover behavior (#504, part 2)

Built

  • Bar previews now hit-test painted bar rectangles. Donut previews hit-test the painted slice arc. Hour and calendar heatmaps target painted cell rectangles. Empty tracks, bar gaps, slice gaps and chart backgrounds do not open a preview.
  • Cursor previews open below the pointer, flip near the viewport edge, and remain inside the viewport. Keyboard focus opens the same readout anchored to the focused mark.
  • Tooltip motion and delay follow the calternal.js Analytics implementation: compositor transform follow, 160 ms enter, 100 ms exit, reduced-motion support, and the heatmap's 140 ms hide grace.
  • Added exact mark/empty checks for bar, donut, hour and heatmap, plus keyboard and viewport placement checks.
  • Added the production screenshot matrix and 3× hover crops. All evidence is attached below.

Files

  • apps/web/e2e/analytics.mjs: production hover checks, screenshot matrix and local hot-path profile.
  • apps/web/src/lib/components/analytics/: chart adapter, exact keyboard mark targets and tests.
  • apps/web/src/lib/components/analytics/vendor/bklit/: bar, pie, heatmap and tooltip hit testing; cursor and keyboard placement; patch notes. Removed the superseded band-invert.ts helper and test.
  • bench/analytics-hover.sh and docs/perf/README.md: profile entry point and workload documentation.

Commits

  • 535b88d3772b9ac501346fb50af42ec33d015c91 — fix previews on painted marks.
  • a44d4c48a65f6081523dbd29a45f6bee1aa2d5d5 — add the Analytics hover workload profile.
  • ed4ec1a70bf4434435ef02d421b8be0649cb80e2 — profile available Year marks.

Head: ed4ec1a70bf4434435ef02d421b8be0649cb80e2. origin/dev was merged before final gates.

E2E and known gaps

The four requested mark/empty hover checks passed for bar, donut, hour and calendar heatmap. The production E2E run still has unrelated existing failures: its Year time-of-day assertion receives 0 hourly data/0 marks from the 378-Log fixture, and existing chart CPU timing thresholds fail under shared host load. I did not change their expectations.

The local profile seeded and indexed all 10,220 Log entries. Its warm Year API sample was p50 256.4 ms / p90 500.9 ms, above the existing 200 ms SLOW threshold under shared load. The profile process exited before producing tooltip, CPU/RSS or heatmap-burst metrics, so it produced no comparable run JSON and no baseline update. I did not repeat the profile.

Screenshot evidence

Dashboard matrix: light/dark × color/photo backgrounds at 390, 820 and 1440 px.

3× tooltip crops:

Web gates (verbatim)

bun run check:

$ node scripts/check-type-tokens.mjs && svelte-kit sync && svelte-check --tsconfig ./tsconfig.json
Text sizes and UI shape values use shared role tokens.
Loading svelte-check in workspace: /home/kayg/Developer/calternal-wt/analytics-504/apps/web
Getting Svelte diagnostics...

svelte-check found 0 errors and 0 warnings

bun run test:

$ vitest run

 RUN  v5.0.1 /home/kayg/Developer/calternal-wt/analytics-504/apps/web

Could not parse CSS stylesheet
Not implemented: Window's scrollTo() method
Not implemented: Window's scrollTo() method
Not implemented: Window's scrollTo() method
Not implemented: Window's scrollTo() method
Not implemented: Window's scrollTo() method
Not implemented: Window's scrollTo() method
Not implemented: Window's scrollTo() method
Not implemented: Window's scrollTo() method
Not implemented: Window's scrollTo() method
Not implemented: Window's scrollTo() method
Not implemented: Window's scrollTo() method
Not implemented: Window's scrollTo() method
Not implemented: Window's scrollTo() method
Not implemented: Window's scrollTo() method
Not implemented: Window's scrollTo() method
Not implemented: Window's scrollTo() method
Not implemented: Window's scrollTo() method
Not implemented: Window's scrollTo() method
Not implemented: Window's scrollTo() method
Not implemented: Window's scrollTo() method
Not implemented: Window's scrollTo() method
Not implemented: Window's scrollTo() method
Not implemented: Window's scrollTo() method
Not implemented: Window's scrollTo() method
Not implemented: Window's scrollTo() method
Not implemented: Window's scrollTo() method
Not implemented: Window's scrollTo() method
Not implemented: Window's scrollTo() method
Not implemented: Window's scrollTo() method
Not implemented: Window's scrollTo() method
Not implemented: Window's scrollTo() method
Not implemented: Window's scrollTo() method
Not implemented: Window's scrollTo() method
Not implemented: Window's scrollTo() method
Not implemented: Window's scrollTo() method
Not implemented: Window's scrollTo() method
Not implemented: Window's scrollTo() method
Not implemented: Window's scrollTo() method
Not implemented: Window's scrollTo() method

 Test Files  136 passed (136)
      Tests  890 passed (890)
   Start at  19:31:58
   Duration  197.96s (transform 54%, environment 20%, import 12%, tests 9%, setup 4%)

Environment  |component| jsdom was created 43 times · 221.81s total, 29% of tracked time
             create it once per worker with pool: 'vmThreads' (keeps per-file isolation) or isolate: false (shares it across files)
             learn more: https://vitest.dev/guide/improving-performance#test-environments

No Rust source changed, so no Rust crate gates were needed. cargo clean removed 7,067 files (4.4 GiB), and generated web build output was removed after the gates.

Decisions not specified by DESIGN

  • The performance profile uses real 2025 Daily Notes (10,220 Log entries across 365 dates). The Year report has no hourly marks, so the hour tooltip is exercised in the Week view E2E checks and excluded from the Year hover measurements.
  • The screenshot theme matrix uses the existing light and dark themes over both color and photo backgrounds; 3× crops use the photo background for a consistent tooltip close-up.
## Completed: Analytics tooltip hover behavior (#504, part 2) ### Built - Bar previews now hit-test painted bar rectangles. Donut previews hit-test the painted slice arc. Hour and calendar heatmaps target painted cell rectangles. Empty tracks, bar gaps, slice gaps and chart backgrounds do not open a preview. - Cursor previews open below the pointer, flip near the viewport edge, and remain inside the viewport. Keyboard focus opens the same readout anchored to the focused mark. - Tooltip motion and delay follow the calternal.js Analytics implementation: compositor transform follow, 160 ms enter, 100 ms exit, reduced-motion support, and the heatmap's 140 ms hide grace. - Added exact mark/empty checks for bar, donut, hour and heatmap, plus keyboard and viewport placement checks. - Added the production screenshot matrix and 3× hover crops. All evidence is attached below. ### Files - `apps/web/e2e/analytics.mjs`: production hover checks, screenshot matrix and local hot-path profile. - `apps/web/src/lib/components/analytics/`: chart adapter, exact keyboard mark targets and tests. - `apps/web/src/lib/components/analytics/vendor/bklit/`: bar, pie, heatmap and tooltip hit testing; cursor and keyboard placement; patch notes. Removed the superseded `band-invert.ts` helper and test. - `bench/analytics-hover.sh` and `docs/perf/README.md`: profile entry point and workload documentation. ### Commits - `535b88d3772b9ac501346fb50af42ec33d015c91` — fix previews on painted marks. - `a44d4c48a65f6081523dbd29a45f6bee1aa2d5d5` — add the Analytics hover workload profile. - `ed4ec1a70bf4434435ef02d421b8be0649cb80e2` — profile available Year marks. Head: `ed4ec1a70bf4434435ef02d421b8be0649cb80e2`. `origin/dev` was merged before final gates. ### E2E and known gaps The four requested mark/empty hover checks passed for bar, donut, hour and calendar heatmap. The production E2E run still has unrelated existing failures: its Year time-of-day assertion receives 0 hourly data/0 marks from the 378-Log fixture, and existing chart CPU timing thresholds fail under shared host load. I did not change their expectations. The local profile seeded and indexed all 10,220 Log entries. Its warm Year API sample was p50 256.4 ms / p90 500.9 ms, above the existing 200 ms SLOW threshold under shared load. The profile process exited before producing tooltip, CPU/RSS or heatmap-burst metrics, so it produced no comparable run JSON and no baseline update. I did not repeat the profile. ### Screenshot evidence Dashboard matrix: light/dark × color/photo backgrounds at 390, 820 and 1440 px. - [analytics-material-color-dark-1440.png](https://git.kayg.org/attachments/c517c70f-665f-4153-abcc-f4dae087c697) - [analytics-material-color-dark-390.png](https://git.kayg.org/attachments/41409e5c-cc14-4efb-bed8-b0bd84fb85a6) - [analytics-material-color-dark-820.png](https://git.kayg.org/attachments/88e9cea5-3cf7-402c-b6cb-6ff17d1385c3) - [analytics-material-color-light-1440.png](https://git.kayg.org/attachments/d26fffa1-0c9e-48b7-8b1d-0bd95ed48542) - [analytics-material-color-light-390.png](https://git.kayg.org/attachments/c6fbb5bb-fe54-4b16-886e-2d476e72ec7e) - [analytics-material-color-light-820.png](https://git.kayg.org/attachments/7ecec9dd-e345-4b68-bc60-37e595d62b72) - [analytics-material-photo-dark-1440.png](https://git.kayg.org/attachments/d003a2ce-cb74-4982-968c-57c8907e37d0) - [analytics-material-photo-dark-390.png](https://git.kayg.org/attachments/18be42e1-745d-4c87-a9fe-781db6cafa2e) - [analytics-material-photo-dark-820.png](https://git.kayg.org/attachments/a7315697-870e-42cc-8a55-ad1383060c56) - [analytics-material-photo-light-1440.png](https://git.kayg.org/attachments/45ccfffd-793c-4ee3-acb0-bef08e87fa87) - [analytics-material-photo-light-390.png](https://git.kayg.org/attachments/42cce87d-ff31-48d5-bc87-f0d3d9d7cad5) - [analytics-material-photo-light-820.png](https://git.kayg.org/attachments/7bf3d0b1-4bcd-4c03-b13f-cf601af7dc9d) 3× tooltip crops: - [analytics-tooltip-photo-dark-1440-3x.png](https://git.kayg.org/attachments/a15ebf37-8e7a-41b1-8a22-d6c14a2de731) - [analytics-tooltip-photo-dark-390-3x.png](https://git.kayg.org/attachments/195eab0e-e63e-4b4c-ade4-517dcaa449a9) - [analytics-tooltip-photo-light-1440-3x.png](https://git.kayg.org/attachments/7a7b8de0-9a6f-4bb5-bf72-1b6144334994) - [analytics-tooltip-photo-light-390-3x.png](https://git.kayg.org/attachments/8f3178f6-1781-4740-af25-d1b8d42ee610) ### Web gates (verbatim) `bun run check`: ```text $ node scripts/check-type-tokens.mjs && svelte-kit sync && svelte-check --tsconfig ./tsconfig.json Text sizes and UI shape values use shared role tokens. Loading svelte-check in workspace: /home/kayg/Developer/calternal-wt/analytics-504/apps/web Getting Svelte diagnostics... svelte-check found 0 errors and 0 warnings ``` `bun run test`: ```text $ vitest run RUN v5.0.1 /home/kayg/Developer/calternal-wt/analytics-504/apps/web Could not parse CSS stylesheet Not implemented: Window's scrollTo() method Not implemented: Window's scrollTo() method Not implemented: Window's scrollTo() method Not implemented: Window's scrollTo() method Not implemented: Window's scrollTo() method Not implemented: Window's scrollTo() method Not implemented: Window's scrollTo() method Not implemented: Window's scrollTo() method Not implemented: Window's scrollTo() method Not implemented: Window's scrollTo() method Not implemented: Window's scrollTo() method Not implemented: Window's scrollTo() method Not implemented: Window's scrollTo() method Not implemented: Window's scrollTo() method Not implemented: Window's scrollTo() method Not implemented: Window's scrollTo() method Not implemented: Window's scrollTo() method Not implemented: Window's scrollTo() method Not implemented: Window's scrollTo() method Not implemented: Window's scrollTo() method Not implemented: Window's scrollTo() method Not implemented: Window's scrollTo() method Not implemented: Window's scrollTo() method Not implemented: Window's scrollTo() method Not implemented: Window's scrollTo() method Not implemented: Window's scrollTo() method Not implemented: Window's scrollTo() method Not implemented: Window's scrollTo() method Not implemented: Window's scrollTo() method Not implemented: Window's scrollTo() method Not implemented: Window's scrollTo() method Not implemented: Window's scrollTo() method Not implemented: Window's scrollTo() method Not implemented: Window's scrollTo() method Not implemented: Window's scrollTo() method Not implemented: Window's scrollTo() method Not implemented: Window's scrollTo() method Not implemented: Window's scrollTo() method Not implemented: Window's scrollTo() method Test Files 136 passed (136) Tests 890 passed (890) Start at 19:31:58 Duration 197.96s (transform 54%, environment 20%, import 12%, tests 9%, setup 4%) Environment |component| jsdom was created 43 times · 221.81s total, 29% of tracked time create it once per worker with pool: 'vmThreads' (keeps per-file isolation) or isolate: false (shares it across files) learn more: https://vitest.dev/guide/improving-performance#test-environments ``` No Rust source changed, so no Rust crate gates were needed. `cargo clean` removed 7,067 files (4.4 GiB), and generated web build output was removed after the gates. ### Decisions not specified by DESIGN - The performance profile uses real 2025 Daily Notes (10,220 Log entries across 365 dates). The Year report has no hourly marks, so the hour tooltip is exercised in the Week view E2E checks and excluded from the Year hover measurements. - The screenshot theme matrix uses the existing light and dark themes over both color and photo backgrounds; 3× crops use the photo background for a consistent tooltip close-up.
Author
Owner

Shipped in merge round 4, deployed to calternal.cloud in 1af8ead26 (healthy).

Shipped in merge round 4, deployed to calternal.cloud in 1af8ead26 (healthy).
kayg closed this issue 2026-10-01 09:17:47 +00:00
Sign in to join this conversation.
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
kayg/calternal#504
No description provided.