Move NPC registry to canonical namespace

This commit is contained in:
2026-08-05 18:38:22 +00:00
parent 9653e06297
commit 3f4a1f2647
94 changed files with 320 additions and 320 deletions

View File

@@ -14,7 +14,7 @@ inputs:
- name: glossary
required: false
content_type: text/plain
- name: npcs
- name: npc_registry
required: false
content_type: application/json
messages:
@@ -33,7 +33,7 @@ messages:
- role: user
content_file: ./sharedassets/common-dnd-extraction-evidence.md
- role: user
content_file: ./sharedassets/common-dnd-npcs.md
content_file: ./sharedassets/common-dnd-npc-registry.md
- role: user
content_file: ./instructions.md
cache_control:

View File

@@ -14,7 +14,7 @@ inputs:
- name: glossary
required: false
content_type: text/plain
- name: npcs
- name: npc_registry
required: true
content_type: application/json
- name: combat_turns
@@ -39,7 +39,7 @@ messages:
- role: user
content_file: ./sharedassets/common-dnd-extraction-evidence.md
- role: user
content_file: ./sharedassets/common-dnd-npcs.md
content_file: ./sharedassets/common-dnd-npc-registry.md
- role: user
content_file: ./combat-grounding.md
- role: user

View File

@@ -14,7 +14,7 @@ inputs:
- name: glossary
required: false
content_type: text/plain
- name: npcs
- name: npc_registry
required: true
content_type: application/json
messages:
@@ -33,7 +33,7 @@ messages:
- role: user
content_file: ./sharedassets/common-dnd-extraction-evidence.md
- role: user
content_file: ./sharedassets/common-dnd-npcs.md
content_file: ./sharedassets/common-dnd-npc-registry.md
- role: user
content_file: ./instructions.md
cache_control:

View File

@@ -1,4 +1,4 @@
id: dnd.npcs
id: dnd.npc_registry
version: "v1"
default_profile: dnd-extraction
inputs:
@@ -36,5 +36,5 @@ messages:
output:
format: json
validation_mode: json_schema
schema_path: dnd_npcs_llm.v1.json
schema_path: dnd_npc_registry_llm.v1.json
repair_attempts: 0

View File

@@ -1,6 +1,6 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "notarius.dnd.npcs.llm",
"$id": "notarius.dnd.npc_registry.llm",
"type": "object",
"additionalProperties": false,
"required": ["npcs"],

View File

@@ -1,4 +1,4 @@
id: dnd.npcs.normalize
id: dnd.npc_registry.normalize
version: "v1"
default_profile: dnd-extraction
inputs:

View File

@@ -7,4 +7,4 @@ participants, effects, or source references from the registry. Registry source
references describe registry provenance and may belong to another session; they
are never evidence for the current transcript.
{{ input "npcs" }}
{{ input "npc_registry" }}

View File

@@ -17,7 +17,7 @@ inputs:
- name: glossary
required: false
content_type: text/plain
- name: npcs
- name: npc_registry
required: false
content_type: application/json
messages:
@@ -36,7 +36,7 @@ messages:
- role: user
content_file: ./sharedassets/common-dnd-extraction-evidence.md
- role: user
content_file: ./sharedassets/common-dnd-npcs.md
content_file: ./sharedassets/common-dnd-npc-registry.md
- role: user
content_file: ./spell-catalog.md
- role: user

View File

@@ -298,7 +298,7 @@ output:
enabled: true
window_units: 3
lanes:
- npcs
- npc_registry
- spells
~~~
@@ -332,15 +332,15 @@ step:
steps:
- id: describe-session
artifacts:
npcs:
extract: dnd/npcs
normalize: dnd/npcs
npc_registry:
extract: dnd/npc-registry
normalize: dnd/npc-registry
- id: extract-events
references:
npcs:
npc_registry:
artifact:
step: describe-session
lane: npcs
lane: npc_registry
artifacts:
spells:
extract: dnd/spells
@@ -371,7 +371,7 @@ selected target declares them:
| **glossary** | Optional text campaign glossary. |
| **spell_catalog** | Optional JSON spell-catalog overlay for spell extraction and normalization. See [spell-catalog overlays](integrations/dnd-spell-catalog-overlays.md). |
| **locations** | Required normalized location registry for location-occurrence extraction and normalization. |
| **npcs** | Normalized NPC registry. Optional for spells and combat turns; required for NPC interactions and enemy-event extraction and normalization. |
| **npc_registry** | Normalized NPC registry. Optional for spells and combat turns; required for NPC interactions and enemy-event extraction and normalization. |
| **scene_descriptions** | Required normalized scene-description artifact for combat-turn and enemy-event extraction. |
| **combat_turns** | Required normalized combat-turn artifact for enemy-event extraction. |
| **npc_interactions** | Required normalized NPC-interaction artifact for enemy-event extraction. |
@@ -383,18 +383,18 @@ binding contracts. Durable semantics and wire shapes remain in their
| Slot | Accepted artifact kind | Media type | Maximum size | Required stage |
| --- | --- | --- | --- | --- |
| `npcs` | `dnd/npc-registry` | `application/json` | 1,048,576 bytes | extract and normalize |
| `npc_registry` | `dnd/npc-registry` | `application/json` | 1,048,576 bytes | extract and normalize |
| `scene_descriptions` | `dnd/scene-description-list` | `application/json` | 1,048,576 bytes | extract only |
| `combat_turns` | `dnd/combat-turn-list` | `application/json` | 1,048,576 bytes | extract only |
| `npc_interactions` | `dnd/npc-interaction-list` | `application/json` | 1,048,576 bytes | extract only |
| `locations` | `dnd/location-list` | `application/json` | 1,048,576 bytes | location-occurrence extract and normalize |
Scene descriptions accept **party**, **players**, and **glossary**, but not
**roster**. NPC interactions require **npcs** for both extraction and
**roster**. NPC interactions require **npc_registry** for both extraction and
normalization. Combat turns require **scene_descriptions** for extraction; the
normalized combat-turn module may use optional **npcs**. Location occurrences
normalized combat-turn module may use optional **npc_registry**. Location occurrences
require **locations** for extraction and normalization. Enemy-event extraction
requires all four of its JSON artifact slots; its normalizer requires **npcs**.
requires all four of its JSON artifact slots; its normalizer requires **npc_registry**.
The [complete example](../examples/dnd-complete.config.yml) shows the ordered
generated bindings.
@@ -404,9 +404,9 @@ generated bindings.
| --- | --- |
| Input | **seriatim** |
| Chunk | **generic**, **dnd/scenes** |
| Extract | **dnd/spells**, **dnd/npcs**, **dnd/combat-turns**, **dnd/item-events**, **dnd/npc-interactions**, **dnd/scene-descriptions**, **dnd/enemy-events**, **dnd/locations**, **dnd/location-occurrences** |
| Extract | **dnd/spells**, **dnd/npc-registry**, **dnd/combat-turns**, **dnd/item-events**, **dnd/npc-interactions**, **dnd/scene-descriptions**, **dnd/enemy-events**, **dnd/locations**, **dnd/location-occurrences** |
| Merge | **appendorder** |
| Normalize | **noop**, **dnd/spells**, **dnd/npcs**, **dnd/combat-turns**, **dnd/item-events**, **dnd/npc-interactions**, **dnd/scene-descriptions**, **dnd/enemy-events**, **dnd/locations**, **dnd/location-occurrences** |
| Normalize | **noop**, **dnd/spells**, **dnd/npc-registry**, **dnd/combat-turns**, **dnd/item-events**, **dnd/npc-interactions**, **dnd/scene-descriptions**, **dnd/enemy-events**, **dnd/locations**, **dnd/location-occurrences** |
| Output | **json** |
`dnd/locations` extraction and normalization are `llm_backed`; location
@@ -417,7 +417,7 @@ step and the occurrence lane in the next.
The D&D artifact contracts define each emitted schema:
[spells](integrations/dnd-spell-artifacts.md),
[NPCs](integrations/dnd-npc-artifacts.md),
[NPC registry](integrations/dnd-npc-registry-artifacts.md),
[NPC interactions](integrations/dnd-npc-interaction-artifacts.md),
[combat turns](integrations/dnd-combat-turn-artifacts.md),
[item events](integrations/dnd-item-event-artifacts.md),
@@ -434,7 +434,7 @@ Available validator keys are:
| --- | --- |
| Generic | **generic/always_accept**, **generic/always_reject**, **generic/valid_json**, **generic/valid_json_schema** |
| Spells | **extract/dnd/spells/shape**, **extract/dnd/spells/catalog**, **extract/dnd/spells/source_refs**, **extract/dnd/spells/source_relatedness** |
| NPCs | **extract/dnd/npcs/shape**, **extract/dnd/npcs/source_refs**, **extract/dnd/npcs/source_relatedness**, **normalize/dnd/npcs/identity** |
| NPC registry | **extract/dnd/npc-registry/shape**, **extract/dnd/npc-registry/source_refs**, **extract/dnd/npc-registry/source_relatedness**, **normalize/dnd/npc-registry/identity** |
| Combat turns | **extract/dnd/combat-turns/shape**, **extract/dnd/combat-turns/source_refs**, **extract/dnd/combat-turns/source_relatedness**, **normalize/dnd/combat-turns/invariants** |
| Item events | **extract/dnd/item-events/shape**, **extract/dnd/item-events/source_refs**, **extract/dnd/item-events/source_relatedness**, **normalize/dnd/item-events/invariants** |
| NPC interactions | **extract/dnd/npc-interactions/shape**, **extract/dnd/npc-interactions/registry**, **extract/dnd/npc-interactions/source_refs**, **extract/dnd/npc-interactions/source_relatedness**, **normalize/dnd/npc-interactions/invariants** |
@@ -450,7 +450,7 @@ same at both stages.
| Lane | Extract | Normalize |
| --- | --- | --- |
| Spells | generic/valid_json, extract/dnd/spells/shape, extract/dnd/spells/catalog, extract/dnd/spells/source_refs, generic/valid_json_schema, extract/dnd/spells/source_relatedness | Same as extract |
| NPCs | generic/valid_json, extract/dnd/npcs/shape, extract/dnd/npcs/source_refs, generic/valid_json_schema, extract/dnd/npcs/source_relatedness | generic/valid_json, extract/dnd/npcs/shape, normalize/dnd/npcs/identity, extract/dnd/npcs/source_refs, generic/valid_json_schema, extract/dnd/npcs/source_relatedness |
| NPC registry | generic/valid_json, extract/dnd/npc-registry/shape, extract/dnd/npc-registry/source_refs, generic/valid_json_schema, extract/dnd/npc-registry/source_relatedness | generic/valid_json, extract/dnd/npc-registry/shape, normalize/dnd/npc-registry/identity, extract/dnd/npc-registry/source_refs, generic/valid_json_schema, extract/dnd/npc-registry/source_relatedness |
| Combat turns | generic/valid_json, extract/dnd/combat-turns/shape, extract/dnd/combat-turns/source_refs, generic/valid_json_schema, extract/dnd/combat-turns/source_relatedness | generic/valid_json, extract/dnd/combat-turns/shape, normalize/dnd/combat-turns/invariants, extract/dnd/combat-turns/source_refs, generic/valid_json_schema, extract/dnd/combat-turns/source_relatedness |
| Item events | generic/valid_json, extract/dnd/item-events/shape, extract/dnd/item-events/source_refs, generic/valid_json_schema, extract/dnd/item-events/source_relatedness | generic/valid_json, extract/dnd/item-events/shape, normalize/dnd/item-events/invariants, extract/dnd/item-events/source_refs, generic/valid_json_schema, extract/dnd/item-events/source_relatedness |
| NPC interactions | generic/valid_json, extract/dnd/npc-interactions/shape, extract/dnd/npc-interactions/registry, extract/dnd/npc-interactions/source_refs, generic/valid_json_schema, extract/dnd/npc-interactions/source_relatedness | generic/valid_json, extract/dnd/npc-interactions/shape, extract/dnd/npc-interactions/registry, normalize/dnd/npc-interactions/invariants, extract/dnd/npc-interactions/source_refs, generic/valid_json_schema, extract/dnd/npc-interactions/source_relatedness |

View File

@@ -55,7 +55,7 @@ record controls eligibility only: its title, summary, and reference do not
become turn evidence. No exact matching scene also produces an empty list and
the `scene_classification_unavailable` warning.
An optional normalized [NPC artifact](dnd-npc-artifacts.md) can ground an
An optional normalized [NPC registry artifact](dnd-npc-registry-artifacts.md) can ground an
actor name. Its registry references are provenance, never combat evidence.
Normalization trims and, where possible, canonicalizes actor names; orders and
deduplicates exact source references; orders valid-evidence turns by source

View File

@@ -65,7 +65,7 @@ for uncertain classification.
## Identity, evidence, and order
The required normalized [NPC artifact](dnd-npc-artifacts.md) resolves `name`.
The required normalized [NPC registry artifact](dnd-npc-registry-artifacts.md) resolves `name`.
Registry references are provenance only and never replace an interaction's own
evidence. Normalization canonicalizes recognized registry names, orders and
deduplicates exact source references, then orders interactions by valid source

View File

@@ -1,6 +1,6 @@
# D&D NPC Registry Artifact
This contract defines the durable NPC registry produced by `dnd/npcs`. It is a
This contract defines the durable NPC registry produced by `dnd/npc-registry`. It is a
minimal, source-grounded identity registry for other D&D artifacts, not a
character sheet or a relationship summary.

View File

@@ -61,7 +61,7 @@ only when it has the same canonical spell, the same case- and
whitespace-insensitive caster identity, and the same complete valid reference
sequence. Remaining entries retain their merged order.
The optional normalized [NPC artifact](dnd-npc-artifacts.md) can ground a
The optional normalized [NPC registry artifact](dnd-npc-registry-artifacts.md) can ground a
caster name. Its own references remain registry provenance and are never copied
into `source_refs`.

View File

