Files
narratio/internal/artifacts/extraction_input.go

77 lines
2.5 KiB
Go

package artifacts
import (
"crypto/sha256"
"encoding/hex"
"fmt"
"path/filepath"
"strings"
"gitea.maximumdirect.net/eric/narratio/internal/fileops"
"gitea.maximumdirect.net/eric/narratio/internal/manifest"
)
const extractionMetadataInput = "direct_input"
// ExtractionInputIdentity identifies the exact trimmed transcript used for extraction.
type ExtractionInputIdentity struct {
Path string `json:"-"`
Checksum string `json:"checksum"`
SourceID string `json:"source_id"`
ProducerStage string `json:"producer_stage"`
OutputKind string `json:"output_kind"`
ProducerRunID string `json:"producer_run_id"`
Provenance string `json:"provenance"`
}
// ResolveExtractionInputIdentity resolves and hashes the direct transcript input.
func ResolveExtractionInputIdentity(paths SessionPaths, m *manifest.Manifest) (ExtractionInputIdentity, error) {
resolved, err := ResolveSessionArtifact(paths, m, ArtifactTranscriptFinalTrimmed)
if err != nil {
return ExtractionInputIdentity{}, err
}
path, err := filepath.Abs(resolved.Path)
if err != nil {
return ExtractionInputIdentity{}, fmt.Errorf("resolve trimmed transcript path: %w", err)
}
bytes, err := fileops.ReadRegularFile(path, MaxResolvedArtifactBytes)
if err != nil {
return ExtractionInputIdentity{}, fmt.Errorf("read trimmed transcript: %w", err)
}
digest := sha256.Sum256(bytes)
return ExtractionInputIdentity{
Path: filepath.Clean(path),
Checksum: hex.EncodeToString(digest[:]),
SourceID: resolved.ID,
ProducerStage: resolved.ProducerStage,
OutputKind: resolved.OutputKind,
ProducerRunID: resolved.ProducerRunID,
Provenance: resolved.Provenance,
}, nil
}
// Metadata returns the durable fields needed to compare this identity on reuse.
func (identity ExtractionInputIdentity) Metadata() map[string]any {
return map[string]any{
"checksum": identity.Checksum,
"source_id": identity.SourceID,
"producer_stage": identity.ProducerStage,
"output_kind": identity.OutputKind,
"producer_run_id": identity.ProducerRunID,
"provenance": identity.Provenance,
}
}
func extractionInputMatchesMetadata(metadata map[string]any, current ExtractionInputIdentity) bool {
stored, ok := metadata[extractionMetadataInput].(map[string]any)
if !ok || strings.TrimSpace(current.Checksum) == "" || strings.TrimSpace(current.SourceID) == "" {
return false
}
for key, want := range current.Metadata() {
if extractionMetadataString(stored, key) != want {
return false
}
}
return true
}