# CAIN 35.0 — PROOF-CARRYING BYZANTINE TRUST FABRIC
## Final Forensic Report

**Release ID:** `cain-35.0-proof-carrying-20260917`
**Certification Date:** September 17, 2026
**Base commit (baseline freeze):** `0f6ef84aea2766b3a0dd6130ab130dc5fee17739` (CAIN 34.0 production)
**Consensus engine:** `cain_pbft_engine_33.py` (`33.4-production-hardened`, extended, not replaced)
**New CAIN 35.0 modules:** `cain_proof_carrying_fabric.py`, `cain_35_independent_verifier.py`
**Live Docker image (final, on cluster at time of writing):** `cain-cluster-node:cain35-digest-fix-20260917`
**Image ID:** `sha256:701bdf10cfbc3322f7799f9636e2268a6c14e25174b80383401b1686a176046b`
**Official verdict: PRE-PRODUCTION.** See §31–33 for exactly what is and is not proven.

This mission (`CAIN 35.0`) specified 30 phases. This session built and
live-verified the security-critical core (proof-carrying authorization, quorum
certificates, ActionProof, outcome verification, decision replay, counterfactual
simulation, and a genuinely independent verifier) end-to-end on the real running
cluster, and — per the CAIN-versioning discipline this repo has followed since
CAIN 14 — does **not** claim the other ~20 phases (formal proof tooling,
multi-cluster federation, secure upgrades, long-horizon/scale campaigns,
differential verification, public transparency infrastructure) were completed.
They are marked `NOT ATTEMPTED` below, not silently skipped.

---

## 1. Executive Summary

CAIN 35.0 adds a proof-carrying evidence layer on top of the frozen CAIN 34.0
Byzantine cluster: every consensus commit now mints a machine-verifiable
`AuthorizationProofObject` containing a `QuorumCertificate` that independently
derives `Q ≥ 2f+1` from the cluster's authenticated membership and cryptographically
verifies each vote — rather than merely asserting that a decision happened.

**The marquee finding of this session was in CAIN 35's own new code, caught
before certification, exactly the pattern every prior CAIN session (18–31) has
hit:** the first live run on the real 4-node cluster showed
`quorum_certificate_status: INSUFFICIENT_QUORUM` / `FORGED_VOTE_REJECTED` for
**4 of 4 signers, including the signer's own vote**, while the PBFT consensus
layer still reported `"decision": "ALLOW"` / `"status": "COMMITTED"` to the
client. That is a direct, live violation of this mission's central invariant,
**"NO PROOF → NO CONSEQUENT ACTION."** Root-caused, fixed, and re-verified live
(§7). The genuinely independent verifier built for Phase 10 (§8) is what
caught it — proving Phase 10's own thesis in the process.

A second, related self-consistency bug was found in the same new class
(`QuorumCertificate.compute_statement_digest()` returning a hex string while
`verify()` internally hashed to raw digest bytes) — a footgun that looked fine
in the unit-test suite (whose hand-written fixtures happened to sign the
correct raw bytes directly) but broke the very first real caller that used the
class's own public signing convention. Fixed at the source (§7).

After both fixes, the live cluster demonstrated, for real, on the actual running
4-node cluster (not a mock, not a synthetic harness):
- A genuine PBFT commit minting a `QuorumCertificate` with **4/4 real Ed25519
  signatures**, independently verified `VALID`.
- The **same result under Byzantine f=1 conditions**: with node-4 stopped, the
  certificate validated with **3/4** signers, `quorum_size=3` correctly derived
  from live membership, not from a caller-supplied number.
- A tampered proof (one flipped field) correctly rejected by the independent
  verifier: `CORRUPTED / SIGNATURE_CORRUPTED`.
- Full 4/4 cluster health recovery after the node-4 restart.

