# 0004 — One author plays every role, until the prototype is deployable **Status:** Accepted, with an expiry **Supersedes nothing. Constrains:** every claim this repository makes about having been tested adversarially. ## Decision For the prototype, **one author writes the design, the implementation, both independent implementations, and every adversary that attacks them**. This is accepted deliberately rather than tolerated quietly, and the acceptance ends at a named point: independent parties must hold the adversary and second-implementer roles **before any deployment under licence**. Every document that reports a result obtained under this arrangement says so at the point of the claim, not in a footnote. ## What prompted this Two limitations were recorded honestly as they were found, and they are the same limitation: - Phase 1's exit criterion asks for *two independent implementations*. `verifier/` is a Rust implementation sharing no code with the Python, and it reproduces every pinned digest — but both were written by the same author, so their agreement is weaker evidence than two genuinely separate parties would give. - Phase 2's exit criterion asks for *adversarial operation*. `scripts/adversarial_run.py` delivers it against five publishers whose behaviour is known in advance — but the adversaries are ones we thought of, and the gap between *"no adversary we imagined succeeds"* and *"no adversary succeeds"* is the entire point of the criterion. The honest reading is that the project had reached the limit of what a single party can establish about itself, and the next step was a counterparty rather than another module. The countervailing fact is that there is nothing yet for a counterparty to attach to: no service to run, no endpoint to query, no deployment to stand up beside. A second implementer needs something to implement against; a witness needs a log to witness. So the order is: build the deployable thing first, with the author playing every role, and bring in the parties the criteria actually require once there is something for them to join. ## The reasoning **A self-written adversary still finds real defects, and it finds them cheaply.** The in-process run already produced results the design did not have before it: that bonding has to be checked on acceptance rather than after a dispute, that a groundless challenge has to cost the challenger, and that unreachable and refusing are indistinguishable from outside. None of those needed an independent party to surface. Declining to test at all until a counterparty appears would have cost all of it. **What a self-written adversary cannot do is bound the unimagined.** It tests the failure modes the author modelled, using the author's model of the system. Where the design is wrong in a way the author cannot see, the adversary inherits the blind spot exactly. This is not a quantity of effort that can be increased into independence — it is a structural limit, and no amount of additional self-attack removes it. **Which is why the acceptance carries an expiry rather than a caveat.** A caveat is something a later reader skips. An expiry is a condition that has to be met before a specific thing happens, and the thing named here — deployment under licence — is the point at which somebody outside this repository begins relying on these claims. **Moving from in-process to over-the-wire is a real strengthening even under one author.** An adversary that is a hostile *service* can do things an in-process fake cannot: serve one history to one reader and a different one to another, present a receipt from a log nobody asked about, or answer some requests and not others. Those are the attacks the design's central claims are about, and they were previously unreachable. The independence gap stays open; the *coverage* gap narrows. ## What was rejected **Waiting for a counterparty before building further.** Rejected. There is nothing to hand one. The cheapest useful counterparty role — a second implementer working from the specification — needs a running deployment to check its output against, and the witness and monitor roles need a log to follow. **Dropping the independence requirement.** Rejected, and it is worth being explicit because it is the tempting one. Determinism verified by its author is the same trust model the project exists to replace: *trust the publisher*. The requirement is not a formality that a sufficiently careful single author can discharge. **Claiming the exit criteria as met.** Rejected. Phase 1's first half and Phase 2's criterion are both recorded in roadmap.md as met *with the author caveat stated in place*, and this record is what those statements point at. A criterion recorded as met when it was met by one party is a criterion that quietly changed its meaning. **Generating adversaries by some automated search and calling that independence.** Rejected for the prototype. Fuzzing the wire format and the proof verifiers is genuinely worth doing and would broaden coverage — but a search harness written by the same author, over an input space that author defined, is a bigger version of the same blind spot, not an escape from it. It belongs on the work list as coverage, never as independence. ## What this costs us **Every adversarial result in this repository carries an asterisk**, including the ones that look strongest. "A split view was detected" means a split view *of the kind we constructed* was detected by a detector we wrote. **A defect in the shared mental model is invisible to all of it.** If the canonical encoding has a flaw the author does not see, the Python has it, the Rust has it, the vectors pin it, and the adversary does not attack it. The conformance suite would agree with itself perfectly. **The strongest evidence available is negative.** What this arrangement can honestly establish is that a specific set of attacks fails and that honest participants are not harmed. It cannot establish that the set is complete. ## What would reverse this — i.e. what discharges it This record is discharged, not reversed, and it takes all three: 1. **An independent implementer** passes `tests/vectors/` working only from [specification.md](../specification.md), with no access to either existing implementation. Any divergence is a specification defect until shown otherwise — the existing implementations do not get to be the reference. 2. **An independent adversary** attacks a running deployment with the authority to publish what it finds, and is not briefed by the author on where to look. 3. **Independent witnesses and monitors** — parties running `witnessd` and `monitord` who are not the log operator and not each other, because [0003](0003-witness-policy-is-the-readers.md) is only meaningful when the reader's named witnesses are parties the operator does not control. Until all three hold, no deployment under licence, and no document in this repository describes a criterion as met without saying by whom. **Progress on the third, and precisely what it is worth.** The *cost* of running an outside witness has been taken down as far as this repository can take it: [witness-quickstart.md](../witness-quickstart.md) is a guide for somebody who has never seen the project, `scripts/witness_key.py` generates a real secret the deployment can never derive, a deployment description can name a witness it does not run and does not key (`external_witnesses`), and `scripts/check_witness.py` tests a candidate witness by trying to make it fail — a rubber stamp, a credulous notary, and an amnesiac are each caught, asserted in `tests/test_witness_conformance.py`. witness-outreach.md covers the remaining half — who to ask and how to frame it — because the obstacle is now social rather than technical. None of that discharges anything. **No party outside this project runs a witness**, and the criterion above is a fact about parties, not about tooling. What changed is that the answer to "why has nobody done it" can no longer be "because it was too much work to find out how" — which was worth removing, and is not the same as removing the gap. ## Consequences for the work - The prototype is built to be *joined*, not only to be run: separate processes over HTTP, with a documented wire format, so an outside party can replace any one node with its own implementation and the rest of the deployment does not notice. - The adversary moves from in-process to over-the-wire, because that is the strengthening available without independence. - roadmap.md states the caveat at both exit criteria and links here.