Document NPC semantic normalization

This commit is contained in:
2026-07-26 01:46:23 +00:00
parent 8d9a496935
commit fbb8e0d241
10 changed files with 107 additions and 22 deletions

View File

@@ -61,9 +61,9 @@ No pipelines are built in. A run requires a configured pipeline.
If `scriptorium` is omitted, Notarius uses Scriptorium's built-in profile
catalog. Prompt definitions may also name default profile IDs. The current D&D
scene and spell prompts default to the built-in `mistral-small-3` profile when a
module binding does not set `llm_profile`. That built-in profile reads its
credential from `OPENROUTER_API_KEY`.
scene, extraction, and NPC-normalization prompts default to `gemini-2-flash`
when a module binding does not set `llm_profile`. The selected built-in profile
reads its credentials from its Scriptorium profile definition.
## Scriptorium Profiles
@@ -322,7 +322,8 @@ Binding fields:
- `llm_profile`: optional Scriptorium profile ID. Empty or omitted lets the
Scriptorium prompt default select the profile.
- `retries`: non-negative retry count for extra runtime attempts after the
first attempt. Default: `0`. Supported on `chunk`, `extract`, `merge`, and
first attempt. Default: `0`, which permits one initial attempt and no
additional attempts. Supported on `chunk`, `extract`, `merge`, and
`normalize` bindings.
- `options`: optional module-specific settings.
- `references`: optional reference bindings. Supported only for `chunk`,
@@ -338,6 +339,15 @@ During resolution, each selected module's registered option validator runs.
Production input, chunk, and output bindings reject unknown or invalid options
with the affected binding context.
### NPC Semantic Normalization
The `dnd/npcs` normalizer combines deterministic canonical-name consolidation
with a document-level LLM identity decision for eligible differently named NPC
records. Its `llm_profile` and `retries` use the ordinary `normalize` binding
fields above; `retries: 0` therefore still makes one normalization attempt.
The normalizer declares no references and accepts no options. Context-window
selection is current module policy, not configuration.
### JSON Output Options
The `json` output module accepts only `include_chunk_map`, a boolean that
@@ -388,7 +398,7 @@ production validators do not call the LLM and must not set `llm_profile`.
| merge | `appendorder` | Combines typed artifacts in chunk order. |
| normalize | `noop` | Passes merged typed artifacts through unchanged. |
| normalize | `dnd/spells` | Deterministically canonicalizes and de-duplicates typed D&D spell-list artifacts. |
| normalize | `dnd/npcs` | Deterministically consolidates typed D&D NPC-list artifacts by canonical name and unions exact evidence. |
| normalize | `dnd/npcs` | Deterministically prepares typed D&D NPC-list artifacts, then uses an LLM-assisted document-level identity decision to consolidate safe name-based matches and union exact evidence. |
| normalize | `dnd/combat-turns` | Deterministically canonicalizes, orders, and de-duplicates typed D&D combat-turn artifacts. |
| normalize | `dnd/item-events` | Deterministically trims, source-orders, and removes only exact D&D item-event duplicates. |
| normalize | `dnd/npc-interactions` | Canonicalizes registry NPC names, orders interaction occurrences, and removes only exact duplicates. |

View File

@@ -75,10 +75,17 @@ The production identities are:
The extractor maps private model records to the current source identity and
assigns deterministic IDs. Extraction validation checks shape, source
references, and source relatedness. The normalizer then consolidates records
only when their normalized canonical names match, preserves the first record's
display and output position, unions exact evidence, and validates the retained
registry's identity. No LLM is used for consolidation.
references, and source relatedness. The normalizer first consolidates equal
canonical-name matches, then may make one document-level LLM-assisted identity
decision per configured normalize attempt for eligible distinctly named
records. Consolidation is name-based: it retains a supplied canonical display
name, keeps the earliest affected output position, derives its ID again, and
unions exact evidence in canonical order. Ambiguous, invalid, or conflicting
proposals are not applied; independently safe matches may still be retained.
After the retry budget is exhausted, the safe result is accepted with bounded
normalization warnings and the usual validation. The durable v1 artifact shape
does not add aliases, proposal fields, or any other semantic-normalization
representation.
The extraction prompt asks only for individually identifiable NPC names backed
by source evidence. Groups, generic roles, invented labels, and descriptive or

