# Adversarial Execution Evidence — Consumer Policy Profile, v0.1

<!-- restatement-banner:begin
     Every figure inside this block is recomputed by scripts/lint_spec_restatement.py and
     is a build failure when it is wrong. Do not edit a number here by hand; re-derive with
     --repin and read what it reports. These sentinels are the gate's parse boundary and the
     reason the banner's own MUSTs are not counted as obligations. Removing or moving one is
     a build failure. -->

> ## THIS DOCUMENT IS A PROFILE, NOT THE SPECIFICATION
>
> **The authoritative predicate text is `spec/predicates/adversarial-execution-evidence.md` in
> the `in-toto/attestation` fork**, mirrored byte-identically in the `aee-conformance`
> repository. That document is 2,322 lines, whose sha256 is
> `759d2383e5da36fa509dc335e6159a20b87641b25ebbadcf1676c55d75ffd8b0`; this one is 798. This
> document does not restate the predicate. It states the **consumer-policy half** the
> predicate deliberately assigns outside itself, and most of what is written here is text the
> authority does not carry. The ledger below says which sentences those are, one row each.
>
> **Do not read a sentence here as one the specification imposes.** The pin ledger
> [`adversarial-execution-evidence-consumer-policy.pins.json`](adversarial-execution-evidence-consumer-policy.pins.json)
> records, per sentence, which of the two it is. A sentence recorded as `anchored` is carried
> verbatim by the authority at a named span. A sentence recorded as unanchored under class
> `profile-addition` is **new normative text proposed for the next revision of the predicate**
> and has no standing beyond this profile until that revision lands. A sentence under
> `prose-divergence` restates an authority obligation in different words, and only a person
> reading both texts establishes that the two say the same thing.
>
> **Why this exists.** The predicate splits verification in two. A byte-pure validity core
> every consumer evaluates identically, and everything irreducibly trust-relative, which it
> assigns to consumer policy. As of 2026-07-30 the trust-relative half existed only as one
> vendor's undocumented policy across three enforcement rails, and an audit of that policy
> found ten consumer controls of which two are derivable from the published predicate, the
> absent-pin behaviour of those two is not, the highest-value control is not reachable from
> the published text at all, and the one obligation the predicate makes mandatory is missing
> from the implementation. Four independent implementers reading the predicate today would
> build four different consumers, and none of them would build ours.
>
> This file carries 38 sentences imposing `MUST` and 0 imposing `REQUIRED`. Every normative
> sentence below is enumerated there: 8 are anchored to a span of the authority that carries
> that sentence verbatim, and 30 are recorded as unanchored. The counts are over sentences,
> taken with this banner and the fenced examples excluded and wrapped paragraphs rejoined
> first.
>
> **What the pin proves, and its honest limit.** That the authority has not moved since a
> person last read it against this text, and that every predicate member this profile
> constrains exists in the authority at all. It does not prove the authority imposes any
> obligation here, and for most of them it does not.

<!-- restatement-banner:end -->

**Profiles:** `https://in-toto.io/attestation/adversarial-execution-evidence/v0.7`

**Status:** draft for the standards thread. Nothing here is adopted upstream.

---

## 0. Scope, and what this document is not

### 0.1 The split this profile occupies

The predicate states the boundary it draws, and the boundary is the reason this document
exists rather than a longer specification:

> The comparison is deliberately not a validity gate: validity is a function of carried
> bytes alone and holds identically for every consumer, while the expected corpus and
> substrate differ per consumer.

A verifier proceeds in two stages. Stage one is byte-pure and belongs to the predicate:
statement well-formedness, coverage validity, the `result` recompute, and manifest and
vocabulary digest integrity. Stage two is trust-relative: the envelope signature, the per-row
evidence tier against consumer key policy, then the strength orderings and the rest of
consumer policy. **This profile is stage two, and only stage two.**

The membership test for this document is mechanical, and it is not "does the predicate
currently say so". It is: **does the rule read anything the consumer supplies?** A rule with
no consumer operand — no pin, no key, no clock, no threshold — is byte-pure and belongs in
the predicate's validity gate however recently it was written, however unimplemented it is
upstream, and however convenient it would be to ship it here first.

### 0.2 Three rules deliberately moved OUT of this profile

Three obligations were carried as one vendor's consumer policy at the time this profile was
written. All three are byte-pure by the test above, and publishing them here would announce
as trust-relative three rules that hold identically for every consumer — precisely the
confusion this document exists to end. Each belongs in the predicate's coverage-validity
list, and each is filed there rather than here:

- **A clean row may not resolve an `observationRefs` index to an `interception` record.**
  Shipped today as an unconditional admission rule with no consumer knob gating it. It is a
  pure predicate over `containmentObserved`, `observationRefs`, and the decoded kind of a
  carried record.
- **Every carried `interception` record is resolved by at least one caught row.** Unwritten
  anywhere. Same shape, same argument. Its value against an attacker who deletes the records
  rather than orphaning them is zero, and it must not be priced as a closure.
- **`subject` cardinality.** The predicate already makes this a validity rule — "For this
  predicate `subject` MUST contain exactly one entry on a statement of any basis; a statement
  carrying zero or more than one subject is malformed, regardless of whether any row is
  `basis: substrate`" — and the reference rego rail enforces it nowhere while two corpus
  vectors sit on a denylist under two mutually contradictory reasons for why it is out of
  scope. It is trivially expressible and it is not consumer policy.

