Clarify NPC mention eligibility
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
Extract Dungeons & Dragons NPC occurrence occurrences from the supplied
|
||||
Extract Dungeons & Dragons NPC occurrences from the supplied
|
||||
transcript. Include an occurrence only when the transcript establishes one
|
||||
supplied NPC, one occurrence kind, and a coherent passage supporting both.
|
||||
Use the exact `npc_id` and matching `name` pair from the supplied NPC registry;
|
||||
|
||||
@@ -1,15 +1,19 @@
|
||||
Extract the individually identifiable Dungeons & Dragons non-player characters
|
||||
established by the provided transcript.
|
||||
|
||||
Include an in-world non-PC participant only when the transcript gives it a
|
||||
proper name or a stable, individually distinguishing title or alias.
|
||||
Include an in-world non-PC only when the transcript factually establishes a
|
||||
proper name or a stable, individually distinguishing title or alias. A factual
|
||||
third-party mention establishes that identity even when the NPC is not
|
||||
physically present, does not speak, and takes no direct action in this chunk.
|
||||
Record only the NPC identity and the transcript evidence that establishes it;
|
||||
do not infer or classify a separate occurrence.
|
||||
|
||||
Exclude human players, transcript speakers, and the GM as out-of-world people;
|
||||
player characters identified by the player or party references; incidental or
|
||||
hypothetical name drops; corrected transcription mistakes; anonymous or generic
|
||||
roles; indistinguishable crowds or groups; invented descriptive labels; and
|
||||
temporary summoned creatures or spell effects without a persistent individual
|
||||
identity.
|
||||
player characters identified by the player or party references; names used only
|
||||
in hypothetical, speculative, or imagined examples; corrected transcription
|
||||
mistakes; anonymous or generic roles; indistinguishable crowds or groups;
|
||||
invented descriptive labels; and temporary summoned creatures or spell effects
|
||||
without a persistent individual identity.
|
||||
|
||||
Preserve observed display spelling. Do not invent a label for an anonymous
|
||||
creature, crowd, or generic role.
|
||||
|
||||
@@ -71,6 +71,9 @@ The required normalized [NPC registry artifact](dnd-npc-registry-artifacts.md) r
|
||||
the exact `{npc_id, name}` pair. Unknown IDs and names that do not match their
|
||||
ID are rejected; normalization does not repair names by similarity. Registry
|
||||
references are provenance only and never replace an occurrence's own evidence.
|
||||
The registry may include an identity established by a factual third-party
|
||||
mention; that provenance alone does not create a `mentioned` occurrence. Each
|
||||
occurrence remains a separately cited fact in the current transcript.
|
||||
Normalization validates the exact pair, orders and
|
||||
deduplicates exact source references, then orders occurrences by valid source
|
||||
chronology, NPC comparison identity, display name, kind, and reference sequence.
|
||||
|
||||
@@ -68,10 +68,16 @@ descriptor.
|
||||
## Scope and consumers
|
||||
|
||||
Only individually identifiable NPC names with transcript evidence belong in
|
||||
this artifact. Groups, generic roles, invented labels, and descriptive
|
||||
enrichment are excluded. Its source references prove registry provenance; they
|
||||
do not become evidence for a spell, occurrence, combat, or enemy-event
|
||||
occurrence.
|
||||
this artifact. A factual third-party mention can establish an identity even if
|
||||
the NPC is not present, speaking, or acting in the cited passage. Names used
|
||||
only in hypothetical, speculative, or imagined examples are excluded, as are
|
||||
groups, generic roles, invented labels, and descriptive enrichment. Its source
|
||||
references prove registry provenance; they do not become evidence for a spell,
|
||||
occurrence, combat, or enemy-event occurrence.
|
||||
|
||||
Registry evidence establishes an identity, not an [NPC occurrence](dnd-npc-occurrence-artifacts.md).
|
||||
That later artifact independently records any current-transcript occurrence
|
||||
with its own cited evidence and category.
|
||||
|
||||
This registry can ground actor or caster names in the [spell](dnd-spell-artifacts.md)
|
||||
and [combat-turn](dnd-combat-turn-artifacts.md) artifacts. It is required to
|
||||
|
||||
@@ -168,11 +168,11 @@ checkpoint fingerprint.
|
||||
| Lane | Intentional behavior |
|
||||
| --- | --- |
|
||||
| Spells | May use a spell-catalog overlay and optional NPC grounding; the catalog validator supplies domain-specific semantic checks. |
|
||||
| NPC registry | Does not consume an NPC registry. Its normalizer is the LLM-assisted reconciliation exception described above. |
|
||||
| NPC registry | Establishes transcript-grounded NPC identities, including factual third-party mentions, without assigning occurrence categories. It does not consume an NPC registry, and its normalizer is the LLM-assisted reconciliation exception described above. |
|
||||
| Combat turns | Requires a scene-description artifact. It calls the LLM only for an exact `combat` classification; exact non-combat classifications return an accepted empty result, while missing or mismatched classifications return an empty result with a bounded warning. Optional NPC grounding never becomes evidence. |
|
||||
| Item occurrences | Requires the normalized item registry for exact ID/name grounding at extraction and normalization. Campaign context may disambiguate, but the registry never becomes occurrence evidence. |
|
||||
| Item registry | Produces source-grounded item types and unique designations. Its LLM-assisted reconciliation is proposal-only, preserves distinct currency denominations and item types, and does not create per-instance identities. |
|
||||
| NPC occurrences | Requires the normalized NPC registry at extraction and normalization, using it for canonical actor grounding only. |
|
||||
| NPC occurrences | Requires the normalized NPC registry at extraction and normalization, using it for canonical actor grounding only. It separately emits cited current-transcript occurrence facts, including `mentioned`, rather than deriving them from registry provenance. |
|
||||
| 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. |
|
||||
| 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. |
|
||||
|
||||
@@ -220,7 +220,7 @@ func groundingReferences(t *testing.T, enemy string, sceneKind dnd.SceneKind) co
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
interactionContent, err := occurrencecodec.New().Encode(dnd.NPCOccurrenceList{Occurrences: []dnd.NPCOccurrence{
|
||||
occurrenceContent, err := occurrencecodec.New().Encode(dnd.NPCOccurrenceList{Occurrences: []dnd.NPCOccurrence{
|
||||
{NPCID: identity.DeriveID(enemy), Name: enemy, Kind: dnd.NPCOccurrenceKindCombatOpponent, SourceRefs: []source.SourceRef{{SourceID: "combat-session", StartUnitID: 1, EndUnitID: 1}}},
|
||||
{NPCID: identity.DeriveID("Aria"), Name: "Aria", Kind: dnd.NPCOccurrenceKindCombatAlly, SourceRefs: []source.SourceRef{{SourceID: "combat-session", StartUnitID: 2, EndUnitID: 2}}},
|
||||
}})
|
||||
@@ -231,7 +231,7 @@ func groundingReferences(t *testing.T, enemy string, sceneKind dnd.SceneKind) co
|
||||
NPCRegistryReferenceSlot: {Items: []contracts.ReferenceItem{newReferenceItem(NPCRegistryReferenceSlot, npcContent)}},
|
||||
SceneDescriptionReferenceSlot: {Items: []contracts.ReferenceItem{newReferenceItem(SceneDescriptionReferenceSlot, sceneContent)}},
|
||||
CombatTurnReferenceSlot: {Items: []contracts.ReferenceItem{newReferenceItem(CombatTurnReferenceSlot, turnContent)}},
|
||||
NPCOccurrenceReferenceSlot: {Items: []contracts.ReferenceItem{newReferenceItem(NPCOccurrenceReferenceSlot, interactionContent)}},
|
||||
NPCOccurrenceReferenceSlot: {Items: []contracts.ReferenceItem{newReferenceItem(NPCOccurrenceReferenceSlot, occurrenceContent)}},
|
||||
}}
|
||||
}
|
||||
|
||||
|
||||
@@ -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"
|
||||
interactionmodel "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/npcoccurrences"
|
||||
occurrencemodel "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/npcoccurrences"
|
||||
npcregistry "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/npcs/registry"
|
||||
"gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/shared"
|
||||
"gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/shared/diagnostics"
|
||||
@@ -107,7 +107,7 @@ func (v *Validator) Validate(_ context.Context, req contracts.TypedValidationReq
|
||||
|
||||
func allSourceRefsValid(index source.DocumentIndex, value dnd.NPCOccurrenceList) bool {
|
||||
for _, occurrence := range value.Occurrences {
|
||||
if !interactionmodel.ValidSourceRefs(index, occurrence.SourceRefs) {
|
||||
if !occurrencemodel.ValidSourceRefs(index, occurrence.SourceRefs) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
@@ -136,13 +136,13 @@ func issuesFor(order shared.SourceRefOrder, value dnd.NPCOccurrenceList, npcRegi
|
||||
}
|
||||
|
||||
if !sort.SliceIsSorted(value.Occurrences, func(left, right int) bool {
|
||||
return interactionmodel.Less(order, value.Occurrences[left], value.Occurrences[right])
|
||||
return occurrencemodel.Less(order, value.Occurrences[left], value.Occurrences[right])
|
||||
}) {
|
||||
issues = append(issues, "occurrences are not in canonical order")
|
||||
}
|
||||
seen := make(map[string]int)
|
||||
for index, occurrence := range value.Occurrences {
|
||||
key := interactionmodel.ExactIdentity(occurrence)
|
||||
key := occurrencemodel.ExactIdentity(occurrence)
|
||||
if previous, ok := seen[key]; ok {
|
||||
issues = append(issues, fmt.Sprintf("occurrences[%d] duplicates occurrence %d", index, previous))
|
||||
continue
|
||||
|
||||
Reference in New Issue
Block a user