Most people never need this page. ZDDC is designed so that a party can take part using nothing but a file browser and the naming convention — that is the whole point of encoding a deliverable's identity in its filename. If you are adopting ZDDC on a project, the Technical Reference is the document you want.
This page is for someone building software that reads or writes ZDDC archives.
The tools are a reference implementation
zddc-server and the single-file HTML tools are a ZDDC implementation. They are not the definition of ZDDC. The on-disk conventions are the contract: the naming convention, the folder layout, the signature envelopes. Anything that follows those conventions interoperates, whoever wrote it and in whatever language.
That is a deliberate constraint rather than an accident of how the project grew. An archive is supposed to outlive the software that made it — a record you cannot read in twenty years without a specific vendor's program is not a record, it is a hostage. Keeping the conventions independently specified is what makes the tools optional.
Three things are versioned, separately
One version number cannot say whether a naming rule changed or a button moved. So there are three lines, and they move independently:
| Layer | What it covers | What a change means |
|---|---|---|
| Core | Filenames and folder names — the Technical Reference, §2–§8 | A migration. Core is baked into files already sitting on disk, so changing it makes existing archives retroactively wrong. |
| Extensions | Optional on-disk formats layered on Core — custody signatures, project workflow, history, configuration, registers | Only affects implementations that chose to support that extension. |
| Software | zddc-server and the HTML tools |
Nothing about the convention. An implementation states which Core and extension versions it implements. |
Within Core, the split runs one level deeper. The grammar — the shape of a filename — is the frozen part. The code tables (disciplines, types, statuses) are registries: separately versioned vocabulary that a project adds to where it has a gap, under the harmonization rule in Core §1. Adding a status code for your project does not fork the convention, and a new code in the base registry does not change the grammar.
What a version number means
Specifications carry two numbers, MAJOR.MINOR. The software carries three (vX.Y.Z), because software has bug-fix releases and a specification does not: a published specification version is never edited, and corrections to it are recorded as errata rather than as a new patch version.
- Minor (1.0 → 1.1) — additive only. Everything valid under 1.0 is still valid and means the same thing, and an implementation of 1.0 still reads everything a 1.1 implementation writes. For Core this should be rare: new status, discipline or type codes go into the registries, which are versioned on their own, not into Core.
- Major (1.x → 2.0) — something that was valid becomes invalid, or changes meaning. For Core that means files already on disk would need renaming, so a major version of Core is a migration and is treated as one.
A version written with ZDDC's own draft prefix — ~1.0 — is a draft of that version, exactly as ~A is a draft of revision A (Core §5): the version it will become is fixed, but its text and vectors may still change without notice. Finalising drops the ~. From then on 1.0 is stable: the text and vectors are frozen under the rules above, and corrections are errata. A draft is published at the address its final version will have, so a link saved today still works after it is finalised.
The specification set
| Document | Version | Status | Covers |
|---|---|---|---|
| Core | ~1.0 | Draft | Filename grammar, tracking numbers, revisions, draft prefix, modifiers, status registry, folder names |
| Custody Extension | ~1.0 | Draft | Signed manifests, DSSE envelopes, key files, the ledger — verifying who issued a record, decades later |
| Workflow Extension | ~0.1 | Draft | Project layout, the staging/-to-archive/ commit, the transmittal workflow |
Other on-disk formats the reference implementation defines — history storage, the .zddc configuration cascade, register and form definitions — are documented in the source repository but are not published specifications yet. They are not listed above because an unfinished specification is worse than an honest absence: it invites someone to build against something that is still moving.
Conformance is a test suite, not a claim
Each published specification ships conformance vectors: language-neutral JSON cases with an input, a required result, and a citation back to the prose rule they pin. They are the executable half of the specification.
Prose alone is not enough, and we have the evidence in-house. ZDDC's Go and browser custody implementations were written independently from the same written specification, by the same team, and still diverged in twelve places before vectors closed them. A stranger reading the same prose will do no better.
Vectors alone are not enough either. A vector says what, never why; anything it does not cover is undefined, and an implementation can pass by coincidence without understanding intent. That is what each vector's description field is for. The two halves are load-bearing together.
If an implementation passes the vectors, it interoperates. That is the entire conformance claim, and it is deliberately the only one. There is no certification, no registry of approved implementations, and nothing to sign.
Conformance levels
A specification may define levels, so an implementation can support part of it honestly rather than claiming all of it.
Core declares two — reader and writer. A reader parses names and orders revisions, and tolerates a status that breaks the grammar so the file can still be found and repaired; a writer composes names and refuses to produce one that breaks it. Every Core vector names the level it tests.
The Custody Extension declares four; they compose, and nothing requires all of them:
- V — Verifier. Checks signatures and returns a verdict with its as-of date.
- P — Producer. Emits canonical payloads, manifests and key files.
- H — Hasher. The chunked Merkle construction and inclusion proofs alone — the minimum a mirror or an indexer needs.
- L — Ledger. Monotonic acceptance at the door, and currency derivation.
Two composition rules come with them, and they are worth reading as a model for what a real conformance section does: a verifier may not ship without a hasher, because verifying a manifest you cannot recompute is not verification; and a producer must be a verifier of its own output, because the cheapest way to emit a broken payload is to never read one back.
Writing your own implementation
The short version: download the vectors, run them offline, pass every valid case and reject every invalid one.
For the Custody Extension, everything is in one archive — the specification sources, the vectors and the vendored Ed25519 corpora: zddc-custody-1.0.tar.gz (SHA-256). The runner contract is its conformance document.
Vectors are designed to be runnable with no clock, no network and no source of randomness, so a conformance run is reproducible and can be part of your own test suite rather than a one-time exercise. Load each JSON file, dispatch on its kind, compare against expect.
Mutation-check your runner before you trust it. A suite that has never failed is not evidence that it checks anything. Corrupt each vector's expectation in a copy of the tree and confirm your runner fails on every one. This is not hypothetical advice — doing exactly this caught a path bug in ours that was silently rewriting the vectors in place instead of the copies, which would have made a broken runner look green.
What not to do
Extensions are additive. If something you need can be expressed as a new extension, or as codes added to a registry where a gap exists, that is the supported path and it requires nobody's permission.
Some limits are permanent rather than deferred, and a proposal that requires breaking one is a redesign of the system rather than an extension of it. That is allowed — but it should say so plainly instead of arriving as a small compatible-looking change. The bar is not that the idea is wrong; it is that a change to the contract has to be visible as one.
And if your implementation disagrees with a vector, the vector may be the thing that is wrong. Two of ours turned out to be unsatisfiable and were repaired during the cross-implementation pass. Report it rather than working around it locally — a private workaround is how two implementations quietly stop interoperating.
Specification defects, vector disputes and extension proposals all go to the issue tracker: codeberg.org/VARASYS/ZDDC.
Errata
A finalised specification version (one without the ~) is immutable. Corrections are recorded here and in the specification's own errata list; they never rewrite a published version in place, because someone has already built against those exact bytes.
No errata recorded.