Conversation
dcece23 to
36d36eb
Compare
Assisted-by: Claude Code
Assisted-by: Claude Code
Add mount/unmount tests for all v5 UI pages that were missing coverage: dashboard, machine-list, machine-detail, run-detail, order-detail, and graph (mount tests added alongside existing pure function tests). Tests follow the established pattern: mock API functions, call page.mount(container, params), assert on rendered DOM and API call arguments. Each test file includes afterEach cleanup to prevent module-level controller state leakage between tests. Coverage: 93 new page-level tests across 6 files (511 total frontend tests, all passing). Assisted-by: Claude Code
Switch the Compare page bar chart from linear percentage to log₂(ratio) y-axis. This makes equal multiplicative changes visually symmetric (e.g. 2× faster and 2× slower produce equal-height bars). Tick labels show percentage change at "nice" values (±1%, ±5%, ±50%, etc.), auto-adapting to the visible range. On zoom, ticks recompute dynamically via Plotly.relayout() with a guard flag to prevent infinite loops. Noise bands are converted to log₂ space. Assisted-by: Claude Code
The link was buried inside the test suite dropdown menu. Move it to a standalone top-level link in the nav bar's right section for visibility. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
SPA navigation links unconditionally called e.preventDefault(), blocking
Cmd+Click / Ctrl+Click from opening pages in new tabs. Add an
isModifiedClick() helper that lets modified clicks fall through to the
browser. Set real href values on all nav links (not href="#") so the
browser knows where to navigate.
Also fix the LNT brand link on the admin page: it called navigate('/')
but only the /admin route was registered, causing a 404. In admin
context, the brand now uses full-page navigation to the selected suite's
dashboard.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Graph and Compare are now "analysis tools" at /v5/graph and /v5/compare
(suite-agnostic), while browsing pages stay suite-scoped at /v5/{ts}/...
This enables cross-suite comparisons (e.g. libc++ vs libstdc++) where
each has its own test suite with incompatible order spaces.
Key changes:
- Flask: consolidated v5_global() serves /v5/admin, /v5/graph, /v5/compare
- Router: initRouter() takes context {testsuite, testsuites}, exports
getTestsuites(); fixes testsuite derivation for agnostic context
- Nav bar: three link categories (suite-scoped SPA, analysis full-page
with ?suite= prefill, admin)
- Graph page: suite <select> dropdown, currentSuite replaces closure ts,
suiteGeneration counter guards async callbacks, full state reset on
suite change
- Compare page: per-side suite selector, initSelection() replaces
setCachedData(), per-side order/field fetching via fetchSideData(),
per-side sample fetching (side A runs use side A's suite)
- Combobox: ComboboxContext uses getSuiteName(side)/getOrderData(side)
- Types: SideSelection.suite field, state encodes suite_a/suite_b
- Design and implementation plan docs updated
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Pinned orders were same-suite reference lines. Baselines are cross-suite
(suite, machine, order) tuples that allow comparing against any test suite.
Key changes:
- PinnedOrder → PinnedBaseline in time-series-chart.ts (label instead of
orderValue, updated hover template)
- Graph page: baseline selector panel with cascading Suite → Machine →
Order dropdowns, "+ Add baseline" expand/collapse UX
- Baseline data fetched independently from each baseline's suite via
queryDataPoints(), cached per suite::machine::order::metric
- buildRefsFromCache → buildBaselinesFromData (reads from baseline cache
instead of main trace data)
- URL encoding: baseline={suite}::{machine}::{order} (repeated param)
- Removed scaffold-based pinned order suggestions (rebuildSuggestions,
cachedOrders, cachedSuggestions) — baseline order search uses per-suite
API-based search
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
… comments - Promote blMachineCleanup/blOrderCleanup to module scope and clean up in unmount() to prevent listener leaks when navigating away with the baseline form open - Call fetchAllBaselineData() in doPlot() so baselines are re-fetched when the metric changes (previously silently disappeared) - Add comment documenting :: separator limitation in baseline URL encoding - Update stale "pinned order" references in comments, test descriptions, and CSS - Remove dead getOrders mock from graph tests Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Place the suite selector in the same flex row as the metric, filter, and aggregation controls instead of its own full-width block. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Baseline form fields (Suite, Machine, Order) now display horizontally instead of stacking vertically, preventing misalignment with Machines - Auto-add baseline when order is selected (no separate Add button needed) - Removed blSelectedTag (unused) and blAddBtn (no longer needed) - Normalize agg-select padding/font-size to match other controls, fixing vertical label alignment in the controls row - Add CSS for baseline form horizontal layout Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Use flex-start alignment on the second controls row so Machines and Baselines labels stay top-aligned regardless of input height differences. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…age regressions Extract createOrderPicker from createOrderCombobox so Graph baseline and Compare page share the same order combobox UX with machine-order filtering and tag display. Use lazy getOrderData getter so async-fetched order data is available when the dropdown opens (fixes empty suggestions regression). Also fix Compare page "Select a test suite first" hint: render Machine, Order, Runs, and Run aggregation sections unconditionally and move the hint into the Runs panel where it belongs. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The query endpoint only supported after_order/before_order range filters with strict inequality (> and <), making it impossible to query data at a single order. Add an order parameter for exact matching (=), mutually exclusive with the range filters (returns 400 if combined). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Baselines were never rendering because fetchAllBaselineData used afterOrder=X & beforeOrder=X (strict exclusive range = empty result). Switch to the new order param for exact-match queries. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add red halo (.combobox-invalid) to machine and order comboboxes when no suggestions match; block acceptance via Enter/blur while invalid. - Enforce suite → machine → order dependency chain on Compare page by disabling each input until its predecessor is selected. - Require exact-match for order picker Enter/blur acceptance — partial substring matches are rejected. - Machine comboboxes fetch the full machine list once on creation and filter locally by case-insensitive substring (no per-keystroke API calls). Input is disabled with "Select a suite first" when no suite is selected. - Fix arrow-key navigation: blur handlers check FocusEvent.relatedTarget to keep dropdown open during keyboard navigation. Add :focus style to dropdown items. - Remove 20-item cap on machine suggestions (machines are always < 100). - On Graph baseline form, onClear callback destroys the order picker when the machine is cleared. Clearing an order clears downstream runs. - Run UUIDs in Compare runs panel are now links to Run Detail page. - Metric area shows "Select a suite to load metrics..." before any suite is loaded. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…to /tests Change the /query endpoint from GET to POST with a JSON body to eliminate URL length limits when querying many tests with long names. The test field accepts a list for disjunction queries. Unknown test names are silently skipped. The schema uses marshmallow's unknown=RAISE to reject unknown fields (returning 422 instead of the previous 400). Add optional machine= and metric= query parameters to GET /tests so clients can discover which tests have actual data for a given machine and/or metric combination, joining through Sample -> Run with DISTINCT. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…uery Restructure the Graph page data loading to fetch only the tests being displayed instead of all data for a machine+metric: - Discover matching test names server-side via GET /tests with machine, metric, and name_contains filters - Fetch data only for discovered tests via POST /query with multi-value test in the JSON body (eliminates URL length limits) - Cache data per (machine, metric, test) with LRU eviction at 500 entries -- filter changes only fetch uncached tests (the delta) - Enforce a hard cap of 50 displayed tests (replaces soft cap of 20) - Case-sensitive test filtering (matches server-side SQL LIKE behavior) - Baseline data fetching scoped to discovered tests only Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
… Suites Replace the three-category navbar (suite-scoped, analysis, admin) and suite selector dropdown with a simpler flat layout where all links are suite-agnostic: [LNT] [Test Suites] [Graph] [Compare] [API] <--> [v4 UI] [Admin] [Settings] - Remove suite selector dropdown from navbar entirely - Remove suite-scoped links (Dashboard, Regressions, Machines) from navbar - Add "Test Suites" link (suite-agnostic placeholder page at /v5/test-suites) - Add "API" link (opens Swagger UI in new tab) - Add suite-agnostic Dashboard placeholder at /v5/ - Move Admin and v4 UI to right side - v4 UI link now points to v4 root page instead of suite-specific URL - Extract buildNavLink() helper to unify link construction - Pass abort signal to getApiKeys() refresh calls in admin page Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Serve a plain-text orientation document at GET /llms.txt following the llms.txt convention (analogous to robots.txt). Helps AI agents quickly understand LNT's domain concepts, API structure, and common workflows. Content includes: what LNT is, key concepts (test suite, machine, order, run, test, sample, regression, field change), endpoint listing, pagination format, links to Swagger UI and OpenAPI spec, and common workflows. - Registered as a plain Flask blueprint (not flask-smorest) to stay out of the OpenAPI spec - Static content with Cache-Control (24h) and ETag headers - Points to OpenAPI spec for full write endpoint documentation Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Extract all graph page caching into a GraphDataCache class that manages test data (LRU), baseline data, test names, and scaffolds behind a clean async/sync API. This fixes three bugs: - Baselines now appear immediately when added (not only after filter change) - Changing aggregation now re-plots traces immediately - Text filter changes use cached test names instead of re-querying the API Also: remove batched chart rendering (caused flicker on legend toggle), remove dead setsEqual, deduplicate test-name discovery logic, parallelize baseline fetches, fix doPlot/filter race condition. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…y and filter
- Make getFields() delegate to getTestSuiteInfoCached(), eliminating
duplicate HTTP requests to /api/v5/test-suites/{ts} across 5 pages.
- Show "X tests across Y machines across Z metrics" in the indicators
heading, with proper singular/plural and null-entity handling.
- Add a debounced text filter above the indicators table matching on
machine, test, or metric (OR logic, case-insensitive). Heading shows
filtered-vs-total context. Batch remove operates on visible rows only.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Tests endpoint: replace open question with concrete TODO to switch
from ?name_contains/?name_prefix to unified ?search= with prefix
matching, reusing the DB layer's list_tests().
- Tests detail: replace question with TODO to remove GET /tests/{name}
(unused by frontend, response contains only the name).
- Commit deletion: remove TODO — current behavior is correct and
well-tested (cascades to runs/samples, blocked by regressions,
11 tests across 3 layers).
- Fix manage scope description to include commit deletion.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The detail endpoint returned only {"name": "..."} — information the caller
already knows. It was never used by the frontend, and the catch-all path
converter for slash-containing test names added routing complexity with no
benefit. Remove the endpoint, its tests, its llms.txt entry, and the design
doc routing caveat.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replace ?name_contains (substring) and ?name_prefix with a single ?search= parameter using prefix matching, consistent with how /machines and /commits handle search (design doc D9). Remove the unused list_tests() DB method. The old parameters now return 400, verified by dedicated tests. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Split the monolithic graph.ts (~1100 lines) and graph-data-cache.ts (~270 lines) into 8 focused modules under pages/graph/: - state.ts: URL state encode/decode (GraphState, BaselineRef types) - data-cache.ts: data cache + fetch with delta-fetch for baselines, regression caching, and clearSuite() that preserves cross-suite data - traces.ts: pure trace-building functions (buildTraces, buildChartData, buildBaselinesFromData, buildRegressionOverlays, buildColorMap) - controls.ts: control panel UI (suite, machines, metric, filter, agg) - baselines.ts: baseline panel with cascading suite/machine/commit - time-series-chart.ts: chart with hover sync and double-click-to-isolate - test-selection-table.ts: moved from components/ (graph-only consumer) - index.ts: page orchestrator wiring all modules together Key improvements over the old implementation: - Clear module boundaries with sub-modules that don't import from each other - Per-machine abort controllers (removing one machine doesn't abort others) - plotGeneration counter + selectionAbort for proper cancellation on metric change, machine add/remove, and rapid selection changes - Suite change resets regression mode dropdown - Delta-fetch for baselines (only fetches un-cached tests) - Parallel baseline fetches (Promise.all instead of sequential loop) - isComplete check across all machines (bug fix: was only checking first) - regressionMode persisted in URL for shareability - Cached colorMap and scaffoldUnion (computed once, not per-render) - O(1) Map-based raw values lookup for hover scatter (was O(n) scan) - Data building moved inside rAF (coalesced during progressive loading) - Double-click chart trace to isolate test in selection table - Always rebuild table in handleSelectionChange (fixes deselection bug) - Baseline chips resolve display values via POST /commits/resolve so they survive page reload, with cross-suite support - Baseline "+" button uses align-self: flex-start (no width stretching) - Machine combobox always rendered (disabled placeholder when no suite) - "Discovering tests..." progress indicator during test discovery phase Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…orderless commits The query endpoint's cursor pagination unconditionally appended (commit, test) as tiebreakers, which mapped to (Commit.ordinal, Test.name). This caused two problems: 1. Every query filtered out commits without ordinals (via the ordinal IS NOT NULL guard), even when the caller didn't request ordinal-based sorting. This violated D10 which states: "When not sorting by ordinal, all runs are included regardless of their commit's ordinal." 2. The (ordinal, test_name) tuple is not unique when multiple runs exist for the same commit, so cursor pagination could lose or duplicate rows at page boundaries. Fix: Replace the (commit, test) tiebreaker with Sample.id (the primary key), which is guaranteed unique and non-null. Change the default sort (when no sort param is provided) from (commit, test) to just (id), providing an arbitrary but deterministic order that excludes no data. The ordinal IS NOT NULL filter now only fires when 'commit' appears in the caller's explicit sort specification. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Remove RESOLVED_STATES from regression-utils.ts (never imported) - Remove readCachedTests() from data-cache.ts (never called from production code; discoverTests() returns the list directly) - Make PLOTLY_COLORS module-private in utils.ts (only used internally by machineColor()) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The frontend getMachines function was sending name_prefix and name_contains query parameters, but the backend machines endpoint only accepts ?search=. This caused a 400 error when using the Machines tab search on the Test Suites page. Update the function, its call site, and its tests to use the correct parameter name. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Removed (already implemented): - Machine field search: ?search= already searches name + searchable fields - Commit filtering by machine: ?machine= on /commits already in use Added from frontend API call audit: - Multi-value machine= on /tests (regression detail N+1) - Multi-value machine= on /commits (graph scaffold) - EXISTS instead of JOIN+DISTINCT on /tests - Broaden page size TODO to cover all fetchAllCursorPages callers - Expand profiles N+1 TODO to include missing ?machine= usage - Expand regression search TODO to cover both list and compare pages, use ?search= for consistency Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Align cursor-paginated endpoints with the query endpoint's existing 10,000 max. This reduces round-trips for bulk consumers: a typical NTS run with ~7,500 samples now needs 1 request instead of 15. Changes across all layers: - Backend: cursor_paginate() and machines offset pagination caps - Frontend: fetchAllCursorPages and data-cache regression loop - Schema docs, design docs (R4), llms.txt - New test proving limits above the old 500 cap work Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…orchestrator The Graph page rewrite left three modules with insufficient test coverage: controls.ts (zero tests), baselines.ts (zero tests), and index.ts (13 tests covering only structural concerns). This adds 55 new tests across those three modules, bringing total Graph page test coverage from 144 to 199 tests. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…hold bug Add a Computation Reference subsection to the Compare page design doc with precise mathematical definitions for all derived quantities (Delta, Delta %, Ratio, Status, Geomean, chart Y-axis, noise band). This makes the formulas unambiguous for anyone relying on comparison results. Fix a bug in the Delta % noise knob: change from <= to strict < so that setting the threshold to 0 no longer misclassifies identical values as "noise" instead of "unchanged". Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…al badge
Client-side:
- Add shared matchesFilter()/isFilterValid()/updateFilterValidation()
utilities in utils.ts with re: regex support and compiled regex caching
- Replace all 18 inline .includes()/.startsWith() filter sites with
matchesFilter() calls
- Add .filter-invalid CSS class for invalid regex red halo
- Add .filter-regex-badge for visual "regex" badge at input right edge
- Add .filter-input-wrapper for lazy positioning context on plain inputs
- updateFilterValidation() called at all 13 filter input sites
Server-side:
- Switch all ?search= endpoints (tests, machines, commits) from
prefix match (.like('term%')) to case-insensitive substring match
(.ilike('%term%'))
- Fix case-sensitivity bug: API endpoints used .like() (case-sensitive)
while DB layer used .ilike() (case-insensitive). Now both use .ilike().
- Update DB layer list_commits/list_machines to substring matching
- Update marshmallow schema metadata descriptions
Design docs updated: D9, D4, R5, endpoints.md, browsing.md,
architecture.md (text filtering convention), implementation guide.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…percentages, tooltips The summary bar percentages now use only comparable tests (improved, regressed, noise, unchanged) as the denominator instead of all tests. Non-comparable categories (Only in A, Only in B, N/A) show bare counts with no percentage. Percentages display one decimal place with trailing .0 stripped for whole numbers. A tooltip on each percentage explains the denominator. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Filter typing with 8k tests caused ~300-400ms freezes. Three fixes: 1. Filter-pass deduplication: pre-compute the filtered test set once and share it across the table, chart, summary bar, and regression panel (syncChartAndSummary helper). Previously matchesFilter ran 5 independent passes over all rows per debounce tick. 2. RAF-batch chart: defer Plotly.react to requestAnimationFrame so the table updates instantly without waiting for the chart render. 3. Display:none fast path: on filter-only changes, toggle visibility on existing rows instead of destroying and recreating all DOM nodes. Full rebuilds only happen on data or sort changes. The table module builds all rows regardless of the current filter so the fast path can widen as well as narrow. Compare: new applyTableFilters() export returns the matching set. Graph: new setFilter() handle method on the test-selection table. Design docs updated with behavioral requirements; implementation guide updated with the display:none and RAF-batch patterns. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Pin a comparison as a shadow, then change side B to overlay both
on the chart. The shadow renders as a thin blue line independently
sorted by its own ratio, enabling visual comparison of how a metric
profile evolved across two versions of side B against a shared
baseline.
- Pin button in Side B panel header, shadow chip above chart
- State persisted to URL via encodeSide/decodeSide('shadow_b')
- Auto-unpin on side A change or swap
- Shadow recompute reuses cached side A aggregation
- Shadow fetch errors isolated from main comparison
- Hide-noise, text filter, and manual toggles apply to shadow
- 24 new tests (state URL round-trip, auto-unpin, chart data prep)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
After creating a regression or adding indicators to an existing one from the Compare page, feedback now shows a clickable link to the regression detail page (using the title if available, otherwise the short UUID). Also clears the title input after successful creation. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Extract the custom one-off regression search widget in the Compare page's "Add to Existing" tab into a standalone regression-combobox component that follows the established machine-combobox pattern: fetch-once with local filtering, ARIA roles, keyboard navigation, collapse on select, blur and outside-click dismiss, and proper lifecycle cleanup. Also adds TODOs for pre-existing issues found during review: shadow toolbar broken for unauthenticated users, machine-combobox swallowing fetch errors, and setupComboboxKeyboard not being shared across combobox implementations. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The Profiles page commit picker had three performance issues: an N+1 pattern in loadMachineCommits (1 + N requests to check which commits have profiles), an N+1 in loadRuns (checking each run for profiles), and an unnecessary bulk fetch of all suite commits. Replace all three with server-side has_profiles= boolean filters on GET /commits and GET /runs, using EXISTS subqueries against the Profile table. The frontend now makes one API call per cascade step instead of 1+N. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Allow clients to include a `uuid` field in POST /runs. When provided, the server uses it (normalized to lowercase) instead of generating one. Duplicate UUIDs are rejected with 409 Conflict via a savepoint-based IntegrityError handler. When omitted, behavior is unchanged (server generates UUID v4). This enables stable UUIDs across re-submissions, mirroring between LNT instances, and pre-craftable URLs. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Small clipboard icon next to the summary bar copies the visible comparison table data as CSV to the clipboard. Respects all active filters (noise hiding, manual click-hiding, text filter, chart zoom) and current sort order. Includes geomean summary row. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Extract shared combobox boilerplate (ARIA, keyboard nav, blur/outside-click dismiss, validation halo) into a generic base component. Machine, commit, and regression comboboxes become thin wrappers that provide data fetching and selection semantics. - New: components/combobox.ts (generic base) - New: components/commit-combobox.ts (extracted from old combobox.ts) - Refactored: machine-combobox.ts (214 -> 95 lines) - Refactored: regression-combobox.ts (226 -> 100 lines) - Deleted: src/combobox.ts (464 lines, fully replaced) - Moved Compare-page wiring into selection.ts, eliminated ComboboxContext - Fixed ARIA inconsistency (role=option now on all dropdown items) - Fixed listener leak on re-render (combobox handles now destroyed) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The Profiles page commit picker was showing raw commit strings while the Compare page showed display values with tags. Both use createCommitPicker which supports displayMap, but the Profiles page never built one. Store full CommitSummary[] instead of Set<string> from getCommits, fetch commit_fields via getTestSuiteInfoCached on suite change, and build a displayMap in the getCommitData callback using commitDisplayValue. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The "Missing tests (N)" section header in the Compare page table did
not update when a text filter or chart zoom was active. Individual
missing rows were hidden via display:none, but the <h4> header always
showed the total count. Now the header updates to "Missing tests (M
of N matching)" when filtering is active, and missing rows also
respect chart zoom (previously only text filter applied to them).
Also adds a TODO for a GET /runs/{uuid}?samples=true endpoint to
enable round-tripping run data.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The Copy as CSV button on the Compare page would vanish when the user zoomed into the chart. Two issues: 1. applyTableFilters() in table.ts set summaryMessageEl.textContent, which destroys all child nodes -- including the copyBtn that compare.ts appends to the .table-message div. Fix: wrap the summary text in a dedicated <span> so textContent updates only touch the span, leaving siblings intact. 2. The CHART_ZOOM handler in compare.ts didn't update copyBtn visibility, so even if the button survived, it wouldn't hide when zooming filtered to zero visible rows. Fix: add the visibility update after renderSummaryBar(). Also removed the now-dead summaryMessageEl module variable from table.ts (only used locally in redraw()). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Value A and Value B cells now show a native browser tooltip indicating how many raw samples and contributing runs produced the aggregated value (e.g. "6 samples across 2 runs"). Delta, Delta %, and Ratio cells show both sides (e.g. "A: 6 samples across 2 runs, B: 4 samples across 1 run"). Counts reflect only runs that have data for the specific test, with singular/plural applied. Geomean and missing- test rows are excluded. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
THIS IS A DRAFT. IT WILL BE THE TARGET OF A RFC BEFORE ANYTHING HAPPENS.