summaryrefslogtreecommitdiff
path: root/src/SomhairlesDream.Server
diff options
context:
space:
mode:
Diffstat (limited to 'src/SomhairlesDream.Server')
-rw-r--r--src/SomhairlesDream.Server/ArtifactRunCoordinator.fs24
1 files changed, 22 insertions, 2 deletions
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<ArtifactManifest, ArtifactLookupError> =
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<ArtifactFile, ArtifactLookupError> =
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