Move location registry modules to canonical namespace

This commit is contained in:
2026-08-05 19:13:37 +00:00
parent c006b163d5
commit e8965ebbbb
58 changed files with 172 additions and 144 deletions

View File

@@ -15,6 +15,11 @@ transcript also establishes an actual proposal, intention, or agreement to
travel. When the hypothetical explicitly names a supplied location, it may be
mentioned.
A generic phrase in the current chunk may refer to a supplied named registry
location only when the chunk's context supports that coreference. It must not
create a registry location, and registry content or provenance must never
replace current-chunk evidence.
For overlapping support, visited outranks planned, recalled, and mentioned;
planned outranks recalled and mentioned; recalled outranks mentioned. A passage
may produce multiple records when it independently establishes separate facts,

View File

@@ -6,4 +6,4 @@ Registry content is context, not occurrence evidence. Do not derive an
occurrence or a source range from the registry, and do not infer a location
that is absent from it.
{{ input "locations" }}
{{ input "location_registry" }}

View File

@@ -14,7 +14,7 @@ inputs:
- name: glossary
required: false
content_type: text/plain
- name: locations
- name: location_registry
required: true
content_type: application/json
messages:

View File

@@ -0,0 +1,13 @@
Extract only physical places established by the provided Dungeons & Dragons
transcript that have a stable proper name or unique in-world designation. This
includes named planes, regions, settlements, districts, buildings, rooms,
landmarks, routes, and geographic features.
Do not create a registry location for generic, temporary, relative, or merely
descriptive phrases, including "the room", "the bar", "the hallway",
"outside", and "upstairs". Do not use capitalization as an eligibility test.
Keep aliases and nested places when the transcript identifies them; do not merge
or invent qualifiers for similarly named places.
Exclude people, creatures, objects, organizations, abstract concepts, and
places merely inferred from an event. Omit uncertain or unsupported places.

View File

@@ -1,4 +1,4 @@
id: dnd.locations
id: dnd.location_registry
version: "v1"
default_profile: dnd-extraction
inputs:
@@ -36,5 +36,5 @@ messages:
output:
format: json
validation_mode: json_schema
schema_path: dnd_locations_llm.v1.json
schema_path: dnd_location_registry_llm.v1.json
repair_attempts: 0

View File

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

View File

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

View File

@@ -1,10 +0,0 @@
Extract physical places established by the provided Dungeons & Dragons
transcript. Include planes, regions, settlements, districts, buildings, rooms,
landmarks, routes, and geographic features.
A generic label such as "the tavern" is allowed only when the transcript uses
it for a specific place. Keep aliases and nested places when the transcript
identifies them; do not merge or invent qualifiers for similarly named places.
Exclude people, creatures, objects, organizations, abstract concepts, and
places merely inferred from an event. Omit uncertain or unsupported places.

View File

