Skip to content

Commit 835a4cd

Browse files
authored
feat: add embodied action receipt fixtures (#36)
1 parent 381b007 commit 835a4cd

12 files changed

Lines changed: 589 additions & 0 deletions

File tree

.github/workflows/ci.yml

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,3 +54,24 @@ jobs:
5454
- name: Verify committed evidence artifacts
5555
if: github.event_name == 'push' || github.event.pull_request.head.repo.full_name == github.repository
5656
run: python validate_artifacts.py
57+
58+
embodied-action-receipts:
59+
runs-on: ubuntu-latest
60+
defaults:
61+
run:
62+
working-directory: embodied-action-receipts
63+
steps:
64+
- uses: actions/checkout@v4
65+
66+
- name: Set up Python 3.11
67+
uses: actions/setup-python@v5
68+
with:
69+
python-version: "3.11"
70+
cache: "pip"
71+
cache-dependency-path: embodied-action-receipts/requirements.txt
72+
73+
- name: Install dependencies
74+
run: python -m pip install -r requirements.txt
75+
76+
- name: Verify embodied-action receipt fixtures
77+
run: python -m unittest discover -s tests -v

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ End-to-end integration examples showing cMCP, Agent Manifest, and TRACE working
1111

1212
| Example | What it shows | Platform | Compliance |
1313
|---|---|---|---|
14+
| `embodied-action-receipts/` | Fixture-style offline verification for embodied action receipts: accepted chain, missing receipt, signature mismatch and valid controller rejection | Software-only fixtures | TRACE action-receipt evidence boundary |
1415
| `financial-services/` | Credit risk agent: MiFID II escalation deny above EUR 500k with structured policy advice | SEV-SNP / TDX | EU AI Act Art. 9/12, MiFID II Art. 25, DORA Art. 9 |
1516
| `healthcare/` | Clinical decision agent: EU AI Act Art. 14 HITL deny on high-risk treatment plans | SEV-SNP / TDX | EU AI Act Art. 14, HIPAA |
1617
| `industrial-embodied-ai/` | Material-movement agent with cMCP authorization, an independent safety-controller boundary and offline-verifiable closed-session evidence | TEE / software-only development mode | OT security and industrial robot safety references |

embodied-action-receipts/README.md

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
# Embodied Action Receipt Fixtures
2+
3+
Fixture-style example for offline verification of embodied-action receipts.
4+
5+
This example complements the cMCP Embodied Action Evidence Profile and the TRACE
6+
`verification.action_receipts` axis. It demonstrates action-level evidence below
7+
a session-level TRACE claim without claiming physical completion, controller
8+
safety, or functional-safety certification.
9+
10+
Related design threads:
11+
12+
- cMCP Embodied Action Evidence Profile: agentrust-io/cmcp#339
13+
- TRACE action-receipt verification axis: agentrust-io/trace-spec#66
14+
15+
## What It Shows
16+
17+
The fixtures cover four verifier outcomes:
18+
19+
| Fixture | Expected result | What it demonstrates |
20+
|---|---|---|
21+
| `valid-chain.json` | `accepted` | A signed, hash-chained controller receipt sequence binds to the TRACE session, cMCP call id, and action reference. |
22+
| `missing-receipt.json` | `missing` | `verification.action_receipts: required` fails when no action receipt is attached. |
23+
| `signature-mismatch.json` | `invalid` | A receipt with a bad Ed25519 signature is rejected. |
24+
| `controller-rejected.json` | `rejected` | A valid signed receipt can prove controller rejection; rejection is evidence, not a verifier failure. |
25+
26+
## Boundary
27+
28+
For embodied AI, `verification.action_receipts: required` means every externally
29+
consequential action has offline-verifiable receipt evidence bound to the
30+
session or cMCP audit `call_id`.
31+
32+
It does not mean TRACE proves:
33+
34+
- physical completion;
35+
- controller safety;
36+
- functional-safety certification;
37+
- that the real world changed as intended.
38+
39+
## Run
40+
41+
```bash
42+
cd embodied-action-receipts
43+
python -m venv .venv
44+
source .venv/bin/activate
45+
pip install -r requirements.txt
46+
python -m unittest discover -s tests -v
47+
```
48+
49+
Verify one fixture manually:
50+
51+
```bash
52+
python verify_receipts.py fixtures/valid-chain.json
53+
```
54+
55+
Regenerate fixtures from the deterministic test key:
56+
57+
```bash
58+
python generate_fixtures.py
59+
```
60+
61+
The deterministic signing seed is public test material. It is only used to make
62+
the committed fixtures reproducible and must never be used in production.
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
{
2+
"action": {
3+
"action_ref": "sha256:6572d6707269d815b6f59aadeca709e29a5a7d73330265f2b5feb92d0290b21f",
4+
"action_scope": "robot-cell-7/material-bin-a",
5+
"action_timestamp": "2026-06-25T16:30:00Z",
6+
"action_type": "move_material",
7+
"agent_id": "spiffe://factory.example/agent/material-movement/dev"
8+
},
9+
"case": "controller-rejected",
10+
"expected": {
11+
"receipt_state": "rejected",
12+
"result": "valid"
13+
},
14+
"note": "A valid rejected receipt is evidence of controller rejection, not physical completion.",
15+
"receipts": [
16+
{
17+
"action_ref": "sha256:6572d6707269d815b6f59aadeca709e29a5a7d73330265f2b5feb92d0290b21f",
18+
"call_id": "call-material-move-001",
19+
"issuer": "spiffe://factory.example/controller/robot-cell-7",
20+
"issuer_key_id": "robot-cell-7-controller",
21+
"observed_at": "2026-06-25T16:30:02Z",
22+
"prev_receipt_hash": null,
23+
"reason": "human_detected_in_safeguarded_area",
24+
"receipt_id": "receipt-001",
25+
"sequence": 1,
26+
"signature": "ed25519:FvPr51RvrY9iSnUPGlTw_4dRRK8b5c7X8shDFzcaZ6hmiVoFu3m0fsWEjuSsTXi2DNbQ5NutMFZ6z8JHHSbjBQ",
27+
"terminal_state": "controller_rejected",
28+
"trace_id": "trace-session-embodied-001",
29+
"type": "embodied.action_receipt.v0",
30+
"verdict": "rejected"
31+
}
32+
],
33+
"trace": {
34+
"cmcp_call_id": "call-material-move-001",
35+
"policy_decision": "allow",
36+
"trace_id": "trace-session-embodied-001",
37+
"verification": {
38+
"action_receipts": "required"
39+
}
40+
}
41+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
{
2+
"action": {
3+
"action_ref": "sha256:6572d6707269d815b6f59aadeca709e29a5a7d73330265f2b5feb92d0290b21f",
4+
"action_scope": "robot-cell-7/material-bin-a",
5+
"action_timestamp": "2026-06-25T16:30:00Z",
6+
"action_type": "move_material",
7+
"agent_id": "spiffe://factory.example/agent/material-movement/dev"
8+
},
9+
"case": "missing-receipt",
10+
"expected": {
11+
"receipt_state": "missing",
12+
"result": "invalid"
13+
},
14+
"receipts": [],
15+
"trace": {
16+
"cmcp_call_id": "call-material-move-001",
17+
"policy_decision": "allow",
18+
"trace_id": "trace-session-embodied-001",
19+
"verification": {
20+
"action_receipts": "required"
21+
}
22+
}
23+
}
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
{
2+
"action": {
3+
"action_ref": "sha256:6572d6707269d815b6f59aadeca709e29a5a7d73330265f2b5feb92d0290b21f",
4+
"action_scope": "robot-cell-7/material-bin-a",
5+
"action_timestamp": "2026-06-25T16:30:00Z",
6+
"action_type": "move_material",
7+
"agent_id": "spiffe://factory.example/agent/material-movement/dev"
8+
},
9+
"case": "signature-mismatch",
10+
"expected": {
11+
"receipt_state": "invalid_signature",
12+
"result": "invalid"
13+
},
14+
"receipts": [
15+
{
16+
"action_ref": "sha256:6572d6707269d815b6f59aadeca709e29a5a7d73330265f2b5feb92d0290b21f",
17+
"call_id": "call-material-move-001",
18+
"issuer": "spiffe://factory.example/controller/robot-cell-7",
19+
"issuer_key_id": "robot-cell-7-controller",
20+
"observed_at": "2026-06-25T16:30:01Z",
21+
"prev_receipt_hash": null,
22+
"receipt_id": "receipt-001",
23+
"sequence": 1,
24+
"signature": "ed25519:GqkLo5j8ZJzjOGwyv8hzS8vdgaYr_1VAZtdgoNTyjMU0NDuCAXK0oDiC2TTz2raMdXy7KiOoWlr4LgBDzWlGDA",
25+
"terminal_state": "handoff_accepted",
26+
"trace_id": "trace-session-embodied-001",
27+
"type": "embodied.action_receipt.v0",
28+
"verdict": "accepted"
29+
},
30+
{
31+
"action_ref": "sha256:6572d6707269d815b6f59aadeca709e29a5a7d73330265f2b5feb92d0290b21f",
32+
"call_id": "call-material-move-001",
33+
"issuer": "spiffe://factory.example/controller/robot-cell-7",
34+
"issuer_key_id": "robot-cell-7-controller",
35+
"observed_at": "2026-06-25T16:30:05Z",
36+
"prev_receipt_hash": "sha256:997a9dd7abb8e6a32bab079da314b62bf867605428f7920e91f2a806db1cd338",
37+
"receipt_id": "receipt-002",
38+
"sequence": 2,
39+
"signature": "ed25519:RdJXHXzttRHLqKm6ockpPAU5-Odc3mZuEwzw4wNZRlm-QNPiQTvp2_LJ33TWqquhebJ9PFaq0SS4UEBW3G7bAQ",
40+
"terminal_state": "controller_completed",
41+
"trace_id": "trace-session-embodied-001",
42+
"type": "embodied.action_receipt.v0",
43+
"verdict": "accepted"
44+
}
45+
],
46+
"trace": {
47+
"cmcp_call_id": "call-material-move-001",
48+
"policy_decision": "allow",
49+
"trace_id": "trace-session-embodied-001",
50+
"verification": {
51+
"action_receipts": "required"
52+
}
53+
}
54+
}
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
{
2+
"action": {
3+
"action_ref": "sha256:6572d6707269d815b6f59aadeca709e29a5a7d73330265f2b5feb92d0290b21f",
4+
"action_scope": "robot-cell-7/material-bin-a",
5+
"action_timestamp": "2026-06-25T16:30:00Z",
6+
"action_type": "move_material",
7+
"agent_id": "spiffe://factory.example/agent/material-movement/dev"
8+
},
9+
"case": "valid-chain",
10+
"expected": {
11+
"receipt_state": "accepted",
12+
"result": "valid"
13+
},
14+
"receipts": [
15+
{
16+
"action_ref": "sha256:6572d6707269d815b6f59aadeca709e29a5a7d73330265f2b5feb92d0290b21f",
17+
"call_id": "call-material-move-001",
18+
"issuer": "spiffe://factory.example/controller/robot-cell-7",
19+
"issuer_key_id": "robot-cell-7-controller",
20+
"observed_at": "2026-06-25T16:30:01Z",
21+
"prev_receipt_hash": null,
22+
"receipt_id": "receipt-001",
23+
"sequence": 1,
24+
"signature": "ed25519:GqkLo5j8ZJzjOGwyv8hzS8vdgaYr_1VAZtdgoNTyjMU0NDuCAXK0oDiC2TTz2raMdXy7KiOoWlr4LgBDzWlGDw",
25+
"terminal_state": "handoff_accepted",
26+
"trace_id": "trace-session-embodied-001",
27+
"type": "embodied.action_receipt.v0",
28+
"verdict": "accepted"
29+
},
30+
{
31+
"action_ref": "sha256:6572d6707269d815b6f59aadeca709e29a5a7d73330265f2b5feb92d0290b21f",
32+
"call_id": "call-material-move-001",
33+
"issuer": "spiffe://factory.example/controller/robot-cell-7",
34+
"issuer_key_id": "robot-cell-7-controller",
35+
"observed_at": "2026-06-25T16:30:05Z",
36+
"prev_receipt_hash": "sha256:997a9dd7abb8e6a32bab079da314b62bf867605428f7920e91f2a806db1cd338",
37+
"receipt_id": "receipt-002",
38+
"sequence": 2,
39+
"signature": "ed25519:RdJXHXzttRHLqKm6ockpPAU5-Odc3mZuEwzw4wNZRlm-QNPiQTvp2_LJ33TWqquhebJ9PFaq0SS4UEBW3G7bAQ",
40+
"terminal_state": "controller_completed",
41+
"trace_id": "trace-session-embodied-001",
42+
"type": "embodied.action_receipt.v0",
43+
"verdict": "accepted"
44+
}
45+
],
46+
"trace": {
47+
"cmcp_call_id": "call-material-move-001",
48+
"policy_decision": "allow",
49+
"trace_id": "trace-session-embodied-001",
50+
"verification": {
51+
"action_receipts": "required"
52+
}
53+
}
54+
}

0 commit comments

Comments
 (0)