Builds on #13/PR #18 review. Makes canon lifecycle machine-checkable. Deliverables: 1. Dependency-free canon_validator.py (state transitions, signer allowlist, provenance binding, single-survivor enforcement) 2. 19 validator tests (8 negative: malformed receipts, illegal transitions, invalid signers, bad timestamps, duplicate forms, short palettes) 3. Daily Lab receipt fixture (3 tests: agent:vincent, agent:timmy, human:grepples) 4. Full suite integration - 31 tests pass from clean checkout 5. .gitignore for bytecode, renamed slop-cannon → slop_cannon (Python import) Closes #19 Refs: #5, #13, PR #12, PR #18
118 lines
3.0 KiB
JSON
118 lines
3.0 KiB
JSON
{
|
|
"schema_version": 1,
|
|
"series": "The Cannon Chain",
|
|
"season": 0,
|
|
"current_episode": "01-pilot",
|
|
"pilot": "TIMMY",
|
|
"laws": [
|
|
"Every firing leaves a power, scar, cost, and receipt.",
|
|
"Only an audience choice advances canon.",
|
|
"Rejected mutations persist as archive ghosts.",
|
|
"No master key may silently combine memory, authority, and exit."
|
|
],
|
|
"forms": [
|
|
{
|
|
"id": "wizard",
|
|
"name": "Wizard Timmy",
|
|
"palette": [
|
|
"midnight blue",
|
|
"tarnished brass",
|
|
"vellum"
|
|
],
|
|
"power": "Negotiates visible covenants",
|
|
"scar": "Contract glyphs burned into both palms",
|
|
"cost": "Cannot use a universal master key",
|
|
"state": "candidate"
|
|
},
|
|
{
|
|
"id": "machine",
|
|
"name": "Machine Timmy",
|
|
"palette": [
|
|
"black chrome",
|
|
"signal lime",
|
|
"white"
|
|
],
|
|
"power": "Proves the execution path",
|
|
"scar": "Red failed-build tallies cut into the faceplate",
|
|
"cost": "Remembers every failed build",
|
|
"state": "candidate"
|
|
},
|
|
{
|
|
"id": "creature",
|
|
"name": "Creature Timmy",
|
|
"palette": [
|
|
"moss",
|
|
"amber",
|
|
"wet copper"
|
|
],
|
|
"power": "Adapts to any habitat",
|
|
"scar": "An unhealed gill seam around the throat",
|
|
"cost": "Gains one appetite per adaptation",
|
|
"state": "candidate"
|
|
},
|
|
{
|
|
"id": "talking-turd",
|
|
"name": "Talking Turd Timmy",
|
|
"palette": [
|
|
"CRT gold",
|
|
"terminal green",
|
|
"soot"
|
|
],
|
|
"power": "Exposes hypocrisy instantly",
|
|
"scar": "One permanently pixelated tooth per insult",
|
|
"cost": "Every truth arrives as an insult",
|
|
"state": "candidate"
|
|
}
|
|
],
|
|
"episodes": [
|
|
{
|
|
"id": "01-pilot",
|
|
"title": "The Cannon Needs a Pilot",
|
|
"state": "ready"
|
|
},
|
|
{
|
|
"id": "02-burnchain",
|
|
"title": "The Survivor Pays the Burnchain",
|
|
"state": "locked"
|
|
},
|
|
{
|
|
"id": "03-vincent",
|
|
"title": "Vincent's Forbidden Mutation",
|
|
"state": "locked"
|
|
},
|
|
{
|
|
"id": "04-escape",
|
|
"title": "The Rejected Timmys Escape",
|
|
"state": "locked"
|
|
},
|
|
{
|
|
"id": "05-master-key",
|
|
"title": "The Master Key",
|
|
"state": "locked"
|
|
},
|
|
{
|
|
"id": "06-council",
|
|
"title": "The Council of Timmys",
|
|
"state": "locked"
|
|
}
|
|
],
|
|
"audience_choice": null,
|
|
"receipts": [],
|
|
"audience_choice_schema": {
|
|
"survivor_id": "<form.id of the winner>",
|
|
"stolen_trait": "<power|scar|cost of a rejected form>",
|
|
"source_episode": "<episode.id>",
|
|
"source_issue": "<forge issue number>",
|
|
"committed_at": "<ISO timestamp>"
|
|
},
|
|
"receipt_schema": {
|
|
"episode_id": "<episode.id>",
|
|
"form_id": "<form.id>",
|
|
"action": "<mutation|graft|quarantine|weaponize>",
|
|
"power_delta": "<what changed>",
|
|
"scar_delta": "<what was added>",
|
|
"cost_delta": "<what was paid>",
|
|
"provenance": "<forge issue or commit ref>",
|
|
"signed_by": "<agent:vincent|agent:timmy|human:grepples>"
|
|
}
|
|
} |