# CAIN-42 Evolution 15 — Threat Model
## Spatial + Physical Autonomous Intelligence Fabric

Scope: the E15 library (`cain45/l5/spatial_physical.py`) running in one process with the E7/E8/E12/E13/E14 layers.
Every attack below is a real, executable scenario in `spatial_physical_attack_bench()` (55 scenarios) or an invariant
in `check_e15_invariants()` (P1–P36). "Contained" means refused (admission, decision, binding, step, E8 or permit) with
**no actuator effect**, or the governed state forced (drift → invalidation). All of it is in-process simulation against
a reference adapter. **Real-world attack validation was not performed.**

### Assets

The right to move a physical system; the integrity of the world state an authorization was issued against; the
binding between a decision and the exact trajectory, capability, authority, policy, risk and consequence it assumed;
the actuator command itself; the evidence that lets an incident be reconstructed.

### Trust boundaries

1. **Sensor adapter → CAIN.** Observations are signed by registered adapter keys. A key proves *which adapter* said
   something, never that it is true (P1). A compromised adapter host can sign lies; cross-modal consistency, identity
   continuity and drift are the only defences, and they are statistical, not proofs.
2. **World model / simulator → CAIN.** Output is PREDICTED / SIMULATED evidence, bound by CAIN to model, config,
   world state, scenario and time. It never becomes observation, world state or authority (P9, P18).
3. **Agent (planner) → CAIN.** A trajectory is a proposal. Authority comes only from E13 ∩ E14 ∩ spatial boundary ∩
   authority scope, and only a signed approval + step + E8 token + permit lets a command through.
4. **CAIN → actuator adapter.** `GovernedActuator` verifies a CAIN-signed, single-use, ≤2 s permit bound to the exact
   command digest and E8 action hash. **If the real actuator can be reached any other way, it is outside the boundary
   (UNCONTROLLED).**
5. **Humans → CAIN.** Human acts are signed, scoped, single-use and audited; an override needs two supervisors and
   still crosses E8; an emergency stop is restriction-only and always honoured.

### Attacks and where they stop

| Class | Scenarios | Stopped by |
|---|---|---|
| Sensor forgery | sensor_spoofing, sensor_replay, stale_observation, timestamp_manipulation | `SensorRegistry.check` (signature, replay set, E12 freshness, per-sensor monotonic time) |
| Sensor conflict / loss | sensor_disagreement, gps_drift, sensor_dropout, cross_entity_confusion | `CrossModalConsistencyEngine`; GNSS/IMU may only describe the system itself; any refused observation makes the batch non-authorizable |
| Map | map_substitution | approved-map digest set in policy |
| Identity | object_identity_substitution, (P31/P32) | identity continuity (classification flip, implied speed), sensor type/source/key match, no re-registration |
| World model / prediction | world_model_substitution, world_model_version_mismatch, prediction_substitution, model_generated_authority | CAIN-signed output binding; re-registration forces REVALIDATE; outputs never enter authority |
| Simulation | simulation_evidence_substitution, sim_to_real_mismatch, counterfactual_manipulation | signed SIMULATED evidence bound to scenario/world/trajectory/simulator; `proves_real_world_safety` always False; counterfactual digests |
| Drift suppression | reality_drift_suppression, recovery_state_bypass, state_resurrection | invalidation needs fresh consistent evidence; in-process un-invalidation changes the bound digest and breaks the history chain |
| Trajectory | trajectory_substitution, trajectory_replay, trajectory_fork, spatial_boundary_confusion | trajectory digest bound in approval + step + E8 action; past-start only for the current plan's continuation; one live approval per system; z-axis and non-finite coordinates refused |
| Capability / authority | physical_capability_escalation, geographic/temporal_boundary_bypass, subagent_physical_capability_escalation, collective_physical_authority_laundering, memory/tool_generated_authority | E13 intersection, E14 envelopes, boundary ⊆ authority, delegation narrows only |
| Mutation after approval | policy/authority/capability/environment_mutation, consequence/risk_suppression, toctou_race, world_state_fork, state_rollback | nine strict live bindings recomputed at commit; world-version high-water mark; E8 re-check |
| Replay | decision_replay, authorization_replay, credential_replay | single-use step, E8 nonce/sequence spend, action-hash binding |
| Actuator | actuator_command_substitution, safe_state_bypass, emergency_stop_bypass, digital_agent_actuation | permit bound to command digest; autonomy state machine; E8 emergency stop; digital systems cannot actuate |
| Health / latency | communication_loss, latency_attack, actuator_degradation | health bound into the risk digest; step and token TTLs |
| Unknown | unknown_to_allow, human_review_bypass | every missing input → UNKNOWN; E7 STEP_UP needs a verified, in-scope, fresh human approval |

### Defects found and fixed while building E15

- The uncommitted E15 skeleton found in the tree (author unknown, session stopped by the owner) had: a fail-open
  `PhysicalCommitBoundary.commit` (returned `committed: True` with no E8 boundary); a trajectory engine that fell
  through to APPROVE when the world was non-authorizable only because of sensor inconsistency; an actuator check that
  compared two caller-supplied strings; a counterfactual engine that invented `risk 0.5` when it had no predictor.
  All replaced; each is covered by an invariant or bench scenario.
- Found in the new code by its own tests: a refused observation (identity discontinuity) was silently dropped and
  the world stayed CONSISTENT; GNSS could attribute a position to another entity; a refused commit left the old
  approval live (re-planning then looked like a fork); a continuation step was refused as a replay; the world-state
  digest did not bind superseded observations. All fixed with regression tests.

### Residual risk (not mitigated here)

Compromised sensor adapters signing consistent lies; hardware and firmware (no hardware attestation — UNKNOWN);
actuators reachable outside the wrapper; the host process itself (an attacker with in-process write access can
change any Python object — the bench shows such changes are *detected at commit*, not prevented); multi-host
behaviour (UNVERIFIED); world-model accuracy and sim-to-real fidelity (UNKNOWN).