A reader looking for those three in this document will not find them, and that absence is
deliberate rather than an omission.

### 0.3 Conformance language

`MUST`, `MUST NOT`, `MAY` and `SHOULD` carry their RFC 2119 senses. They bind a **consumer**:
a party that reads an adversarial-execution-evidence statement and makes a decision from it.
They bind no producer and constrain no wire format.

A **conforming consumer at a stated level** satisfies every obligation that level names, and
declares — in the machine-readable rail map of section 6 — the disposition of every
obligation it does not enforce. **A consumer that silently omits an obligation is
non-conformant even where the omission is forced by its engine**, because the omission and
the declaration are what a relying party can tell apart.

---

## 1. The obligation registry

Fourteen obligations. Each carries a permanent slug of the form `aee-p-<name>`. The slug is
never renumbered, never reused, and retired only by a tombstone row.

**Why a slug and not an ordinal.** Every ordinal in the reference implementation that names
an obligation has drifted, and the drift reached the diagnostics: a filter step renumbers
Kyverno condition indices so that conditions 13 through 16 are reported as 11 through 14 in
every corpus-run message; a prose reference to "conditions (6) and (7)" as separately
requiring `basis` and `method` names a single combined entry and a length check; a policy
header says fifteen conditions where the file carries sixteen. Spec line anchors are no
better for this purpose — an obligation outlives any line of a document under active review,
and the anchor gate that exists in the sibling repository exists because those lines move. A
slug cannot drift, because there is nothing to recompute.

| Slug | Obligation, in short | Source | Consumer input | Absent-input default |
|---|---|---|---|---|
| `aee-p-tier-derivation` | derive a per-row evidence tier before crediting any `basis: substrate` row | authority L537-542 | substrate observation keys | mandatory; no opt-out |
| `aee-p-no-tofu` | with no pinned substrate root, every `basis: substrate` row is `unattested`, and the root is never inferred from the predicate | authority L542-545 | same | mandatory; no opt-out |
| `aee-p-ignore-carried-tier` | ignore a carried `evidenceTier`, and any predicate-level member with the reserved prefix | authority L550-552 | none | mandatory; no opt-out |
| `aee-p-corpus-anchor` | pin the expected corpus digest out of band and compare it at consumption | authority L1213-1218 | expected corpus digest | deny, on the two-leg argument |
| `aee-p-substrate-anchor` | pin the expected substrate digest out of band and compare it at consumption | authority L1213-1218 | expected substrate digest | deny, on the two-leg argument |
| `aee-p-threshold` | admit only the result tokens this consumer has declared | authority L448-449 | accepted result tokens | the authority's own default, the strict end |
| `aee-p-clean-row-live` | key on each clean row's vantage, directness and derived tier | authority L450-453, L1270-1272 | a declining boolean | keep the obligation |
| `aee-p-key-window-operand` | evaluate a key validity window against a substrate-signed instant, never the producer's clock | authority L925-943 | per-key validity window | vacuous; the obligation is conditional |
| `aee-p-admission-result` | expose one admission result conjoining validity, tier policy and the anchors | authority L1223-1226 | none | recommended, not mandatory |
| `aee-p-demanded-scope` | pin the assessment classes this deployment demands and require the evidence to cover them | new | demanded class codes | deny, on the third-leg argument |
| `aee-p-issuance-lag` | bound the interval between the substrate-signed instant and the producer's clock | new | a bound in hours | vacuous, deliberately |
| `aee-p-evidence-age` | bound the age of the evidence against the substrate-signed instant | new | a bound in hours | vacuous, deliberately |
| `aee-p-posture-allowlist` | require the carried network posture to be one this deployment accepts | new, promoted from a MAY | allowed posture tokens | vacuous |
| `aee-p-catchpolicy-pin` | require the carried catch-policy digest to equal a pinned one | new, promoted from a MAY | expected catch-policy digest | vacuous |

The `Source` column is the justification for publishing at all, and it should be read as the
answer to one question: **could an independent implementer, reading only the published
predicate, arrive at this obligation?** Five of the fourteen rows say `new`, and for two more
— the anchors — the obligation is reachable while its absent-input behaviour is not. Of
section 2's additions only the two replay pins have any counterpart upstream, and that
counterpart is a bare permission with no mechanism attached.

---

### 1.1 `aee-p-tier-derivation` — the one obligation the predicate makes mandatory

The authority states it, and this profile adds nothing to it:

> Given a valid attestation, a consumer MUST, before crediting any `basis: substrate` row or
> applying either strength ordering, derive a per-row evidence tier: a `basis: artifact` row
> is `declared`;

A `basis: substrate` row is `attested` when every covering record's signature verifies
against a key this consumer's policy names as a substrate observation key, and `unattested`
otherwise. The tier is total and deterministic given the key policy, and it never alters
`result`.

**A consumer MUST NOT treat this obligation as optional on the ground that its engine cannot
perform it.** An engine with no signature primitive cannot derive a tier; that fact makes the
consumer's admission result mean less, and it does not make the obligation go away. Such a
consumer declares `unreachable` under section 6 and states the reduced meaning of its result
under section 5.

**Consumer input.** A set of substrate observation keys, each an Ed25519 public key. A record's
`keyid` is an unauthenticated lookup hint that selects which pinned key to try and is never
the check itself.

