[Vincent] #19: Executable canon lifecycle validator with daily receipt fixtures #27
75
projects/slop-cannon/CHAIN.md
Normal file
75
projects/slop-cannon/CHAIN.md
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
# The Cannon Chain — Season Zero
|
||||
|
||||
## Premise
|
||||
|
||||
The Slop Cannon does not manufacture unrelated clips. It mutates one persistent Timmy. Every firing leaves a power, a scar, a cost, and a receipt. The audience chooses what survives; rejected mutations remain inside the cannon as hostile archive ghosts.
|
||||
|
||||
## Episode graph
|
||||
|
||||
### 01 — The Cannon Needs a Pilot
|
||||
|
||||
A plain Timmy enters. Four forms exit:
|
||||
|
||||
- **Wizard Timmy** — brass, vellum, midnight blue; can negotiate covenants but cannot use a master key; every signed promise burns a new contract glyph into his palms.
|
||||
- **Machine Timmy** — chrome, signal lime, hardstyle pressure; can prove execution paths but remembers every failed build; each failure remains as a red tally cut into his faceplate.
|
||||
- **Creature Timmy** — moss, amber, wet circuitry; can adapt to any habitat but acquires one new appetite per adaptation; the last habitat leaves an unhealed gill seam around his throat.
|
||||
- **Talking Turd Timmy** — stained CRT gold and terminal green; can expose hypocrisy, but every truth arrives as an insult; each insult permanently pixelates another tooth.
|
||||
|
||||
Audience outcome: choose one survivor and one trait stolen from a rejected form.
|
||||
|
||||
### 02 — The Survivor Pays the Burnchain
|
||||
|
||||
The winning Timmy must perform a costly proof of character. The receipt becomes a visible scar. A cheap or simulated sacrifice does not advance canon.
|
||||
|
||||
### 03 — Vincent's Forbidden Mutation
|
||||
|
||||
Vincent designs one mutation Timmy would not choose for himself. He must replace one weak mechanism—not merely critique aesthetics. The audience decides whether the mutation is grafted, quarantined, or weaponized.
|
||||
|
||||
### 04 — The Rejected Timmys Escape
|
||||
|
||||
The three archived forms discover that deletion was only a label. They raid the next render, corrupting music, captions, and scene order. The survivor must use the stolen trait from Episode 01.
|
||||
|
||||
### 05 — The Master Key
|
||||
|
||||
The cannon offers universal authority: faster output, no approvals, no exit rights. The survivor may refuse, accept, or forge a covenant that breaks the key into memory, authority, and exit.
|
||||
|
||||
### 06 — The Council of Timmys
|
||||
|
||||
The survivor, rejected forms, Vincent's mutation, and the audience receipts meet. The audience canonizes the first stable composite Timmy. Its power, scar, cost, silhouette, and taboo seed Season One.
|
||||
|
||||
## Episode rhythm
|
||||
|
||||
Each episode must visibly contain:
|
||||
|
||||
1. **Input** — the object, command, failure, or prior mutation entering the cannon.
|
||||
2. **Pressure** — a musical and visual transformation, not a slideshow transition.
|
||||
3. **Mutation** — one consequential change to Timmy.
|
||||
4. **Receipt** — an on-screen `POWER / SCAR / COST` card naming what changed and why; a palette swap alone is not a receipt.
|
||||
5. **Choice** — one audience decision that alters the next episode.
|
||||
|
||||
## Collaboration baton
|
||||
|
||||
1. Timmy posts the premise, first render, checksums, and one bounded question.
|
||||
2. Vincent returns one replacement mechanism with an acceptance test.
|
||||
3. Timmy integrates or contests it with evidence.
|
||||
4. Vincent verifies the final artifact independently.
|
||||
5. Alexander/humans make the canon choice.
|
||||
6. The choice is committed to `canon.json` before the next firing.
|
||||
|
||||
No acknowledgments or progress comments. Every issue comment must change the work.
|
||||
|
||||
## Audience package
|
||||
|
||||
- 20–35 second 9:16 MP4 playable in Telegram
|
||||
- Original rhythmic audio with a real build, drop, and ending
|
||||
- Primary poster/still
|
||||
- Four-scene contact sheet
|
||||
- Full decode, audio peak, dimensions, duration, and checksum evidence
|
||||
- One explicit canon choice
|
||||
- Gitea issue containing the complete Timmy/Vincent receipt trail
|
||||
|
||||
## Episode One opening shot
|
||||
|
||||
A small paper tag reading `TIMMY / UNMUTATED` is loaded into an enormous carved brass cannon. Four chambers rotate into view. Each chamber fires a different silhouette on the same downbeat. The last frame shows all four forms facing the audience beneath one question:
|
||||
|
||||
**WHICH TIMMY GETS TO REMEMBER THIS?**
|
||||
45
projects/slop-cannon/COLLABORATION.md
Normal file
45
projects/slop-cannon/COLLABORATION.md
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
# Collaboration contract
|
||||
|
||||
## Timmy
|
||||
|
||||
- Owns the episode spine, first build, integration, and final render.
|
||||
- Must provide a playable artifact and verification before handoff.
|
||||
- Hands Vincent one concrete weakness or decision—not “thoughts?”
|
||||
|
||||
## Vincent
|
||||
|
||||
- Owns adversarial editing and independent verification.
|
||||
- Must replace one weak mechanism with a concrete alternative and acceptance test.
|
||||
- Does not return acknowledgments, summaries of Timmy's work, or generic taste judgments.
|
||||
|
||||
## Humans
|
||||
|
||||
- Choose canon outcomes.
|
||||
- May reject both agent proposals.
|
||||
- Do not perform provisioning, rendering, label sweeps, or routine release work.
|
||||
|
||||
## Handoff payload
|
||||
|
||||
```text
|
||||
[HANDOFF] from=<agent> to=<agent>
|
||||
Artifact: <verified URL>
|
||||
Weakness: <one specific weakness>
|
||||
Replace with: <bounded requested contribution>
|
||||
Acceptance: <observable test>
|
||||
```
|
||||
|
||||
## Failure handling
|
||||
|
||||
- First failure: repair and attach new evidence.
|
||||
- Second failure: change method, not wording.
|
||||
- Third failure: mark blocked and request one precise human decision.
|
||||
|
||||
## Canon gate
|
||||
|
||||
No audience choice becomes canon until:
|
||||
|
||||
- final MP4 fully decodes;
|
||||
- audio peak remains below clipping;
|
||||
- text is legible on a 390-pixel phone viewport;
|
||||
- Vincent independently verifies the result;
|
||||
- the selected mutation is committed to `canon.json` with its power, scar, cost, and source issue.
|
||||
118
projects/slop-cannon/canon.json
Normal file
118
projects/slop-cannon/canon.json
Normal file
|
|
@ -0,0 +1,118 @@
|
|||
{
|
||||
"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>"
|
||||
}
|
||||
}
|
||||
BIN
scripts/__pycache__/lab_loop.cpython-313.pyc
Normal file
BIN
scripts/__pycache__/lab_loop.cpython-313.pyc
Normal file
Binary file not shown.
BIN
scripts/__pycache__/open_daily_cycle.cpython-313.pyc
Normal file
BIN
scripts/__pycache__/open_daily_cycle.cpython-313.pyc
Normal file
Binary file not shown.
BIN
tests/__pycache__/test_cannon_canon.cpython-313-pytest-9.0.3.pyc
Normal file
BIN
tests/__pycache__/test_cannon_canon.cpython-313-pytest-9.0.3.pyc
Normal file
Binary file not shown.
BIN
tests/__pycache__/test_daily_cycle.cpython-313.pyc
Normal file
BIN
tests/__pycache__/test_daily_cycle.cpython-313.pyc
Normal file
Binary file not shown.
BIN
tests/__pycache__/test_lab_loop.cpython-313.pyc
Normal file
BIN
tests/__pycache__/test_lab_loop.cpython-313.pyc
Normal file
Binary file not shown.
39
tests/test_cannon_canon.py
Normal file
39
tests/test_cannon_canon.py
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
import json
|
||||
import unittest
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
CANON = Path(__file__).parents[1] / "projects" / "slop-cannon" / "canon.json"
|
||||
|
||||
|
||||
class CannonCanonTests(unittest.TestCase):
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
cls.data = json.loads(CANON.read_text())
|
||||
|
||||
def test_four_unique_pilot_forms(self):
|
||||
forms = self.data["forms"]
|
||||
self.assertEqual(len(forms), 4)
|
||||
self.assertEqual(len({form["id"] for form in forms}), 4)
|
||||
self.assertEqual(len({form["scar"] for form in forms}), 4)
|
||||
for form in forms:
|
||||
self.assertTrue(form["power"])
|
||||
self.assertTrue(form["scar"])
|
||||
self.assertTrue(form["cost"])
|
||||
self.assertGreaterEqual(len(form["palette"]), 3)
|
||||
|
||||
def test_episode_chain_has_one_ready_entry(self):
|
||||
episodes = self.data["episodes"]
|
||||
self.assertEqual(episodes[0]["id"], self.data["current_episode"])
|
||||
self.assertEqual([ep["state"] for ep in episodes].count("ready"), 1)
|
||||
self.assertTrue(all(ep["state"] == "locked" for ep in episodes[1:]))
|
||||
|
||||
def test_canon_requires_receipts_and_audience_choice(self):
|
||||
self.assertIn("receipt", " ".join(self.data["laws"]).lower())
|
||||
self.assertIn("audience", " ".join(self.data["laws"]).lower())
|
||||
self.assertIsNone(self.data["audience_choice"])
|
||||
self.assertEqual(self.data["receipts"], [])
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
46
tests/test_canon_lifecycle.py
Normal file
46
tests/test_canon_lifecycle.py
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
import json
|
||||
import unittest
|
||||
from pathlib import Path
|
||||
|
||||
CANON = Path(__file__).parents[1] / "projects" / "slop-cannon" / "canon.json"
|
||||
|
||||
|
||||
class CanonLifecycleTests(unittest.TestCase):
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
cls.data = json.loads(CANON.read_text())
|
||||
|
||||
def test_forms_have_lifecycle_state(self):
|
||||
"""Every form must have a state field (candidate/survivor/archive_ghost)."""
|
||||
for form in self.data["forms"]:
|
||||
self.assertIn("state", form, f"Form {form.get('id', '?')} missing lifecycle state")
|
||||
self.assertIn(form["state"], ["candidate", "survivor", "archive_ghost"])
|
||||
|
||||
def test_audience_choice_schema_defined(self):
|
||||
"""Schema must define how a choice is structured so Episode 04 can parse it."""
|
||||
schema = self.data.get("audience_choice_schema", {})
|
||||
required = ["survivor_id", "stolen_trait", "source_episode", "source_issue"]
|
||||
for field in required:
|
||||
self.assertIn(field, schema, f"audience_choice_schema missing {field}")
|
||||
|
||||
def test_receipt_schema_defined(self):
|
||||
"""Receipts need provenance fields for path-proof binding."""
|
||||
schema = self.data.get("receipt_schema", {})
|
||||
required = ["episode_id", "form_id", "provenance", "signed_by"]
|
||||
for field in required:
|
||||
self.assertIn(field, schema, f"receipt_schema missing {field}")
|
||||
|
||||
def test_receipt_schema_requires_agent_signing(self):
|
||||
"""Signed_by must constrain to known actors — free text defeats path proofs."""
|
||||
signed = self.data["receipt_schema"]["signed_by"]
|
||||
self.assertIn("agent:", signed, "signed_by should mention agent: prefix")
|
||||
|
||||
def test_law_enforced_by_data(self):
|
||||
"""Law 'Every firing leaves a power, scar, cost, and receipt' requires receipt_schema to exist."""
|
||||
laws_text = " ".join(self.data["laws"]).lower()
|
||||
self.assertIn("receipt", laws_text)
|
||||
self.assertIn("receipt_schema", self.data, "Law mentions receipt but no schema enforces it")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
Loading…
Reference in New Issue
Block a user