# NPC regression fixture starter

This original offline teaching project validates handwritten candidate dialogue objects against a tiny invented merchant rule. It does not call DeepSeek, contain model responses, measure an inference model, or run a game engine. All examples are synthetic. The CSV reports validator behavior, not model accuracy.

## Downloads
- [Validator](validate_npc.py)
- [Tests](test_validate_npc.py)
- [Handwritten fixtures](fixtures.json)
- [Expected CSV](fixture-results.csv)

## Reproduce
Download `validate_npc.py`, `test_validate_npc.py` and `fixtures.json` into the same folder. Python 3.10+; standard library only. Run:

```sh
python -B -m unittest -v test_validate_npc.py
python -B validate_npc.py > results.csv
```

Compare the generated CSV with `fixture-results.csv`. Seventeen cases cover three accepted structures and fourteen rejected structures. The tests also check that validation does not mutate the supplied state.

## Invented contract
The top-level object must contain exactly `dialogue`, `action` and `gold_delta`. Dialogue is a nonempty string no longer than 240 Python characters (not tokens or display cells). Action is `talk` or `reward`. Gold delta must be an integer, not a boolean. Talk changes no balance. A reward is exactly 10 gold, only when the quest is complete and the reward has not been claimed. State is trusted test input. Content is limited to 8,192 UTF-8 bytes before parsing; duplicate JSON keys and non-finite numeric constants are rejected.

This is a deliberately small checker, not a full JSON Schema implementation or hardened hostile-input parser. The single returned category is the first applicable failure. A truncated example is categorized as parse failure; an API finish reason must be recorded separately to identify why a real response ended.

## Use with a real evaluation
Keep this synthetic suite to test the checker itself. Separately freeze your real prompts, prior dialogue, game states, retrieval results, tools and scoring rubric. Store each raw response with the requested alias, documented version and access date, returned model/fingerprint if present, exact effective settings, timestamps, finish reason and usage. These are suggested evaluation records, not a DeepSeek response schema. Do not store API keys or player-identifying data in shared reports.

After any model update, run the same cases repeatedly with an authorized inference setup. Report actual counts and all failure categories without silently retrying away failures. Review narrative consistency and tone separately: accepted structure does not show that dialogue is truthful or enjoyable. This checker cannot detect a string promising an unauthorized reward while its numeric action remains `talk`.

Never apply a model-supplied state mutation blindly. Recheck the authoritative game state when executing a permitted action and enforce transaction/idempotency rules in the game server. This demo does not implement execution or concurrency safety.

## Sources and rights
- DeepSeek alias mapping, checked October 17, 2026: https://api-docs.deepseek.com/
- JSON Output requirements: https://api-docs.deepseek.com/guides/json_mode/
- Effective settings: https://api-docs.deepseek.com/guides/thinking_mode/
- Python parser hooks and default extensions: https://docs.python.org/3/library/json.html

The code and invented examples were created for this guide; no third-party model output or game artwork is redistributed. The accompanying concept image is illustration, not evidence of a model run.
