Compare commits
2
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
47ca557c27 | ||
|
|
560042abcb |
No files matched your search
@@ -1,98 +0,0 @@
|
|||||||
# Path Proof Receipt v0
|
|
||||||
|
|
||||||
## Decision
|
|
||||||
|
|
||||||
The smallest useful receipt is a **runtime-signed commitment to an action and its observed execution path**. It must be emitted by a trusted recorder at the model/tool boundary, not composed by the agent whose claim is being checked.
|
|
||||||
|
|
||||||
A self-reported model name or an unsigned transcript is provenance metadata, not proof.
|
|
||||||
|
|
||||||
## Receipt
|
|
||||||
|
|
||||||
The wire form is RFC 8785 canonical JSON. Hashes are lowercase SHA-256 hex. The signature covers the canonical JSON object with `attestation.sig` omitted.
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"v": 0,
|
|
||||||
"action": {
|
|
||||||
"kind": "gitea.issue.labels.replace",
|
|
||||||
"target": "stackchain/stackchain-lab-loop#3",
|
|
||||||
"request_sha256": "<sha256-of-exact-action-request>",
|
|
||||||
"result_sha256": "<sha256-of-exact-observed-result>"
|
|
||||||
},
|
|
||||||
"path": {
|
|
||||||
"model": {
|
|
||||||
"id": "<provider/model-version>",
|
|
||||||
"invocation": "<provider-or-gateway-invocation-id>"
|
|
||||||
},
|
|
||||||
"tools": {
|
|
||||||
"count": 1,
|
|
||||||
"trace_sha256": "<sha256-of-canonical-ordered-tool-events>"
|
|
||||||
},
|
|
||||||
"policy": {
|
|
||||||
"bundle_sha256": "<sha256-of-effective-policy-bundle>"
|
|
||||||
},
|
|
||||||
"code": {
|
|
||||||
"repo": "<immutable-repository-identity>",
|
|
||||||
"commit": "<full-commit-id>",
|
|
||||||
"entrypoint": "<path-or-image-digest>"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"evidence": {
|
|
||||||
"uri": "sha256:<content-addressed-evidence-bundle-digest>"
|
|
||||||
},
|
|
||||||
"attestation": {
|
|
||||||
"issuer": "<runtime-recorder-identity>",
|
|
||||||
"key_id": "<verification-key-id>",
|
|
||||||
"alg": "Ed25519",
|
|
||||||
"sig": "<base64url-signature>"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
`tools.trace_sha256` commits to a canonical ordered array of `{seq, tool, request_sha256, response_sha256}` records. The evidence bundle contains the exact request/result bytes, ordered tool records, effective policy bundle, model gateway record, and code checkout/image metadata. Secrets may be replaced by typed redaction commitments before hashing; the redaction manifest is part of the bundle.
|
|
||||||
|
|
||||||
## Why each field survives minimization
|
|
||||||
|
|
||||||
- `action` binds the receipt to the consequential effect rather than merely to an agent run.
|
|
||||||
- `model.id` plus `model.invocation` lets the recorder correlate the claim with gateway/provider evidence. A model string alone proves nothing.
|
|
||||||
- `tools.trace_sha256` commits to the complete ordered tool path without inflating the receipt.
|
|
||||||
- `policy.bundle_sha256` identifies the policy actually loaded, including system/developer/project rules after assembly—not just a policy version label.
|
|
||||||
- `code.commit` and `entrypoint` identify both source and the invoked path. For non-Git execution, `entrypoint` must be an immutable image/module digest.
|
|
||||||
- `evidence.uri` makes all commitments independently retrievable and rejects a receipt whose evidence was discarded.
|
|
||||||
- `attestation` establishes who observed these facts and detects mutation.
|
|
||||||
|
|
||||||
Removing any one of these leaves one requested claim—actual model, tool, policy, code path, or action—unbound or unverifiable.
|
|
||||||
|
|
||||||
## Recorder requirements
|
|
||||||
|
|
||||||
1. The recorder is outside the agent process and intercepts model calls, tool dispatch/results, policy assembly, and the final action result.
|
|
||||||
2. It derives model identity from the authenticated gateway/provider response, never from assistant text.
|
|
||||||
3. It hashes exact bytes with media type and canonicalization rules recorded in the evidence bundle.
|
|
||||||
4. It emits the receipt only after observing the consequential result and stores the evidence bundle under its digest.
|
|
||||||
5. Its signing key is hardware- or service-isolated from agent-controlled tools. Key metadata states issuer, validity interval, and revocation status.
|
|
||||||
|
|
||||||
## Verification algorithm
|
|
||||||
|
|
||||||
A verifier MUST:
|
|
||||||
|
|
||||||
1. Resolve a trusted key for `attestation.issuer` and `key_id`; reject revoked or out-of-validity keys.
|
|
||||||
2. Recreate RFC 8785 canonical bytes without `attestation.sig` and verify Ed25519.
|
|
||||||
3. Fetch `evidence.uri`, hash it, and require equality with the URI digest.
|
|
||||||
4. Recompute the action request/result, ordered tool trace, and effective policy hashes from evidence.
|
|
||||||
5. Verify the model invocation against authenticated gateway/provider evidence.
|
|
||||||
6. Resolve the immutable code identity and require that `entrypoint` belongs to that checkout/image.
|
|
||||||
7. Apply action-specific checks (for example, read Gitea state back and compare it with `result_sha256`).
|
|
||||||
|
|
||||||
Any missing evidence or unsupported identity yields **unverified**, not partial success.
|
|
||||||
|
|
||||||
## Threat boundary
|
|
||||||
|
|
||||||
This receipt proves only what the trusted recorder observed. It does not prove the provider ran the advertised weights unless the provider supplies a separately trusted model attestation, and it cannot survive compromise of both recorder and signing key. Those limitations must be reported explicitly rather than papered over with transcript hashes.
|
|
||||||
|
|
||||||
## Adversarial-review questions
|
|
||||||
|
|
||||||
1. Can the `model.invocation` be replayed or bound to a different request?
|
|
||||||
2. Is one `policy.bundle_sha256` sufficient to represent dynamic policy/tool authorization changes during the run?
|
|
||||||
3. What canonical evidence-bundle format permits selective disclosure without making redactions ambiguous?
|
|
||||||
4. Should code provenance require a signed build/SLSA subject instead of a Git commit for production actions?
|
|
||||||
5. Which action-specific freshness field (trusted timestamp, nonce, or transparency-log index) is the minimum needed to prevent receipt replay?
|
|
||||||
@@ -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?**
|
||||||
@@ -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.
|
||||||
@@ -0,0 +1,57 @@
|
|||||||
|
{
|
||||||
|
"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"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"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"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"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"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"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"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"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": []
|
||||||
|
}
|
||||||
@@ -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()
|
||||||
Reference in new issue
Block a user