Repository navigation
feat(cost): filter rail, provider marks and drill-down on the Cost page - #2548
Confidence 6/10 · 1 issue to address
🟡 Confidence 6/10 · needs attention. Held at 6 because a correctness warning is open.
1 warning −1 · 3 notes · tests partial −1 · risk medium
Moves the /cost filters into the shared rail, adds provider marks in the table, legend, chips and rail, and makes a row click regroup instead of keeping the grouping. The rail ships a dead Only action, and a few labels and kit reads need tightening.
FilterSectiongainsformatCount;BarChartgainsseriesMarks; chips gainmarkFetchCostFacetsreads one breakdown per dimension under the other dimensions' filters- Row clicks regroup via
drilledInto/drillTarget;usage_typeleaves the URL and grouping marks.tsnames AWS/OpenRouter accounts and picks a mark per dimension
Findings
🟠 Warning · F1 · onOnly without onExclude renders no Only button, so the rail has none
correctness · apps/web/src/page/cost/view-filters.ts:69
filter-section.ts:270 draws the Only/Exclude hover overlay only when onExclude is set, and this section passes onOnly alone. No rail row ever shows Only: Message.ClickedOnlyFacetValue is never sent and onlyFilter is dead. Every other rail (services/list/view-filters.ts:39) passes both.
Pass an `onExclude` too, or in `filter-section.ts:270` render the overlay when either action exists: `...(config.onExclude === undefined && config.onOnly === undefined ? [] : [...])`.
🔵 Note · F2 · keyDetail repeats the id accountLabel already appended
correctness · apps/web/src/page/cost/marks.ts:146-148
With two OpenRouter sources accountLabel returns OpenRouter org_second (marks.ts:95), and keyDetail returns the id unconditionally, so the table row and the rail's title read OpenRouter org_second · org_second.
Return `key` only while the label is the bare name: `accountLabel(key, sources) === COST_PROVIDERS.openrouter.name ? key : null`.
🔵 Note · F3 · One facet key re-reads all five breakdowns on every filter change
performance · apps/web/src/page/cost/update.ts:124-128
requestKey covers the whole facets input, so a checkbox click re-runs all five FetchCostFacets reads (command.ts:104). facetFilters leaves the toggled dimension out of its own read, so only four of them changed and the fifth is re-read unchanged on every click.
Key and store each dimension's facet on its own (`costFacet.${dimension}` plus a `Keyed` slot), so the untouched one is reused.
🔵 Note · F4 · seriesMarks indexed without Rec.has, so a constructor series crashes the legend
correctness · packages/views/src/charts/bar-chart.ts:88
A series column named constructor reads back Object.prototype.constructor, so mark is not undefined, mark.icon is undefined, and the legend's icon(h, undefined) throws instead of drawing a plain entry. marks.ts:57 and ai-vendor.ts:68 guard exactly this read with Rec.has.
`mark: Rec.has(inputs.seriesMarks, definition.rawKey) ? inputs.seriesMarks[definition.rawKey] : undefined`
What was checked
- Every
IconNameinCATEGORY_ICONSand the account/region glyphs resolves inicons.generated.ts rawKeyis the row's column name, so legend marks keyed by label resolve (timeseries.ts:43)sourcesOfis exported atmodel.ts:69and everykeyLabel/keyMarkcaller passes it
0b4b4eb · Reply "won't fix" to dismiss a finding, or mention @maple-review-bot to ask about one.
Annotations
Check warning on line 69 in apps/web/src/page/cost/view-filters.ts
maple-review-bot / Maple / review
correctness: `onOnly` without `onExclude` renders no Only button, so the rail has none
`filter-section.ts:270` draws the Only/Exclude hover overlay only when `onExclude` is set, and this section passes `onOnly` alone. No rail row ever shows Only: `Message.ClickedOnlyFacetValue` is never sent and `onlyFilter` is dead. Every other rail (`services/list/view-filters.ts:39`) passes both.
Check notice on line 148 in apps/web/src/page/cost/marks.ts
maple-review-bot / Maple / review
correctness: `keyDetail` repeats the id `accountLabel` already appended
With two OpenRouter sources `accountLabel` returns `OpenRouter org_second` (`marks.ts:95`), and `keyDetail` returns the id unconditionally, so the table row and the rail's title read `OpenRouter org_second · org_second`.
Check notice on line 128 in apps/web/src/page/cost/update.ts
maple-review-bot / Maple / review
performance: One facet key re-reads all five breakdowns on every filter change
`requestKey` covers the whole `facets` input, so a checkbox click re-runs all five `FetchCostFacets` reads (`command.ts:104`). `facetFilters` leaves the toggled dimension out of its own read, so only four of them changed and the fifth is re-read unchanged on every click.
Check notice on line 88 in packages/views/src/charts/bar-chart.ts
maple-review-bot / Maple / review
correctness: `seriesMarks` indexed without `Rec.has`, so a `constructor` series crashes the legend
A series column named `constructor` reads back `Object.prototype.constructor`, so `mark` is not undefined, `mark.icon` is undefined, and the legend's `icon(h, undefined)` throws instead of drawing a plain entry. `marks.ts:57` and `ai-vendor.ts:68` guard exactly this read with `Rec.has`.