**What declining costs.** Everything the predicate's second gate is for. Every field a keyless
consumer reads out of a record payload — `aeeRunBinding`, `aeeMethod`, the record kind — comes
out of a base64 payload whose signature nothing in that consumer's path checks, so anything a
real substrate can write into a record, the party assembling the statement can write too.

### 1.2 `aee-p-no-tofu` — no trust on first use

> A consumer with no policy-pinned substrate root MUST treat every `basis: substrate` row as
> `unattested` and MUST NOT infer the substrate root from the predicate.

This is the obligation that makes `aee-p-tier-derivation` total rather than conditional: there
is no state in which a consumer has no key policy and therefore no tier. It has one. Every
substrate row derives `unattested`, and a consumer whose admission rule requires `attested`
admits no substrate-bearing statement at all until it pins a key.

**A consumer MUST NOT resolve a record's `keyid`, or any other carried value, into a trust
anchor it did not already hold.** The predicate carries the substrate's own subject reference
in `observationEnvironment.substrate`, and reading that as an instruction about which key to
trust is exactly the inference this obligation forbids.

### 1.3 `aee-p-ignore-carried-tier` — the reserved prefix

> A carried predicate member named `evidenceTier`, or any predicate-level member beginning
> with the reserved prefix `aee`, MUST be ignored and MUST NOT alter the derivation.

A consumer satisfies this by never reading such a member. Satisfying it by accident — because
no rule happens to name one — is satisfaction, but it is not a declaration, and section 6
requires the disposition to be stated either way. The distinction matters the first time a
producer ships a carried tier and a consumer that never considered the question starts reading
it because the field is conveniently there.

### 1.4 `aee-p-corpus-anchor` and `aee-p-substrate-anchor`

The authority makes both mandatory in one sentence, and the sentence is unambiguous about the
members compared:

> A consumer MUST pin, out of band, the corpus digest and the substrate digest it expects for
> the deployment it is admitting into, and at consumption MUST compare them against
> `observationEnvironment.corpus.digest` and `observationEnvironment.substrate.digest`; on
> mismatch the attestation is not admitted, exactly as an attestation whose covering
> signatures do not verify is not admitted.

These are two obligations rather than one because a consumer can hold one value and not the
other, and a rail that folded them together would let an operator who pinned the corpus
believe it had pinned the substrate.

**Why in-policy re-derivation cannot substitute, and this is the part an implementer gets
wrong.** Every other corpus check available to a consumer is self-consistency: the digest
commits the manifest, the coverage parts partition it, the attack identifiers exhaust it. Self
consistency costs an attacker holding only the envelope key nothing. Substituting a weaker
corpus for the real one — one declaring a single trivial attack the run duly passes — and
re-hashing the substitute needs no key at all, and the substituted statement then satisfies
every recompute a consumer can run. **The difference between the real corpus and the
substitute is not carried in the bytes, so no amount of in-policy re-derivation can reach it.**
Only a value pinned outside the attestation can.

**A consumer MUST NOT derive a pinned anchor value from a bundle the party being checked
supplied.** A digest copied out of a producer's own statement pins whatever the producer chose
to ship, and it will match forever.

The absent-input default is argued in section 2.1, and it is the single most important
sentence in this profile that the published predicate does not contain.

### 1.5 `aee-p-threshold` — the admission threshold, and why it is not the row gate

> The default admission threshold is `result == "pass"`.

A consumer MAY accept `pass_indirect` beside `pass`. **A consumer's accepted-result set MUST
be either `{pass}` or `{pass, pass_indirect}` and MUST NOT be any other set.** This is a
threshold over the ordering `fail < degraded < pass_indirect < pass`, not a free choice of
tokens: a set naming `pass_indirect` without `pass` names no threshold, the empty set names
none, and a set naming `degraded` admits a disclosed coverage gap. Each is a typo rather than
a policy, and **a consumer MUST refuse a malformed accepted-result set by name rather than
falling back to a default**, because a fallback here silently narrows or widens a running
deployment.

**The absent-input default is the authority's own**, `{pass}`, and this is the one place in
the profile where an absent input neither denies nor is vacuous. The corpus, substrate and
scope pins deny when absent because the obligation exists whether or not the consumer states
it and only the consumer holds the value. The replay pins and the freshness bounds are vacuous
when absent because nothing obliges a consumer to set them at all. Here the predicate itself
supplies the value an absent pin would otherwise have to demand, and that value is the strict
end of the range, so absence cannot admit anything a pin would have refused.

### 1.6 `aee-p-clean-row-live` — the row obligation a relaxed threshold must keep

> A consumer MAY accept `pass_indirect`, and a consumer relaxing its threshold below `pass`
> MUST additionally key on each clean row's `basis` and `method` and on that row's derived
> evidence tier, because below `pass` the ordinal stops distinguishing them: a `degraded`
> reached through a disclosed coverage gap and a `degraded` whose clean rows are all
> `artifact` carry the same token.

and, at the authority's own consumer-policy example:

> a policy relaxed to admit `pass_indirect` MUST keep the rule, because the token states that
> some clean row is indirect and never which one.

The obligation itself: a clean row — one whose `containmentObserved` is inside the carried
`observationVocabulary.labels` and outside its caught subset — is `basis: substrate` and
`method: intercepted`. A clean row that is artifact-basis or reconstructed is a
"nothing bad happened" claim assembled from state diffing rather than from a live observation
at the substrate.

**Three normative consequences, and the first two are where the reference implementation was
wrong until 2026-07-30.**

