94 lines
4.0 KiB
Go
94 lines
4.0 KiB
Go
package semanticreconcile
|
|
|
|
import (
|
|
"testing"
|
|
|
|
"gitea.maximumdirect.net/eric/notarius/internal/framework/llm"
|
|
"gitea.maximumdirect.net/eric/notarius/internal/framework/pipeline"
|
|
)
|
|
|
|
func TestEngineMetadataAndFingerprintsCoverCoreIdentity(t *testing.T) {
|
|
base := newTestEngine(t, &recordingReconciliationClient{}, DefaultLimits())
|
|
metadata := base.ManifestMetadata()
|
|
for _, key := range []string{
|
|
"prompt_id", "prompt_version", "prompt_sha256",
|
|
"response_schema_key", "response_schema_id", "response_schema_name", "response_schema_version", "response_schema_sha256",
|
|
"semantic_reconciliation_policy", "semantic_reconciliation_limits",
|
|
} {
|
|
if metadata[key] == nil || metadata[key] == "" {
|
|
t.Fatalf("metadata[%q] = %#v, want populated core identity", key, metadata[key])
|
|
}
|
|
}
|
|
limits, ok := metadata["semantic_reconciliation_limits"].(map[string]any)
|
|
if !ok || len(limits) != 3 || limits["context_radius"] == nil || limits["maximum_candidates"] == nil || limits["maximum_material_bytes"] == nil {
|
|
t.Fatalf("limit metadata = %#v, want complete limits", metadata["semantic_reconciliation_limits"])
|
|
}
|
|
fingerprints := base.CheckpointFingerprints()
|
|
wantNames := []string{"prompt", "response_schema", "semantic_reconciliation_policy", "semantic_reconciliation_limits"}
|
|
if len(fingerprints) != len(wantNames) {
|
|
t.Fatalf("fingerprints = %#v, want required categories", fingerprints)
|
|
}
|
|
for index, want := range wantNames {
|
|
if fingerprints[index].Name != want || fingerprints[index].Value == "" {
|
|
t.Fatalf("fingerprint %d = %#v, want %q with value", index, fingerprints[index], want)
|
|
}
|
|
}
|
|
|
|
metadata["prompt_id"] = "changed"
|
|
limits["context_radius"] = -1
|
|
fingerprints[0].Name = "changed"
|
|
if got := base.ManifestMetadata(); got["prompt_id"] == "changed" || got["semantic_reconciliation_limits"].(map[string]any)["context_radius"] == -1 {
|
|
t.Fatalf("ManifestMetadata() exposed retained state: %#v", got)
|
|
}
|
|
if got := base.CheckpointFingerprints(); got[0].Name == "changed" {
|
|
t.Fatalf("CheckpointFingerprints() exposed retained state: %#v", got)
|
|
}
|
|
}
|
|
|
|
func TestCoreFingerprintsChangeWithBehavioralIdentity(t *testing.T) {
|
|
base := newTestEngine(t, &recordingReconciliationClient{}, DefaultLimits())
|
|
baseFingerprints := base.CheckpointFingerprints()
|
|
|
|
promptChanged, err := NewEngine(&recordingReconciliationClient{}, testPromptSpec("b"), DefaultLimits())
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
assertOnlyFingerprintChanged(t, baseFingerprints, promptChanged.CheckpointFingerprints(), "prompt")
|
|
|
|
schema, err := LoadResponseSchema()
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
schema.SHA256 = testDigest("b")
|
|
schemaChanged := newEngine(&recordingReconciliationClient{}, base.prompt, schema, DefaultLimits())
|
|
assertOnlyFingerprintChanged(t, baseFingerprints, schemaChanged.CheckpointFingerprints(), "response_schema")
|
|
|
|
limits := DefaultLimits()
|
|
limits.ContextRadius++
|
|
limitsChanged, err := NewEngine(&recordingReconciliationClient{}, base.prompt, limits)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
assertOnlyFingerprintChanged(t, baseFingerprints, limitsChanged.CheckpointFingerprints(), "semantic_reconciliation_limits")
|
|
}
|
|
|
|
func TestInvalidEngineIdentityHasNoMetadataOrFingerprints(t *testing.T) {
|
|
invalid := newEngine(&recordingReconciliationClient{}, testPromptSpec("a"), llm.ResponseSchema{}, DefaultLimits())
|
|
if invalid.ManifestMetadata() != nil || invalid.CheckpointFingerprints() != nil {
|
|
t.Fatalf("invalid engine exposed identity: metadata %#v fingerprints %#v", invalid.ManifestMetadata(), invalid.CheckpointFingerprints())
|
|
}
|
|
}
|
|
|
|
func assertOnlyFingerprintChanged(t *testing.T, before, after []pipeline.CheckpointFingerprint, changedName string) {
|
|
t.Helper()
|
|
if len(before) != len(after) {
|
|
t.Fatalf("fingerprint counts differ: %#v %#v", before, after)
|
|
}
|
|
for index := range before {
|
|
changed := before[index] != after[index]
|
|
if changed != (before[index].Name == changedName) {
|
|
t.Fatalf("fingerprint %q change = %t, want only %q changed\nbefore: %#v\nafter: %#v", before[index].Name, changed, changedName, before, after)
|
|
}
|
|
}
|
|
}
|