Minimize D&D NPC extraction contracts

This commit is contained in:
2026-07-22 18:51:26 +00:00
parent 14991cf58b
commit a263a0840c
43 changed files with 486 additions and 1395 deletions

View File

@@ -65,14 +65,16 @@ func TestNPCOutputGroundsSpellAndCombatConsumersThroughOneOperation(t *testing.T
t.Fatalf("encode canonical NPC producer payload: %v", err)
}
canonicalDigest := digestBytes(npcPayload)
projection := []byte(`{"npcs":[{"name":"Mira Thorn"},{"name":"Hooded Guard"}]}`)
projectionDigest := digestBytes(projection)
seenConsumers := map[string]bool{}
for _, request := range client.requestsSnapshot() {
if request.PromptID != spells.PromptID && request.PromptID != combatextract.PromptID {
continue
}
input := request.Inputs["npcs"]
if input.MediaType != npccodec.MediaType || input.Digest != canonicalDigest || string(input.Content) != string(npcPayload) || input.OriginURI != "" {
t.Fatalf("%s NPC prompt input = %#v, want canonical generated registry without provenance", request.PromptID, input)
if input.MediaType != npccodec.MediaType || input.Digest != projectionDigest || string(input.Content) != string(projection) || input.OriginURI != "" {
t.Fatalf("%s NPC prompt input = %#v, want names-only generated registry", request.PromptID, input)
}
seenConsumers[request.PromptID] = true
}
@@ -107,7 +109,7 @@ func TestNPCOutputGroundsSpellAndCombatConsumersThroughOneOperation(t *testing.T
switch serialized.LaneID {
case "spells":
spellValue := decodeRunnerSpellResponse(t, serialized.Artifact.Content)
if len(spellValue.SpellCasts) != 1 || spellValue.SpellCasts[0].Caster != "The Greencloak" {
if len(spellValue.SpellCasts) != 1 || spellValue.SpellCasts[0].Caster != "Mira Thorn" {
t.Fatalf("spell output = %#v, want one registry-grounded-context spell", spellValue)
}
assertSpellEvidence(t, spellValue.SpellCasts[0].SourceRefs)
@@ -174,25 +176,23 @@ func (client *groundedDNDLLMClient) CompleteStructured(ctx context.Context, requ
case npcs.PromptID:
payload = map[string]any{"npcs": []any{
map[string]any{
"name": "Mira Thorn", "aliases": []string{"The Greencloak"}, "description": "A guarded ranger.",
"relationships": []any{}, "source_refs": []any{map[string]int{"start_unit_id": 1, "end_unit_id": 1}},
"name": "Mira Thorn", "source_refs": []any{map[string]int{"start_unit_id": 1, "end_unit_id": 1}},
},
map[string]any{
"name": "Hooded Guard", "aliases": []string{}, "description": "A sentry.",
"relationships": []any{}, "source_refs": []any{map[string]int{"start_unit_id": 3, "end_unit_id": 3}},
"name": "Hooded Guard", "source_refs": []any{map[string]int{"start_unit_id": 3, "end_unit_id": 3}},
},
}}
case spells.PromptID:
payload = map[string]any{"spell_casts": []any{map[string]any{
"caster": "The Greencloak", "spell": "Cure Wounds", "effect": "Restores an ally.",
"narrative_description": "The Greencloak restores an ally.",
"caster": "Mira Thorn", "spell": "Cure Wounds", "effect": "Restores an ally.",
"narrative_description": "Mira Thorn restores an ally.",
"source_refs": []any{map[string]int{"start_unit_id": 1, "end_unit_id": 1}},
}}}
case combatextract.PromptID:
payload = map[string]any{"combat_turns": []any{map[string]any{
"actor": "The Greencloak", "turn_kind": "turn", "round": 1,
"actor": "Mira Thorn", "turn_kind": "turn", "round": 1,
"actions": []any{map[string]any{"category": "attack", "declaration": "watches", "targets": []string{"Hooded Guard"}, "resolution": "observed"}},
"summary": "The Greencloak watches the gate.",
"summary": "Mira Thorn watches the gate.",
"source_refs": []any{map[string]int{"start_unit_id": 1, "end_unit_id": 1}},
}}}
default: