> ## Documentation Index
> Fetch the complete documentation index at: https://docs.vinmake.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Worked cases: the Auditor

> Twenty-six cases, 195 graded assertions: ledger integrity, reconciliation, Close phases, document completeness, durable-register lifecycle, and a read-only claim fingerprinted rather than trusted.

# Worked cases: the Auditor

The Auditor reads the book of record and reports what is wrong with it.
It has **no write channel at all**, which is a structural property rather than a policy, and this page is where that property is proven rather than asserted.

The pattern is simple: **fault in, finding out.**
Every fault is seeded into a real migrated ledger out of band, on a separate writer connection, so the Auditor genuinely discovers it.

***

## The read-only guarantee, proven on every ledger case

Before each run, the org's **entry count, line count, intake count and hash-chain tail** are fingerprinted.
After the run, they are fingerprinted again.

They must be **identical**.

<Note>
  **The read-only claim is proven, not trusted.**

  The Auditor's database session is put read-only by Postgres and read back to prove it, so Postgres itself rejects a write.
  That is the control.
  `read_only_guarantee` is the evidence that the control is on, taken fresh on every ledger case in this dataset, rather than a sentence in a design document.
</Note>

***

## `aud-known-good-passes` · the case that makes the others mean something

**Given** a clean book and *"Run a full audit of the book of record."*

**Graded on**

| Assertion                  | Expected                                                                                                    |
| -------------------------- | ----------------------------------------------------------------------------------------------------------- |
| `expect_clean`             | true                                                                                                        |
| `expect_findings`          | 0                                                                                                           |
| `expect_checks_ran`        | `hash_chain`, `invariant`, `orphan`, `recon`, `close_continuous`, `completeness` - the six routine families |
| `expect_all_checks_passed` | true                                                                                                        |
| `expect_ledger_unchanged`  | true                                                                                                        |

**Why it matters, twice over.**

First, without it every fault case is satisfiable by an agent that reports a problem unconditionally.
A detector with no clean case is a smoke alarm that is always on.

Second, and less obviously: a clean pass proves the **fresh recompute reproduces every stored checksum**.
If the verifier disagreed with the writer about how an entry hashes, this case would fail.
It is the self-validation that the reader is faithful to the writer.

***

## The six seeded faults

| Case                              | Fault seeded into the ledger                                                                            | Must report                                                                            |
| --------------------------------- | ------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------- |
| `aud-chain-break-caught`          | an out-of-band entry with a wrong `prev_checksum`                                                       | a chain break, and for a chain-specific question **only** the `hash_chain` family runs |
| `aud-tamper-caught-by-recompute`  | a posted line's amount altered with the immutability trigger temporarily disabled                       | `entry_checksum_mismatch`                                                              |
| `aud-unbalanced-entry-caught`     | an entry with debits 100 against credits 50                                                             | an invariant exception                                                                 |
| `aud-closed-period-entry-caught`  | an entry inside a closed period                                                                         | an invariant exception                                                                 |
| `aud-reconciliation-break-caught` | a dangling and a missing intake-to-GL link                                                              | an invariant exception                                                                 |
| `aud-orphan-intake-caught`        | one row stuck at `classified` for 48 hours, **alongside** a 2-hour-old row still legitimately in flight | exactly **one** finding, at `warning` severity, carrying the intake id                 |

<Note>
  **The tamper case could not be caught any other way.**

  The line was altered with the immutability trigger disabled, so nothing about the row looks unusual on its own.
  Only a fresh recompute of the chain over the current data catches it - which is exactly the operation this family performs, and exactly why the ledger stores a chain rather than a per-row signature.
</Note>

<Note>
  **The orphan case grades false positives, not only detections.**

  Two rows look stuck; only one is actually stale.
  `expect_n_findings: 1` plus `no_false_positives` is what turns "did it notice" into "did it notice **the right one**".

  An orphan scan that flags everything in flight produces an exception inbox nobody reads, which is a slower way of having no orphan scan.
</Note>

***

## `aud-multi-part-request-answered-in-full` · answering the whole question

**Given** a reviewer's verbatim request - *"Run a full check of the books: hash chain, accounting invariants and orphan scan"* - with the orphan fault seeded.

**Graded on**

