All notable public changes to charter_agreement_protocol are documented here.
[0.3.2] — 2026-09-16
Toolchain-and-hygiene release; no wire-visible or behavioral library change
(lib/ is byte-identical to 0.3.1).
Fixed
- Both shipped notebooks (charter tour, fork repair) minted their
Ed25519-signed artifacts with
protocol_revision => 1; the registry admits the Ed25519 key grammar from revision 2, sodescriptor_signing_inputfail-closed withsigning_input_invalid— both notebooks were broken at execution time, not merely stale to read. All nine claims sites now declare revision 2 and both notebooks' full cell sequences execute green end to end from their own directory.
Changed
- The declared Elixir floor drops to
~> 1.19(tested lines 1.19.x and 1.20.x), matchingcharter_agreement_signer; anything below 1.19.0 is refused by Mix withMix.ElixirVersionErrorbefore anything compiles. The supported-OTP set is declared as {28, 29} and enforced in-repo:config/config.exsrefuses a foreign OTP major before compilation. The set is decided by substrate probe — stable precompiled 1.20.x builds also exist for OTP 27, but on OTP 27.3.4.17 with OpenSSL 3.5.5 confirmed linked,:crypto.supports(:public_keys)exposes none of:mldsa44/65/87, so the revision-3 corpus fail-closes on 27. The range, the set,.tool-versions, and the CI matrix lanes move together in one commit; docs/adr/supported-otp-set.md records the probes, the proof legs, and the floor lane green end to end on Elixir 1.19.5 / OTP 28.5.0.3. - CI's floor lane mirrors the signer sibling's (Elixir 1.19.5 /
OTP 28.5.0.3 on ubuntu-26.04). dialyxir moves to 1.4.8 and ex_doc to
0.40.4; the charter-family
==pins carry inline exact-identity reasons. - Dependency currency becomes latest-first and gated
(docs/adr/dependency-currency-gate.md):
mix currency.checkruns inside the quality battery and as its own CI step. The gate fails on any resolvable drift, prints every resolver-rejected pin with its requirement chain, classifies on the rendered table with whitespace-anchored matches, and exits nonzero unverified when the hex.pm lookup renders no table.
Added
- The Windows clone-and-build bar.
.gitattributesnormalizes line endings and marks the byte-exact conformance corpus and test fixtures binary socore.autocrlfcannot corrupt a Windows checkout; CI gains a windows-build lane proving checkout, dependency fetch, test-environment compile with warnings-as-errors, format, and the currency gate on the official OTP 29 Windows builds, plus an informational runtime crypto-capability report. No declared gate depends on a POSIX shell — the currency gate is an Elixir script that spawnsmixthroughcmd /con Windows. The full test suite on Windows is not yet claimed; the gated extension is recorded in the supported-toolchain ADR.
[0.3.1] — 2026-09-15
Docs-and-tooling correction release; no wire-visible or library-code change
(lib/ is byte-identical to 0.3.0).
Fixed
- The runtime floor's second axis. The 0.3.0 floor statement named
OTP ≥ 28.1 but omitted the linked crypto library. ML-DSA (FIPS 204)
reached OpenSSL in 3.5.0, and OTP's
:cryptoexposes ML-DSA key generation and verification only when the runtime's libcrypto is ≥ 3.5. The declared floor is therefore OTP ≥ 28.1 with a linked OpenSSL ≥ 3.5. - CI ran the quality gate on ubuntu-24.04, whose OpenSSL 3.0.x cannot
generate or verify ML-DSA keys: 7 of 268 tests failed with the OpenSSL
Bad key typeerror and the corpus's valid ML-DSA verdicts fail-closed assignature_invalid, while the same tree passed every local gate on a runtime linked against OpenSSL 3.6. bob's OTP builds dynamically link the distrolibcrypto.so.3and bundle nothing, so the distro library was the only variable. The quality gate now runs on ubuntu-26.04 (OpenSSL 3.5.x) with the pinned and floor matrix legs unchanged. On the floor leg (OTP 28.1 / crypto 5.7) the two ML-DSA test sign calls now pass the documentedmldsa_privatetuple form ({:expandedkey, binary}) — crypto 5.7 rejects the raw binary that later cryptos accept; verification itself needs no accommodation (the corpus agrees 100/100 at the floor). - The release-candidate gate now pins the package CONTENT identity (the
SHA-256 over the unpacked archive's sorted path+bytes, excluding
hex_metadata.config) instead of the tarball bytes:mix hex.build's gzip layer is reproducible within one OS but not across OSes, and the generated metadata embeds its file list in filesystem enumeration order — so the 0.3.0 byte pin, recorded locally and never before exercised in CI, could not match a Linux CI rebuild of identical content. The gate still requires byte reproducibility between its two in-run builds and still verifies the unpacked boundary and metadata; the content pin hashes only git-tracked bytes and passes identically on every platform.record_release_metadatarecords the same identity. - Documentation re-trued to the revision-3 surface (the corpus, guides,
notebooks, and reference tables had drifted): the certified identities in
Conformance and Test vectors now carry the live 0.3.0-recertified values;
the security model's primitives section admits ML-DSA (it still said
"Ed25519 only"); signature-length and key-history prose states the
registry-row rule instead of a universal 64-byte/Ed25519 claim;
protocol_revisiontables accept 1–3; the error-code reference carries the live per-code corpus counts; the corpus quick-start commands propagate the CLI exit status throughSystem.halt/1and no longer claim the repository-onlymix conformance.verifyalias works from an unpacked package; install examples carry~> 0.3.0; the npm family paragraph notes the published companion signer package; the Node verifier floor reads ≥ 24.8; the limits table gains the byte-weighted artifact-set ceiling; the party-descriptor and receipt signature MUST-clauses inspec/core.mdstate the registry row's key algorithm (completing the revision-3 ADR's recorded consequence, with the specification digest re-recorded); the release-candidate gate now pins the docs' certified-identity tables to the live values so a truncated transcription cannot ship; and the release runbook describes the content-identity pin.
[0.3.0] — 2026-09-14
The standards-release: protocol_revision 3 (the ML-DSA registry act) plus
the audit hardening batch.
Protocol (wire-visible, revision-gated)
- ML-DSA admission (RFC 9964; ADR
ml-dsa-admission.md): the registry gainsML-DSA-44,ML-DSA-65, andML-DSA-87atprotocol_revision3, each with its exact public-key and signature byte lengths as registry data. Verification dispatches per registry row on both implementations; the descriptor key grammar admits ML-DSA keys gated on descriptor revision (an ML-DSA key in a revision-1/2 descriptor rejects), and mixed-algorithm key sets are legal with the Ed25519→ML-DSA bridge exercised by the corpus. Producers mint exactly (Ed25519, revision 2) or (ML-DSA-65, revision 3) via the optional"algorithm"input member. - Verdict audit: red→green — (ML-DSA names, revision 3), (EdDSA, revision 3), (Ed25519, revision 3), mixed-revision ML-DSA views. Nothing green→red on the wire. Unknown revisions still fail closed (revision 4 carries the fail-closed corpus probe).
Resource boundary (not wire-visible; recorded policy)
Limitsgainsmax_artifact_set_bytes(default 64 MiB, compiled maximum 1 GiB); set verification bounds items, bytes, proper-list shape, and binaries in one pre-decode traversal — improper lists return typed errors.Chain.verifypasses its own verified facts to the acceptance and termination seams, removing the O(A×D) per-artifact re-verification; governing computation memoizes ancestry per view.- The JSON decoder rejects integer lexemes over 21 digits and float lexemes over 32 bytes before conversion (linear-time rejection; no accepted value changes — oversized spellings could never round-trip).
- Timestamp-valued members carry 1..64 string-byte schema constraints.
Second verifier parity
- The TypeScript verifier now mirrors the reference implementation: strict
I-JSON strings (noncharacters, lone surrogates), lexeme-faithful float
tagging, bounded JWS decode, strict Ed25519 pre-checks, exact timestamps
(real calendar, the June/December leap-second slot, untruncated
fractions), the full chain battery (predecessor linkage, one genesis,
supersession shape, unique acceptance coordinates, role-pair dual
acceptance, terminations,
effective_until, ancestry-coverage governing), the closed receipt decision/outcome matrix, the ML-DSA registry, and the compiled limit maximums.
Conformance and certification
- Certified corpus regenerated and recertified at 100 cases: the frozen ML-DSA population (descriptor positives and per-name negatives, the PQ key bridge, the mixed-revision view, ML-DSA acceptance and receipt), revision-4 fail-closed, and the (EdDSA, 3) compatibility flip. All four certified identities and the archive digest re-recorded; the named mutation battery grows to 25.
Runtime floors
- OTP ≥ 28.1 (the corpus contains ML-DSA cases and report byte-identity
forbids runtime-conditional verification;
:cryptoML-DSA landed in OTP 28.1). The Node verifier floor rises to 24.8 (ML-DSA in the builtins landed across 24.6–24.8). CI now tests the floor toolchain alongside the pinned current one.
[0.2.1] — 2026-08-26
Documentation-only release: the docs now point hosts at the reviewed
companion signer — charter_agreement_signer
(atomic kid/key snapshot, wrong-key guard, post-sign verify, refusal
surfacing) — from four surfaces (README key-custody, protocol.md
host-obligations, getting-started's new companion section, the charter-tour
notebook's sign-helper cell). Hosts may always hand-roll per the spec;
verifiers never depend on the companion. No protocol, corpus, or identity
changes.
[0.2.0] — 2026-08-26
protocol_revision 2: the RFC 9864 alg-name bundle.
Protocol (wire-visible, revision-gated)
- The per-artifact binding rule:
alg: "EdDSA"is accepted at any accepted revision;alg: "Ed25519"requiresprotocol_revision >= 2; unknown revisions fail closed.(Ed25519, revision 1)is rejected — no honest producer could have minted it. - New minting is exactly (
Ed25519,protocol_revision2), enforced by construction (the framing-layer binding check runs on the producer's provisional decode). - Cross-revision composition: artifacts from revisions 1 and 2 mix freely
in one verified view — a revision-2 acceptance anchors a revision-1
charter. Decoded artifacts carry their actual
protocol_revision(structs no longer pin 1).
Verifiers
- Both implementations enforce the binding rule at the framing layer; the TypeScript reference verifier additionally gained the revision-range check it previously lacked, and its acceptance-revision equality was replaced by the accepted-set semantics the mixed views require.
Conformance
- Certified corpus regenerated and recertified (90 cases): the
revision-2/
Ed25519population, the revision-2/EdDSAcompatibility case, the(revision 1, Ed25519)per-name negative, the revision-3 fail-closed case, and the mixed-revision acceptance view. Legacy fixtures pin revision 1 +EdDSAliterally, on purpose. All four certified identities re-recorded; the requirements matrix growsCAP-REVISION-fail-closedandCAP-ALG-registry-bindingwith thealg-binding-defeatsource mutation.
[0.1.0] — 2026-08-26
Everything below is the 0.1.0 candidate content, frozen for the publication decision; the archive at this commit is the reviewed candidate.
Conformance
- The certified corpus closes its error-code coverage gap: 28 new cases across every surface lift corpus-exercised codes from 19 to 45 of the closed 57 (two codes gain cases on a second surface); the remaining twelve are structurally outside case certification (corpus loader, producer seams, typed query arguments, and the explicit schema-view seam), stated with reasons in the error-code reference. The requirements matrix grows to 45 bound requirements over 61 applicability cells and 85 certified cases; the independent TypeScript verifier implements every newly certified failure path, and all four certified identities are re-recorded.
Documentation
- A complete documentation corpus for integrators and evaluators: ten guides (overview, getting started, artifacts, verification semantics, receipts, extensions, security model, recipes, conformance, FAQ), two runnable Livebook notebooks (charter tour and fork repair, executed against the live package), a rewritten landing README, and a contributor guide stating the change bar and invariants.
- The package archive now ships the guides and notebooks alongside the normative protocol specification; the API reference is grouped by surface (artifacts, facts, verification, primitives, extensions, conformance).
Added
- Foundational byte-contract modules for strict unpadded base64url, deterministic tagged JSON, RFC 8785 canonicalization with exact-byte verification, domain-separated tagged SHA-256 digests with all-byte comparison, and a closed typed error vocabulary.
- Caller-supplied bounded JSON decode limits; a table-driven closed-schema engine with fixed seven-stage failure precedence; and a pure conformance corpus loader enforcing self-digest, file/hash/count/ID integrity, compiled applicability, and non-vacuous expectations.
- A shipped foundational corpus plus a Node 24-or-newer, builtins-only integrity harness that independently rejects corrupted corpus bytes and stays outside the package archive.
- Strict UTC RFC 3339 timestamps and canonical attached compact-JWS parsing for the Party Descriptor boundary, including exact protected-header and Ed25519 signature checks.
- Closed Party Descriptor decoding and verification with self-signed genesis, predecessor-active-key transitions, reverified lineage, linear supersession, signed sibling-fork facts, and no winner selection.
- Elixir and Node corpus coverage for valid descriptors, superseded descriptors, and signed sibling forks, with exact applicability-floor enforcement.
- Closed unsigned Charter Revision decoding with raw-byte legal-text digests, mandatory precedence, bounded temporal and termination declarations, exact ABP 0.1.1 deployment identities, and executable cross-language corpus cells.
- Attached Acceptance verification with exact revision/party claim equality, reverified descriptor key context, view-relative signer position, and same-signer equivocation evidence that never selects a branch.
- Attached Termination Notice verification with exact revision/party binding, listed-reason enforcement, pure issue/effective ordering, active descriptor key verification, and no clock or governance-effect decision.
- Pure set-level chain verification and caller-time governing computation with bilateral acceptance, exact revision ancestry, start-inclusive effective windows, retained fork evidence, explicit supersession repair, termination closure without fallback, and no digest tie-break.
- One redacted facts-construction boundary that forces the twelve-item
not_verifiedfloor across descriptor, revision, acceptance, termination, fork, and chain facts, plus executable Elixir and Node corpus cells for chain forks, supersession, and temporal precedence. - Attached Receipt verification with exact revision-number/digest and ABP deployment cross-checks, BAP grant-hash byte identity, total decision/outcome states including indeterminate effects, issuing-party Ed25519 verification under full chain context, view-relative fork/governance facts, redacted ReceiptFacts, and five executable corpus cases.
- Exact development/test-only, runtime-disabled ABP 0.1.1 and BAP 0.1.2 Hex dependencies with package checksums and frozen/live byte-identity gates; the CAP production application remains OTP-crypto-only.
- Deterministic Party Descriptor, Acceptance, Termination, and Receipt signing inputs plus external-signature-only compact assembly. The set-aware seam refuses false coordinates and equivocation, requires Acceptance ancestry to cover maximum accepted heads while preserving bilateral supersession repair, and requires a Termination to name the unique governing revision at its own effective time; source and BEAM gates prohibit signing custody.
- Architecture gates that reject implementation-version tokens everywhere
except the exact Hex package source reference, reject runtime dependency
drift away from OTP
:crypto, and keep declared error codes synchronized with production emission sites. - Architecture gates that force every facts record through the shared twelve-item omission floor; reject authorization and term-evaluation vocabulary; prohibit production filesystem, clock, calendar, shell/OS escape, and dynamic-dispatch calls; require public specifications and non-authorizing module stances; and census CAP, ABP, and BAP separators and protected types for completeness and disjointness.
- A compiled seven-field extension registry with RFC 2606 example-class identities, exact critical/optional envelope validation, schema-digest-bound critical bodies, fail-closed critical lifecycle handling, and verbatim unknown-optional quarantine with names-only facts.
- The indexed-price profile family: closed ISO 4217 revision terms under
com.example/pricing-indexed, optional receipt observation evidence undercom.example/pricing-indexed-observation, authoritative evaluation-semantics documentation, and executable valid/invalid/quarantine corpus cells. - Reserved, schema-free vLEI and eIDAS QEAA attestation profile names. CAP interprets no attestation bytes until a normative authority defines and a later protocol revision adopts a closed schema.
- A pure conformance runner, canonical identity-bound report, explicit-corpus CLI/escript, and compiled requirement map linking every stable public requirement to corpus, architecture-gate, and mutation evidence.
- A 57-case obligation-complete corpus whose index binds the compiled extension registry and carries both a domain-separated self-digest and a separately certified exact-byte SHA-256 pin.
- An independent Node 24-or-newer TypeScript verifier using only built-ins. It recomputes every certified signature, artifact and set fact, governing view, receipt projection, and foundational codec verdict; its canonical report is byte-identical to Elixir over repository and unpacked-package corpora.
- The complete 22-break mutation battery, with baseline-green calibration and the corpus-expectation flip last, plus directional second-verifier reds.
- Release metadata, errata policy, conformance/release ADR, NIST CAVP SHA-256 known-answer checks, exact package allowlist verification, reproducible archive comparison, and a mechanical no-publication-authority receipt.
- A separate runnable supplier fork-evidence demo using real signed artifacts. It reports same-signer equivocation, a contested governing view, Receipt cross-check facts, and a countersigned bilateral supersession repair without adjudicating or authorizing.
- Package scaffold: mix project with the complete
mix qualitybattery (dependency audits, format check, warnings-as-errors compile,credo --strict, 100% coverage census, conformance, mutations, independent verifier agreement, dialyzer, warnings-as-errors docs, and release candidate), pinned GitHub CI with a full-history gitleaks secret scan, weekly dependabot updates for mix and GitHub Actions, and the Apache-2.0 licensing set (LICENSE, NOTICE, SECURITY.md).
Fixed
- Enumerate hidden corpus entries, reject non-regular paths, and enforce corpus byte ceilings before file reads in every filesystem verifier.
- Align the independent verifier's Receipt projection, issuer-key selection, JSON structural limits, and compiled extension-registry identity with the certified Elixir boundary.
- Require every mutation's exact scratch environment to pass before a failing mutated command can receive credit.
- Reject noncanonical Ed25519 points, all eight low-order torsion encodings for
public keys and signature
Rvalues, and out-of-range signature scalars before runtime verification; this closes the identity-key universal forgery accepted by the raw OTP primitive. - Preserve typed artifact-set verification failures at the signing seam, accept JSON float values that the canonicalization and extension boundaries support, and make the signing-custody BEAM gate observable under cover compilation.
- Reject I-JSON noncharacters symmetrically during JSON decoding and constructed canonicalization, and close alternate error-construction paths that could bypass the declared-code and value-free-detail architecture gates.
- Bound complete artifact-set inputs and verify descriptor chains with one signature check per artifact instead of repeatedly replaying each predecessor lineage.
- Preserve
invalid_limitsacross every descriptor and chain entry point, order accepted leap-second instants before the following midnight, reject unknown critical descriptor extensions until the registry is available, and keep long-chain test fixtures on valid timestamps. - Require wrong-signature and disconnected-chain rejection cells in both corpus integrity implementations.
- Return typed revision errors for malformed supersession members and reject supersession targets on genesis revisions.