Bind extraction reuse to transcript identity

This commit is contained in:
2026-08-10 22:15:53 +00:00
parent 4e4eff6ba7
commit f39fc94610
14 changed files with 256 additions and 41 deletions

View File

@@ -79,9 +79,10 @@ func TestHydrateExtractionArtifactsAcceptsOnlyCompleteCurrentBundle(t *testing.T
func TestInspectExtractionEvidenceClassifiesBundleStates(t *testing.T) {
tests := []struct {
name string
state ExtractionEvidenceState
mutate func(*testing.T, *SessionPaths, *manifest.Manifest)
name string
state ExtractionEvidenceState
recomputeInputIdentity bool
mutate func(*testing.T, *SessionPaths, *manifest.Manifest)
}{
{name: "valid", state: ExtractionEvidenceValid, mutate: func(_ *testing.T, _ *SessionPaths, _ *manifest.Manifest) {}},
{name: "absent", state: ExtractionEvidenceAbsent, mutate: func(_ *testing.T, _ *SessionPaths, m *manifest.Manifest) {
@@ -90,6 +91,12 @@ func TestInspectExtractionEvidenceClassifiesBundleStates(t *testing.T) {
{name: "obsolete version", state: ExtractionEvidenceObsolete, mutate: func(_ *testing.T, _ *SessionPaths, m *manifest.Manifest) {
m.Stages["extract"].Outputs[0].Contract.SchemaVersion = "99"
}},
{name: "changed direct transcript", state: ExtractionEvidenceObsolete, recomputeInputIdentity: true, mutate: func(t *testing.T, _ *SessionPaths, m *manifest.Manifest) {
writeExtractionFixtureFile(t, m.Stages["trim"].Outputs[0].LocalPath, `{"segments":[{"id":"changed"}]}`)
}},
{name: "changed direct producer", state: ExtractionEvidenceObsolete, recomputeInputIdentity: true, mutate: func(_ *testing.T, _ *SessionPaths, m *manifest.Manifest) {
m.Stages["trim"].Outputs[0].ProducerRunID = "trim-run-2"
}},
{name: "incomplete", state: ExtractionEvidenceObsolete, mutate: func(_ *testing.T, _ *SessionPaths, m *manifest.Manifest) {
m.Stages["extract"].Outputs = m.Stages["extract"].Outputs[1:]
}},
@@ -115,8 +122,18 @@ func TestInspectExtractionEvidenceClassifiesBundleStates(t *testing.T) {
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
paths, currentManifest, definitions := validExtractionCatalogFixture(t)
input, err := ResolveExtractionInputIdentity(paths, currentManifest)
if err != nil {
t.Fatal(err)
}
test.mutate(t, &paths, currentManifest)
proof := InspectExtractionEvidence(paths, currentManifest, definitions)
if test.recomputeInputIdentity {
input, err = ResolveExtractionInputIdentity(paths, currentManifest)
if err != nil {
t.Fatal(err)
}
}
proof := InspectExtractionEvidence(paths, currentManifest, definitions, input)
if proof.State != test.state {
t.Fatalf("proof = %#v, want %q", proof, test.state)
}
@@ -231,18 +248,31 @@ func validExtractionCatalogFixture(t *testing.T) (SessionPaths, *manifest.Manife
t.Helper()
root := t.TempDir()
paths := SessionPaths{Root: root, ArtifactsDir: filepath.Join(root, "artifacts")}
trimmedPath := filepath.Join(paths.Root, filepath.FromSlash(TranscriptPathFinalTrimmed))
bundleRoot := filepath.Join(paths.ArtifactsDir, "notarius", "extract-run-1")
lanePath := filepath.Join(bundleRoot, "lanes", "encounters.json")
indexPath := filepath.Join(bundleRoot, "index.json")
writeExtractionFixtureFile(t, lanePath, `{"encounters":[]}`)
writeExtractionFixtureFile(t, indexPath, `{"lanes":[]}`)
writeExtractionFixtureFile(t, trimmedPath, `{"segments":[]}`)
definitions := extractionFixtureDefinitions()
m := manifest.New("session", fixtureTime)
m.Stages["trim"] = &manifest.StageRecord{
Name: "trim", Status: manifest.StatusSucceeded,
Outputs: []manifest.ArtifactRecord{{
Kind: TranscriptOutputKindFinalTrimmed, LocalPath: trimmedPath, ProducerRunID: "trim-run-1",
}},
}
input, err := ResolveExtractionInputIdentity(paths, m)
if err != nil {
t.Fatal(err)
}
m.Stages["extract"] = &manifest.StageRecord{
Name: "extract", Status: manifest.StatusSucceeded,
Metadata: map[string]any{
"narratio_run_id": "extract-run-1", "bundle_root": bundleRoot,
"receipt": map[string]any{"run_id": "notarius-run-1", "pipeline_id": "campaign.extract"},
"receipt": map[string]any{"run_id": "notarius-run-1", "pipeline_id": "campaign.extract"},
extractionMetadataInput: input.Metadata(),
},
Outputs: []manifest.ArtifactRecord{
{