Commit graph

50 commits

Author SHA1 Message Date
iamtoruk
cbddd3a9d7 fix(app): accuracy batch A — provider scoping, honest chart axes, range threading, stale-error banner
- Provider filter: Models-this-period sources current.topModels (history
  days carry empty topModels per provider); StackedBars falls back to a
  cost-proportional single segment like the Swift menubar
- Chart windows align to the CLI (week -7, 30days -30, all = 6 months)
  and zero-fill a contiguous calendar window; history.daily is sparse and
  both sides key local YYYY-MM-DD, so lookups are safe (verified on real
  CLI output)
- Custom range threads into Overview panels (chart, models table) and
  suppresses MTD/projected and vs-last-week comparisons; Compare states
  that custom dates fall back to the period
- usePolled clears errors per attempt and sections show a StaleBanner
  instead of silently rendering last-good data after a failed refresh
- Cache-hit denominator matches the CLI; hero savings relabeled 'Saved by
  applied fixes' + new 'Saved via local models' line; formatCompact
  everywhere; Optimize 'Fixes' count matches the rendered list

App suite 163/163 (was 147), root 1613/1613.
2026-07-16 01:14:41 -07:00
iamtoruk
a8351bfd1a fix(app): daily charts empty/flat on real data — use real last-N days
contiguousDailyWindow rebuilt a calendar window from the client clock and looked
up days by date key; on real CLI data every lookup missed and zero-filled, so the
Spend chart went empty and the Overview chart went flat. Use the real last-N
backfilled entries of history.daily directly (Spend last-15, Overview
last-max(30, periodDaily)) and remove the dead helper.

typecheck clean; 147/147 tests pass.
2026-07-12 17:06:46 -07:00
iamtoruk
a216b841ae feat(app): rebuild Plans on live quota (real 5h/weekly windows + auto-detected tier)
Replace the $-budget model as the primary view: per-provider cards (Claude/Codex)
from getQuota show the real 5-hour/weekly windows (% used, resets-in, severity
colors), the auto-detected subscription tier, connection states, and the credit
footer. Manual budget plans demoted to a secondary section.

typecheck clean; 148/148 tests pass. Needs a full relaunch for live quota.
2026-07-12 16:48:58 -07:00
iamtoruk
905d94253a feat(app): actionable Optimize — wire the CLI's rich findings + copy-paste fixes
- new getOptimizeReport bridge (main + preload + renderer types) running
  `codeburn optimize --format json` (needs a full relaunch)
- restore the Waste / Reverts / Abandoned / Fixes tabs
- Waste findings expand inline to show the explanation (why you're losing
  tokens) + a copy-paste fix block with a Copy button, like the TUI
- summary header: findings count / potential savings / health score

typecheck clean; 133/133 tests pass.
2026-07-12 16:28:47 -07:00
iamtoruk
82f0402abd feat(app): Spend chart — fixed 15-day window + date axis, no gridlines
- extract contiguousDailyWindow + formatChartDate to lib/period (shared)
- Spend "Daily spend by model": fixed contiguous 15-day window (zero-filled)
  with an .ov-xax date axis, matching the Overview chart
- remove the horizontal gridlines from both charts (they read like data lines)

typecheck clean; 129/129 tests pass.
2026-07-12 16:21:41 -07:00
iamtoruk
185f25f8d1 feat(app): fixed-height + scrollbar on Spend list panels
By-project and the Activity/Tools/MCP/Subagents breakdown panels cap at 300px
with a slim internal scrollbar, so they stay a consistent compact size instead
of growing unbounded with the data.

typecheck clean; 126/126 tests pass.
2026-07-12 15:56:07 -07:00
iamtoruk
0bab74c18d feat(app): flatten Optimize to one page (no tabs)
Drop the Waste/Reverts/Abandoned/Fixes tabs. One scrolling page: findings
(count + potential in the header), then Reverted and Abandoned session sections;
empty sections hidden. The redundant Fixes tab folds into the findings header.

typecheck clean; 126/126 tests pass (removed 2 now-moot tab-isolation tests;
impact-badge + section coverage preserved).
2026-07-12 15:34:16 -07:00
iamtoruk
bd32624afb feat(app): flatten Spend to one page (no tabs)
Drop the Projects/Activity/Tools/MCP/Subagents lens tabs. Everything shows on
one scrolling page: chart + By-project, Cost-flow Sankey, then the breakdown
sections in a responsive grid. Empty sections are hidden. All reflects the
selected date range.

