Harden chunk map export and retire completed plans

This commit is contained in:
2026-07-23 17:38:04 +00:00
parent 06148074a2
commit b490297cde
6 changed files with 166 additions and 733 deletions

View File

@@ -4,6 +4,7 @@ import (
"bytes"
"encoding/json"
"os"
"reflect"
"strings"
"testing"
@@ -140,6 +141,62 @@ func TestCodecRejectsInvalidDurableBoundaries(t *testing.T) {
}
}
func TestDecodeEnforcesRequiredSchemaFieldsAndTypes(t *testing.T) {
request := acceptedBuildRequest(t)
request.Plan.Annotations = nil
var err error
request.Chunks, err = source.MaterializeChunkPlan(request.Source, request.Plan)
if err != nil {
t.Fatal(err)
}
artifact, err := Serialize(request)
if err != nil {
t.Fatal(err)
}
for _, test := range []struct {
name string
mutate func(map[string]any)
}{
{name: "missing plan annotations", mutate: func(value map[string]any) { delete(value, "plan_annotations") }},
{name: "null plan annotations", mutate: func(value map[string]any) { value["plan_annotations"] = nil }},
{name: "missing first index", mutate: func(value map[string]any) { delete(chunkDocument(value, 0), "index") }},
{name: "null first index", mutate: func(value map[string]any) { chunkDocument(value, 0)["index"] = nil }},
{name: "missing empty chunk annotations", mutate: func(value map[string]any) { delete(chunkDocument(value, 1), "annotations") }},
{name: "null empty chunk annotations", mutate: func(value map[string]any) { chunkDocument(value, 1)["annotations"] = nil }},
{name: "explicit empty llm profile", mutate: func(value map[string]any) {
value["producer"].(map[string]any)["llm_profile"] = ""
}},
} {
t.Run(test.name, func(t *testing.T) {
value := decodeJSONDocument(t, artifact.Content)
test.mutate(value)
content, err := json.Marshal(value)
if err != nil {
t.Fatal(err)
}
if _, err := New().Decode(content); err == nil {
t.Fatalf("Decode(%s) error = nil, want schema rejection", content)
}
})
}
}
func TestEncodeDoesNotMutateValue(t *testing.T) {
value, err := Build(acceptedBuildRequest(t))
if err != nil {
t.Fatal(err)
}
value.Chunks[0].Annotations["dnd/scenes"] = json.RawMessage(" { \n \"kind\" : \"narrative\" \n } ")
before := clone(value)
if _, err := New().Encode(value); err != nil {
t.Fatalf("Encode() error = %v", err)
}
if !reflect.DeepEqual(value, before) {
t.Fatalf("Encode() mutated value:\nbefore: %#v\nafter: %#v", before, value)
}
}
func TestChunkMapOwnershipIsIndependent(t *testing.T) {
request := acceptedBuildRequest(t)
first, err := Build(request)
@@ -157,6 +214,21 @@ func TestChunkMapOwnershipIsIndependent(t *testing.T) {
}
}
func decodeJSONDocument(t *testing.T, content []byte) map[string]any {
t.Helper()
decoder := json.NewDecoder(bytes.NewReader(content))
decoder.UseNumber()
var value map[string]any
if err := decoder.Decode(&value); err != nil {
t.Fatal(err)
}
return value
}
func chunkDocument(value map[string]any, index int) map[string]any {
return value["chunks"].([]any)[index].(map[string]any)
}
func acceptedBuildRequest(t *testing.T) BuildRequest {
t.Helper()
document := &source.SourceDocument{