From 449b5068049c86c5390e013943b3a9e93a500591 Mon Sep 17 00:00:00 2001 From: Eric Rakestraw Date: Sun, 9 Aug 2026 19:45:21 +0000 Subject: [PATCH] Update evidence context output coverage --- .../cli/dnd_enemy_events_contract_test.go | 25 +++++++--------- .../generic/output/json/encoder_test.go | 7 +++-- .../dnd_location_registry_runner_test.go | 18 +++++------ .../integration/dnd_npc_grounded_test.go | 30 ++++++++----------- 4 files changed, 35 insertions(+), 45 deletions(-) diff --git a/internal/cli/dnd_enemy_events_contract_test.go b/internal/cli/dnd_enemy_events_contract_test.go index 886de26..5085492 100644 --- a/internal/cli/dnd_enemy_events_contract_test.go +++ b/internal/cli/dnd_enemy_events_contract_test.go @@ -189,10 +189,18 @@ func TestMaintainedCompleteExamplePublishesRegistryBackedEntityOccurrences(t *te } evidence := readProductionJSON[evidencecontext.Document](t, filepath.Join(runRoot, "evidence-context.json")) - for _, laneID := range []string{"enemy-events", "npc-registry", "npc-occurrences", "item-registry", "item-occurrences", "location-registry", "location-occurrences"} { - if !containsString(evidence.SelectedLanes, laneID) || !evidenceHasLane(evidence, laneID) { - t.Fatalf("evidence context = %#v, want direct %s evidence", evidence, laneID) + if len(evidence) == 0 { + t.Fatalf("evidence context = %#v, want selected source-unit evidence", evidence) + } + seenEvidenceUnits := make(map[int]struct{}, len(evidence)) + for _, unit := range evidence { + if unit.Ref.SourceID != "session-ravenfall" || unit.Ref.StartUnitID != unit.ID || unit.Ref.EndUnitID != unit.ID { + t.Fatalf("evidence unit = %#v, want unchanged source-unit self-reference", unit) } + if _, exists := seenEvidenceUnits[unit.ID]; exists { + t.Fatalf("evidence context = %#v, want each source unit once", evidence) + } + seenEvidenceUnits[unit.ID] = struct{}{} } requests := client.requestsFor(enemyevents.PromptID) @@ -415,17 +423,6 @@ func containsString(values []string, want string) bool { return false } -func evidenceHasLane(value evidencecontext.Document, laneID string) bool { - for _, context := range value.Contexts { - for _, reference := range context.EvidenceRefs { - if reference.LaneID == laneID { - return true - } - } - } - return false -} - func generatedReferenceBinding(bindings []pipeline.ReferenceBinding, slotName string) (pipeline.ReferenceBinding, bool) { for _, binding := range bindings { if binding.SlotName == slotName && binding.Artifact != nil { diff --git a/internal/modules/generic/output/json/encoder_test.go b/internal/modules/generic/output/json/encoder_test.go index b51551a..86a13c1 100644 --- a/internal/modules/generic/output/json/encoder_test.go +++ b/internal/modules/generic/output/json/encoder_test.go @@ -353,8 +353,8 @@ func TestEncodeIncludesValidatedEvidenceContext(t *testing.T) { if err != nil { t.Fatalf("Decode(evidence context file) error = %v", err) } - if len(value.Contexts) != 0 { - t.Fatalf("evidence context = %#v, want explicit empty contexts", value) + if len(value) != 1 || value[0].ID != 7 || value[0].Text != "Source content retained only in the evidence artifact." { + t.Fatalf("evidence context = %#v, want the published source-unit array", value) } index := decodeObject(t, fileBytes(t, result.Files, "index.json")) if got, want := index["evidence_context"], map[string]any{ @@ -786,7 +786,8 @@ func acceptedEvidenceContextArtifact(t *testing.T) contracts.SerializedArtifact } document.Digest = digest artifact, err := evidencecontext.Serialize(evidencecontext.BuildRequest{ - Source: document, WindowUnits: 3, SelectedLanes: []string{"spells"}, + Source: document, WindowUnits: 3, + SourceRefs: []source.SourceRef{{SourceID: "source-1", StartUnitID: 7, EndUnitID: 7}}, }) if err != nil { t.Fatal(err) diff --git a/internal/modules/integration/dnd_location_registry_runner_test.go b/internal/modules/integration/dnd_location_registry_runner_test.go index 86e03d2..a51a9c2 100644 --- a/internal/modules/integration/dnd_location_registry_runner_test.go +++ b/internal/modules/integration/dnd_location_registry_runner_test.go @@ -4,6 +4,7 @@ import ( "context" "encoding/json" "fmt" + "reflect" "strings" "sync" "testing" @@ -71,20 +72,17 @@ func TestLocationRegistryHandoffProducesOccurrencesAndEvidence(t *testing.T) { if err != nil { t.Fatalf("Decode(evidence context) error = %v", err) } - if !locationEvidenceHasLane(evidence, "locations") || !locationEvidenceHasLane(evidence, "occurrences") { - t.Fatalf("evidence context = %#v, want registry and occurrence evidence from their own artifacts", evidence) + if actual := locationEvidenceUnitIDs(evidence); !reflect.DeepEqual(actual, []int{1, 2, 3, 4, 5}) { + t.Fatalf("evidence context = %#v, want deduplicated registry and occurrence source-unit evidence", evidence) } } -func locationEvidenceHasLane(document evidencecontext.Document, laneID string) bool { - for _, context := range document.Contexts { - for _, reference := range context.EvidenceRefs { - if reference.LaneID == laneID { - return true - } - } +func locationEvidenceUnitIDs(document evidencecontext.Document) []int { + ids := make([]int, len(document)) + for index, unit := range document { + ids[index] = unit.ID } - return false + return ids } func TestLocationOccurrenceConsumerDoesNotRunAfterRejectedRegistry(t *testing.T) { diff --git a/internal/modules/integration/dnd_npc_grounded_test.go b/internal/modules/integration/dnd_npc_grounded_test.go index fa5b45e..15fb17b 100644 --- a/internal/modules/integration/dnd_npc_grounded_test.go +++ b/internal/modules/integration/dnd_npc_grounded_test.go @@ -279,22 +279,8 @@ func TestProductionDNDOutputPublishesSelectedEvidenceContext(t *testing.T) { if err != nil { t.Fatalf("Decode(evidence context) error = %v", err) } - if !reflect.DeepEqual(value.SelectedLanes, []string{"combat", "npc_registry", "spells"}) { - t.Fatalf("selected lanes = %#v, want configured production lanes without scene descriptions", value.SelectedLanes) - } - if len(value.Contexts) != 2 || len(value.Contexts[0].Units) != 1 || len(value.Contexts[1].Units) != 1 || value.Contexts[0].Units[0].ID != 10 || value.Contexts[1].Units[0].ID != 20 { - t.Fatalf("evidence contexts = %#v, want source-position union with non-monotonic unit IDs", value.Contexts) - } - firstRefs := value.Contexts[0].EvidenceRefs - if len(firstRefs) != 3 || firstRefs[0].LaneID != "combat" || firstRefs[1].LaneID != "npc_registry" || firstRefs[2].LaneID != "spells" { - t.Fatalf("first context evidence = %#v, want overlapping selected lane references", firstRefs) - } - for _, context := range value.Contexts { - for _, reference := range context.EvidenceRefs { - if reference.LaneID == "scene-descriptions" { - t.Fatalf("evidence refs = %#v, want scene descriptions excluded by allowlist", value.Contexts) - } - } + if actual := evidenceUnitIDs(value); !reflect.DeepEqual(actual, []int{10, 20}) { + t.Fatalf("evidence units = %#v, want deduplicated source-position union without scene descriptions", actual) } } @@ -312,11 +298,19 @@ func TestProductionDNDOutputCanExplicitlySelectSceneDescriptionEvidence(t *testi if err != nil { t.Fatalf("Decode(evidence context) error = %v", err) } - if !reflect.DeepEqual(value.SelectedLanes, []string{"scene-descriptions"}) || len(value.Contexts) == 0 || len(value.Contexts[0].EvidenceRefs) == 0 || value.Contexts[0].EvidenceRefs[0].LaneID != "scene-descriptions" { - t.Fatalf("evidence context = %#v, want explicitly selected scene-description evidence", value) + if len(value) == 0 { + t.Fatalf("evidence context = %#v, want explicitly selected scene-description source units", value) } } +func evidenceUnitIDs(value evidencecontext.Document) []int { + ids := make([]int, len(value)) + for index, unit := range value { + ids[index] = unit.ID + } + return ids +} + func TestGroundedPipelineSkipsCombatForExactNarrativeScene(t *testing.T) { registries := productionNPCRegistries(t) configValue := loadGroundedPipelineConfig(t)