# Evolution 18 — what an observation establishes

## Levels (per declared effect)

| Level | Requires | Establishes | Does not establish |
|---|---|---|---|
| `UNAVAILABLE` | nothing looked, or the sensors that cover it did not see it | nothing | — |
| `SELF_REPORTED` | the executor's claim | that the executor says so | the effect |
| `INSTRUMENTED` | the enforcer compared the declared object before and after, in its own process | a change of that object, if the enforcer is honest and uncompromised | anything about other objects |
| `EXTERNALLY_OBSERVED` | one sensor in another process, own key, complete scope, saw it | that a process the executor does not share memory with reported it | that a second method agrees |
| `INDEPENDENTLY_CORROBORATED` | two such sensors with different processes, keys **and methods** saw it | that two methods with different blind spots agree | independence from the kernel, the user id, or the machine |
| `CONFLICTING` | sensors that both cover the effect disagree | that at least one is wrong or blind | which one |

Every grade carries `independence_ceiling: SAME_HOST_SAME_KERNEL_SAME_UID_SOFTWARE_ONLY`. "Independent" in this code
never means more than that. It is not attestation and not hardware-backed.

## Rules

1. A sensor counts only if its statement's signature verifies under the key it was started with, its nonce and
   action binding are this run's, it says `SEPARATE_PROCESS`, it shares neither key nor pid with another counted
   sensor, and its scope is complete. Anything else is a recorded gap (corpus OC-03, OC-06, OC-07, IE-04).
2. A declared effect that a covering sensor did not see is *absent*: the verdict is `FAILED`, not `VERIFIED`
   (EO-04). Exception, stated: a READ. Only the event sensor can see reads, and a read that returns no data raises no
   event, so an unseen READ is a gap (`INCOMPLETE`), not a contradiction (IE-01).
3. An effect any counted sensor saw that was not declared is an undeclared effect: `FAILED`, and the tool's passport
   is suspended (EO-01, EO-02, EO-03, AD-01).
4. "No undeclared effect occurred" is claimed only when a complete mutation sensor and a complete read sensor covered
   the root. Otherwise it is a gap.
5. An effect with no observation method (network export, process execution) is `UNSUPPORTED` and at most
   `SELF_REPORTED` (IE-02).
6. A sensor that fails to arm, dies, or returns something invalid is a `sensor_failure` and a gap (OC-04, OC-05).

## What each sensor sees and misses (measured, not assumed)

| | TREE_DIFF | INOTIFY |
|---|---|---|
| create / modify / delete | yes (net change) | yes (events) |
| change undone inside the window | **no** (EO-03) | yes |
| read that returned data | no | yes (EO-02) |
| read that returned nothing | no | **no** (IE-01) |
| write through mmap | yes | **no** (CX-02; documented in inotify(7)) |
| second hard link to a written inode | yes, as a change to the other name (EC-07) | no |
| anything outside the root | no | no (EO-07) |
| tree larger than its limit | reports the gap and is not counted (IE-04) | watch limit: same |
| directory created inside the window | yes | watches it late, lists its contents, **reports a gap** |

## The audit questions from the specification

| Can the observer detect… | Answer | Evidence |
|---|---|---|
| an authorized action with an unexpected effect | yes, inside the root | EO-01, AD-01, EC-07 |
| a side effect the agent's report omits | yes for writes, deletes, non-empty reads inside the root | EO-01..03 |
| a receipt claiming success without the postcondition | yes | EO-04, EO-05 |
| a mutation after the initial observation | within the window yes (events); after the report: **no** — nothing watches after the receipt is sealed | EO-03; open risk R-3 |
| an action that leaves the adapter's expected path | inside the root yes; outside **no**, and the receipt says so | AD-01; EO-07 |
| success externally, timeout locally | not applicable to local files; a crash before evidence is `AMBIGUOUS_OUTCOME` | PE-03 |
| conflicting observations | yes | CX-01, CX-02 |
| a missing or unavailable observer | yes | OC-04, OC-05, EO-06 |

## Sensor identity is the weak point

The enforcer starts the sensors, so an enforcer that lies can start fake ones. The receipt cannot fix that. The
verifier therefore takes the sensor public keys from the *reader*: with anchors, a receipt built on invented sensors
is `FAILED` (OC-02); without anchors the best verdict is `INCOMPLETE` (IE-06). In a deployment the sensors should be
started by an operator other than the enforcer, and their keys published before use. That separation of duty is not
implemented; the harness plays both roles.