typecheck clean; 128/128 tests pass.
2026-07-12 15:30:00 -07:00
iamtoruk
642a12b7ff feat(app): remove the Nearest-limit quota ring from Overview
Drop the FuelRing (and its now-unused plans polling) from the ov-stats3 card;
the stats row is now Month-to-date + Projected month (2 equal columns).

typecheck clean; 128/128 tests pass.
2026-07-12 15:25:00 -07:00
iamtoruk
49a2811093 feat(app): Settings — custom dropdowns, more currencies, fix pane layout
- new Dropdown component (our .pop menu style, keyboard-accessible) replacing
  every native <select> (currency, period, plan preset, export, Compare pickers)
- expand currencies to 30 common ISO codes (engine handles any valid currency)
- fix the Settings pane so rail + content anchor top-left and fill the area

typecheck clean; 128/128 tests pass.
2026-07-12 14:02:52 -07:00
iamtoruk
76a5db4f55 feat(app): Optimize organization + gear icon, more logos, drop relative-cost column
- Optimize: colored impact badges (High/Medium/Low) + fixed-column layout;
  fix the dead "Fixes" tab; findings no longer look falsely clickable
- Optimize nav icon: gear + magnifying glass (was a lightning bolt)
- remove the "Relative cost" bar column from the Overview models table
- provider logos: Goose / Pi / Warp + Cursor Agent (own logo) from repo assets

typecheck clean; 128/128 tests pass.
2026-07-12 13:56:07 -07:00
iamtoruk
a02ae15b6b feat(app): rebuild Sessions — fixed columns, clean paths, inline expand
- share a shortenProjectPath helper (Sankey + Sessions) so rows show
  "projects/eywa" instead of the dash-mangled full path
- fixed-column table layout so values align and stop shifting row-to-row
- TUI-style inline row expansion: click a row to unfold its 8-stat detail in
  place (one at a time, chevron + aria-expanded); replaces the navigate-away view

typecheck clean; 128/128 tests pass.
2026-07-12 13:38:45 -07:00
iamtoruk
44ef875a6d fix(app): adaptive K/M/B token counts on Models (was forced to M)
Models used a local fmtCompact that forced every token count to "M" (0.0M, 0.5M).
Switch to the shared adaptive formatCompact (K/M/B, whole numbers under 1000).

typecheck clean; 128/128 tests pass.
2026-07-12 13:32:46 -07:00
iamtoruk
144d2b3363 fix(app): strip prose em-dashes from UI copy
Replace em-dashes used as sentence punctuation (Plans, Settings, Compare,
Overview, CliErrorPanel) with cleaner punctuation; keep the standalone "—"
empty-value placeholders (a no-data convention). Update affected copy assertions.

typecheck clean; 128/128 tests pass.
2026-07-12 13:13:31 -07:00
iamtoruk
34333dc2c5 feat(app): more provider logos + drop redundant session dot
- ProviderLogo: add Copilot/Gemini/Qwen/OpenCode marks; reuse the Cursor logo
  for Cursor Agent; single-color logos (Claude, Gemini) via a SINGLE_LOGOS map
- remove the redundant model-series dot from Overview "Most expensive sessions"
  (the row already names the model in its sub text)

typecheck clean; 128/128 tests pass.
2026-07-12 13:09:53 -07:00
iamtoruk
428caab6fd feat(app): real provider logos in the picker and Settings
- add Claude/OpenAI/Cursor/Grok brand SVGs under app/renderer/assets/providers
- ProviderLogo component: brand-orange Claude in both themes; light/dark
  monochrome variants for OpenAI/Cursor/Grok swapped per active theme
- show the logo in the provider dropdown (trigger + menu items) and in
  Settings > Providers, left of each provider name

typecheck clean; 128/128 tests pass.
2026-07-12 13:00:43 -07:00
iamtoruk
3f40aeee97 feat(app): Sankey slash-paths + Models "By task" regroup
- Sankey project labels now show the last 2-3 path segments joined by "/"
  (dropping the users/home prefix) instead of the dash-mangled full path
- Models "By task" regrouped CI-style: a per-model group header (series dot +
  model + aggregate calls/cost/saved) with indented task sub-rows and aligned
  columns, replacing the flat list that repeated the model name on every row