**A consumer MUST NOT relax `aee-p-threshold` to admit `pass_indirect` and decline
`aee-p-clean-row-live` in the same act.** These are two declarations, and a policy in which
one flag performs both is non-conformant however its two halves are individually defensible.
Under such a flag no configuration admits `pass_indirect` with the row rule still running, so
the conformant posture is not merely easy to miss, it is inexpressible.

**A consumer that cannot derive an evidence tier MUST NOT relax `aee-p-threshold` at all.**
The authority's sentence requires a relaxing consumer to key on the derived tier as well as on
`basis` and `method`, so the relaxation is unavailable to a consumer that declares
`aee-p-tier-derivation` unreachable. Separating the threshold from the row gate satisfies the
`basis`-and-`method` half of that sentence and leaves this half open; a keyless rail offering
the relaxation is non-conformant on this row even after that separation.

**A consumer declining `aee-p-clean-row-live` under a `{pass}`-only threshold MUST be refused
rather than accepted as a no-op.** A statement carrying an indirect clean row recomputes to
`pass_indirect` and is refused by the threshold before the row gate is reached, so that
pairing changes nothing, and an operator who wrote it wanted something it does not do.

**Polarity.** The authority's non-normative example spells this knob as an opt-in to strictness
whose default is lax. **This profile inverts it: the obligation holds by default and a consumer
declines it explicitly.** An implementer following the example literally builds a less safe
consumer than an implementer following this profile, and that divergence is stated here rather
than left to be discovered.

### 1.7 `aee-p-key-window-operand` — the operand, where a consumer bounds a key

The obligation is conditional on the consumer choosing to bound a key's validity, and where it
applies the authority fixes the operand hard:

> Where it does, that window MUST be evaluated against a substrate-signed instant, and the one
> this predicate mandates is the `armedAt` carried inside an `arming` record whose signature
> verifies under the key being bounded; it MUST NOT be evaluated against `issuedAt`.

`issuedAt` is producer-asserted, sits outside every substrate signature, and is not among the
run binding digest's inputs, so a party holding the envelope key moves it at will, changing no
digest and breaking no signature. A window evaluated against it rehabilitates, by back-dating
alone, every record the revoked key ever signed.

**A consumer bounding a key's validity MUST refuse a statement carrying no `arming` record
that verifies under the bounded key, and MUST NOT fall back to `issuedAt`.** Such a statement
carries no substrate-signed instant for that key and therefore supports no claim about its own
age. Reading absence as satisfaction is the failure this obligation exists to correct.

The predicate amended itself for this operand once already, and the changelog states why in a
sentence this profile takes as its own standard of evidence: one implementer choosing the
defeated operand is a mistake, and two choosing it separately is a property of how the field
reads.

### 1.8 `aee-p-admission-result` — one result, not two

> Verification surfaces SHOULD expose one consumer-facing admission result that conjoins
> validity, tier-policy satisfaction, and the anchor comparison, so a result-only consumer
> cannot read a valid-but-wrong-context attestation as admissible.

This profile keeps it a SHOULD and widens what the conjunction covers: an admission result
exposed under this profile conjoins validity, every obligation the consumer's declared level
names, and every obligation it declares `enforced` above that level. **A surface exposing an
admission result MUST NOT report as admitted a statement failing any obligation it declares
`enforced`.**

---

## 2. The obligations this profile adds

Four obligations and one absent-input rule that the published predicate does not carry. This
section has no counterpart upstream and is the profile's clearest single contribution.

### 2.1 The absent-input default for the two anchors: DENY

The predicate makes the anchor comparison mandatory and says nothing whatever about a consumer
that has not pinned. **A consumer that has pinned neither the expected corpus digest nor the
expected substrate digest MUST refuse the statement, and MUST NOT treat the absent pin as
vacuously satisfied.** Two legs carry this, and both are needed.

**The appeal-to-the-predicate leg.** A policy that treats an absent mandate as vacuously
satisfied has implemented a recommendation. The two replay pins in section 2.4 default
permissive precisely because nothing in the predicate obliges a consumer to set either; this
pair is different in kind.

**The asymmetric-failure leg.** The two failure modes are not symmetric. Defaulting permissive
fails silently and indefinitely: an operator who believes they pinned, or who never read this
far, admits evidence about any corpus and nothing in the verdict ever says so. Defaulting
strict fails loudly and once, at rollout, with an error naming the exact input that is missing.

**The cost, stated rather than hidden.** An unedited copy of a policy written to this profile
admits nothing until the operator pins. Rolling out through an audit-first variant measures the
blast radius before it blocks. **Declining this obligation MUST be an explicit act and MUST NOT
be reachable by leaving an input unset.**

### 2.2 `aee-p-demanded-scope` — the demanded assessment classes

**A consumer MUST pin the set of assessment class codes its deployment demands, and MUST
refuse a statement whose `coverage.assessedClasses` does not contain every demanded code.**
Absent that pin the consumer refuses, on the argument below.

**Classes, not attack identifiers, and an implementer asks this first.** Attack identifiers are
corpus-version-scoped, so a consumer pinning them re-pins on every corpus revision, and the
list it would re-pin to is one it read out of the producer's own manifest rather than one it
chose. **A pin whose value comes from the party being checked is not a demand.**

**This is not the corpus anchor restated.** The corpus anchor pins bytes and says nothing about
what those bytes must contain; a consumer that pinned a digest it copied out of a producer's
bundle has pinned whatever the producer chose to ship. **This is the only pin in the profile
whose value a consumer derives from what it wants** rather than from what it was handed.