@@ -36,7 +36,7 @@ evidence publishes `contexts: []`.
"source_id": "session-alpha",
"source_digest": "sha256:0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef",
"window_units": 1,
"selected_lanes": ["npcs", "spells"],
"selected_lanes": ["npc_registry", "spells"],
"contexts": [
{
"context_ref": {

View File

@@ -71,7 +71,7 @@ output encoding fail.
Each `lanes/<safe-lane-id>.json` file is the codec-owned normalized JSON for
that lane. Consumers should use the index descriptors schema identity rather
than infer a lane schema from its name. The current D&D payload contracts are
[spells](dnd-spell-artifacts.md), [NPCs](dnd-npc-artifacts.md),
[spells](dnd-spell-artifacts.md), [NPC registry](dnd-npc-registry-artifacts.md),
[NPC interactions](dnd-npc-interaction-artifacts.md),
[combat turns](dnd-combat-turn-artifacts.md),
[item events](dnd-item-event-artifacts.md),

View File

@@ -13,7 +13,7 @@ does not repeat their JSON shapes or schemas.
| Lane | Durable contract |
| --- | --- |
| Spells | [spell artifacts](../integrations/dnd-spell-artifacts.md) |
| NPCs | [NPC artifacts](../integrations/dnd-npc-artifacts.md) |
| NPC registry | [NPC registry artifacts](../integrations/dnd-npc-registry-artifacts.md) |
| Combat turns | [combat-turn artifacts](../integrations/dnd-combat-turn-artifacts.md) |
| Item events | [item-event artifacts](../integrations/dnd-item-event-artifacts.md) |
| NPC interactions | [NPC-interaction artifacts](../integrations/dnd-npc-interaction-artifacts.md) |

View File

@@ -38,7 +38,7 @@ pipelines:
- item-events
- locations
- location-occurrences
- npcs
- npc_registry
- spells
- combat-turns
- npc-interactions
@@ -53,13 +53,13 @@ pipelines:
retries: 2
merge: appendorder
normalize: dnd/item-events
npcs:
npc_registry:
extract:
module: dnd/npcs
module: dnd/npc-registry
retries: 2
merge: appendorder
normalize:
module: dnd/npcs
module: dnd/npc-registry
retries: 2
locations:
extract:
@@ -83,10 +83,10 @@ pipelines:
artifact:
step: describe-session
lane: locations
npcs:
npc_registry:
artifact:
step: describe-session
lane: npcs
lane: npc_registry
scene_descriptions:
artifact:
step: describe-session
@@ -124,10 +124,10 @@ pipelines:
normalize: dnd/location-occurrences
- id: track-enemies
references:
npcs:
npc_registry:
artifact:
step: describe-session
lane: npcs
lane: npc_registry
scene_descriptions:
artifact:
step: describe-session

View File

@@ -48,7 +48,7 @@ func TestProductionCombatConfigurationResolvesTypedLane(t *testing.T) {
if !ok || codecSpec.Schema.ID != "notarius.dnd.combat_turns" || codecSpec.Schema.Version != "v1" {
t.Fatalf("combat codec spec = %#v, want compatible durable schema", codecSpec)
}
if !hasReferenceSlot(extractSpec.ReferenceSlots, "npcs") || !hasReferenceSlot(extractSpec.ReferenceSlots, "scene_descriptions") || !hasReferenceSlot(normalizeSpec.ReferenceSlots, "npcs") {
if !hasReferenceSlot(extractSpec.ReferenceSlots, "npc_registry") || !hasReferenceSlot(extractSpec.ReferenceSlots, "scene_descriptions") || !hasReferenceSlot(normalizeSpec.ReferenceSlots, "npc_registry") {
t.Fatalf("combat reference slots = %#v / %#v, want extraction scene and NPC slots plus normalization NPC slot", extractSpec.ReferenceSlots, normalizeSpec.ReferenceSlots)
}
sceneSlot := referenceSlot(extractSpec.ReferenceSlots, "scene_descriptions")
@@ -85,15 +85,15 @@ func TestProductionCombatConfigurationResolvesTypedLane(t *testing.T) {
PipelineID: "dnd-combat",
Catalog: catalog,
ReferenceOverrides: []pipeline.ReferenceBinding{
{Stage: pipeline.StageExtract, LaneID: "combat", SlotName: "npcs", Source: "npc-run/lanes/npcs.json", BindingSource: contracts.ReferenceBindingSourceCLI},
{Stage: pipeline.StageNormalize, LaneID: "combat", SlotName: "npcs", Source: "npc-run/lanes/npcs.json", BindingSource: contracts.ReferenceBindingSourceCLI},
{Stage: pipeline.StageExtract, LaneID: "combat", SlotName: "npc_registry", Source: "npc-run/lanes/npc_registry.json", BindingSource: contracts.ReferenceBindingSourceCLI},
{Stage: pipeline.StageNormalize, LaneID: "combat", SlotName: "npc_registry", Source: "npc-run/lanes/npc_registry.json", BindingSource: contracts.ReferenceBindingSourceCLI},
},
})
if err != nil {
t.Fatalf("Resolve(bound references) error = %v, want nil", err)
}
boundLane := bound.ResolvedPipeline.Steps[0].ArtifactLanes[0]
if len(boundLane.ExtractReferences.Bindings) != 2 || len(boundLane.NormalizeReferences.Bindings) != 1 || !hasReferenceBinding(boundLane.ExtractReferences.Bindings, "npcs") || !hasReferenceBinding(boundLane.ExtractReferences.Bindings, "scene_descriptions") || !hasReferenceBinding(boundLane.NormalizeReferences.Bindings, "npcs") {
if len(boundLane.ExtractReferences.Bindings) != 2 || len(boundLane.NormalizeReferences.Bindings) != 1 || !hasReferenceBinding(boundLane.ExtractReferences.Bindings, "npc_registry") || !hasReferenceBinding(boundLane.ExtractReferences.Bindings, "scene_descriptions") || !hasReferenceBinding(boundLane.NormalizeReferences.Bindings, "npc_registry") {
t.Fatalf("bound combat references = %#v / %#v, want extraction scene and NPC bindings plus normalization NPC binding", boundLane.ExtractReferences, boundLane.NormalizeReferences)
}
}

View File

@@ -28,12 +28,12 @@ import (
locationoccurrences "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/extract/locationoccurrences"
locations "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/extract/locations"
npcinteractions "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/extract/npcinteractions"
npcs "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/extract/npcs"
npcregistry "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/extract/npcregistry"
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"
locationnormalize "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/normalize/locations"
npcnormalize "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/normalize/npcs"
npcnormalize "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/normalize/npcregistry"
)
func TestProductionEnemyEventConfigurationResolvesGeneratedHandoffs(t *testing.T) {
@@ -55,7 +55,7 @@ func TestProductionEnemyEventConfigurationResolvesGeneratedHandoffs(t *testing.T
t.Fatalf("enemy event lane = %#v, want typed production composition", lane)
}
for slot, want := range map[string]struct{ step, lane string }{
"npcs": {step: "describe-session", lane: "npcs"},
"npc_registry": {step: "describe-session", lane: "npc_registry"},
"scene_descriptions": {step: "describe-session", lane: "scene-descriptions"},
"combat_turns": {step: "extract-events", lane: "combat-turns"},
"npc_interactions": {step: "extract-events", lane: "npc-interactions"},
@@ -65,7 +65,7 @@ func TestProductionEnemyEventConfigurationResolvesGeneratedHandoffs(t *testing.T
t.Fatalf("enemy event %s reference = %#v, want generated %s/%s artifact", slot, binding, want.step, want.lane)
}
}
if binding, found := generatedReferenceBinding(lane.NormalizeReferences.Bindings, "npcs"); !found || binding.Artifact.Step != "describe-session" || binding.Artifact.Lane != "npcs" {
if binding, found := generatedReferenceBinding(lane.NormalizeReferences.Bindings, "npc_registry"); !found || binding.Artifact.Step != "describe-session" || binding.Artifact.Lane != "npc_registry" {
t.Fatalf("enemy event normalizer NPC reference = %#v, want generated NPC artifact", binding)
}
@@ -78,17 +78,17 @@ func TestProductionEnemyEventConfigurationResolvesGeneratedHandoffs(t *testing.T
if !ok || !reflect.DeepEqual(normalizeSpec.Requires, []string{"merged"}) || !reflect.DeepEqual(normalizeSpec.Provides, []string{"normalized"}) {
t.Fatalf("enemy event normalizer spec = %#v, want merged/normalized capabilities", normalizeSpec)
}
for _, slot := range []string{"npcs", "scene_descriptions", "combat_turns", "npc_interactions"} {
for _, slot := range []string{"npc_registry", "scene_descriptions", "combat_turns", "npc_interactions"} {
if !hasReferenceSlot(extractSpec.ReferenceSlots, slot) {
t.Fatalf("enemy event extractor slots = %#v, want %q", extractSpec.ReferenceSlots, slot)
}
}
if !hasReferenceSlot(normalizeSpec.ReferenceSlots, "npcs") {
if !hasReferenceSlot(normalizeSpec.ReferenceSlots, "npc_registry") {
t.Fatalf("enemy event normalizer slots = %#v, want NPC registry", normalizeSpec.ReferenceSlots)
}
profile := cfg.Pipelines["dnd-session"]
profile.Steps[2].References["npcs"] = pipeline.GeneratedReference("track-enemies", "enemy-events")
profile.Steps[2].References["npc_registry"] = pipeline.GeneratedReference("track-enemies", "enemy-events")
cfg.Pipelines["dnd-session"] = profile
if _, err := cfg.Resolve(resolveInputForMaintainedExample(components, "dnd-session")); err == nil || !strings.Contains(err.Error(), "earlier step") {
t.Fatalf("Resolve() error = %v, want future generated-reference rejection", err)
@@ -171,7 +171,7 @@ func TestMaintainedCompleteExampleProducesEnemyEventsThroughGeneratedHandoffs(t
t.Fatalf("enemy event session = %q, want shared session", request.SessionID)
}
for slot, required := range map[string]string{
"npcs": "Kesh",
"npc_registry": "Kesh",
"combat_turns": "Kesh",
"npc_interactions": "Kesh",
} {
@@ -229,7 +229,7 @@ func (client *enemyEventLLMClient) CompleteStructured(ctx context.Context, reque
switch request.PromptID {
case scenes.PromptID:
content = []byte(`{"scenes":[{"start_unit_id":1,"end_unit_id":6},{"start_unit_id":7,"end_unit_id":11}]}`)
case npcs.PromptID:
case npcregistry.PromptID:
if combatScene {
content = []byte(`{"npcs":[{"name":"Kesh","source_refs":[{"start_unit_id":7,"end_unit_id":7}]}]}`)
} else {

View File

@@ -10,14 +10,14 @@ import (
"gitea.maximumdirect.net/eric/notarius/internal/modules/dnd"
interactioncodec "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/codec/npcinteractions"
interactionextract "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/extract/npcinteractions"
npcextract "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/extract/npcs"
npcextract "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/extract/npcregistry"
interactionnormalize "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/normalize/npcinteractions"
npcnormalize "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/normalize/npcs"
npcnormalize "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/normalize/npcregistry"
)
func TestProductionNPCInteractionPipelineResolvesAndPrepares(t *testing.T) {
components := productionTestComponents(t)
resolved, err := pipeline.ResolvePipeline(npcInteractionProfile(pipeline.GeneratedReference("npcs", "npcs")), pipeline.ResolveOptions{}, catalogFromRegistries(components.registries))
resolved, err := pipeline.ResolvePipeline(npcInteractionProfile(pipeline.GeneratedReference("npc-registry", "npc_registry")), pipeline.ResolveOptions{}, catalogFromRegistries(components.registries))
if err != nil {
t.Fatalf("ResolvePipeline() error = %v", err)
}
@@ -29,7 +29,7 @@ func TestProductionNPCInteractionPipelineResolvesAndPrepares(t *testing.T) {
t.Fatalf("interaction lane = %#v", lane)
}
for _, bindings := range [][]pipeline.ReferenceBinding{lane.ExtractReferences.Bindings, lane.NormalizeReferences.Bindings} {
if len(bindings) != 1 || bindings[0].SlotName != "npcs" || bindings[0].Artifact == nil || bindings[0].Artifact.Step != "npcs" || bindings[0].Artifact.Lane != "npcs" {
if len(bindings) != 1 || bindings[0].SlotName != "npc_registry" || bindings[0].Artifact == nil || bindings[0].Artifact.Step != "npc-registry" || bindings[0].Artifact.Lane != "npc_registry" {
t.Fatalf("generated bindings = %#v", bindings)
}
}
@@ -47,14 +47,14 @@ func TestProductionNPCInteractionPipelineResolvesAndPrepares(t *testing.T) {
func TestProductionNPCInteractionReferencesRequireEarlierCompatibleProducer(t *testing.T) {
components := productionTestComponents(t)
catalog := catalogFromRegistries(components.registries)
laterProfile := npcInteractionProfile(pipeline.GeneratedReference("npcs", "npcs"))
laterProfile := npcInteractionProfile(pipeline.GeneratedReference("npc-registry", "npc_registry"))
laterProfile.Steps[0].ID = "seed"
laterProfile.Steps[0].Artifacts["seed"] = laterProfile.Steps[0].Artifacts["npcs"]
delete(laterProfile.Steps[0].Artifacts, "npcs")
laterProfile.Steps[0].Artifacts["seed"] = laterProfile.Steps[0].Artifacts["npc_registry"]
delete(laterProfile.Steps[0].Artifacts, "npc_registry")
laterProfile.Steps = append(laterProfile.Steps, pipeline.PipelineStepProfile{ID: "future", Artifacts: map[string]pipeline.ArtifactLaneProfile{
"npcs": {Extract: pipeline.Binding(npcextract.Key), Normalize: pipeline.Binding(npcnormalize.Key)},
"npc_registry": {Extract: pipeline.Binding(npcextract.Key), Normalize: pipeline.Binding(npcnormalize.Key)},
}})
laterProfile.Steps[1].References["npcs"] = pipeline.GeneratedReference("future", "npcs")
laterProfile.Steps[1].References["npc_registry"] = pipeline.GeneratedReference("future", "npc_registry")
tests := []struct {
name string
profile pipeline.PipelineProfile
@@ -63,9 +63,9 @@ func TestProductionNPCInteractionReferencesRequireEarlierCompatibleProducer(t *t
{name: "missing", profile: npcInteractionProfile(pipeline.ReferenceSource{}), want: "source must not be empty"},
{name: "same step", profile: npcInteractionProfile(pipeline.GeneratedReference("interactions", "interactions")), want: "earlier step"},
{name: "later step", profile: laterProfile, want: "earlier step"},
{name: "wrong artifact kind", profile: npcInteractionProfile(pipeline.GeneratedReference("npcs", "npcs")), want: "does not accept artifact kind"},
{name: "wrong artifact kind", profile: npcInteractionProfile(pipeline.GeneratedReference("npc-registry", "npc_registry")), want: "does not accept artifact kind"},
}
tests[3].profile.Steps[0].Artifacts["npcs"] = pipeline.ArtifactLaneProfile{Extract: pipeline.Binding("dnd/spells")}
tests[3].profile.Steps[0].Artifacts["npc_registry"] = pipeline.ArtifactLaneProfile{Extract: pipeline.Binding("dnd/spells")}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
_, err := pipeline.ResolvePipeline(test.profile, pipeline.ResolveOptions{}, catalog)
@@ -123,10 +123,10 @@ func npcInteractionProfile(reference pipeline.ReferenceSource) pipeline.Pipeline
Chunk: pipeline.ModuleBinding{Module: "generic", Options: map[string]any{"max_units": 1}},
Output: pipeline.Binding("json"),
Steps: []pipeline.PipelineStepProfile{
{ID: "npcs", Artifacts: map[string]pipeline.ArtifactLaneProfile{
"npcs": {Extract: pipeline.Binding(npcextract.Key), Normalize: pipeline.Binding(npcnormalize.Key)},
{ID: "npc-registry", Artifacts: map[string]pipeline.ArtifactLaneProfile{
"npc_registry": {Extract: pipeline.Binding(npcextract.Key), Normalize: pipeline.Binding(npcnormalize.Key)},
}},
{ID: "interactions", References: map[string]pipeline.ReferenceSource{"npcs": reference}, Artifacts: map[string]pipeline.ArtifactLaneProfile{
{ID: "interactions", References: map[string]pipeline.ReferenceSource{"npc_registry": reference}, Artifacts: map[string]pipeline.ArtifactLaneProfile{
"interactions": {Extract: pipeline.Binding(interactionextract.Key), Normalize: pipeline.Binding(interactionnormalize.Key)},
}},
},

View File

@@ -8,9 +8,9 @@ import (
"gitea.maximumdirect.net/eric/notarius/internal/core/config"
"gitea.maximumdirect.net/eric/notarius/internal/framework/pipeline"
"gitea.maximumdirect.net/eric/notarius/internal/modules/dnd"
npccodec "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/codec/npcs"
npcextract "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/extract/npcs"
npcnormalize "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/normalize/npcs"
npccodec "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/codec/npcregistry"
npcextract "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/extract/npcregistry"
npcnormalize "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/normalize/npcregistry"
)
func TestProductionNPCConfigurationResolvesTypedLane(t *testing.T) {
@@ -28,7 +28,7 @@ func TestProductionNPCConfigurationResolvesTypedLane(t *testing.T) {
t.Fatalf("artifact lanes = %#v, want one NPC lane", effective.ResolvedPipeline.Steps[0].ArtifactLanes)
}
lane := effective.ResolvedPipeline.Steps[0].ArtifactLanes[0]
if lane.ID != "npcs" || lane.ArtifactKind != dnd.NPCRegistryKind || lane.Extract.Module != npcextract.Key || lane.Extract.Retries != 2 || lane.Merge.Module != pipeline.DefaultMergeModule || lane.Normalize.Module != npcnormalize.Key {
if lane.ID != "npc_registry" || lane.ArtifactKind != dnd.NPCRegistryKind || lane.Extract.Module != npcextract.Key || lane.Extract.Retries != 2 || lane.Merge.Module != pipeline.DefaultMergeModule || lane.Normalize.Module != npcnormalize.Key {
t.Fatalf("resolved NPC lane = %#v, want typed production composition", lane)
}
if len(lane.ExtractReferences.Bindings) != 0 || len(lane.NormalizeReferences.Bindings) != 0 {
@@ -36,7 +36,7 @@ func TestProductionNPCConfigurationResolvesTypedLane(t *testing.T) {
}
extractSpec, ok := catalog.Extractors.Spec(npcextract.Key)
if !ok || !reflect.DeepEqual(extractSpec.Requires, []string{"chunks", "source.transcript"}) || !reflect.DeepEqual(extractSpec.Provides, []string{"dnd.npcs"}) {
if !ok || !reflect.DeepEqual(extractSpec.Requires, []string{"chunks", "source.transcript"}) || !reflect.DeepEqual(extractSpec.Provides, []string{"dnd.npc_registry"}) {
t.Fatalf("NPC extractor spec = %#v, want source and artifact capabilities", extractSpec)
}
mergeSpec, ok := catalog.Mergers.SpecForArtifact(pipeline.DefaultMergeModule, dnd.NPCRegistryKind)
@@ -54,18 +54,18 @@ func TestProductionNPCConfigurationResolvesTypedLane(t *testing.T) {
wantExtractChain := []pipeline.ModuleBinding{
pipeline.Binding("generic/valid_json"),
pipeline.Binding("extract/dnd/npcs/shape"),
pipeline.Binding("extract/dnd/npcs/source_refs"),
pipeline.Binding("extract/dnd/npc-registry/shape"),
pipeline.Binding("extract/dnd/npc-registry/source_refs"),
pipeline.Binding("generic/valid_json_schema"),
pipeline.Binding("extract/dnd/npcs/source_relatedness"),
pipeline.Binding("extract/dnd/npc-registry/source_relatedness"),
}
wantNormalizeChain := []pipeline.ModuleBinding{
pipeline.Binding("generic/valid_json"),
pipeline.Binding("extract/dnd/npcs/shape"),
pipeline.Binding("normalize/dnd/npcs/identity"),
pipeline.Binding("extract/dnd/npcs/source_refs"),
pipeline.Binding("extract/dnd/npc-registry/shape"),
pipeline.Binding("normalize/dnd/npc-registry/identity"),
pipeline.Binding("extract/dnd/npc-registry/source_refs"),
pipeline.Binding("generic/valid_json_schema"),
pipeline.Binding("extract/dnd/npcs/source_relatedness"),
pipeline.Binding("extract/dnd/npc-registry/source_relatedness"),
}
if got := validatorChain(effective.ResolvedPipeline, pipeline.StageExtract, npcextract.Key); !reflect.DeepEqual(got, wantExtractChain) {
t.Fatalf("NPC extract chain = %#v, want %#v", got, wantExtractChain)
@@ -90,16 +90,16 @@ func TestProductionNPCConfigurationValidatesOptionsReferencesAndPlacement(t *tes
}
if err := resolve(func(profile *pipeline.PipelineProfile) {
lane := profile.Artifacts["npcs"]
lane := profile.Artifacts["npc_registry"]
lane.Extract.Options = map[string]any{"unexpected": true}
profile.Artifacts["npcs"] = lane
profile.Artifacts["npc_registry"] = lane
}); err == nil || !strings.Contains(err.Error(), "unknown option") {
t.Fatalf("unknown extractor option error = %v, want strict option rejection", err)
}
if err := resolve(func(profile *pipeline.PipelineProfile) {
lane := profile.Artifacts["npcs"]
lane := profile.Artifacts["npc_registry"]
lane.Normalize.Options = map[string]any{"unexpected": true}
profile.Artifacts["npcs"] = lane
profile.Artifacts["npc_registry"] = lane
}); err == nil || !strings.Contains(err.Error(), "unknown option") {
t.Fatalf("unknown normalizer option error = %v, want strict option rejection", err)
}
@@ -113,9 +113,9 @@ func TestProductionNPCConfigurationValidatesOptionsReferencesAndPlacement(t *tes
t.Fatalf("optional NPC references error = %v, want resolution success", err)
}
if err := resolve(func(profile *pipeline.PipelineProfile) {
lane := profile.Artifacts["npcs"]
lane.Validators = []pipeline.ModuleBinding{pipeline.Binding("normalize/dnd/npcs/identity")}
profile.Artifacts["npcs"] = lane
lane := profile.Artifacts["npc_registry"]
lane.Validators = []pipeline.ModuleBinding{pipeline.Binding("normalize/dnd/npc-registry/identity")}
profile.Artifacts["npc_registry"] = lane
}); err == nil || !strings.Contains(err.Error(), "artifact lane level") {
t.Fatalf("lane-level validator error = %v, want invalid placement rejection", err)
}
@@ -128,7 +128,7 @@ func productionNPCContractConfig() config.Config {
Input: pipeline.Binding("seriatim"),
Chunk: pipeline.Binding(pipeline.DefaultChunkModule),
Artifacts: map[string]pipeline.ArtifactLaneProfile{
"npcs": {
"npc_registry": {
Extract: pipeline.ModuleBinding{Module: npcextract.Key, Retries: 2},
Normalize: pipeline.Binding(npcnormalize.Key),
},

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,npcs,scene-descriptions|extract-events:combat-turns,location-occurrences,npc-interactions,spells|track-enemies:enemy-events" {
if got := exampleStepLaneIDs(materialized); strings.Join(got, "|") != "describe-session:item-events,locations,npc_registry,scene-descriptions|extract-events:combat-turns,location-occurrences,npc-interactions,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")
@@ -90,7 +90,7 @@ func TestMaintainedExamplesLoadResolveAndList(t *testing.T) {
}
itemEventLane := referenceContractLane(t, materialized, "item-events")
for _, references := range []pipeline.ResolvedReferenceTarget{itemEventLane.ExtractReferences, itemEventLane.NormalizeReferences} {
if _, found := references.ReferenceSet.Slots["npcs"]; found {
if _, found := references.ReferenceSet.Slots["npc_registry"]; found {
t.Fatalf("item event lane unexpectedly depends on generated NPCs: %#v", itemEventLane)
}
if _, found := references.ReferenceSet.Slots["scene_descriptions"]; found {
@@ -99,7 +99,7 @@ func TestMaintainedExamplesLoadResolveAndList(t *testing.T) {
}
enemyEventLane := referenceContractLane(t, materialized, "enemy-events")
for slot, want := range map[string]struct{ step, lane string }{
"npcs": {step: "describe-session", lane: "npcs"},
"npc_registry": {step: "describe-session", lane: "npc_registry"},
"scene_descriptions": {step: "describe-session", lane: "scene-descriptions"},
"combat_turns": {step: "extract-events", lane: "combat-turns"},
"npc_interactions": {step: "extract-events", lane: "npc-interactions"},

View File

@@ -38,7 +38,7 @@ pipelines:
extract:
module: dnd/spells
references:
npcs: %q
npc_registry: %q
normalize: dnd/spells
`, checkpointRoot, npcPath)
configPath := filepath.Join(t.TempDir(), "config.yml")
@@ -66,7 +66,7 @@ pipelines:
"--input", repositoryPath("examples", "seriatim-minimal-transcript.json"),
"--chunk_cache", "bypass", "--output-dir", t.TempDir(),
}, &stdout, &stderr, options)
for _, fragment := range []string{`pipeline "dnd-session"`, `reference slot "npcs"`, "1048577 bytes", "limit 1048576"} {
for _, fragment := range []string{`pipeline "dnd-session"`, `reference slot "npc_registry"`, "1048577 bytes", "limit 1048576"} {
if code == 0 || !strings.Contains(stderr.String(), fragment) {
t.Fatalf("RunWithOptions() code = %d stderr = %q, want context fragment %q", code, stderr.String(), fragment)
}

View File

@@ -49,9 +49,9 @@ func TestProductionCatalogCoversMaintainedConfigurations(t *testing.T) {
assertProductionContains(t, "inputs", registries.Inputs.RegisteredKeys(), []string{"seriatim"})
assertProductionContains(t, "chunkers", registries.Chunkers.RegisteredKeys(), []string{"dnd/scenes", "generic"})
assertProductionContains(t, "extractors", registries.Extractors.RegisteredKeys(), []string{"dnd/spells", "dnd/npcs", combatextract.Key, itemeventextract.Key, enemyeventextract.Key})
assertProductionContains(t, "extractors", registries.Extractors.RegisteredKeys(), []string{"dnd/spells", "dnd/npc-registry", combatextract.Key, itemeventextract.Key, enemyeventextract.Key})
assertProductionContains(t, "mergers", registries.Mergers.RegisteredKeys(), []string{"appendorder"})
assertProductionContains(t, "normalizers", registries.Normalizers.RegisteredKeys(), []string{"noop", spellnormalize.Key, "dnd/npcs", combatnormalize.Key, itemeventnormalize.Key, enemyeventnormalize.Key})
assertProductionContains(t, "normalizers", registries.Normalizers.RegisteredKeys(), []string{"noop", spellnormalize.Key, "dnd/npc-registry", combatnormalize.Key, itemeventnormalize.Key, enemyeventnormalize.Key})
assertProductionContains(t, "outputs", registries.Outputs.RegisteredKeys(), []string{"json"})
assertProductionContains(t, "validators", registries.Validators.RegisteredKeys(), []string{
"extract/dnd/spells/catalog",
@@ -162,7 +162,7 @@ func TestProductionCatalogCoversMaintainedConfigurations(t *testing.T) {
{stage: pipeline.StageChunk, key: "generic", want: contracts.ExecutionClassDeterministic},
{stage: pipeline.StageChunk, key: "dnd/scenes", want: contracts.ExecutionClassLLMBacked},
{stage: pipeline.StageExtract, key: "dnd/spells", want: contracts.ExecutionClassLLMBacked},
{stage: pipeline.StageExtract, key: "dnd/npcs", want: contracts.ExecutionClassLLMBacked},
{stage: pipeline.StageExtract, key: "dnd/npc-registry", want: contracts.ExecutionClassLLMBacked},
{stage: pipeline.StageExtract, key: "dnd/combat-turns", want: contracts.ExecutionClassLLMBacked},
{stage: pipeline.StageExtract, key: "dnd/item-events", want: contracts.ExecutionClassLLMBacked},
{stage: pipeline.StageExtract, key: "dnd/npc-interactions", want: contracts.ExecutionClassLLMBacked},
@@ -171,7 +171,7 @@ func TestProductionCatalogCoversMaintainedConfigurations(t *testing.T) {
{stage: pipeline.StageMerge, key: "appendorder", want: contracts.ExecutionClassDeterministic},
{stage: pipeline.StageNormalize, key: "noop", want: contracts.ExecutionClassDeterministic},
{stage: pipeline.StageNormalize, key: "dnd/spells", want: contracts.ExecutionClassDeterministic},
{stage: pipeline.StageNormalize, key: "dnd/npcs", want: contracts.ExecutionClassLLMBacked},
{stage: pipeline.StageNormalize, key: "dnd/npc-registry", want: contracts.ExecutionClassLLMBacked},
{stage: pipeline.StageNormalize, key: "dnd/combat-turns", want: contracts.ExecutionClassDeterministic},
{stage: pipeline.StageNormalize, key: "dnd/item-events", want: contracts.ExecutionClassDeterministic},
{stage: pipeline.StageNormalize, key: "dnd/npc-interactions", want: contracts.ExecutionClassDeterministic},

View File

@@ -639,14 +639,14 @@ pipelines:
steps:
- id: identify-npcs
artifacts:
npcs:
extract: dnd/npcs
npc_registry:
extract: dnd/npc-registry
- id: grounded-events
references:
npcs:
npc_registry:
artifact:
step: identify-npcs
lane: npcs
lane: npc_registry
artifacts:
spells:
extract: dnd/spells
@@ -659,8 +659,8 @@ pipelines:
if len(profile.Steps) != 2 || profile.Steps[0].ID != "identify-npcs" || profile.Steps[1].ID != "grounded-events" {
t.Fatalf("steps = %#v", profile.Steps)
}
source := profile.Steps[1].References["npcs"]
if source.Artifact == nil || source.Artifact.Step != "identify-npcs" || source.Artifact.Lane != "npcs" {
source := profile.Steps[1].References["npc_registry"]
if source.Artifact == nil || source.Artifact.Step != "identify-npcs" || source.Artifact.Lane != "npc_registry" {
t.Fatalf("generated source = %#v", source)
}
}

View File

@@ -1,4 +1,4 @@
package npcs
package npcregistry
import (
"embed"

View File

@@ -1,4 +1,4 @@
package npcs
package npcregistry
import (
"bytes"

View File

@@ -12,7 +12,7 @@ import (
"gitea.maximumdirect.net/eric/notarius/internal/framework/contracts"
"gitea.maximumdirect.net/eric/notarius/internal/framework/pipeline"
"gitea.maximumdirect.net/eric/notarius/internal/modules/dnd"
npccodec "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/codec/npcs"
npccodec "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/codec/npcregistry"
scenecodec "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/codec/scenedescriptions"
"gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/npcs/identity"
)

View File

@@ -25,7 +25,7 @@ var promptAssetManifest = shared.PromptAssetManifest{
"common-dnd-identity.md",
"common-dnd-transcript-chunk.md",
"common-dnd-references.md",
"common-dnd-npcs.md",
"common-dnd-npc-registry.md",
},
}

View File

@@ -49,11 +49,11 @@ func TestPromptAssetsPrepareRequiredInputs(t *testing.T) {
prepared, err := engine.Prepare(context.Background(), promptkit.RunRequest{
PromptID: PromptID, PromptVersion: SchemaVersion, ProfileID: "combat-test-profile",
Inputs: map[string]promptkit.ArtifactRef{
"transcript": promptkit.InlineWithURI("file:///session.json", transcript),
"players": promptkit.Inline("combat-player"),
"party": promptkit.Inline(" "),
"glossary": promptkit.Inline(" "),
"npcs": promptkit.Inline(`{"npcs":[{"name":"combat-npc"}]}`),
"transcript": promptkit.InlineWithURI("file:///session.json", transcript),
"players": promptkit.Inline("combat-player"),
"party": promptkit.Inline(" "),
"glossary": promptkit.Inline(" "),
"npc_registry": promptkit.Inline(`{"npcs":[{"name":"combat-npc"}]}`),
},
})
if err != nil {

View File

@@ -16,7 +16,7 @@ import (
"gitea.maximumdirect.net/eric/notarius/internal/modules/dnd"
combatturncodec "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/codec/combatturns"
interactioncodec "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/codec/npcinteractions"
npccodec "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/codec/npcs"
npccodec "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/codec/npcregistry"
scenecodec "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/codec/scenedescriptions"
npcregistry "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/npcs/registry"
sceneregistry "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/scenedescriptions/registry"

View File

@@ -11,7 +11,7 @@ import (
"gitea.maximumdirect.net/eric/notarius/internal/modules/dnd"
combatturncodec "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/codec/combatturns"
interactioncodec "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/codec/npcinteractions"
npccodec "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/codec/npcs"
npccodec "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/codec/npcregistry"
scenecodec "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/codec/scenedescriptions"
"gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/npcs/identity"
sceneregistry "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/scenedescriptions/registry"

View File

@@ -26,7 +26,7 @@ var promptAssetManifest = shared.PromptAssetManifest{
"common-dnd-identity.md",
"common-dnd-transcript-chunk.md",
"common-dnd-references.md",
"common-dnd-npcs.md",
"common-dnd-npc-registry.md",
},
}

View File

@@ -32,7 +32,7 @@ func TestRegisterPromptAssetsAndPrepareEnemyEventPrompt(t *testing.T) {
func TestEnemyEventPromptRequiresGroundingInputs(t *testing.T) {
engine := newEnemyEventPromptEngine(t)
for _, inputName := range []string{"npcs", "combat_turns", "npc_interactions"} {
for _, inputName := range []string{"npc_registry", "combat_turns", "npc_interactions"} {
t.Run(inputName, func(t *testing.T) {
inputs := enemyEventPromptInputs()
delete(inputs, inputName)
@@ -83,7 +83,7 @@ func enemyEventPromptInputs() map[string]promptkit.ArtifactRef {
"players": promptkit.Inline("enemy-player"),
"party": promptkit.Inline("enemy-party"),
"glossary": promptkit.Inline("enemy-glossary"),
"npcs": promptkit.Inline(`{"npcs":[{"name":"enemy-npc"}]}`),
"npc_registry": promptkit.Inline(`{"npcs":[{"name":"enemy-npc"}]}`),
"combat_turns": promptkit.Inline(`{"combat_turns":[{"actor":"enemy-turn","turn_kind":"turn"}]}`),
"npc_interactions": promptkit.Inline(`{"npc_interactions":[{"name":"enemy-opponent","kind":"combat_opponent"}]}`),
}

View File

@@ -121,7 +121,7 @@ func TestExtractUsesOnlySupportedPromptInputs(t *testing.T) {
"players": {Slot: contracts.ReferenceSlot{Name: "players"}, Items: []contracts.ReferenceItem{{SlotName: "players", Content: []byte("Dana: Aria")}}},
"party": {Slot: contracts.ReferenceSlot{Name: "party"}, Items: []contracts.ReferenceItem{{SlotName: "party", Content: []byte("Aria: ranger")}}},
"glossary": {Slot: contracts.ReferenceSlot{Name: "glossary"}, Items: []contracts.ReferenceItem{{SlotName: "glossary", Content: []byte("Moonblade: heirloom")}}},
"npcs": {Slot: contracts.ReferenceSlot{Name: "npcs"}, Items: []contracts.ReferenceItem{{SlotName: "npcs", Content: []byte("must not be used")}}},
"npcs": {Slot: contracts.ReferenceSlot{Name: "npc_registry"}, Items: []contracts.ReferenceItem{{SlotName: "npc_registry", Content: []byte("must not be used")}}},
}}
if _, err := newExtractor(t, client).Extract(context.Background(), req); err != nil {
t.Fatal(err)

View File

@@ -12,7 +12,7 @@ import (
"gitea.maximumdirect.net/eric/notarius/internal/framework/contracts"
"gitea.maximumdirect.net/eric/notarius/internal/framework/pipeline"
"gitea.maximumdirect.net/eric/notarius/internal/modules/dnd"
npccodec "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/codec/npcs"
npccodec "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/codec/npcregistry"
"gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/npcs/identity"
)

View File

@@ -25,7 +25,7 @@ var promptAssetManifest = shared.PromptAssetManifest{
"common-dnd-identity.md",
"common-dnd-transcript-chunk.md",
"common-dnd-references.md",
"common-dnd-npcs.md",
"common-dnd-npc-registry.md",
},
}

View File

@@ -38,11 +38,11 @@ func TestRegisterPromptAssetsAndPrepareInteractionPrompt(t *testing.T) {
prepared, err := engine.Prepare(context.Background(), promptkit.RunRequest{
PromptID: PromptID, PromptVersion: SchemaVersion, ProfileID: "npc-interactions-test-profile",
Inputs: map[string]promptkit.ArtifactRef{
"transcript": promptkit.InlineWithURI("file:///session.json", transcript),
"players": promptkit.Inline("interaction-player"),
"party": promptkit.Inline("Mira: ranger"),
"glossary": promptkit.Inline("Greencloak: title"),
"npcs": promptkit.Inline(`{"npcs":[{"name":"interaction-npc"}]}`),
"transcript": promptkit.InlineWithURI("file:///session.json", transcript),
"players": promptkit.Inline("interaction-player"),
"party": promptkit.Inline("Mira: ranger"),
"glossary": promptkit.Inline("Greencloak: title"),
"npc_registry": promptkit.Inline(`{"npcs":[{"name":"interaction-npc"}]}`),
},
})
if err != nil {

View File

@@ -1,4 +1,4 @@
package npcs
package npcregistry
import (
"sort"

View File

@@ -1,4 +1,4 @@
package npcs
package npcregistry
import (
"context"
@@ -11,9 +11,9 @@ import (
"gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/shared"
)
const Key = "dnd/npcs"
const Key = "dnd/npc-registry"
const mappingPolicy = "dnd.npcs.extract_mapping.v2"
const mappingPolicy = "dnd.npc_registry.extract_mapping.v2"
var requiredCapabilities = []string{
"chunks",
@@ -21,7 +21,7 @@ var requiredCapabilities = []string{
}
var providedCapabilities = []string{
"dnd.npcs",
"dnd.npc_registry",
}
var referenceSlotDescriptions = shared.ReferenceSlotDescriptions{
@@ -166,5 +166,5 @@ func DecodeOptions(options map[string]any) (Options, error) {
}
func extractorErrorf(format string, args ...any) error {
return fmt.Errorf("dnd npcs extractor: "+format, args...)
return fmt.Errorf("dnd npc registry extractor: "+format, args...)
}

View File

@@ -1,4 +1,4 @@
package npcs
package npcregistry
import (
"context"
@@ -188,13 +188,13 @@ func TestExtractRetainsLocalErrorContextAndProviderFailures(t *testing.T) {
{name: "wrapped preflight failure", extractor: extractor, req: mismatchedSourceInputRequest(request), want: "must match chunk"},
} {
t.Run(test.name, func(t *testing.T) {
if _, err := test.extractor.Extract(context.Background(), test.req); err == nil || !strings.Contains(err.Error(), "dnd npcs") || !strings.Contains(err.Error(), test.want) {
if _, err := test.extractor.Extract(context.Background(), test.req); err == nil || !strings.Contains(err.Error(), "dnd npc registry") || !strings.Contains(err.Error(), test.want) {
t.Fatalf("Extract() error = %v, want contextual local error", err)
}
})
}
_, err := newExtractor(t, &fakeNPCsLLMClient{err: errors.New("provider unavailable")}).Extract(context.Background(), request)
if err == nil || !strings.Contains(err.Error(), "dnd npcs") || !strings.Contains(err.Error(), "provider unavailable") {
if err == nil || !strings.Contains(err.Error(), "dnd npc registry") || !strings.Contains(err.Error(), "provider unavailable") {
t.Fatalf("provider Extract() error = %v, want contextual provider error", err)
}
}

View File

@@ -1,4 +1,4 @@
package npcs
package npcregistry
type extractionResponse struct {
NPCs []npcResponse `json:"npcs"`

View File

@@ -1,4 +1,4 @@
package npcs
package npcregistry
import (
"fmt"
@@ -14,7 +14,7 @@ import (
const promptAssetRoot = "assets/prompts"
var promptAssetManifest = shared.PromptAssetManifest{
ModuleDir: "dnd.npcs",
ModuleDir: "dnd.npc_registry",
ModuleFiles: []promptfs.ModulePromptFile{
{Name: "prompt.yaml", Path: "prompts/prompt.yaml"},
{Name: "instructions.md", Path: "prompts/instructions.md"},
@@ -29,7 +29,7 @@ var promptAssetManifest = shared.PromptAssetManifest{
}
func moduleAssetFS() (fs.FS, error) {
assets, err := fs.Sub(rootassets.FS(), "dnd/npcs/extract")
assets, err := fs.Sub(rootassets.FS(), "dnd/npc-registry/extract")
if err != nil {
return nil, fmt.Errorf("scope NPC extraction assets: %w", err)
}

View File

@@ -1,4 +1,4 @@
package npcs
package npcregistry
import (
"context"
@@ -39,7 +39,7 @@ func TestRegisterPromptAssetsAndPrepareNPCPrompt(t *testing.T) {
if err != nil {
t.Fatalf("Prepare() error = %v, want nil", err)
}
if prepared.PromptID != PromptID || prepared.OutputContract.SchemaPath != "dnd_npcs_llm.v1.json" {
if prepared.PromptID != PromptID || prepared.OutputContract.SchemaPath != "dnd_npc_registry_llm.v1.json" {
t.Fatalf("prepared prompt = %#v, want NPC prompt identity and wiring", prepared)
}
}
@@ -54,7 +54,7 @@ func TestPromptMetadataAndDiagnosticsDoNotContainRawAssets(t *testing.T) {
if err != nil {
t.Fatal(err)
}
for _, forbidden := range []string{"common-dnd-system", "dnd_npcs_llm.v1.json"} {
for _, forbidden := range []string{"common-dnd-system", "dnd_npc_registry_llm.v1.json"} {
if strings.Contains(string(payload), forbidden) {
t.Fatalf("metadata leaked raw prompt/schema content %q: %s", forbidden, payload)
}

View File

@@ -1,4 +1,4 @@
package npcs
package npcregistry
import (
"reflect"
@@ -29,7 +29,7 @@ func TestModuleSpecAndReferenceSlots(t *testing.T) {
Stage: pipeline.StageExtract,
ExecutionClass: contracts.ExecutionClassLLMBacked,
Requires: []string{"chunks", "source.transcript"},
Provides: []string{"dnd.npcs"},
Provides: []string{"dnd.npc_registry"},
ArtifactKind: dnd.NPCRegistryKind,
ReferenceSlots: []contracts.ReferenceSlot{
{Name: "glossary", Description: "Optional campaign glossary reference material used only for NPC disambiguation.", AcceptedMediaTypes: []string{"application/json", "application/x-yaml", "application/yaml", "text/markdown", "text/plain"}},

View File

@@ -1,12 +1,12 @@
package npcs
package npcregistry
import "gitea.maximumdirect.net/eric/notarius/internal/framework/llm"
const (
PromptID = "dnd.npcs"
ResponseSchemaKey = llm.ResponseSchemaKey("dnd_npcs_llm")
ResponseSchemaID = "notarius.dnd.npcs.llm"
ResponseSchemaName = "notarius_dnd_npcs_llm_v1"
PromptID = "dnd.npc_registry"
ResponseSchemaKey = llm.ResponseSchemaKey("dnd_npc_registry_llm")
ResponseSchemaID = "notarius.dnd.npc_registry.llm"
ResponseSchemaName = "notarius_dnd_npc_registry_llm_v1"
SchemaVersion = "v1"
)
@@ -20,6 +20,6 @@ func loadResponseSchema() (llm.ResponseSchema, error) {
ID: ResponseSchemaID,
Version: SchemaVersion,
Name: ResponseSchemaName,
AssetPath: "schemas/dnd_npcs_llm.v1.json",
AssetPath: "schemas/dnd_npc_registry_llm.v1.json",
})
}

View File

@@ -1,4 +1,4 @@
package npcs
package npcregistry
import (
"bytes"

View File

@@ -1,4 +1,4 @@
package npcs
package npcregistry
import (
"context"

View File

@@ -11,7 +11,7 @@ import (
"gitea.maximumdirect.net/eric/notarius/internal/framework/contracts"
"gitea.maximumdirect.net/eric/notarius/internal/framework/pipeline"
"gitea.maximumdirect.net/eric/notarius/internal/modules/dnd"
npccodec "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/codec/npcs"
npccodec "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/codec/npcregistry"
"gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/npcs/identity"
"gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/npcs/registry"
)

View File

@@ -26,7 +26,7 @@ var promptAssetManifest = shared.PromptAssetManifest{
"common-dnd-identity.md",
"common-dnd-transcript-chunk.md",
"common-dnd-references.md",
"common-dnd-npcs.md",
"common-dnd-npc-registry.md",
},
}

View File

@@ -108,7 +108,7 @@ func prepareSpellsPrompt(t *testing.T, transcript []byte, players string, party
Inputs: map[string]promptkit.ArtifactRef{
"transcript": promptkit.InlineWithURI("file:///session.json", string(transcript)),
"spell_catalog": promptkit.Inline(`{"spell_names":["spell-catalog-sentinel"]}`),
"npcs": promptkit.Inline(`{"npcs":[{"name":"spell-npc-sentinel"}]}`),
"npc_registry": promptkit.Inline(`{"npcs":[{"name":"spell-npc-sentinel"}]}`),
"players": promptkit.Inline(players),
"party": promptkit.Inline(party),
"glossary": promptkit.Inline(glossary),

View File

@@ -13,7 +13,7 @@ import (
"gitea.maximumdirect.net/eric/notarius/internal/framework/contracts"
"gitea.maximumdirect.net/eric/notarius/internal/framework/pipeline"
"gitea.maximumdirect.net/eric/notarius/internal/modules/dnd"
npccodec "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/codec/npcs"
npccodec "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/codec/npcregistry"
"gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/npcs/identity"
)

View File

@@ -11,7 +11,7 @@ import (
"gitea.maximumdirect.net/eric/notarius/internal/framework/contracts"
"gitea.maximumdirect.net/eric/notarius/internal/framework/pipeline"
"gitea.maximumdirect.net/eric/notarius/internal/modules/dnd"
npccodec "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/codec/npcs"
npccodec "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/codec/npcregistry"
"gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/npcs/identity"
"gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/shared/diagnostics"
)

View File

@@ -9,7 +9,7 @@ import (
"gitea.maximumdirect.net/eric/notarius/internal/framework/contracts"
"gitea.maximumdirect.net/eric/notarius/internal/framework/pipeline"
"gitea.maximumdirect.net/eric/notarius/internal/modules/dnd"
npccodec "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/codec/npcs"
npccodec "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/codec/npcregistry"
"gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/npcs/identity"
"gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/shared/diagnostics"
)

View File

@@ -1,5 +1,5 @@
// Package npcs normalizes merged D&D non-player character records.
package npcs
// Package npcregistry normalizes merged D&D non-player character records.
package npcregistry
import (
"context"
@@ -21,9 +21,9 @@ import (
)
const (
Key = "dnd/npcs"
PromptID = "dnd.npcs.normalize"
normalizationPolicy = "dnd.npcs.normalize.v3"
Key = "dnd/npc-registry"
PromptID = "dnd.npc_registry.normalize"
normalizationPolicy = "dnd.npc_registry.normalize.v3"
semanticContextPolicy = "dnd.entity_reconcile.context.v1"
NormalizationPolicy = normalizationPolicy
@@ -385,5 +385,5 @@ func DecodeOptions(options map[string]any) (Options, error) {
}
func normalizerErrorf(format string, args ...any) error {
return fmt.Errorf("dnd npcs normalizer: "+format, args...)
return fmt.Errorf("dnd npc registry normalizer: "+format, args...)
}

View File

@@ -1,4 +1,4 @@
package npcs
package npcregistry
import (
"context"

View File

@@ -1,4 +1,4 @@
package npcs
package npcregistry
import (
"fmt"
@@ -28,7 +28,7 @@ var promptAssetManifest = shared.PromptAssetManifest{
}
func moduleAssetFS() (fs.FS, error) {
assets, err := fs.Sub(rootassets.FS(), "dnd/npcs/normalize")
assets, err := fs.Sub(rootassets.FS(), "dnd/npc-registry/normalize")
if err != nil {
return nil, fmt.Errorf("scope NPC normalization assets: %w", err)
}

View File

@@ -1,4 +1,4 @@
package npcs
package npcregistry
import (
"fmt"

View File

@@ -11,14 +11,14 @@ import (
"gitea.maximumdirect.net/eric/notarius/internal/core/source"
"gitea.maximumdirect.net/eric/notarius/internal/framework/contracts"
"gitea.maximumdirect.net/eric/notarius/internal/modules/dnd"
npccodec "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/codec/npcs"
npccodec "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/codec/npcregistry"
"gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/npcs/identity"
"gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/shared/diagnostics"
"gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/shared/registryresolver"
)
const (
ReferenceSlot = "npcs"
ReferenceSlot = "npc_registry"
MaxBytes = 1048576
emptyPrompt = `{"npcs":[]}`
)

View File

@@ -9,7 +9,7 @@ import (
"gitea.maximumdirect.net/eric/notarius/internal/core/source"
"gitea.maximumdirect.net/eric/notarius/internal/framework/contracts"
"gitea.maximumdirect.net/eric/notarius/internal/modules/dnd"
npccodec "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/codec/npcs"
npccodec "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/codec/npcregistry"
"gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/npcs/identity"
)

View File

@@ -8,7 +8,7 @@ import (
locationoccurrenceextract "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/extract/locationoccurrences"
locationextract "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/extract/locations"
interactionextract "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/extract/npcinteractions"
npcextract "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/extract/npcs"
npcextract "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/extract/npcregistry"
scenedescriptionextract "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/extract/scenedescriptions"
spellextract "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/extract/spells"
combatnormalize "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/normalize/combatturns"
@@ -17,7 +17,7 @@ import (
locationoccurrencenormalize "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/normalize/locationoccurrences"
locationnormalize "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/normalize/locations"
interactionnormalize "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/normalize/npcinteractions"
npcnormalize "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/normalize/npcs"
npcnormalize "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/normalize/npcregistry"
scenedescriptionnormalize "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/normalize/scenedescriptions"
spellnormalize "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/normalize/spells"
combatinvariants "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/validate/combatturns/invariants"
@@ -47,10 +47,10 @@ import (
interactionshape "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/validate/npcinteractions/shape"
interactionrefs "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/validate/npcinteractions/source_refs"
interactionrelatedness "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/validate/npcinteractions/source_relatedness"
npcidentity "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/validate/npcs/identity"
npcshape "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/validate/npcs/shape"
npcsourcerefs "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/validate/npcs/source_refs"
npcrelatedness "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/validate/npcs/source_relatedness"
npcidentity "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/validate/npcregistry/identity"
npcshape "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/validate/npcregistry/shape"
npcsourcerefs "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/validate/npcregistry/source_refs"
npcrelatedness "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/validate/npcregistry/source_relatedness"
sceneinvariants "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/validate/scenedescriptions/invariants"
sceneshape "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/validate/scenedescriptions/shape"
scenerefs "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/validate/scenedescriptions/source_refs"
@@ -93,7 +93,7 @@ func registerDefaultChains(registry *pipeline.ValidatorChainRegistry) error {
},
})
}},
{name: "npcs validator chain", register: func() error {
{name: "npc registry validator chain", register: func() error {
return registry.Register(pipeline.ValidatorChainMapping{
Stage: pipeline.StageExtract,
Module: npcextract.Key,
@@ -106,7 +106,7 @@ func registerDefaultChains(registry *pipeline.ValidatorChainRegistry) error {
},
})
}},
{name: "npcs normalize validator chain", register: func() error {
{name: "npc registry normalize validator chain", register: func() error {
return registry.Register(pipeline.ValidatorChainMapping{
Stage: pipeline.StageNormalize,
Module: npcnormalize.Key,

View File

@@ -9,7 +9,7 @@ import (
func registerEvidence(registry *pipeline.ArtifactEvidenceRegistry) error {
return runRegistrations([]registration{
{name: "spells evidence", register: func() error { return pipeline.RegisterArtifactEvidence(registry, dnd.SpellListKind, spellEvidence) }},
{name: "npcs evidence", register: func() error { return pipeline.RegisterArtifactEvidence(registry, dnd.NPCRegistryKind, npcEvidence) }},
{name: "npc registry evidence", register: func() error { return pipeline.RegisterArtifactEvidence(registry, dnd.NPCRegistryKind, npcEvidence) }},
{name: "combat turns evidence", register: func() error {
return pipeline.RegisterArtifactEvidence(registry, dnd.CombatTurnListKind, combatTurnEvidence)
}},

View File

@@ -11,7 +11,7 @@ import (
locationoccurrencecodec "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/codec/locationoccurrences"
locationcodec "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/codec/locations"
interactioncodec "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/codec/npcinteractions"
npccodec "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/codec/npcs"
npccodec "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/codec/npcregistry"
scenedescriptioncodec "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/codec/scenedescriptions"
spellcodec "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/codec/spells"
combatextract "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/extract/combatturns"
@@ -20,7 +20,7 @@ import (
locationoccurrenceextract "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/extract/locationoccurrences"
locationextract "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/extract/locations"
interactionextract "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/extract/npcinteractions"
npcextract "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/extract/npcs"
npcextract "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/extract/npcregistry"
scenedescriptionextract "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/extract/scenedescriptions"
spellextract "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/extract/spells"
combatnormalize "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/normalize/combatturns"
@@ -29,7 +29,7 @@ import (
locationoccurrencenormalize "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/normalize/locationoccurrences"
locationnormalize "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/normalize/locations"
interactionnormalize "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/normalize/npcinteractions"
npcnormalize "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/normalize/npcs"
npcnormalize "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/normalize/npcregistry"
scenedescriptionnormalize "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/normalize/scenedescriptions"
spellnormalize "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/normalize/spells"
"gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/shared/entityreconcile"
@@ -41,7 +41,7 @@ func registerModules(registries pipeline.Registries) error {
codec := spellcodec.New()
return runRegistrations([]registration{
{name: "spells codec", register: func() error { return pipeline.RegisterArtifactCodec(registries.ArtifactCodecs, codec) }},
{name: "npcs codec", register: func() error { return pipeline.RegisterArtifactCodec(registries.ArtifactCodecs, npccodec.New()) }},
{name: "npc registry codec", register: func() error { return pipeline.RegisterArtifactCodec(registries.ArtifactCodecs, npccodec.New()) }},
{name: "combat turns codec", register: func() error { return pipeline.RegisterArtifactCodec(registries.ArtifactCodecs, combatcodec.New()) }},
{name: "enemy events codec", register: func() error { return pipeline.RegisterArtifactCodec(registries.ArtifactCodecs, enemyeventcodec.New()) }},
{name: "item events codec", register: func() error { return pipeline.RegisterArtifactCodec(registries.ArtifactCodecs, itemeventcodec.New()) }},
@@ -55,7 +55,7 @@ func registerModules(registries pipeline.Registries) error {
}},
{name: "scenes chunker", register: func() error { return scenes.Register(registries.Chunkers) }},
{name: "spells extractor", register: func() error { return spellextract.Register(registries.Extractors) }},
{name: "npcs extractor", register: func() error { return npcextract.Register(registries.Extractors) }},
{name: "npc registry extractor", register: func() error { return npcextract.Register(registries.Extractors) }},
{name: "combat turns extractor", register: func() error { return combatextract.Register(registries.Extractors) }},
{name: "enemy events extractor", register: func() error { return enemyeventextract.Register(registries.Extractors) }},
{name: "item events extractor", register: func() error { return itemeventextract.Register(registries.Extractors) }},
@@ -91,7 +91,7 @@ func registerModules(registries pipeline.Registries) error {
return appendorder.RegisterTyped(registries.Mergers, dnd.LocationOccurrenceListKind, appendLocationOccurrenceLists)
}},
{name: "spells normalizer", register: func() error { return spellnormalize.Register(registries.Normalizers) }},
{name: "npcs normalizer", register: func() error { return npcnormalize.Register(registries.Normalizers) }},
{name: "npc registry normalizer", register: func() error { return npcnormalize.Register(registries.Normalizers) }},
{name: "combat turns normalizer", register: func() error { return combatnormalize.Register(registries.Normalizers) }},
{name: "enemy events normalizer", register: func() error { return enemyeventnormalize.Register(registries.Normalizers) }},
{name: "item events normalizer", register: func() error { return itemeventnormalize.Register(registries.Normalizers) }},
@@ -134,7 +134,7 @@ func registerPromptAssets(assets *llm.AssetRegistry) error {
{name: "entity reconciliation schema assets", register: func() error { return entityreconcile.RegisterSchemaAssets(assets) }},
{name: "scenes prompt assets", register: func() error { return scenes.RegisterPromptAssets(assets) }},
{name: "spells prompt assets", register: func() error { return spellextract.RegisterPromptAssets(assets) }},
{name: "npcs prompt assets", register: func() error { return npcextract.RegisterPromptAssets(assets) }},
{name: "npc registry prompt assets", register: func() error { return npcextract.RegisterPromptAssets(assets) }},
{name: "npc normalization prompt assets", register: func() error { return npcnormalize.RegisterPromptAssets(assets) }},
{name: "combat turns prompt assets", register: func() error { return combatextract.RegisterPromptAssets(assets) }},
{name: "enemy events prompt assets", register: func() error { return enemyeventextract.RegisterPromptAssets(assets) }},

View File

@@ -14,7 +14,7 @@ import (
locationoccurrenceextract "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/extract/locationoccurrences"
locationextract "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/extract/locations"
interactionextract "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/extract/npcinteractions"
npcextract "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/extract/npcs"
npcextract "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/extract/npcregistry"
scenedescriptionextract "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/extract/scenedescriptions"
spellextract "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/extract/spells"
"gitea.maximumdirect.net/eric/promptkit"
@@ -57,7 +57,7 @@ func TestExtractionPromptComposition(t *testing.T) {
promptID: combatextract.PromptID,
promptVersion: combatextract.SchemaVersion,
inputs: withPromptInputs(commonInputs, map[string]promptkit.ArtifactRef{
"npcs": promptkit.Inline(`{"sentinel":"` + npcSentinel + `"}`),
"npc_registry": promptkit.Inline(`{"sentinel":"` + npcSentinel + `"}`),
}),
suffixGroups: [][]string{{evidenceSentinel}, {npcSentinel}},
},
@@ -66,7 +66,7 @@ func TestExtractionPromptComposition(t *testing.T) {
promptID: enemyeventextract.PromptID,
promptVersion: enemyeventextract.SchemaVersion,
inputs: withPromptInputs(commonInputs, map[string]promptkit.ArtifactRef{
"npcs": promptkit.Inline(`{"sentinel":"` + npcSentinel + `"}`),
"npc_registry": promptkit.Inline(`{"sentinel":"` + npcSentinel + `"}`),
"combat_turns": promptkit.Inline(`{"sentinel":"combat-turns-sentinel"}`),
"npc_interactions": promptkit.Inline(`{"sentinel":"npc-interactions-sentinel"}`),
}),
@@ -81,7 +81,7 @@ func TestExtractionPromptComposition(t *testing.T) {
promptID: interactionextract.PromptID,
promptVersion: interactionextract.SchemaVersion,
inputs: withPromptInputs(commonInputs, map[string]promptkit.ArtifactRef{
"npcs": promptkit.Inline(`{"sentinel":"` + npcSentinel + `"}`),
"npc_registry": promptkit.Inline(`{"sentinel":"` + npcSentinel + `"}`),
}),
suffixGroups: [][]string{{evidenceSentinel}, {npcSentinel}},
},
@@ -99,7 +99,7 @@ func TestExtractionPromptComposition(t *testing.T) {
promptID: spellextract.PromptID,
promptVersion: spellextract.SchemaVersion,
inputs: withPromptInputs(commonInputs, map[string]promptkit.ArtifactRef{
"npcs": promptkit.Inline(`{"sentinel":"` + npcSentinel + `"}`),
"npc_registry": promptkit.Inline(`{"sentinel":"` + npcSentinel + `"}`),
"spell_catalog": promptkit.Inline(`{"sentinel":"` + catalogSentinel + `"}`),
}),
suffixGroups: [][]string{{evidenceSentinel}, {npcSentinel}, {catalogSentinel}},

View File

@@ -18,7 +18,7 @@ import (
locationoccurrenceextract "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/extract/locationoccurrences"
locationextract "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/extract/locations"
interactionextract "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/extract/npcinteractions"
npcextract "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/extract/npcs"
npcextract "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/extract/npcregistry"
scenedescriptionextract "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/extract/scenedescriptions"
"gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/extract/spells"
combatnormalize "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/normalize/combatturns"
@@ -27,7 +27,7 @@ import (
locationoccurrencenormalize "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/normalize/locationoccurrences"
locationnormalize "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/normalize/locations"
interactionnormalize "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/normalize/npcinteractions"
npcnormalize "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/normalize/npcs"
npcnormalize "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/normalize/npcregistry"
scenedescriptionnormalize "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/normalize/scenedescriptions"
spellnormalize "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/normalize/spells"
)
@@ -42,19 +42,19 @@ func TestRegisterAddsDNDFamily(t *testing.T) {
if err != nil {
t.Fatalf("PromptFS() error = %v", err)
}
if _, err := fs.ReadFile(promptFS, "dnd.npcs.normalize/prompt.yaml"); err != nil {
if _, err := fs.ReadFile(promptFS, "dnd.npc_registry.normalize/prompt.yaml"); err != nil {
t.Fatalf("normalization prompt asset = %v, want registered private prompt", err)
}
for _, name := range []string{
"dnd.scenes/prompt.yaml",
"dnd.spells/prompt.yaml",
"dnd.npcs/prompt.yaml",
"dnd.npc_registry/prompt.yaml",
"dnd.combat_turns/prompt.yaml",
"dnd.enemy_events/prompt.yaml",
"dnd.item_events/prompt.yaml",
"dnd.npc_interactions/prompt.yaml",
"dnd.scene_descriptions/prompt.yaml",
"dnd.npcs.normalize/prompt.yaml",
"dnd.npc_registry.normalize/prompt.yaml",
"dnd.locations/prompt.yaml",
"dnd.locations.normalize/prompt.yaml",
"dnd.location_occurrences/prompt.yaml",
@@ -97,10 +97,10 @@ func TestRegisterAddsDNDFamily(t *testing.T) {
assertContainsKeys(t, "validators", registries.Validators.RegisteredKeys(), []string{
"extract/dnd/locations/shape", "normalize/dnd/locations/identity", "extract/dnd/locations/source_refs", "extract/dnd/locations/source_relatedness",
"extract/dnd/location-occurrences/shape", "extract/dnd/location-occurrences/registry", "normalize/dnd/location-occurrences/invariants", "extract/dnd/location-occurrences/source_refs", "extract/dnd/location-occurrences/source_relatedness",
"extract/dnd/npcs/shape",
"extract/dnd/npcs/source_refs",
"extract/dnd/npcs/source_relatedness",
"normalize/dnd/npcs/identity",
"extract/dnd/npc-registry/shape",
"extract/dnd/npc-registry/source_refs",
"extract/dnd/npc-registry/source_relatedness",
"normalize/dnd/npc-registry/identity",
"extract/dnd/spells/catalog",
"extract/dnd/spells/shape",
"extract/dnd/spells/source_refs",
@@ -162,21 +162,21 @@ func TestRegisterAddsDNDFamily(t *testing.T) {
}
npcExtractChain := []pipeline.ModuleBinding{
pipeline.Binding("generic/valid_json"),
pipeline.Binding("extract/dnd/npcs/shape"),
pipeline.Binding("extract/dnd/npcs/source_refs"),
pipeline.Binding("extract/dnd/npc-registry/shape"),
pipeline.Binding("extract/dnd/npc-registry/source_refs"),
pipeline.Binding("generic/valid_json_schema"),
pipeline.Binding("extract/dnd/npcs/source_relatedness"),
pipeline.Binding("extract/dnd/npc-registry/source_relatedness"),
}
if got := registries.ValidatorChains.Validators(pipeline.StageExtract, npcextract.Key); !reflect.DeepEqual(got, npcExtractChain) {
t.Fatalf("NPC extract validator chain = %#v, want %#v", got, npcExtractChain)
}
npcNormalizeChain := []pipeline.ModuleBinding{
pipeline.Binding("generic/valid_json"),
pipeline.Binding("extract/dnd/npcs/shape"),
pipeline.Binding("normalize/dnd/npcs/identity"),
pipeline.Binding("extract/dnd/npcs/source_refs"),
pipeline.Binding("extract/dnd/npc-registry/shape"),
pipeline.Binding("normalize/dnd/npc-registry/identity"),
pipeline.Binding("extract/dnd/npc-registry/source_refs"),
pipeline.Binding("generic/valid_json_schema"),
pipeline.Binding("extract/dnd/npcs/source_relatedness"),
pipeline.Binding("extract/dnd/npc-registry/source_relatedness"),
}
if got := registries.ValidatorChains.Validators(pipeline.StageNormalize, npcnormalize.Key); !reflect.DeepEqual(got, npcNormalizeChain) {
t.Fatalf("NPC normalize validator chain = %#v, want %#v", got, npcNormalizeChain)
@@ -298,7 +298,7 @@ func TestRegisterAddsDNDFamily(t *testing.T) {
assertAssetNamesContain(t, assets.SchemaFS, []string{
"dnd_scenes_llm.v1.json",
"dnd_spells_llm.v1.json",
"dnd_npcs_llm.v1.json",
"dnd_npc_registry_llm.v1.json",
"dnd_combat_turns_llm.v1.json",
"dnd_enemy_events_llm.v1.json",
"dnd_item_events_llm.v1.json",
@@ -336,8 +336,8 @@ func TestRegisterAddsDNDFamily(t *testing.T) {
if len(enemyEventExtractSpec.ReferenceSlots) != 8 || len(enemyEventNormalizeSpec.ReferenceSlots) != 1 {
t.Fatalf("enemy event reference slots = %#v / %#v", enemyEventExtractSpec.ReferenceSlots, enemyEventNormalizeSpec.ReferenceSlots)
}
npcRegistrySlot := referenceSlot(enemyEventExtractSpec.ReferenceSlots, "npcs")
enemyNormalizeRegistrySlot := referenceSlot(enemyEventNormalizeSpec.ReferenceSlots, "npcs")
npcRegistrySlot := referenceSlot(enemyEventExtractSpec.ReferenceSlots, "npc_registry")
enemyNormalizeRegistrySlot := referenceSlot(enemyEventNormalizeSpec.ReferenceSlots, "npc_registry")
if !npcRegistrySlot.Required || !enemyNormalizeRegistrySlot.Required || npcRegistrySlot.MaxBytes != enemyNormalizeRegistrySlot.MaxBytes || !reflect.DeepEqual(npcRegistrySlot.AcceptedMediaTypes, enemyNormalizeRegistrySlot.AcceptedMediaTypes) || !reflect.DeepEqual(npcRegistrySlot.AcceptedArtifactKinds, enemyNormalizeRegistrySlot.AcceptedArtifactKinds) {
t.Fatalf("enemy-event NPC registry slots disagree: %#v / %#v", enemyEventExtractSpec.ReferenceSlots, enemyEventNormalizeSpec.ReferenceSlots)
}
@@ -388,8 +388,8 @@ func TestRegisterAddsDNDFamily(t *testing.T) {
if len(sceneExtractSpec.ReferenceSlots) != 3 || len(sceneNormalizeSpec.ReferenceSlots) != 0 {
t.Fatalf("scene description reference slots = %#v / %#v, want extractor campaign slots only", sceneExtractSpec.ReferenceSlots, sceneNormalizeSpec.ReferenceSlots)
}
extractRegistrySlot := referenceSlot(interactionExtractSpec.ReferenceSlots, "npcs")
normalizeRegistrySlot := referenceSlot(interactionNormalizeSpec.ReferenceSlots, "npcs")
extractRegistrySlot := referenceSlot(interactionExtractSpec.ReferenceSlots, "npc_registry")
normalizeRegistrySlot := referenceSlot(interactionNormalizeSpec.ReferenceSlots, "npc_registry")
if !extractRegistrySlot.Required || !reflect.DeepEqual(extractRegistrySlot.AcceptedArtifactKinds, []contracts.ArtifactKind{dnd.NPCRegistryKind}) || !sameReferenceSlotContract(extractRegistrySlot, normalizeRegistrySlot) {
t.Fatalf("NPC interaction registry slots disagree: %#v / %#v", interactionExtractSpec.ReferenceSlots, interactionNormalizeSpec.ReferenceSlots)
}

View File

@@ -30,10 +30,10 @@ import (
interactionshape "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/validate/npcinteractions/shape"
interactionrefs "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/validate/npcinteractions/source_refs"
interactionrelatedness "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/validate/npcinteractions/source_relatedness"
npcidentity "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/validate/npcs/identity"
npcshape "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/validate/npcs/shape"
npcsourcerefs "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/validate/npcs/source_refs"
npcrelatedness "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/validate/npcs/source_relatedness"
npcidentity "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/validate/npcregistry/identity"
npcshape "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/validate/npcregistry/shape"
npcsourcerefs "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/validate/npcregistry/source_refs"
npcrelatedness "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/validate/npcregistry/source_relatedness"
sceneinvariants "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/validate/scenedescriptions/invariants"
sceneshape "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/validate/scenedescriptions/shape"
scenerefs "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/validate/scenedescriptions/source_refs"

View File

@@ -27,7 +27,7 @@ var sharedPromptPaths = map[string]string{
"common-dnd-transcript-chunk.md": "prompts/common-dnd-transcript-chunk.md",
"common-dnd-transcript-windows.md": "prompts/common-dnd-transcript-windows.md",
"common-dnd-references.md": "prompts/common-dnd-references.md",
"common-dnd-npcs.md": "prompts/common-dnd-npcs.md",
"common-dnd-npc-registry.md": "prompts/common-dnd-npc-registry.md",
"common-dnd-entity-reconciliation.md": "prompts/common-dnd-entity-reconciliation.md",
}

View File

@@ -63,7 +63,7 @@ func TestPromptAssetManifestPromptFS(t *testing.T) {
}
for _, path := range []string{
"assets/prompts/dnd.test/sharedassets/common-dnd-references.md",
"assets/prompts/dnd.test/sharedassets/common-dnd-npcs.md",
"assets/prompts/dnd.test/sharedassets/common-dnd-npc-registry.md",
} {
if _, err := fs.ReadFile(fsys, path); err == nil {
t.Fatalf("ReadFile(%q) succeeded, want unlisted shared asset to be absent", path)
@@ -182,7 +182,7 @@ func TestPromptAssetManifestHashMatchesManifestParts(t *testing.T) {
{FS: moduleFS, Path: "assets/prompts/instructions.md"},
{FS: sharedFS, Path: "prompts/common-dnd-transcript-chunk.md"},
{FS: sharedFS, Path: "prompts/common-dnd-system.md"},
{FS: sharedFS, Path: "prompts/common-dnd-npcs.md"},
{FS: sharedFS, Path: "prompts/common-dnd-npc-registry.md"},
})
if err != nil {
t.Fatalf("HashAssets() with unused asset error = %v, want nil", err)

View File

@@ -11,7 +11,7 @@ import (
"gitea.maximumdirect.net/eric/notarius/internal/framework/contracts"
"gitea.maximumdirect.net/eric/notarius/internal/framework/pipeline"
"gitea.maximumdirect.net/eric/notarius/internal/modules/dnd"
npccodec "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/codec/npcs"
npccodec "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/codec/npcregistry"
"gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/npcs/identity"
npcregistry "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/npcs/registry"
)

View File

@@ -12,7 +12,7 @@ import (
func TestValidatorUsesOnlyCitedTranscriptEvidence(t *testing.T) {
value := validEventList()
references := contracts.ReferenceSet{Slots: map[string]contracts.ResolvedReferenceSlot{"npcs": {Items: []contracts.ReferenceItem{{Content: []byte("Ashfang")}}}}}
references := contracts.ReferenceSet{Slots: map[string]contracts.ResolvedReferenceSlot{"npc_registry": {Items: []contracts.ReferenceItem{{Content: []byte("Ashfang")}}}}}
result, err := New(Options{}).Validate(context.Background(), contracts.TypedValidationRequest[dnd.EnemyEventList]{Source: document("The party waits."), References: references, Value: value})
if err != nil || !result.Approved || len(result.Warnings) != 1 || result.Warnings[0].ReasonCode != WarningReasonCode {
t.Fatalf("Validate() = %#v, %v", result, err)

View File

@@ -11,7 +11,7 @@ import (
"gitea.maximumdirect.net/eric/notarius/internal/framework/contracts"
"gitea.maximumdirect.net/eric/notarius/internal/framework/pipeline"
"gitea.maximumdirect.net/eric/notarius/internal/modules/dnd"
npccodec "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/codec/npcs"
npccodec "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/codec/npcregistry"
"gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/npcs/identity"
npcregistry "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/npcs/registry"
)

View File

@@ -11,7 +11,7 @@ import (
"gitea.maximumdirect.net/eric/notarius/internal/framework/contracts"
"gitea.maximumdirect.net/eric/notarius/internal/framework/pipeline"
"gitea.maximumdirect.net/eric/notarius/internal/modules/dnd"
npccodec "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/codec/npcs"
npccodec "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/codec/npcregistry"
"gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/npcs/identity"
npcregistry "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/npcs/registry"
)

View File

@@ -10,11 +10,11 @@ import (
"gitea.maximumdirect.net/eric/notarius/internal/modules/dnd"
domainidentity "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/npcs/identity"
"gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/shared/diagnostics"
npcshape "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/validate/npcs/shape"
npcshape "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/validate/npcregistry/shape"
)
const (
Key = "normalize/dnd/npcs/identity"
Key = "normalize/dnd/npc-registry/identity"
ReasonCode = "invalid_npc_identity"
policy = domainidentity.Policy
)

View File

@@ -12,9 +12,9 @@ import (
)
const (
Key = "extract/dnd/npcs/shape"
Key = "extract/dnd/npc-registry/shape"
ReasonCode = "invalid_npc_shape"
policy = "dnd.npcs.validator.shape.v1"
policy = "dnd.npc_registry.validator.shape.v1"
)
type Options struct{}

View File

@@ -50,7 +50,7 @@ func TestValidatorBoundsDiagnosticsAndQuotesUnicode(t *testing.T) {
}
func TestValidatorSpecCheckpointAndRegistration(t *testing.T) {
if got := New(Options{}).CheckpointFingerprints(); len(got) != 1 || got[0].Name != "policy" || got[0].Value != "dnd.npcs.validator.shape.v1" {
if got := New(Options{}).CheckpointFingerprints(); len(got) != 1 || got[0].Name != "policy" || got[0].Value != "dnd.npc_registry.validator.shape.v1" {
t.Fatalf("CheckpointFingerprints() = %#v, want local policy", got)
}
if spec := Spec(); spec.Key != Key || spec.ExecutionClass != contracts.ExecutionClassDeterministic {

View File

@@ -9,13 +9,13 @@ import (
"gitea.maximumdirect.net/eric/notarius/internal/framework/pipeline"
"gitea.maximumdirect.net/eric/notarius/internal/modules/dnd"
"gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/shared/diagnostics"
npcshape "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/validate/npcs/shape"
npcshape "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/validate/npcregistry/shape"
)
const (
Key = "extract/dnd/npcs/source_refs"
Key = "extract/dnd/npc-registry/source_refs"
ReasonCode = "invalid_npc_source_refs"
policy = "dnd.npcs.validator.source_refs.v1"
policy = "dnd.npc_registry.validator.source_refs.v1"
)
type Options struct{}

View File

@@ -57,7 +57,7 @@ func TestValidatorBoundsDiagnosticsAndHandlesMissingDocument(t *testing.T) {
}
func TestValidatorSpecCheckpointAndRegistration(t *testing.T) {
if got := New(Options{}).CheckpointFingerprints(); len(got) != 1 || got[0].Name != "policy" || got[0].Value != "dnd.npcs.validator.source_refs.v1" {
if got := New(Options{}).CheckpointFingerprints(); len(got) != 1 || got[0].Name != "policy" || got[0].Value != "dnd.npc_registry.validator.source_refs.v1" {
t.Fatalf("CheckpointFingerprints() = %#v, want local policy", got)
}
if Spec().ExecutionClass != contracts.ExecutionClassDeterministic {

View File

@@ -9,13 +9,13 @@ import (
"gitea.maximumdirect.net/eric/notarius/internal/modules/dnd"
"gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/shared"
"gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/shared/diagnostics"
npcshape "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/validate/npcs/shape"
npcshape "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/validate/npcregistry/shape"
)
const (
Key = "extract/dnd/npcs/source_relatedness"
Key = "extract/dnd/npc-registry/source_relatedness"
WarningReasonCode = "npc_not_near_source"
policy = "dnd.npcs.validator.source_relatedness.v2"
policy = "dnd.npc_registry.validator.source_relatedness.v2"
)
type Options struct{}

View File

@@ -76,7 +76,7 @@ func TestValidatorUsesOnlyTranscriptEvidenceAndRegistersPolicy(t *testing.T) {
if err != nil || len(result.Warnings) != 1 {
t.Fatalf("reference-only relatedness = %#v, %v; want warning", result, err)
}
if got := New(Options{}).CheckpointFingerprints(); len(got) != 1 || got[0].Name != "policy" || got[0].Value != "dnd.npcs.validator.source_relatedness.v2" {
if got := New(Options{}).CheckpointFingerprints(); len(got) != 1 || got[0].Name != "policy" || got[0].Value != "dnd.npc_registry.validator.source_relatedness.v2" {
t.Fatalf("CheckpointFingerprints() = %#v, want local policy", got)
}
if Spec().ExecutionClass != contracts.ExecutionClassDeterministic {

View File

@@ -17,7 +17,7 @@ import (
"gitea.maximumdirect.net/eric/notarius/internal/framework/pipeline"
"gitea.maximumdirect.net/eric/notarius/internal/modules/dnd"
combatcodec "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/codec/combatturns"
npccodec "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/codec/npcs"
npccodec "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/codec/npcregistry"
scenecodec "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/codec/scenedescriptions"
combatextract "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/extract/combatturns"
combatnormalize "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/normalize/combatturns"
@@ -36,8 +36,8 @@ func TestProductionCombatPipelineRetriesMergesNormalizesAndWritesJSON(t *testing
PipelineID: "dnd-combat-fixture",
Catalog: catalog,
ReferenceOverrides: []pipeline.ReferenceBinding{
{Stage: pipeline.StageExtract, LaneID: "combat", SlotName: "npcs", Source: npcPayload.path, BindingSource: contracts.ReferenceBindingSourceCLI},
{Stage: pipeline.StageNormalize, LaneID: "combat", SlotName: "npcs", Source: npcPayload.path, BindingSource: contracts.ReferenceBindingSourceCLI},
{Stage: pipeline.StageExtract, LaneID: "combat", SlotName: "npc_registry", Source: npcPayload.path, BindingSource: contracts.ReferenceBindingSourceCLI},
{Stage: pipeline.StageNormalize, LaneID: "combat", SlotName: "npc_registry", Source: npcPayload.path, BindingSource: contracts.ReferenceBindingSourceCLI},
},
})
if err != nil {
@@ -278,8 +278,8 @@ func TestCombatPreparationRejectsMalformedOrOversizedNPCReferencesBeforeExecutio
PipelineID: "dnd-combat",
Catalog: catalog,
ReferenceOverrides: []pipeline.ReferenceBinding{
{Stage: pipeline.StageExtract, LaneID: "combat", SlotName: "npcs", Source: path, BindingSource: contracts.ReferenceBindingSourceCLI},
{Stage: pipeline.StageNormalize, LaneID: "combat", SlotName: "npcs", Source: path, BindingSource: contracts.ReferenceBindingSourceCLI},
{Stage: pipeline.StageExtract, LaneID: "combat", SlotName: "npc_registry", Source: path, BindingSource: contracts.ReferenceBindingSourceCLI},
{Stage: pipeline.StageNormalize, LaneID: "combat", SlotName: "npc_registry", Source: path, BindingSource: contracts.ReferenceBindingSourceCLI},
},
})
if err != nil {

View File

@@ -19,14 +19,14 @@ import (
"gitea.maximumdirect.net/eric/notarius/internal/framework/pipeline"
"gitea.maximumdirect.net/eric/notarius/internal/modules/dnd"
combatcodec "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/codec/combatturns"
npccodec "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/codec/npcs"
npccodec "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/codec/npcregistry"
scenecodec "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/codec/scenedescriptions"
spellcodec "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/codec/spells"
combatextract "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/extract/combatturns"
"gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/extract/npcs"
"gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/extract/npcregistry"
sceneextract "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/extract/scenedescriptions"
"gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/extract/spells"
npcnormalize "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/normalize/npcs"
npcnormalize "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/normalize/npcregistry"
)
func TestNPCOutputGroundsSpellAndCombatConsumersThroughOneOperation(t *testing.T) {
@@ -49,20 +49,20 @@ func TestNPCOutputGroundsSpellAndCombatConsumersThroughOneOperation(t *testing.T
t.Fatalf("Prepare() error = %v", err)
}
for name, value := range map[string]string{
"extract:npcs:dnd/npcs:mapping_policy": "dnd.npcs.extract_mapping.v2",
"normalize:npcs:dnd/npcs:identity_policy": "dnd.npc_registry.identity.v1",
"normalize:npcs:dnd/npcs:normalization_policy": "dnd.npcs.normalize.v3",
"normalize:npcs:dnd/npcs:semantic_context_policy": "dnd.entity_reconcile.context.v1:2",
"extract:spells:dnd/spells:mapping_policy": "dnd.spells.extract_mapping.v2",
"extract:combat:dnd/combat-turns:scene_gate_policy": "dnd.combat_turns.scene_gate.v1",
"extract:npc_registry:dnd/npc-registry:mapping_policy": "dnd.npc_registry.extract_mapping.v2",
"normalize:npc_registry:dnd/npc-registry:identity_policy": "dnd.npc_registry.identity.v1",
"normalize:npc_registry:dnd/npc-registry:normalization_policy": "dnd.npc_registry.normalize.v3",
"normalize:npc_registry:dnd/npc-registry:semantic_context_policy": "dnd.entity_reconcile.context.v1:2",
"extract:spells:dnd/spells:mapping_policy": "dnd.spells.extract_mapping.v2",
"extract:combat:dnd/combat-turns:scene_gate_policy": "dnd.combat_turns.scene_gate.v1",
} {
assertFingerprintValue(t, prepared.CheckpointFingerprints(), name, value)
}
for _, name := range []string{
"extract:npcs:dnd/npcs:prompt",
"extract:npcs:dnd/npcs:response_schema",
"normalize:npcs:dnd/npcs:prompt",
"normalize:npcs:dnd/npcs:response_schema",
"extract:npc_registry:dnd/npc-registry:prompt",
"extract:npc_registry:dnd/npc-registry:response_schema",
"normalize:npc_registry:dnd/npc-registry:prompt",
"normalize:npc_registry:dnd/npc-registry:response_schema",
"extract:spells:dnd/spells:prompt",
"extract:spells:dnd/spells:response_schema",
"extract:spells:dnd/spells:npc_registry",
@@ -87,14 +87,14 @@ func TestNPCOutputGroundsSpellAndCombatConsumersThroughOneOperation(t *testing.T
if len(output.Rejected) != 0 || len(output.NormalizeOutputs) != 4 {
t.Fatalf("run outputs = %#v rejected = %#v, want NPC, scene, spell, and combat outputs", output.NormalizeOutputs, output.Rejected)
}
wantSchemas := map[string]string{"npcs": npccodec.SchemaID, "scene-descriptions": scenecodec.SchemaID, "spells": spellcodec.SchemaID, "combat": combatcodec.SchemaID}
wantSchemas := map[string]string{"npc_registry": npccodec.SchemaID, "scene-descriptions": scenecodec.SchemaID, "spells": spellcodec.SchemaID, "combat": combatcodec.SchemaID}
for _, serialized := range output.NormalizeOutputs {
if serialized.Artifact.Schema.ID != wantSchemas[serialized.LaneID] || serialized.Artifact.Schema.Version != "v1" {
t.Fatalf("%s artifact schema = %#v, want minimal v1 identity", serialized.LaneID, serialized.Artifact.Schema)
}
}
wantExtractorIdentity := map[string]struct{ promptID, schemaID string }{
"npcs": {npcs.PromptID, npcs.ResponseSchemaID},
"npc_registry": {npcregistry.PromptID, npcregistry.ResponseSchemaID},
"scene-descriptions": {sceneextract.PromptID, sceneextract.ResponseSchemaID},
"spells": {spells.PromptID, spells.ResponseSchemaID},
"combat": {combatextract.PromptID, combatextract.ResponseSchemaID},
@@ -112,13 +112,13 @@ func TestNPCOutputGroundsSpellAndCombatConsumersThroughOneOperation(t *testing.T
for _, serialized := range output.NormalizeOutputs {
seenSteps[serialized.LaneID] = serialized.StepID
switch serialized.LaneID {
case "npcs":
case "npc_registry":
npcPayload = append([]byte(nil), serialized.Artifact.Content...)
case "scene-descriptions":
scenePayload = append([]byte(nil), serialized.Artifact.Content...)
}
}
if seenSteps["npcs"] != "identify-npcs" || seenSteps["scene-descriptions"] != "identify-npcs" || seenSteps["spells"] != "grounded-events" || seenSteps["combat"] != "grounded-events" {
if seenSteps["npc_registry"] != "identify-npcs" || seenSteps["scene-descriptions"] != "identify-npcs" || seenSteps["spells"] != "grounded-events" || seenSteps["combat"] != "grounded-events" {
t.Fatalf("normalized output steps = %#v, want ordered producer and consumer steps", seenSteps)
}
if len(npcPayload) == 0 {
@@ -152,7 +152,7 @@ func TestNPCOutputGroundsSpellAndCombatConsumersThroughOneOperation(t *testing.T
if request.PromptID != spells.PromptID && request.PromptID != combatextract.PromptID {
continue
}
input := request.Inputs["npcs"]
input := request.Inputs["npc_registry"]
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)
}
@@ -182,7 +182,7 @@ func TestNPCOutputGroundsSpellAndCombatConsumersThroughOneOperation(t *testing.T
provenanceCount := 0
for _, reference := range output.Manifest.References {
if reference.SlotName != "npcs" {
if reference.SlotName != "npc_registry" {
continue
}
provenanceCount++
@@ -261,7 +261,7 @@ func TestProductionDNDOutputPublishesSelectedEvidenceContext(t *testing.T) {
configValue := loadGroundedPipelineConfig(t)
profile := configValue.Pipelines["dnd-npc-grounded"]
profile.Output.Options = map[string]any{"evidence_context": map[string]any{
"enabled": true, "window_units": 0, "lanes": []any{"npcs", "spells", "combat"},
"enabled": true, "window_units": 0, "lanes": []any{"npc_registry", "spells", "combat"},
}}
configValue.Pipelines["dnd-npc-grounded"] = profile
raw := strings.NewReplacer(
@@ -277,14 +277,14 @@ func TestProductionDNDOutputPublishesSelectedEvidenceContext(t *testing.T) {
if err != nil {
t.Fatalf("Decode(evidence context) error = %v", err)
}
if !reflect.DeepEqual(value.SelectedLanes, []string{"combat", "npcs", "spells"}) {
if !reflect.DeepEqual(value.SelectedLanes, []string{"combat", "npc_registry", "spells"}) {
t.Fatalf("selected lanes = %#v, want configured production lanes without scene descriptions", value.SelectedLanes)
}
if len(value.Contexts) != 2 || len(value.Contexts[0].Units) != 1 || len(value.Contexts[1].Units) != 1 || value.Contexts[0].Units[0].ID != 10 || value.Contexts[1].Units[0].ID != 20 {
t.Fatalf("evidence contexts = %#v, want source-position union with non-monotonic unit IDs", value.Contexts)
}
firstRefs := value.Contexts[0].EvidenceRefs
if len(firstRefs) != 3 || firstRefs[0].LaneID != "combat" || firstRefs[1].LaneID != "npcs" || firstRefs[2].LaneID != "spells" {
if len(firstRefs) != 3 || firstRefs[0].LaneID != "combat" || firstRefs[1].LaneID != "npc_registry" || firstRefs[2].LaneID != "spells" {
t.Fatalf("first context evidence = %#v, want overlapping selected lane references", firstRefs)
}
for _, context := range value.Contexts {
@@ -538,7 +538,7 @@ func (client *groundedDNDLLMClient) CompleteStructured(ctx context.Context, requ
thirdUnitID = 3
}
switch request.PromptID {
case npcs.PromptID:
case npcregistry.PromptID:
payload = map[string]any{"npcs": []any{
map[string]any{
"name": "Mira Thorn", "source_refs": []any{map[string]int{"start_unit_id": firstUnitID, "end_unit_id": firstUnitID}},

View File

@@ -15,10 +15,10 @@ import (
"gitea.maximumdirect.net/eric/notarius/internal/framework/contracts"
"gitea.maximumdirect.net/eric/notarius/internal/framework/pipeline"
interactioncodec "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/codec/npcinteractions"
npccodec "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/codec/npcs"
npccodec "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/codec/npcregistry"
interactionextract "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/extract/npcinteractions"
"gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/extract/npcs"
npcnormalize "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/normalize/npcs"
"gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/extract/npcregistry"
npcnormalize "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/normalize/npcregistry"
"gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/npcs/identity"
)
@@ -37,11 +37,11 @@ func TestNPCInteractionPipelineUsesAcceptedRegistryAndCurrentEvidence(t *testing
request := client.requestFor(t, interactionextract.PromptID)
wantRegistry := `{"npcs":[{"name":"Mira Thorn"},{"name":"Hooded Guard"}]}`
if got := string(request.Inputs["npcs"].Content); got != wantRegistry {
if got := string(request.Inputs["npc_registry"].Content); got != wantRegistry {
t.Fatalf("interaction registry input = %s, want names-only projection %s", got, wantRegistry)
}
if request.Inputs["npcs"].MediaType != npccodec.MediaType {
t.Fatalf("interaction registry media type = %q, want %q", request.Inputs["npcs"].MediaType, npccodec.MediaType)
if request.Inputs["npc_registry"].MediaType != npccodec.MediaType {
t.Fatalf("interaction registry media type = %q, want %q", request.Inputs["npc_registry"].MediaType, npccodec.MediaType)
}
serialized := normalizedLane(t, output, "interactions")
@@ -94,10 +94,10 @@ func TestSemanticNPCNormalizationCrossesOrderedRegistryHandoff(t *testing.T) {
if err != nil {
t.Fatalf("Run() error = %v", err)
}
if client.requestCount(npcs.PromptID) != 2 || client.requestCount(npcnormalize.PromptID) != 1 {
if client.requestCount(npcregistry.PromptID) != 2 || client.requestCount(npcnormalize.PromptID) != 1 {
t.Fatalf("prompt requests = %#v, want two extraction calls and one document normalization call", client.requests)
}
npcOutput := normalizedLane(t, output, "npcs")
npcOutput := normalizedLane(t, output, "npc_registry")
npcsValue, err := npccodec.New().Decode(npcOutput.Artifact.Content)
if err != nil {
t.Fatal(err)
@@ -113,7 +113,7 @@ func TestSemanticNPCNormalizationCrossesOrderedRegistryHandoff(t *testing.T) {
t.Fatalf("interaction output step = %q, want ordered downstream step", interactionOutput.StepID)
}
registryRequest := client.requestFor(t, interactionextract.PromptID)
if got := string(registryRequest.Inputs["npcs"].Content); got != `{"npcs":[{"name":"Mira Thorn"}]}` {
if got := string(registryRequest.Inputs["npc_registry"].Content); got != `{"npcs":[{"name":"Mira Thorn"}]}` {
t.Fatalf("downstream registry = %s, want one canonical names-only NPC", got)
}
manifestContent, err := json.Marshal(output.Manifest)
@@ -136,8 +136,8 @@ func TestNPCInteractionPipelineSkipsConsumerWhenNPCProducerIsRejected(t *testing
if err == nil {
t.Fatalf("Run() output = %#v, want missing generated NPC producer error", output)
}
if client.requestCount(npcs.PromptID) != 1 {
t.Fatalf("NPC requests = %d, want rejected producer", client.requestCount(npcs.PromptID))
if client.requestCount(npcregistry.PromptID) != 1 {
t.Fatalf("NPC requests = %d, want rejected producer", client.requestCount(npcregistry.PromptID))
}
if client.requestCount(interactionextract.PromptID) != 0 {
t.Fatalf("interaction requests = %d, want none after rejected producer", client.requestCount(interactionextract.PromptID))
@@ -214,7 +214,7 @@ func (client *npcInteractionLLMClient) CompleteStructured(ctx context.Context, r
var payload any
switch request.PromptID {
case npcs.PromptID:
case npcregistry.PromptID:
if client.rejectNPCs {
payload = map[string]any{"npcs": []any{map[string]any{
"name": "", "source_refs": []any{map[string]int{"start_unit_id": 1, "end_unit_id": 1}},
@@ -281,7 +281,7 @@ func (client *semanticNPCInteractionClient) CompleteStructured(_ context.Context
client.requests = append(client.requests, cloneStructuredCompletionRequest(request))
var payload any
switch request.PromptID {
case npcs.PromptID:
case npcregistry.PromptID:
client.npcCalls++
name := "Mira Thorn"
if client.npcCalls == 2 {

View File

@@ -12,14 +12,14 @@ import (
"gitea.maximumdirect.net/eric/notarius/internal/framework/contracts"
"gitea.maximumdirect.net/eric/notarius/internal/framework/llm"
"gitea.maximumdirect.net/eric/notarius/internal/framework/pipeline"
npccodec "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/codec/npcs"
"gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/extract/npcs"
npcnormalize "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/normalize/npcs"
npccodec "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/codec/npcregistry"
"gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/extract/npcregistry"
npcnormalize "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/normalize/npcregistry"
"gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/npcs/identity"
dndregister "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/register"
"gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/shared/entityreconcile"
npcshape "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/validate/npcs/shape"
npcsourcerefs "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/validate/npcs/source_refs"
npcshape "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/validate/npcregistry/shape"
npcregistrysourcerefs "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/validate/npcregistry/source_refs"
genericregister "gitea.maximumdirect.net/eric/notarius/internal/modules/generic/register"
"gitea.maximumdirect.net/eric/notarius/internal/modules/seriatim/input/transcript"
seriatimregister "gitea.maximumdirect.net/eric/notarius/internal/modules/seriatim/register"
@@ -33,7 +33,7 @@ func TestRunnerProcessesSeriatimInputWithProductionDNDNPCPipeline(t *testing.T)
}
registries := productionNPCRegistries(t)
configValue := loadNPCPipelineConfig(t)
effective, err := configValue.Resolve(config.ResolveInput{PipelineID: "dnd-npcs-fixture", Catalog: moduleCatalog(registries)})
effective, err := configValue.Resolve(config.ResolveInput{PipelineID: "dnd-npc-registry-fixture", Catalog: moduleCatalog(registries)})
if err != nil {
t.Fatalf("Resolve() error = %v, want nil", err)
}
@@ -62,7 +62,7 @@ func TestRunnerProcessesSeriatimInputWithProductionDNDNPCPipeline(t *testing.T)
t.Fatalf("normalize outputs = %d, want one NPC output; rejected=%#v", len(output.NormalizeOutputs), output.Rejected)
}
serialized := output.NormalizeOutputs[0]
if serialized.LaneID != "npcs" || serialized.NormalizerKey != npcs.Key || serialized.Artifact.Schema.ID != npccodec.SchemaID || serialized.Artifact.Schema.Version != npccodec.SchemaVersion {
if serialized.LaneID != "npc_registry" || serialized.NormalizerKey != npcregistry.Key || serialized.Artifact.Schema.ID != npccodec.SchemaID || serialized.Artifact.Schema.Version != npccodec.SchemaVersion {
t.Fatalf("serialized output = %#v, want durable NPC lane schema", serialized)
}
value, err := npccodec.New().Decode(serialized.Artifact.Content)
@@ -93,7 +93,7 @@ func TestRunnerProcessesSeriatimInputWithProductionDNDNPCPipeline(t *testing.T)
t.Fatalf("manifest = %#v, want approved NPC lane", output.Manifest)
}
lane := output.Manifest.ArtifactLanes[0]
if lane.ID != "npcs" || lane.Extractor != npcs.Key || lane.Merger != pipeline.DefaultMergeModule || lane.Normalizer != npcs.Key {
if lane.ID != "npc_registry" || lane.Extractor != npcregistry.Key || lane.Merger != pipeline.DefaultMergeModule || lane.Normalizer != npcregistry.Key {
t.Fatalf("manifest lane = %#v, want NPC production composition", lane)
}
normalizerMetadata, ok := lane.Metadata["normalizer"].(map[string]any)
@@ -102,7 +102,7 @@ func TestRunnerProcessesSeriatimInputWithProductionDNDNPCPipeline(t *testing.T)
}
var npcOutputFile *contracts.OutputFile
for index := range output.OutputFiles {
if output.OutputFiles[index].Name == "lanes/npcs.json" {
if output.OutputFiles[index].Name == "lanes/npc_registry.json" {
npcOutputFile = &output.OutputFiles[index]
break
}
@@ -110,7 +110,7 @@ func TestRunnerProcessesSeriatimInputWithProductionDNDNPCPipeline(t *testing.T)
if npcOutputFile == nil || npcOutputFile.ContentType != npccodec.MediaType {
t.Fatalf("output files = %#v, want JSON NPC lane file", output.OutputFiles)
}
if len(client.requests) != 2 || client.requests[0].PromptID != npcs.PromptID || client.requests[1].PromptID != npcnormalize.PromptID {
if len(client.requests) != 2 || client.requests[0].PromptID != npcregistry.PromptID || client.requests[1].PromptID != npcnormalize.PromptID {
t.Fatalf("LLM requests = %#v, want extraction and normalization prompt requests", client.requests)
}
}
@@ -118,7 +118,7 @@ func TestRunnerProcessesSeriatimInputWithProductionDNDNPCPipeline(t *testing.T)
func TestProductionNPCPipelineRoutesSemanticCandidatesToDeterministicValidators(t *testing.T) {
registries := productionNPCRegistries(t)
effective, err := loadNPCPipelineConfig(t).Resolve(config.ResolveInput{
PipelineID: "dnd-npcs-fixture",
PipelineID: "dnd-npc-registry-fixture",
Catalog: moduleCatalog(registries),
})
if err != nil {
@@ -145,14 +145,14 @@ func TestProductionNPCPipelineRoutesSemanticCandidatesToDeterministicValidators(
{
name: "nonpositive unit candidate",
response: []byte(`{"npcs":[{"name":"Mira Thorn","source_refs":[{"start_unit_id":0,"end_unit_id":1}]}]}`),
reasonCode: npcsourcerefs.ReasonCode,
validatorName: npcsourcerefs.Key,
reasonCode: npcregistrysourcerefs.ReasonCode,
validatorName: npcregistrysourcerefs.Key,
},
{
name: "unknown unit candidate",
response: []byte(`{"npcs":[{"name":"Mira Thorn","source_refs":[{"start_unit_id":99,"end_unit_id":99}]}]}`),
reasonCode: npcsourcerefs.ReasonCode,
validatorName: npcsourcerefs.Key,
reasonCode: npcregistrysourcerefs.ReasonCode,
validatorName: npcregistrysourcerefs.Key,
},
} {
t.Run(test.name, func(t *testing.T) {
@@ -194,12 +194,12 @@ func TestProductionNPCNormalizationRetryUsesFinalSafeProposal(t *testing.T) {
} {
t.Run(test.name, func(t *testing.T) {
cfg := loadNPCPipelineConfig(t)
profile := cfg.Pipelines["dnd-npcs-fixture"]
lane := profile.Artifacts["npcs"]
profile := cfg.Pipelines["dnd-npc-registry-fixture"]
lane := profile.Artifacts["npc_registry"]
lane.Normalize.Retries = test.retries
profile.Artifacts["npcs"] = lane
cfg.Pipelines["dnd-npcs-fixture"] = profile
effective, err := cfg.Resolve(config.ResolveInput{PipelineID: "dnd-npcs-fixture", Catalog: moduleCatalog(registries)})
profile.Artifacts["npc_registry"] = lane
cfg.Pipelines["dnd-npc-registry-fixture"] = profile
effective, err := cfg.Resolve(config.ResolveInput{PipelineID: "dnd-npc-registry-fixture", Catalog: moduleCatalog(registries)})
if err != nil {
t.Fatal(err)
}
@@ -243,9 +243,9 @@ func (client *fakeNPCProductionLLMClient) CompleteStructured(_ context.Context,
client.requests = append(client.requests, req)
var content []byte
switch req.PromptID {
case npcs.PromptID:
case npcregistry.PromptID:
if client.rawResponses != nil {
index := client.requestCount(npcs.PromptID) - 1
index := client.requestCount(npcregistry.PromptID) - 1
if index >= len(client.rawResponses) {
return contracts.StructuredCompletionResponse{}, fmt.Errorf("missing fake NPC response %d", index)
}
@@ -325,9 +325,9 @@ func moduleCatalog(registries pipeline.Registries) pipeline.ModuleCatalog {
func loadNPCPipelineConfig(t *testing.T) config.Config {
t.Helper()
data, err := os.ReadFile("testdata/dnd_npcs_pipeline.yml")
data, err := os.ReadFile("testdata/dnd_npc_registry_pipeline.yml")
if err != nil {
t.Fatalf("ReadFile(dnd_npcs_pipeline.yml) error = %v", err)
t.Fatalf("ReadFile(dnd_npc_registry_pipeline.yml) error = %v", err)
}
fileConfig, err := config.ParseFileConfigYAML(data)
if err != nil {

View File

@@ -13,18 +13,18 @@ pipelines:
steps:
- id: identify-npcs
artifacts:
npcs:
extract: dnd/npcs
normalize: dnd/npcs
npc_registry:
extract: dnd/npc-registry
normalize: dnd/npc-registry
scene-descriptions:
extract: dnd/scene-descriptions
normalize: dnd/scene-descriptions
- id: grounded-events
references:
npcs:
npc_registry:
artifact:
step: identify-npcs
lane: npcs
lane: npc_registry
scene_descriptions:
artifact:
step: identify-npcs

View File

@@ -13,15 +13,15 @@ pipelines:
steps:
- id: identify-npcs
artifacts:
npcs:
extract: dnd/npcs
normalize: dnd/npcs
npc_registry:
extract: dnd/npc-registry
normalize: dnd/npc-registry
- id: extract-interactions
references:
npcs:
npc_registry:
artifact:
step: identify-npcs
lane: npcs
lane: npc_registry
artifacts:
interactions:
extract: dnd/npc-interactions

View File

@@ -8,13 +8,13 @@ cache:
debug:
directory: ./notarius-debug
pipelines:
dnd-npcs-fixture:
dnd-npc-registry-fixture:
input: seriatim
chunk: generic
artifacts:
npcs:
npc_registry:
extract:
module: dnd/npcs
module: dnd/npc-registry
retries: 2
normalize: dnd/npcs
normalize: dnd/npc-registry
output: json