Skip to content

explorer: facet counts use padded viewport, matching the table (#234)#245

Open
rdhyee wants to merge 1 commit into
isamplesorg:mainfrom
rdhyee:fix/facet-count-padding
Open

explorer: facet counts use padded viewport, matching the table (#234)#245
rdhyee wants to merge 1 commit into
isamplesorg:mainfrom
rdhyee:fix/facet-count-padding

Conversation

@rdhyee
Copy link
Copy Markdown
Contributor

@rdhyee rdhyee commented May 29, 2026

What

Facet-legend counts were computed over the exact viewport (pad 0) in updateCrossFilteredCounts, while every other "in view" surface — the samples-table COUNT (loadCount), the point-mode sample loader, the "samples in view" stat, and the heatmap — pads the viewport by VIEWPORT_PAD_FACTOR (0.3). A sample sitting in that 30% margin was counted by the table but not the facet legend, so the legend read one (or more) low.

Reproduction: /explorer.html?material=…/mineral#v=1&lat=35.0900&lng=32.8900&alt=50000&mode=point → the table says "14 samples match the current filters" but the mineral facet shows 13.

Verified against live data (DuckDB queries at that exact view): the facet query returns 13 at pad 0 and 14 at pad 0.3 (== the table). Exactly one mineral sample lives in the pad margin.

Fix

One line in updateCrossFilteredCounts — align the facet-count bbox to the shared contract:

- const bboxSQL = isGlobal ? null : viewerBboxSQL('l.latitude', 'l.longitude', 0);
+ const bboxSQL = isGlobal ? null : viewerBboxSQL('l.latitude', 'l.longitude', VIEWPORT_PAD_FACTOR);

The heatmap hit the identical mismatch earlier and was moved to the padded contract in the #241 follow-up; this aligns the last stray surface.

The durable fix — one shared "in view" bbox source so these surfaces can't drift apart again — is noted as architectural follow-up on #234.

Tests (tests/playwright/facet-viewport.spec.js)

  • New coherence regression: active-material legend count == table "N match" count at the repro view (backreference assertion — 14/14 passes, 13/14 fails).
  • Hardened flyToAndSettle: the padded (slower) facet query reliably exposed a pre-existing race — the helper waited only for .recomputing to clear, which can be a transient before the new counts apply. It now keys on the full recompute cycle (.recomputing appear → clear) plus a two-consecutive-equal-reads stability gate, so it's correct even for moves that leave counts unchanged. This also confirms there is no real product stale-overwrite race — the restore settles correctly on global.
  • Full B1 suite green 2× each (10/10).

Provenance

Claude; empirically verified (DuckDB 13/14 + Playwright); Codex 2-round review (resolved an unchanged-counts hang in the test helper). Deployed to the rdhyee fork staging and verified live (mineral legend now reads 14, matching the table).

🤖 Generated with Claude Code

…lesorg#234)

Facet-legend counts were computed over the EXACT viewport (pad 0) in
updateCrossFilteredCounts, while every other "in view" surface — the
samples-table COUNT (loadCount), the point-mode sample loader, the
"samples in view" stat, and the heatmap — pads by VIEWPORT_PAD_FACTOR
(0.3). A matching sample sitting in the 30% pad margin was counted by the
table but not the legend, so the legend read one (or more) low. RY hit it
2026-05-28: material=mineral at a Cyprus deep-zoom showed 13 on the
legend but "14 samples match the current filters" in the table.

Verified against the live data: the facet query returns 13 at pad 0 and
14 at pad 0.3 (== the table). Fix: align the facet-count bbox to
VIEWPORT_PAD_FACTOR. The heatmap hit the identical mismatch earlier and
was moved to the padded contract in the isamplesorg#241 follow-up; this aligns the
last stray surface. (The durable fix — one shared "in view" bbox source so
these can't drift again — is tracked on isamplesorg#234.)

Tests (tests/playwright/facet-viewport.spec.js):
- New coherence regression: active-material legend count == table
  "N match" count at the exact repro view (backreference assertion).
- Hardened flyToAndSettle: the padded (slower) facet query reliably
  exposed a pre-existing race — the helper waited only for `.recomputing`
  to clear, which can be a transient before the new counts apply. It now
  keys on the full recompute cycle (`.recomputing` appear → clear) plus a
  two-consecutive-equal-reads stability gate, so it's correct even for
  moves that leave counts unchanged. Confirms there is no real product
  stale-overwrite race (the restore settles on global).
- Full B1 suite green 2x each (10/10).

Provenance: Claude; empirically verified (DuckDB 13/14 + Playwright);
Codex 2-round review (resolved the unchanged-counts hang in the helper).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant