Spaces:
Sleeping
Prompt β "Stability across seeds" panel in the Lab (HNSC/HPV)
Add a multi-seed stability panel to the Lab that reruns the HPV search across
several seeds and shows (a) how tightly the result holds and (b) which genes
recur across independent searches. Frontend-only β reuse the existing run,
transfer, reveal, and full-rank endpoints. No engine / API / airgap change.
tsc after.
Gated to dataset === "hnsc" && target === "hpv" (hidden otherwise). Everything
this needs already exists on the wire; do not add a backend endpoint.
What it does
For each seed in a list (default [1, 3, 7, 11, 13, 17, 23, 29]), fire a normal
HPV run with that seed, wait for it to finish, then pull its held-out result and
its independent-cohort transfer. Aggregate across seeds into one panel.
Data flow (all existing endpoints)
- Fire a run:
postRun({ objective_spec: OBJECTIVE_PRESETS.hpv, params: { ...params, seed }, engine: "v2", dataset, coherence, diversity, ...ratesDiff })β i.e. the SAME bodylaunchRun()builds, onlyparams.seedoverridden per seed. Use the user's current Parameters / coherence / diversity / DSL rates so the sweep matches their single-run config. - Wait for completion without disturbing the main Live view / Result state.
Write a dedicated helper
awaitRunDone(runId): Promise<RunResult>that opens anEventSource(${API_URL}/runs/${runId}/stream), resolves on thedoneevent (parseRunResult), rejects onerror, and closes the stream β it must NOT callsetGenerations/setResult/setStatus(those belong to the main single-run UI). (PollinggetRunStatusuntil done thengetRunResultis an acceptable alternative.) - Per seed collect:
winning.holdout_score(this is the field the Result panel's "Held-out AUROC" card and the verdict display β use it, NOTholdout_auroc, so the stability dots match the numbers already on screen) andwinning.permutation_p(from the RunResult), thengetRunTransfer(runId)βauroc,p,n,found_symbols,missing_symbols. If transfer fails (e.g. GSE65858 not built), store null for the transfer fields and keep the held-out row β never crash the sweep. - After all seeds: call
getFullRankDiagnostic(dataset, target)once and build asymbol β set_namemap fromreference_marks(p16 / cell_cycle) to tag genes.
Recurrence (the key output)
- A seed's winner symbols come from
postReveal(winning.gene_ids)β a bounded reveal of just that winner's genes (same discipline/transferuses). Source it from the winner, not the transfer payload, so recurrence still works even if a seed's transfer call failed. (found_symbols βͺ missing_symbolsfrom the transfer is an equivalent set when transfer succeeds.) - Tally: for every symbol, count in how many seeds it appears. Sort desc. Tag each with its reference set via the map (else "alternate"/"β"). Genes in only 1 seed collapse into a single "passengers Β· 1 seed each" row (show the count of such genes).
UI (new <StabilityPanel> β match the approved mockup)
Reuse <SectionCard>, <InfoTip>, fmtFit, and the palette tokens so it looks
native. Place it as its own SectionCard in the Result area, after the
independent-cohort validation panel. Gated to hnsc/hpv.
- Header + its own "Run stability check" button (independent of the main Run button) + a seed-list input (comma or space separated, default the 8 above). While sweeping: disable both this button and the main Run button, show "Running seed {k} of {N}β¦", and offer a Stop button that sets a cancel flag checked between seeds (finish the current seed, then halt).
- Section 1 β "Does the result hold across seeds?" Two horizontal dot-strips
on a 0.5 β 1.0 axis (label "0.5 coin-flip" left, "1.0" right): Held-out AUROC
(accent-teal dots) and Independent AUROC (amber dots), one dot per completed
seed, with a light minβmax band behind the dots. Caption with the two ranges
(
minβmax, viafmtFit) and a one-line plain read ("tight + high = stable, not a lucky seed; the independent cohort costs a little, as expected"). - Section 2 β "Do the same genes keep coming back?" Recurrence bars: symbol | bar (width = seeds-appeared / N) | "{k} / {N} Β· {set}". Colour by tag: cell_cycle amber, p16 gold, alternate teal, passengers grey. Caption: recurring cell-cycle / proliferation genes = real signal; one-off passengers = noise.
- Section 3 β per-seed table: seed | held-out AUROC | p | independent AUROC |
p | genes found/total. Route every number through
fmtFit("β" for null). - Panel
?(InfoTip): what multi-seed proves β that the result isn't one lucky random start (spread), and that the same biology recurs across independent searches (recurrence); note each seed is a full run so the sweep takes a while.
CONSTRAINTS
- Frontend-only. No engine/API/airgap change. Reuse
postRun, the SSE stream,getRunResult,getRunTransfer,getFullRankDiagnostic. The only gene names shown are the winner's revealed symbols (already bounded via/transfer) and the reference marks (bounded known set) β no new reveal surface. - The sweep must not overwrite the main single-run Result / Live view; it keeps
its own state (
stabilityRows,stabilityStatus,stabilityProgress,stabilityCancel). - Runs are sequential (the backend runs one at a time); show progress, allow Stop. Graceful nulls if a transfer fails.
Checkpoint
- On an HNSC/HPV run, a "Stability across seeds" panel appears with a "Run stability check" button; clicking it sweeps the seeds, showing live progress.
- When done: two dot-strips (held-out + independent AUROC, one dot per seed with the range), a gene-recurrence bar list tagged by reference set, and a per-seed table. Hidden for colorectal.
- Main single-run Result/Live view is untouched while the sweep runs.
tscclean; no behaviour change to existing runs; airgap untouched.