Skip to content

Explorer: three-state facet index status fixes permanent dash on slow connections (#313 P0)#316

Open
rdhyee wants to merge 1 commit into
isamplesorg:mainfrom
rdhyee:fix/313-facet-status-p0
Open

Explorer: three-state facet index status fixes permanent dash on slow connections (#313 P0)#316
rdhyee wants to merge 1 commit into
isamplesorg:mainfrom
rdhyee:fix/313-facet-status-p0

Conversation

@rdhyee

@rdhyee rdhyee commented Jun 30, 2026

Copy link
Copy Markdown
Contributor

Summary

On slow connections, the Explorer's facet-count UI showed a permanent "—" dash (meant to mean "can't compute a trustworthy count") even when the facet index was still downloading — not actually broken, just not done yet. Root cause: a single boolean, window.__facetIndexReady, was used to mean BOTH "still loading" and "failed to load," so during the ~20-80s cold-boot window before sample_facet_index finishes downloading, the UI couldn't distinguish "wait, it's coming" from "this broke, don't expect a count." This was diagnosed and posted as a comment on #313.

This PR fixes that by replacing the boolean with a real three-state machine, window.__facetIndexStatus:

  • 'pending' (initial state) — the index is still loading → the UI now shows "Loading…", not the dash.
  • 'ready' — loaded and validated → real cross-filtered counts render, exactly as before.
  • 'failed' — a preflight check failed (schema version, generation mismatch, coverage mismatch) or the query threw → the UI shows the "—" dash + the existing "Count unavailable for this filter combination" tooltip, permanent for the session until refresh — matching today's behavior for the genuine-failure case.

The pending-vs-failed decision is extracted into a pure function, facetCountsDisplayState(status, res) in assets/js/explorer-utils.js, following the same closure-free "pure logic extracted to ES modules" pattern already used in this file (issue #249, PR3) — dynamically imported into explorer.qmd's OJS runtime and unit-tested directly under Node.

window.__facetIndexReady is removed, not kept as a backward-compat alias: there were only two read/write sites and both were in explorer.qmd (the boot/load cell that set it, and applyMaskIndexCounts() that read it), both updated in this commit. A repo-wide grep confirmed no other file referenced it, so an alias wasn't needed for safety.

This is P0 of the #313 joint Claude+Codex mitigation plan (P0+P1+P3+P6 revised). P1 (lighter boot manifest), P3 (decoupling the facet-index preflight from the masks scan), and P6 (Firefox CI) are separate follow-up PRs, NOT included here.

Relates to #313 (not closing it — the other mitigations are still pending).

Test plan

  • Added tests/unit/explorer-utils.test.mjs coverage for facetCountsDisplayState(): pending→'pending' (Loading…), failed→'unavailable' (dash+tooltip), and the query-failed ('unavailable' from applyMaskIndexCounts) case for every status.
  • npm run test:unit — all 17 tests pass (8 pre-existing + 4 new, no regressions).
  • quarto render explorer.qmd --to html succeeds, confirming the edited {ojs} boot-sequence cell is syntactically valid and the new code is present in the compiled output.
  • Tradeoff / what's NOT covered: I did not add a Playwright spec. Simulating the pending window end-to-end would mean booting the full DuckDB-WASM app and delaying the sample_facet_index parquet fetch via page.route() (a pattern that exists in tests/playwright/facet-tree.spec.js, but only against a local data mirror gated behind FACET_TREE_LOCAL=1, with ~90s timeouts). The existing markFacetCountsUnavailable() dash path it.self has zero Playwright coverage today, so the unit test on the extracted pure decision function keeps this PR's coverage depth consistent with the rest of the facet-count UI rather than introducing new test infra as a side effect of a UI bugfix. Manual verification (DevTools network throttling, per Need to explore what browser/operating system/bandwidth combinations the Explore works and does not work in #313's repro steps) is still the recommended manual check before merge.

🤖 Generated with Claude Code

…n slow connections (isamplesorg#313 P0)

window.__facetIndexReady was a single boolean meaning BOTH "still loading"
and "failed to load", so on a slow connection the facet-count UI showed the
same "—" dash for the entire ~20-80s cold-boot window as it would for a
genuine, permanent load failure — indistinguishable to the user.

Replace it with window.__facetIndexStatus ('pending' | 'ready' | 'failed'):
- 'pending' (initial state): show "Loading…", not the dash.
- 'ready': real cross-filtered counts render, same as before.
- 'failed' (preflight check failed, or the query threw): show the "—" dash
  + existing tooltip, permanent for the session until refresh — matching
  today's failure-case behavior exactly.

The pending-vs-failed UI decision is extracted to a pure function,
facetCountsDisplayState() in assets/js/explorer-utils.js, alongside the
existing extracted-pure-logic modules (issue isamplesorg#249 pattern) and covered by
unit tests in tests/unit/explorer-utils.test.mjs.

window.__facetIndexReady is removed (not aliased) — the only two read/write
sites were both in explorer.qmd and are updated in this commit; no other
file in the repo referenced it.

This is P0 of the isamplesorg#313 joint Claude+Codex mitigation plan. P1 (lighter boot
manifest), P3 (decouple from masks scan), and P6 (Firefox CI) are separate
follow-up work.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XEtSoXjsKtnYWQ7yS8mGRo
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