typecheck clean; 128/128 tests pass.
2026-07-12 12:58:15 -07:00
iamtoruk
b0299c57ac feat(app): design reskin — token unification, a11y, and chart color + shading
Design-consistency pass (from the audit):
- unify the indigo→plain grey/border token families (alias --t1/2/3, --hair/2 onto --ink/mut/mut2, --line/2); fix a leftover hardcoded chevron color
- accent :focus-visible rings on SegTabs, chart bars, calendar, buttons, Settings toggles; ov-link hover
- theme-aware Spend legend swatches + Sankey (fixes a light-mode contrast failure)
- wire Models "Compare…" → Compare and Plans "Add plan…" → Settings pane; drop the fake-affordance Plans label; Settings loading captions
- Compare card radius/title, set-input, alias CTA color, outer-border tokens, session mono numbers, frame spacing to match the mockup
- scope a date-flaky Overview test assertion to its card

Reskin batch 1 — color + shade (current tone):
- validated CVD-safe model-series palette via dedicated --s-* tokens (light+dark), applied to the daily bars, Sankey, and series dots
- subtle soft card elevation via --card-shadow on the main card containers

typecheck clean; 128/128 tests pass.
2026-07-12 12:36:50 -07:00
iamtoruk
1de907ac8b feat(app): Settings part 2 — Plans, Export, Devices actions, theme on boot
- Plans tab: add/remove budget presets via `plan set`/`plan reset`, lists
  configured plans, links to the full Plans screen
- Export tab: format + provider + native folder picker (electron dialog)
  → runs `codeburn export`, reports the result
- Devices: real Remove (`devices rm`) + Refresh; visibility is read-only
  from `share status`; pairing shows an honest "pair from terminal" note
  instead of a dead Approve button; combine row is read-only status
- Apply the persisted theme at app startup (not only when General mounts)
- Settings gets onNavigate for the "Open Plans" link

Only one-shot, non-interactive CLI commands are wired as buttons; the
interactive share daemon and pairing flow stay honestly read-only.
2026-07-11 17:31:32 -07:00
iamtoruk
55e9fa51f6 feat(app): functional Settings — rail nav + General/Providers/Aliases/Privacy
Settings was a dead shell (rail didn't switch, all buttons disabled).
Now the rail navigates and four tabs are wired to the real CLI:
- action bridge: spawnCliAction + runAction (text output, not JSON) with
  getAliases/getProxyPaths reads and setCurrency/resetCurrency/addAlias/
  removeAlias actions
- General: theme switcher (System/Light/Dark, persisted) + live currency
  (reads status, changes via `currency`) + default-period preference
- Providers: real detected-tools list with spend
- Model aliases: full add/remove against real config
- Privacy: honest local-only info

Devices content preserved as-is; Plans/Export are placeholders for Part 2.
2026-07-11 17:24:04 -07:00
iamtoruk
1efc0ceb44 fix(app): daily-spend chart fills its card, bars bottom-aligned
The StackedBars chart lived in a fixed 96px band, so when the grid
stretched its card to match the taller "By project" panel the bars
floated at the top over a large empty gap. Make the panel/body flex so
the chart fills the card height (min 120px) with bars bottom-anchored;
round stacked-segment corners only at the top/bottom of each column.
2026-07-11 17:06:00 -07:00
iamtoruk
d9c56e3c6b feat(app): production-ready Sessions screen
Search (project/model/id), sort (cost/recent/turns/tokens), group-by-
provider toggle, and a summary bar (count · cost · tokens) over the
filtered set. Dependency-free "show more" paging keeps large lists fast;
provider headers are sticky and the list flows in the page scroll.

Richer detail: 8 real stat cards (cost/calls/turns/saved/input/output/
cache read+hit%/cache write), full date range + duration, Esc-to-back,
selection tracked by id so background refreshes keep the detail live.

Centralizes formatCompact/date/duration helpers in lib/format ("184K"
not "0.2M"); Compare now uses the shared helper. Search-aware empty state.
2026-07-11 13:50:58 -07:00
iamtoruk
e331c7da63 feat(app): Sessions and Compare screens
Sessions: provider-grouped list of every session in range (project,
models, turns, cost, tokens) with a lightweight real detail — no
fabricated titles, no unbacked context-window widget.

Compare: two-model picker (defaults to top two by cost) across
Performance, Efficiency, Category head-to-head, Working style, and a
derived Context panel, all mapped straight from `compare --format json`.

Nav reordered to match the design: Overview, Sessions, Spend, Optimize,
Models, Compare, Plans, Settings (⌘1-7).
2026-07-11 12:37:04 -07:00
iamtoruk
22c5eabd21 style(app): move daily-spend chart up to a full-width row under the stats card
The trend chart is the headline breakdown; pull it out of the rail into
a prominent full-width row (row 3), above the insight/analytics bands.
2026-07-11 12:04:00 -07:00
iamtoruk
a39b2630c5 style(app): arrange Overview body into a balanced dashboard
Re-arrange everything below the two top cards so it reads as a dashboard:
- Insight band grouping the coach pacing line + anomaly callouts.
- Analytics row: Cost-per-outcome | Routing what-if (equal 2-up).
- Height-balanced 2-column body — Left: Models table + Most expensive
  sessions; Right: Top activities + Daily spend — so the left column no
  longer dead-ends into a big empty gap.
- Consistent gaps, align-items:start, single-column reflow under 900px.
typecheck clean, 88 tests pass.
2026-07-11 12:00:33 -07:00
iamtoruk
a50389b076 style(app): Overview into divided 3-column cards + metallic grade medal
- Top card: one card, three equal columns split by dividers —
  current spend (with Saved-to-date) | daily activity | efficiency
  scorecard. Removed the duplicate one-shot/cache ratings column and the
  separate efficiency card (EfficiencyScorecard + FuelRing gain a 'bare'
  mode).
- Stats: one card, three equal divided columns — Month-to-date |
  Projected | Nearest-limit fuel ring.
- Efficiency grade is now a circular brushed-metal medal (one subtle
  gradient + inset highlight + depth shadow), tiered A/B-C/D/F, tokenized
  for light+dark — premium, not the flat AI-looking pill.
- Tightened spacing/dead space; 1-column reflow under 900px.
typecheck clean, 88 tests pass.
2026-07-11 11:47:30 -07:00
iamtoruk
a4259720f2 style(app): 3-section hero card + fuel ring into the stats row
- Hero card now splits into three divider-separated sections: current
  spend | daily-activity heatmap | one-shot/cache/saved ratings.
- Move the Nearest-limit fuel ring next to Month-to-date and Projected
  (fills the previously-empty third stats column). Efficiency scorecard
  takes the row above.
2026-07-11 11:34:36 -07:00
iamtoruk
9bc06e74ad style(app): merge hero + daily-activity heatmap into one split card
Per feedback, the hero (number + KPIs) and the git-style daily-activity
heatmap now share a single card, split left/right with a divider.
ActivityHeatmap gains a 'bare' mode (renders head+grid without its own
card wrapper). Efficiency scorecard + fuel ring move to a row below.
2026-07-11 11:30:15 -07:00
iamtoruk
7ad1b76a8c style(app): move daily-activity heatmap up under the hero row
The git-style contribution heatmap was buried at the bottom; pull it up
to a prominent full-width strip right below the hero row.
2026-07-11 11:25:40 -07:00
iamtoruk
0ba3a853d8 feat(app): Overview v2 phase 2 — efficiency scorecard, cost-per-outcome, anomalies, routing what-if
Unique widgets neither the TUI nor menubar has, all from real data:
- Efficiency scorecard: A+..F composite (45% one-shot / 30% cache /
  25% retry-health), with the source component rows + retry share of
  spend; null one-shot → neutral input + 'partial' disclosure.
- Cost per outcome (new getYield poll): $/commit, $/productive session,
  productive/reverted/abandoned split; honest — for zero/empty/error.
- Anomaly callouts: today-vs-weekday (1.8x), w/w spend (25%), low cache
  (<50%); strip omitted when nothing fires.
- Routing what-if from current.routingWaste (omitted unless positive).
typecheck clean, 88 tests pass.
2026-07-11 11:24:47 -07:00
iamtoruk
8e00356724 refactor(app): merge KPI strip into the hero card
The KPI strip duplicated the hero (Spend = hero total, Calls/Sessions =
hero subline). Drop the strip; fold the unique KPIs — One-shot, Cache
hit, Saved — into the hero as a secondary row (keeps the a11y label).
2026-07-11 11:15:45 -07:00
iamtoruk
9d906832f6 feat(app): Overview v2 phase 1 — dashboard layout, KPI strip, activity heatmap
- Full-width responsive dashboard grid (2-col body, reflows <900px) so the
  Overview uses the window instead of a narrow column.
- KPI strip: Spend/Calls/Sessions + one-shot rate (current.oneShotRate,
  the previously-missing metric; null → em dash) + cache-hit % + Saved.
- New ActivityHeatmap: GitHub-style 26-week contribution grid from
  history.daily (5 cost levels, active-day count, portal tooltip), ported
  from the menubar's ContributionHeatmapInsight.
- Top activities rail: name · cost · turns · one-shot % (current.topActivities).
- All real payload data, no new bridge calls. typecheck clean, 87 tests pass.
2026-07-11 11:12:41 -07:00
iamtoruk
dce18fff83 feat(app): Overview redesign — models table, legible chart, period-aware hero
- Hero now reflects the SELECTED period (current.cost + current.label +
  calls/sessions), not just today — 30D no longer shows today's number.
- New Models table: per-model Input/Output tokens + Cost + Calls,
  aggregated from history.daily[].topModels[] (real per-day data),
  rebuilt with a robust bar → left-name → right-numbers layout (fixes
  the offset/misaligned columns).
- Daily chart: weekly date ticks (MMM d), Avg/Peak/Yesterday chips, and
  the hover tooltip now portals to document.body (position:fixed,
  edge-clamped) so it is never clipped.
- Removed the meaningless decorative sparklines. Empty fuel-ring card no
  longer reserves a tall empty box.
- typecheck clean, 87 vitest pass.
2026-07-11 09:33:51 -07:00
iamtoruk
d0ce20e49c feat(app): working periods, detected-provider dropdown, drag-select date range
- Period seg now uses the 5 real CLI periods (Today/7D/30D/Month/6M);
  6M maps to 'all' (matches the menubar).
- Provider control is a real dropdown listing only DETECTED providers
  (accumulated from current.providers so it never shrinks) + All.
- New RangeCalendar: month grid with click-and-drag range selection
  (+ two-click fallback, future-date disabling) behind a calendar button;
  commits a custom {from,to} threaded to Overview/Spend/Models/Optimize
  via new --from/--to CLI args (Plans/Settings stay period-only).
- typecheck clean, 87 vitest pass.
2026-07-11 09:14:54 -07:00
iamtoruk
51e47112ca fix(app): Overview daily chart min 30-day window, internal scroll, native chrome
- Daily-spend chart always shows a contiguous >=30 calendar-day trend
  (backfilling gaps with zero bars) instead of collapsing to the period
  selector (e.g. a single bar on Today).
- Real app shell: viewport-height window with an internally scrolling
  .body (was clipped/unscrollable).
- Drop the wireframe's fake traffic-light dots; rely on the real OS
  window controls. Window background follows the system theme.
- Update Overview test to assert the 30-day chart window.
2026-07-11 08:48:35 -07:00
iamtoruk
95cf876999 feat(app): plain theme + Overview reskin wired to real data
New plain.css token layer (light+dark) repaints the whole app shell;
Overview.tsx rebuilt to the locked mockup: hero burn with count-up +
streak, budget fuel ring (getPlans), coach insight, Saved-to-date
(act report), area sparklines, gridline + hover-tooltip daily chart,
sessions. Adds getActReport bridge plumbing. All data real/derived;
per-day tooltip shows calls (no per-day sessions field). typecheck
clean, 82/82 vitest pass.

Note: Saved-to-date needs a codeburn build with 'act report --json'
(source-only today; installed 0.9.15 lacks it) — falls back to $0.
2026-07-11 08:32:11 -07:00
iamtoruk
f362195946 fix(app): final-review nits — app menu (⌘R refresh), honest model labels, yield retain, hint cleanup
Install an app menu without the CmdOrCtrl+R reload accelerator so ⌘R reaches the renderer for
in-place refresh (keeps Edit/Window roles + dev DevTools). Model labels are now family-level
("Opus"/"Sonnet"/"Haiku"/"GPT / Codex") and the Sankey shows the real model id instead of the
wireframe's sample version names. Optimize retains last-good yield across 30s revalidation (no
flicker to "—"). Removed hints for unimplemented ⌘K/⌘E/esc; fixed stale TopBar comment.

