# Verifier Divergence Log

Living record of every divergence between implementations that the corpus round-trip surfaced. Each entry must include: the canonical Rust behavior (authoritative), the divergent behavior, when it was caught, and the remediation path. Closed entries are kept for posterity.

## Open divergences

_(none — all known divergences are closed)_

## Closed divergences

### DIV-001 — TypeScript impl: cascading `if` reversed verdict precedence + open challenges leaked into Incomplete

- **Discovered:** 2026-06-01, during Rust round-trip of corpus fixtures 04–07
- **Closed:** 2026-06-01, by branch `fix/div-001-open-challenge-conformance`
- **Triggering fixture:** `06_open_challenge`
- **Canonical Rust behavior (`src/agent_zero/astate_replay.rs:606-618` + line 622):**
  ```rust
  let verdict = if !conflicts.is_empty() {
      ReplayVerdict::AuthorityConflict
  } else if revoked_chain_observed {
      ReplayVerdict::RevokedChain
  } else if provenance_broken_observed {
      ReplayVerdict::ProvenanceBroken
  } else if policy_missing_observed {
      ReplayVerdict::PolicyMissing
  } else if incomplete_observed {
      ReplayVerdict::Incomplete
  } else {
      ReplayVerdict::Valid
  };

  let _ = (..., open_challenges);  // explicitly discarded
  ```
  Open challenges do NOT affect verdict or snapshot. Precedence is first-match wins.
- **Browser JS behavior (`/agent-zero/replay-engine/replay.js:357-362`):**
  ```js
  if (conflicts.length > 0) verdict = 'authority_conflict';
  else if (revokedChainObserved) verdict = 'revoked_chain';
  else if (provenanceBrokenObserved) verdict = 'provenance_broken';
  else if (policyMissingObserved) verdict = 'policy_missing';
  else if (incompleteObserved) verdict = 'incomplete';
  else verdict = 'valid';
  ```
  **Conforming.** Matches Rust byte-for-byte. Open challenges tracked internally in `openChallenges` Map but never consulted for verdict computation.
- **TypeScript divergence (was at `reference-impl-ts/src/replay.ts:417-421`):**
  ```ts
  let verdict: ReplayVerdict = "valid";
  if (revokedChainObserved) verdict = "revoked_chain";
  if (provenanceBrokenObserved) verdict = "provenance_broken";
  if (policyMissingObserved) verdict = "policy_missing";
  if (conflicts.length > 0) verdict = "authority_conflict";
  if (openChallenges.size > 0 || incompleteObserved) verdict = "incomplete";
  ```
  **Two bugs:**
  1. Cascading `if` (not `else if`) — later conditions overwrote earlier ones, so the effective precedence was reversed: `Incomplete > AuthorityConflict > PolicyMissing > ProvenanceBroken > RevokedChain > Valid`
  2. `openChallenges.size > 0` was OR'd into the incomplete condition — open challenges should not affect verdict per Rust
- **Resolution:** TypeScript impl rewritten to match Rust verbatim. `void openChallenges;` suppresses the unused-variable lint without changing behavior (mirrors Rust's `let _ = (..., open_challenges);`).
- **Initial misdiagnosis (process finding):** the original DIV-001 entry incorrectly claimed browser JS also exhibited this bug. The mistake was caught when re-reading the actual browser JS source for the fix. **Browser JS was already conforming.** The misdiagnosis is recorded here because the discipline is to log every divergence finding honestly — including the ones that turn out to be wrong. The corrected entry above is the authoritative one.

## Process

Every divergence is recorded here, even if the resolution is "browser/TS were right and Rust was wrong." Rust remains canonical by default, but the discipline is to surface every divergence — silent fixes are forbidden because they erode trust in the conformance contract.

Misdiagnoses are corrected in place rather than deleted. The historical record matters more than the appearance of perfect attribution.

When a divergence is closed:
1. Move the entry from "Open" to "Closed"
2. Add a `Closed:` date and reference to the closing commit / branch
3. Confirm conformance test passes for the affected fixture across all impls
4. The "No known replay divergence ships into a customer or verifier surface" rule (Eric, 2026-06-01) is satisfied when this section reads `(none — all known divergences are closed)`.
