All notable public changes to agent_blueprint_protocol are documented here.
[Unreleased]
[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 (base §6), 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 base-§8.2 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).