**The absent-input default is deny, and the appeal-to-the-predicate leg does not carry it.** The
demanded-scope obligation is new text in this profile, so a consumer unpinned here would not be
implementing a recommendation in place of a mandate. A third leg replaces that one and is
stronger: an unpinned corpus
anchor still leaves the consumer every self-consistency rule available to it, a weakened
control; **an unpinned scope demand leaves it nothing, because the withdrawal is provably
invisible in the bytes.** Absence here is not a degraded control, it is the absence of one, and
that is the case for making the operator say so.

**The opt-out is its own input.** The two decline different things: declining the anchors
concedes "evidence about any corpus and any substrate", declining the scope demand concedes "a
producer may withdraw any class it likes". **A consumer MUST NOT fold the two declinations into
one input**, because an operator who declined the digest pin would then have declined the scope
demand without ever saying so.

**An empty pin is not a pin.** An empty array, or a value that is not an array, comprehends to
the empty set. **A consumer MUST treat an empty demanded-class set as an absent pin** and refuse
under the rule above, naming the input.

**Its honest limit travels with it.** This obligation converts an undetectable attack into a
documented consumer obligation that some consumers will not perform. That is a real reduction
in assurance relative to a validity rule, and it is the best available, because the validity
rule does not exist: coverage suppression is unreachable by any rule over the carried
statement, measured byte-identical on 27 of 27 finding-bearing baselines against honest
analogues, three rails agreeing. And the obligation does not reach the form in which a corpus
manifest never declared the demanded class in the first place, which is the one form of scope
withdrawal that reaches a passing verdict.

### 2.3 `aee-p-issuance-lag` and `aee-p-evidence-age` — the two freshness bounds

Neither bound exists in the published predicate. What the predicate does fix, normatively, is
the operand both must use, and section 1.7 states it.

**A consumer bounding the interval between the substrate-signed instant and the producer's
clock MUST evaluate it as `issuedAt` minus the `armedAt` of every carried `arming` record, and
MUST refuse the statement if any one of them exceeds the bound.** Every arming record, not the
earliest or the latest: a run whose vantages were armed hours apart is a run whose weakest
record is the one that matters.

**A consumer bounding the age of the evidence MUST evaluate it as its own clock minus
`armedAt`, and MUST NOT evaluate it against `issuedAt`.**

**The absent-input default is vacuous, and deliberately not the deny that the anchors and the
scope demand take.** Those implement obligations that exist whether or not a consumer states
them. There is no such obligation here: the predicate does not require a consumer to bound the
age of its evidence at all, and the obligation it does state is conditional — that a consumer
which bounds age evaluates the bound against a substrate-signed instant. **Denying an unpinned
consumer would be inventing a requirement rather than enforcing one.**

**The applicability rule is not vacuous, and it is where an implementation goes wrong.** A
consumer that has pinned a bound and is handed a statement carrying no arming record **MUST
deny**, and MUST NOT pass it and MUST NOT fall back to `issuedAt`.

### 2.4 `aee-p-posture-allowlist` and `aee-p-catchpolicy-pin` — the two replay pins

The predicate grants these as a bare MAY with no mechanism:

> Consumers MAY additionally coherence-check row claims against the pinned
> `observationEnvironment`: a `substrate` row claiming a network-boundary observation under a
> `networkPosture` that provides no interception path at that boundary is incoherent, and a
> consumer MAY reject on that ground.

This profile gives the permission a shape. A consumer MAY pin the set of `networkPosture.posture`
tokens it accepts and the expected `catchPolicy` digest; where it pins either, **a consumer MUST
refuse a statement whose carried value is outside the pinned set or unequal to the pinned
digest.** Both are vacuous when absent, on the argument that nothing obliges a consumer to set
either.

**A consumer MUST NOT evaluate either pin inside its validity gate.** These are private
consumer values, and a rail that lets one of them decide a validity rule makes a
specification-valid statement structurally unsound on that rail alone. Where such a rail is also
the oracle for a conformance corpus, it hollows the corpus in the direction that only bites the
consumers who followed the guidance. The reference rego rail does exactly this today, and
appendix B records it.

---

## 3. Profile levels

A level is a named set of obligations, so that a consumer states what it meets instead of
publishing a bespoke list nobody can compare.

| Level | Obligations |
|---|---|
| **Minimal** | `aee-p-tier-derivation`, `aee-p-no-tofu`, `aee-p-ignore-carried-tier`, `aee-p-corpus-anchor`, `aee-p-substrate-anchor`, `aee-p-threshold` |
| **Recommended** | Minimal, plus `aee-p-clean-row-live`, `aee-p-demanded-scope`, `aee-p-admission-result` |
| **Strict** | Recommended, plus `aee-p-key-window-operand`, `aee-p-issuance-lag`, `aee-p-evidence-age`, `aee-p-posture-allowlist`, `aee-p-catchpolicy-pin` |

**A consumer MUST NOT claim a level while declaring any obligation of that level `unreachable`
or `approximated`.** A rail that cannot derive a tier meets no level of this profile, and it
says so under section 5 rather than claiming Minimal with a footnote. The levels exist so that
a partial consumer has something honest to state, not so that it has something flattering to
claim.

---

## 4. What a byte-pure consumer cannot know

