Skip to content

Fetch glossary on file-select, not on compiler page load #123

Description

@khahani

Problem Statement

As a scientist using the EasyEyes Compiler, I don't benefit from the glossary being downloaded the moment the compiler page loads — I only need it once I actually select an experiment file to compile. The current implementation eagerly fetches the glossary on page load, which:

  • Makes the page do network work the scientist hasn't asked for yet.
  • Renders the just-added "Glossary …" loading dialog (shown while the glossary downloads on file-select) effectively dead, because by the time I drop a file the launch fetch has usually already populated the glossary, so the dialog never appears.
  • Has spread a dependency on "the glossary is already loaded at launch" into several places that shouldn't depend on it (the whole page refuses to render until the glossary arrives; the Prolific draft defaults and the glossary viewer are fed from React state that only the launch fetch populates).

Solution

Stop fetching the glossary when the compiler page loads. Fetch it lazily when the scientist selects an experiment file (the existing file-drop / handleTable path already fetches a version-pinned glossary and already contains the "Glossary …" loading dialog — which becomes meaningful again once the launch fetch is gone).

Collapse the glossary to a single source of truth — the in-memory glossary registry singleton — and migrate the three remaining consumers that depend on the launch-populated React state onto the registry:

  • The page-render gate that blocks the entire compiler UI until the glossary loads is removed.
  • The Prolific study draft default title/description read from the registry instead of a React-state prop threaded through the component tree.
  • The (currently unreachable) glossary viewer reads from the registry via a new non-throwing getter instead of React state.

Behavior the scientist sees: the page loads without a glossary network call; on selecting a file, the "Glossary …" loading dialog appears while the version-pinned glossary downloads, then compile proceeds; Prolific drafts still fall back to glossary defaults for title/description when the experiment doesn't define them.

User Stories

  1. As a scientist, I want the compiler page to load without downloading the glossary, so that page load does only the work I've asked for.
  2. As a scientist, I want the compiler UI to render immediately on load, so that I'm not staring at a blank page waiting on a glossary download.
  3. As a scientist, I want the glossary to download when I select an experiment file, so that the glossary is fetched exactly when it's first needed.
  4. As a scientist, I want to see a "Glossary …" loading dialog while the glossary downloads on file-select, so that I understand why there's a brief pause before compile begins.
  5. As a scientist, I want the glossary used for my compile to be the version pinned for this file-select, so that I never compile against a staler launch-time snapshot.
  6. As a scientist who didn't define _online1Title in my experiment, I want the Prolific study title to fall back to the glossary default, so that my study still has a sensible title.
  7. As a scientist who didn't define _online2Description, I want the Prolific study description to fall back to the glossary default, so that my study still has a sensible description.
  8. As a scientist who DID define _online1Title/_online2Description, I want my own value to be used and never overridden by the glossary default, so that my study shows the title/description I chose.
  9. As a scientist, I want the Prolific draft defaults to come from the same version-pinned glossary that my experiment compiled against, so that the defaults are consistent with the compile.
  10. As a scientist who selects multiple files in one session, I want the glossary re-fetched only when its published version actually changed, so that I'm not made to wait on a redundant download each compile.
  11. As a developer, I want a single source of truth for the glossary (the registry) rather than parallel React state, so that the glossary can't be inconsistent between consumers.
  12. As a developer, I want the Prolific draft flow to read the glossary from the registry directly, so that the glossary no longer has to be threaded as a prop through the component tree.
  13. As a developer, I want the glossary viewer to read from a non-throwing registry getter, so that the (currently dead) viewer can't crash if it's later wired up before a glossary is loaded.
  14. As a developer, I want the obsolete test asserting a launch-time glossary fetch removed, so that the test suite reflects the new lazy-fetch contract.
  15. As a developer, I want the Prolific fallback-default tests to keep passing against the registry, so that the title/description fallback behavior stays covered.

Implementation Decisions

Single source of truth. The in-memory glossary registry singleton becomes the only glossary store in the compiler app. The separate React state holding glossary data is removed, along with everything that depended on it being populated at launch.