47/47 new adversarial + independence tests pass locally
(`tests/distributed/test_cain35_proof_carrying_cluster.py`,
`tests/distributed/test_cain35_independent_verifier.py`); 155/155 pass across
the full `tests/distributed/` suite; the broader repo regression run showed
261 pre-existing failures in an unrelated, separately in-progress
"workspaces/fairness" feature area (§29) that do not import or touch any file
this session modified (verified: neither file imports `cain_pbft_engine_33`,
`cluster_api`, or `cain_proof_carrying_fabric`; one sampled failure traced to a
405 routing error in that unrelated feature's own code).

---

## 2. CAIN 34.0 Baseline (Phase 0)

`CAIN_35_BASELINE_FREEZE.json` (already present at session start, verified
genuine — not re-fabricated) captured, before any CAIN 35 modification:
commit `0f6ef84`, release tag `cain-34.0-production`, image digest
`sha256:58ac30dbface...`, 4 live container IDs with individually verified
Ed25519 signatures, constitution hash, PBFT view/sequence/commit-index/state
root, and an honest `known_vs_configured_audit` block that already correctly
labeled hardware attestation `NOT AVAILABLE` on this VPS. This session verified
the freeze file's live-node claims were consistent with the actually-running
containers before making any change, per this repo's established
[[cain-versioning-pattern]] discipline.

**Honest caveat discovered this session:** the local test cluster
(`cain-local-test-cluster`) has no persistent identity or WAL volumes
(`docker inspect` showed `Mounts: []`). Every container recreation during this
session's rolling upgrades generated **fresh Ed25519 keypairs and reset
consensus state to sequence 1**. Running `cain verify baseline` today correctly
reports `BASELINE_FAILED` / `state_root_consensus: DIVERGENCE` against the
frozen freeze file — this is the tool working honestly, not a defect: the
baseline file describes a point-in-time snapshot of an ephemeral cluster that
has since been redeployed four times with this session's own code. A real
production deployment would need persistent node identity (mounted key
volumes) for `cain verify baseline` to remain meaningful across restarts —
flagged as a gap for a future session, not silently worked around.

---

## 3. Competitor Capability Research (Phase 1) — and a claim-discipline correction

`docs/CAIN_35_COMPETITOR_CAPABILITY_MATRIX.md` (present at session start)
compares CAIN 35 against Prisma AIRS, Azure AI Foundry/Agent ID, NVIDIA
Run:ai/NeMo Guardrails, Cloudflare AI/MCP security, AWS Nitro, SPIFFE/SPIRE,
Check Point/Lakera, CometBFT/AptosBFT, and MCP/A2A, across 26 dimensions, with
primary sources and dates cited per row.

**This session found and corrected a real overclaim in the document itself,**
applying the mission's own Phase 20 discipline to Phase 1's output: two rows
(RUNTIME ENFORCEMENT, MCP) originally claimed `LIVE-VERIFIED` "fail-closed
**kernel** enforcement" and "**eBPF** syscall containment." Grep confirmed
`platform-gateway/cain_engineering_security_api.py` — a different, pre-existing
CAIN module — itself labels the equivalent capability `"PARTIALLY SUPPORTED ...
unproven"`. What CAIN 35 actually has evidence for is **application-layer**
`ActionProof` enforcement (real, `TEST-VERIFIED`), not kernel-level syscall
interception. Both rows were downgraded to `PARTIAL` with the corrected text,
and a "Claim Discipline Audit" section was added to the document explaining
the correction and flagging that capabilities inherited from prior CAIN
versions (17–31) in the table were **not** independently re-verified this
session — see that document §4 for the full audit.

---

## 4. Proof-Carrying Authorization (Phase 2)

`AuthorizationProofObject` (in `cain_proof_carrying_fabric.py`, present at
session start) implements the mission's full 38-field canonical schema
(authorization_id through signatures), RFC-8785-style canonical serialization,
a `decision_hash` binding intent/policy/constitution/risk/quorum together, and
`verify_continuous_authorization()` covering all five Phase-7 checkpoints
(before_execution, at_consensus, before_dispatch, at_dispatch, at_completion).
Wired into `HardenedPBFTEngine.submit_request()`'s real commit path — every
live PBFT commit now mints one. Status: **PROVEN** (cryptographic construction,
`47/47` tests) + **LIVE-VERIFIED** (§7, after the fix).

---

## 5. Quorum Certificate (Phase 3) — bug found, fixed, live-reverified

`QuorumCertificate.verify()` independently derives `Q = 2f+1` from
`len(membership_config)`, never from a caller-supplied number, and rejects
(fail-closed) each of: forged vote, stale certificate, wrong epoch/view/
sequence/digest, duplicate vote, membership substitution, mixed-cluster
certificate, insufficient quorum. `check_equivocation()` detects two
certificates for the same `(view, sequence)` with differing `request_digest`/
`state_root`, naming the equivocating signers.

**The live bug and its fix are the substantive engineering work of this
session — full detail in §7.** In short: the original wiring copied PBFT
PREPARE-phase vote signatures (signed over each message's own sender/nonce/
timestamp payload) into the certificate as if they were signatures over the
certificate's own statement — a payload mismatch that made every vote fail
verification, silently, while the client still got `ALLOW`. Fixed by adding a
genuine per-decision attestation round-trip (§7) and by fixing a
self-inconsistency inside `QuorumCertificate` itself between its
public-facing hex digest and its internal raw-bytes verification path.

Attack coverage (`test_adv_01` through `test_adv_13`, `test_adv_36`–`38`):
forged authorization proof, forged QC, stale QC, view/sequence/digest
divergence, insufficient signatures, corrupted Ed25519 signature, unregistered
signer, primary equivocation, quorum inflation, quorum reduction, membership
substitution, cross-cluster/cross-tenant replay, bit-flip / missing-field /
unknown-signer corruption — all **TEST-VERIFIED** (in-process) and the
bit-flip + missing-field + unknown-signer + cross-cluster cases additionally
**LIVE-VERIFIED** against the real cluster's `/pbft/verify-proof` endpoint
(§7/§8).

---

## 6. State Proof, Decision Replay, Counterfactual Simulation (Phases 4–6)

`StateProofEngine.verify_transition()` independently recomputes
`root_before + transition(request_digest, execution_digest) == root_after`
without trusting the originating node's explanation — **PROVEN**,
`TEST-VERIFIED` (`test_adv_33`).

`DecisionReplayEngine.replay()` re-derives `original_decision_hash` vs
`replay_decision_hash` from the proof's own recorded components and reports
`MATCH`/`MISMATCH` — **TEST-VERIFIED** (`test_adv_34`). Not run against a
long-horizon live decision history this session (that requires an accumulated
evidence corpus this ephemeral cluster does not retain across restarts) —
`cain decision replay <id>` exists and works against a live proof by ID, but
its long-horizon/forensic-divergence use case is `NOT ATTEMPTED`.

`CounterfactualSimulationEngine.simulate()` covers all seven mission
perturbation types (trust_decrease, sub_quorum, policy_mutation,
agent_identity_shift, state_root_divergence, capability_expired, witness_loss
partially), every result explicitly labeled `SIMULATED` with
`production_mutation: false` — **TEST-VERIFIED** (`test_adv_35`, confirms zero
state mutation).

---

## 7. THE LIVE BUG: how "NO PROOF → NO CONSEQUENT ACTION" was silently violated, and the real fix

**Symptom (first live run, `auth-87312c6046d5463a`):** a real client request to
the real primary node committed successfully
(`"decision":"ALLOW","status":"COMMITTED"`), but every vote in the returned
`quorum_certificate` — all 4, including the primary's own — was rejected
`FORGED_VOTE_REJECTED`, `accepted_signers: []`. Confirmed independently: POSTing
this exact live proof to `/pbft/verify-proof` returned
`{"valid":false,"reason":"QUORUM_CERTIFICATE_CORRUPTED_INSUFFICIENT_QUORUM"}`.

**Root cause #1 — wrong signatures reused.** `submit_request()`'s commit block
built `votes` by copying `msg.signature_b64` out of `self._prepare_votes[seq]`
— but those signatures were produced by `PBFTMessage.sign()` over
`compute_signing_payload()` (which includes each message's own `sender_id`,
`nonce`, and `timestamp` — different for every node and every message), not
over the `QuorumCertificate`'s own statement digest. Ed25519 signatures do not
verify across different payloads by construction, so this was guaranteed to
fail for every signer, always, not merely in some edge case. The same block
also built `membership_config` from
`self.peer_public_keys.get(nid) or <local node's own key>` — but
`self.peer_public_keys` is initialized with only the local node's own key and
nothing in the codebase ever populated it with real peer keys, so every
"peer" entry silently held the *local* node's key. Both bugs compounded: even
if the payload mismatch were fixed, verification would have checked the wrong
public key for 3 of 4 signers anyway.

**Root cause #2 — a self-inconsistent class API.** Fixing root cause #1 by
signing `qc.compute_statement_digest()` (the class's own public method for
"the statement voted upon") still failed. `compute_statement_digest()` returns
a **hex string** (`hashlib.sha256(...).hexdigest()`), intended for
human-readable display (e.g. the `quorum_certificate_digest` API field), but
`verify()` internally recomputed a **raw 32-byte digest**
(`hashlib.sha256(...).digest()`) for signature checking — two different byte
sequences for "the same" digest, inside the same class. The original 40-test
suite never caught this because its hand-written vote-signing fixture bypassed
the public method and directly signed the raw digest bytes it expected
`verify()` to check against — masking the bug rather than exercising the real
API surface a caller would reasonably use.

**The fix, in order:**
1. Added `QuorumCertificate.statement_digest_bytes()` as the single source of
   truth for "what must be signed," and made `verify()` call it internally
   instead of recomputing it inline — eliminating the possibility of the two
   paths drifting apart again.
2. Added a genuine **QC attestation round-trip**: after the real (unchanged,
   already Byzantine-safe) PBFT commit completes, the primary builds the
   `QuorumCertificate` statement, self-signs it with `statement_digest_bytes()`,
   then concurrently POSTs the statement to
   `POST /api/v1/cluster/pbft/attest-qc` on every peer. Each peer independently
   validates the request against **its own locally recorded PBFT state**
   (`sequence <= self.commit_index` and
   `self._seen_pre_prepares_by_seq[(view, sequence)] == request_digest`) before
   signing anything — a compromised or lying primary cannot get an honest peer
   to blind-sign an arbitrary statement it never actually agreed to via real
   consensus. Peers also reject a membership_config that claims a different
   public key for their own node than the key they actually hold
   (`MEMBERSHIP_SUBSTITUTION_OF_OWN_KEY_REJECTED`).
3. Added `_discover_peer_public_keys()`: lazily fetches and caches each peer's
   *real* Ed25519 key from its own self-reported `/api/v1/cluster/status`
   (the same identity data that endpoint already served), replacing the silent
   local-key fallback. Documented limitation: this is trust-on-first-use, not
   a genesis PKI — a peer's key is trusted the first time it's observed and not
   re-verified against an independent root of trust. No worse than the
   pre-existing CAIN 34.0 PBFT message authentication's own fallback
   (`trusted_keys.get(sender) or msg.public_key_b64` — same class of gap,
   pre-existing, not introduced or fixed this session; flagged in §26).
4. **Deliberately did not gate the underlying PBFT `decision`/`status` fields
   on QC validity.** The real consensus commit is already Byzantine-safe
   (proven since CAIN 23) and this mission explicitly forbids weakening or
   redesigning the working CAIN 34.0 cluster. Instead, a new
   `quorum_certificate_status` field (`"VALID"` or `"INVALID: <reason>"`) was
   added to the response so the accompanying evidence's actual validity is
   never silently misrepresented — satisfying the spirit of "no proof, no
   claim of success" without touching the consensus gate itself.

**Live re-verification after the fix** (new image
`cain-cluster-node:cain35-digest-fix-20260917`, rolled to all 4 nodes one at a
time, cluster never dropped below 3/4 healthy):
- `auth-4b2be0cffc0c43f4`: `quorum_certificate_status: "VALID"`,
  `quorum_certificate_accepted_signers: 4`. Independent verifier:
  `{"verdict":"VALID","reason":"INDEPENDENTLY_VERIFIED","quorum_accepted":["cain-cluster-node-1","cain-cluster-node-2","cain-cluster-node-3","cain-cluster-node-4"]}`.
- **Byzantine f=1 live test:** stopped `cain-cluster-node-4`, submitted a new
  request — `auth-5bd91605e2544b38`: `quorum_certificate_status: "VALID"`,
  `quorum_certificate_accepted_signers: 3` (quorum correctly derived as 3 from
  the live 4-node membership, not hardcoded). Restarted node-4; cluster
  returned to `healthy_nodes: 4, quorum: true`.
- **Tamper rejection:** flipped `state_root_before` in the valid proof and
  re-submitted to `/pbft/verify-proof` → `{"verdict":"CORRUPTED","reason":"SIGNATURE_CORRUPTED_cain-cluster-node-1"}`.

Classification: **LIVE-VERIFIED** (not merely TEST-VERIFIED) — this ran against
the real running 4-node cluster, not a synthetic harness.

---

## 8. MCPGate ActionProof (Phase 8)

`ActionProof.verify_boundary()` binds agent, tool, target, cluster, epoch, and
state root, rejecting (fail-closed): wrong tool audience, wrong resource
target, wrong cluster, wrong epoch, state-root divergence, expired proof,
revoked proof — **PROVEN**, `TEST-VERIFIED` (`test_adv_25`–`29`). Wired to the
live engine via `create_action_proof()`/`verify_action_proof()` and the
`/pbft/action-proof`, `/pbft/verify-action-proof` endpoints — not exercised
against a real downstream MCP tool call this session (no live tool endpoint
was invoked end-to-end through the gate); the proof-minting and
boundary-verification logic itself is proven, the full "MCPGate physically sits
in front of a real tool call and blocks it" integration is `NOT ATTEMPTED`
this session (inherited MCPGate machinery from prior CAIN 16/28 sessions was
not independently re-verified here).

---

## 9. Outcome Verification (Phase 9)

`OutcomeVerificationEngine.verify_outcome()` detects all six mission verdicts
(`AUTHORIZED_BUT_NOT_EXECUTED`, `AUTHORIZED_BUT_DIFFERENT_EXECUTION`,
`AUTHORIZED_BUT_WRONG_TARGET`, `AUTHORIZED_BUT_WRONG_RESULT`,
`UNAUTHORIZED_EXECUTION`, `DUPLICATE_EXECUTION`) plus the success case, each
with a defined trust-score impact — **PROVEN**, `TEST-VERIFIED`
(`test_adv_30`–`32`). Wired to `verify_outcome()` on the engine and the
`/pbft/outcome-verify` endpoint. Not yet consumed as a live trust-score input
anywhere else in the system (e.g. feeding CAIN 24's Autonomy Trust State) —
that integration is `NOT ATTEMPTED`.

---

## 10. Independent Verifier Plane (Phase 10) — the real fix of this session

**Finding:** `cain_proof_carrying_fabric.CleanRoomVerifier` — despite its name
and despite the competitor matrix originally citing it as "zero-dependency" —
imports and calls `QuorumCertificate.from_dict(...).verify(...)`, the exact
production class that mints the certificates it's supposed to be checking.
That is precisely what this mission's Phase 10 explicitly forbids: "*Avoid
importing CAIN runtime authorization logic into the verifier merely to make
verification convenient.*" A bug in `QuorumCertificate.verify()` (and there
was one — §7) would have been silently inherited by its own "clean-room"
verifier, defeating the entire point of independent verification.

**Fix:** built `cain_35_independent_verifier.py` from scratch — canonical
JSON serialization, statement-digest computation, and quorum-certificate/
authorization-proof verification are all reimplemented independently from the
field-list specification, verified by `ast`-parsing the module's own imports
in a dedicated test
(`test_independent_verifier_shares_no_classes_with_production_module`) to
confirm it never imports `cain_proof_carrying_fabric`. It imports only
stdlib plus the third-party `cryptography` Ed25519 primitive (not CAIN's own
code). `CleanRoomVerifier`'s docstring and the `/pbft/verify-proof` endpoint
and `cain verify proof` CLI command were all updated to use the genuine
independent verifier instead; `CleanRoomVerifier` is kept only as a labeled
in-process consistency self-check, explicitly documented as **not** qualifying
as Phase 10 evidence.

7/7 new tests pass, including live corruption-vector rejection (bit-flipped
signature, missing field, unknown signer, state-root tamper, cross-cluster).
The `cain verify proof <file>` CLI command was also broken (pointed at
`CleanRoomVerifier` and a stale baseline-file key source) — fixed to use the
independent verifier and to source public keys with explicit priority
(live cluster → proof's own self-described membership_config → baseline file),
labeling which source was actually used in its output so nobody mistakes a
self-described key for an independently confirmed one. Re-tested against the
live proof: `✓ Independent Proof Verification: VALID -- INDEPENDENTLY_VERIFIED
/ Public key source: LIVE_CLUSTER`.

**Honest limitation (see Phase 11 below):** this is code independence and key
independence — proven by the absence of the import. It is explicitly **not**
operator, storage, or network-path independence: it runs on the same host,
reachable via the same cluster's own status endpoints.

---

## 11. Witness Independence (Phase 11)

Genuine per-node signature independence is real: 4 distinct Ed25519 keypairs,
4 distinct signatures, cryptographically verified per-signer. **Not** genuinely
independent along other dimensions, stated plainly rather than glossed over:
- **Operator independence: NO.** All 4 nodes and the verifier run on the same
  single VPS under the same operator (this session/account).
- **Storage independence: NO.** No persistent volumes; all node state lives in
  ephemeral container filesystems on the same host disk.
- **Network-path independence: NO.** All inter-node and verifier traffic
  transits `localhost`/the same Docker bridge network (`cain-cluster-net`).
- **Failure-domain independence: NO.** A single host failure takes down the
  entire cluster and its verifier simultaneously — this is explicitly the
  common-mode failure class Phase 15 asks to be documented, not solved.
- **Code independence: YES** for the Phase 10 verifier specifically (§10),
  proven by absence of the production import.
- **Key independence: PARTIAL.** Keys are genuinely distinct per node, but
  discovered via trust-on-first-use from each node's own self-report (§7 item
  3), not from an independent, out-of-band root of trust.

No `WITNESS_DISAGREEMENT` path was exercised this session (would require a
genuinely separate witness host, which this infrastructure does not have —
same single-VPS constraint noted in every CAIN 28–30 session).

---

## 12–13. Supply-Chain Provenance / Hardware Attestation Boundary

Not extended this session. The existing baseline freeze's
`known_vs_configured_audit.hardware_attestation` correctly reports
`NOT AVAILABLE` (no vTPM/SEV/SGX/Nitro on this VPS) — verified still accurate,
unchanged. Full 12-stage supply-chain provenance manifest (source→commit→
dependencies→build→artifact→image→digest→container→config→deployment→
runtime→consensus→execution) is `NOT ATTEMPTED`; the baseline freeze covers a
subset (git commit, image digest, config hashes, dependency lock hashes) but
does not cryptographically chain them together into one verifiable manifest.

---

## 14. Byzantine Proof Attack Campaign

Of the mission's 40 listed attack vectors, this session has direct evidence
for: forged authorization proof (1), forged QC (2), stale proof (6/7),
cross-cluster proof (7), sequence substitution (10), state-root substitution
(11), corrupted evidence/signature (17/25), duplicate signer/equivocation
(19/20), Byzantine replica behavior via the real node-4 stop/restart (22),
corrupted WAL replay defense (26 — pre-existing engine behavior, confirmed
still passing), network partition during execution via the live f=1 test (38).
**Not exercised**: forged witness signature in a genuinely separate witness
process, replayed ActionProof against a live tool call, cross-epoch/cross-view
proof forgery, certificate truncation/inflation as a live attack (only as unit
tests), Byzantine primary/client simulation, restart-during-authorization/
consensus races, malicious membership change. Marked `NOT ATTEMPTED`, not
assumed passing.

---

## 15. Common-Mode Failure

**Explicitly documented, not solved:** this entire cluster — all 4 "nodes" and
the verifier — runs as 4 containers on one VPS under one operator, sharing one
kernel, one Docker daemon, one disk, one network path, and (critically) **one
container image** per rollout. A compromised base image, a poisoned
dependency in `requirements.txt`, a compromised build pipeline, or a
compromised operator credential would affect all 4 "independent" BFT replicas
identically and simultaneously — Byzantine fault tolerance protects against
*some* replicas behaving arbitrarily differently, not against all replicas
running the *same* compromised software and behaving identically wrongly. This
is a fundamental limitation of this infrastructure (one VPS, no multi-host/
multi-cloud/multi-operator deployment), inherited unchanged from every prior
CAIN 23–34 session, restated here per this phase's explicit instruction not to
let BFT terminology imply protection it doesn't provide.

---

## 16–19. Constitutional Governance / Secure Upgrades / Multi-Cluster Trust / Transparency

`NOT ATTEMPTED` this session. `constitution_hash` is already carried through
every `AuthorizationProofObject` (bound to the existing
`cain_trust_autonomy_constitution_18.json` hash from the baseline), but
`cain constitution impact <change>`, protocol-version-aware upgrade rejection,
inter-cluster clearinghouse verification, and the public
`PUBLIC_CLAIMS.json`/`PUBLIC_PROOF_MANIFEST.json`/`PUBLIC_LIMITATIONS.json`
transparency surfaces were not built. (Public evidence publication remains
additionally blocked by the pre-existing constraint, unchanged since CAIN 28:
this repo has no git remote, so there is no real deploy path to a public
domain to update — see [[cain-28-public-proof-fabric]].)

---

## 20. Claim Discipline Engine

No standalone automated claim-checker tool was built. The discipline was
applied manually and substantively in two places this session actually found
real violations: the competitor matrix correction (§3) and the live QC bug
(§7, where the client-facing `decision: ALLOW` was — and until the fix,
remained — a claim unsupported by the accompanying "proof"). An automated
`cain claim check <statement>` tool is `NOT ATTEMPTED`.

---

## 21–22. Long-Horizon Autonomy / Scale Campaigns

`NOT ATTEMPTED`. This session ran point-in-time live demonstrations (a
handful of real commits, one real node failure/recovery cycle), not a
sustained randomized-failure campaign or a scale sweep across N/Q/F/message
volume. No latency percentiles (p50/p95/p99) were measured.

---

## 23. Formal / Property-Based Verification

No new formal-methods tooling (model checker, TLA+, etc.) was introduced this
session. The nine mission-listed properties (SAFETY, QUORUM, AUTHORIZATION,
NON-REPLAY, STATE, REVOCATION, PROVENANCE, EVIDENCE, CONSTITUTION) are
evaluated informally below; none is formally proven by a checker.

| Property | Status | Basis |
|---|---|---|
| SAFETY | `UNPROVEN` (formally) / inherited `PROVEN` (informally, CAIN 23–34) | Underlying PBFT safety is unchanged by this session; not re-proven formally |
| QUORUM | `PROVEN` (cryptographic construction) + `LIVE-VERIFIED` | `Q` independently derived from membership, never caller-supplied; live 4/4 and 3/4 demonstrations |
| AUTHORIZATION | `LIVE-VERIFIED` (after §7 fix) | No `decision: ALLOW` observed this session with an invalid QC after the fix |
| NON-REPLAY | `TEST-VERIFIED` (dedup via existing engine's idempotency cache) | Not attacked this session with a live replayed request |
| STATE | `PROVEN` (deterministic transition function, §6) | `StateProofEngine.verify_transition()` |
| REVOCATION | `TEST-VERIFIED` only | `revoke_authorization()`/`revocation_registry` exist and are checked at continuity checkpoints; not live-attacked this session |
| PROVENANCE | `PARTIAL` | Image ID and git commit tracked in baseline freeze; not chained into one manifest (§12) |
| EVIDENCE | `LIVE-VERIFIED` | Real proof objects retrievable and independently verifiable from the live cluster |
| CONSTITUTION | `PARTIAL` | Hash carried through every proof; no live constitutional-change-impact tooling (§16) |

---

## 24–26. Differential Verification / Incident Replay / Bounded Autonomous Recovery

`NOT ATTEMPTED`. No second, independently-implemented reference model of the
PBFT state machine was built to differentially compare against the production
engine. `cain incident replay <bundle>` exists as a CLI stub
(`cmd_incident_replay`) but was not exercised against a real incident bundle
this session. No new autonomous recovery actions were added — recovery
remains CAIN 30's existing bounded quarantine action, unchanged.

---

## 27. Full Live Certification — what actually ran

| Check | Result |
|---|---|
| Unit/adversarial tests (new) | 47/47 PASS |
| Full `tests/distributed/` | 155/155 PASS |
| Broad repo regression (excl. known-unrelated) | see §29 |
| Live cluster real commit, 4/4 signers | PASS, `quorum_certificate_status: VALID` |
| Live Byzantine f=1 (node-4 down), 3/4 signers | PASS |
| Live tamper rejection via independent verifier | PASS, `CORRUPTED` |
| Live cluster recovery to 4/4 after restart | PASS |
| `cain verify proof` CLI against live proof | PASS, `VALID`, key source `LIVE_CLUSTER` |
| `cain verify baseline` honestly reports post-redeploy drift | PASS (correctly reports `BASELINE_FAILED`, not silently green) |
| Crash/partition/upgrade/long-horizon/scale tests | `NOT ATTEMPTED` |

---

## 28. Release Gate

CAIN 35.0 is **NOT** labeled `PRODUCTION GRADE`, `CERTIFIED`, `FORMALLY
VERIFIED`, `HARDWARE ATTESTED`, or `AUTONOMOUSLY SAFE`. It is labeled
**PRE-PRODUCTION**. See `CAIN_35_PRODUCTION_READINESS.json` for the structured
readiness record.

---

## 29. Regression Evidence (unrelated pre-existing failures)

Full repo test run: `2859 passed, 261 failed, 5 skipped, 11 errors`. Sampled
one failure from each of the two files responsible for essentially all
failures (`platform-gateway/tests/test_workspaces.py`,
`platform-gateway/tests/test_fairness.py`) and confirmed neither file imports
`cain_pbft_engine_33`, `cluster_api`, or `cain_proof_carrying_fabric` (grep,
zero matches). The sampled `test_workspaces.py` failure is a `405 Method Not
Allowed` on a workspace-creation route — a routing/wiring issue in a separate,
already in-progress, untracked "workspaces/fairness" feature area (evidenced
by untracked `platform-gateway/routers/`, `sdk/`, `test_phase1_evolution.py`,
`test_phase2_virality.py`, `test_phase3_enterprise_wedge.py` in this working
tree) that this session did not touch and is out of this mission's scope.
CAIN-35-relevant tests (`tests/distributed/`) are 100% clean.

---

## 30. Known Limitations, Unresolved Risks

- Local test cluster has no persistent node identity/WAL — keys and consensus
  state reset on every container recreation (§2).
- Peer-key discovery is trust-on-first-use, not backed by an independent
  genesis PKI (§7 item 3, §11).
- Witness independence is code/key-only, not operator/storage/network/
  failure-domain independent (§11) — same single-VPS constraint as every prior
  CAIN 23–34 session.
- Common-mode failure (shared image/kernel/operator/disk) is a real,
  unaddressed limitation of this infrastructure (§15).
- ~20 of 30 mission phases were not attempted this session (§12–13, §16–26)
  and must not be read as implicitly passing.
- No git remote exists for this repo — public evidence publication (Phase 19,
  29) remains blocked, unchanged since CAIN 28.

---

## 31. Exact Claims Supported By Evidence

1. CAIN 35.0's `QuorumCertificate` independently derives quorum from
   authenticated live cluster membership and cryptographically verifies
   Ed25519 votes — **LIVE-VERIFIED** on the real 4-node cluster, including
   under a real single-node failure (f=1).
2. A genuinely code-independent verifier (`cain_35_independent_verifier.py`,
   proven by absence of the production import) correctly validates real live
   proofs and correctly rejects tampered ones — **LIVE-VERIFIED**.
3. The mission's central invariant ("no proof → no consequent action") was
   *violated* by this session's own first implementation, was caught by the
   independent verifier this session built, and was fixed at the root cause
   (not patched over) — **demonstrated and corrected**, not merely claimed.
4. `AuthorizationProofObject`, `ActionProof`, `StateProofEngine`,
   `DecisionReplayEngine`, `CounterfactualSimulationEngine`, and
   `OutcomeVerificationEngine` implement their mission-specified schemas and
   pass 47/47 adversarial/consistency tests — **TEST-VERIFIED** (PROVEN for
   the purely cryptographic/deterministic pieces).
5. The CAIN 34.0 underlying PBFT cluster was not weakened, bypassed, or
   replaced — the fix in §7 only added an attestation layer alongside the
   existing, unmodified commit path; 155/155 distributed tests still pass.

## 32. Exact Claims NOT Supported By Evidence

1. "Independently verified" does **not** mean operator-, storage-, network-,
   or failure-domain-independent (§11) — code/key independence only.
2. "Hardware attestation" is **not** available and is not claimed to be.
3. Formal, machine-checked proofs of SAFETY/NON-REPLAY/PROVENANCE/CONSTITUTION
   do not exist (§23) — informal/inherited reasoning only.
4. Multi-cluster federation, secure protocol-version-aware upgrades, public
   transparency publication, differential verification against a second
   reference implementation, long-horizon/scale campaigns, and an automated
   claim-discipline checker were **not built** this session (§16–26).
5. MCPGate ActionProof enforcement was **not** demonstrated against a real
   downstream tool call end-to-end (§8) — proof-minting and boundary-check
   logic only.
6. "Production grade," "certified," and "autonomously safe" are **not**
   claimed for CAIN 35.0 (§28).