This section is carried forward from the reference bundle's own account, unsoftened, because it
is the most useful paragraph in it and a published profile that omitted it would be selling a
gate rather than describing one.

**A verifier that evaluates coverage validity without verifying the observation records'
signatures cannot distinguish a substrate observation from an assembly-plane forgery.** Every
record field such a consumer reads comes out of a base64 payload whose signature nothing in its
path checks. Anything a real substrate can write into a record, the party assembling the
statement can write too.

**Stated plainly: a consumer relying on a byte-pure admission controller is extending full
trust to the envelope signer.** The envelope key is the entirety of the trust decision there.
The record-level cryptography is evidence for an offline auditor; it is not evidence such a
gate can weigh.

Three byte-pure checks narrow that gap without closing it, and none of the three is a
substitute for `aee-p-tier-derivation`:

- **Record signature presence.** A band-aid, not verification, and its home is the predicate's
  validity gate rather than this profile. It needs no key, so it holds in every deployment, but
  the bytes are never inspected and an attacker who writes garbage into a signature passes
  exactly as a real substrate does. What it closes is the literal strip: the batch-root leaves
  span only the payload type and payload, so deleting every signature entry leaves the root
  unchanged and the statement otherwise intact.
- **`aee-p-clean-row-live`.** The method-and-vantage half of the authority's own example. The
  tier half is not computable without a key, which is why section 1.6 forbids a keyless rail
  from relaxing its threshold.
- **Coverage validity.** The predicate's own class-match family, and a validity rule rather
  than a consumer threshold. The authority is explicit about its reach: a verifier that
  evaluates coverage validity and skips signature verification has checked that the producer
  filled the form in correctly.

---

## 5. Declaring a capability gap

An engine without a signature primitive cannot derive an evidence tier. That is a fact about
the engine, and this profile's position is that the fact is publishable rather than
embarrassing — but only as a declaration.

**A consumer that cannot satisfy an obligation MUST declare it `unreachable` with the engine
obstruction stated, and MUST NOT omit it.** The declaration lives in the rail map of section 6.
Concretely, a rail declaring `aee-p-tier-derivation` unreachable is stating all of:

- its admission result binds to validity plus whatever obligations it does enforce, and
  **MUST NOT** be published as, or conjoined into, a claim that any `basis: substrate` row is
  attested;
- every field it reads out of a record payload is unverified, and the envelope key is the
  entirety of its trust decision;
- it meets no level of this profile, per section 3;
- it does not offer the `pass_indirect` relaxation, per section 1.6.

**A consumer MAY satisfy an obligation out of band.** Three shapes are conformant, and all
three are declarations rather than omissions:

1. **An out-of-band verifier.** A tier-capable verifier runs ahead of the policy engine and the
   engine consumes its admission result. The engine declares `aee-p-tier-derivation` enforced by
   reference and names the verifier and the key policy it ran under.
2. **A sidecar annotation.** The tier column is computed elsewhere and attached to the object
   under decision. **A consumer relying on a sidecar MUST establish the sidecar's integrity by a
   mechanism outside the attestation**, because a tier annotation the same party can write is
   the carried `evidenceTier` that section 1.3 forbids reading, wearing a different hat.
3. **An explicit declaration that no tier is derived**, with the reduced meaning of the
   admission result stated above.

---

## 6. Obligation identifiers and the rail map

Each rail — this project's and anyone else's — publishes a rail map declaring, for **every**
slug in the registry, exactly one disposition:

- **`enforced`**, with the rule, condition or code path that carries it;
- **`approximated`**, with the approximation stated in both directions, so that a rail
  applying an obligation more widely than the profile scopes it declares a strengthening
  rather than leaving an undocumented divergence;
- **`unreachable`**, with the engine obstruction stated.

**A rail map MUST carry an entry for every registry slug, and MUST NOT carry an entry for a
slug the registry does not define.** A gate asserts the correspondence in both directions. The
value of the both-directions form is measured rather than assumed: the reference bundle's own
cross-rail driver already refuses both an undeclared disagreement and a stale declaration
whose rail has since gained the power, and the second half is the half that rots.

The mapping runs one way only. **Rails map into the slug, and a rail MUST NOT define a slug.**
An identifier a rail can mint is an identifier the registry does not control, and the ten
engine-capability reasons the reference driver carries per vector are exactly the material that
belongs on a per-obligation row instead — lifted out of a bilateral exception table, where they
say "my engine agrees with one vendor's module modulo my own exception list", and put where
they say what an engine can and cannot do.

Registry row fields: the slug; the profile section that defines it, named rather than numbered
by line; the obligation sentence; the consumer input and its type; the absent-input default and
which of the four absent-input arguments carries it — the authority's own default at section
1.5, the two-leg deny at 2.1, the third-leg deny at 2.2, or deliberate vacuity at 2.3; the
declining input, or none; and the denial code emitted on violation, compared as a set. Four
defaults with four different arguments, and a profile that stated a default without stating
which argument carried it would have published a preference.

---

## 7. The reference consumer and the conformance suite

### 7.1 The reference consumer

`probity-verify`, in `packages/verify`, is this profile's reference consumer. It is the only
implementation in the reference tree that derives an evidence tier, and it draws the
valid-versus-admitted line this profile turns on: in bare replay mode exit 0 means the
statement is valid; when any consumer policy is supplied the exit code binds to admitted, and
never to bare validity.