@@ -370,7 +370,7 @@ selected target declares them:
| **players** | Optional text player context. |
| **glossary** | Optional text campaign glossary. |
| **spell_catalog** | Optional JSON spell-catalog overlay for spell extraction and normalization. See [spell-catalog overlays](integrations/dnd-spell-catalog-overlays.md). |
| **locations** | Required normalized location registry for location-occurrence extraction and normalization. |
| **location_registry** | Required normalized location registry for location-occurrence extraction and normalization. |
| **npc_registry** | Normalized NPC registry. Optional for spells and combat turns; required for NPC occurrences and enemy-event extraction and normalization. |
| **scene_descriptions** | Required normalized scene-description artifact for combat-turn and enemy-event extraction. |
| **combat_turns** | Required normalized combat-turn artifact for enemy-event extraction. |
@@ -387,13 +387,13 @@ binding contracts. Durable semantics and wire shapes remain in their
| `scene_descriptions` | `dnd/scene-description-list` | `application/json` | 1,048,576 bytes | extract only |
| `combat_turns` | `dnd/combat-turn-list` | `application/json` | 1,048,576 bytes | extract only |
| `npc_occurrences` | `dnd/npc-occurrence-list` | `application/json` | 1,048,576 bytes | extract only |
| `locations` | `dnd/location-registry` | `application/json` | 1,048,576 bytes | location-occurrence extract and normalize |
| `location_registry` | `dnd/location-registry` | `application/json` | 1,048,576 bytes | location-occurrence extract and normalize |
Scene descriptions accept **party**, **players**, and **glossary**, but not
**roster**. NPC occurrences require **npc_registry** for both extraction and
normalization. Combat turns require **scene_descriptions** for extraction; the
normalized combat-turn module may use optional **npc_registry**. Location occurrences
require **locations** for extraction and normalization. Enemy-event extraction
require **location_registry** for extraction and normalization. Enemy-event extraction
requires all four of its JSON artifact slots; its normalizer requires **npc_registry**.
The [complete example](../examples/dnd-complete.config.yml) shows the ordered
generated bindings.
@@ -404,12 +404,12 @@ generated bindings.
| --- | --- |
| Input | **seriatim** |
| Chunk | **generic**, **dnd/scenes** |
| Extract | **dnd/spells**, **dnd/npc-registry**, **dnd/combat-turns**, **dnd/item-events**, **dnd/npc-occurrences**, **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-occurrences**, **dnd/scene-descriptions**, **dnd/enemy-events**, **dnd/location-registry**, **dnd/location-occurrences** |
| Merge | **appendorder** |
| Normalize | **noop**, **dnd/spells**, **dnd/npc-registry**, **dnd/combat-turns**, **dnd/item-events**, **dnd/npc-occurrences**, **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-occurrences**, **dnd/scene-descriptions**, **dnd/enemy-events**, **dnd/location-registry**, **dnd/location-occurrences** |
| Output | **json** |
`dnd/locations` extraction and normalization are `llm_backed`; location
`dnd/location-registry` extraction and normalization are `llm_backed`; location
normalization may use the pipeline's selected LLM profile for bounded duplicate
proposals. `dnd/location-occurrences` extraction is `llm_backed`, while its
normalizer is `deterministic`. The complete example binds the registry in one
@@ -423,7 +423,7 @@ The D&D artifact contracts define each emitted schema:
[item events](integrations/dnd-item-event-artifacts.md),
[scene descriptions](integrations/dnd-scene-description-artifacts.md), and
[enemy events](integrations/dnd-enemy-event-artifacts.md),
[locations](integrations/dnd-location-artifacts.md), and
[location registry](integrations/dnd-location-registry-artifacts.md), and
[location occurrences](integrations/dnd-location-occurrence-artifacts.md).
## Production Validator Keys And Default Chains
@@ -440,7 +440,7 @@ Available validator keys are:
| NPC occurrences | **extract/dnd/npc-occurrences/shape**, **extract/dnd/npc-occurrences/registry**, **extract/dnd/npc-occurrences/source_refs**, **extract/dnd/npc-occurrences/source_relatedness**, **normalize/dnd/npc-occurrences/invariants** |
| Scene descriptions | **extract/dnd/scene-descriptions/shape**, **extract/dnd/scene-descriptions/source_refs**, **extract/dnd/scene-descriptions/source_relatedness**, **normalize/dnd/scene-descriptions/invariants** |
| Enemy events | **extract/dnd/enemy-events/shape**, **extract/dnd/enemy-events/engagements**, **extract/dnd/enemy-events/source_refs**, **extract/dnd/enemy-events/source_relatedness**, **normalize/dnd/enemy-events/invariants** |
| Locations | **extract/dnd/locations/shape**, **extract/dnd/locations/source_refs**, **extract/dnd/locations/source_relatedness**, **normalize/dnd/locations/identity** |
| Location registry | **extract/dnd/location-registry/shape**, **extract/dnd/location-registry/source_refs**, **extract/dnd/location-registry/source_relatedness**, **normalize/dnd/location-registry/identity** |
| Location occurrences | **extract/dnd/location-occurrences/shape**, **extract/dnd/location-occurrences/registry**, **extract/dnd/location-occurrences/source_refs**, **extract/dnd/location-occurrences/source_relatedness**, **normalize/dnd/location-occurrences/invariants** |
When no override is configured, production D&D bindings use the following
@@ -456,7 +456,7 @@ same at both stages.
| NPC occurrences | generic/valid_json, extract/dnd/npc-occurrences/shape, extract/dnd/npc-occurrences/registry, extract/dnd/npc-occurrences/source_refs, generic/valid_json_schema, extract/dnd/npc-occurrences/source_relatedness | generic/valid_json, extract/dnd/npc-occurrences/shape, extract/dnd/npc-occurrences/registry, normalize/dnd/npc-occurrences/invariants, extract/dnd/npc-occurrences/source_refs, generic/valid_json_schema, extract/dnd/npc-occurrences/source_relatedness |
| Scene descriptions | generic/valid_json, extract/dnd/scene-descriptions/shape, extract/dnd/scene-descriptions/source_refs, generic/valid_json_schema, extract/dnd/scene-descriptions/source_relatedness | generic/valid_json, extract/dnd/scene-descriptions/shape, normalize/dnd/scene-descriptions/invariants, extract/dnd/scene-descriptions/source_refs, generic/valid_json_schema, extract/dnd/scene-descriptions/source_relatedness |
| Enemy events | generic/valid_json, extract/dnd/enemy-events/shape, extract/dnd/enemy-events/engagements, extract/dnd/enemy-events/source_refs, generic/valid_json_schema, extract/dnd/enemy-events/source_relatedness | generic/valid_json, extract/dnd/enemy-events/shape, normalize/dnd/enemy-events/invariants, extract/dnd/enemy-events/source_refs, generic/valid_json_schema, extract/dnd/enemy-events/source_relatedness |
| Locations | generic/valid_json, extract/dnd/locations/shape, extract/dnd/locations/source_refs, generic/valid_json_schema, extract/dnd/locations/source_relatedness | generic/valid_json, extract/dnd/locations/shape, normalize/dnd/locations/identity, extract/dnd/locations/source_refs, generic/valid_json_schema, extract/dnd/locations/source_relatedness |
| Location registry | generic/valid_json, extract/dnd/location-registry/shape, extract/dnd/location-registry/source_refs, generic/valid_json_schema, extract/dnd/location-registry/source_relatedness | generic/valid_json, extract/dnd/location-registry/shape, normalize/dnd/location-registry/identity, extract/dnd/location-registry/source_refs, generic/valid_json_schema, extract/dnd/location-registry/source_relatedness |
| Location occurrences | generic/valid_json, extract/dnd/location-occurrences/shape, extract/dnd/location-occurrences/registry, extract/dnd/location-occurrences/source_refs, generic/valid_json_schema, extract/dnd/location-occurrences/source_relatedness | generic/valid_json, extract/dnd/location-occurrences/shape, extract/dnd/location-occurrences/registry, normalize/dnd/location-occurrences/invariants, extract/dnd/location-occurrences/source_refs, generic/valid_json_schema, extract/dnd/location-occurrences/source_relatedness |
Chains are only registered for the D&D extract and normalize modules shown

View File

@@ -25,7 +25,7 @@ Each occurrence has these required fields:
| Field | Contract |
| --- | --- |
| `location_id` | Exact ID from the required normalized [location registry](dnd-location-artifacts.md). |
| `location_id` | Exact ID from the required normalized [location registry](dnd-location-registry-artifacts.md). |
| `name` | Exact canonical display name for `location_id` in that registry. |
| `kind` | One of `visited`, `planned`, `recalled`, or `mentioned`. |
| `source_refs` | One or more current-transcript evidence ranges for this occurrence. |
@@ -71,7 +71,7 @@ complete canonical evidence sequence.
## Required grounding and evidence
Both extraction and normalization require exactly one `locations` reference of
Both extraction and normalization require exactly one `location_registry` reference of
kind `dnd/location-registry`, media type `application/json`, and at most 1 MiB. The
registry provides identity grounding only: unknown IDs and mismatched ID/name
pairs are rejected rather than guessed or reassigned. The current transcript is

View File

