feat(api): canon log JSON Schema + validator, enforce §7 luck boundary

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-07-09 12:31:10 -05:00
parent 710745e548
commit 843ab11a5c
3 changed files with 170 additions and 0 deletions

View File

@@ -0,0 +1,58 @@
import copy
import json
from pathlib import Path
from app.canon_log import validate_canon_log
FIXTURE = Path(__file__).parent / "fixtures" / "canon_log_valid.json"
def _valid():
with open(FIXTURE) as f:
return json.load(f)
def test_valid_canon_log_passes():
assert validate_canon_log(_valid()) == []
def test_numeric_luck_is_rejected():
# Charter §7: the AI must never be able to calculate Luck. A stray numeric
# luck field must fail validation, not slip through.
doc = _valid()
doc["player"]["luck"] = 5
assert validate_canon_log(doc) != []
def test_recent_events_over_five_is_rejected():
doc = _valid()
doc["recent_events"] = [f"event {i}" for i in range(6)]
assert validate_canon_log(doc) != []
def test_disposition_out_of_range_is_rejected():
doc = _valid()
doc["party"][0]["disposition"] = 200
assert validate_canon_log(doc) != []
def test_unknown_quest_status_is_rejected():
doc = _valid()
doc["active_quests"][0]["status"] = "abandoned"
assert validate_canon_log(doc) != []
def test_humiliation_weight_bounds_enforced():
doc = _valid()
doc["humiliations"][0]["weight"] = 11
assert validate_canon_log(doc) != []
def test_empty_optional_arrays_are_allowed():
doc = _valid()
doc["party"] = []
doc["recent_events"] = []
doc["established_facts"] = []
doc["active_quests"] = []
doc["humiliations"] = []
assert validate_canon_log(doc) == []