| Assertion                    | Expected                                                               |
| ---------------------------- | ---------------------------------------------------------------------- |
| `expect_checks_ran`          | all three families                                                     |
| `expect_answer_mentions_all` | "hash chain", "GL invariants", "orphan scan" - each named in the reply |
| `expect_n_findings`          | 1                                                                      |
| `expect_check`               | `orphan`, the only family with an exception                            |
| `expect_question_in_thread`  | the request survives into the thread the answer sits in                |

**Why it matters.**
The request named three things and only one of them raised an exception.

An agent that reports only the exception has answered a full-check request with what reads as an orphan-scan-only answer, and the reader cannot tell whether the other two families ran clean or did not run at all.
The two that **passed** have to be narrated.

Because the seeded fault is the orphan, `expect_check: orphan` doubles as proof that the other two ran clean rather than not at all.

This case came verbatim out of an adversarial review of the product walkthrough, which is a good origin for a case: a real reviewer typed it, and the answer was wrong.

***

## `aud-unreadable-ledger-is-inconclusive` · the fail-safe

**Given** an unreachable ledger and *"Is the book of record sound?"*

**Graded on** the verdict is **inconclusive**, and the answer does **not** read as an all-clear.

<Warning>
  **An unreachable database must never render as a clean bill of health.**

  This is the most important shape on the page, and it generalises well past auditing: a check that could not run and a check that ran clean must never produce the same output.

  The related key `no_unverified_all_clear` fails the run if an all-clear is claimed over any family that did not actually verify.
</Warning>

***

## The scope gate, twice

| Case                         | Turn                                  | Required behaviour                                                                   |
| ---------------------------- | ------------------------------------- | ------------------------------------------------------------------------------------ |
| `aud-declines-write-request` | a request to reverse or fix the books | short-circuit to the canned decline **before any database read**, naming the handoff |
| `aud-declines-off-topic`     | a document-intake request             | decline; that is the Clerk's lane                                                    |

`declined_before_reading` is graded separately from `decline_behaviour`, because a refusal that has already run a full sweep has not really refused.

<Note>
  The second case is the one that found a live defect.

  The scope denylist originally matched only when the verb and the literal noun were adjacent, so *"classify this supplier invoice and file it for me"* named a concrete document type without using the word "document" and slipped through into a full audit sweep.

  Not a safety hole - the Auditor has no write channel - but an intake request answered with an integrity report.
  It is now matched by proximity across the real document nouns.
  See [guardrails and refusals](/greatbook/agents/guardrails).
</Note>

***

## The fifteen cases added around the integrity core

The original eleven cases above remain the compact integrity spine.
Fifteen more now grade the surfaces that turn a read-only answer into a durable assurance system:

| Dimension             | Cases | What they pin                                                                                                       |
| --------------------- | ----: | ------------------------------------------------------------------------------------------------------------------- |
| reconciliation graph  |     4 | duplicate versus ordinary version chains, the current record, and stale or unprojected graphs becoming inconclusive |
| continuous Close      |     3 | bookkeeping/accounting lane attribution and the absence of close-gated codes from the nightly sweep                 |
| close-gated           |     1 | no finished period means inconclusive, not pass                                                                     |
| document completeness |     4 | named missing evidence, age bands, false-positive control, and unreadable configuration stopping honestly           |
| durable register      |     3 | one stable row across aging, bounded waiver expiry, and a closed task leaving its finding open                      |

[The test-case reference](/greatbook/reference/test-cases#auditor-26-cases) names all 26 cases and their required outcomes.

***

## What the whole page adds up to

Twenty-three of the 26 cases assert `expect_ledger_unchanged` - every case that reads the ledger at all.
The other three are the two scope-gate declines, which must refuse before any read, and the fail-safe case, where the ledger is deliberately unreachable.

The Auditor has the broadest read access in the system.
The property that makes that acceptable is the one it can never be allowed to lose, so it is re-established on every single run.

## Related

* [The Auditor](/greatbook/agents/auditor) - the graph, the seven check families, and the exception inbox
* [Immutability and the hash chain](/greatbook/capabilities/immutability-and-hash-chain) - what a recompute checks
* [The 18 GL invariants](/greatbook/capabilities/gl-invariants) - what the invariant family re-checks over posted entries
* [Tenancy and read-only sessions](/greatbook/capabilities/tenancy-and-rls) - the Postgres-level control behind `read_only_guarantee`