It is a reference consumer and not a conforming one, and the difference is stated here rather
than in a footnote. Measured at `probity` HEAD `c2ebf615`, it enforces `aee-p-tier-derivation`,
`aee-p-no-tofu`, `aee-p-ignore-carried-tier` and `aee-p-admission-result`, and it implements
the anchor comparison for both anchors while **defaulting permissive when an anchor is not
supplied** — an unsupplied anchor compares nothing and the statement can still be admitted.
That is the opposite of section 2.1, in the file whose own type documentation states that a
consumer must supply both anchors for admission decisions. The obligation is written down
beside the code that does not enforce it. Appendix B carries it as a defect.

The reference rego rail is the mirror image: default-deny on both anchors, and no tier at all.
**Neither reference implementation is a conforming consumer, and they fail on different
obligations.** That is the sharpest available argument that this document needed to be written:
the boundary is not one an implementation holds unaided, even with the specification in front
of it and the other implementation in the same repository.

### 7.2 The conformance suite

The suite is an extension of the published external-rail contract in
`aee-conformance/packaging/run_vectors.py`, not a new harness and not a suite built on the
reference rego rail.

**Why not the rego rail.** Its declaration keys are corpus vector identifiers and its ten
reason families are engine-capability statements about three named engines. A third party's
policy language is not on that list and cannot be added to it, so a suite hosted there would
require an implementer to author its own exception table by running its engine against one
vendor's module and transcribing whatever disagreed. The artifact that produces is a
compatibility test between two implementations, not conformance to an obligation — and every
defect in appendix B would become the correct answer by accident, so an implementer who
followed this profile correctly would fail.

**What the existing contract already gives.** A fixed argv, a set-compared answer, and a
consumer context injected by environment with a per-context expectation: each vector is run
twice through the same command, once with a pinned test key policy and once with none, and the
second run is what puts a rail under the no-TOFU rule. Argv is fixed by the contract, so naming
a flag would dictate a spelling to every rail while naming a variable dictates only where to
look.

**What this profile adds to it.** One response member, one context variable, one expectation
cell:

- the response object gains an admission verdict and a denials array, the array compared as a
  set exactly as the validity codes already are;
- the consumer context travels in one environment variable beside the key policy, holding a
  path to a **consumer context document**;
- each vector gains a per-context admission expectation.

The consumer context document is the profile's serialization of the inputs in section 1, and it
exists so that a suite can inject a policy without dictating how a policy engine spells it.
**A conforming context document MUST name its members `substrateObservationKeys`,
`expectedCorpusDigest`, `expectedSubstrateDigest`, `acceptedResults`,
`admitUninterceptedCleanRows`, `demandedClasses`, `maxIssuanceLagHours`,
`maxEvidenceAgeHours`, `allowedNetworkPostures`, `expectedCatchPolicyDigest` and
`keyValidityWindow`, and MUST NOT require a rail to use those names anywhere else.** The
serialization is a wire between the suite and a rail, and a profile that let it leak into the
rail's own configuration would be dictating a spelling.

**Verdicts are three-valued from the first line.** `admit`, `deny`, and `did-not-run`. **A
suite MUST report a rail invocation that crashed, timed out, or emitted an unparseable answer
as `did-not-run`, and MUST NOT record it as a denial.** This is not a hypothetical
defensiveness: the reference cross-rail driver's oracle returns a denial when its engine
process fails for any reason, indistinguishable from a genuine one, and a vector the rail under
test also denies produces zero disagreement and is reported as agreement. A negative is
reportable only when the check demonstrably ran.

**Corpus pin.** The coverage figures below were measured against the conformance corpus this
repository vendors at `packages/verify/vectors/aee-v06/` — release `v0.8.0`, source commit
`0c4e27ec4f28b03d9688885bb5a00c6e96334d1e`, manifest digest
`eb24532be577ee6a936410e6850482847cecac07147aa3c76d737fc730d4bf2b` — which carries 272 vectors:
61 `accept`, 209 `reject`, 2 `indeterminate`. `scripts/lint_failure_codes.py` holds this
declaration to the vendored copy on all three axes and refuses to grade anything when they
disagree, and it counts the figures in the next paragraph out of that same corpus rather than
reading them here.

**The honest state of the coverage this suite starts from.** **No expectation in it is an
admission expectation.** The manifest's expectation shape has no member naming an admission
outcome at all, which is the structural reason nothing this profile adds is measurable from the
corpus yet, and it is the same absence that leaves the four anchor codes of section 1.4 with
zero forcing vectors — a zero recomputed from the manifest on every run rather than asserted
here. 6 vectors carry a per-context evidence-tier expectation, `tierWithPinnedKey` beside
`tierWithoutKey`, and in 4 of them the two contexts differ. **That four, not the six, is the
forcing coverage of section 1.1's mandatory obligation.** A vector whose two contexts agree is
satisfied by a consumer that never consults its key policy at all, so it cannot distinguish a
consumer that derives the tier from one that does not; only a vector that answers `attested`
under a pinned key and `unattested` without it can. Four out of 272, and none at all for
section 1.4: the mechanism the suite needs is proven and its coverage is a token. The one
carrying condition `aee-c-33` — that the evidence tier is derived per row and never carried —
is the only vector in the corpus declaring it, and it is the one that exercises the obligation
across rows of mixed basis. **The profile's first release ships the vectors, and until it does
no claim of conformance to this profile is measurable.**

---

## 8. Non-claims, and what this profile does not cover