View File

@@ -154,6 +154,22 @@ identity, campaign-reference, and instruction messages are ephemeral cache
boundaries; the transcript is last and has no cache control. Compatible shared
messages remain canonical shared assets rather than copied package text.
### D&D NPC Normalization Prompt Ordering And Cache Boundaries
NPC normalization has a distinct prompt and response-schema identity from NPC
extraction. Its stable message tiers are the common D&D system and identity
assets, followed by package-owned task and normalization instructions. Cache
boundaries follow the shared identity tier and the package instructions. The
variable tail contains the private candidate-name-and-range input and a
windowed transcript input whose cited units provide local context; neither has
a cache boundary because it changes with the document.
This prompt intentionally omits extraction-evidence and campaign-reference
assets: it reconciles existing records rather than extracting events or adding
evidence. Its package-owned manifest and schema identity are fingerprinted
separately, so a normalization prompt or schema change cannot reuse a prior
normalization checkpoint.
Shared wording belongs in the canonical assets under
`internal/modules/dnd/shared`; extraction packages reference those assets in
their manifests instead of copying similar text into package-local files.

View File

@@ -395,11 +395,27 @@ omission-summary warning when truncated.
### `internal/modules/dnd/normalize/npcs`
The NPC normalizer performs deterministic identity-aware consolidation in
merged input order. It consolidates only equal canonical-name comparison keys,
retains the first display record, and unions exact source references. It exposes
the identity policy as its local checkpoint fingerprint and emits bounded
normalization warnings.
The NPC normalizer deterministically trims display names, recomputes IDs,
canonicalizes evidence, and consolidates equal comparison keys before semantic
work. Records are eligible for the document-level identity call only when they
have a non-empty comparison key and wholly valid current-document references.
It sends private candidate names and source ranges plus coalesced, cited
transcript windows to its own prompt; stable NPC IDs and the durable artifact
shape are not prompt inputs.
The private structured response proposes groups of supplied names and a
canonical supplied name. Deterministic comparison-key resolution validates each
group, discards unsafe or overlapping groups, and independently applies safe
ones. Application preserves earliest record order, unions canonical evidence,
and derives the final canonical ID. Invalid structured output and discarded
groups request framework retry with a safe fallback; bounded diagnostics become
durable only on final fallback exhaustion.
The normalizer records prompt and response-schema identities and digests,
identity and normalization policies, and semantic-context policy and radius as
manifest metadata. Its local checkpoint fingerprints cover the prompt, response
schema, identity policy, normalization policy, and semantic-context policy so a
meaningful behavior change invalidates prior normalize reuse.
## Merger And Normalizer

View File

@@ -119,7 +119,7 @@ Configuration. The implemented module packages are:
| `internal/modules/generic/merge/appendorder` | Combines accepted extraction results in chunk order. |
| `internal/modules/generic/normalize/noop` | Preserves accepted merged output. |
| `internal/modules/dnd/normalize/spells` | Canonicalizes catalog-backed spell names and exact source references, conservatively collapses duplicate casts, and reports deterministic warnings and independently scoped catalog checkpoint identity. |
| `internal/modules/dnd/normalize/npcs` | Consolidates NPC records deterministically by canonical name, unions exact evidence, and reports bounded warnings. |
| `internal/modules/dnd/normalize/npcs` | Deterministically prepares and safely applies document-level LLM-assisted NPC identity consolidation, preserving canonical evidence, order, and diagnostics. |
| `internal/modules/generic/output/json` | Encodes manifests, lane payloads, warnings, rejections, and an explicitly enabled accepted chunk map as logical JSON files. |
`internal/modules/dnd/shared` owns reusable D&D prompt fragments,

