Harden prepare and transcribe transitions

This commit is contained in:
2026-08-10 21:53:54 +00:00
parent 9da2c1e144
commit 702f622e18
8 changed files with 165 additions and 22 deletions

View File

@@ -205,10 +205,10 @@ func (prepareStage) Run(ctx context.Context, env *Env, m *manifest.Manifest) (*S
previousRequirements := collectPreparePreviousRequirements(env.Config)
var previousHydration *previousSessionHydrationResult
if err := clearManagedPreviousState(paths); err != nil {
return nil, fmt.Errorf("prepare: clear previous-session cache: %w", err)
}
if len(previousRequirements) > 0 {
if err := clearManagedPreviousState(paths); err != nil {
return nil, fmt.Errorf("prepare: clear previous-session cache: %w", err)
}
hydration, err := hydratePreviousSessionArtifacts(ctx, env, paths, previousRequirements)
if err != nil {
return nil, fmt.Errorf("prepare: hydrate previous-session artifacts: %w", err)
@@ -302,6 +302,7 @@ func resolveAudioInputs(sessionDir string, inputs config.SessionInputsConfig) ([
func resolveLocalAudioFiles(sessionDir string, inputs config.SessionInputsConfig) ([]string, error) {
if len(inputs.AudioFiles) > 0 {
out := make([]string, 0, len(inputs.AudioFiles))
seen := make(map[string]struct{}, len(inputs.AudioFiles))
for _, p := range inputs.AudioFiles {
resolved, err := resolvePath(sessionDir, p)
if err != nil {
@@ -313,6 +314,10 @@ func resolveLocalAudioFiles(sessionDir string, inputs config.SessionInputsConfig
if err := requireFile(resolved, "audio file"); err != nil {
return nil, err
}
if _, exists := seen[resolved]; exists {
return nil, fmt.Errorf("duplicate audio source %q", resolved)
}
seen[resolved] = struct{}{}
out = append(out, resolved)
}
sort.Strings(out)
@@ -352,24 +357,41 @@ func resolveLocalAudioFiles(sessionDir string, inputs config.SessionInputsConfig
}
func materializeLocalAudioInputs(env *Env, paths artifacts.SessionPaths, resolvedAudio []string, registerInput func(kind, path, checksum string)) error {
copiedByDest := map[string]string{}
destinations := localAudioDestinations(resolvedAudio)
for _, src := range resolvedAudio {
base := filepath.Base(src)
if prev, exists := copiedByDest[base]; exists && prev != src {
return fmt.Errorf("duplicate audio basename %q from %q and %q", base, prev, src)
}
copiedByDest[base] = src
dst := filepath.Join(paths.AudioDir, base)
dst := filepath.Join(paths.AudioDir, destinations[src])
checksum, err := copyFileIfChanged(env.ArtifactStore, src, dst)
if err != nil {
return fmt.Errorf("materialize audio %q: %w", base, err)
return fmt.Errorf("materialize audio %q: %w", src, err)
}
registerInput("audio", dst, checksum)
}
return nil
}
func localAudioDestinations(audioPaths []string) map[string]string {
byBase := make(map[string][]string, len(audioPaths))
for _, audioPath := range audioPaths {
base := filepath.Base(audioPath)
byBase[base] = append(byBase[base], audioPath)
}
destinations := make(map[string]string, len(audioPaths))
for base, sources := range byBase {
if len(sources) == 1 {
destinations[sources[0]] = base
continue
}
extension := filepath.Ext(base)
stem := strings.TrimSuffix(base, extension)
for _, source := range sources {
digest := sha256.Sum256([]byte(filepath.Clean(source)))
destinations[source] = fmt.Sprintf("%s-%s%s", stem, hex.EncodeToString(digest[:8]), extension)
}
}
return destinations
}
type s3AudioMaterializationStats struct {
CacheHits int
CacheMisses int