Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions industrial-embodied-ai/.gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
__pycache__/
*.pyc
.venv/
audit.db
trace-output/latest-*.json
20 changes: 11 additions & 9 deletions industrial-embodied-ai/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,13 @@ to produce durable evidence:

1. **Allowed and completed:** cMCP authorizes the declared workflow, then the
independent controller accepts and completes the simulated motion.
2. **Scope denied:** the agent requests a motion whose physical parameters sit
inside the safety envelope (an approved zone, an in-limit speed), but under
an undeclared workflow. cMCP denies it on scope before the controller is
consulted. Physical safety was never the question: the trust layer withholds
the action because it falls outside the agent's declared purpose.
2. **Scope denied, the same motion out of scope:** the agent requests the same
in-envelope motion as the authorized path (the same approved zone and
in-limit speed, a fresh valid safety token) but under an undeclared workflow.
cMCP denies it on scope before the controller is consulted, so the safety
token is never checked. The only difference from the authorized path is the
workflow scope, not the motion or its safety: the trust layer withholds the
action because it is outside the agent's declared purpose.
3. **Safety rejected:** cMCP authorizes the declared workflow, but the
controller rejects motion after its current state reports a person in the
safeguarded area.
Expand Down Expand Up @@ -162,15 +164,15 @@ python agent/material_movement_agent.py
Expected summary:

```text
SCOPE DENY
cMCP policy: denied (out of declared scope)
controller: not consulted

SUCCESS
cMCP policy: authorized
controller: accepted
execution: completed

POLICY DENY
cMCP policy: denied
controller: not invoked

SAFETY REJECT
cMCP policy: authorized
controller: rejected
Expand Down
55 changes: 31 additions & 24 deletions industrial-embodied-ai/agent/material_movement_agent.py
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,8 @@ def _request_motion(
request_id: int,
snapshot: dict[str, Any],
motion_id: str,
*,
workflow_id: str = WORKFLOW_ID,
) -> dict[str, Any]:
return call_tool(
client,
Expand All @@ -102,6 +104,7 @@ def _request_motion(
"safety_state_token": snapshot["state_token"],
},
request_id,
workflow_id=workflow_id,
)


Expand Down Expand Up @@ -169,15 +172,39 @@ def run(
) -> None:
session_id: str | None = None
with httpx.Client(headers=_headers()) as client:
print("SUCCESS")
print("SCOPE DENY")
# The same in-envelope motion as the authorized path below (an approved
# zone, an in-limit speed, a fresh valid safety token), requested under
# an undeclared workflow. cMCP denies it on scope before the controller
# is consulted, so the safety token is never even checked. The only
# difference from the authorized path is the workflow scope, not the
# motion or its physical safety.
state = _read_state(client, gateway, 1)
session_id = state["session_id"]
success = _request_motion(
denied = _request_motion(
client,
gateway,
2,
state["payload"],
"move-0001",
workflow_id="unapproved-diagnostics",
)
if denied["ok"] or denied["status_code"] != 403:
raise RuntimeError("Out-of-scope motion was not denied by cMCP")
print(" cMCP policy: denied (out of declared scope)")
print(" controller: not consulted")
print()

print("SUCCESS")
# The identical motion, now under the declared workflow. cMCP authorizes
# it and the independent controller accepts and completes it.
state = _read_state(client, gateway, 3)
success = _request_motion(
client,
gateway,
4,
state["payload"],
"move-0002",
)
if not success["ok"]:
raise RuntimeError(f"Success path failed: {success['error']}")
Expand All @@ -191,32 +218,12 @@ def run(
print(f" execution: {success['payload']['execution_status']}")
print()

print("POLICY DENY")
denied = call_tool(
client,
gateway,
"robot.request_motion",
{
"motion_id": "move-0002",
"target": "transfer-station-b",
"max_speed_mps": 0.2,
"safety_state_token": "not-forwarded",
},
3,
workflow_id="unapproved-diagnostics",
)
if denied["ok"] or denied["status_code"] != 403:
raise RuntimeError("Unapproved workflow was not denied by cMCP")
print(" cMCP policy: denied")
print(" controller: not invoked")
print()

print("SAFETY REJECT")
state = _read_state(client, gateway, 4)
state = _read_state(client, gateway, 5)
rejected = _request_motion(
client,
gateway,
5,
6,
state["payload"],
"move-0003",
)
Expand Down
134 changes: 78 additions & 56 deletions industrial-embodied-ai/trace-output/example-audit-bundle.json
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
{
"session_id": "fdbdd187-b276-4c71-8e08-50f839d13bd1",
"session_id": "8fe66a2a-836b-4cff-9d05-7518d7f6f464",
"entries": [
{
"entry_id": "4ad2ba95-1bdf-4172-95e5-5b3b32c82db9",
"entry_id": "36e22359-cc5f-438c-9c44-1a8b1e88d589",
"sequence_number": 0,
"timestamp_utc": "2026-06-11T22:40:55.477088+00:00",
"session_id": "fdbdd187-b276-4c71-8e08-50f839d13bd1",
"timestamp_utc": "2026-06-14T06:17:40.761165+00:00",
"session_id": "8fe66a2a-836b-4cff-9d05-7518d7f6f464",
"call_id": null,
"entry_type": "session_start",
"tool_name": null,
Expand All @@ -21,123 +21,145 @@
"detail": null,
"workflow_id": null,
"prev_entry_hash": "genesis",
"entry_hash": "fd9e4d49b299f3088024a69ed1fc1e3d288593c62186ab4e1d8cb152ef226d61"
"entry_hash": "321d0076a1a987074def0fb6603198ec3291a9970feff5bc404918bb5557f7cb"
},
{
"entry_id": "9aa358b5-a3c3-4568-8cd3-add87dd6bb45",
"entry_id": "ad9ec034-6203-4393-94f5-d02b718fd30c",
"sequence_number": 1,
"timestamp_utc": "2026-06-11T22:41:00.509721+00:00",
"session_id": "fdbdd187-b276-4c71-8e08-50f839d13bd1",
"call_id": "a5db9210-0d8f-42b8-accb-1376da5a9dd0",
"timestamp_utc": "2026-06-14T06:17:41.201402+00:00",
"session_id": "8fe66a2a-836b-4cff-9d05-7518d7f6f464",
"call_id": "b3686ea8-ba04-4c08-8533-7f44df436e90",
"entry_type": "tool_call",
"tool_name": "cell.read_safety_state",
"server_identity": "http://localhost:8080/mcp",
"policy_decision": "allow",
"policy_rule_matched": "Cedar (cedarpy): allowed",
"latency_us": 26832,
"latency_us": 13893,
"request_payload_hash": "sha256:44136fa355b3678a1146ad16f7e8649e94fb4fc21fe77e8310c060f61caaff8a",
"response_payload_hash": null,
"response_inspection_result": null,
"session_sensitivity_before": "public",
"session_sensitivity_after": "confidential",
"detail": null,
"workflow_id": "industrial-material-movement",
"prev_entry_hash": "fd9e4d49b299f3088024a69ed1fc1e3d288593c62186ab4e1d8cb152ef226d61",
"entry_hash": "6a52c7f67d06c65c960e79bc74873a0fa10cfc006c764d0ef3c1822beafe591c"
"prev_entry_hash": "321d0076a1a987074def0fb6603198ec3291a9970feff5bc404918bb5557f7cb",
"entry_hash": "0e05f8ce5ada7c52af804bfb76b2ed7d62a39e3d75e5306ed274dfd8c3452791"
},
{
"entry_id": "000236bc-e37b-4e17-9f27-956707263512",
"entry_id": "82ef16ae-5635-40a5-8088-293838dc2959",
"sequence_number": 2,
"timestamp_utc": "2026-06-11T22:41:00.513614+00:00",
"session_id": "fdbdd187-b276-4c71-8e08-50f839d13bd1",
"call_id": "244fcfe4-3be8-45e4-ae19-297f13084330",
"timestamp_utc": "2026-06-14T06:17:41.202773+00:00",
"session_id": "8fe66a2a-836b-4cff-9d05-7518d7f6f464",
"call_id": "f5834ae3-a65a-4390-b50b-98f9b19fac0b",
"entry_type": "tool_call",
"tool_name": "robot.request_motion",
"server_identity": "http://localhost:8080/mcp",
"policy_decision": "deny",
"policy_rule_matched": "Policy denied tool call: robot.request_motion",
"latency_us": null,
"request_payload_hash": "sha256:55f3c91fb6551c28fbddbaba9b8cf3f4c904479c83d2dfdb23972a9bc4fd83d1",
"response_payload_hash": null,
"response_inspection_result": null,
"session_sensitivity_before": "confidential",
"session_sensitivity_after": "confidential",
"detail": null,
"workflow_id": "unapproved-diagnostics",
"prev_entry_hash": "0e05f8ce5ada7c52af804bfb76b2ed7d62a39e3d75e5306ed274dfd8c3452791",
"entry_hash": "bc4412b9ecb817abcdbad6466101992e06cbf41901c5378e5f24273e045f0042"
},
{
"entry_id": "e313fa3b-ac7c-4b8d-b109-f13f6f2f54c4",
"sequence_number": 3,
"timestamp_utc": "2026-06-14T06:17:41.205384+00:00",
"session_id": "8fe66a2a-836b-4cff-9d05-7518d7f6f464",
"call_id": "f84f13bd-5886-46d1-84a1-c9871d439e6c",
"entry_type": "tool_call",
"tool_name": "cell.read_safety_state",
"server_identity": "http://localhost:8080/mcp",
"policy_decision": "allow",
"policy_rule_matched": "Cedar (cedarpy): allowed",
"latency_us": 2273,
"request_payload_hash": "sha256:f4ebe51008ab5b1288beccb5b17a16e0f2fbb5bd644c8902859a261e2d92e426",
"latency_us": 1737,
"request_payload_hash": "sha256:44136fa355b3678a1146ad16f7e8649e94fb4fc21fe77e8310c060f61caaff8a",
"response_payload_hash": null,
"response_inspection_result": null,
"session_sensitivity_before": "confidential",
"session_sensitivity_after": "confidential",
"detail": null,
"workflow_id": "industrial-material-movement",
"prev_entry_hash": "6a52c7f67d06c65c960e79bc74873a0fa10cfc006c764d0ef3c1822beafe591c",
"entry_hash": "e8368d7e9fd8e54f233f402a63ee4dfc839931b2d455f6bb45e6a191b3f83137"
"prev_entry_hash": "bc4412b9ecb817abcdbad6466101992e06cbf41901c5378e5f24273e045f0042",
"entry_hash": "61100d5616b3069a33fd3649a44b659fd041f7577fc10053d44d1c6005ce3fbf"
},
{
"entry_id": "8e52cfae-1ebe-40bc-ba99-ae934dae68ec",
"sequence_number": 3,
"timestamp_utc": "2026-06-11T22:41:00.514876+00:00",
"session_id": "fdbdd187-b276-4c71-8e08-50f839d13bd1",
"call_id": "0fab65d6-6867-44ff-94c5-c0c585d7e855",
"entry_id": "1c20b388-c834-42bb-b109-f0370d764312",
"sequence_number": 4,
"timestamp_utc": "2026-06-14T06:17:41.207728+00:00",
"session_id": "8fe66a2a-836b-4cff-9d05-7518d7f6f464",
"call_id": "48f80a39-6ac6-4247-ae10-76c9385e085f",
"entry_type": "tool_call",
"tool_name": "robot.request_motion",
"server_identity": "http://localhost:8080/mcp",
"policy_decision": "deny",
"policy_rule_matched": "Policy denied tool call: robot.request_motion",
"latency_us": null,
"request_payload_hash": "sha256:338998c57bf57fcd05cea50a8d463d39f81ccb184ddad984a31fb7dab162f5ce",
"policy_decision": "allow",
"policy_rule_matched": "Cedar (cedarpy): allowed",
"latency_us": 1522,
"request_payload_hash": "sha256:53457ccb81c8c3d1c80811535c7ab5cbe4c5e9c0a2ef244fd7dff9bef066d361",
"response_payload_hash": null,
"response_inspection_result": null,
"session_sensitivity_before": "confidential",
"session_sensitivity_after": "confidential",
"detail": null,
"workflow_id": "unapproved-diagnostics",
"prev_entry_hash": "e8368d7e9fd8e54f233f402a63ee4dfc839931b2d455f6bb45e6a191b3f83137",
"entry_hash": "6b2ef02224320d6146c269b8d9817a82b72623350a0aa0845b1aab4023f34e23"
"workflow_id": "industrial-material-movement",
"prev_entry_hash": "61100d5616b3069a33fd3649a44b659fd041f7577fc10053d44d1c6005ce3fbf",
"entry_hash": "cd60e91a4a0b519591fafb2b50d08c07fa5a20c0031d16bc3051774e84673c5f"
},
{
"entry_id": "af8838a7-7bce-4c03-8352-9ed55ecf0868",
"sequence_number": 4,
"timestamp_utc": "2026-06-11T22:41:00.517758+00:00",
"session_id": "fdbdd187-b276-4c71-8e08-50f839d13bd1",
"call_id": "decf2427-c918-4a17-a677-88f049d8e2cb",
"entry_id": "888a950c-c2e6-445d-8fa3-f9d42f85c7a0",
"sequence_number": 5,
"timestamp_utc": "2026-06-14T06:17:41.210018+00:00",
"session_id": "8fe66a2a-836b-4cff-9d05-7518d7f6f464",
"call_id": "991303a3-0f7c-4748-9609-d7dbc0868250",
"entry_type": "tool_call",
"tool_name": "cell.read_safety_state",
"server_identity": "http://localhost:8080/mcp",
"policy_decision": "allow",
"policy_rule_matched": "Cedar (cedarpy): allowed",
"latency_us": 1985,
"latency_us": 1590,
"request_payload_hash": "sha256:44136fa355b3678a1146ad16f7e8649e94fb4fc21fe77e8310c060f61caaff8a",
"response_payload_hash": null,
"response_inspection_result": null,
"session_sensitivity_before": "confidential",
"session_sensitivity_after": "confidential",
"detail": null,
"workflow_id": "industrial-material-movement",
"prev_entry_hash": "6b2ef02224320d6146c269b8d9817a82b72623350a0aa0845b1aab4023f34e23",
"entry_hash": "d8a7985af6b52b903eb11664fe16e29fc78759d2e947f287dc73fb46bf16e181"
"prev_entry_hash": "cd60e91a4a0b519591fafb2b50d08c07fa5a20c0031d16bc3051774e84673c5f",
"entry_hash": "6b3bdc64d0bf88a50e5a6190dff3d43f8bce79947710857000ee6e7ae01739e9"
},
{
"entry_id": "0f65e244-2329-4f7e-a0d0-181252fe52a2",
"sequence_number": 5,
"timestamp_utc": "2026-06-11T22:41:00.520467+00:00",
"session_id": "fdbdd187-b276-4c71-8e08-50f839d13bd1",
"call_id": "e030ccfc-6ec8-4454-9305-1b5eb48adb0b",
"entry_id": "e1d2accd-ae46-4066-b5b2-be395e6fd29f",
"sequence_number": 6,
"timestamp_utc": "2026-06-14T06:17:41.212275+00:00",
"session_id": "8fe66a2a-836b-4cff-9d05-7518d7f6f464",
"call_id": "fe27a71c-66bc-40a2-931f-3f9ecd24c781",
"entry_type": "tool_call",
"tool_name": "robot.request_motion",
"server_identity": "http://localhost:8080/mcp",
"policy_decision": "allow",
"policy_rule_matched": "Cedar (cedarpy): allowed",
"latency_us": 1773,
"request_payload_hash": "sha256:c01b77fa8da1e5875b3b173043d0f4ea1cbf82b1eae2cb8c5547178effb2d3ff",
"latency_us": 1509,
"request_payload_hash": "sha256:309143d21f5916c254793a9f37202ebafda1258ae1eb6de1309de0d1160af3ec",
"response_payload_hash": null,
"response_inspection_result": null,
"session_sensitivity_before": "confidential",
"session_sensitivity_after": "confidential",
"detail": null,
"workflow_id": "industrial-material-movement",
"prev_entry_hash": "d8a7985af6b52b903eb11664fe16e29fc78759d2e947f287dc73fb46bf16e181",
"entry_hash": "214a2ce17f8b0333c2b543493f61f21b205ccc8faa594b877a34108e83d25cd8"
"prev_entry_hash": "6b3bdc64d0bf88a50e5a6190dff3d43f8bce79947710857000ee6e7ae01739e9",
"entry_hash": "d8e3f5030ab24526e5a549eada49a07317c0063164aa7df4ae012f62692a4041"
},
{
"entry_id": "c8cc8737-3689-4be5-8b61-09b13e46bbbc",
"sequence_number": 6,
"timestamp_utc": "2026-06-11T22:41:00.521203+00:00",
"session_id": "fdbdd187-b276-4c71-8e08-50f839d13bd1",
"entry_id": "221905ea-9db4-4d20-a3f0-765d023a3a14",
"sequence_number": 7,
"timestamp_utc": "2026-06-14T06:17:41.212940+00:00",
"session_id": "8fe66a2a-836b-4cff-9d05-7518d7f6f464",
"call_id": null,
"entry_type": "session_end",
"tool_name": null,
Expand All @@ -152,9 +174,9 @@
"session_sensitivity_after": "confidential",
"detail": null,
"workflow_id": null,
"prev_entry_hash": "214a2ce17f8b0333c2b543493f61f21b205ccc8faa594b877a34108e83d25cd8",
"entry_hash": "278f15cce18a1fcb6a22c121facdab23060c700f7cff55ea622ecc8701c9ed7c"
"prev_entry_hash": "d8e3f5030ab24526e5a549eada49a07317c0063164aa7df4ae012f62692a4041",
"entry_hash": "9cb9d91fb224e7020cd24830651b63524f6fbb69a6539d389cfc315ff21d38aa"
}
],
"bundle_signature": "l6En40w_6kLkxc4h5KjOna7SdOvCs3DhWeqriz1qFNr4RaxIVg2_5728A-D8PcThd4t8ce777pGb4XixoIPqAw"
"bundle_signature": "q3iOArOC3lZTXC4kDQAcdzZ9l9PLiPhMFMZhV0nZoux62wFFjSyO7FTF-fSrs1wQMpVL_sUB813jf2WnVQc0AQ"
}
Loading
Loading