# ACAM Exception-Class Taxonomy v1 — the 12 classes and the 2 record types

**Version 0.1.0-draft** · Status: **draft for review** (pre-1.0; versions with `ACAM-SPEC.md`
§17) · License: **CC BY 4.0** · apeiris.ai

> Work package A3 of the ACAM build plan (`ACAM_BUILD_PLAN.md` WS-A). Normative prose half of a
> two-file pair: the machine half is **`acam/acam-exceptions.json`** (classes, predicates,
> consequence classes, worked examples, and the completion-status binding as data) plus the
> procedure-register skeleton **`acam/acam-procedures.json`**. All three join the ACAM release
> unit (`ACAM-SPEC.md` §17 V-1) and version together with `acam-core.json`.
>
> Source of authority: `ACAM-SPEC.md` §7.4 and §16.3; `COVERAGE_ASSESSMENT_PLAN.md` §7 and
> §14/B3; the round-3 disposition register `requirements/VALIDATION-FINDINGS-2026-08-06-acam-round3.md`
> row B3 (the merged Claude/GPT 12-class list, class 4 as amended, and the two record types).
>
> **Drafting discipline** (inherited from `ACAM-SPEC.md`): every normative clause carries an
> **Enforcement:** line naming its mechanism. The verifier and the defective-dossier corpus that
> execute these predicates are WS-B B4/B5 — specified here, not yet implemented; each
> Enforcement line states which side of that boundary it is on.

---

## 1. Scope and discipline

This document defines the complete finding vocabulary of the **ACAM Dossier Conformance Check**
(`apeiris:dossier-conformance-check:v1`, `ACAM-SPEC.md` §16.3): the **12 exception classes**
findings are keyed to, the **2 record types that display but never count**, the
**consequence-class derivation** (procedure-derived, never assessor-assigned), the
**completion-status binding**, and the **count-rendering rule**.

Four properties are constitutional for every class (round-3 B3; `acam-core.json`
`review_record.class_discipline`):

- **EX-1 (machine-decidable).** Every class predicate is a computable condition over recorded
  dossier fields — fields `ACAM-SPEC.md` names, or fields this document names as B1 schema
  requirements (§8). No predicate requires judgment, inspection of underlying evidence
  artifacts, or client interaction. Enforcement: the predicates in
  `acam-exceptions.json` name their fields and comparisons; the B4 verifier implements them as
  pure functions; the B5 corpus contains a triggering specimen per predicate branch. *(B4/B5
  not yet implemented.)*
- **EX-2 (mutually exclusive).** One defect produces exactly one finding under exactly one
  class, per the classification rules in §2.2. Distinct defects in the same dossier — even in
  the same field group — produce distinct findings; exclusivity is per-defect, never
  per-dossier. Enforcement: the MX rules of §2.2 are part of the published predicate set; the
  B5 corpus includes the collision specimens (a defect matching a specific class and the
  structural class must classify to the specific class).
- **EX-3 (severity-free).** No finding carries an assessor-assigned severity. Severity is
  expressed only as the **consequence class** — a published pure function of the detecting
  procedure (§3) — plus counted dimensions the procedure computes (affected controls, affected
  blocking controls, affected populations). The ICFR register (deficiency / significant
  deficiency / material weakness) and the word "material" remain prohibited (`ACAM-SPEC.md`
  §16.4). Enforcement: the finding schema (WS-B B3) has no severity field; `consequence_class`
  is a closed enum whose value is derived, not authored; the prohibited-terms machine list
  covers the ICFR register.
- **EX-4 (traceable).** Every finding names the procedure that detected it (`procedure_id`,
  §7). A finding whose class does not match its procedure's published `detects` list is itself
  a conformance failure of the producing check. Enforcement: `acam-procedures.json` publishes
  the class↔procedure map; the B4 verifier cross-checks every finding against it.

Scope reminder: the classes describe **dossier conformance only, never control effectiveness**
(`ACAM-SPEC.md` §16.3). A triggered class states that the dossier failed a published check
procedure; it states nothing about whether the organization's controls work.

## 2. The classification model

### 2.1 The finding record

Each finding is one machine-readable record, on the same shape discipline as the corpus
security-suite record (`{test_id, component, threat, expected_result, actual_result, status,
gate}`) — the expected/actual pair is what makes the finding reproducible:

