From 36e217f51ef14b228979f6e472c8ecbd307f1c4f Mon Sep 17 00:00:00 2001 From: Michael Pilosov Date: Wed, 22 Apr 2026 15:39:05 -0600 Subject: [PATCH] submit: reject runs whose output would overwrite an existing fig MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Before dispatching to Prefect, check if figs/.html already exists. If so, return 409 with a message asking to bump seed/jitter/N/T or delete the fig. Stem is derived from (generator, embedder, N, T, J, seed), so embed_args-only changes still collide and are blocked — users must vary a stem-shaping param to get a distinct output file. --- app/web/main.py | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/app/web/main.py b/app/web/main.py index dee1952..551fd34 100644 --- a/app/web/main.py +++ b/app/web/main.py @@ -751,6 +751,24 @@ async def submit(request: Request) -> HTMLResponse: embed_args = build_embed_args(reducer, data) + # Reject submissions whose output path would overwrite an existing fig. + # The stem is fully determined by (generator, embedder, N, T, J, seed) — + # embed_args don't affect the filename, so e.g. UMAP(n_neighbors=5) and + # UMAP(n_neighbors=15) with otherwise-matching params collide too. Force + # the user to change a stem-shaping param (seed is usually cheapest) or + # delete the existing fig first. + _, emb_file = synthesize_output_paths( + generator_path, reducer, num_points, num_timesteps, jitter_scale, seed + ) + if (FIGS_DIR / emb_file).exists(): + return HTMLResponse( + f"
a run with these params already exists " + f"({emb_file}). change seed / " + f"jitter / N / T, or delete " + f"the fig first.
", + status_code=409, + ) + parameters: Dict[str, Any] = { "num_points": num_points, "num_timesteps": num_timesteps,