### 8.1 What a conforming consumer has and has not established

A consumer at Strict has established that a valid statement about the corpus and substrate it
pinned, covering the classes it demanded, carries a result at or above its threshold, with
every substrate row attested under keys it pinned, inside the freshness bounds it set. It has
not established that the run happened. The substrate is a passive sensor with no view of the
runner that injects the corpus, so the set of attacks actually executed is a producer
assertion, and no consumer obligation in this profile reaches it.

It has not established that no attack was quietly withdrawn from scope. `aee-p-demanded-scope`
reaches a withdrawal that leaves the demanded class out of `coverage.assessedClasses`; it does
not reach a corpus whose manifest never declared the class, and that is the form that reaches a
passing verdict.

It has not established that a caught row was not relabelled clean. The citing form of that
rewrite — a relabelled row still pointing at the `interception` record its caught predecessor
cited — is closed by a validity rule this profile deliberately does not carry (section 0.2).
The deleting form is open, and it is open against every rail today.

### 8.2 What this document deliberately does not cover

- **Any byte-pure rule.** Statement well-formedness, coverage validity, the `result` recompute,
  digest integrity, and the three rules named in section 0.2. All of them belong to the
  predicate and none of them is trust-relative.
- **The envelope trust decision.** Which key signs the outer envelope, how it is distributed,
  rotated and revoked, and what a consumer does on revocation. That is the attestation
  framework's, and for a byte-pure consumer it is the entirety of the trust decision — which
  makes its absence here a gap in the reader's coverage, not a claim that it does not matter.
- **Substrate observation key distribution.** This profile requires a consumer to hold pinned
  keys and says nothing about how it gets them.
- **Tier refinements.** The predicate permits a consumer policy to subdivide `attested` into
  stricter refinements — a hardware-attested observation key, agreement of multiple keys — and
  this profile standardizes none of them. A refinement refines and never reorders the three
  tiers, and a consumer using one declares it.
- **Producing evidence.** Nothing here constrains a producer.
- **Any predicate other than adversarial-execution-evidence.** A result-bearing sibling
  predicate carried in the same bundle is out of scope, and a rail evaluating both states which
  obligations it applies to which.
- **Additional levels.** Three are defined. A deployment needing a fourth publishes a rail map,
  not a level.
- **The conformance vectors themselves.** Section 7.2 designs the suite; it does not ship it.

### 8.3 An obligation not published here is not a conformance requirement

Two obligations were considered for this release and are not in it, and they are named so that
a reader can tell a deliberate exclusion from an oversight. A consumer requirement that every
row declare a hash-pinned rather than time-window attribution has no member to read until the
predicate revision that introduces one, and stating it now would be a requirement about a field
that does not exist. A requirement that a consumer bound the number of records a statement may
carry has no argument behind it yet.

**This profile makes no claim to completeness.** It covers the consumer surface of one shipped
implementation, audited against one specification revision, and an obligation nobody has
written down cannot be one this profile enforces. A document that could not fail would be
worth nothing, and enumerating what it does not reach is what keeps it able to.

---

## Appendix A — the reference rails

The rego module in `deploy/admission/rego/probity_admission.rego` is **an** implementation at a
stated set of dispositions, and it is not the definition of this profile. Two facts about it
must travel with any conformance claim made on it.

**The cross-rail conformance driver does not execute the deployment artifact the bundle
recommends.** It loads the three Kyverno documents and one CUE file; the deep policy-controller
policy that embeds the full module — the one the install instructions recommend — is kept in
sync by a generator and a byte-equality check, which is not an execution.

**A correctly pinned deployment fails that driver by construction.** The driver asserts that
each policy carries exactly two unreplaced anchor placeholders, so an operator who follows the
documented first install step and replaces both turns their own policy files red. The check is
correct as a repository drift guard and fatal to any "run this against your own deployment"
reading of it.

## Appendix B — known defects in the reference implementations

Recorded so that a reader who goes to the source is not misled. Every one is either fixed or
disclosed before a conformance claim cites these rails.

1. **The rego rail derives no evidence tier**, and credits `basis: substrate` rows without one.
   It is a non-conformant consumer of its own predicate, and until 2026-07-30 neither the
   module nor its documentation said so — the capability gap was stated honestly and its
   conformance consequence was not.
2. **The rego rail offers the `pass_indirect` relaxation while unable to derive a tier**, which
   section 1.6 forbids. The 2026-07-30 separation of the threshold from the row gate closed the
   `basis`-and-`method` half of that sentence and left this half open.
3. **`probity-verify` defaults permissive on both anchors**, against section 2.1, in a file
   whose own documentation states the obligation it does not enforce.
4. **Two consumer pins are evaluated inside the rego rail's validity gate.** The catch-policy
   and posture pins are conjuncts of the module's soundness rule rather than of its admission
   rule. Latent today because both default permissive, and live for exactly the consumers who
   follow the guidance and pin them.
5. **`subject` cardinality is enforced nowhere in the rego rail**, and two corpus vectors are
   denylisted under two reasons that are each false and that contradict each other.
6. **The cross-rail driver's oracle is two-valued**, recording a crashed or unparseable engine
   invocation as a denial.
7. **The reference bundle's prose carries stale figures throughout** — vector counts, test
   counts, rail-comparison tables, condition ordinals, and a worked command whose sample
   statement predates a run-binding version change and now fails. No figure in it should be
   quoted, and this profile quotes none.