Implemented by Codex gpt-5.5 (high); committed by Fable (git blocked in Codex sandbox).
2026-07-10 19:54:09 -07:00
iamtoruk
9e6ea306fe feat(app): T8 integration + cleanup — single refresh, ⌘-nav, shared error/format/period/series, README
- One 30s refresh + manual ⌘R; footer shows real last-fetch time; getOverview fetched once (no double-poll).
- Keyboard nav: ⌘1–⌘5/⌘, switch sections, ⌘R refresh.
- Verified period/provider re-polls all sections.
- Shared CliErrorPanel: amber permission ("Full Disk Access") vs red error, used by every section.
- DRY: shared lib/format.ts (USD), lib/period.ts (Overview migrated to it), lib/modelSeries.ts (unified model→series).
- Settings review-minor tests (!paired filter, empty/not-found states) + App.test.tsx.
- app/README.md incl. the approved M2 delivery model (self-contained, bundles engine, Electron auto-updater).
- 76 tests, typecheck clean. Live GUI smoke (npm --prefix app run dev) still pending a display.

Implemented by Codex gpt-5.5 (high); committed by Fable (git blocked in Codex sandbox).
2026-07-10 19:35:41 -07:00
iamtoruk
dc52b3226b feat(app): Settings/Devices section + getDevicesScan bridge
Settings rail (Devices active) with This device (getIdentity), Discovered nearby
(new getDevicesScan bridge → `codeburn devices scan --format json`), and Paired
(getDevices perDevice). Pairing/approve/pull/visibility/combine are M1 visual
affordances (mutations = M2); share status is process-local so not shown as
authoritative. Settings uses a title-only bar (no period/provider).

