Adopt registry-backed item occurrences

This commit is contained in:
2026-08-05 19:55:34 +00:00
parent f91237e9c0
commit 3dfefd0e14
46 changed files with 996 additions and 1034 deletions

View File

@@ -25,6 +25,7 @@ import (
combat "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/extract/combatturns"
enemyevents "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/extract/enemyevents"
itemevents "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/extract/itemevents"
itemregistry "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/extract/itemregistry"
locationoccurrences "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/extract/locationoccurrences"
locations "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/extract/locationregistry"
npcoccurrences "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/extract/npcoccurrences"
@@ -32,6 +33,7 @@ import (
scenedescriptions "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/extract/scenedescriptions"
"gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/extract/spells"
enemyeventnormalize "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/normalize/enemyevents"
itemregistrynormalize "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/normalize/itemregistry"
locationnormalize "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/normalize/locationregistry"
npcnormalize "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/normalize/npcregistry"
)
@@ -253,8 +255,12 @@ func (client *enemyEventLLMClient) CompleteStructured(ctx context.Context, reque
content = []byte(`{"duplicate_groups":[]}`)
case spells.PromptID:
content = []byte(`{"spell_casts":[]}`)
case itemregistry.PromptID:
content = []byte(`{"items":[]}`)
case itemregistrynormalize.PromptID:
content = []byte(`{"duplicate_groups":[]}`)
case itemevents.PromptID:
content = []byte(`{"events":[]}`)
content = []byte(`{"occurrences":[]}`)
case combat.PromptID:
content = []byte(`{"combat_turns":[{"actor":"Kesh","turn_kind":"turn","source_refs":[{"start_unit_id":8,"end_unit_id":8}]}]}`)
case npcoccurrences.PromptID:

View File

@@ -58,7 +58,7 @@ func TestMaintainedExamplesLoadResolveAndList(t *testing.T) {
t.Fatalf("materialize maintained example references for %q: %v", pipelineID, err)
}
if example.name == "complete" {
if got := exampleStepLaneIDs(materialized); strings.Join(got, "|") != "describe-session:item-events,locations,npc_registry,scene-descriptions|extract-events:combat-turns,location-occurrences,npc-occurrences,spells|track-enemies:enemy-events" {
if got := exampleStepLaneIDs(materialized); strings.Join(got, "|") != "describe-session:item-registry,locations,npc_registry,scene-descriptions|extract-events:combat-turns,item-events,location-occurrences,npc-occurrences,spells|track-enemies:enemy-events" {
t.Fatalf("complete example steps and lanes = %v, want the documented D&D extractor composition", got)
}
locationLane := referenceContractLane(t, materialized, "locations")

View File

@@ -34,10 +34,12 @@ import (
combatextract "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/extract/combatturns"
enemyeventextract "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/extract/enemyevents"
itemeventextract "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/extract/itemevents"
itemregistryextract "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/extract/itemregistry"
"gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/extract/spells"
combatnormalize "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/normalize/combatturns"
enemyeventnormalize "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/normalize/enemyevents"
itemeventnormalize "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/normalize/itemevents"
itemregistrynormalize "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/normalize/itemregistry"
spellnormalize "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/normalize/spells"
"gitea.maximumdirect.net/eric/notarius/internal/modules/generic/normalize/noop"
"gitea.maximumdirect.net/eric/promptkit"
@@ -76,12 +78,12 @@ func TestProductionCatalogCoversMaintainedConfigurations(t *testing.T) {
"generic/valid_json",
"generic/valid_json_schema",
})
assertProductionContains(t, "artifact codec kinds", registries.ArtifactCodecs.RegisteredKinds(), []contracts.ArtifactKind{dnd.SpellListKind, dnd.NPCRegistryKind, dnd.CombatTurnListKind, dnd.ItemEventListKind, dnd.EnemyEventListKind})
assertProductionContains(t, "merger variants", registries.Mergers.RegisteredArtifactKinds(pipeline.DefaultMergeModule), []contracts.ArtifactKind{dnd.SpellListKind, dnd.NPCRegistryKind, dnd.CombatTurnListKind, dnd.ItemEventListKind, dnd.EnemyEventListKind})
assertProductionContains(t, "normalizer variants", registries.Normalizers.RegisteredArtifactKinds(pipeline.DefaultNormalizeModule), []contracts.ArtifactKind{dnd.SpellListKind, dnd.NPCRegistryKind, dnd.CombatTurnListKind, dnd.ItemEventListKind, dnd.EnemyEventListKind})
assertProductionContains(t, "artifact codec kinds", registries.ArtifactCodecs.RegisteredKinds(), []contracts.ArtifactKind{dnd.SpellListKind, dnd.NPCRegistryKind, dnd.CombatTurnListKind, dnd.ItemOccurrenceListKind, dnd.EnemyEventListKind})
assertProductionContains(t, "merger variants", registries.Mergers.RegisteredArtifactKinds(pipeline.DefaultMergeModule), []contracts.ArtifactKind{dnd.SpellListKind, dnd.NPCRegistryKind, dnd.CombatTurnListKind, dnd.ItemOccurrenceListKind, dnd.EnemyEventListKind})
assertProductionContains(t, "normalizer variants", registries.Normalizers.RegisteredArtifactKinds(pipeline.DefaultNormalizeModule), []contracts.ArtifactKind{dnd.SpellListKind, dnd.NPCRegistryKind, dnd.CombatTurnListKind, dnd.ItemOccurrenceListKind, dnd.EnemyEventListKind})
assertProductionContains(t, "spell normalizer variants", registries.Normalizers.RegisteredArtifactKinds(spellnormalize.Key), []contracts.ArtifactKind{dnd.SpellListKind})
assertProductionContains(t, "combat normalizer variants", registries.Normalizers.RegisteredArtifactKinds(combatnormalize.Key), []contracts.ArtifactKind{dnd.CombatTurnListKind})
assertProductionContains(t, "item event normalizer variants", registries.Normalizers.RegisteredArtifactKinds(itemeventnormalize.Key), []contracts.ArtifactKind{dnd.ItemEventListKind})
assertProductionContains(t, "item event normalizer variants", registries.Normalizers.RegisteredArtifactKinds(itemeventnormalize.Key), []contracts.ArtifactKind{dnd.ItemOccurrenceListKind})
assertProductionContains(t, "enemy event normalizer variants", registries.Normalizers.RegisteredArtifactKinds(enemyeventnormalize.Key), []contracts.ArtifactKind{dnd.EnemyEventListKind})
wantChain := []pipeline.ModuleBinding{
@@ -122,6 +124,7 @@ func TestProductionCatalogCoversMaintainedConfigurations(t *testing.T) {
itemEventExtractChain := []pipeline.ModuleBinding{
pipeline.Binding("generic/valid_json"),
pipeline.Binding("extract/dnd/item-events/shape"),
pipeline.Binding("extract/dnd/item-events/registry"),
pipeline.Binding("extract/dnd/item-events/source_refs"),
pipeline.Binding("generic/valid_json_schema"),
pipeline.Binding("extract/dnd/item-events/source_relatedness"),
@@ -129,6 +132,7 @@ func TestProductionCatalogCoversMaintainedConfigurations(t *testing.T) {
itemEventNormalizeChain := []pipeline.ModuleBinding{
pipeline.Binding("generic/valid_json"),
pipeline.Binding("extract/dnd/item-events/shape"),
pipeline.Binding("extract/dnd/item-events/registry"),
pipeline.Binding("normalize/dnd/item-events/invariants"),
pipeline.Binding("extract/dnd/item-events/source_refs"),
pipeline.Binding("generic/valid_json_schema"),
@@ -196,8 +200,8 @@ func TestProductionCatalogCoversMaintainedConfigurations(t *testing.T) {
if !ok || combatCodecSpec.Kind != dnd.CombatTurnListKind || combatCodecSpec.Schema.ID != combatcodec.SchemaID {
t.Fatalf("combat codec spec = %#v, ok=%t, want typed D&D combat codec", combatCodecSpec, ok)
}
itemEventCodecSpec, ok := catalog.ArtifactCodecs.Spec(dnd.ItemEventListKind)
if !ok || itemEventCodecSpec.Kind != dnd.ItemEventListKind || itemEventCodecSpec.Schema.ID != itemeventcodec.SchemaID {
itemEventCodecSpec, ok := catalog.ArtifactCodecs.Spec(dnd.ItemOccurrenceListKind)
if !ok || itemEventCodecSpec.Kind != dnd.ItemOccurrenceListKind || itemEventCodecSpec.Schema.ID != itemeventcodec.SchemaID {
t.Fatalf("item event codec spec = %#v, ok=%t, want typed D&D item-event codec", itemEventCodecSpec, ok)
}
enemyEventCodecSpec, ok := catalog.ArtifactCodecs.Spec(dnd.EnemyEventListKind)
@@ -916,11 +920,23 @@ pipelines:
module: json
options:
include_chunk_map: true
artifacts:
spells:
extract: dnd/spells
item-events:
extract: dnd/item-events
steps:
- id: identify-items
artifacts:
item-registry:
extract: dnd/item-registry
normalize: dnd/item-registry
- id: extract-occurrences
references:
item_registry:
artifact:
step: identify-items
lane: item-registry
artifacts:
spells:
extract: dnd/spells
item-events:
extract: dnd/item-events
`, outputRoot, filepath.Join(filepath.Dir(outputRoot), "debug"), chunkModule)
}
@@ -998,7 +1014,11 @@ func (client *productionFakeLLMClient) CompleteStructured(ctx context.Context, r
content = []byte(`{"spell_casts":[{"caster":"Aria","spell":"Cure Wounds","source_refs":[{"start_unit_id":1,"end_unit_id":1}]}]}`)
}
case itemeventextract.PromptID:
content = []byte(`{"events":[{"name":"Cure Wounds","kind":"acquired","to":"party","source_refs":[{"start_segment":1,"end_segment":1}]}]}`)
content = []byte(`{"occurrences":[]}`)
case itemregistryextract.PromptID:
content = []byte(`{"items":[]}`)
case itemregistrynormalize.PromptID:
content = []byte(`{"duplicate_groups":[]}`)
default:
return contracts.StructuredCompletionResponse{}, fmt.Errorf("unexpected prompt %q", req.PromptID)
}