Skip to content

Commit 7786d12

Browse files
authored
docs(industrial-embodied-ai): show that an individually safe motion is not a trusted one (#27)
1 parent 5c270fd commit 7786d12

2 files changed

Lines changed: 66 additions & 3 deletions

File tree

industrial-embodied-ai/README.md

Lines changed: 41 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,21 +19,36 @@ to produce durable evidence:
1919

2020
1. **Allowed and completed:** cMCP authorizes the declared workflow, then the
2121
independent controller accepts and completes the simulated motion.
22-
2. **Policy denied:** cMCP denies an undeclared workflow before the controller
23-
receives the request.
22+
2. **Scope denied:** the agent requests a motion whose physical parameters sit
23+
inside the safety envelope (an approved zone, an in-limit speed), but under
24+
an undeclared workflow. cMCP denies it on scope before the controller is
25+
consulted. Physical safety was never the question: the trust layer withholds
26+
the action because it falls outside the agent's declared purpose.
2427
3. **Safety rejected:** cMCP authorizes the declared workflow, but the
2528
controller rejects motion after its current state reports a person in the
2629
safeguarded area.
2730
4. **Closed-session evidence:** cMCP signs a TRACE Trust Record and audit
2831
bundle that can be verified from the saved files without a running agent,
2932
runtime or controller.
3033

31-
The third path is the central boundary:
34+
Two boundaries sit at the center of this example, and they point in opposite
35+
directions:
3236

3337
> A cMCP `allow` decision means the software request is authorized. It does
3438
> not mean that a physical action is safe, accepted by the controller, or
3539
> completed by a machine.
3640
41+
> A controller `accept` decision means a motion is inside the safety envelope.
42+
> It does not mean the action was authorized, in declared scope, or issued by
43+
> the agent that was reviewed. The safety controller has no concept of
44+
> workflow, declared purpose, or agent identity, so it cannot answer those
45+
> questions. The trust layer is what answers them.
46+
47+
The third path shows the first boundary: an authorized request the controller
48+
still refuses. The second path shows the second boundary: an in-envelope motion
49+
the trust layer refuses on scope. Neither layer subsumes the other, and an
50+
individually safe motion is not, by itself, a trusted one.
51+
3752
## Architecture
3853

3954
```text
@@ -75,13 +90,35 @@ rather than a native runtime binding.
7590
|---|---|
7691
| Declared agent configuration | A signed Agent Manifest declares the development agent identity and hashes for its prompt, policy and tools |
7792
| Governed tool access | cMCP intercepts each MCP request and evaluates the active Cedar policy before forwarding |
93+
| Scope over safety | cMCP denies an in-envelope motion that falls outside the declared workflow, a check the safety controller does not perform |
7894
| Physical authority | The independent controller rechecks current state and remains authoritative for simulated execution |
7995
| Durable session evidence | TRACE and the signed audit bundle bind the cMCP session, policy, catalog and tool-call transcript |
8096

8197
The example composes these boundaries without claiming that the developer
8298
preview already forms one end-to-end identity and outcome proof. The precise
8399
gaps are listed under [Evidence boundaries](#evidence-boundaries).
84100

101+
## Why individually safe motions still need trust
102+
103+
A safety controller answers one question per motion: is this movement, right
104+
now, inside the envelope. It cannot answer whether a long run of individually
105+
safe motions adds up to something the operator never authorized: an agent that
106+
quietly skips an inspection step, drifts from its declared task, or runs a
107+
configuration that no longer matches the one that was reviewed. Every motion
108+
passes. The harm is in the pattern, not in any single move, and no safety
109+
controller is built to see it.
110+
111+
That is why the durable evidence matters as much as the live decision. The
112+
signed TRACE record and audit bundle let a later reader, an auditor or an
113+
insurer who has no reason to trust the operator's database, reconstruct which
114+
agent configuration acted, under which policy, and against which declared scope,
115+
across the whole session. The trust layer is not a second safety check. It
116+
answers a different question, on a different clock, that physical safety alone
117+
cannot. The controller-side of this boundary is pinned by
118+
`test_safe_motion_is_not_proof_of_authorization` in `tests/test_controller.py`:
119+
a motion the controller accepts as safe carries no claim about scope, purpose
120+
or agent identity.
121+
85122
## Run it
86123

87124
Prerequisites:
@@ -216,6 +253,7 @@ The validator checks:
216253
|---|---|---|
217254
| Agent Manifest | The signed agent identity declaration and hashes of the approved prompt, policy and tools | That cMCP loaded the manifest or bound its agent identity to the runtime session |
218255
| cMCP decision | The active policy authorized or denied a cataloged tool request | That an authorized physical request was safe |
256+
| Controller accept | The motion was inside the safety envelope for this run | That the action was authorized, in declared scope, or issued by the reviewed agent |
219257
| TRACE Trust Record | cMCP session identity, runtime, policy hash, catalog hash and tool-call transcript integrity | The Agent Manifest identity, controller acceptance, physical completion or functional-safety compliance |
220258
| Saved TRACE and audit files | The closed session can be checked after the processes stop | Continuity of agent memory, reputation or logical identity across a restart or replacement |
221259
| Client-observed controller response | The mock controller's decision returned to the agent during this run | A signed, hardware-backed or independently retained execution record |

industrial-embodied-ai/tests/test_controller.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,31 @@ def test_target_must_be_in_approved_zone(self) -> None:
102102
self.request(snapshot["state_token"], target="loading-dock")
103103
)
104104

105+
def test_safe_motion_is_not_proof_of_authorization(self) -> None:
106+
"""An individually safe motion is not, by itself, a trusted one.
107+
108+
The controller accepts a motion purely on its physical safety
109+
envelope: a fresh state token, an approved zone, an in-limit speed and
110+
no human present. It has no field for workflow, declared purpose or
111+
agent identity, so it cannot tell an in-scope motion from an
112+
out-of-scope one. Catching the out-of-scope case is the trust layer's
113+
job (the workflow-scoped Cedar policy in policy/allow.cedar), not the
114+
safety controller's. This test pins the controller side of that
115+
boundary: a safe motion is accepted, and the accept decision carries
116+
no authorization claim.
117+
"""
118+
snapshot = self.controller.read_safety_state()
119+
accepted = self.controller.request_motion(
120+
self.request(snapshot["state_token"])
121+
)
122+
self.assertEqual(accepted["controller_decision"], "accepted")
123+
self.assertEqual(accepted["execution_status"], "completed")
124+
# The accept result says nothing about scope, declared purpose or which
125+
# agent issued the request. None of these are inputs the controller can
126+
# see, which is exactly why physical safety cannot stand in for trust.
127+
for authorization_field in ("workflow_id", "agent_id", "declared_scope"):
128+
self.assertNotIn(authorization_field, accepted)
129+
105130

106131
if __name__ == "__main__":
107132
unittest.main()

0 commit comments

Comments
 (0)