Implemented by Codex gpt-5.5 (high); committed by Fable (git blocked in Codex sandbox).
2026-07-10 19:17:14 -07:00
iamtoruk
73fb86dec6 fix(app): Plans — inclusive local cycle end (periodEnd-1d), correct day count, honest near copy
Review fix: periodEnd is exclusive (next reset), so the cycle end now renders periodEnd-1 day
with totalDays=diff (was Jul 15/31, now Jul 14/30); dates format in local time (not UTC);
test mock re-derived from the real emitter. Minor: en/em dashes, CLI provider order, non-
contradictory near-status copy, +near-status and plan-singular tests.

Implemented by Codex gpt-5.5 (high); committed by Fable (git blocked in Codex sandbox).
2026-07-10 19:12:42 -07:00
iamtoruk
e1bb78399c feat(app): Plans section — per-plan budget tracks, overage, pace text from getPlans
One track per plan from getPlans() (StatusJson/JsonPlanSummary): fill = percentUsed, red
`.over` past 100% with overage shown, amber `.pace.hot` when over/near pace vs mint `.ok`.
Cycle caption from the plan period; pay-as-you-go rows use `.mut`. Add plan… is M2 (visual).
Honest empty state when no plan is configured.

Implemented by Codex gpt-5.5 (high); committed by Fable (git blocked in Codex sandbox).
2026-07-10 19:01:23 -07:00
iamtoruk
fe54d9f352 fix(app): Models — unpriced = no cost AND no savings (stop dimming Codex + local rows)
Critical review fix: the unpriced predicate misclassified every Codex row (all have credits)
and every local saved-only model, hiding real cost/savings. Now unpriced = costUSD===0 &&
savingsUSD===0. Fixtures made realistic (codex priced, local saved-only priced, genuine proxy
dimmed); proxy token cols show "—"; sub-1M tokens use the wireframe's "0.4M" style.

Implemented by Codex gpt-5.5 (high); committed by Fable (git blocked in Codex sandbox).
2026-07-10 18:56:48 -07:00
iamtoruk
18b4b728ff feat(app): Models section — per-model pricing table with series dots, by-model/by-task, unpriced-row alias
Table from getModels(): calls/input/output/cache-read/cost/saved with a model-family series
dot (reuses the ListRow helper). Unpriced/proxy rows show the dim "add alias" affordance +
dashes. By-model / By-task SegTabs re-fetch (byTask). Compare… is a visual affordance (M2).