| Field | Meaning |
|---|---|
| `finding_id` | Stable per-record id within the check. |
| `class_id` | `EXC-01`…`EXC-12` (this taxonomy), or a record type (§5). |
| `procedure_id` | The detecting procedure, `PROC-01`…`PROC-12` (§7). |
| `target` | JSON pointer(s) into the dossier naming the field(s) examined. |
| `expected` | The published condition (the predicate, instantiated with the dossier's values). |
| `actual` | The recorded value(s) that breached it. |
| `consequence_class` | Derived per §3 — never authored. |
| `affected_control_count` / `affected_blocking_control_count` / `affected_population_count` | Counted dimensions, computed by the procedure. |

Enforcement: the finding schema is WS-B B3; the expected/actual discipline mirrors
`apeiris-control-core/tests/security/lib/harness.mjs` and is checkable (a finding whose
`expected`/`actual` pair does not reproduce under recomputation fails B4 verification).

### 2.2 Mutual-exclusivity rules

- **MX-1 (one defect, one finding, one class).** A defect is the smallest recomputable breach
  of one predicate at one target. Two predicates breached at the same target are two defects.
  Enforcement: B4 emits findings per (predicate branch × target); the B5 corpus pins the
  expected finding count per specimen.
- **MX-2 (specific over structural).** A constraint violation that is enumerated in the
  predicate of any class `EXC-02`…`EXC-12` classifies there, even where the same violation
  would also fail the published dossier schema. `EXC-01` is the **residual structural class**:
  it takes only violations no specific class claims. (Example: an unanswered conflicts question
  is both a schema `required` failure and the `EXC-03` predicate — it classifies `EXC-03`. An
  out-of-enum `variance_reason` is both a schema enum failure and the `EXC-04` predicate — it
  classifies `EXC-04`.) Enforcement: the specific classes' claimed constraint sets are listed
  field-by-field in `acam-exceptions.json`; the B5 collision specimens test the precedence.
- **MX-3 (disjoint specific domains).** Classes `EXC-02`…`EXC-12` are pairwise disjoint by
  construction — each claims a distinct field group and cap-rule set, stated per class under
  "exclusivity" below. Where two specific classes touch the same field family
  (`EXC-04`/`EXC-05` on populations; `EXC-06`/`EXC-11` on evidence supporting a rung), the
  per-class exclusivity notes give the deciding condition. Enforcement: the disjointness is
  documented per predicate; a B4 implementation in which one defect matches two specific
  predicates is non-conforming (B5 includes near-miss specimens on each documented boundary).

## 3. Consequence classes (the severity discipline made computable)

`ACAM-SPEC.md` §7.4 requires severity to be *"counted, published classes derived from
procedures — which procedure fired, on which `blocking_effect` class of control, with what
population consequence."* This document finalizes that derivation:

- **CQ-1 (derivation).** `consequence_class` is a **pure function of `class_id`** — the
  published table below (shipped as data in `acam-exceptions.json`). The blocking and
  population dimensions are **not** folded into the class; they are the counted fields of §2.1,
  computed by the detecting procedure. Nothing about consequence is authored per-finding.
  Enforcement: the map ships as data; B4 computes the value; the finding schema marks the field
  derived (a record whose `consequence_class` differs from the map fails verification).
- **CQ-2 (the closed enum).** Eight values:

| Consequence class | Meaning (what the breach does to the record's usability) | Classes |
|---|---|---|
| `record-invalid` | The artifact fails structural validation; nothing downstream is defined. | EXC-01 |
| `recomputation-blocked` | The verifier cannot recompute verdicts against pinned criteria or verified provenance. | EXC-02 · EXC-03 |
| `denominator-unreliable` | A population-derived figure rests on an unreconciled or unsupported denominator. | EXC-04 · EXC-05 |
| `cap-unapplied` | A fail-closed cap the recorded fields trigger was not applied; a recorded rung exceeds the recomputed rung. | EXC-06 · EXC-07 · EXC-08 |
| `declaration-incomplete` | A conditionally-required supporting declaration is absent; the relying computation loses its basis. | EXC-09 |
| `coverage-misstated` | A computed coverage figure does not equal its recomputation (either direction). | EXC-10 |
| `admissibility-misapplied` | Evidence inadmissible under the window/freshness/expiry rules was relied on. | EXC-11 |
| `disclosure-incomplete` | A mandatory computed disclosure is absent from, or contradicts, the rendered record. | EXC-12 |

- **CQ-3 (no free text, no override).** There is no `other` value, no free-text severity or
  consequence field, and no per-engagement override. Enforcement: closed enum in the B3 schema;
  the contract-diff discipline (`ACAM-SPEC.md` V-3) gates changes.

## 4. The 12 exception classes

Four families (round-3 register): **A — structural / cryptographic** (EXC-01…03) ·
**B — population / sampling** (EXC-04…06) · **C — evidence / procedure** (EXC-07…10) ·
**D — window / freshness / disclosure** (EXC-11…12).

Field paths below use the B1 dossier model as named in `ACAM-SPEC.md` §10–§15; fields marked
**[B1-new]** are schema requirements this document adds — collected in §8. The worked examples
are the derive-from-data seeds for the B5 defective-dossier corpus (one artifact, two
obligations — `ACAM-SPEC.md` RC-3); each ships machine-readable in `acam-exceptions.json` as
`{input_fragment, expected: {fires: true}}` on the conformance-vectors pattern.

---

### EXC-01 `schema-or-type` — family A

- **Predicate.** The dossier (or a composite contribution) fails validation against the
  published B1/B2 JSON Schema at its pinned version — parse failure, missing required field,
  type mismatch, or out-of-enum value — **excluding** every constraint claimed by a specific
  class under MX-2 (the exclusion list ships with the predicate: the `EXC-03` identity/conflicts
  constraints, the `EXC-04` variance constraints, the `EXC-09` conditional `ipe_basis`
  requirement, the `EXC-10` digest-fraction sum, and the `EXC-12` disclosure-sibling
  constraints).
- **Detecting procedure.** PROC-01 (schema validation).
- **Consequence class.** `record-invalid`.
- **Worked example.** A control record carries `"operating": "held"` — not a member of the
  closed enum `{not-tested, tested-held, tested-exception}` (`acam-core.json`
  `sub_states.operating`). Fires.
- **Exclusivity.** The residual structural class (MX-2): it never takes a violation a specific
  class enumerates. Absence of `contradictory_or_limiting_observations` (CAP-04) classifies
  here — no specific class claims it.
- Enforcement: PROC-01 = standard JSON Schema validation plus the published exclusion list;
  B5 carries one specimen per branch (parse / required / type / enum). *(B4/B5 pending.)*

### EXC-02 `corpus-anchor-version-hash` — family A

- **Predicate.** Any of, over the dossier header and per-control pins: (a) `corpus_version`,
  `manifest_sha256`, or `acam_version` absent or not resolvable to a published release;
  (b) `manifest_sha256` ≠ the SHA-256 of the published manifest for the pinned
  `corpus_version`; (c) a per-control `content_sha256` **[B1-new]** ≠ the pinned
  `object_hashes.json` value for that `control_uri` at the pinned corpus version; (d) a
  `control_uri` that does not resolve in the pinned corpus; (e) the sampling-annex pin
  (`acam-sampling.json` version, once A2 ships) absent or mismatched.
- **Detecting procedure.** PROC-02 (corpus-pin resolution and hash recomputation).
- **Consequence class.** `recomputation-blocked`.
- **Worked example.** Header pins `corpus_version: "2026.07.30"` with `manifest_sha256` equal
  to a value that is not the SHA-256 of that release's published manifest. Fires.
- **Exclusivity.** Claims all version/hash/URI resolution facts. A signature that fails to
  verify is EXC-03 (cryptographic verification), not EXC-02 (hash resolution); the boundary is
  "digest recomputation vs signature verification".
- Enforcement: PROC-02 recomputes hashes against published artifacts exactly as the corpus
  `verify-manifest` discipline does; `stale-at-signature` (CAP-24) is **not** this class — a
  stale-but-correctly-pinned corpus is an EXC-12 disclosure matter if unstamped. *(B4/B5
  pending.)*

### EXC-03 `signature-or-identity` — family A

- **Predicate.** Any of: (a) the producer's Ed25519 signature over the JCS-canonical payload
  fails verification against the declared key; (b) the identity binding (ID-1: DNS TXT /
  `.well-known`) does not resolve or does not match the declared organization/key
  (`identity_binding` **[B1-new]**); (c) the conflicts declaration is absent or any question
  is unanswered (CAP-23, shipped with identity per ID-2); (d) a declaration matches an entry
  on the published bright-line prohibited-conflicts list (ID-3, entries finalized in A5);
  (e) `reviewed_by` = `assessor_of_record` (RV-1); (f) on a composite: a contributor
  signature fails, or the contribution-manifest binding does not recompute (CO-5).
- **Detecting procedure.** PROC-03 (signature, identity, and conflicts verification).
- **Consequence class.** `recomputation-blocked`.
- **Worked example.** `conflicts_declaration.fee_contingent_on_outcome` is `null` (question
  present, unanswered). Fires.
- **Exclusivity.** Claims cryptographic-verification and identity/conflicts facts (MX-2 takes
  these from EXC-01 even though they are also schema `required`s). Hash mismatches belong to
  EXC-02.
- Enforcement: PROC-03 reuses the `@apeiris/verify` primitives (one-verify discipline); the
  DNS/`.well-known` resolution is a recorded procedure step with its own retrieved evidence.
  Branches (b) resolution and (d) prohibited-list evaluation are **Apeiris-side procedures**:
  where resolution is impossible for reviewer-side reasons, the correct record is a
  `scope-limitation` (§5), not this class. *(B4/B5 pending; prohibited-list entries are A5.)*

---

### EXC-04 `population-reconciliation` — family B *(the amended class 4)*

- **Predicate (as amended by round-3 B3 — the free-text hole closed).** On any
  population-governing control, over the §11.1 declarations and the scoping-header
  system-of-record counts: a declared count differs from the reconciled or corroborating count
  and the recorded variance set is **any** of:
  - **absent** — no `variances[]` entry covering the difference;
  - **out-of-enum** — a `variances[].reason` outside the closed `variance_reason` enum
    (`acam-core.json`; there is deliberately no `other` value);
  - **arithmetically unaccounted** — Σ `variances[].amount` **[B1-new]** ≠ (declared −
    reconciled) for that population;
  - **unevidenced** — a `variances[]` entry with no resolving `evidence_ref` **[B1-new]**.
  Free text accompanying a typed variance never satisfies the predicate; it can only accompany
  it (`ACAM-SPEC.md` §11.1).
- **Detecting procedure.** PROC-04 (denominator reconciliation — the first substantive lane
  procedure after the three family-A gates; `ACAM-SPEC.md` §11.1 D3).
- **Consequence class.** `denominator-unreliable`.
- **Worked example.** Scoping header declares a system-of-record identity count of 1,250; the
  control-level population declares 1,200; `variances` records one typed entry
  `{reason: "timing-difference", amount: 30, evidence_ref: "wp-041"}`. 20 of the 50-unit
  variance is arithmetically unaccounted. Fires.
- **Exclusivity.** Claims reconciliation-arithmetic and variance-typing defects (incl. the
  out-of-enum schema overlap, per MX-2). Defects in the enumeration **basis itself** — its
  value, its support, its corroboration — are EXC-05. What PROC-04 establishes is internal
  consistency against a declared basis, never population-completeness assurance
  (`ACAM-SPEC.md` §11.1).
- Enforcement: CAP-15 is the in-dossier fail-closed consequence (treated as missing
  enumeration basis, ≤ `documented`); this class fires in the lane whether or not the producer
  applied the cap — an unapplied CAP-15 additionally leaves the recorded rung above the
  recomputation, which is still this class (one defect: the variance breach; the rung delta is
  its counted dimension, not a second finding). *(B4/B5 pending.)*

### EXC-05 `unsupported-enumeration-basis` — family B

- **Predicate.** On any population-governing control, any of: (a) `population_enumeration_basis`
  absent while the recorded `effective_rung` exceeds `documented` (CAP-06 unapplied);
  (b) basis = `interview-assertion` or `estimate` while the recorded `effective_rung` exceeds
  `documented` (CAP-14 unapplied); (c) `corroborating_count` **[B1-new]** absent where its
  `obtainable` field records that one was obtainable, while the recorded `effective_rung`
  exceeds `documented` (CAP-14 unapplied).
- **Detecting procedure.** PROC-05 (enumeration-basis support check).
- **Consequence class.** `denominator-unreliable`.
- **Worked example.** `population_enumeration_basis: "interview-assertion"` with
  `effective_rung: "tested"` on the same control. `tested` > `documented`. Fires.
- **Exclusivity.** Claims the basis field's value/support; EXC-04 claims the reconciliation
  arithmetic over the counts. A single population can raise both — as two defects at two
  targets (MX-1), never one defect in two classes.
- Enforcement: pure enum/ordering comparison over recorded fields using the `acam-core.json`
  ladder order. *(B4/B5 pending.)*

### EXC-06 `sample-below-minimum-uncapped` — family B

- **Predicate.** The recorded `effective_rung` exceeds the ceiling a §11.2 sampling cap
  computes from the recorded sampling declarations: (a) `sample_size` < the published
  minimum-n for the control's frequency/risk key (`minimum_n_key` **[B1-new]**, resolved
  against the pinned `acam-sampling.json`) while `effective_rung` = `effective` (CAP-05);
  (b) `selection_method` = `management-selected`, or `judgmental-with-rationale` with
  `selection_rationale` **[B1-new]** absent, while `effective_rung` exceeds `tested` (CAP-07);
  (c) `deviations_found` > 0 on a control whose `blocking_effect` ∈
  {`blocks-deployment`, `blocks-runtime-action`} with no `tested-exception` token and no
  appended extended-testing sub-record (CAP-08).
- **Detecting procedure.** PROC-06 (sampling-cap recomputation).
- **Consequence class.** `cap-unapplied`.
- **Worked example.** `control_frequency: "daily"`, `sample_size: 5`, minimum-n for the pinned
  key 25 (illustrative pending A2), `effective_rung: "effective"`. Fires. By construction the
  §11.2 headline line "N controls reached `effective` on samples below ACAM minimums" is
  non-zero exactly when branch (a) has fired — a non-conforming producer.
- **Exclusivity.** Claims the §11.2 sampling-cap set (CAP-05/07/08). Rungs resting on
  time-inadmissible evidence are EXC-11 (the deciding condition: which cap rule the
  recomputation applied). Note the class name is the round-3 canonical token; its predicate
  scope is the full sampling-cap family — a deliberate scoping decision recorded in the A3
  work-package report.
- Enforcement: predicate (a) binds by reference to the A2 annex; until `acam-sampling.json`
  ships, B5 specimens carry an explicit table stub pin so the predicate stays decidable.
  *(A2/B4/B5 pending.)*

---

### EXC-07 `assertion-only-uncapped` — family C

- **Predicate.** A recorded `effective_rung` exceeds what the workpapers' procedure blocks
  support: (a) every workpaper for the control has
  `procedure_performed: none-assertion-only` and no `execution_log_ref`, while
  `effective_rung` exceeds `mapped` (CAP-01 unapplied); (b) a workpaper cited for
  `documented`-or-above has an empty `observation`, and recomputing without that workpaper
  yields a lower rung than recorded (CAP-02 unapplied); (c) `claimed_rung` present with no
  qualifying workpaper while `effective_rung` ≠ `mapped` (CAP-22 unapplied).
- **Detecting procedure.** PROC-07 (procedure-block admissibility recomputation).
- **Consequence class.** `cap-unapplied`.
- **Worked example.** Three workpapers, each `procedure_performed: "none-assertion-only"`;
  `effective_rung: "documented"`. `documented` > `mapped`. Fires.
- **Exclusivity.** Claims procedure-block qualification (CAP-01/02/22). Reliability-class
  floors are EXC-08; time admissibility is EXC-11.
- Enforcement: recomputation over the recorded workpaper fields only — the lane never inspects
  the underlying evidence artifact (dossier conformance, not effectiveness). *(B4/B5 pending.)*

### EXC-08 `reliability-floor-breach` — family C

- **Predicate.** Either: (a) the control's pinned `validation_objective` concerns operation, no
  operating-role evidence item (`evidence_role` **[B1-new]**) carries `evidence_class`
  **[B1-new]** ∈ {`automated`, `third-party`}, and the recorded `effective_rung` exceeds
  `design-effective` (CAP-03 / AP-1 unapplied); or (b) on a control with `blocking_effect` ∈
  {`blocks-deployment`, `blocks-runtime-action`}, interview notes (`procedure_performed:
  "inquiry"`) are the sole support and the recorded rung was not recomputed as unevidenced
  (CAP-12 / AP-2 / F-2 unapplied — non-overridable).
- **Detecting procedure.** PROC-08 (reliability-floor recomputation).
- **Consequence class.** `cap-unapplied`.
- **Worked example.** An operationally-scoped control's operating evidence items are all
  `evidence_class: "attested"`; `effective_rung: "tested"`. `tested` > `design-effective`.
  Fires.
- **Exclusivity.** Claims the reliability-class floors (CAP-03/12). Procedure-block
  qualification is EXC-07; staleness of an otherwise-adequate class is EXC-11.
- Enforcement: pure comparison over `evidence_role` × `evidence_class` × the ladder order;
  the operational-objective flag comes from the pinned corpus control, not from assessor
  judgment. *(B4/B5 pending.)*

### EXC-09 `ipe-basis-absent` — family C

- **Predicate.** `ipe_basis` is absent on any record where `ACAM-SPEC.md` §10.1/§11.1
  conditionally requires it: (a) an evidence item with `evidence_class: "automated"` or an
  `execution_log_ref`; (b) the scoping-header system-of-record count where that count is
  automated.
- **Detecting procedure.** PROC-09 (IPE-basis presence check).
- **Consequence class.** `declaration-incomplete`.
- **Worked example.** A workpaper records `execution_log_ref: "logstore://runs/118"` with no
  `ipe_basis`. Fires.
- **Exclusivity.** The conditional `ipe_basis` requirement is claimed here, not by EXC-01
  (MX-2), and not by EXC-04 even when the omission sits on the SoR count (the deciding
  condition: field absence is EXC-09; count arithmetic is EXC-04).
- Enforcement: conditional-presence check; fires on omission regardless of whether any rung
  changed (`ACAM-SPEC.md` §10.1). *(B4/B5 pending.)*

### EXC-10 `digest-scope-miscount` — family C *(fires in both directions)*

- **Predicate.** Over the digest fields of §10.3: (a) the declared three-part coverage
  fraction (`evidence_digest_coverage.{hashed, metadata_with_declared_reason, unaccounted}`
  **[B1-new]**) does not equal the recomputation from the per-item `digest_scope` records —
  **over-counted or under-counted alike**; (b) the three parts do not sum to
  `declared_evidence_inventory` **[B1-new]** (CAP-19); (c) a `digest_scope: "metadata-only"`
  item counted toward content-integrity (gating) coverage (CAP-16 unapplied); (d) a
  `metadata-only` item with `digest_unavailable_reason` absent or inconsistent with its
  `component_operator` (CAP-17).
- **Detecting procedure.** PROC-10 (digest-coverage recount).
- **Consequence class.** `coverage-misstated`.
- **Worked example.** `declared_evidence_inventory: 40`;
  `evidence_digest_coverage: {hashed: 30, metadata_with_declared_reason: 6, unaccounted: 0}`.
  30 + 6 + 0 = 36 ≠ 40. Fires.
- **Exclusivity.** Claims all digest-coverage arithmetic and admissibility (incl. the CAP-19
  sum, per MX-2 — a miscount literally). Boundary-limited-system admission without its
  scope-limitation record (CAP-18) is EXC-12 (a disclosure defect); the digest fields
  themselves are this class.
- Enforcement: recount is pure arithmetic over recorded fields; digests are commitments, never
  "verification" (§10.3 claim-language rule), and the lane recomputes counts, not artifact
  bytes. *(B4/B5 pending.)*

---

### EXC-11 `window-or-freshness` — family D

- **Predicate.** A recorded rung or verifier state rests on time-inadmissible evidence, or the
  time arithmetic itself is wrong: (a) an operating-role item with `collected_on` **[B1-new]**
  outside `assessment_window` supports a recorded `tested`/`effective` (CAP-09 / W1 —
  no-override); (b) a design-role item predating the window by > 90 days, or by ≤ 90 days
  with `w2_justification` **[B1-new]** absent, was admitted (CAP-10 / W2); (c) an item stale
  under the pinned freshness table supports the recorded rung unchanged (CAP-11 / F-1
  unapplied); (d) `assessment_window.end − assessment_window.start` > 12 months, or
  `dossier_expires` ≠ `assessment_window.end + 12 months` (authored, not computed — CAP-25
  arithmetic); (e) a freshness override recorded against W1 or CAP-12 (non-overridable rules
  in an override record — CAP-13).
- **Detecting procedure.** PROC-11 (window/freshness/expiry recomputation).
- **Consequence class.** `admissibility-misapplied`.
- **Worked example.** `assessment_window: {start: "2026-01-01", end: "2026-06-30"}`; an
  operating item `collected_on: "2025-11-14"` is the sole operating support;
  `effective_rung: "effective"`. Fires.
- **Exclusivity.** Claims time admissibility (CAP-09/10/11/25 arithmetic + the CAP-13
  non-overridable boundary). Sampling-cap deltas are EXC-06; the **count** of permitted
  overrides on the cover is EXC-12 (deciding condition: admissibility of the evidence vs
  disclosure of the override).
- Enforcement: date arithmetic over recorded fields; freshness-table branch (c) binds by
  reference to the A2 annex like EXC-06's minimum-n. *(A2/B4/B5 pending.)*

### EXC-12 `disclosure` — family D

- **Predicate.** A mandatory computed disclosure is absent from, or contradicts recomputation
  on, the rendered record: (a) the §11.1 cover consistency line
  (`population_consistency_line`) absent or ≠ its regeneration from recorded fields; (b) the
  freshness-override count (`override_count`, CAP-13) absent or ≠ the count of override
  records; (c) the corpus-currency stamp absent where the pinned release was not current at
  signature, or the scoped version delta absent (CAP-24 unapplied); (d) a percentage rendered
  without its numerator/denominator/scope-enumeration siblings, or
  `out_of_scope_with_rationale` absent from the cover (SC-2); (e) failure-token counts absent
  from a scorecard aggregate (DOM-4/SC-4); (f) a `claimed_rung` not rendered beside its
  `effective_rung` (R-1), the Assurance Basis not co-rendered on a verdict (AB-2), Tier-S
  `effective` not labeled self-attested (AB-4), or `review_extent`/`review_date` absent from
  the face of the record (RV-2); (g) a boundary-limited system admitted without its mandatory
  scope-limitation record (CAP-18's disclosure half); (h) any prohibited term
  (`acam-core.json` `prohibited_terms`) present in the artifact's rendered language
  (`ACAM-SPEC.md` §16.4).
- **Detecting procedure.** PROC-12 (disclosure completeness and regeneration check).
- **Consequence class.** `disclosure-incomplete`.
- **Worked example.** A scorecard renders `coverage_percent: 63.5` with no
  numerator/denominator fields and no scope enumeration. Fires (SC-2).
- **Exclusivity.** Claims every mandatory-disclosure constraint (MX-2 takes the SC-2 sibling
  constraints from EXC-01). The underlying facts disclosed belong to their own classes — an
  undisclosed stale corpus is (c) here, while a *mispinned* corpus is EXC-02; an inadmissible
  override is EXC-11(e), while a *miscounted* override is (b) here.
- Enforcement: every §16.4/§14.2 rendered value is a recorded field, so regeneration is
  computable; branch (h) runs the prohibited-terms machine list as a structural check (the
  `validate-framing.mjs` pattern). *(B4/B5 pending.)*

## 5. The two record types that display but never count

Findings arrays may contain, alongside class-keyed exceptions, exactly two further record
types. Both **render at identical prominence** and **never increment any exception count**
(they never appear in the "K of 12" numerator or its class breakdown):

- **`observation`** — a fact about the **dossier** worth surfacing that breaches no published
  predicate. The canonical case: the §10.4 all-nil screen — a dossier of hundreds of controls
  with zero contradictory-or-limiting observations anywhere is itself the reviewable finding
  ("400 controls, zero limitations"), yet no rule is violated. Observations keep the lane
  honest without inflating counted exceptions into judgment calls.
- **`scope-limitation`** — a fact about the **check**, not the client: a published procedure
  (or an identified part of one) could not be executed — reviewer-side access, tooling, or
  boundary (e.g. provider-held bytes cannot be re-presented for a digest recount; an identity
  binding could not be resolved from the reviewer's network position). **The
  Apeiris-fact-vs-client-fact rationale:** counting a reviewer-side inability as a client
  exception would misattribute the client's posture, and silently dropping it would overstate
  the check — so it displays, moves the completion status (§6), names the affected
  `procedure_id`(s), and never counts. This is the same misattribution discipline as
  RO-1's `relation-undeclared` vs `insufficiently-evidenced` split (`ACAM-SPEC.md` §14.1).

Rules:

- **RT-1.** Both types carry `procedure_id` and `target` like any finding, and a
  `record_type` discriminator; they carry **no** `class_id` and **no** `consequence_class`.
  Enforcement: B3 schema — the discriminator excludes the class fields (`oneOf`).
- **RT-2.** A `scope-limitation` record is mandatory whenever any procedure result is
  `scope-limited` or `not-performed` for reviewer-side reasons, and its presence forces the
  completion status per §6. Enforcement: verifier cross-check procedure-results ↔ records.
- **RT-3.** Neither type may be rendered less prominently than exceptions (outcome invariance,
  `ACAM-SPEC.md` §16.1). Enforcement: the rendering rule is checkable because both live in the
  same findings arrays every projection carries.

## 6. Completion-status binding and count rendering

The Conformance Check's completion status (`acam-core.json` `review_record.completion_status`)
contains **no findings summary**; findings live only in the per-procedure arrays. The binding
between statuses, procedures, and classes (shipped as data in `acam-exceptions.json`):

| Completion status | Procedure results required | Compatible classes | New findings possible |
|---|---|---|---|
| `procedures-completed` | All 12 procedures executed (`no-exception` or `exception-recorded`); **zero** `scope-limitation` records | EXC-01…EXC-12 (any) | yes |
| `procedures-completed-with-scope-limitation` | All procedures executed or `scope-limited`; ≥ 1 `scope-limitation` record | EXC-01…EXC-12 (any) | yes |
| `unable-to-complete` | ≥ 1 procedure `not-performed`; the blocking finding or scope-limitation is named | Classes of executed procedures only | yes |
| `expired` | none executed post-issuance | rendered frozen as at signing | no |
| `revoked` | none executed post-issuance | rendered frozen as at signing | no |

- **CS-1.** A family-A finding forces `unable-to-complete` **only** when it makes downstream
  procedures unexecutable (e.g. an unparseable dossier). A localized family-A finding — one
  control's `content_sha256` mismatch while the rest resolve — coexists with
  `procedures-completed`. The deciding fact is recorded per procedure (`not-performed` +
  `blocked_by`), never inferred. Enforcement: procedure-result records; verifier cross-check.
- **CS-2.** `exception-recorded` on every procedure is fully compatible with
  `procedures-completed` — completion describes procedure execution, never favorability
  (outcome invariance). Enforcement: no schema path couples status to finding counts.
- **CS-3 (count rendering).** The one aggregate rendering is the computed count line:
  **"K of 12 exception classes triggered across N procedures"** — K = distinct `class_id`s
  with ≥ 1 finding, N = procedures with result ≠ `not-performed`. The zero case renders
  **"0 of 12 exception classes triggered across N procedures"** and **never** an enum token
  (`ACAM-SPEC.md` RC-1: a favorable aggregate token retains the negative-assurance form the
  attestation literature prohibits). Record types are excluded from K by construction (§5).
  Enforcement: the line is renderer-computed from the findings arrays; no aggregate token
  exists in any closed enum.

## 7. The procedure register

The detecting procedures PROC-01…PROC-12 are the Conformance Check's published procedure set —
**versioned and hashed at release**: the signed check record pins
`{procedure_set_version, procedure_set_sha256}` over the canonical bytes of
`acam-procedures.json` (`ACAM-SPEC.md` §16.3: "the versioned+hashed procedure set"). The
skeleton register ships as **`acam/acam-procedures.json`**: per procedure
`{procedure_id, description, detects: [class_ids], machine_decidable: true}`, executed in
register order (the three family-A structural gates first, then reconciliation — §11.1 D3 —
then the recomputation and disclosure procedures). v1 is deliberately 1:1
(PROC-nn detects EXC-nn); the register shape permits many-to-many so later procedure versions
can split or share detection without a taxonomy change. Enforcement: EX-4 traceability; the
pinned hash makes any procedure-set drift visible in the signed record.

## 8. B1 field requirements (feeds the B1 dossier-schema work package)

Every predicate above is decidable from fields `ACAM-SPEC.md` already names, **plus** the
following, which B1 MUST define (named here so the taxonomy and the schema cannot drift; also
shipped as `b1_field_requirements` in `acam-exceptions.json`):

| # | Field (path) | Needed by | Purpose |
|---|---|---|---|
| 1 | `workpapers[].evidence_role` ∈ {`design`, `operating`} | EXC-08, EXC-11 | §10–§11 distinguish design vs operating evidence throughout but never name the discriminator field. |
| 2 | `workpapers[].evidence_class` ∈ `reliability_rank` enum | EXC-08 | §10.2 names the rank vocabulary, not the per-item field. |
| 3 | `workpapers[].collected_on` (date) | EXC-11 | §11.3 says evidence is "dated" without naming the field. |
| 4 | `workpapers[].w2_justification` | EXC-11 | The W2 recorded justification for design evidence predating the window ≤ 90 days. |
| 5 | `workpapers[].freshness_override` (record) | EXC-11, EXC-12 | CAP-13 counts overrides; the override must be a recorded object naming the table row permitting it. |
| 6 | `sampling.minimum_n_key` (or the derivable pair frequency × risk band) | EXC-06 | The lookup key into the A2 `acam-sampling.json` minimum-n table. |
| 7 | `sampling.selection_rationale` | EXC-06 | CAP-07's "judgmental-with-rationale with no recorded rationale" needs the rationale field. |
| 8 | `sampling.corroborating_count` = `{value, source, obtainable}` | EXC-05 | CAP-14's "where one was obtainable" must be a recorded fact, not an inference. |
| 9 | `sampling.variances[]` = `{reason, amount, evidence_ref}` | EXC-04 | §11.1 requires quantitative accounting; `amount` and `evidence_ref` are the fields that make "arithmetically unaccounted" and "unevidenced" computable. |
| 10 | `controls[].content_sha256` | EXC-02 | §3 pins controls "by corpus version and content hash"; the per-control hash field must exist to recompute against `object_hashes.json`. |
| 11 | `header.identity_binding` = `{method ∈ {dns-txt, well-known}, domain, key_id, verified_on}` | EXC-03 | ID-1 names the mechanisms; the recorded binding object makes resolution recomputable. |
| 12 | `cover.declared_evidence_inventory` (count) | EXC-10 | The CAP-19 sum target. |
| 13 | `cover.evidence_digest_coverage` = `{hashed, metadata_with_declared_reason, unaccounted}` | EXC-10 | §10.3's three-part fraction needs canonical field names. |
| 14 | `cover.population_consistency_line` · `cover.override_count` · `cover.corpus_currency` · `cover.out_of_scope_with_rationale` | EXC-12 | The mandatory computed cover disclosures as recorded (regenerable) fields. |
| 15 | `scorecard.*_percent` sibling fields `{numerator, denominator, scope_enumeration_ref}` | EXC-12 | SC-2's schema constraint needs the sibling field names. |

Enforcement: this table is the A3→B1 hand-off contract; B1's schema review checks every row
off (a predicate whose field B1 renames without updating `acam-exceptions.json` is a release
defect under V-3).

## 9. Versioning

This document, `acam-exceptions.json`, and `acam-procedures.json` join the ACAM release unit
(`ACAM-SPEC.md` §17). Any change to a class predicate, the consequence map, the
completion-status binding, the record types, or the procedure register is a new ACAM version;
removing or renarrowing a class, weakening a predicate, or changing a consequence-class
assignment is breaking (MAJOR). The 12-class count is load-bearing (the count line renders
"of 12"): adding a class is MAJOR. Enforcement: the contract-diff gate pattern (V-3) applied
to `acam-exceptions.json` against its blessed baseline.
