Migrate NPC reconciliation to shared engine

This commit is contained in:
2026-08-09 16:38:43 +00:00
parent 569e12c6f4
commit 8c071800cf
14 changed files with 270 additions and 304 deletions

View File

@@ -213,7 +213,7 @@ func Prepare(document *source.SourceDocument, candidates []Candidate, limits Lim
}
windows, err := buildContextWindows(document.Units, coalesceIntervals(intervals), cited)
if err != nil {
return Preparation{}, fmt.Errorf("prepare semantic reconciliation: build transcript material: %w", err)
return Preparation{}, fmt.Errorf("prepare semantic reconciliation: build transcript material: invalid source metadata")
}
transcriptContent, err := json.Marshal(transcriptInput{Windows: windows})
if err != nil {

View File

@@ -4,6 +4,7 @@ import (
"crypto/sha256"
"encoding/hex"
"encoding/json"
"math"
"reflect"
"strings"
"testing"
@@ -148,6 +149,27 @@ func TestPrepareBuildsContiguousCandidatesAndOwnedSourceContext(t *testing.T) {
}
}
func TestPrepareRedactsInvalidSourceMetadata(t *testing.T) {
const sensitiveKey = "sensitive-metadata-key"
document := &source.SourceDocument{ID: "private-source", Units: []source.SourceUnit{
{ID: 1, Text: "private transcript", Metadata: map[string]any{sensitiveKey: math.NaN()}},
{ID: 2, Text: "other private transcript"},
}}
candidates := []Candidate{
{Label: "Private One", SourceRefs: []source.SourceRef{{SourceID: document.ID, StartUnitID: 1, EndUnitID: 1}}},
{Label: "Private Two", SourceRefs: []source.SourceRef{{SourceID: document.ID, StartUnitID: 2, EndUnitID: 2}}},
}
_, err := Prepare(document, candidates, DefaultLimits())
if err == nil || !strings.Contains(err.Error(), "invalid source metadata") {
t.Fatalf("Prepare() error = %v, want redacted metadata failure", err)
}
for _, forbidden := range []string{sensitiveKey, document.ID, document.Units[0].Text, candidates[0].Label, "non-finite", "float64"} {
if strings.Contains(err.Error(), forbidden) {
t.Fatalf("Prepare() error leaked %q: %v", forbidden, err)
}
}
}
func TestPrepareFiltersUnsafeCandidatesAndCoalescesAdjacentWindows(t *testing.T) {
document := &source.SourceDocument{ID: "session", Units: []source.SourceUnit{
{ID: 9}, {ID: 3}, {ID: 8}, {ID: 1}, {ID: 7},