summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSomhairle H. Marisol <[email protected]>2026-09-21 10:58:44 +0800
committerSomhairle H. Marisol <[email protected]>2026-09-21 10:58:44 +0800
commit7a4e0b4677e0241ab19489ef40a462810f841415 (patch)
treeb33d7ca5fb8d9527989696da52be8e47d26a5198
parentb8e49e1b8b57393f47bcc9a29664a7f509584ba2 (diff)
downloadsomhairles-dream-fsharp-7a4e0b4677e0241ab19489ef40a462810f841415.tar.gz
fix(boot): failed live attempt no longer shadows pre-published history; boot-default submit picks a fresh live run id
-rw-r--r--public/App.js16
-rw-r--r--src/SomhairlesDream.Frontend/App.fs15
-rw-r--r--src/SomhairlesDream.Server/ArtifactRunCoordinator.fs13
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