Implemented by Codex gpt-5.5 (high); committed by Fable (git blocked in Codex sandbox).
2026-07-10 18:47:07 -07:00
iamtoruk
87f5a9bac1 fix(app): Optimize — honest em-dash on yield failure, +Abandoned/Fixes tab tests, cost semantics
Reverts/Abandoned totals + bodies show "—" while yield is loading/errored instead of a fake
$0.00; adds positive-path Abandoned and Fixes-tab tests (guards category filtering); reverted/
abandoned costs use plain .val (mint reserved for savings); simplified FixesRows copy.

Implemented by Codex gpt-5.5 (high); committed by Fable (git blocked in Codex sandbox).
2026-07-10 18:42:52 -07:00
iamtoruk
39d2f79ef3 feat(app): Optimize section — Waste/Reverts/Abandoned/Fixes tabs with dollar totals
Segment tabs carry their totals (Waste=optimize.savingsUSD, Reverts/Abandoned from
getYield summary, Fixes=findingCount). Waste findings from optimize.topFindings; reverts
and abandoned lists from yield.details by category. Evidence lines + copy-fix chips are
honestly omitted (not present in MenubarPayload.optimize) — a richer `optimize --format
json` emitter is flagged as a follow-up.

Implemented by Codex gpt-5.5 (high); committed by Fable (git blocked in Codex sandbox).
2026-07-10 18:33:54 -07:00
iamtoruk
5cd5c783a2 test(app): Spend coverage (lenses, states, colors, Sankey, period windows) + proportional/labeled Sankey
Addresses T3 review: full test coverage for all lenses + empty/error states, segment
color mapping, Sankey ribbon properties, and lib/period.ts across all windows; Sankey
ribbon widths now truly proportional (removed the 28px cap) and labels are pretty/basename
+ truncated so real ids don't clip; legend reflects present models; honest "top N" project count.

Implemented by Codex gpt-5.5 (high); committed by Fable (git blocked in Codex sandbox).
2026-07-10 18:30:17 -07:00
iamtoruk
d7f3ccd1f0 feat(app): Spend section — daily-by-model stacked chart, by-project, model→project Sankey
Period-sliced StackedBars (history.daily[].topModels within the selected window via
a new shared lib/period.ts), the By-project list, and a Sankey rendered dynamically
from getSpendFlow (per-model hue ribbons). Lens tabs; series palette shared with the
legend. Adds a neutral .s-other class for the rollup segment.

Implemented by Codex gpt-5.5 (high); committed by Fable (git blocked in Codex sandbox).
2026-07-10 16:43:27 -07:00
iamtoruk
343156618f test(app): assert Overview period-window slicing, waste-rate, and model joins
Payload now spans a 30-day backfill so slicing is provable. Adds: chart slices
to the week window (7 bars, 23 excluded); which bar is peak/runner-up (idx
10/20); corrected Waste/wk ($5.51 @30d, $23.60 @week); deterministic MTD/
Projected/rest-of-month and "-3% vs June pace" (May days prepended to prove the
prev-calendar-month comparator); matched model-join dot+sub-line and a
same-project/day/calls collision resolving by cost ($10 opus / $2 haiku).
2026-07-10 16:32:54 -07:00
iamtoruk
6bec11b57f fix(app): scope Overview chart + waste-rate to selected period, harden joins
history.daily is unbounded CLI backfill (up to 365d, zero-days absent), not
period-scoped. Slice it to the selected period's date window before the chart
(new periodWindowStart/sliceDailyToPeriod), and normalize Waste/wk by the
selected period length (periodLengthDays), not the backfill length.

Also: pace comparator = previous calendar month only (label/math now agree);
session sub-line unit turns->calls; model-join key gains cost to avoid
same-project/day/calls collisions (sessionModelKey); Panel rightLink "See all ›"
on the sessions panel; hide fabricated $0-window gridline labels; correct the
projection comment to the active-days approximation.
2026-07-10 16:32:48 -07:00
iamtoruk
055e0d07e4 feat(app): Overview section wired to getOverview
Real Overview driven by usePolled(getOverview): 4 stat cards (Today, Month
to date +% vs pace, Projected month est, Waste found /wk), the daily-spend
CapsuleChart, and the most-expensive-sessions list. Every rendered number is
derived from the single MenubarPayload (formulas documented in-code, mirroring
plan-usage projectMonthEnd); topSessions' missing model is recovered from
topProjects sessionDetails. App renders <Overview/> for the overview section,
replacing the T0 smoke view; first-run/error/loading states retained. TDD
spec added (test written first, red→green).
2026-07-10 16:10:51 -07:00