diff options
Diffstat (limited to 'src/SomhairlesDream.Server/ArtifactRunCoordinator.fs')
| -rw-r--r-- | src/SomhairlesDream.Server/ArtifactRunCoordinator.fs | 24 |
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 |