View File

@@ -322,9 +322,24 @@ error when attempts are exhausted. A rejection becomes a recorded
`RejectedOutput` when attempts are exhausted. Cancellation stops retry
processing immediately.
Rejected output is a non-fatal pipeline outcome and does not advance. Warnings
from discarded attempts are not promoted. Configuration owns retry counts and
validator overrides; see [Module Bindings](../config.md#module-bindings).
Structured-completion adapters classify malformed or undecodable provider
output with the provider-neutral `contracts.ErrInvalidStructuredOutput` error.
A typed normalizer may turn that condition, or another unsafe proposal, into a
normalize retry directive with a deterministic safe candidate, stable
diagnostic, and fallback warnings. The directive consumes the same configured
normalize retry budget: `retries` permits that many additional attempts after
the initial attempt. It neither creates a normalizer-local retry loop nor
records an accepted checkpoint for the discarded attempt.
When a later normalize attempt succeeds, its candidate alone proceeds through
the usual validation and checkpoint path. When the final attempt still returns
a directive, the runner validates its supplied safe fallback through that same
normalizer validator chain before accepting or rejecting it. Ordinary
attempt-local warnings and fallback warnings remain unpromoted while another
attempt is available; only final exhaustion promotes the supplied fallback
warnings. Rejected output is a non-fatal pipeline outcome and does not advance.
Configuration owns retry counts and validator overrides; see
[Module Bindings](../config.md#module-bindings).
## Checkpoint And Debug Hooks
@@ -389,7 +404,9 @@ boundaries. Every executed chunk, extract, merge, and normalize attempt writes
one terminal envelope for acceptance, validator rejection, module or validator
error, or applicable candidate or final serialization error. The envelope
contains its attempt-local warnings, any available candidate and rejection,
and terminal error text; failures before a candidate exists omit that payload.
and terminal error text; normalize retry directives retain their attempt-local
candidate and diagnostic, while only the final safe fallback reaches validation.
Failures before a candidate exists omit that payload.
Only LLM calls made by the module operation belong to the module attempt.
Validator calls retain independent scopes under `validate/` and are not
duplicated into the module envelope. A failed terminal-envelope write is a

View File

@@ -86,6 +86,22 @@ workflow intentionally crosses a process or session boundary. Those files are
validated against the consumer slot and must be protected as sensitive
campaign data. They are not part of the maintained ordered handoff workflow.
### NPC Semantic Normalization
Before the first step can release its accepted NPC artifact across the ordered
generated-reference barrier, `dnd/npcs` performs one document-level semantic
normalization call for each configured normalize attempt when eligible distinct
names remain. The normalize binding's `retries` setting controls additional
attempts. If an invalid or unsafe identity proposal exhausts that budget, the
run safely accepts the deterministic and any independently safe partial
consolidation, with a bounded warning; ordinary validation still applies before
the artifact can cross the barrier.
An accepted normalized NPC checkpoint can be reused on `--resume` just like
other accepted normalize work. A changed normalization prompt, response schema,
or policy identity produces a cold cache miss, so the current reconciliation is
recomputed rather than silently reusing incompatible state.
## Chunk-Plan Cache
Chunk plans are stored at:

View File

@@ -2,7 +2,7 @@
## Status
Accepted scope; not implemented.
Implemented.
## Purpose

View File

@@ -2,7 +2,7 @@
## Status
Ready for implementation.
Completed.
## Objective

View File

@@ -43,7 +43,10 @@ pipelines:
module: dnd/npcs
retries: 2
merge: appendorder
normalize: dnd/npcs
normalize:
module: dnd/npcs
llm_profile: gemini-2-flash
retries: 2
scene-descriptions:
extract:
module: dnd/scene-descriptions