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

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,4 +1,4 @@
id: dnd.npcs.normalize id: dnd.npc_registry.normalize
version: "v1" version: "v1"
default_profile: dnd-extraction default_profile: dnd-extraction
inputs: 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 references describe registry provenance and may belong to another session; they
are never evidence for the current transcript. are never evidence for the current transcript.
{{ input "npcs" }} {{ input "npc_registry" }}

View File

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

View File

@@ -298,7 +298,7 @@ output:
enabled: true enabled: true
window_units: 3 window_units: 3
lanes: lanes:
- npcs - npc_registry
- spells - spells
~~~ ~~~
@@ -332,15 +332,15 @@ step:
steps: steps:
- id: describe-session - id: describe-session
artifacts: artifacts:
npcs: npc_registry:
extract: dnd/npcs extract: dnd/npc-registry
normalize: dnd/npcs normalize: dnd/npc-registry
- id: extract-events - id: extract-events
references: references:
npcs: npc_registry:
artifact: artifact:
step: describe-session step: describe-session
lane: npcs lane: npc_registry
artifacts: artifacts:
spells: spells:
extract: dnd/spells extract: dnd/spells
@@ -371,7 +371,7 @@ selected target declares them:
| **glossary** | Optional text campaign glossary. | | **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). | | **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. | | **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. | | **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. | | **combat_turns** | Required normalized combat-turn artifact for enemy-event extraction. |
| **npc_interactions** | Required normalized NPC-interaction 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 | | 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 | | `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 | | `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 | | `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 | | `locations` | `dnd/location-list` | `application/json` | 1,048,576 bytes | location-occurrence extract and normalize |
Scene descriptions accept **party**, **players**, and **glossary**, but not 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 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 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 The [complete example](../examples/dnd-complete.config.yml) shows the ordered
generated bindings. generated bindings.
@@ -404,9 +404,9 @@ generated bindings.
| --- | --- | | --- | --- |
| Input | **seriatim** | | Input | **seriatim** |
| Chunk | **generic**, **dnd/scenes** | | 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** | | 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** | | Output | **json** |
`dnd/locations` extraction and normalization are `llm_backed`; location `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: The D&D artifact contracts define each emitted schema:
[spells](integrations/dnd-spell-artifacts.md), [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), [NPC interactions](integrations/dnd-npc-interaction-artifacts.md),
[combat turns](integrations/dnd-combat-turn-artifacts.md), [combat turns](integrations/dnd-combat-turn-artifacts.md),
[item events](integrations/dnd-item-event-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** | | 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** | | 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** | | 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** | | 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** | | 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 | | 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 | | 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 | | 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 | | 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 | | 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 become turn evidence. No exact matching scene also produces an empty list and
the `scene_classification_unavailable` warning. 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. actor name. Its registry references are provenance, never combat evidence.
Normalization trims and, where possible, canonicalizes actor names; orders and Normalization trims and, where possible, canonicalizes actor names; orders and
deduplicates exact source references; orders valid-evidence turns by source deduplicates exact source references; orders valid-evidence turns by source

View File

@@ -65,7 +65,7 @@ for uncertain classification.
## Identity, evidence, and order ## 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 Registry references are provenance only and never replace an interaction's own
evidence. Normalization canonicalizes recognized registry names, orders and evidence. Normalization canonicalizes recognized registry names, orders and
deduplicates exact source references, then orders interactions by valid source deduplicates exact source references, then orders interactions by valid source

View File

@@ -1,6 +1,6 @@
# D&D NPC Registry Artifact # 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 minimal, source-grounded identity registry for other D&D artifacts, not a
character sheet or a relationship summary. 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 whitespace-insensitive caster identity, and the same complete valid reference
sequence. Remaining entries retain their merged order. 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 caster name. Its own references remain registry provenance and are never copied
into `source_refs`. into `source_refs`.

View File

@@ -36,7 +36,7 @@ evidence publishes `contexts: []`.
"source_id": "session-alpha", "source_id": "session-alpha",
"source_digest": "sha256:0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef", "source_digest": "sha256:0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef",
"window_units": 1, "window_units": 1,
"selected_lanes": ["npcs", "spells"], "selected_lanes": ["npc_registry", "spells"],
"contexts": [ "contexts": [
{ {
"context_ref": { "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 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 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 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), [NPC interactions](dnd-npc-interaction-artifacts.md),
[combat turns](dnd-combat-turn-artifacts.md), [combat turns](dnd-combat-turn-artifacts.md),
[item events](dnd-item-event-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 | | Lane | Durable contract |
| --- | --- | | --- | --- |
| Spells | [spell artifacts](../integrations/dnd-spell-artifacts.md) | | 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) | | Combat turns | [combat-turn artifacts](../integrations/dnd-combat-turn-artifacts.md) |
| Item events | [item-event artifacts](../integrations/dnd-item-event-artifacts.md) | | Item events | [item-event artifacts](../integrations/dnd-item-event-artifacts.md) |
| NPC interactions | [NPC-interaction artifacts](../integrations/dnd-npc-interaction-artifacts.md) | | NPC interactions | [NPC-interaction artifacts](../integrations/dnd-npc-interaction-artifacts.md) |

View File

@@ -38,7 +38,7 @@ pipelines:
- item-events - item-events
- locations - locations
- location-occurrences - location-occurrences
- npcs - npc_registry
- spells - spells
- combat-turns - combat-turns
- npc-interactions - npc-interactions
@@ -53,13 +53,13 @@ pipelines:
retries: 2 retries: 2
merge: appendorder merge: appendorder
normalize: dnd/item-events normalize: dnd/item-events
npcs: npc_registry:
extract: extract:
module: dnd/npcs module: dnd/npc-registry
retries: 2 retries: 2
merge: appendorder merge: appendorder
normalize: normalize:
module: dnd/npcs module: dnd/npc-registry
retries: 2 retries: 2
locations: locations:
extract: extract:
@@ -83,10 +83,10 @@ pipelines:
artifact: artifact:
step: describe-session step: describe-session
lane: locations lane: locations
npcs: npc_registry:
artifact: artifact:
step: describe-session step: describe-session
lane: npcs lane: npc_registry
scene_descriptions: scene_descriptions:
artifact: artifact:
step: describe-session step: describe-session
@@ -124,10 +124,10 @@ pipelines:
normalize: dnd/location-occurrences normalize: dnd/location-occurrences
- id: track-enemies - id: track-enemies
references: references:
npcs: npc_registry:
artifact: artifact:
step: describe-session step: describe-session
lane: npcs lane: npc_registry
scene_descriptions: scene_descriptions:
artifact: artifact:
step: describe-session 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" { if !ok || codecSpec.Schema.ID != "notarius.dnd.combat_turns" || codecSpec.Schema.Version != "v1" {
t.Fatalf("combat codec spec = %#v, want compatible durable schema", codecSpec) 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) 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") sceneSlot := referenceSlot(extractSpec.ReferenceSlots, "scene_descriptions")
@@ -85,15 +85,15 @@ func TestProductionCombatConfigurationResolvesTypedLane(t *testing.T) {
PipelineID: "dnd-combat", PipelineID: "dnd-combat",
Catalog: catalog, Catalog: catalog,
ReferenceOverrides: []pipeline.ReferenceBinding{ ReferenceOverrides: []pipeline.ReferenceBinding{
{Stage: pipeline.StageExtract, 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: "npcs", Source: "npc-run/lanes/npcs.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 { if err != nil {
t.Fatalf("Resolve(bound references) error = %v, want nil", err) t.Fatalf("Resolve(bound references) error = %v, want nil", err)
} }
boundLane := bound.ResolvedPipeline.Steps[0].ArtifactLanes[0] 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) 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" locationoccurrences "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/extract/locationoccurrences"
locations "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/extract/locations" locations "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/extract/locations"
npcinteractions "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/extract/npcinteractions" 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" scenedescriptions "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/extract/scenedescriptions"
"gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/extract/spells" "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/extract/spells"
enemyeventnormalize "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/normalize/enemyevents" enemyeventnormalize "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/normalize/enemyevents"
locationnormalize "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/normalize/locations" 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) { 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) t.Fatalf("enemy event lane = %#v, want typed production composition", lane)
} }
for slot, want := range map[string]struct{ step, lane string }{ 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"}, "scene_descriptions": {step: "describe-session", lane: "scene-descriptions"},
"combat_turns": {step: "extract-events", lane: "combat-turns"}, "combat_turns": {step: "extract-events", lane: "combat-turns"},
"npc_interactions": {step: "extract-events", lane: "npc-interactions"}, "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) 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) 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"}) { 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) 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) { if !hasReferenceSlot(extractSpec.ReferenceSlots, slot) {
t.Fatalf("enemy event extractor slots = %#v, want %q", 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) t.Fatalf("enemy event normalizer slots = %#v, want NPC registry", normalizeSpec.ReferenceSlots)
} }
profile := cfg.Pipelines["dnd-session"] 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 cfg.Pipelines["dnd-session"] = profile
if _, err := cfg.Resolve(resolveInputForMaintainedExample(components, "dnd-session")); err == nil || !strings.Contains(err.Error(), "earlier step") { 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) 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) t.Fatalf("enemy event session = %q, want shared session", request.SessionID)
} }
for slot, required := range map[string]string{ for slot, required := range map[string]string{
"npcs": "Kesh", "npc_registry": "Kesh",
"combat_turns": "Kesh", "combat_turns": "Kesh",
"npc_interactions": "Kesh", "npc_interactions": "Kesh",
} { } {
@@ -229,7 +229,7 @@ func (client *enemyEventLLMClient) CompleteStructured(ctx context.Context, reque
switch request.PromptID { switch request.PromptID {
case scenes.PromptID: case scenes.PromptID:
content = []byte(`{"scenes":[{"start_unit_id":1,"end_unit_id":6},{"start_unit_id":7,"end_unit_id":11}]}`) 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 { if combatScene {
content = []byte(`{"npcs":[{"name":"Kesh","source_refs":[{"start_unit_id":7,"end_unit_id":7}]}]}`) content = []byte(`{"npcs":[{"name":"Kesh","source_refs":[{"start_unit_id":7,"end_unit_id":7}]}]}`)
} else { } else {

View File

@@ -10,14 +10,14 @@ import (
"gitea.maximumdirect.net/eric/notarius/internal/modules/dnd" "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd"
interactioncodec "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/codec/npcinteractions" interactioncodec "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/codec/npcinteractions"
interactionextract "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/extract/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" 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) { func TestProductionNPCInteractionPipelineResolvesAndPrepares(t *testing.T) {
components := productionTestComponents(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 { if err != nil {
t.Fatalf("ResolvePipeline() error = %v", err) t.Fatalf("ResolvePipeline() error = %v", err)
} }
@@ -29,7 +29,7 @@ func TestProductionNPCInteractionPipelineResolvesAndPrepares(t *testing.T) {
t.Fatalf("interaction lane = %#v", lane) t.Fatalf("interaction lane = %#v", lane)
} }
for _, bindings := range [][]pipeline.ReferenceBinding{lane.ExtractReferences.Bindings, lane.NormalizeReferences.Bindings} { 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) t.Fatalf("generated bindings = %#v", bindings)
} }
} }
@@ -47,14 +47,14 @@ func TestProductionNPCInteractionPipelineResolvesAndPrepares(t *testing.T) {
func TestProductionNPCInteractionReferencesRequireEarlierCompatibleProducer(t *testing.T) { func TestProductionNPCInteractionReferencesRequireEarlierCompatibleProducer(t *testing.T) {
components := productionTestComponents(t) components := productionTestComponents(t)
catalog := catalogFromRegistries(components.registries) 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].ID = "seed"
laterProfile.Steps[0].Artifacts["seed"] = laterProfile.Steps[0].Artifacts["npcs"] laterProfile.Steps[0].Artifacts["seed"] = laterProfile.Steps[0].Artifacts["npc_registry"]
delete(laterProfile.Steps[0].Artifacts, "npcs") delete(laterProfile.Steps[0].Artifacts, "npc_registry")
laterProfile.Steps = append(laterProfile.Steps, pipeline.PipelineStepProfile{ID: "future", Artifacts: map[string]pipeline.ArtifactLaneProfile{ 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 { tests := []struct {
name string name string
profile pipeline.PipelineProfile profile pipeline.PipelineProfile
@@ -63,9 +63,9 @@ func TestProductionNPCInteractionReferencesRequireEarlierCompatibleProducer(t *t
{name: "missing", profile: npcInteractionProfile(pipeline.ReferenceSource{}), want: "source must not be empty"}, {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: "same step", profile: npcInteractionProfile(pipeline.GeneratedReference("interactions", "interactions")), want: "earlier step"},
{name: "later step", profile: laterProfile, 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 { for _, test := range tests {
t.Run(test.name, func(t *testing.T) { t.Run(test.name, func(t *testing.T) {
_, err := pipeline.ResolvePipeline(test.profile, pipeline.ResolveOptions{}, catalog) _, 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}}, Chunk: pipeline.ModuleBinding{Module: "generic", Options: map[string]any{"max_units": 1}},
Output: pipeline.Binding("json"), Output: pipeline.Binding("json"),
Steps: []pipeline.PipelineStepProfile{ Steps: []pipeline.PipelineStepProfile{
{ID: "npcs", Artifacts: map[string]pipeline.ArtifactLaneProfile{ {ID: "npc-registry", 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)},
}}, }},
{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)}, "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/core/config"
"gitea.maximumdirect.net/eric/notarius/internal/framework/pipeline" "gitea.maximumdirect.net/eric/notarius/internal/framework/pipeline"
"gitea.maximumdirect.net/eric/notarius/internal/modules/dnd" "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"
npcextract "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/extract/npcs" npcextract "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/extract/npcregistry"
npcnormalize "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/normalize/npcs" npcnormalize "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/normalize/npcregistry"
) )
func TestProductionNPCConfigurationResolvesTypedLane(t *testing.T) { 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) t.Fatalf("artifact lanes = %#v, want one NPC lane", effective.ResolvedPipeline.Steps[0].ArtifactLanes)
} }
lane := effective.ResolvedPipeline.Steps[0].ArtifactLanes[0] 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) t.Fatalf("resolved NPC lane = %#v, want typed production composition", lane)
} }
if len(lane.ExtractReferences.Bindings) != 0 || len(lane.NormalizeReferences.Bindings) != 0 { 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) 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) t.Fatalf("NPC extractor spec = %#v, want source and artifact capabilities", extractSpec)
} }
mergeSpec, ok := catalog.Mergers.SpecForArtifact(pipeline.DefaultMergeModule, dnd.NPCRegistryKind) mergeSpec, ok := catalog.Mergers.SpecForArtifact(pipeline.DefaultMergeModule, dnd.NPCRegistryKind)
@@ -54,18 +54,18 @@ func TestProductionNPCConfigurationResolvesTypedLane(t *testing.T) {
wantExtractChain := []pipeline.ModuleBinding{ wantExtractChain := []pipeline.ModuleBinding{
pipeline.Binding("generic/valid_json"), pipeline.Binding("generic/valid_json"),
pipeline.Binding("extract/dnd/npcs/shape"), pipeline.Binding("extract/dnd/npc-registry/shape"),
pipeline.Binding("extract/dnd/npcs/source_refs"), pipeline.Binding("extract/dnd/npc-registry/source_refs"),
pipeline.Binding("generic/valid_json_schema"), pipeline.Binding("generic/valid_json_schema"),
pipeline.Binding("extract/dnd/npcs/source_relatedness"), pipeline.Binding("extract/dnd/npc-registry/source_relatedness"),
} }
wantNormalizeChain := []pipeline.ModuleBinding{ wantNormalizeChain := []pipeline.ModuleBinding{
pipeline.Binding("generic/valid_json"), pipeline.Binding("generic/valid_json"),
pipeline.Binding("extract/dnd/npcs/shape"), pipeline.Binding("extract/dnd/npc-registry/shape"),
pipeline.Binding("normalize/dnd/npcs/identity"), pipeline.Binding("normalize/dnd/npc-registry/identity"),
pipeline.Binding("extract/dnd/npcs/source_refs"), pipeline.Binding("extract/dnd/npc-registry/source_refs"),
pipeline.Binding("generic/valid_json_schema"), 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) { if got := validatorChain(effective.ResolvedPipeline, pipeline.StageExtract, npcextract.Key); !reflect.DeepEqual(got, wantExtractChain) {
t.Fatalf("NPC extract chain = %#v, want %#v", 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) { if err := resolve(func(profile *pipeline.PipelineProfile) {
lane := profile.Artifacts["npcs"] lane := profile.Artifacts["npc_registry"]
lane.Extract.Options = map[string]any{"unexpected": true} 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") { }); err == nil || !strings.Contains(err.Error(), "unknown option") {
t.Fatalf("unknown extractor option error = %v, want strict option rejection", err) t.Fatalf("unknown extractor option error = %v, want strict option rejection", err)
} }
if err := resolve(func(profile *pipeline.PipelineProfile) { if err := resolve(func(profile *pipeline.PipelineProfile) {
lane := profile.Artifacts["npcs"] lane := profile.Artifacts["npc_registry"]
lane.Normalize.Options = map[string]any{"unexpected": true} 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") { }); err == nil || !strings.Contains(err.Error(), "unknown option") {
t.Fatalf("unknown normalizer option error = %v, want strict option rejection", err) 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) t.Fatalf("optional NPC references error = %v, want resolution success", err)
} }
if err := resolve(func(profile *pipeline.PipelineProfile) { if err := resolve(func(profile *pipeline.PipelineProfile) {
lane := profile.Artifacts["npcs"] lane := profile.Artifacts["npc_registry"]
lane.Validators = []pipeline.ModuleBinding{pipeline.Binding("normalize/dnd/npcs/identity")} lane.Validators = []pipeline.ModuleBinding{pipeline.Binding("normalize/dnd/npc-registry/identity")}
profile.Artifacts["npcs"] = lane profile.Artifacts["npc_registry"] = lane
}); err == nil || !strings.Contains(err.Error(), "artifact lane level") { }); err == nil || !strings.Contains(err.Error(), "artifact lane level") {
t.Fatalf("lane-level validator error = %v, want invalid placement rejection", err) t.Fatalf("lane-level validator error = %v, want invalid placement rejection", err)
} }
@@ -128,7 +128,7 @@ func productionNPCContractConfig() config.Config {
Input: pipeline.Binding("seriatim"), Input: pipeline.Binding("seriatim"),
Chunk: pipeline.Binding(pipeline.DefaultChunkModule), Chunk: pipeline.Binding(pipeline.DefaultChunkModule),
Artifacts: map[string]pipeline.ArtifactLaneProfile{ Artifacts: map[string]pipeline.ArtifactLaneProfile{
"npcs": { "npc_registry": {
Extract: pipeline.ModuleBinding{Module: npcextract.Key, Retries: 2}, Extract: pipeline.ModuleBinding{Module: npcextract.Key, Retries: 2},
Normalize: pipeline.Binding(npcnormalize.Key), 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) t.Fatalf("materialize maintained example references for %q: %v", pipelineID, err)
} }
if example.name == "complete" { 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) t.Fatalf("complete example steps and lanes = %v, want the documented D&D extractor composition", got)
} }
locationLane := referenceContractLane(t, materialized, "locations") locationLane := referenceContractLane(t, materialized, "locations")
@@ -90,7 +90,7 @@ func TestMaintainedExamplesLoadResolveAndList(t *testing.T) {
} }
itemEventLane := referenceContractLane(t, materialized, "item-events") itemEventLane := referenceContractLane(t, materialized, "item-events")
for _, references := range []pipeline.ResolvedReferenceTarget{itemEventLane.ExtractReferences, itemEventLane.NormalizeReferences} { 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) t.Fatalf("item event lane unexpectedly depends on generated NPCs: %#v", itemEventLane)
} }
if _, found := references.ReferenceSet.Slots["scene_descriptions"]; found { if _, found := references.ReferenceSet.Slots["scene_descriptions"]; found {
@@ -99,7 +99,7 @@ func TestMaintainedExamplesLoadResolveAndList(t *testing.T) {
} }
enemyEventLane := referenceContractLane(t, materialized, "enemy-events") enemyEventLane := referenceContractLane(t, materialized, "enemy-events")
for slot, want := range map[string]struct{ step, lane string }{ 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"}, "scene_descriptions": {step: "describe-session", lane: "scene-descriptions"},
"combat_turns": {step: "extract-events", lane: "combat-turns"}, "combat_turns": {step: "extract-events", lane: "combat-turns"},
"npc_interactions": {step: "extract-events", lane: "npc-interactions"}, "npc_interactions": {step: "extract-events", lane: "npc-interactions"},

View File

@@ -38,7 +38,7 @@ pipelines:
extract: extract:
module: dnd/spells module: dnd/spells
references: references:
npcs: %q npc_registry: %q
normalize: dnd/spells normalize: dnd/spells
`, checkpointRoot, npcPath) `, checkpointRoot, npcPath)
configPath := filepath.Join(t.TempDir(), "config.yml") configPath := filepath.Join(t.TempDir(), "config.yml")
@@ -66,7 +66,7 @@ pipelines:
"--input", repositoryPath("examples", "seriatim-minimal-transcript.json"), "--input", repositoryPath("examples", "seriatim-minimal-transcript.json"),
"--chunk_cache", "bypass", "--output-dir", t.TempDir(), "--chunk_cache", "bypass", "--output-dir", t.TempDir(),
}, &stdout, &stderr, options) }, &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) { if code == 0 || !strings.Contains(stderr.String(), fragment) {
t.Fatalf("RunWithOptions() code = %d stderr = %q, want context fragment %q", code, 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, "inputs", registries.Inputs.RegisteredKeys(), []string{"seriatim"})
assertProductionContains(t, "chunkers", registries.Chunkers.RegisteredKeys(), []string{"dnd/scenes", "generic"}) 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, "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, "outputs", registries.Outputs.RegisteredKeys(), []string{"json"})
assertProductionContains(t, "validators", registries.Validators.RegisteredKeys(), []string{ assertProductionContains(t, "validators", registries.Validators.RegisteredKeys(), []string{
"extract/dnd/spells/catalog", "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: "generic", want: contracts.ExecutionClassDeterministic},
{stage: pipeline.StageChunk, key: "dnd/scenes", want: contracts.ExecutionClassLLMBacked}, {stage: pipeline.StageChunk, key: "dnd/scenes", want: contracts.ExecutionClassLLMBacked},
{stage: pipeline.StageExtract, key: "dnd/spells", 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/combat-turns", want: contracts.ExecutionClassLLMBacked},
{stage: pipeline.StageExtract, key: "dnd/item-events", want: contracts.ExecutionClassLLMBacked}, {stage: pipeline.StageExtract, key: "dnd/item-events", want: contracts.ExecutionClassLLMBacked},
{stage: pipeline.StageExtract, key: "dnd/npc-interactions", 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.StageMerge, key: "appendorder", want: contracts.ExecutionClassDeterministic},
{stage: pipeline.StageNormalize, key: "noop", 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/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/combat-turns", want: contracts.ExecutionClassDeterministic},
{stage: pipeline.StageNormalize, key: "dnd/item-events", want: contracts.ExecutionClassDeterministic}, {stage: pipeline.StageNormalize, key: "dnd/item-events", want: contracts.ExecutionClassDeterministic},
{stage: pipeline.StageNormalize, key: "dnd/npc-interactions", want: contracts.ExecutionClassDeterministic}, {stage: pipeline.StageNormalize, key: "dnd/npc-interactions", want: contracts.ExecutionClassDeterministic},

View File

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

View File

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

View File

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

View File

@@ -12,7 +12,7 @@ import (
"gitea.maximumdirect.net/eric/notarius/internal/framework/contracts" "gitea.maximumdirect.net/eric/notarius/internal/framework/contracts"
"gitea.maximumdirect.net/eric/notarius/internal/framework/pipeline" "gitea.maximumdirect.net/eric/notarius/internal/framework/pipeline"
"gitea.maximumdirect.net/eric/notarius/internal/modules/dnd" "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" scenecodec "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/codec/scenedescriptions"
"gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/npcs/identity" "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-identity.md",
"common-dnd-transcript-chunk.md", "common-dnd-transcript-chunk.md",
"common-dnd-references.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{ prepared, err := engine.Prepare(context.Background(), promptkit.RunRequest{
PromptID: PromptID, PromptVersion: SchemaVersion, ProfileID: "combat-test-profile", PromptID: PromptID, PromptVersion: SchemaVersion, ProfileID: "combat-test-profile",
Inputs: map[string]promptkit.ArtifactRef{ Inputs: map[string]promptkit.ArtifactRef{
"transcript": promptkit.InlineWithURI("file:///session.json", transcript), "transcript": promptkit.InlineWithURI("file:///session.json", transcript),
"players": promptkit.Inline("combat-player"), "players": promptkit.Inline("combat-player"),
"party": promptkit.Inline(" "), "party": promptkit.Inline(" "),
"glossary": promptkit.Inline(" "), "glossary": promptkit.Inline(" "),
"npcs": promptkit.Inline(`{"npcs":[{"name":"combat-npc"}]}`), "npc_registry": promptkit.Inline(`{"npcs":[{"name":"combat-npc"}]}`),
}, },
}) })
if err != nil { if err != nil {

View File

@@ -16,7 +16,7 @@ import (
"gitea.maximumdirect.net/eric/notarius/internal/modules/dnd" "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd"
combatturncodec "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/codec/combatturns" combatturncodec "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/codec/combatturns"
interactioncodec "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/codec/npcinteractions" 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" scenecodec "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/codec/scenedescriptions"
npcregistry "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/npcs/registry" npcregistry "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/npcs/registry"
sceneregistry "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/scenedescriptions/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" "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd"
combatturncodec "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/codec/combatturns" combatturncodec "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/codec/combatturns"
interactioncodec "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/codec/npcinteractions" 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" scenecodec "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/codec/scenedescriptions"
"gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/npcs/identity" "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/npcs/identity"
sceneregistry "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/scenedescriptions/registry" 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-identity.md",
"common-dnd-transcript-chunk.md", "common-dnd-transcript-chunk.md",
"common-dnd-references.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) { func TestEnemyEventPromptRequiresGroundingInputs(t *testing.T) {
engine := newEnemyEventPromptEngine(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) { t.Run(inputName, func(t *testing.T) {
inputs := enemyEventPromptInputs() inputs := enemyEventPromptInputs()
delete(inputs, inputName) delete(inputs, inputName)
@@ -83,7 +83,7 @@ func enemyEventPromptInputs() map[string]promptkit.ArtifactRef {
"players": promptkit.Inline("enemy-player"), "players": promptkit.Inline("enemy-player"),
"party": promptkit.Inline("enemy-party"), "party": promptkit.Inline("enemy-party"),
"glossary": promptkit.Inline("enemy-glossary"), "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"}]}`), "combat_turns": promptkit.Inline(`{"combat_turns":[{"actor":"enemy-turn","turn_kind":"turn"}]}`),
"npc_interactions": promptkit.Inline(`{"npc_interactions":[{"name":"enemy-opponent","kind":"combat_opponent"}]}`), "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")}}}, "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")}}}, "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")}}}, "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 { if _, err := newExtractor(t, client).Extract(context.Background(), req); err != nil {
t.Fatal(err) 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/contracts"
"gitea.maximumdirect.net/eric/notarius/internal/framework/pipeline" "gitea.maximumdirect.net/eric/notarius/internal/framework/pipeline"
"gitea.maximumdirect.net/eric/notarius/internal/modules/dnd" "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/identity"
) )

View File

@@ -25,7 +25,7 @@ var promptAssetManifest = shared.PromptAssetManifest{
"common-dnd-identity.md", "common-dnd-identity.md",
"common-dnd-transcript-chunk.md", "common-dnd-transcript-chunk.md",
"common-dnd-references.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{ prepared, err := engine.Prepare(context.Background(), promptkit.RunRequest{
PromptID: PromptID, PromptVersion: SchemaVersion, ProfileID: "npc-interactions-test-profile", PromptID: PromptID, PromptVersion: SchemaVersion, ProfileID: "npc-interactions-test-profile",
Inputs: map[string]promptkit.ArtifactRef{ Inputs: map[string]promptkit.ArtifactRef{
"transcript": promptkit.InlineWithURI("file:///session.json", transcript), "transcript": promptkit.InlineWithURI("file:///session.json", transcript),
"players": promptkit.Inline("interaction-player"), "players": promptkit.Inline("interaction-player"),
"party": promptkit.Inline("Mira: ranger"), "party": promptkit.Inline("Mira: ranger"),
"glossary": promptkit.Inline("Greencloak: title"), "glossary": promptkit.Inline("Greencloak: title"),
"npcs": promptkit.Inline(`{"npcs":[{"name":"interaction-npc"}]}`), "npc_registry": promptkit.Inline(`{"npcs":[{"name":"interaction-npc"}]}`),
}, },
}) })
if err != nil { if err != nil {

View File

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

View File

@@ -1,4 +1,4 @@
package npcs package npcregistry
import ( import (
"context" "context"
@@ -11,9 +11,9 @@ import (
"gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/shared" "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{ var requiredCapabilities = []string{
"chunks", "chunks",
@@ -21,7 +21,7 @@ var requiredCapabilities = []string{
} }
var providedCapabilities = []string{ var providedCapabilities = []string{
"dnd.npcs", "dnd.npc_registry",
} }
var referenceSlotDescriptions = shared.ReferenceSlotDescriptions{ var referenceSlotDescriptions = shared.ReferenceSlotDescriptions{
@@ -166,5 +166,5 @@ func DecodeOptions(options map[string]any) (Options, error) {
} }
func extractorErrorf(format string, args ...any) 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 ( import (
"context" "context"
@@ -188,13 +188,13 @@ func TestExtractRetainsLocalErrorContextAndProviderFailures(t *testing.T) {
{name: "wrapped preflight failure", extractor: extractor, req: mismatchedSourceInputRequest(request), want: "must match chunk"}, {name: "wrapped preflight failure", extractor: extractor, req: mismatchedSourceInputRequest(request), want: "must match chunk"},
} { } {
t.Run(test.name, func(t *testing.T) { 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) t.Fatalf("Extract() error = %v, want contextual local error", err)
} }
}) })
} }
_, err := newExtractor(t, &fakeNPCsLLMClient{err: errors.New("provider unavailable")}).Extract(context.Background(), request) _, 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) t.Fatalf("provider Extract() error = %v, want contextual provider error", err)
} }
} }

View File

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

View File

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

View File

@@ -1,4 +1,4 @@
package npcs package npcregistry
import ( import (
"context" "context"
@@ -39,7 +39,7 @@ func TestRegisterPromptAssetsAndPrepareNPCPrompt(t *testing.T) {
if err != nil { if err != nil {
t.Fatalf("Prepare() error = %v, want nil", err) 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) t.Fatalf("prepared prompt = %#v, want NPC prompt identity and wiring", prepared)
} }
} }
@@ -54,7 +54,7 @@ func TestPromptMetadataAndDiagnosticsDoNotContainRawAssets(t *testing.T) {
if err != nil { if err != nil {
t.Fatal(err) 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) { if strings.Contains(string(payload), forbidden) {
t.Fatalf("metadata leaked raw prompt/schema content %q: %s", forbidden, payload) t.Fatalf("metadata leaked raw prompt/schema content %q: %s", forbidden, payload)
} }

View File

@@ -1,4 +1,4 @@
package npcs package npcregistry
import ( import (
"reflect" "reflect"
@@ -29,7 +29,7 @@ func TestModuleSpecAndReferenceSlots(t *testing.T) {
Stage: pipeline.StageExtract, Stage: pipeline.StageExtract,
ExecutionClass: contracts.ExecutionClassLLMBacked, ExecutionClass: contracts.ExecutionClassLLMBacked,
Requires: []string{"chunks", "source.transcript"}, Requires: []string{"chunks", "source.transcript"},
Provides: []string{"dnd.npcs"}, Provides: []string{"dnd.npc_registry"},
ArtifactKind: dnd.NPCRegistryKind, ArtifactKind: dnd.NPCRegistryKind,
ReferenceSlots: []contracts.ReferenceSlot{ 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"}}, {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" import "gitea.maximumdirect.net/eric/notarius/internal/framework/llm"
const ( const (
PromptID = "dnd.npcs" PromptID = "dnd.npc_registry"
ResponseSchemaKey = llm.ResponseSchemaKey("dnd_npcs_llm") ResponseSchemaKey = llm.ResponseSchemaKey("dnd_npc_registry_llm")
ResponseSchemaID = "notarius.dnd.npcs.llm" ResponseSchemaID = "notarius.dnd.npc_registry.llm"
ResponseSchemaName = "notarius_dnd_npcs_llm_v1" ResponseSchemaName = "notarius_dnd_npc_registry_llm_v1"
SchemaVersion = "v1" SchemaVersion = "v1"
) )
@@ -20,6 +20,6 @@ func loadResponseSchema() (llm.ResponseSchema, error) {
ID: ResponseSchemaID, ID: ResponseSchemaID,
Version: SchemaVersion, Version: SchemaVersion,
Name: ResponseSchemaName, 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 ( import (
"bytes" "bytes"

View File

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

View File

@@ -11,7 +11,7 @@ import (
"gitea.maximumdirect.net/eric/notarius/internal/framework/contracts" "gitea.maximumdirect.net/eric/notarius/internal/framework/contracts"
"gitea.maximumdirect.net/eric/notarius/internal/framework/pipeline" "gitea.maximumdirect.net/eric/notarius/internal/framework/pipeline"
"gitea.maximumdirect.net/eric/notarius/internal/modules/dnd" "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/identity"
"gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/npcs/registry" "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-identity.md",
"common-dnd-transcript-chunk.md", "common-dnd-transcript-chunk.md",
"common-dnd-references.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{ Inputs: map[string]promptkit.ArtifactRef{
"transcript": promptkit.InlineWithURI("file:///session.json", string(transcript)), "transcript": promptkit.InlineWithURI("file:///session.json", string(transcript)),
"spell_catalog": promptkit.Inline(`{"spell_names":["spell-catalog-sentinel"]}`), "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), "players": promptkit.Inline(players),
"party": promptkit.Inline(party), "party": promptkit.Inline(party),
"glossary": promptkit.Inline(glossary), "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/contracts"
"gitea.maximumdirect.net/eric/notarius/internal/framework/pipeline" "gitea.maximumdirect.net/eric/notarius/internal/framework/pipeline"
"gitea.maximumdirect.net/eric/notarius/internal/modules/dnd" "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/identity"
) )

View File

@@ -11,7 +11,7 @@ import (
"gitea.maximumdirect.net/eric/notarius/internal/framework/contracts" "gitea.maximumdirect.net/eric/notarius/internal/framework/contracts"
"gitea.maximumdirect.net/eric/notarius/internal/framework/pipeline" "gitea.maximumdirect.net/eric/notarius/internal/framework/pipeline"
"gitea.maximumdirect.net/eric/notarius/internal/modules/dnd" "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/identity"
"gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/shared/diagnostics" "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/contracts"
"gitea.maximumdirect.net/eric/notarius/internal/framework/pipeline" "gitea.maximumdirect.net/eric/notarius/internal/framework/pipeline"
"gitea.maximumdirect.net/eric/notarius/internal/modules/dnd" "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/identity"
"gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/shared/diagnostics" "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 npcregistry normalizes merged D&D non-player character records.
package npcs package npcregistry
import ( import (
"context" "context"
@@ -21,9 +21,9 @@ import (
) )
const ( const (
Key = "dnd/npcs" Key = "dnd/npc-registry"
PromptID = "dnd.npcs.normalize" PromptID = "dnd.npc_registry.normalize"
normalizationPolicy = "dnd.npcs.normalize.v3" normalizationPolicy = "dnd.npc_registry.normalize.v3"
semanticContextPolicy = "dnd.entity_reconcile.context.v1" semanticContextPolicy = "dnd.entity_reconcile.context.v1"
NormalizationPolicy = normalizationPolicy NormalizationPolicy = normalizationPolicy
@@ -385,5 +385,5 @@ func DecodeOptions(options map[string]any) (Options, error) {
} }
func normalizerErrorf(format string, args ...any) 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 ( import (
"context" "context"

View File

@@ -1,4 +1,4 @@
package npcs package npcregistry
import ( import (
"fmt" "fmt"
@@ -28,7 +28,7 @@ var promptAssetManifest = shared.PromptAssetManifest{
} }
func moduleAssetFS() (fs.FS, error) { 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 { if err != nil {
return nil, fmt.Errorf("scope NPC normalization assets: %w", err) return nil, fmt.Errorf("scope NPC normalization assets: %w", err)
} }

View File

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

View File

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

View File

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

View File

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

View File

@@ -9,7 +9,7 @@ import (
"gitea.maximumdirect.net/eric/notarius/internal/core/source" "gitea.maximumdirect.net/eric/notarius/internal/core/source"
"gitea.maximumdirect.net/eric/notarius/internal/framework/contracts" "gitea.maximumdirect.net/eric/notarius/internal/framework/contracts"
"gitea.maximumdirect.net/eric/notarius/internal/modules/dnd" "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/identity"
) )

View File

@@ -8,7 +8,7 @@ import (
locationoccurrenceextract "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/extract/locationoccurrences" locationoccurrenceextract "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/extract/locationoccurrences"
locationextract "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/extract/locations" locationextract "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/extract/locations"
interactionextract "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/extract/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"
scenedescriptionextract "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/extract/scenedescriptions" scenedescriptionextract "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/extract/scenedescriptions"
spellextract "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/extract/spells" spellextract "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/extract/spells"
combatnormalize "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/normalize/combatturns" 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" locationoccurrencenormalize "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/normalize/locationoccurrences"
locationnormalize "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/normalize/locations" locationnormalize "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/normalize/locations"
interactionnormalize "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/normalize/npcinteractions" 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" scenedescriptionnormalize "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/normalize/scenedescriptions"
spellnormalize "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/normalize/spells" spellnormalize "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/normalize/spells"
combatinvariants "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/validate/combatturns/invariants" 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" 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" 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" 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" npcidentity "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/validate/npcregistry/identity"
npcshape "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/validate/npcs/shape" npcshape "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/validate/npcregistry/shape"
npcsourcerefs "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/validate/npcs/source_refs" npcsourcerefs "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/validate/npcregistry/source_refs"
npcrelatedness "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/validate/npcs/source_relatedness" 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" sceneinvariants "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/validate/scenedescriptions/invariants"
sceneshape "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/validate/scenedescriptions/shape" 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" 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{ return registry.Register(pipeline.ValidatorChainMapping{
Stage: pipeline.StageExtract, Stage: pipeline.StageExtract,
Module: npcextract.Key, 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{ return registry.Register(pipeline.ValidatorChainMapping{
Stage: pipeline.StageNormalize, Stage: pipeline.StageNormalize,
Module: npcnormalize.Key, Module: npcnormalize.Key,

View File

@@ -9,7 +9,7 @@ import (
func registerEvidence(registry *pipeline.ArtifactEvidenceRegistry) error { func registerEvidence(registry *pipeline.ArtifactEvidenceRegistry) error {
return runRegistrations([]registration{ return runRegistrations([]registration{
{name: "spells evidence", register: func() error { return pipeline.RegisterArtifactEvidence(registry, dnd.SpellListKind, spellEvidence) }}, {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 { {name: "combat turns evidence", register: func() error {
return pipeline.RegisterArtifactEvidence(registry, dnd.CombatTurnListKind, combatTurnEvidence) 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" locationoccurrencecodec "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/codec/locationoccurrences"
locationcodec "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/codec/locations" locationcodec "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/codec/locations"
interactioncodec "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/codec/npcinteractions" 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" scenedescriptioncodec "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/codec/scenedescriptions"
spellcodec "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/codec/spells" spellcodec "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/codec/spells"
combatextract "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/extract/combatturns" 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" locationoccurrenceextract "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/extract/locationoccurrences"
locationextract "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/extract/locations" locationextract "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/extract/locations"
interactionextract "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/extract/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"
scenedescriptionextract "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/extract/scenedescriptions" scenedescriptionextract "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/extract/scenedescriptions"
spellextract "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/extract/spells" spellextract "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/extract/spells"
combatnormalize "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/normalize/combatturns" 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" locationoccurrencenormalize "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/normalize/locationoccurrences"
locationnormalize "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/normalize/locations" locationnormalize "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/normalize/locations"
interactionnormalize "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/normalize/npcinteractions" 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" scenedescriptionnormalize "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/normalize/scenedescriptions"
spellnormalize "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/normalize/spells" spellnormalize "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/normalize/spells"
"gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/shared/entityreconcile" "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/shared/entityreconcile"
@@ -41,7 +41,7 @@ func registerModules(registries pipeline.Registries) error {
codec := spellcodec.New() codec := spellcodec.New()
return runRegistrations([]registration{ return runRegistrations([]registration{
{name: "spells codec", register: func() error { return pipeline.RegisterArtifactCodec(registries.ArtifactCodecs, codec) }}, {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: "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: "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()) }}, {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: "scenes chunker", register: func() error { return scenes.Register(registries.Chunkers) }},
{name: "spells extractor", register: func() error { return spellextract.Register(registries.Extractors) }}, {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: "combat turns extractor", register: func() error { return combatextract.Register(registries.Extractors) }},
{name: "enemy events extractor", register: func() error { return enemyeventextract.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) }}, {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) return appendorder.RegisterTyped(registries.Mergers, dnd.LocationOccurrenceListKind, appendLocationOccurrenceLists)
}}, }},
{name: "spells normalizer", register: func() error { return spellnormalize.Register(registries.Normalizers) }}, {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: "combat turns normalizer", register: func() error { return combatnormalize.Register(registries.Normalizers) }},
{name: "enemy events normalizer", register: func() error { return enemyeventnormalize.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) }}, {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: "entity reconciliation schema assets", register: func() error { return entityreconcile.RegisterSchemaAssets(assets) }},
{name: "scenes prompt assets", register: func() error { return scenes.RegisterPromptAssets(assets) }}, {name: "scenes prompt assets", register: func() error { return scenes.RegisterPromptAssets(assets) }},
{name: "spells prompt assets", register: func() error { return spellextract.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: "npc normalization prompt assets", register: func() error { return npcnormalize.RegisterPromptAssets(assets) }},
{name: "combat turns prompt assets", register: func() error { return combatextract.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) }}, {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" locationoccurrenceextract "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/extract/locationoccurrences"
locationextract "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/extract/locations" locationextract "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/extract/locations"
interactionextract "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/extract/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"
scenedescriptionextract "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/extract/scenedescriptions" scenedescriptionextract "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/extract/scenedescriptions"
spellextract "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/extract/spells" spellextract "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/extract/spells"
"gitea.maximumdirect.net/eric/promptkit" "gitea.maximumdirect.net/eric/promptkit"
@@ -57,7 +57,7 @@ func TestExtractionPromptComposition(t *testing.T) {
promptID: combatextract.PromptID, promptID: combatextract.PromptID,
promptVersion: combatextract.SchemaVersion, promptVersion: combatextract.SchemaVersion,
inputs: withPromptInputs(commonInputs, map[string]promptkit.ArtifactRef{ inputs: withPromptInputs(commonInputs, map[string]promptkit.ArtifactRef{
"npcs": promptkit.Inline(`{"sentinel":"` + npcSentinel + `"}`), "npc_registry": promptkit.Inline(`{"sentinel":"` + npcSentinel + `"}`),
}), }),
suffixGroups: [][]string{{evidenceSentinel}, {npcSentinel}}, suffixGroups: [][]string{{evidenceSentinel}, {npcSentinel}},
}, },
@@ -66,7 +66,7 @@ func TestExtractionPromptComposition(t *testing.T) {
promptID: enemyeventextract.PromptID, promptID: enemyeventextract.PromptID,
promptVersion: enemyeventextract.SchemaVersion, promptVersion: enemyeventextract.SchemaVersion,
inputs: withPromptInputs(commonInputs, map[string]promptkit.ArtifactRef{ 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"}`), "combat_turns": promptkit.Inline(`{"sentinel":"combat-turns-sentinel"}`),
"npc_interactions": promptkit.Inline(`{"sentinel":"npc-interactions-sentinel"}`), "npc_interactions": promptkit.Inline(`{"sentinel":"npc-interactions-sentinel"}`),
}), }),
@@ -81,7 +81,7 @@ func TestExtractionPromptComposition(t *testing.T) {
promptID: interactionextract.PromptID, promptID: interactionextract.PromptID,
promptVersion: interactionextract.SchemaVersion, promptVersion: interactionextract.SchemaVersion,
inputs: withPromptInputs(commonInputs, map[string]promptkit.ArtifactRef{ inputs: withPromptInputs(commonInputs, map[string]promptkit.ArtifactRef{
"npcs": promptkit.Inline(`{"sentinel":"` + npcSentinel + `"}`), "npc_registry": promptkit.Inline(`{"sentinel":"` + npcSentinel + `"}`),
}), }),
suffixGroups: [][]string{{evidenceSentinel}, {npcSentinel}}, suffixGroups: [][]string{{evidenceSentinel}, {npcSentinel}},
}, },
@@ -99,7 +99,7 @@ func TestExtractionPromptComposition(t *testing.T) {
promptID: spellextract.PromptID, promptID: spellextract.PromptID,
promptVersion: spellextract.SchemaVersion, promptVersion: spellextract.SchemaVersion,
inputs: withPromptInputs(commonInputs, map[string]promptkit.ArtifactRef{ inputs: withPromptInputs(commonInputs, map[string]promptkit.ArtifactRef{
"npcs": promptkit.Inline(`{"sentinel":"` + npcSentinel + `"}`), "npc_registry": promptkit.Inline(`{"sentinel":"` + npcSentinel + `"}`),
"spell_catalog": promptkit.Inline(`{"sentinel":"` + catalogSentinel + `"}`), "spell_catalog": promptkit.Inline(`{"sentinel":"` + catalogSentinel + `"}`),
}), }),
suffixGroups: [][]string{{evidenceSentinel}, {npcSentinel}, {catalogSentinel}}, suffixGroups: [][]string{{evidenceSentinel}, {npcSentinel}, {catalogSentinel}},

View File

@@ -18,7 +18,7 @@ import (
locationoccurrenceextract "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/extract/locationoccurrences" locationoccurrenceextract "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/extract/locationoccurrences"
locationextract "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/extract/locations" locationextract "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/extract/locations"
interactionextract "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/extract/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"
scenedescriptionextract "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/extract/scenedescriptions" scenedescriptionextract "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/extract/scenedescriptions"
"gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/extract/spells" "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/extract/spells"
combatnormalize "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/normalize/combatturns" 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" locationoccurrencenormalize "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/normalize/locationoccurrences"
locationnormalize "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/normalize/locations" locationnormalize "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/normalize/locations"
interactionnormalize "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/normalize/npcinteractions" 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" scenedescriptionnormalize "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/normalize/scenedescriptions"
spellnormalize "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/normalize/spells" spellnormalize "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/normalize/spells"
) )
@@ -42,19 +42,19 @@ func TestRegisterAddsDNDFamily(t *testing.T) {
if err != nil { if err != nil {
t.Fatalf("PromptFS() error = %v", err) 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) t.Fatalf("normalization prompt asset = %v, want registered private prompt", err)
} }
for _, name := range []string{ for _, name := range []string{
"dnd.scenes/prompt.yaml", "dnd.scenes/prompt.yaml",
"dnd.spells/prompt.yaml", "dnd.spells/prompt.yaml",
"dnd.npcs/prompt.yaml", "dnd.npc_registry/prompt.yaml",
"dnd.combat_turns/prompt.yaml", "dnd.combat_turns/prompt.yaml",
"dnd.enemy_events/prompt.yaml", "dnd.enemy_events/prompt.yaml",
"dnd.item_events/prompt.yaml", "dnd.item_events/prompt.yaml",
"dnd.npc_interactions/prompt.yaml", "dnd.npc_interactions/prompt.yaml",
"dnd.scene_descriptions/prompt.yaml", "dnd.scene_descriptions/prompt.yaml",
"dnd.npcs.normalize/prompt.yaml", "dnd.npc_registry.normalize/prompt.yaml",
"dnd.locations/prompt.yaml", "dnd.locations/prompt.yaml",
"dnd.locations.normalize/prompt.yaml", "dnd.locations.normalize/prompt.yaml",
"dnd.location_occurrences/prompt.yaml", "dnd.location_occurrences/prompt.yaml",
@@ -97,10 +97,10 @@ func TestRegisterAddsDNDFamily(t *testing.T) {
assertContainsKeys(t, "validators", registries.Validators.RegisteredKeys(), []string{ 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/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/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/npc-registry/shape",
"extract/dnd/npcs/source_refs", "extract/dnd/npc-registry/source_refs",
"extract/dnd/npcs/source_relatedness", "extract/dnd/npc-registry/source_relatedness",
"normalize/dnd/npcs/identity", "normalize/dnd/npc-registry/identity",
"extract/dnd/spells/catalog", "extract/dnd/spells/catalog",
"extract/dnd/spells/shape", "extract/dnd/spells/shape",
"extract/dnd/spells/source_refs", "extract/dnd/spells/source_refs",
@@ -162,21 +162,21 @@ func TestRegisterAddsDNDFamily(t *testing.T) {
} }
npcExtractChain := []pipeline.ModuleBinding{ npcExtractChain := []pipeline.ModuleBinding{
pipeline.Binding("generic/valid_json"), pipeline.Binding("generic/valid_json"),
pipeline.Binding("extract/dnd/npcs/shape"), pipeline.Binding("extract/dnd/npc-registry/shape"),
pipeline.Binding("extract/dnd/npcs/source_refs"), pipeline.Binding("extract/dnd/npc-registry/source_refs"),
pipeline.Binding("generic/valid_json_schema"), 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) { if got := registries.ValidatorChains.Validators(pipeline.StageExtract, npcextract.Key); !reflect.DeepEqual(got, npcExtractChain) {
t.Fatalf("NPC extract validator chain = %#v, want %#v", got, npcExtractChain) t.Fatalf("NPC extract validator chain = %#v, want %#v", got, npcExtractChain)
} }
npcNormalizeChain := []pipeline.ModuleBinding{ npcNormalizeChain := []pipeline.ModuleBinding{
pipeline.Binding("generic/valid_json"), pipeline.Binding("generic/valid_json"),
pipeline.Binding("extract/dnd/npcs/shape"), pipeline.Binding("extract/dnd/npc-registry/shape"),
pipeline.Binding("normalize/dnd/npcs/identity"), pipeline.Binding("normalize/dnd/npc-registry/identity"),
pipeline.Binding("extract/dnd/npcs/source_refs"), pipeline.Binding("extract/dnd/npc-registry/source_refs"),
pipeline.Binding("generic/valid_json_schema"), 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) { if got := registries.ValidatorChains.Validators(pipeline.StageNormalize, npcnormalize.Key); !reflect.DeepEqual(got, npcNormalizeChain) {
t.Fatalf("NPC normalize validator chain = %#v, want %#v", 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{ assertAssetNamesContain(t, assets.SchemaFS, []string{
"dnd_scenes_llm.v1.json", "dnd_scenes_llm.v1.json",
"dnd_spells_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_combat_turns_llm.v1.json",
"dnd_enemy_events_llm.v1.json", "dnd_enemy_events_llm.v1.json",
"dnd_item_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 { if len(enemyEventExtractSpec.ReferenceSlots) != 8 || len(enemyEventNormalizeSpec.ReferenceSlots) != 1 {
t.Fatalf("enemy event reference slots = %#v / %#v", enemyEventExtractSpec.ReferenceSlots, enemyEventNormalizeSpec.ReferenceSlots) t.Fatalf("enemy event reference slots = %#v / %#v", enemyEventExtractSpec.ReferenceSlots, enemyEventNormalizeSpec.ReferenceSlots)
} }
npcRegistrySlot := referenceSlot(enemyEventExtractSpec.ReferenceSlots, "npcs") npcRegistrySlot := referenceSlot(enemyEventExtractSpec.ReferenceSlots, "npc_registry")
enemyNormalizeRegistrySlot := referenceSlot(enemyEventNormalizeSpec.ReferenceSlots, "npcs") 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) { 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) 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 { 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) t.Fatalf("scene description reference slots = %#v / %#v, want extractor campaign slots only", sceneExtractSpec.ReferenceSlots, sceneNormalizeSpec.ReferenceSlots)
} }
extractRegistrySlot := referenceSlot(interactionExtractSpec.ReferenceSlots, "npcs") extractRegistrySlot := referenceSlot(interactionExtractSpec.ReferenceSlots, "npc_registry")
normalizeRegistrySlot := referenceSlot(interactionNormalizeSpec.ReferenceSlots, "npcs") normalizeRegistrySlot := referenceSlot(interactionNormalizeSpec.ReferenceSlots, "npc_registry")
if !extractRegistrySlot.Required || !reflect.DeepEqual(extractRegistrySlot.AcceptedArtifactKinds, []contracts.ArtifactKind{dnd.NPCRegistryKind}) || !sameReferenceSlotContract(extractRegistrySlot, normalizeRegistrySlot) { 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) 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" 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" 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" 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" npcidentity "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/validate/npcregistry/identity"
npcshape "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/validate/npcs/shape" npcshape "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/validate/npcregistry/shape"
npcsourcerefs "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/validate/npcs/source_refs" npcsourcerefs "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/validate/npcregistry/source_refs"
npcrelatedness "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/validate/npcs/source_relatedness" 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" sceneinvariants "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/validate/scenedescriptions/invariants"
sceneshape "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/validate/scenedescriptions/shape" 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" 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-chunk.md": "prompts/common-dnd-transcript-chunk.md",
"common-dnd-transcript-windows.md": "prompts/common-dnd-transcript-windows.md", "common-dnd-transcript-windows.md": "prompts/common-dnd-transcript-windows.md",
"common-dnd-references.md": "prompts/common-dnd-references.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", "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{ for _, path := range []string{
"assets/prompts/dnd.test/sharedassets/common-dnd-references.md", "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 { if _, err := fs.ReadFile(fsys, path); err == nil {
t.Fatalf("ReadFile(%q) succeeded, want unlisted shared asset to be absent", path) 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: moduleFS, Path: "assets/prompts/instructions.md"},
{FS: sharedFS, Path: "prompts/common-dnd-transcript-chunk.md"}, {FS: sharedFS, Path: "prompts/common-dnd-transcript-chunk.md"},
{FS: sharedFS, Path: "prompts/common-dnd-system.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 { if err != nil {
t.Fatalf("HashAssets() with unused asset error = %v, want nil", err) 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/contracts"
"gitea.maximumdirect.net/eric/notarius/internal/framework/pipeline" "gitea.maximumdirect.net/eric/notarius/internal/framework/pipeline"
"gitea.maximumdirect.net/eric/notarius/internal/modules/dnd" "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/identity"
npcregistry "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/npcs/registry" npcregistry "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/npcs/registry"
) )

View File

@@ -12,7 +12,7 @@ import (
func TestValidatorUsesOnlyCitedTranscriptEvidence(t *testing.T) { func TestValidatorUsesOnlyCitedTranscriptEvidence(t *testing.T) {
value := validEventList() 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}) 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 { if err != nil || !result.Approved || len(result.Warnings) != 1 || result.Warnings[0].ReasonCode != WarningReasonCode {
t.Fatalf("Validate() = %#v, %v", result, err) 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/contracts"
"gitea.maximumdirect.net/eric/notarius/internal/framework/pipeline" "gitea.maximumdirect.net/eric/notarius/internal/framework/pipeline"
"gitea.maximumdirect.net/eric/notarius/internal/modules/dnd" "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/identity"
npcregistry "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/npcs/registry" 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/contracts"
"gitea.maximumdirect.net/eric/notarius/internal/framework/pipeline" "gitea.maximumdirect.net/eric/notarius/internal/framework/pipeline"
"gitea.maximumdirect.net/eric/notarius/internal/modules/dnd" "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/identity"
npcregistry "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/npcs/registry" 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" "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd"
domainidentity "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/npcs/identity" domainidentity "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/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 ( const (
Key = "normalize/dnd/npcs/identity" Key = "normalize/dnd/npc-registry/identity"
ReasonCode = "invalid_npc_identity" ReasonCode = "invalid_npc_identity"
policy = domainidentity.Policy policy = domainidentity.Policy
) )

View File

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

View File

@@ -50,7 +50,7 @@ func TestValidatorBoundsDiagnosticsAndQuotesUnicode(t *testing.T) {
} }
func TestValidatorSpecCheckpointAndRegistration(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) t.Fatalf("CheckpointFingerprints() = %#v, want local policy", got)
} }
if spec := Spec(); spec.Key != Key || spec.ExecutionClass != contracts.ExecutionClassDeterministic { 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/framework/pipeline"
"gitea.maximumdirect.net/eric/notarius/internal/modules/dnd" "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd"
"gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/shared/diagnostics" "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 ( const (
Key = "extract/dnd/npcs/source_refs" Key = "extract/dnd/npc-registry/source_refs"
ReasonCode = "invalid_npc_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{} type Options struct{}

View File

@@ -57,7 +57,7 @@ func TestValidatorBoundsDiagnosticsAndHandlesMissingDocument(t *testing.T) {
} }
func TestValidatorSpecCheckpointAndRegistration(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) t.Fatalf("CheckpointFingerprints() = %#v, want local policy", got)
} }
if Spec().ExecutionClass != contracts.ExecutionClassDeterministic { 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"
"gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/shared" "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/shared"
"gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/shared/diagnostics" "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 ( const (
Key = "extract/dnd/npcs/source_relatedness" Key = "extract/dnd/npc-registry/source_relatedness"
WarningReasonCode = "npc_not_near_source" WarningReasonCode = "npc_not_near_source"
policy = "dnd.npcs.validator.source_relatedness.v2" policy = "dnd.npc_registry.validator.source_relatedness.v2"
) )
type Options struct{} type Options struct{}

View File

@@ -76,7 +76,7 @@ func TestValidatorUsesOnlyTranscriptEvidenceAndRegistersPolicy(t *testing.T) {
if err != nil || len(result.Warnings) != 1 { if err != nil || len(result.Warnings) != 1 {
t.Fatalf("reference-only relatedness = %#v, %v; want warning", result, err) 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) t.Fatalf("CheckpointFingerprints() = %#v, want local policy", got)
} }
if Spec().ExecutionClass != contracts.ExecutionClassDeterministic { 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/framework/pipeline"
"gitea.maximumdirect.net/eric/notarius/internal/modules/dnd" "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd"
combatcodec "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/codec/combatturns" 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" scenecodec "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/codec/scenedescriptions"
combatextract "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/extract/combatturns" combatextract "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/extract/combatturns"
combatnormalize "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/normalize/combatturns" combatnormalize "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/normalize/combatturns"
@@ -36,8 +36,8 @@ func TestProductionCombatPipelineRetriesMergesNormalizesAndWritesJSON(t *testing
PipelineID: "dnd-combat-fixture", PipelineID: "dnd-combat-fixture",
Catalog: catalog, Catalog: catalog,
ReferenceOverrides: []pipeline.ReferenceBinding{ ReferenceOverrides: []pipeline.ReferenceBinding{
{Stage: pipeline.StageExtract, 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: "npcs", Source: npcPayload.path, BindingSource: contracts.ReferenceBindingSourceCLI}, {Stage: pipeline.StageNormalize, LaneID: "combat", SlotName: "npc_registry", Source: npcPayload.path, BindingSource: contracts.ReferenceBindingSourceCLI},
}, },
}) })
if err != nil { if err != nil {
@@ -278,8 +278,8 @@ func TestCombatPreparationRejectsMalformedOrOversizedNPCReferencesBeforeExecutio
PipelineID: "dnd-combat", PipelineID: "dnd-combat",
Catalog: catalog, Catalog: catalog,
ReferenceOverrides: []pipeline.ReferenceBinding{ ReferenceOverrides: []pipeline.ReferenceBinding{
{Stage: pipeline.StageExtract, 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: "npcs", Source: path, BindingSource: contracts.ReferenceBindingSourceCLI}, {Stage: pipeline.StageNormalize, LaneID: "combat", SlotName: "npc_registry", Source: path, BindingSource: contracts.ReferenceBindingSourceCLI},
}, },
}) })
if err != nil { if err != nil {

View File

@@ -19,14 +19,14 @@ import (
"gitea.maximumdirect.net/eric/notarius/internal/framework/pipeline" "gitea.maximumdirect.net/eric/notarius/internal/framework/pipeline"
"gitea.maximumdirect.net/eric/notarius/internal/modules/dnd" "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd"
combatcodec "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/codec/combatturns" 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" scenecodec "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/codec/scenedescriptions"
spellcodec "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/codec/spells" spellcodec "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/codec/spells"
combatextract "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/extract/combatturns" 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" sceneextract "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/extract/scenedescriptions"
"gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/extract/spells" "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) { func TestNPCOutputGroundsSpellAndCombatConsumersThroughOneOperation(t *testing.T) {
@@ -49,20 +49,20 @@ func TestNPCOutputGroundsSpellAndCombatConsumersThroughOneOperation(t *testing.T
t.Fatalf("Prepare() error = %v", err) t.Fatalf("Prepare() error = %v", err)
} }
for name, value := range map[string]string{ for name, value := range map[string]string{
"extract:npcs:dnd/npcs:mapping_policy": "dnd.npcs.extract_mapping.v2", "extract:npc_registry:dnd/npc-registry:mapping_policy": "dnd.npc_registry.extract_mapping.v2",
"normalize:npcs:dnd/npcs:identity_policy": "dnd.npc_registry.identity.v1", "normalize:npc_registry:dnd/npc-registry:identity_policy": "dnd.npc_registry.identity.v1",
"normalize:npcs:dnd/npcs:normalization_policy": "dnd.npcs.normalize.v3", "normalize:npc_registry:dnd/npc-registry:normalization_policy": "dnd.npc_registry.normalize.v3",
"normalize:npcs:dnd/npcs:semantic_context_policy": "dnd.entity_reconcile.context.v1:2", "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: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:combat:dnd/combat-turns:scene_gate_policy": "dnd.combat_turns.scene_gate.v1",
} { } {
assertFingerprintValue(t, prepared.CheckpointFingerprints(), name, value) assertFingerprintValue(t, prepared.CheckpointFingerprints(), name, value)
} }
for _, name := range []string{ for _, name := range []string{
"extract:npcs:dnd/npcs:prompt", "extract:npc_registry:dnd/npc-registry:prompt",
"extract:npcs:dnd/npcs:response_schema", "extract:npc_registry:dnd/npc-registry:response_schema",
"normalize:npcs:dnd/npcs:prompt", "normalize:npc_registry:dnd/npc-registry:prompt",
"normalize:npcs:dnd/npcs:response_schema", "normalize:npc_registry:dnd/npc-registry:response_schema",
"extract:spells:dnd/spells:prompt", "extract:spells:dnd/spells:prompt",
"extract:spells:dnd/spells:response_schema", "extract:spells:dnd/spells:response_schema",
"extract:spells:dnd/spells:npc_registry", "extract:spells:dnd/spells:npc_registry",
@@ -87,14 +87,14 @@ func TestNPCOutputGroundsSpellAndCombatConsumersThroughOneOperation(t *testing.T
if len(output.Rejected) != 0 || len(output.NormalizeOutputs) != 4 { 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) 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 { for _, serialized := range output.NormalizeOutputs {
if serialized.Artifact.Schema.ID != wantSchemas[serialized.LaneID] || serialized.Artifact.Schema.Version != "v1" { 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) t.Fatalf("%s artifact schema = %#v, want minimal v1 identity", serialized.LaneID, serialized.Artifact.Schema)
} }
} }
wantExtractorIdentity := map[string]struct{ promptID, schemaID string }{ wantExtractorIdentity := map[string]struct{ promptID, schemaID string }{
"npcs": {npcs.PromptID, npcs.ResponseSchemaID}, "npc_registry": {npcregistry.PromptID, npcregistry.ResponseSchemaID},
"scene-descriptions": {sceneextract.PromptID, sceneextract.ResponseSchemaID}, "scene-descriptions": {sceneextract.PromptID, sceneextract.ResponseSchemaID},
"spells": {spells.PromptID, spells.ResponseSchemaID}, "spells": {spells.PromptID, spells.ResponseSchemaID},
"combat": {combatextract.PromptID, combatextract.ResponseSchemaID}, "combat": {combatextract.PromptID, combatextract.ResponseSchemaID},
@@ -112,13 +112,13 @@ func TestNPCOutputGroundsSpellAndCombatConsumersThroughOneOperation(t *testing.T
for _, serialized := range output.NormalizeOutputs { for _, serialized := range output.NormalizeOutputs {
seenSteps[serialized.LaneID] = serialized.StepID seenSteps[serialized.LaneID] = serialized.StepID
switch serialized.LaneID { switch serialized.LaneID {
case "npcs": case "npc_registry":
npcPayload = append([]byte(nil), serialized.Artifact.Content...) npcPayload = append([]byte(nil), serialized.Artifact.Content...)
case "scene-descriptions": case "scene-descriptions":
scenePayload = append([]byte(nil), serialized.Artifact.Content...) 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) t.Fatalf("normalized output steps = %#v, want ordered producer and consumer steps", seenSteps)
} }
if len(npcPayload) == 0 { if len(npcPayload) == 0 {
@@ -152,7 +152,7 @@ func TestNPCOutputGroundsSpellAndCombatConsumersThroughOneOperation(t *testing.T
if request.PromptID != spells.PromptID && request.PromptID != combatextract.PromptID { if request.PromptID != spells.PromptID && request.PromptID != combatextract.PromptID {
continue 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 != "" { 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) 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 provenanceCount := 0
for _, reference := range output.Manifest.References { for _, reference := range output.Manifest.References {
if reference.SlotName != "npcs" { if reference.SlotName != "npc_registry" {
continue continue
} }
provenanceCount++ provenanceCount++
@@ -261,7 +261,7 @@ func TestProductionDNDOutputPublishesSelectedEvidenceContext(t *testing.T) {
configValue := loadGroundedPipelineConfig(t) configValue := loadGroundedPipelineConfig(t)
profile := configValue.Pipelines["dnd-npc-grounded"] profile := configValue.Pipelines["dnd-npc-grounded"]
profile.Output.Options = map[string]any{"evidence_context": map[string]any{ 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 configValue.Pipelines["dnd-npc-grounded"] = profile
raw := strings.NewReplacer( raw := strings.NewReplacer(
@@ -277,14 +277,14 @@ func TestProductionDNDOutputPublishesSelectedEvidenceContext(t *testing.T) {
if err != nil { if err != nil {
t.Fatalf("Decode(evidence context) error = %v", err) 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) 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 { 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) t.Fatalf("evidence contexts = %#v, want source-position union with non-monotonic unit IDs", value.Contexts)
} }
firstRefs := value.Contexts[0].EvidenceRefs 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) t.Fatalf("first context evidence = %#v, want overlapping selected lane references", firstRefs)
} }
for _, context := range value.Contexts { for _, context := range value.Contexts {
@@ -538,7 +538,7 @@ func (client *groundedDNDLLMClient) CompleteStructured(ctx context.Context, requ
thirdUnitID = 3 thirdUnitID = 3
} }
switch request.PromptID { switch request.PromptID {
case npcs.PromptID: case npcregistry.PromptID:
payload = map[string]any{"npcs": []any{ payload = map[string]any{"npcs": []any{
map[string]any{ map[string]any{
"name": "Mira Thorn", "source_refs": []any{map[string]int{"start_unit_id": firstUnitID, "end_unit_id": firstUnitID}}, "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/contracts"
"gitea.maximumdirect.net/eric/notarius/internal/framework/pipeline" "gitea.maximumdirect.net/eric/notarius/internal/framework/pipeline"
interactioncodec "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/codec/npcinteractions" 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" interactionextract "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/extract/npcinteractions"
"gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/extract/npcs" "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/extract/npcregistry"
npcnormalize "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/normalize/npcs" npcnormalize "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/normalize/npcregistry"
"gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/npcs/identity" "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/npcs/identity"
) )
@@ -37,11 +37,11 @@ func TestNPCInteractionPipelineUsesAcceptedRegistryAndCurrentEvidence(t *testing
request := client.requestFor(t, interactionextract.PromptID) request := client.requestFor(t, interactionextract.PromptID)
wantRegistry := `{"npcs":[{"name":"Mira Thorn"},{"name":"Hooded Guard"}]}` 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) t.Fatalf("interaction registry input = %s, want names-only projection %s", got, wantRegistry)
} }
if 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["npcs"].MediaType, npccodec.MediaType) t.Fatalf("interaction registry media type = %q, want %q", request.Inputs["npc_registry"].MediaType, npccodec.MediaType)
} }
serialized := normalizedLane(t, output, "interactions") serialized := normalizedLane(t, output, "interactions")
@@ -94,10 +94,10 @@ func TestSemanticNPCNormalizationCrossesOrderedRegistryHandoff(t *testing.T) {
if err != nil { if err != nil {
t.Fatalf("Run() error = %v", err) 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) 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) npcsValue, err := npccodec.New().Decode(npcOutput.Artifact.Content)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
@@ -113,7 +113,7 @@ func TestSemanticNPCNormalizationCrossesOrderedRegistryHandoff(t *testing.T) {
t.Fatalf("interaction output step = %q, want ordered downstream step", interactionOutput.StepID) t.Fatalf("interaction output step = %q, want ordered downstream step", interactionOutput.StepID)
} }
registryRequest := client.requestFor(t, interactionextract.PromptID) 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) t.Fatalf("downstream registry = %s, want one canonical names-only NPC", got)
} }
manifestContent, err := json.Marshal(output.Manifest) manifestContent, err := json.Marshal(output.Manifest)
@@ -136,8 +136,8 @@ func TestNPCInteractionPipelineSkipsConsumerWhenNPCProducerIsRejected(t *testing
if err == nil { if err == nil {
t.Fatalf("Run() output = %#v, want missing generated NPC producer error", output) t.Fatalf("Run() output = %#v, want missing generated NPC producer error", output)
} }
if client.requestCount(npcs.PromptID) != 1 { if client.requestCount(npcregistry.PromptID) != 1 {
t.Fatalf("NPC requests = %d, want rejected producer", client.requestCount(npcs.PromptID)) t.Fatalf("NPC requests = %d, want rejected producer", client.requestCount(npcregistry.PromptID))
} }
if client.requestCount(interactionextract.PromptID) != 0 { if client.requestCount(interactionextract.PromptID) != 0 {
t.Fatalf("interaction requests = %d, want none after rejected producer", client.requestCount(interactionextract.PromptID)) 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 var payload any
switch request.PromptID { switch request.PromptID {
case npcs.PromptID: case npcregistry.PromptID:
if client.rejectNPCs { if client.rejectNPCs {
payload = map[string]any{"npcs": []any{map[string]any{ payload = map[string]any{"npcs": []any{map[string]any{
"name": "", "source_refs": []any{map[string]int{"start_unit_id": 1, "end_unit_id": 1}}, "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)) client.requests = append(client.requests, cloneStructuredCompletionRequest(request))
var payload any var payload any
switch request.PromptID { switch request.PromptID {
case npcs.PromptID: case npcregistry.PromptID:
client.npcCalls++ client.npcCalls++
name := "Mira Thorn" name := "Mira Thorn"
if client.npcCalls == 2 { 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/contracts"
"gitea.maximumdirect.net/eric/notarius/internal/framework/llm" "gitea.maximumdirect.net/eric/notarius/internal/framework/llm"
"gitea.maximumdirect.net/eric/notarius/internal/framework/pipeline" "gitea.maximumdirect.net/eric/notarius/internal/framework/pipeline"
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/extract/npcs" "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/extract/npcregistry"
npcnormalize "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/normalize/npcs" npcnormalize "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/normalize/npcregistry"
"gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/npcs/identity" "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/npcs/identity"
dndregister "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/register" dndregister "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/register"
"gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/shared/entityreconcile" "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/shared/entityreconcile"
npcshape "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/validate/npcs/shape" npcshape "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/validate/npcregistry/shape"
npcsourcerefs "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/validate/npcs/source_refs" npcregistrysourcerefs "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/validate/npcregistry/source_refs"
genericregister "gitea.maximumdirect.net/eric/notarius/internal/modules/generic/register" genericregister "gitea.maximumdirect.net/eric/notarius/internal/modules/generic/register"
"gitea.maximumdirect.net/eric/notarius/internal/modules/seriatim/input/transcript" "gitea.maximumdirect.net/eric/notarius/internal/modules/seriatim/input/transcript"
seriatimregister "gitea.maximumdirect.net/eric/notarius/internal/modules/seriatim/register" seriatimregister "gitea.maximumdirect.net/eric/notarius/internal/modules/seriatim/register"
@@ -33,7 +33,7 @@ func TestRunnerProcessesSeriatimInputWithProductionDNDNPCPipeline(t *testing.T)
} }
registries := productionNPCRegistries(t) registries := productionNPCRegistries(t)
configValue := loadNPCPipelineConfig(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 { if err != nil {
t.Fatalf("Resolve() error = %v, want nil", err) 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) t.Fatalf("normalize outputs = %d, want one NPC output; rejected=%#v", len(output.NormalizeOutputs), output.Rejected)
} }
serialized := output.NormalizeOutputs[0] 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) t.Fatalf("serialized output = %#v, want durable NPC lane schema", serialized)
} }
value, err := npccodec.New().Decode(serialized.Artifact.Content) 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) t.Fatalf("manifest = %#v, want approved NPC lane", output.Manifest)
} }
lane := output.Manifest.ArtifactLanes[0] 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) t.Fatalf("manifest lane = %#v, want NPC production composition", lane)
} }
normalizerMetadata, ok := lane.Metadata["normalizer"].(map[string]any) normalizerMetadata, ok := lane.Metadata["normalizer"].(map[string]any)
@@ -102,7 +102,7 @@ func TestRunnerProcessesSeriatimInputWithProductionDNDNPCPipeline(t *testing.T)
} }
var npcOutputFile *contracts.OutputFile var npcOutputFile *contracts.OutputFile
for index := range output.OutputFiles { 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] npcOutputFile = &output.OutputFiles[index]
break break
} }
@@ -110,7 +110,7 @@ func TestRunnerProcessesSeriatimInputWithProductionDNDNPCPipeline(t *testing.T)
if npcOutputFile == nil || npcOutputFile.ContentType != npccodec.MediaType { if npcOutputFile == nil || npcOutputFile.ContentType != npccodec.MediaType {
t.Fatalf("output files = %#v, want JSON NPC lane file", output.OutputFiles) 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) 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) { func TestProductionNPCPipelineRoutesSemanticCandidatesToDeterministicValidators(t *testing.T) {
registries := productionNPCRegistries(t) registries := productionNPCRegistries(t)
effective, err := loadNPCPipelineConfig(t).Resolve(config.ResolveInput{ effective, err := loadNPCPipelineConfig(t).Resolve(config.ResolveInput{
PipelineID: "dnd-npcs-fixture", PipelineID: "dnd-npc-registry-fixture",
Catalog: moduleCatalog(registries), Catalog: moduleCatalog(registries),
}) })
if err != nil { if err != nil {
@@ -145,14 +145,14 @@ func TestProductionNPCPipelineRoutesSemanticCandidatesToDeterministicValidators(
{ {
name: "nonpositive unit candidate", name: "nonpositive unit candidate",
response: []byte(`{"npcs":[{"name":"Mira Thorn","source_refs":[{"start_unit_id":0,"end_unit_id":1}]}]}`), response: []byte(`{"npcs":[{"name":"Mira Thorn","source_refs":[{"start_unit_id":0,"end_unit_id":1}]}]}`),
reasonCode: npcsourcerefs.ReasonCode, reasonCode: npcregistrysourcerefs.ReasonCode,
validatorName: npcsourcerefs.Key, validatorName: npcregistrysourcerefs.Key,
}, },
{ {
name: "unknown unit candidate", name: "unknown unit candidate",
response: []byte(`{"npcs":[{"name":"Mira Thorn","source_refs":[{"start_unit_id":99,"end_unit_id":99}]}]}`), response: []byte(`{"npcs":[{"name":"Mira Thorn","source_refs":[{"start_unit_id":99,"end_unit_id":99}]}]}`),
reasonCode: npcsourcerefs.ReasonCode, reasonCode: npcregistrysourcerefs.ReasonCode,
validatorName: npcsourcerefs.Key, validatorName: npcregistrysourcerefs.Key,
}, },
} { } {
t.Run(test.name, func(t *testing.T) { 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) { t.Run(test.name, func(t *testing.T) {
cfg := loadNPCPipelineConfig(t) cfg := loadNPCPipelineConfig(t)
profile := cfg.Pipelines["dnd-npcs-fixture"] profile := cfg.Pipelines["dnd-npc-registry-fixture"]
lane := profile.Artifacts["npcs"] lane := profile.Artifacts["npc_registry"]
lane.Normalize.Retries = test.retries lane.Normalize.Retries = test.retries
profile.Artifacts["npcs"] = lane profile.Artifacts["npc_registry"] = lane
cfg.Pipelines["dnd-npcs-fixture"] = profile cfg.Pipelines["dnd-npc-registry-fixture"] = profile
effective, err := cfg.Resolve(config.ResolveInput{PipelineID: "dnd-npcs-fixture", Catalog: moduleCatalog(registries)}) effective, err := cfg.Resolve(config.ResolveInput{PipelineID: "dnd-npc-registry-fixture", Catalog: moduleCatalog(registries)})
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@@ -243,9 +243,9 @@ func (client *fakeNPCProductionLLMClient) CompleteStructured(_ context.Context,
client.requests = append(client.requests, req) client.requests = append(client.requests, req)
var content []byte var content []byte
switch req.PromptID { switch req.PromptID {
case npcs.PromptID: case npcregistry.PromptID:
if client.rawResponses != nil { if client.rawResponses != nil {
index := client.requestCount(npcs.PromptID) - 1 index := client.requestCount(npcregistry.PromptID) - 1
if index >= len(client.rawResponses) { if index >= len(client.rawResponses) {
return contracts.StructuredCompletionResponse{}, fmt.Errorf("missing fake NPC response %d", index) 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 { func loadNPCPipelineConfig(t *testing.T) config.Config {
t.Helper() t.Helper()
data, err := os.ReadFile("testdata/dnd_npcs_pipeline.yml") data, err := os.ReadFile("testdata/dnd_npc_registry_pipeline.yml")
if err != nil { 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) fileConfig, err := config.ParseFileConfigYAML(data)
if err != nil { if err != nil {

View File

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

View File

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

View File

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