# WORKFLOW.md — NotBefore in one page, for the person who has to defend the randomization

You want a sample, a split, an assignment or a single number that nobody — you included — could have steered, and a
record a reviewer or auditor can check without trusting you or us. Six commands, four artifacts.

## The six commands

```
pip install notbefore                                        # the verifier, every key and trust root are inside the package
notbefore keygen                                             # 1. once: your Ed25519 identity (~/.config/notbefore/identity.key; back it up)
notbefore plan --after 2026-10-01T00:00Z --purpose chart-audit-2026-q4 \
               --decision-id NCT01234567/protocol-3/randomization-1 --sample 50 eligible.txt
                                                             # 2. BEFORE the hour: the contract, signed, timestamped by two TSAs, registered write-once
#  ... wait for the hour ...
notbefore execute notbefore-plan-chart-audit-2026-q4.json   # 3. AFTER: no choices — the rule picks the pulse, everything is re-verified, the output is written
notbefore receipt notbefore-plan-chart-audit-2026-q4.json   # 4. one page, human-readable, every line re-verified
notbefore bundle  notbefore-plan-chart-audit-2026-q4.json --out randomization-1.zip
                                                             # 5. the verification bundle to attach to the paper / workpaper
notbefore check-bundle randomization-1.zip                   # 6. what your reviewer runs — offline, against their own installed release
```

`--after` is the instant your decision must precede; the pulse is the first eligible hourly reveal released at or after
it. `--decision-id` is the write-once namespace under your key: bind it to something your institution already holds
(`<registry id>/<protocol version>/<decision>`), because NotBefore cannot tell two names for one experiment apart.
The input file is committed by SHA-256 and never leaves your machine unless you say `--include-input`.

## The four artifacts

| artifact | what it is | what it proves |
|---|---|---|
| **contract** `notbefore-plan-<purpose>.json` + `.sig.json` + two `.tsr` + `.log.json` | canonical JSON of the decision; your Ed25519 statement over its hash; FreeTSA and DigiCert timestamps of its bytes; the decision log's signed receipt | *who* committed, to *exactly what*, *when* (two independent clocks), and that it was *the* first registration for that decision id |
| **transcript** `notbefore-executed-<sha16>.json` | the pulse pair, V, the derived seed, the operation and parameters, input and output SHA-256s, the checks that ran | *how* the result follows deterministically from V and the contract — anyone re-runs it byte for byte |
| **receipt** `README.md` (also `notbefore receipt`) | one page in words: status, who, what, when, the randomness, the result, how to check | the human summary — but generated by re-verifying, never by copying |
| **bundle** directory or `.zip` | contract + sidecars, transcript, the pulse pair and its predecessor with tokens, checkpoint + inclusion proofs + witness cosignatures, Rekor anchor records, the decision-log leaf/proof/checkpoint, the release's public keys, README, `MANIFEST.json` | a self-contained file set a stranger checks **offline** with `notbefore check-bundle` |

## What a reviewer or auditor does

1. `pip install notbefore` and `notbefore check-bundle <bundle>`. Offline. The verdict is VERIFIED (exit 0), DEGRADED
   (exit 2: a dry run, or the input was not included so the result was not re-executed) or INVALID (exit 1). It re-verifies the manifest, the contract's
   canonical hash, the signer's statement, both RFC 3161 tokens (against roots pinned in *their* installation, not the
   bundle's copy), the decision-log receipt (signed checkpoint + Merkle inclusion under the vendored log key), the
   transcript's binding, the pulse pair's host signatures, chain links and drand BLS signature, the commit's tokens,
   the pulse-log checkpoint signature and inclusion proofs, the witness cosignatures, and the Rekor anchor records.
2. `notbefore verify <seq>` — the same pair against the live log, drand and Rekor, so a bundle cannot describe a
   pulse the world never saw.
3. `notbefore execute <contract> --input <the file with the committed SHA-256>` — the same output, or a refusal.
   `execute` fails closed: no confirmed decision-log registration, no output. A transcript that says `DEGRADED` was
   produced with `--allow-unregistered` and should be treated as a dry run, not a preregistered result.
4. Read the receipt's decision id and key id against the registry / protocol / audit order they hold.

## What this does and does not establish

Established, independently checkable: who committed (signature), what (contract hash), when (two TSAs, and the log's
receipt time fixed by anchored checkpoints), that it was the authoritative preregistration (first entry in a write-once
namespace), that the value was not yet knowable (a future drand round; the beacon's own entropy committed before it),
how the result was computed (deterministic derivation, transcript), and that none of it was silently rewritten
(checkpoints, witnesses, repository mirror, Rekor). Also established since 0.13.0 (timing profile): that the hosts' signed clock measurements for the selected commit met
the declared limits over their stated windows — reported separately from the cryptography, required only if you say so.

Also established since 0.11.0 (commit-bound contracts): that the beacon operator could not have steered the value —
it is fixed by the commit and the drand round, a withheld reveal changes nothing (the hour is labelled
COMMITMENT-FALLBACK and carries no QRNG provenance), and a commit only counts if it was Rekor-anchored before its
round. Not established: that two decision ids or two keys are not the same experiment — that is what the
registry-bound `decision_id` convention is for — nor that the operator cannot stall (it can, blindly and visibly).
Claims discipline: `CLAIMS.md`.

*Spec: `NOTBEFORE.md` (0.6, §7.11–7.12). Log: `DECISION-LOG.md`. Details and every command: `USAGE.md`.*
