The editor had written the escapes of the sources as their characters:
the cases "round escaped as round" and "round twice, once escaped as
round" of release.json had a plain round, and the surrogate pair of
"a surrogate pair in a value" a plain emoji, so the shared vectors tested
no escaped name. TestStrictJSON had lost its escaped é, its pair and the
escape after a lone high surrogate. They are escapes again, and the texts
of words_test.go too, so that no mark or invisible character hides in the
source. release.json gained 26 cases of drand's JSON, not 25 as b570338
says; the draft and the CHANGELOG now say 26.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
SpecVersion is 0.16, and so is the spec field of every file of testdata,
the frozen security_cms.json and locator.json included. annex/recovery.md
is §79 of the draft v0.16, with the key of words in 79.7. The draft lists
the two new fixtures in 67, says in 79 what recovery_check.sh opens, and
names in 76 the tests that now exist. The CHANGELOG has its section.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
JSON of RFC 8259 in UTF-8 whose value is an object; no object repeats a
name, and names are compared exactly once their escapes are decoded, so
"round" is round and ROUND another name; an escape of a lone surrogate
is malformed; round is a number without sign, fraction or exponent from 1
to 2^53 - 1; signature and randomness are strings (spec v0.16, 47.1). Go's
encoding/json kept the last of two repeated names and matched ROUND to
round. ParseDrandJSON, exported, is the one reader of drand's JSON:
provider/drand reads the answers of the relays with it too. The error
texts do not change.
release.json gains 25 cases of drand's JSON for v0.16.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The author approved the draft v0.15 on 7 October 2026, after removing the
.dkr file from it: the long-term recovery of capsules rests on the release
object, archives and cache services of all rounds, a release in hand that
the clock does not stop, and the recovery annex. Only the date of the
header changes here. SpecVersion is 0.15, the records of the fixtures and
the vectors say so, and the frozen security_cms.json and locator.json
change only their spec field. spec/README.md records the SHA-256.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The author's decision of 7 October 2026. A release saved next to a capsule
cannot exist when the capsule is made, and once the date comes the capsule
can be opened: such a file only opens it again and does not cover the real
case, someone opening it decades later when drand is gone and nobody saved
anything. Long-term recovery rests instead on archives and cache services
that keep the releases of all rounds; a reader asks for its round and
verifies the signature against the pinned key.
Spec: the .dkr extension (section 20, back to v0.14), sections 1, 4, 8, 45,
47.1, 49, 50 (rewritten), 53, 62.1 (rule 28 removed, rule 26 reworded),
63, 70, 73, 74 (the datekeys.release .dkk extension dropped too), 76
(the v0.15 block, with the discarded design) and the annex 79. The
release object, the chain hash at step 10, step 9.c option B and the
archive format stay.
Code: decrypt -save-release and the command datekeys release are gone,
with writeRelease and their tests; decrypt -release FILE stays. The
release objects of testdata/releases are now <round>.cbor, and
TestVectorFilesAreCurrent fails on a file the generator no longer writes.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The release of a round becomes a file, .dkr: a release object in
deterministic CBOR, {0: "datekeys-release", 1: 1, 2: chain_hash, 3: round,
4: signature}, which provider.EncodeRelease writes and DecodeRelease reads
with its layers (size, type and version, schema). provider.ParseRelease
also reads drand's JSON as the input of the caller. Verify checks the chain
hash a release names before its round and its signature, with
ERR_PROFILE_MISMATCH. provider.Archive reads a local release archive, the
informative format of the draft.
capsule.OpenOptions.Release takes a release in hand, a provider.Supplier,
exclusive with Source: Open does not compare it with the clock (step 9.c,
option B) and reports a clock behind it in Opened.ClockBehind; a network
source is still never asked before the round time. The CLI gains
decrypt -release FILE (.dkr, drand's JSON or a local archive),
decrypt -save-release FILE.dkr and the command release, which fetches,
verifies and saves the .dkr without opening the capsule.
Test data: vectors/release.json, releases/<round>.dkr for rounds 1000,
1001, 1004 and 2000, and a local archive of rounds 1000 to 1004. In
mutations.json every case says its source, "supplied" or "network"; the
case "round not reached yet", a release in hand, now opens, and four cases
are added: the same with a network source, a release of another round from
a network source, and two release objects of another chain. SpecVersion
stays 0.14 until the author approves the draft.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>