@@ -1,7 +1,7 @@
# D&D Location Registry Artifact
This contract defines the durable, source-grounded location registry produced
by `dnd/locations`. It records transcript-established physical places for one
by `dnd/location-registry`. It records transcript-established physical places for one
source document; it is not a map, location hierarchy, campaign-wide world
registry, or location description.
@@ -64,12 +64,14 @@ anchors differ, so a generic name does not force distinct places to collapse.
## Scope, reconciliation, and evidence
Locations are physical or spatial places established by the transcript, such
as planes, regions, settlements, districts, buildings, rooms, landmarks,
routes, and geographic features. A generic label is permitted only when it
identifies a specific place in the transcript. Notarius does not infer an
unstated place or add hierarchy, coordinates, descriptions, participants, or
ownership.
Locations are physical or spatial places established by the transcript with a
stable proper name or unique in-world designation, such as named planes,
regions, settlements, districts, buildings, rooms, landmarks, routes, and
geographic features. Generic, temporary, relative, and descriptive phrases
such as “the room,” “the bar,” “the hallway,” “outside,” and “upstairs” are not
registry locations. Capitalization alone does not establish eligibility.
Notarius does not infer an unstated place or add hierarchy, coordinates,
descriptions, participants, or ownership.
Normalization first applies deterministic display, evidence, and ID rules. It
then may use a bounded LLM-assisted proposal to reconcile semantically duplicate
@@ -81,7 +83,7 @@ not evidence for later artifacts.
## Consumers and publication
`dnd/location-occurrences` requires one approved location registry through its
`locations` reference slot. Its prompt receives an ordered source-free `{id,
`location_registry` reference slot. Its prompt receives an ordered source-free `{id,
name}` projection and must not treat registry references as occurrence
evidence. See the [location-occurrence artifact](dnd-location-occurrence-artifacts.md)
for that contract, [Configuration](../config.md#references-and-ordered-handoffs)

View File

@@ -77,7 +77,7 @@ than infer a lane schema from its name. The current D&D payload contracts are
[item events](dnd-item-event-artifacts.md),
[scene descriptions](dnd-scene-description-artifacts.md), and
[enemy events](dnd-enemy-event-artifacts.md),
[locations](dnd-location-artifacts.md), and
[location registry](dnd-location-registry-artifacts.md), and
[location occurrences](dnd-location-occurrence-artifacts.md).
## `manifest.json`

View File

@@ -19,7 +19,7 @@ does not repeat their JSON shapes or schemas.
| NPC occurrences | [NPC-occurrence artifacts](../integrations/dnd-npc-occurrence-artifacts.md) |
| Scene descriptions | [scene-description artifacts](../integrations/dnd-scene-description-artifacts.md) |
| Enemy events | [enemy-event artifacts](../integrations/dnd-enemy-event-artifacts.md) |
| Locations | [location artifacts](../integrations/dnd-location-artifacts.md) |
| Location registry | [location-registry artifacts](../integrations/dnd-location-registry-artifacts.md) |
| Location occurrences | [location-occurrence artifacts](../integrations/dnd-location-occurrence-artifacts.md) |
## Family Composition
@@ -166,7 +166,7 @@ shared helper changes.
| NPC occurrences | Requires the normalized NPC registry at extraction and normalization, using it for canonical actor grounding only. |
| Scene descriptions | Produces the classifications consumed by combat routing; it does not consume an NPC registry or provide evidence for combat artifacts. |
| Enemy events | Requires NPC, scene-description, combat-turn, and NPC-occurrence artifacts. It calls the LLM only for an exact `combat` classification, records ordered observations rather than terminal state, and normalizes recognized names through the NPC registry while preserving grounded collective labels. |
| Locations | Produces a source-anchored, session-scoped registry. Its LLM-assisted reconciliation is proposal-only and never collapses same-name places without validated identity and evidence rules. |
| Location registry | Produces a source-anchored, session-scoped registry from stable proper names or unique in-world designations. Its LLM-assisted reconciliation is proposal-only and never collapses same-name places without validated identity and evidence rules. |
| Location occurrences | Requires the normalized location registry for both extraction and normalization. Its [durable occurrence categories](../integrations/dnd-location-occurrence-artifacts.md#occurrence-categories) distinguish explicit speculation from unsupported inference; the deterministic normalizer enforces exact registry grounding and never turns registry provenance into occurrence evidence. |
The combat and scene-description contracts describe their exact handoff and

View File

@@ -63,11 +63,11 @@ pipelines:
retries: 2
locations:
extract:
module: dnd/locations
module: dnd/location-registry
retries: 2
merge: appendorder
normalize:
module: dnd/locations
module: dnd/location-registry
retries: 2
scene-descriptions:
extract:
@@ -79,7 +79,7 @@ pipelines:
# Accepted registry artifacts and scene-description eligibility artifacts
# are supplied in memory to their compatible consumers in this step.
references:
locations:
location_registry:
artifact:
step: describe-session
lane: locations

View File

@@ -21,18 +21,18 @@ import (
"gitea.maximumdirect.net/eric/notarius/internal/modules/dnd"
"gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/chunk/scenes"
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/locationregistry"
combat "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/extract/combatturns"
enemyevents "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/extract/enemyevents"
itemevents "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/extract/itemevents"
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/locationregistry"
npcoccurrences "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/extract/npcoccurrences"
npcregistry "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/extract/npcregistry"
scenedescriptions "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/extract/scenedescriptions"
"gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/extract/spells"
enemyeventnormalize "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/normalize/enemyevents"
locationnormalize "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/normalize/locations"
locationnormalize "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/normalize/locationregistry"
npcnormalize "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/normalize/npcregistry"
)
@@ -185,7 +185,7 @@ func TestMaintainedCompleteExampleProducesEnemyEventsThroughGeneratedHandoffs(t
t.Fatalf("location occurrence requests = %#v, want one request per scene", locationRequests)
}
for _, request := range locationRequests {
registryInput := request.Inputs["locations"]
registryInput := request.Inputs["location_registry"]
if !strings.Contains(string(registryInput.Content), "Moon Gate") || !strings.Contains(string(registryInput.Content), `"id"`) || strings.Contains(string(registryInput.Content), "source_refs") {
t.Fatalf("location occurrence registry input = %q, want source-free ID grounding", registryInput.Content)
}
@@ -280,7 +280,7 @@ func (client *enemyEventLLMClient) CompleteStructured(ctx context.Context, reque
ID string `json:"id"`
} `json:"locations"`
}
if err := json.Unmarshal(request.Inputs["locations"].Content, &registry); err != nil {
if err := json.Unmarshal(request.Inputs["location_registry"].Content, &registry); err != nil {
return contracts.StructuredCompletionResponse{}, fmt.Errorf("decode generated location registry: %w", err)
}
if len(registry.Locations) == 0 {

View File

@@ -16,9 +16,9 @@ import (
"gitea.maximumdirect.net/eric/notarius/internal/framework/pipeline"
"gitea.maximumdirect.net/eric/notarius/internal/modules/dnd"
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/locationregistry"
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/locationregistry"
spellnormalize "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/normalize/spells"
"gitea.maximumdirect.net/eric/notarius/internal/modules/seriatim/input/transcript"
)
@@ -70,7 +70,7 @@ func TestMaintainedExamplesLoadResolveAndList(t *testing.T) {
t.Fatalf("location occurrence lane = %#v, want typed occurrence composition", occurrenceLane)
}
for _, target := range []pipeline.ResolvedReferenceTarget{occurrenceLane.ExtractReferences, occurrenceLane.NormalizeReferences} {
binding, found := generatedReferenceBinding(target.Bindings, "locations")
binding, found := generatedReferenceBinding(target.Bindings, "location_registry")
if !found || binding.Artifact.Step != "describe-session" || binding.Artifact.Lane != "locations" {
t.Fatalf("location occurrence %s reference = %#v, want generated location registry", target.Stage, binding)
}

View File

@@ -1,5 +1,5 @@
// Package locations encodes durable D&D location artifacts.
package locations
// Package locationregistry encodes durable D&D location-registry artifacts.
package locationregistry
import (
"embed"

View File

@@ -1,4 +1,4 @@
package locations
package locationregistry
import (
"bytes"

View File

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

View File

@@ -30,7 +30,7 @@ func TestRegisterPromptAssetsPreparesLocationOccurrencePrompt(t *testing.T) {
PromptID: PromptID, PromptVersion: SchemaVersion, ProfileID: "location-occurrences-test",
Inputs: map[string]promptkit.ArtifactRef{
"transcript": promptkit.Inline(`{"units":[{"sentinel":"location-occurrence-transcript"}]}`), "players": promptkit.Inline("location-occurrence-player"), "party": promptkit.Inline(" "), "glossary": promptkit.Inline(" "),
"locations": promptkit.Inline(`{"locations":[{"id":"location:sha256:test","name":"location-occurrence-registry"}]}`),
"location_registry": promptkit.Inline(`{"locations":[{"id":"location:sha256:test","name":"location-occurrence-registry"}]}`),
},
})
if err != nil {
@@ -48,4 +48,13 @@ func TestRegisterPromptAssetsPreparesLocationOccurrencePrompt(t *testing.T) {
if !strings.Contains(registryMessage, "location:sha256:test") || !strings.Contains(registryMessage, "location-occurrence-registry") || strings.Contains(registryMessage, "source_refs") {
t.Fatalf("rendered prompt did not preserve source-free registry grounding: %s", registryMessage)
}
content := make([]string, len(prepared.Messages))
for index, message := range prepared.Messages {
content[index] = message.Content
}
rendered := strings.Join(content, "\n")
policy := strings.ReplaceAll(rendered, "\n", " ")
if !strings.Contains(policy, "context supports that coreference") || !strings.Contains(policy, "must not create a registry location") || !strings.Contains(policy, "provenance must never replace current-chunk evidence") {
t.Fatalf("rendered prompt = %q, want contextual coreference without registry-derived evidence", rendered)
}
}

View File

@@ -1,4 +1,4 @@
package locations
package locationregistry
import (
"sort"

View File

@@ -1,5 +1,5 @@
// Package locations extracts source-grounded D&D physical location candidates.
package locations
// Package locationregistry extracts source-grounded D&D location-registry candidates.
package locationregistry
import (
"context"
@@ -13,12 +13,12 @@ import (
)
const (
Key = "dnd/locations"
mappingPolicy = "dnd.locations.extract_mapping.v1"
Key = "dnd/location-registry"
mappingPolicy = "dnd.location_registry.extract_mapping.v1"
)
var requiredCapabilities = []string{"chunks", "source.transcript"}
var providedCapabilities = []string{"dnd.locations"}
var providedCapabilities = []string{"dnd.location_registry"}
var referenceSlotDescriptions = shared.ReferenceSlotDescriptions{
Glossary: "Optional campaign glossary reference material used only for location disambiguation.",
@@ -148,5 +148,5 @@ func DecodeOptions(options map[string]any) (Options, error) {
}
func extractorErrorf(format string, args ...any) error {
return fmt.Errorf("dnd locations extractor: "+format, args...)
return fmt.Errorf("dnd location registry extractor: "+format, args...)
}

View File

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

View File

@@ -1,4 +1,4 @@
package locations
package locationregistry
type extractionResponse struct {
Locations []locationResponse `json:"locations"`

View File

@@ -1,4 +1,4 @@
package locations
package locationregistry
import (
"fmt"
@@ -29,7 +29,7 @@ var promptAssetManifest = shared.PromptAssetManifest{
}
func moduleAssetFS() (fs.FS, error) {
assets, err := fs.Sub(rootassets.FS(), "dnd/locations/extract")
assets, err := fs.Sub(rootassets.FS(), "dnd/location-registry/extract")
if err != nil {
return nil, fmt.Errorf("scope location extraction assets: %w", err)
}

View File

@@ -1,7 +1,8 @@
package locations
package locationregistry
import (
"context"
"strings"
"testing"
"time"
@@ -29,7 +30,15 @@ func TestRegisterPromptAssetsPreparesLocationPrompt(t *testing.T) {
if err != nil {
t.Fatalf("Prepare() error = %v", err)
}
if prepared.PromptID != PromptID || prepared.OutputContract.SchemaPath != "dnd_locations_llm.v1.json" {
if prepared.PromptID != PromptID || prepared.OutputContract.SchemaPath != "dnd_location_registry_llm.v1.json" {
t.Fatalf("prepared prompt = %#v, want location prompt identity and schema wiring", prepared)
}
content := make([]string, len(prepared.Messages))
for index, message := range prepared.Messages {
content[index] = message.Content
}
rendered := strings.Join(content, "\n")
if !strings.Contains(rendered, "stable proper name or unique in-world designation") || !strings.Contains(rendered, "the room") || !strings.Contains(rendered, "Do not use capitalization as an eligibility test") {
t.Fatalf("rendered prompt = %q, want named-or-unique location eligibility rules", rendered)
}
}

View File

@@ -1,4 +1,4 @@
package locations
package locationregistry
import (
"reflect"
@@ -18,7 +18,7 @@ func TestModuleRegistrationAndMetadata(t *testing.T) {
if _, err := New(&fakeLocationsLLMClient{}, Options{}, contracts.ReferenceSet{}, contracts.ReferenceSet{}); err == nil || !strings.Contains(err.Error(), "at most one") {
t.Fatalf("New() error = %v, want reference-set rejection", err)
}
want := pipeline.ModuleSpec{Key: Key, Stage: pipeline.StageExtract, ExecutionClass: contracts.ExecutionClassLLMBacked, Requires: []string{"chunks", "source.transcript"}, Provides: []string{"dnd.locations"}, ArtifactKind: dnd.LocationRegistryKind, ReferenceSlots: referenceSlots()}
want := pipeline.ModuleSpec{Key: Key, Stage: pipeline.StageExtract, ExecutionClass: contracts.ExecutionClassLLMBacked, Requires: []string{"chunks", "source.transcript"}, Provides: []string{"dnd.location_registry"}, ArtifactKind: dnd.LocationRegistryKind, ReferenceSlots: referenceSlots()}
if got := ModuleSpec(); !reflect.DeepEqual(got, want) {
t.Fatalf("ModuleSpec() = %#v, want %#v", got, want)
}

View File

@@ -1,12 +1,12 @@
package locations
package locationregistry
import "gitea.maximumdirect.net/eric/notarius/internal/framework/llm"
const (
PromptID = "dnd.locations"
ResponseSchemaKey = llm.ResponseSchemaKey("dnd_locations_llm")
ResponseSchemaID = "notarius.dnd.locations.llm"
ResponseSchemaName = "notarius_dnd_locations_llm_v1"
PromptID = "dnd.location_registry"
ResponseSchemaKey = llm.ResponseSchemaKey("dnd_location_registry_llm")
ResponseSchemaID = "notarius.dnd.location_registry.llm"
ResponseSchemaName = "notarius_dnd_location_registry_llm_v1"
SchemaVersion = "v1"
)
@@ -20,6 +20,6 @@ func loadResponseSchema() (llm.ResponseSchema, error) {
ID: ResponseSchemaID,
Version: SchemaVersion,
Name: ResponseSchemaName,
AssetPath: "schemas/dnd_locations_llm.v1.json",
AssetPath: "schemas/dnd_location_registry_llm.v1.json",
})
}

View File

@@ -1,4 +1,4 @@
package locations
package locationregistry
import (
"encoding/json"

View File

@@ -1,4 +1,4 @@
package locations
package locationregistry
import (
"context"

View File

@@ -11,14 +11,14 @@ import (
"gitea.maximumdirect.net/eric/notarius/internal/core/source"
"gitea.maximumdirect.net/eric/notarius/internal/framework/contracts"
"gitea.maximumdirect.net/eric/notarius/internal/modules/dnd"
locationcodec "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/codec/locations"
locationcodec "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/codec/locationregistry"
"gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/locations/identity"
"gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/shared/diagnostics"
"gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/shared/registryresolver"
)
const (
ReferenceSlot = "locations"
ReferenceSlot = "location_registry"
MaxBytes = 1048576
emptyPrompt = `{"locations":[]}`
)
@@ -59,7 +59,7 @@ func (r *Resolver) Seeded() *Registry {
return r.resolver.Seeded()
}
// Resolve returns the generated operation-time registry when the locations
// Resolve returns the generated operation-time registry when the location_registry
// slot is present, otherwise it returns the construction-time registry.
func (r *Resolver) Resolve(references contracts.ReferenceSet) (*Registry, error) {
if r == nil || r.resolver == nil {

View File

@@ -8,7 +8,7 @@ import (
"gitea.maximumdirect.net/eric/notarius/internal/core/source"
"gitea.maximumdirect.net/eric/notarius/internal/framework/contracts"
"gitea.maximumdirect.net/eric/notarius/internal/modules/dnd"
locationcodec "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/codec/locations"
locationcodec "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/codec/locationregistry"
"gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/locations/identity"
)

View File

@@ -10,7 +10,7 @@ import (
"gitea.maximumdirect.net/eric/notarius/internal/framework/contracts"
"gitea.maximumdirect.net/eric/notarius/internal/framework/pipeline"
"gitea.maximumdirect.net/eric/notarius/internal/modules/dnd"
locationcodec "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/codec/locations"
locationcodec "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/codec/locationregistry"
"gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/locations/identity"
"gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/shared/diagnostics"
)

View File

@@ -1,5 +1,5 @@
// Package locations normalizes merged D&D location candidates conservatively.
package locations
// Package locationregistry normalizes merged D&D location-registry candidates conservatively.
package locationregistry
import (
"context"
@@ -21,9 +21,9 @@ import (
)
const (
Key = "dnd/locations"
PromptID = "dnd.locations.normalize"
normalizationPolicy = "dnd.locations.normalize.v1"
Key = "dnd/location-registry"
PromptID = "dnd.location_registry.normalize"
normalizationPolicy = "dnd.location_registry.normalize.v1"
semanticContextPolicy = "dnd.entity_reconcile.context.v1"
semanticContextRadius = 2
NormalizationPolicy = normalizationPolicy
@@ -339,5 +339,5 @@ func DecodeOptions(options map[string]any) (Options, error) {
return Options{}, nil
}
func normalizerErrorf(format string, args ...any) error {
return fmt.Errorf("dnd locations normalizer: "+format, args...)
return fmt.Errorf("dnd location registry normalizer: "+format, args...)
}

View File

@@ -1,4 +1,4 @@
package locations
package locationregistry
import (
"context"

View File

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

View File

@@ -1,4 +1,4 @@
package locations
package locationregistry
import (
"context"

View File

@@ -1,4 +1,4 @@
package locations
package locationregistry
import (
"fmt"

View File

@@ -1,4 +1,4 @@
package locations
package locationregistry
import (
"context"

View File

@@ -6,7 +6,7 @@ import (
enemyeventextract "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/extract/enemyevents"
itemeventextract "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/extract/itemevents"
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/locationregistry"
occurrenceextract "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/extract/npcoccurrences"
npcextract "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/extract/npcregistry"
scenedescriptionextract "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/extract/scenedescriptions"
@@ -15,7 +15,7 @@ import (
enemyeventnormalize "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/normalize/enemyevents"
itemeventnormalize "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/normalize/itemevents"
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/locationregistry"
occurrencenormalize "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/normalize/npcoccurrences"
npcnormalize "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/normalize/npcregistry"
scenedescriptionnormalize "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/normalize/scenedescriptions"
@@ -38,10 +38,10 @@ import (
locationoccurrenceshape "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/validate/locationoccurrences/shape"
locationoccurrencerefs "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/validate/locationoccurrences/source_refs"
locationoccurrencerelatedness "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/validate/locationoccurrences/source_relatedness"
locationidentity "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/validate/locations/identity"
locationshape "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/validate/locations/shape"
locationrefs "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/validate/locations/source_refs"
locationrelatedness "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/validate/locations/source_relatedness"
locationidentity "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/validate/locationregistry/identity"
locationshape "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/validate/locationregistry/shape"
locationrefs "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/validate/locationregistry/source_refs"
locationrelatedness "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/validate/locationregistry/source_relatedness"
npcoccurrenceinvariants "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/validate/npcoccurrences/invariants"
npcoccurrenceregistry "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/validate/npcoccurrences/registry"
npcoccurrenceshape "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/validate/npcoccurrences/shape"

View File

@@ -9,7 +9,7 @@ import (
enemyeventcodec "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/codec/enemyevents"
itemeventcodec "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/codec/itemevents"
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/locationregistry"
occurrencecodec "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/codec/npcoccurrences"
npccodec "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/codec/npcregistry"
scenedescriptioncodec "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/codec/scenedescriptions"
@@ -18,7 +18,7 @@ import (
enemyeventextract "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/extract/enemyevents"
itemeventextract "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/extract/itemevents"
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/locationregistry"
occurrenceextract "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/extract/npcoccurrences"
npcextract "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/extract/npcregistry"
scenedescriptionextract "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/extract/scenedescriptions"
@@ -27,7 +27,7 @@ import (
enemyeventnormalize "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/normalize/enemyevents"
itemeventnormalize "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/normalize/itemevents"
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/locationregistry"
occurrencenormalize "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/normalize/npcoccurrences"
npcnormalize "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/normalize/npcregistry"
scenedescriptionnormalize "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/normalize/scenedescriptions"
@@ -49,7 +49,7 @@ func registerModules(registries pipeline.Registries) error {
{name: "scene descriptions codec", register: func() error {
return pipeline.RegisterArtifactCodec(registries.ArtifactCodecs, scenedescriptioncodec.New())
}},
{name: "locations codec", register: func() error { return pipeline.RegisterArtifactCodec(registries.ArtifactCodecs, locationcodec.New()) }},
{name: "location registry codec", register: func() error { return pipeline.RegisterArtifactCodec(registries.ArtifactCodecs, locationcodec.New()) }},
{name: "location occurrences codec", register: func() error {
return pipeline.RegisterArtifactCodec(registries.ArtifactCodecs, locationoccurrencecodec.New())
}},
@@ -61,7 +61,7 @@ func registerModules(registries pipeline.Registries) error {
{name: "item events extractor", register: func() error { return itemeventextract.Register(registries.Extractors) }},
{name: "npc occurrences extractor", register: func() error { return occurrenceextract.Register(registries.Extractors) }},
{name: "scene descriptions extractor", register: func() error { return scenedescriptionextract.Register(registries.Extractors) }},
{name: "locations extractor", register: func() error { return locationextract.Register(registries.Extractors) }},
{name: "location registry extractor", register: func() error { return locationextract.Register(registries.Extractors) }},
{name: "location occurrences extractor", register: func() error { return locationoccurrenceextract.Register(registries.Extractors) }},
{name: "spell-list appendorder merger", register: func() error {
return appendorder.RegisterTyped(registries.Mergers, dnd.SpellListKind, appendSpellLists)
@@ -97,7 +97,7 @@ func registerModules(registries pipeline.Registries) error {
{name: "item events normalizer", register: func() error { return itemeventnormalize.Register(registries.Normalizers) }},
{name: "npc occurrences normalizer", register: func() error { return occurrencenormalize.Register(registries.Normalizers) }},
{name: "scene descriptions normalizer", register: func() error { return scenedescriptionnormalize.Register(registries.Normalizers) }},
{name: "locations normalizer", register: func() error { return locationnormalize.Register(registries.Normalizers) }},
{name: "location registry normalizer", register: func() error { return locationnormalize.Register(registries.Normalizers) }},
{name: "location occurrences normalizer", register: func() error { return locationoccurrencenormalize.Register(registries.Normalizers) }},
{name: "spell-list noop normalizer", register: func() error {
return noop.RegisterTyped[dnd.SpellList](registries.Normalizers, dnd.SpellListKind)

View File

@@ -12,7 +12,7 @@ import (
enemyeventextract "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/extract/enemyevents"
itemeventextract "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/extract/itemevents"
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/locationregistry"
occurrenceextract "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/extract/npcoccurrences"
npcextract "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/extract/npcregistry"
scenedescriptionextract "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/extract/scenedescriptions"
@@ -90,7 +90,7 @@ func TestExtractionPromptComposition(t *testing.T) {
promptID: locationoccurrenceextract.PromptID,
promptVersion: locationoccurrenceextract.SchemaVersion,
inputs: withPromptInputs(commonInputs, map[string]promptkit.ArtifactRef{
"locations": promptkit.Inline(`{"sentinel":"location-registry-sentinel"}`),
"location_registry": promptkit.Inline(`{"sentinel":"location-registry-sentinel"}`),
}),
suffixGroups: [][]string{{evidenceSentinel}, {"location-registry-sentinel"}},
},

View File

@@ -16,7 +16,7 @@ import (
enemyeventextract "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/extract/enemyevents"
itemeventextract "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/extract/itemevents"
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/locationregistry"
occurrenceextract "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/extract/npcoccurrences"
npcextract "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/extract/npcregistry"
scenedescriptionextract "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/extract/scenedescriptions"
@@ -25,7 +25,7 @@ import (
enemyeventnormalize "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/normalize/enemyevents"
itemeventnormalize "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/normalize/itemevents"
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/locationregistry"
occurrencenormalize "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/normalize/npcoccurrences"
npcnormalize "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/normalize/npcregistry"
scenedescriptionnormalize "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/normalize/scenedescriptions"
@@ -55,8 +55,8 @@ func TestRegisterAddsDNDFamily(t *testing.T) {
"dnd.npc_occurrences/prompt.yaml",
"dnd.scene_descriptions/prompt.yaml",
"dnd.npc_registry.normalize/prompt.yaml",
"dnd.locations/prompt.yaml",
"dnd.locations.normalize/prompt.yaml",
"dnd.location_registry/prompt.yaml",
"dnd.location_registry.normalize/prompt.yaml",
"dnd.location_occurrences/prompt.yaml",
} {
content, err := fs.ReadFile(promptFS, name)
@@ -95,7 +95,7 @@ func TestRegisterAddsDNDFamily(t *testing.T) {
assertContainsArtifactKinds(t, registries.Normalizers.RegisteredArtifactKinds(occurrencenormalize.Key), []contracts.ArtifactKind{dnd.NPCOccurrenceListKind})
assertContainsArtifactKinds(t, registries.Normalizers.RegisteredArtifactKinds(scenedescriptionnormalize.Key), []contracts.ArtifactKind{dnd.SceneDescriptionListKind})
assertContainsKeys(t, "validators", registries.Validators.RegisteredKeys(), []string{
"extract/dnd/locations/shape", "normalize/dnd/locations/identity", "extract/dnd/locations/source_refs", "extract/dnd/locations/source_relatedness",
"extract/dnd/location-registry/shape", "normalize/dnd/location-registry/identity", "extract/dnd/location-registry/source_refs", "extract/dnd/location-registry/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/npc-registry/shape",
"extract/dnd/npc-registry/source_refs",
@@ -130,8 +130,8 @@ func TestRegisterAddsDNDFamily(t *testing.T) {
"generic/always_accept",
"generic/always_reject",
})
locationExtractChain := []pipeline.ModuleBinding{pipeline.Binding("generic/valid_json"), pipeline.Binding("extract/dnd/locations/shape"), pipeline.Binding("extract/dnd/locations/source_refs"), pipeline.Binding("generic/valid_json_schema"), pipeline.Binding("extract/dnd/locations/source_relatedness")}
locationNormalizeChain := []pipeline.ModuleBinding{pipeline.Binding("generic/valid_json"), pipeline.Binding("extract/dnd/locations/shape"), pipeline.Binding("normalize/dnd/locations/identity"), pipeline.Binding("extract/dnd/locations/source_refs"), pipeline.Binding("generic/valid_json_schema"), pipeline.Binding("extract/dnd/locations/source_relatedness")}
locationExtractChain := []pipeline.ModuleBinding{pipeline.Binding("generic/valid_json"), pipeline.Binding("extract/dnd/location-registry/shape"), pipeline.Binding("extract/dnd/location-registry/source_refs"), pipeline.Binding("generic/valid_json_schema"), pipeline.Binding("extract/dnd/location-registry/source_relatedness")}
locationNormalizeChain := []pipeline.ModuleBinding{pipeline.Binding("generic/valid_json"), pipeline.Binding("extract/dnd/location-registry/shape"), pipeline.Binding("normalize/dnd/location-registry/identity"), pipeline.Binding("extract/dnd/location-registry/source_refs"), pipeline.Binding("generic/valid_json_schema"), pipeline.Binding("extract/dnd/location-registry/source_relatedness")}
occurrenceExtractChain := []pipeline.ModuleBinding{pipeline.Binding("generic/valid_json"), pipeline.Binding("extract/dnd/location-occurrences/shape"), pipeline.Binding("extract/dnd/location-occurrences/registry"), pipeline.Binding("extract/dnd/location-occurrences/source_refs"), pipeline.Binding("generic/valid_json_schema"), pipeline.Binding("extract/dnd/location-occurrences/source_relatedness")}
occurrenceNormalizeChain := []pipeline.ModuleBinding{pipeline.Binding("generic/valid_json"), pipeline.Binding("extract/dnd/location-occurrences/shape"), pipeline.Binding("extract/dnd/location-occurrences/registry"), pipeline.Binding("normalize/dnd/location-occurrences/invariants"), pipeline.Binding("extract/dnd/location-occurrences/source_refs"), pipeline.Binding("generic/valid_json_schema"), pipeline.Binding("extract/dnd/location-occurrences/source_relatedness")}
for _, test := range []struct {
@@ -304,7 +304,7 @@ func TestRegisterAddsDNDFamily(t *testing.T) {
"dnd_item_events_llm.v1.json",
"dnd_npc_occurrences_llm.v1.json",
"dnd_scene_descriptions_llm.v1.json",
"dnd_locations_llm.v1.json",
"dnd_location_registry_llm.v1.json",
"dnd_location_occurrences_llm.v1.json",
})
if spec, ok := registries.Chunkers.Spec("dnd/scenes"); !ok || spec.Key != "dnd/scenes" {
@@ -366,8 +366,8 @@ func TestRegisterAddsDNDFamily(t *testing.T) {
if !locationOccurrenceExtractOK || locationOccurrenceExtractSpec.ArtifactKind != dnd.LocationOccurrenceListKind || locationOccurrenceExtractSpec.ExecutionClass != contracts.ExecutionClassLLMBacked || !locationOccurrenceNormalizeOK || locationOccurrenceNormalizeSpec.ArtifactKind != dnd.LocationOccurrenceListKind || locationOccurrenceNormalizeSpec.ExecutionClass != contracts.ExecutionClassDeterministic {
t.Fatalf("location occurrence specs = %#v / %#v", locationOccurrenceExtractSpec, locationOccurrenceNormalizeSpec)
}
locationRegistrySlot := referenceSlot(locationOccurrenceExtractSpec.ReferenceSlots, "locations")
occurrenceNormalizeRegistrySlot := referenceSlot(locationOccurrenceNormalizeSpec.ReferenceSlots, "locations")
locationRegistrySlot := referenceSlot(locationOccurrenceExtractSpec.ReferenceSlots, "location_registry")
occurrenceNormalizeRegistrySlot := referenceSlot(locationOccurrenceNormalizeSpec.ReferenceSlots, "location_registry")
if len(locationOccurrenceExtractSpec.ReferenceSlots) != 5 || len(locationOccurrenceNormalizeSpec.ReferenceSlots) != 1 {
t.Fatalf("location occurrence reference slots = %#v / %#v, want extractor campaign context and normalizer registry only", locationOccurrenceExtractSpec.ReferenceSlots, locationOccurrenceNormalizeSpec.ReferenceSlots)
}

View File

@@ -21,10 +21,10 @@ import (
locationoccurrenceshape "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/validate/locationoccurrences/shape"
locationoccurrencerefs "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/validate/locationoccurrences/source_refs"
locationoccurrencerelatedness "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/validate/locationoccurrences/source_relatedness"
locationidentity "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/validate/locations/identity"
locationshape "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/validate/locations/shape"
locationrefs "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/validate/locations/source_refs"
locationrelatedness "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/validate/locations/source_relatedness"
locationidentity "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/validate/locationregistry/identity"
locationshape "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/validate/locationregistry/shape"
locationrefs "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/validate/locationregistry/source_refs"
locationrelatedness "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/validate/locationregistry/source_relatedness"
npcoccurrenceinvariants "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/validate/npcoccurrences/invariants"
npcoccurrenceregistry "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/validate/npcoccurrences/registry"
npcoccurrenceshape "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/validate/npcoccurrences/shape"

View File

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

View File

@@ -10,11 +10,11 @@ import (
"gitea.maximumdirect.net/eric/notarius/internal/modules/dnd"
domainidentity "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/locations/identity"
"gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/shared/diagnostics"
locationshape "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/validate/locations/shape"
locationshape "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/validate/locationregistry/shape"
)
const (
Key = "normalize/dnd/locations/identity"
Key = "normalize/dnd/location-registry/identity"
ReasonCode = "invalid_location_identity"
policy = domainidentity.Policy
)

View File

@@ -13,9 +13,9 @@ import (
)
const (
Key = "extract/dnd/locations/shape"
Key = "extract/dnd/location-registry/shape"
ReasonCode = "invalid_location_shape"
policy = "dnd.locations.validator.shape.v1"
policy = "dnd.location_registry.validator.shape.v1"
)
type Options struct{}

View File

@@ -10,13 +10,13 @@ import (
"gitea.maximumdirect.net/eric/notarius/internal/framework/pipeline"
"gitea.maximumdirect.net/eric/notarius/internal/modules/dnd"
"gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/shared/diagnostics"
locationshape "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/validate/locations/shape"
locationshape "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/validate/locationregistry/shape"
)
const (
Key = "extract/dnd/locations/source_refs"
Key = "extract/dnd/location-registry/source_refs"
ReasonCode = "invalid_location_source_refs"
policy = "dnd.locations.validator.source_refs.v2"
policy = "dnd.location_registry.validator.source_refs.v2"
)
type Options struct{}

View File

@@ -10,14 +10,14 @@ import (
"gitea.maximumdirect.net/eric/notarius/internal/modules/dnd"
"gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/shared"
"gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/shared/diagnostics"
locationshape "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/validate/locations/shape"
locationshape "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/validate/locationregistry/shape"
)
const (
Key = "extract/dnd/locations/source_relatedness"
Key = "extract/dnd/location-registry/source_relatedness"
WarningReasonCode = "location_not_near_source"
OmittedReasonCode = "location_relatedness_warnings_omitted"
policy = "dnd.locations.validator.source_relatedness.v2"
policy = "dnd.location_registry.validator.source_relatedness.v2"
)
type Options struct{}

View File

@@ -14,10 +14,10 @@ import (
"gitea.maximumdirect.net/eric/notarius/internal/framework/pipeline"
"gitea.maximumdirect.net/eric/notarius/internal/modules/dnd"
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/locationregistry"
locationoccurrences "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/extract/locationoccurrences"
locations "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/extract/locations"
locationnormalize "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/normalize/locations"
locations "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/extract/locationregistry"
locationnormalize "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/normalize/locationregistry"
)
func TestLocationRegistryHandoffProducesOccurrencesAndEvidence(t *testing.T) {
@@ -62,7 +62,7 @@ func TestLocationRegistryHandoffProducesOccurrencesAndEvidence(t *testing.T) {
}
request := client.requestFor(t, locationoccurrences.PromptID)
registryInput := request.Inputs["locations"]
registryInput := request.Inputs["location_registry"]
if registryInput.MediaType != locationcodec.MediaType || strings.Contains(string(registryInput.Content), "source_refs") || !strings.Contains(string(registryInput.Content), registry.Locations[0].ID) || !strings.Contains(string(registryInput.Content), registry.Locations[1].ID) {
t.Fatalf("occurrence registry input = %#v, want source-free generated ID projection", registryInput)
}
@@ -122,7 +122,7 @@ func TestLocationOccurrenceCheckpointTracksGeneratedRegistry(t *testing.T) {
t.Fatalf("Run() error = %v", err)
}
for _, dependency := range checkpoint.extractDependencies("occurrences") {
if dependency.Name == "generated-reference:locations:0" && strings.HasPrefix(dependency.Value, "sha256:") {
if dependency.Name == "generated-reference:location_registry:0" && strings.HasPrefix(dependency.Value, "sha256:") {
return
}
}
@@ -176,12 +176,12 @@ pipelines:
- id: identify-locations
artifacts:
locations:
extract: dnd/locations
extract: dnd/location-registry
merge: appendorder
normalize: dnd/locations
normalize: dnd/location-registry
- id: track-location-occurrences
references:
locations:
location_registry:
artifact:
step: identify-locations
lane: locations
@@ -221,7 +221,7 @@ func (client *locationHandoffLLMClient) CompleteStructured(ctx context.Context,
ID string `json:"id"`
} `json:"locations"`
}
if err := json.Unmarshal(request.Inputs["locations"].Content, &projection); err != nil {
if err := json.Unmarshal(request.Inputs["location_registry"].Content, &projection); err != nil {
return contracts.StructuredCompletionResponse{}, fmt.Errorf("decode location registry: %w", err)
}
if len(projection.Locations) != 2 {