Stop the launch fetch. The compiler app no longer fetches or initializes the glossary on mount. The glossary is fetched and initialized only on file-select, via the existing file-drop handler, which already performs a version-probe and a version-pinned fetch and already shows the "Glossary …" loading dialog.

Render gate removed. The compiler UI no longer blocks rendering on the glossary being present. This is verified safe: nothing in the initial render path calls the throwing glossary accessor — only the non-throwing version accessor (which safely returns null before init) is used before a file is selected. All throwing glossary reads occur during preprocessing/compile, which runs after the file-select fetch.

Prolific draft defaults read the registry. The Prolific study draft creation reads the title/description defaults from the registry's glossary accessor instead of receiving a glossary-data prop. The glossaryData argument is dropped from the draft-creation function's interface, and the prop is no longer threaded through the Step/Running component tree.

Fallback precedence is preserved exactly. The experiment-defined value wins; the glossary default is used only when the experiment didn't define the parameter (the bridge that copies the experiment value only assigns it when the parameter row exists in the table, so an undefined value correctly signals "not defined"). An empty-but-present value continues to fall back to the default (pre-existing behavior, unchanged). This is a same-value swap — only the source of .default changes, not the precedence logic.

New registry getter. A non-throwing getter is added to the registry returning the full glossary list (or an empty list when uninitialized), consumed by the currently-unreachable glossary viewer. The viewer code itself is kept (not deleted), merely rewired off React state.

Modules built/modified:

  • Glossary registry module — add a non-throwing "full glossary list" getter alongside the existing accessors.
  • Compiler app root — remove the launch fetch, the glossary React state, the render gate, and the glossary prop passed to child steps; rewire the viewer to the registry getter.
  • File-drop handler — unchanged; its version-probe + version-pinned fetch + "Glossary …" dialog now actually executes on first file-select.
  • Prolific integration module — drop the glossary-data parameter; read defaults from the registry accessor.
  • Running step — stop forwarding the glossary-data prop into Prolific draft creation.

Testing Decisions

What makes a good test here: assert externally observable behavior, not implementation details. For the Prolific draft, that means asserting the request payload's title/description given experiment params and a registry-provided glossary — not how the value is plumbed.

Modules tested:

  • Prolific draft creation — keep the existing fallback-default tests green by mocking the registry's glossary accessor to return the test glossary (instead of passing glossary data as an argument). Continue asserting: defined experiment value wins; empty/undefined experiment value falls back to the glossary default in the request payload.
  • File-drop handler — existing tests remain valid and green; they already prove the version-pinned fetch and registry init happen on file-select. No changes required.

Prior art: the existing file-drop handler tests (version-probe, fetch-by-version, registry init ordering) and the existing Prolific draft fallback-default tests are the model to follow.

Removed: the compiler-app-root test asserting a launch-time glossary fetch/registry-init on mount is deleted, as that contract no longer exists. The "we don't fetch on mount" guarantee is implicitly covered by the file-drop tests proving the fetch happens on select.

Out of Scope

  • Reworking the Prolific fallback to read resolved compiled params instead of the raw glossary default (the redundancy noted during design). Behavior is preserved as-is.
  • Changing how an empty-but-present _online1Title/_online2Description is treated (still falls back to default).
  • Wiring up / reviving the glossary viewer (it remains unreachable; this PRD only keeps it from referencing deleted state).
  • The participant-runtime glossary path (the experiment runtime bundle loads its glossary at experiment runtime via its own loader). It is a separate bundle/context and is not affected.
  • The file-drop handler's version-probe/fetch logic and the loading dialog itself — kept as written.

Further Notes

  • A subtle correctness improvement falls out of this change: the Prolific draft defaults now come from the version-pinned glossary fetched for the current compile, rather than the launch-time "current" (short-cached) snapshot — so defaults are consistent with the glossary the experiment compiled against.
  • The "Glossary …" loading dialog was added recently but was effectively dead because the launch fetch usually beat the scientist to the file-select; removing the launch fetch is what makes that dialog do its job.

Metadata

Metadata

Assignees

Labels

needs-triageNewly created, awaiting triage

Type

No type
No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions