From 958e24b0fd08e4bc92656964e832606dbf7d3fa3 Mon Sep 17 00:00:00 2001 From: "Somhairle H. Marisol" Date: Mon, 21 Sep 2026 10:14:24 +0800 Subject: feat(boot): surface pre-published probe replay on landing page - boot loads the completed run from /api/artifacts/manifest and renders its latest checkpoint with concrete build-review labels (no fake unknown-state wording); offline fallback still shows the honest placeholder - artifact manifest/steps endpoints now fall back to disk when a completed run has no in-memory registry entry, keeping pre-published history browsable after a service restart (digest-verified, .glb-only / steps/ / logs/ rejected) - driver: heritage flows pin heritage ids explicitly; new checks for the boot probe replay and its labels; 72/72 green with zero console errors --- .../ArtifactRunCoordinator.fs | 24 ++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) (limited to 'src/SomhairlesDream.Server') diff --git a/src/SomhairlesDream.Server/ArtifactRunCoordinator.fs b/src/SomhairlesDream.Server/ArtifactRunCoordinator.fs index 07ac984..51a4fcd 100644 --- a/src/SomhairlesDream.Server/ArtifactRunCoordinator.fs +++ b/src/SomhairlesDream.Server/ArtifactRunCoordinator.fs @@ -261,7 +261,9 @@ type ArtifactRunCoordinator( member _.Manifest(projectId: string, runId: string) : Result = match registry.TryFind(projectId, runId) with - | None -> Error RunNotFound + // Pre-published historical runs persist on disk after restarts; serve + // them from the verified manifest when no live registry entry exists. + | None -> verifiedManifest projectId runId | Some store -> let snapshot = store.Observe(clock ()) @@ -293,7 +295,25 @@ type ArtifactRunCoordinator( member _.StepArtifact(projectId: string, runId: string, relativePath: string) : Result = match registry.TryFind(projectId, runId) with - | None -> Error RunNotFound + // Disk fallback keeps pre-published historical checkpoints reachable + // for boot replay after a service restart; only .glb step artifacts + // under steps/ are ever served, digest-verified against the manifest. + | None -> + match safeArtifactPath (runDirectory projectId runId) relativePath with + | Error message -> Error(InvalidArtifactPath message) + | Ok(_, normalized) when not (normalized.EndsWith(".glb", StringComparison.OrdinalIgnoreCase)) -> + Error(InvalidArtifactPath "step artifacts must be .glb files") + | Ok(_, normalized) when not (normalized.StartsWith("steps/", StringComparison.Ordinal)) -> + Error(InvalidArtifactPath "step artifacts must live under steps/") + | Ok(fullPath, normalized) -> + let digest = + match rejectLinks fullPath with + | Error message -> Error(InvalidArtifactPath message) + | Ok () -> completedDigest projectId runId normalized + + match digest with + | Error lookupError -> Error lookupError + | Ok(sha256, bytes) -> openValidated fullPath normalized sha256 bytes | Some store -> let directory = runDirectory projectId runId -- cgit v1.2.3