All notable public changes to agent_blueprint_protocol are documented here.
[0.8.0] — 2026-09-24
Added — the release-identity consumer contract
priv/release-metadata.jsonis now a versioned public contract (manifest_version: 2; additive-only within a version). New fields: the manifest version,verification_semantics_version(the semantics/census split — unchanged at 1), thedigest_identitylabel (RFC 8785 JCS + SHA-256 + domain separation + unpadded base64url — unchanged across every release),protocol_revisions_supported, the certified compatibility matrixprior_census_verdicts(the prior censussha-256:sg6Fo7…is certifiedequivalentby replay), and the verifier-kit identity derived frompackage.json. The npm kit embeds the manifest byte-identically (agreement-gated).priv/release-history.json: the append-only retroactive mapping — one row per manifest-era release, every PRIOR release's row verified against derived state (the corpus digest recomputed from the loaded census bytes, the registry digest from the census index, the specification digest recomputed over the tag's tree); the current release's row is asserted against the live manifest and gains its tag verification at the next release. Semantics version 1 spans the whole manifest era through this release: the prior census replays case-perfect (observed under the preceding package on 2026-09-23; this release's gate re-establishes it mechanically on every run), so exact-pinned consumers upgrading between any of these releases keep historical replays green when they bind the semantics identity. The record also shows the specification digest moved at 0.4.0 and 0.4.1 — movement the changelog prose of those releases never stated.mix compatibility.replay(quality battery): certifies the compatibility claims and the history from live repository state — every manifest-era census loads through the new prior-census loader mode and replays under the current Runner (each PRIOR census also through the TS verifier, byte-compared; the current census's TS agreement is the verifier.agreement gate's duty); anequivalentclaim with any disagreement reds, a registry-explained divergence class is gated by the registry diff, an unclaimed census, stale claim, or tampered history row reds, and a tag-less checkout refuses (a named override exists and is never a green claim). Self-proving seeded reds fire every run: four claim flips (including a self-contradictorynot_equivalentclaim), a tampered census file, a tampered history row, and both tag-absent refusal arms. The prior-census loader mode (Corpus.load_prior_census/1, mirrored in the TS verifier's--prior-corpus) suspends exactly the two current-state couplings — the compiled registry digest and the compiled applicability floor — because a released census was certified against the registry and floor of its release; the ordinary loader's couplings are unchanged and correct for conformance runs.- The Evolution clause gains the normative semantics/census law and the
immutability policy (released identities are never edited in place;
corrections are new releases); the upgrading guide gains the
exact-pinned consumer partition — replay identity versus provenance
metadata — and the fail-closed enumeration guidance; the decision
record
docs/adr/release-identity-semantics.mdships with theno-versioning-ruleaxis amendment (precedence: the wire revision, the semantics version, and the release identity are independent axes). Answering an inbound consumer request for input (bounded_authority, 2026-09-23) in full. docs/consumer-evidence.md(repository-level, deliberately NOT shipped): the unverified third-party consumer-rehearsal lane, its first entry reserved for the bounded_authority rehearsal.
The correction the record now states plainly: the 0.6.0 corpus change
was not purely additive at the byte level — the golden vectors' fixture
signature rotated on unchanged covered bytes (content_digest
identical), verdict-neutral and replay-proven, but the 0.6.0 entry's
"grows 94 → 96" prose under-recorded it.
The public-history privacy scan's budget grows with the repository (the scan is O(tracked files × commits)); its ceiling moves 960s → 1920s on the same evidence as every prior raise — a borderline clip on this release's tree, a timeout there being a flake, never a privacy finding.
The test suite is 924 tests (59 properties) at 100% coverage. Corpus:
96 cases, digest
sha-256:vMyREM8ggUqVvGG0y2e4Gf-KmpksJjnx2eF8UjtpVP8; registry
sha-256:FG2f38K0hba8tTP7iUaw7vHjgcnN_5F5Mp0v4G6UDVs; specification
digest sha-256:yC0gV-zIn8J8bXI5gV0dQyPmgEQgVsH6k7YOlkis37Q.
[0.7.1] — 2026-09-16
Changed — the toolchain enforces itself (hygiene release)
- The declared Elixir requirement is a supported range (
~> 1.19: the 1.19 and 1.20 lines are admitted, and Mix refuses anything outside the range at compile), andconfig/config.exsrefuses any Erlang/OTP major outside the supported set (27/28/29) before anything compiles. The set was probed from the official precompiled build lists, not assumed; the decision record ships asdocs/adr/supported-otp-set.md. The assert governs development and CI only — the Hex archive does not shipconfig/, so package consumers see no new requirement. - CI exercises every lane of the supported matrix: Elixir 1.19 on
OTP 28, and Elixir 1.20 on OTP 27, 28, and 29 (the dev pin, mirrored
in the new
.tool-versions). The four toolchain declarations — the Elixir range, the supported-OTP set, the dev pin, and the CI lanes — move together in one commit. - A dependency-currency gate (
mix deps.currency; decision record atdocs/adr/dependency-currency-gate.md) reds the battery on any resolvable drift and never passes an unverified registry state. dialyxir rides at its latest resolvable release. - Clones are byte-identical on every platform:
.gitattributesdisables line-ending conversion regardless of a machine's autocrlf settings (Git for Windows defaults to rewriting LF to CRLF, which would shift the byte-frozen digests). The repository tree was probed for Windows checkout obstacles (reserved device names, forbidden characters, case collisions, symlinks, path length): none found. - Development documentation re-trued to the enforced-range story
(README, CONTRIBUTING, quickstart). No Livebooks ship in this
repository (probed — no notebook files and no
Mix.installanywhere), so no notebook cells were in scope. The npm kit version moves with the Hex line under the version-sync gate; no kit behavior changed.
For consumers nothing reachable changed: the library surface, the
conformance corpus, the registry, and the specification are
byte-identical to 0.7.0, and the Elixir floor widened (1.20 to 1.19),
never narrowed. The test suite is 917 tests (59 properties) at 100%
coverage. Corpus: 96 cases, digest
sha-256:vMyREM8ggUqVvGG0y2e4Gf-KmpksJjnx2eF8UjtpVP8; registry
sha-256:FG2f38K0hba8tTP7iUaw7vHjgcnN_5F5Mp0v4G6UDVs; specification
digest sha-256:UkpTfB07D8H8xxtuqDysU-xIXFCKovkaUn7_aiR-tAs.
[0.7.0] — 2026-09-14
Changed — the npm kit moves to @agent-blueprint-protocol/verifier
- Portfolio naming consistency with the bounded-authority kit: the
verifier publishes under a project-named npm organization with a
role-named package. The 0.6.0 package
(
@rjpalermo/agent-blueprint-protocol) is deprecated with a forward pointer. Version numbering continues the protocol's single release line (the version-sync gate binds npm semver == the Hex line). - The bin gains a
verifieralias alongsideagent-blueprint-protocol—npx @agent-blueprint-protocol/verifierandnpx agent-blueprint-protocolboth work after install. - The publish workflow is fully idempotent: registry-published versions skip loudly instead of erroring (re-runs, and releases bootstrapped by a local first publish — required for a brand-new package, since a trusted publisher cannot be configured before the package exists), and the GitHub release step creates only when absent.
- The no-versioning-rule npm-axis amendment records the rename and its history; every shipped mention of the old name is updated (the changelog's historical entries keep it, as records).
The conformance corpus, registry, and test-suite counts are unchanged
from 0.6.0; the specification digest moves with the deferred-work
registry row naming the kit. The test suite is 917 tests (59
properties) at 100% coverage. Corpus: 96 cases, digest
sha-256:vMyREM8ggUqVvGG0y2e4Gf-KmpksJjnx2eF8UjtpVP8; registry
sha-256:FG2f38K0hba8tTP7iUaw7vHjgcnN_5F5Mp0v4G6UDVs; specification
digest sha-256:UkpTfB07D8H8xxtuqDysU-xIXFCKovkaUn7_aiR-tAs.
[0.6.0] — 2026-09-14
Added — the installable verifier (npm kit)
@rjpalermo/agent-blueprint-protocolon npm: the verifier compiled to.js+.d.ts(strict, declarations, zero runtime dependencies, Node >= 24), the conformance corpus embedded byte-identically to the release-certified copy, and a single bin —npxverifies out of the box. The verifier itself typechecks clean for the first time (66 type-level fixes, byte-frozen against the strip-types baseline).--artifact <file>single-artifact mode (kit-only by design; the escript stays corpus-only): verifies one JSON file against all three artifact kinds; a valid report names the kind, a denial names each kind's typed code.- The agreement gate proves the KIT, not just the tree: npm
version-sync with a one-side-bump seed, kit-vs-escript byte equality
over the embedded corpus, and a single-artifact sweep replaying
every text-only decode-surface corpus case with an
inverted-expectation seed.
kit.buildis a quality-alias step; CI builds the kit before the battery. - The TypeScript quickstart (
documentation/typescript.md); the ARD mapping (docs/ard-mapping.md— sources pinned at exact commits, trust-manifest DNA shared, the capability layer instrument-verified absent); the EU AI Act evidence anchor (documentation/evidence-commitments.md); the blueprint-card section in the specification (derived, non-normative, never conforming on its own) with a mirror-tested derivation in the concept guide; the no-versioning-rule npm-axis amendment (the npm semver is the fifth permitted version axis, bound equal to the Hex line). - Two new examples, both byte-exact corpus cases:
examples/signed-blueprint.json(a producer-signed envelope over the golden digest — signing never changes the digest it covers) andexamples/extension-blueprint.json(a registered optional namespace retained by a supporting host, quarantined byte-exactly by one without it).
Changed
- The conformance corpus grows 94 → 96 cases (the two valid signed and extension-bearing decode cases); every shipped count and digest claim re-tied.
- The privacy history-scan budget grows with the repository (480s → 960s; the scan is O(tracked files × commits) and clipped its old ceiling under full-suite load — a timeout there is a flake, never a privacy finding).
The test suite is 917 tests (59 properties) at 100% coverage. The
conformance corpus is 96 cases, digest
sha-256:vMyREM8ggUqVvGG0y2e4Gf-KmpksJjnx2eF8UjtpVP8; registry digest
sha-256:FG2f38K0hba8tTP7iUaw7vHjgcnN_5F5Mp0v4G6UDVs; specification
digest sha-256:iBllJ-J8aoWUaYKI7VAqjIfXx9bqwNqWXFO4nxBTCfM.
[0.5.0] — 2026-09-12
Fixed — the credibility floor
- Dependency pull requests can go green again. The public-surface
privacy history scan hard-requires the maintainer HMAC key, which
GitHub never delivers to dependabot or fork runs — every dependency
PR was structurally red. The gate now has exactly one relaxation:
CI marks true fork pull requests
ABP_PRIVACY_SCAN=fork-skip, where the scan skips LOUDLY (a greppable[privacy-scan] SKIPPEDbanner naming what did not run); every other mode value — including typos — fails closed exactly as before, and a fork run whose secret IS present still enforces. All three arms are red-proven in the requirement map; the dependabot green run is recorded as a green observation. - The documentation-currency gate's shipped-file enumeration now globs
DIRECTORY package entries: the original filter silently skipped
every guide inside
"documentation", and the onboarding install pins had drifted into a line SECURITY.md marks unsupported (the organic red is recorded in the requirement map). - macOS Finder artifacts (
.DS_Store,._*) are excluded from the four digest/file-set walks (specification identity, both release asset walks, the corpus directory walk): a stray.DS_Storeinsidespec/shifted the specification digest and red the release-candidate check on any Mac that had previewed the folder.
Added — the adoption surface
- Community intake: bug-report and registry-request issue templates
(the registry template follows
spec/registry/OPERATIONS.md), GitHub Discussions, SUPPORT.md, and a how-to-propose-changes path in CONTRIBUTING with the deferred-work registry surfaced as the public roadmap. - Onboarding reaches a green verification: the quickstart and getting-
started guides now decode the shipped echo example to
{:ok, _}and round-trip its canonical bytes byte-exactly (mirror-tested), state the minimum Elixir version, and keep the typed-denial teaching moment after the green path. - The worked host integration: a full
reconcile/3over the shipped echo pair under the default:denyclamp posture (the typed protected-clamp denial) and under:acknowledge(a green Evidence record whosenot_verifiednames the seven host-owned surfaces) — mirror-tested line by line. - The producer signing recipe: the detached-JWS Ed25519 envelope built
with
:cryptoover the RFC 7797 preimage and verified end-to-end against the shipped verifier — mirror-tested. The package itself remains verify-only. examples/federation-envelope.json: the 23-member federation TaskEnvelope as a byte-exact conformance corpus case, documented in the examples guide.- The hexdocs sidebar groups the guides (getting started, concepts, guides by role, reference, specification, design records, governance).
- A CI compatibility job: the previous supported Elixir/OTP pair (1.20.1 / 29.0.2) runs the test suite and the conformance corpus on every push and pull request — the broadened-target receipt the README's support claim now rests on.
The test suite is 917 tests (59 properties) at 100% coverage. The
conformance corpus is unchanged at 94 cases, digest
sha-256:sg6Fo7p8nZpJDzxFn4dXHBWgbGvEvtOk-7t3m7OT7Yo; registry digest
sha-256:FG2f38K0hba8tTP7iUaw7vHjgcnN_5F5Mp0v4G6UDVs; specification
digest sha-256:LSSVPdBlOwb844Eg0NQ71ju-sCiBv2_wgRp9RV5Vf0U.
[0.4.1] — 2026-08-26
Fixed — verification posture hardening
- CI green on the public repository (GitHub Actions is free for public repos; the prior 'billing-blocked' posture was wrong and is retired). The standing CI failures are fixed: a stale reprove copy path (a pre-promotion directory that never exists in a fresh checkout) crashed the release-candidate check.
- The README test-count claim is tied to the suite-REGISTERED count, not just the source macro census: the release-candidate check asserts macro census == registered count == README claim (both divergence arms red-proven and replanted in the evidence map).
- The deferred-work registry (twelve named items, each with its checkable reopen trigger) ships inside the specification tree's FOUNDATION-TRANSITION document — the durable record no longer lives only in planning artifacts.
The conformance corpus is unchanged at 94 cases, digest
sha-256:sg6Fo7p8nZpJDzxFn4dXHBWgbGvEvtOk-7t3m7OT7Yo; registry digest
sha-256:FG2f38K0hba8tTP7iUaw7vHjgcnN_5F5Mp0v4G6UDVs; specification
digest sha-256:LSSVPdBlOwb844Eg0NQ71ju-sCiBv2_wgRp9RV5Vf0U.
[0.4.0] — 2026-08-26
Added — examples gallery + minutes-long quickstart
examples/: complete, corpus-verified artifact pairs — byte-exact conformance corpus cases (the gallery gate proves it against the corpus on every build; a drifted example reds). The echo pair (blueprint + deployment) is annotated member-by-member in the examples guide.- The quickstart (
documentation/quickstart.md): frommix deps.getto a green verification iniex— no heavyweight gates; its result-claiming lines are mirror-tested like every guide example. - The documentation corpus: 13 adopter guides (getting started, the artifacts, extension authoring, host integration, producing, portability, the full 74-code error guide, federation, registry, upgrading, FAQ, operations), every file an ex_doc extra, every result-claiming example executed against the real package by the mirror gate; README as a decision document (when to use, when NOT to use).
The conformance corpus is unchanged at 94 cases, digest
sha-256:sg6Fo7p8nZpJDzxFn4dXHBWgbGvEvtOk-7t3m7OT7Yo; registry digest
sha-256:FG2f38K0hba8tTP7iUaw7vHjgcnN_5F5Mp0v4G6UDVs.
[0.3.0] — 2026-08-26
Added — the specification corpus (normative hardening + governance)
The normative specification is a specification in the standards sense:
- RFC 2119/8174 conformance language throughout (BCP 14 boilerplate, MUST/MUST NOT/SHOULD/SHOULD NOT/MAY used where load-bearing), a terminology section, and a normative Conformance clause (corpus pass + byte-identical report agreement + release identity pinning; partial conformance is not conformance).
- Member grammar for all three artifacts (18 Blueprint Core, 19 Deployment Manifest, 23 Federation TaskEnvelope members) with cardinalities, types, constraints, and the pinned failure precedence; the full 74-code error semantics table (raised when / subject / host action).
- Security considerations with a corpus-traceable threat model; privacy considerations as the data-minimization profile with honest limits; the positioning boundary (AI Catalog owns discovery + identity + attestation; this protocol owns the portable contract layer).
- Machine-readable grammar: CDDL (RFC 8610) normative under spec/grammar/ with JSON Schema derived (never hand-edited) — bound to the compiled tables and the corpus goldens by the grammar-derivation gate.
- Registry data governance: spec/registry/registry.json as the governance-canonical source, bound to both compiled twins and the corpus index by the registry-equality gate (all four carriers verified at sha-256:FG2f38K0…).
- Governance pack: spec-scoped IPR (Apache-2.0 + DCO, no CLA, donation-ready), FOUNDATION-TRANSITION inventory, registry operations process, errata policy; root CONTRIBUTING (the verification battery published) and CODE_OF_CONDUCT. Steward: the unincorporated BaseLabs org, Russ Palermo as named maintainer.
- The release identity chain: priv/release-metadata.json pins the specification digest, package version, corpus and registry digests, and the corpus index hash — asserted from live state on every run.
- Specification extraction is a tested proof (spec/ + the conformance corpus extract self-contained; the CI job runs the literal repository-filter extraction).
Every new gate carries a recorded red proof in the requirement map and is replanted by the release-candidate reprove (74 plants).
The conformance corpus is unchanged at 94 cases, digest
sha-256:sg6Fo7p8nZpJDzxFn4dXHBWgbGvEvtOk-7t3m7OT7Yo; registry digest
sha-256:FG2f38K0hba8tTP7iUaw7vHjgcnN_5F5Mp0v4G6UDVs.
[0.2.1] — 2026-08-25
Fixed — public documentation credibility
- README install pin corrected to the current release line (
~> 0.2.1; the previous~> 0.1.0excluded every 0.2.x release in Hex requirement semantics). - SECURITY.md's supported-version table names the 0.2.x line (0.1.x is no longer supported — upgrade to the current line).
- Two changelog entries cited an internal working document by section number (a document that ships nowhere); both are reworded to self-contained prose, and a new document-citation gate (below) keeps the class dead.
docs/protocol.mdstates the producer surface explicitly in its shipped-surface section (Blueprint.from_value/2,Deployment.from_value/2, the per-artifactcontent_digest/1andcanonical_bytes/1), resolving the pointer the producer-surface ADR relied on.- The federation mapping's pinned sources now carry canonical
repository URLs, each pinned by plain SHA-1 of the served bytes
(A2A
lf.a2a.v1line at commitcfc9d34b; the MCP Tasks extension draft at commit0d0a6bd4). - README rewritten for external readers: CI, Hex version, and license badges; an outsider-readable status section; current test and corpus counts.
Added — documentation gates
- Documentation-currency gate
(
test/architecture/documentation_currency_test.exs): README, SECURITY.md, and CHANGELOG version claims, install pins, count claims, and the current release's corpus identity (digest and case total) are checked against the live project on every run. - Document-citation gate
(
test/architecture/document_citation_gate_test.exs): shipped markdown documents may cite only documents that exist — a named section citation must name a shipped document or a pinned external standard, and every repository-relative link must resolve to a real file.
The conformance corpus is unchanged at 94 cases, digest
sha-256:sg6Fo7p8nZpJDzxFn4dXHBWgbGvEvtOk-7t3m7OT7Yo; registry digest
sha-256:FG2f38K0hba8tTP7iUaw7vHjgcnN_5F5Mp0v4G6UDVs.
[0.2.0] — 2026-08-25
Added — product-extension registration
- The extension registry registers
com.example.platform/estate-contract(ownerExamplePlatform, critical, active, never promoted) — the first product-owned critical namespace with an authored schema digest pin, riding the:authored_extensionsvalidated channel: critical bodies validate against a host-supplied schema whoseextension_schemaJCS digest matches the registry pin, then thread intofrom_value/2as authored content. The schema document covers the asset materialization window (definition {name, version}+ nullablewindow_days) and the objective condition AST (leavesmaterialization_present/materialization_stale/materialization_count_within; compositesand/orn-ary,notunary), hand-tiered as uniform-depth strict tiers because the bounded dialect denies$refcycles — portable condition depth is three composite tiers (metered complexity 417/512; the single free-form string —definition.name— is bounded to 128 bytes by the schema itself, the bound on the authored channel's unscanned surface). Seedocs/adr/product-extension-registration.md. - The schema document ships as corpus data
(
priv/conformance/schemas/estate-contract.schema.json);lib/records only the digest pin, and a test binds the pin to the SHIPPED document (the corpus index hashes raw file bytes, the pin hashes JCS of the parsed document — the test is the bridge between the two domains). - The conformance corpus grows 88 → 94 cases: the validated-channel cells
(valid attach with matching schema, schema absent, digest mismatch,
criticality conflict, the tier-bound deny) and the deprecated-optional
retention cell; two new applicability classes (
extension_schema_unavailable,extension_deprecated_retained); the floor is now 16 surfaces × 31 classes / 90 required cells. Corpus digestsha-256:sg6Fo7p8nZpJDzxFn4dXHBWgbGvEvtOk-7t3m7OT7Yo; registry digestsha-256:FG2f38K0hba8tTP7iUaw7vHjgcnN_5F5Mp0v4G6UDVs. docs/adr/producer-surface.mdrecords the producer-surface disposition: the documented per-artifact constructors ARE the intended producer surface for hosts; the facade stays a verification facade.
Deprecated
com.example.platform/estate(the placeholder optional namespace) isdeprecated: its payload role — a condition body carried verbatim as a free object — is superseded by the schema-validated channel. Optional bodies in existing artifacts remain verifiable, retained with a typedextension_deprecatednotice.
Fixed
- Cross-vendor review fix pass: the schema document bounds
definition.namewithmaxLength: 128(the free-form string in a body that skips the portability value-shape heuristics — the schema is the bound on that surface); the registry's closed-schema lens test now fails loudly for any future pinned namespace without its own document binding; stale 0.1.x release-line claims and the generator's section counts were reconciled to 0.2.0. - The second-language verifier's schema
itemsevaluation had its schema and instance arguments swapped, so no cross-language case had ever actually validated array items (object-shaped items passed vacuously; scalar items crashed the verifier). The estate-contract tier schemas are the first corpus-bearingitemsuser; the byte-identical agreement gate now proves both languages validate items identically.
Changed — from the unreleased queue
- The gitleaks secret-scan configuration was invalid TOML (a string concatenation TOML does not support) and, independently, nothing executed it — no CI job or alias ran gitleaks, so a committed credential would have passed the complete quality gate. The config now parses (the corpus key fragment is matched via a single-character class instead of concatenation), the generated conformance corpus is allowlisted by path (per-value fragments had rotted: the federation corpus keys were uncovered), and CI runs a full-history gitleaks v8.30.1 scan as its own job, pinned to the release commit. Red-proven against a staged canary secret; every finding the allowlists suppress was adjudicated as deterministic public-by-construction fixture material.
- GitHub CI now selects Node 24.19.0 through the immutable
setup-nodev7.0.0 commit before running the complete quality gate. This removes dependence on the runner image's ambient Node release while preserving the verifier's Node 24 minimum. - The normative protocol header and README introduction were reconciled to the live public 0.1.x package state (obsolete pre-publication/release-candidate framing removed).
[0.1.1] — 2026-08-23
Changed — documentation packaging (no code change)
- The Hex archive and hexdocs now ship the seven architecture decision
records (
docs/adr/), anddocs/federation-mapping.mdjoins the hexdocs extras — matching the house packaging convention of the publishedbounded_authority_protocolpackage. - The requirement map stays repository-side BY DESIGN (public in the repository, not in the archive): its verbatim red receipts quote the very internal tokens the publish guard bans from the archive, so archiving it reds the guard — that red is now recorded in the map's own publish-guard entry as the boundary's proof. An earlier draft of this release stripped the map's receipt fences from the guard's scan instead; cross-vendor review correctly blocked it as a guard blind spot that would have shipped the banned tokens verbatim.
- README restructured to the house convention: Installation directly after the introduction, a function-level "What it provides" section, and the requirement map's boundary stated.
[0.1.0] — 2026-08-23
Initial public release: the Agent Blueprint Protocol, its Elixir reference implementation, the conformance corpus, and the second-language verifier.
Normative docs + release-candidate gates
docs/protocol.md: the normative protocol document (ships in the Hex archive) — artifacts and the closed member registries, bounded bytes and the integer window, RFC 8785 canonicalization, domain-separated digests, the detached-JWS envelope, evolution and extension rules, the compiled registry's first-release entries, the bounds algebra laws, the 74-code error vocabulary, the evidence contract, and the conformance corpus identity (88 cases at the recorded digest).docs/design/requirement-map.md(repository-side, not in the Hex archive): every build gate's recorded red proof — each quality-alias step, every architecture-lane test case, and the conformance lanes — re-derived live (plant → run → restore) with verbatim failing output.docs/adr/(repository-side, slug-only filenames): the seven decisions of record — the non-authorizing boundary, the detached JWS envelope, the two-consumer amendment, deny-default protected-bound clamps, the compiled-in registry (closing the package-boundary contradiction of record), the federation lanes, and the no-versioning rule.- New architecture gates, both red-proven at birth:
- publish guard — no internal-planning reference, private-tool path, or home-directory path in any archived file (byte patterns plus word-bounded text patterns that cannot false-positive inside base64url tokens; registry owner/namespace/URI data is published by design and exempted on record);
- spec coverage — every public function carries a matching
@spec(default-arity rule recorded) and every shipped module's moduledoc states the non-authorizing boundary (39 modules gained an honest stance sentence;ExtensionRegistry.federation_schema/0gained its missing@spec).
mix release.candidate(also inmix quality): re-derives the requirement map's completeness from live project state (every architecture test case, every live quality-alias step), structure- checks each entry's red fence, and couplesdocs/protocol.mdto the shipped implementation (facade functions, registry namespaces, corpus digest and case total, the stance sentence).- Internal-reference scrub of the shipped surface: tracker numerals,
internal design-shorthand citations, and a portfolio-terminology
section removed from
docs/federation-mapping.md, README, CHANGELOG, andlib/comments/@docs (comments and docs only — zero behavior change). - README Status and Installation rewritten to the published 0.1.0 state.
Second-language verifier + agreement gate
conformance/verifier/: the repo-side TypeScript verifier (Node ≥ 24,node:builtins only, zero npm runtime deps; never in the Hex archive) — an independent recomputation of every corpus surface and integrity check, with a CLI byte-compatible with the Elixir escript (--corpusrequired; exit 0/1/2; report bytes on stdout, no trailing newline).mix verifier.agreement(inmix quality): byte-agrees the TS report with the escript's over the repo corpus AND the built Hex archive's, runs the self-check battery (RFC 8785 Appendix B three-way, the integer-window matrix incl. the mis-round lexeme, Ed25519 key acceptance, stored JOSE vectors), and proves three seeded reds fire (verdict inversion, report member drift, window-check deletion) — with a calibration self-proof of the raise path.conformance/verifier/testdata/jose-vectors.json+scripts/generate_jws_vectors.exs: the stored detached-JWS vectors, KAT- anchored to RFC 8032 §7.1 TEST 1, verified Elixir-signed → node-verified in both detached and compact forms.Signature: small-order key rejection hardened — the identity (order 1) and order-2 encodings no longer passusable_ed25519_key?(found by the mirror's torsion battery; latent on this OTP).Federation.decode: an empty claim value or compatibility identity now denies:invalid_constraintinstead of raisingFunctionClauseError(never-raising posture restored; found by the mirror's parity battery).Conformance.Runner: a malformed observed identity element denies typed:invalid_typeinstead of raising (the prior-receipts pattern).- Corpus regenerated to 88 cases (digest
sha-256:QsRbWGreygTJ0m47csgfpwYtoNId3FbjNP49sK-X-MY): two obligation-varying intersect cases pin the protected-bound meet direction inside corpus agreement (previously corpus-invisible; carried by the verifier's vectors); the mutation gate gains anobligation-meet-minentry (7 total). The real-escript end-to-end test covers the halt shim's exit contract in-suite (the coverage-exclusion ack's substance).
Conformance corpus subsystem
Conformance.{Corpus,Runner,Report,Cli}: the portable conformance corpus — pure loader with the 16×29 applicability floor compiled in, two-directional integrity with typed errors (corpus-registry and corpus-digest bindings, tamper verbatim-vs-derived audits, vacuous-green refusal), a code-level shape-agnostic runner over all 16 surfaces, a JCS report bound to the corpus identity, and an escript CLI (--corpusrequired; exit 0/1/2).priv/conformance/: 86 shipped cases, full-registry goldens (evidence members included), RFC 8785 vectors, deterministic key fixtures.mix conformance.verify+mix conformance.mutationswired intomix quality— five named implementation mutations each proven to redden the corpus, plus a corpus-expectation-flip calibration entry.ExtensionRegistry.digest/0(+ the:extension_registrydigest domain): the corpus-registry binding.- Facade:
canonical_bytes/1(the named canonicalize gap) and typednegotiate/intersectrims. Decode surfaces deny typed on non-binary input (was aFunctionClauseErrorraise). - Eight new error codes: the seven corpus integrity codes + the recorded
:corpus_case_invalidaddition.
Added
Federation profile:
AgentBlueprintProtocol.Federationwith the 23-memberTaskEnvelope(one wire member per logical field of the protocol's federation seam; decoded through the shared registry engine, canonical-before-semantics, cross-field rules, and a per-member portability pass where an authority-shaped identity claim denies:nonportable_content); the lossy-aware A2A/MCP state codecs (UNSPECIFIED denies at intake; crossing into MCP denies for rejected/submitted/auth_required; cancellation is never a terminal receipt); the carrier placement laws for both transports (Task.metadata[a2a_uri]on A2A,_meta[namespace]on MCP — the_metakey grammar forbids a URI key);terminal_commitment/1over the seven commitment components; andverify_commitment/2with the signature BINDING step (the signed content digest must name the receiving envelope's covered bytes — an honestly-signed statement naming a different digest is evidence over THAT digest), the issuer/subject/audience comparison (:audience_mismatch), and:federation_terminal_conflicton any divergence between receipts for one task identity. Facade rowsdecode_federation_envelope/2andfederation_mapping/0(the 23-row mapping as data, bijective with the envelope's members by an architecture gate). Published mapping docdocs/federation-mapping.mdwith the pinned live sources, the A2A primary / MCP draft-tracking flag and revisit trigger, and the ttlMs-is-not-an-execution-bound, AUTH_REQUIRED-is-not-authorization, and AgentCard protobuf pre-normalization notes.Federation hardening (independent review): a signature whose signed
purposeis notfederation-envelopenever verifies a federation receipt (the symmetric cross-surface purpose gap, closed on this surface — cross-surface signature lifting denied:invalid_constraint); the receipt'skid/key_idpositions are portability-scanned strict (PEM/hex secrets deny:forbidden_portable_value; the signature blob stays deliberately opaque — every honest signature is entropy-dense and never survives verification without the key);terminal_commitment/1andverify_commitment/2are total over hand-built structs (typed denials replace raises on absent/non-string members and malformed commitment spellings); the carrier-reconstruction lane re-imposes the decoder's member/item/node/string/depth ceilings and the UTF-8 gate on hand-built carrier maps; duplicate regulated markers deny:invalid_cardinality. Receiver posture documented (purpose pinning, key-ids-as-labels, keys-are-not-issuers, replay-is-receiver-policy).Federation residual hardening:
Federation.Contextgainsissuer_key_sets— per-issuer key attribution where the receipt's claimed (and binding-proven)issuermember selects the signature key pool, with strictest-wins precedence over the flat pool and deny-all for an empty map (cross-attribution now denies by mechanism) — andcreated_after/created_beforefreshness pins over the SIGNEDcreated_at(receiver-supplied inclusive window, Z-form double-gated, checked after conflict detection so equivocation still reports:federation_terminal_conflict). Fixes a live crash the adversarial pass reproduced:verify_commitmentwith the Context'skeys: nildefault raisedFunctionClauseError— nil/malformed pools now deny:invalid_typetyped. Attribution-miss denials name the issuer subject; a value-free structural guard pins every federation denial's subject to schema shape with nil detail. Signature-blob opacity ruled irreducible in-package (honest signatures are entropy-dense); the boundary is shape-checked, never echoed, and never survives verification without the key.Error vocabulary:
:forbidden_portable_valueis now declared and emitted through per-site literals (the per-site vocabulary walk could not see the module-attribute-carried emission — a live closedness hole, closed with a staged red); the federation codes:federation_state_unmappable,:federation_mapping_conflict,:nonportable_content,:audience_mismatch, and:federation_terminal_conflictdeclared exactly as emitted.Reconcile hardening (independent review): the composed pass gates non-object artifact roots at the canonical stage (typed denial, never a raise);
Reconcile.Inputsdrops the unused observed-identities field (the eight-stage pass performs no compatibility verification — hosts callverify_compatibility/2; recorded contract delta); the portability stage mirrors each artifact's own per-position scan modes (authored schema documents and predicate operands, the blueprint's five identifier member tables, strict elsewhere) instead of strict-scanning everything;Evidence .build/1validates every field's shape and denies struct inputs typed; compatibility re-asserts the identity manifest's cardinality and closed four-member entries, and case-folds range tags (LATEST denies like latest); signatures checks carry the entry count as detail; the two facade delegates deny typed on malformed arguments; the vocabulary gate treats sigil-built code positions as dynamic build failures, sees piped call sites, and fixes the case/cond branch tag.Reconcile, compatibility, and the evidence record:
AgentBlueprintProtocol.Reconcile.reconcile/3— the one call per import, running the pinned stage order canonical → digest → negotiation → structure → portability → signatures → bind → bounds, each stage reject-or-annotate, never repair, under host-suppliedReconcile.Inputs(host policy bounds, negotiation support, trusted public keys, observed build identities, the protected-clamp posture, and the bind-time observations). The signature stage BINDS each entry's signedcontent_digestto the artifact's recomputed digest — an honestly-signed statement naming a different digest is evidence over that digest, not this artifact (:digest_mismatch). The portability stage runs the direct scans under the authored channel re-derived from this import's negotiated critical extensions; the structure stage is the registry validation, kept disjoint so both guards are independently observable. Every clamp lands asEvidence.clampsand as a per-bound:boundscheck carrying the%ClampEvidence{}.AgentBlueprintProtocol.Compatibility.verify/2— identity-exact matching of manifestbuild_identitiesagainst host-observed identities: ranges deny:compatibility_identity_inexacton both sides, duplicate candidates (including byte-identical observations) and duplicated manifest names deny:compatibility_duplicate_entry, unmatched entries deny:compatibility_entry_missing, extra observed identities are evidence-neutral;exact?/1is the public exact-version predicate.AgentBlueprintProtocol.Evidence— the non-authorizing verification record whosenot_verifiedis non-empty BY CONSTRUCTION:build/1unions in the seven host-owned surfaces (tenancy, live_policy, authority, effect_ownership, execution, billing, evaluation_truth), never replacing them; callers may only add. The facade gainsverify_compatibility/2andreconcile/3, andError.codewidens to carry the{:ceiling, key}family. All eight reconcile stage guards and the Evidence constructor are mutation-redded (each guard's removal fails its committed tamper or order test).Bounds-algebra hardening pass: classification comparison moves to the PRODUCT order the meet computes in (ordinal ≤ AND markers ⊇) — a marker dropped at ANY ordinal is a widening (obligations are not tradeable against scope),
widens?becomes¬(a ⪯ b)and so fail-closed on every incomparable pair (an independent review's blocking finding:{pci}vs{phi}previously compared non-widening in both directions), andnarrowerrequires both components. The rim is now deny-typed everywhere it previously raised on struct-bypass inputs: hostile map keys and unknown/extra names deny:bound_unknownwith the CONTAINING surface as subject (never the attacker key — the echo channel closes), plain-map markers and marker maps with extra keys deny:bound_value_invalidat construction and again atintersect's revalidation, malformed lifter sub-shapes read as absent (total, never-raising), off-lattice envelope strings deny with a constructible subject (the error builder itself was a crash site), a string on a numeric host bound denies:invalid_type, duplicate or extra members in hand-builthost_bounds/ceilingsobjects deny:invalid_type(decode already enforced both), bound values above the parse profile's declared integer magnitude deny,widens?/narrowernever raise on forged values (total predicates, fail-closed in the widening direction), andResult.t's clamps type resolves its module. Every fix re-probed live against the finding's original probe input.Bounds algebra:
AgentBlueprintProtocol.BoundsAlgebra— the pointwise narrowest intersection of the Blueprint's declared bounds, the Deployment'shost_bounds, and the host's live policy over the closed thirteen-bound vocabulary, with per-family direction (scope families narrow at the low end; authority/approval/effect narrow at the STRICT end; classification markers are retained regulatory obligations whose effective set is the UNION of the sources' sets — dropping one is the widening the mutation gate names). Protected narrowings never happen silently: under the default:denyposture they deny:protected_bound_clamp_deniedcarrying the field/requested/effective triple; under:acknowledgethey clamp withacknowledged: trueevidence ALWAYS. Operational narrowings emitClampEvidence{field, class, unit, requested, effective, source, acknowledged}with:hostattribution on ties and composites (the live policy is the operative constraint), clamps ordered by the name-sorted vocabulary.max_costcompares within one currency only (:bound_unit_mismatch, order-free). All three sources must be total: an operational absence denies:missing_ceiling, a protected absence:bound_source_missing, under the pinned precedence (source order, then numerics → cost → protected, each name-sorted).widens?/2is fail-closed on incomparable pairs;Bound.narrower/2is direction-encoded per family and function-total (marker-bearing classification is a partial order — the lexicographic ordinal-then-marker superset relation). The lifters derive the Blueprint side totally (classification is the WIDEST across all five declaration sites; approval/authority/impact are the strictest claims across capabilities/effects with bottoms for empty arrays; disclosure is the identity element:full— the Blueprint declares no disclosure member) and lift the Deployment fromhost_boundsonly (model_policyanddata_bindingsare not intersection inputs). The newAgentBlueprintProtocol.Error{code, subject, detail}record (typed shape, string subject paths,detailonly for the protected deny) lands with the algebra surface; the facade gainsintersect/1. Property lane: idempotent/commutative/associative (pinned fold encoding),not widens?(effective, host)universal, clamp iffeffective ≠ requested, marker-union law — with the min→max, marker-intersection, direction-flip, struct-default, and silent-path mutations each proven RED against them.
Fixed
- The bounds-algebra rim's coverage claim was corrected to a true
100% (measured 2026-08-22: the then-committed suite reached only
97.7% — the deny-typed rim's catch-all clauses had no tests). The rim probes now ship as tests: struct-bypass forged
values through
widens?/2andBound.narrower/2for every family, wrong-shape cost at construction, non-mapnew/1, absent-namefetch/2, non-Sources/junk-posture/non-set-sourceintersect/1, and thehost_boundslifter shape matrix (absent, malformed member, malformed value, off-lattice ordinal, non-string on a protected name), each asserting the typed denial or fail-closed verdict. Eleven representative rim mutations each redded their test before restore. Two provably unreachable arms were removed (the only production change):widens_value/3's unknown-name arm (its only caller iteratesnames/0, always@tablekeys) andmember_of/2's{:object, _}clause (no call site passes an object tuple). An independent re-review of the follow-up range then found the rim's one remaining hole:widens?/2matched any%BoundSet{}regardless ofbounds' type, so a struct-forged%BoundSet{bounds: nil}raisedBadMapErrorfrom either argument position instead of failing closed (the head now guardsis_mapon both, dropping the forgery to the fail-closed catch-all), plus its guard-family siblingBoundSet.to_map/1(same forged shape raised; now deny-typed:invalid_typewith subject["bound_set"]). Both probed red before the fix, green after.mix qualityhas reported a true 100.00% since. - A one-off suite flake, root-caused: the
"mutating the signatures member" test replaced the first
Ain the base64url signature, which lands on the FINAL character ~7% of random signatures — the one position whose value is canonicality-constrained — producing a correctly-rejected non-canonical string (:signature_malformed). The tamper now targets the first character (a significant 6-bit position at every base64url length), making the test deterministic for every key.
Core surfaces
- Deployment Manifest + binding: the 19-member table
(re-derived against the protocol's Deployment Manifest definition) on the
SAME generic engine —
AgentBlueprintProtocol.Deploymentmirrors the Blueprint pipeline stage-for-stage (canonical verify → registry validation → portability scan → digest comparison) under the:deployment_contentdomain, with only the table, the scan's open regions (extension bodies, eligibility expressions), and the digest domain as deltas. The binding surface:binds?/2(digest equality and nothing else, against the paired Blueprint's recomputed digest, constant-time, total over malformed deployment input) and the six-stageverify_binding/3with a pinned order — release digest (:deployment_digest_mismatch), release identity and tool-binding completeness (:binding_incomplete), mutation/recovery (:no_authoritative_recovery, the stricter of both operation sources), attestation staleness (:binding_attestation_stale, future attestations deny), and observed rug-pull (:binding_descriptor_mismatch); stages carrying host observations skip exactly when their inputs are absent. Table semantics:blueprint_releasewith a REQUIRED digest; exact-only build identities (the range vocabulary — comparators, wildcards,latest, range spans — denies:compatibility_identity_inexact; prerelease/build suffixes are exact pins); theas_oftotal rule; lifecycle temporal rules (:lifecycle_state_invalid);host_boundstotality over the thirteen bound names (structure only — the algebra surface owns the rest); emptyallowed_model_rolesvalid. Everyadapter_identity/profile_identityand every string nested in tool/data/build members is strict-scanned (:forbidden_portable_valuein deployment positions). A signature'spurposeis asserted per artifact (deploymenthere,blueprintinBlueprint— the symmetric cross-surface gap this closes). The extension envelope judgment is extracted toAgentBlueprintProtocol.Extensionso both tables carry one definition, andNegotiationresolves the artifact kind from the digest member so each artifact'srequired_core_fieldscheck against its own vocabulary. The facade gainsdecode_deployment/2, and a new architecture gate proves the no-second-pipeline invariant (delegation toRegistry.validateplus no local stage definitions — planted-red proven, after the exports-only form was found vacuous by the same mutation). - Deployment hardening pass:
verify_binding/3gains a stage-0 shape totality — a non-object root, DUPLICATE root members, or a malformedtool_bindingsentry (shape, operands, digest) denies before any cross-artifact judgment, and validated entries thread every later stage (the blocking finding of an independent review: malformed bindings were silently discarded, failing OPEN); negotiation restores revision-first order ahead of the new artifact-kind resolution, which now requires a well-formed string digest member (a malformed tag is machinery:invalid_type); the exact-version detector becomes one total charset rule (bare tilde, OR/comma/semicolon lists, and not-equal comparators join the denied range vocabulary);max_attestation_age_msis shape-guarded (a non-integer bound silently failed to apply); scheme-relative network-path references (//authority/path) deny in every strict scan position; and the portability member-name denylist folds kebab/SCREAMING/camel spellings onto one normalized form (the normalization lesson swept across the guard family). - Negotiation + compiled-in extension registry: the
evolution gate (
AgentBlueprintProtocol.Negotiation) with the pinned internal precedence (revision → required_core_fields → extensions) and registry-consistent reason rules for malformed machinery; explicit revision SET support (never ranges — a miss denies:protocol_revision_unsupportedin both directions); the three fail-closed required-core-field checks; the positional extension state machine (unregistered critical denies, unregistered optional QUARANTINES byte-exactly with a notice fact, criticality conflict denies for live states before state handling, deprecated/retired/reserved cells all decided); critical-body validation only against digest-pinned host schemas (:extension_schema_unavailable/:extension_schema_digest_mismatch); and a reserved-semantics denylist (bound-shaped member names, camelCase twins included) over ALL extension bodies. The registry (ExtensionRegistry) is compiled-in data — drift unrepresentable, backed by a new beam-census gate that asserts no shipped module touches the filesystem (planted-red proven) — carrying the five first-release entries withcom.example/federation's schema authored in-repo under the new:extension_schemadigest domain.Blueprint.from_value/2's:authored_extensionsoption opens the encoded-content carriage channel: negotiation-validated critical bodies skip the portability value-shape heuristics (their controls are the schema pin and the denylist). The facade gainsnegotiate/2. - Portability named-encoding closures: the raw-key floor drops to 24 decoded bytes (catches AES-128-class hex keys) with hyphenated UUIDs exempt by shape in every mode (the spec-pinned honest-limit calibration); padded standard base32 (up to six pad chars) joins the padded-base64 class; and a colon-chunked hex fingerprint class (the SSH fingerprint / EUI form, 24+ decoded bytes) denies while the chunk grammar spares tagged content addresses and MAC addresses.
- Blueprint artifact + generic registry engine: the ONE
table-driven decode/validate engine (
AgentBlueprintProtocol.Registry) parameterized byAgentBlueprintProtocol.Blueprint.table/0's 18-member field registry (the closed-world Blueprint core member table), with the pinned failure precedence (unknown member → missing required → type → constraint → cardinality → nested → cross-field hooks).Blueprint.decode/2runs the fail-closed pipeline in order: canonical verify (:non_canonical_bytesbefore any semantic read or digest work — the canonicality obligation, digests computed only over exact received bytes), registry validation (closed world; tag-strict integer typing so a float-tagged window value in an integer-typed core field denies:invalid_type— the window-float obligation, visible only at this layer), the portability scan, then the content-digest comparison (:digest_mismatch). Also shipsAgentBlueprintProtocol.Predicate(the closed, order-independent predicate algebra: grammar validation against declared ports, the 256-node ceiling, and error-dominantevaluate/2), andAgentBlueprintProtocol.Portability(the never-portable structural guard: the 34-name member denylist over the open regions and the value-shape denylist — PEM armour, compact JWS, network-authority URIs, ≥32-byte clean base64url with the identifier-style exemption — over every other string including signaturekey_id). The facade gainsdecode_blueprint/2. - Public Elixir package starter with zero third-party/Hex production dependencies.
- Explicit non-authorizing product boundary and release-candidate posture.
- RFC 8785 JSON Canonicalization Scheme (
AgentBlueprintProtocol.Canonicalization): UTF-16 code-unit member sorting, §3.2.2.2 string escaping, hand-written ECMA-262 §7.1.12.1 number serialization (byte-exact against every finite RFC 8785 Appendix B vector), andverify/2decode→re-encode→byte-compare interchange enforcement with fail-closed guards for duplicate names, invalid UTF-8/lone surrogates, and out-of-bound integers on the encode path. - Strict unpadded base64url codec (
AgentBlueprintProtocol.Base64Url): RFC 4648 §5 alphabet, RFC 7515 §2 padding-free wire form, and RFC 4648 §3.3/§3.5 canonicality — padded input, non-alphabet characters, and non-canonical pad-bit spellings (which alias the same bytes) all reject with value-free reasons. - Tagged content digests (
AgentBlueprintProtocol.Digest):"sha-256:<43-char unpadded base64url>"wire strings over domain-separated preimages (SHA-256(separator || <<0>> || canonical JCS bytes)under the registered domain-separation separators),from_tagged/1fail-closed parsing (unknown algorithm tag vs malformed body, wrong-length bodies included), constant-timeequal?/2, andverify_content/3(parse, then compare; divergence denies:digest_mismatch). SHA-256 conformance is pinned to the FIPS 180-4 known-answer vectors. - Detached JWS signature envelope (
AgentBlueprintProtocol.Signature): RFC 7515 compact serialization with the RFC 7797b64=falseunencoded detached payload — the signing input isBASE64URL(JCS(protected_header)) || "." || JCS(signed_attributes)— Ed25519 verified through:crypto, verify-only (an architecture gate enforces no:crypto.signcall, no private-key parameters, and no key-material shape anywhere in the shipped source). Host-supplied trusted keys match bykey_id(:signature_key_unsupportedwhen absent,:signature_not_verifiedon divergence — facts, never authorization). The exact four-member protected header (alg/crit/b64/kid) and the five signed attributes are closed-world with fail-closed, value-free denials;kidmust equal the signedkey_id, which is dot-free so the unencoded payload can never carry.(RFC 7797 §5.2). Compact rendering (h..s, empty payload segment per RFC 7515 Appendix F) supports standard-tooling cross-checks. RFC 8032 §7.1 TEST 1 is reproduced byte-exact. Attestations share the envelope with a registeredkindandstatement_digest; the kind registry is empty, so attestations deny:attestation_malformedtoday (fail-closed until kinds become data).
Changed
- Integer window decode rule (the amendment): a pure-digit number lexeme
above the I-JSON bound ±(2^53−1) now decodes as a float when it is exactly
that double's canonical ECMAScript serialization (e.g. the RFC 8785
Appendix B vectors
9007199254740992,295147905179352830000), and denies with the new:number_not_double_expressiblereason otherwise (retiring the interim:integer_magnitudedecode reason). Canonical pure-digit float output in [2^53, 10^21) now round-tripsverify/2; the encode/verify asymmetry previously documented here is closed. - Bounded JSON Schema 2020-12 dialect + instance validator
(
AgentBlueprintProtocol.Schema): the closed 16-keyword subset (type properties required items enum const minimum maximum minLength maxLength minItems maxItems additionalProperties oneOf $defsplus document-local$ref) over the tagged algebra, with everything else —pattern/format/patternProperties/if-then-else/allOf/remote$refand the rest of the 2020-12 keyword universe — denying:schema_keyword_not_allowed. 2020-12 semantics read first-hand and pinned: type-targeted assertions auto-pass other types, missing keywords never fail,oneOfis exactly-one, boolean schemas are the substrate, numbers compare by mathematical value across the integer/float tags (tag-blindtype:"integer"— the tags do not survive the wire), object equality is order-blind, and string lengths count codepoints (not graphemes, not UTF-16 units). Resource posture: complexity metered asnodes + keywords + Σ(branches) + depth × 4against the 512 profile ceiling; evaluation memoized on (schema node, instance location) — closing the acyclic-$ref-DAG exponential blowup for passing AND failing instances; document-local RFC 6901 pointers (split-then-unescape,~1before~0) resolve at parse, and application-reachable reference cycles deny while dead$defsself-references parse. Bothparse/2andvalidate_instance/3are total — malformed tagged shapes deny, never raise. Multi-failure reasons follow a fixed canonical keyword order (mirrored for the TS verifier).