diff options
| -rw-r--r-- | public/App.js | 16 | ||||
| -rw-r--r-- | src/SomhairlesDream.Frontend/App.fs | 15 | ||||
| -rw-r--r-- | src/SomhairlesDream.Server/ArtifactRunCoordinator.fs | 13 |
3 files changed, 39 insertions, 5 deletions
diff --git a/public/App.js b/public/App.js index a401102..c98b708 100644 --- a/public/App.js +++ b/public/App.js @@ -841,6 +841,20 @@ export function selectedRun() { return new RunSelection(inputValue("project-id-input"), inputValue("run-id-input"), inputValue("base-id-input"), inputValue("target-id-input"), element("run-render-input").checked); } +export function freshLiveRunId(base_) { + const arg_1 = ~~(Date.now() % 1000000) | 0; + return toText(printf("%s-live-%d"))(base_)(arg_1); +} + +export function selectionForLiveStart(selection) { + if (selection.RunId === "run-probe-real-2") { + return new RunSelection(selection.ProjectId, freshLiveRunId(selection.RunId), selection.BaseId, selection.TargetId, selection.Render); + } + else { + return selection; + } +} + export function startRun(selection) { const requestBody = { projectId: selection.ProjectId, @@ -960,7 +974,7 @@ export function boot() { }); element("run-controls").addEventListener("submit", (event) => { event.preventDefault(); - startRun(selectedRun()); + startRun(selectionForLiveStart(selectedRun())); }); loadBootHistory(); renderTimeline(); diff --git a/src/SomhairlesDream.Frontend/App.fs b/src/SomhairlesDream.Frontend/App.fs index f9184c5..ec9e273 100644 --- a/src/SomhairlesDream.Frontend/App.fs +++ b/src/SomhairlesDream.Frontend/App.fs @@ -662,6 +662,19 @@ let selectedRun () = TargetId = inputValue "target-id-input" Render = (element "run-render-input" :?> HtmlInput).``checked`` } +// The boot run id names a pre-published historical replay that already has an +// on-disk manifest; re-running it can only fail ("run directory already +// exists"). A user submit keeps their typed ids unless they left the boot +// default untouched — then pick a fresh live run id instead. +let freshLiveRunId (base_: string) = + sprintf "%s-live-%d" base_ (int (JS.Constructors.Date.now () % 1000000.0)) + +let selectionForLiveStart (selection: RunSelection) = + if selection.RunId = "run-probe-real-2" then + { selection with RunId = freshLiveRunId selection.RunId } + else + selection + let startRun (selection: RunSelection) = let requestBody = createObj @@ -762,7 +775,7 @@ let boot () = (element "viewport-note").addEventListener("click", fun _ -> retryFailedLoad ()) (element "run-controls").addEventListener("submit", fun event -> event.preventDefault() - startRun (selectedRun ())) + startRun (selectionForLiveStart (selectedRun ()))) loadBootHistory () diff --git a/src/SomhairlesDream.Server/ArtifactRunCoordinator.fs b/src/SomhairlesDream.Server/ArtifactRunCoordinator.fs index 51a4fcd..6cd5fd3 100644 --- a/src/SomhairlesDream.Server/ArtifactRunCoordinator.fs +++ b/src/SomhairlesDream.Server/ArtifactRunCoordinator.fs @@ -267,10 +267,17 @@ type ArtifactRunCoordinator( | Some store -> let snapshot = store.Observe(clock ()) - if snapshot.Status <> "complete" then - Error(RunNotComplete snapshot) - else + if snapshot.Status = "complete" then verifiedManifest projectId runId + else + // A live entry that failed or is idling (e.g. "run directory + // already exists" because the run was pre-published on disk) + // must not shadow a complete on-disk manifest: the historical + // replay stays viewable while the rejected live attempt is + // reported by /api/runs/events. + match verifiedManifest projectId runId with + | Ok manifest -> Ok manifest + | Error _ -> Error(RunNotComplete snapshot) member _.Artifact(projectId: string, runId: string, relativePath: string) : Result<ArtifactFile, ArtifactLookupError> = match registry.TryFind(projectId, runId) with |
