# `BoundedAuthorityProtocol.Conformance.Cli`
[🔗](https://github.com/baselabs/bounded_authority_protocol/blob/v1.0.0/lib/bounded_authority_protocol/conformance/cli.ex#L1)

Deterministic offline verifier CLI for every packaged conformance corpus.

Run it as the `bounded_authority_conformance` escript or call `run/1` from Elixir. Both take the
same arguments and return the same exit status; `run/1` never halts the VM.

    bounded_authority_conformance --corpus DIR [--report PATH]
    bounded_authority_conformance --help
    bounded_authority_conformance --version

## Corpora

`--corpus DIR` is required. `DIR` is one corpus directory, the one holding its `index.json`.
The CLI recognizes the corpus from its index; there is no flag per corpus. Inside the package
(`Application.app_dir(:bounded_authority_protocol, "priv/conformance")`, or
`deps/bounded_authority_protocol/priv/conformance` in a Mix project) they are:

| Directory | Corpus |
|---|---|
| `v1/corpus`, `v2/corpus`, `v3/corpus` | contract-majors 1, 2 and 3 |
| `strict-ed25519` | strict Ed25519 (`bap-strict-ed25519/1`) |
| `producer-canonicality` | producer canonicality (`bap-producer-canonicality/1`) |
| `selector-float-zero` | selector float zero (`bap-selector-float-zero/1`) |
| `application-profiles/local-loopback-http/v1` | local-loopback HTTP proofs |
| `attestation-profiles/role-attestation/v1` | role attestations |
| `attestation-profiles/content-assertion/v1` | content assertions |

Each directory must be exactly the certified corpus this release was built against: its
`index.json` bytes must hash to the pinned identity, so a regenerated or edited corpus fails
even when it is internally consistent.

## What it reads

The CLI reads `index.json`, then only the files the index names. It refuses, with exit 1:

- a symbolic link, device or other non-regular entry anywhere inside `DIR`;
- any file inside `DIR` that the index does not name;
- an index path that is absolute or contains an empty, `.` or `..` segment;
- a file larger than 1 MiB, or more than 4,096 entries under `DIR`.

`DIR` itself, and the directories above it, may be reached through symbolic links (Mix links
`_build/*/lib/*/priv` to the package's `priv`).

## Exit status

- `0`: complete agreement. Every named file is present with its SHA-256, the counts match, and
  the executed cases are exactly the certified census (unique case ids, the same id set and
  count as the index, each case executed from the file that declares it), every one agreeing
  with its expected verdict and bytes.
- `1`: anything else: a disagreement, an incomplete or padded run, an integrity or
  certification failure, a refused or unreadable file, or a report that cannot be written.
- `2`: a usage error: `--corpus` missing, an unknown flag, or a flag without its value.

`--help` and `--version` print to standard output and exit 0.

## Output

The report goes to `--report PATH`, or to standard output when the flag is absent. It is one
line of RFC 8785 (JCS) JSON followed by a newline, with exactly these members:

- `format`: `"bounded-authority-protocol-<corpus>-conformance-report"`, where `<corpus>` is
  `v1`, `v2`, `v3`, `strict-ed25519`, `producer-canonicality`, `selector-float-zero`,
  `local-loopback-http`, `role-attestation` or `content-assertion`;
- `agreement`: `true` only for exit 0;
- `exit_status`: `0` or `1`, the status the run returns when the report is written;
- `total`, `agreed`, `disagreed`: case counts;
- `index_sha256_base64url`: base64url SHA-256 of the exact `index.json` bytes.

These members, the flags and the exit statuses are a stable contract of package 1.x. A failure
before a report exists (usage, refusal, integrity, certification) writes no report.

Every failure writes one line to standard error naming its class, for example
`bounded_authority_conformance: the corpus directory holds a file the index does not name`. The
line never contains a path, a case id or corpus bytes. Usage errors print the usage text to
standard error.

## Purity

This module is the package's one I/O carve-out: argument parsing, reading the corpus directory
and writing the report. Every judgment (integrity, certification, case execution, agreement and
completeness, report bytes) is made by the package's pure internal core. No clock, network,
randomness or trust selection is involved.

# `run`

```elixir
@spec run([binary()]) :: 0 | 1 | 2
```

Runs the CLI against `argv` and returns the exit status (0, 1 or 2). See the module
documentation for the arguments, the files read, the report and the exit statuses.

It does not halt; the escript's entry point halts with the returned status. The certified index
identities are fixed in this module and cannot be supplied by the caller.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
