Build Process Saga
Convert the build process to use the saga framework, including a streaming I/O pattern that lets us recover tar uploads if the original stream is gone by the time we resume.
Scope
Convert BuildFromTar (and the shared buildFromDir core used by BuildFromPrepared) into a saga definition with actions for each step of the build pipeline: stage source, detect stack, run BuildKit, locate artifact, validate config, create version, activate. Compensation undoes entity creation and cleans up staged source.
The novel piece is a StreamRegistry (application-level, not framework) that maps stream IDs to active readers and staged paths, so the first action can stage the incoming tar to disk and recovery can fall back to that path when the original stream is long gone.
Wire the saga path behind the existing labs.Sagas() flag alongside the sandbox saga from MIR-440.
Testing
- Success path with real tar data
- Failure injection at each build step verifying compensation runs in reverse
- Crash recovery (interrupt during tar receive, during build, during entity creation)
- Stream recovery (original stream gone, staged path used)
- Multiple concurrent builds
- Performance check that saga overhead doesn't regress build times
Why One Issue
The streaming pattern is unique to builds and requires all pieces working together. Splitting would create incomplete, non-testable code.
Dependencies
Requires: MIR-439 (Saga Framework Foundation). Builds on MIR-440 (Sandbox Creation Saga) for the pattern.
Reference
RFD 0035: Saga Pattern for Distributed Operations — "Handling Non-Serializable Data" and the build-process motivation.