Skip to main content

N-AALP: The Native Agentic Application Layer Protocol
draft-bubblefish-naalp-01

Document Type Active Internet-Draft (individual)
Author Shawn Edward Sammartano
Last updated 2026-09-06
RFC stream (None)
Intended RFC status (None)
Formats
Stream Stream state (No stream defined)
Consensus boilerplate Unknown
RFC Editor Note (None)
IESG IESG state I-D Exists
Telechat date (None)
Responsible AD (None)
Send notices to (None)
draft-bubblefish-naalp-01
Network Working Group                                      S. Sammartano
Internet-Draft                             BubbleFish Technologies, Inc.
Intended status: Informational                          6 September 2026
Expires: 10 March 2027

         N-AALP: The Native Agentic Application Layer Protocol
                       draft-bubblefish-naalp-01

Abstract

   The Native Agentic Application Layer Protocol (N-AALP) is an
   application-layer object protocol for autonomous software agents.
   Every N-AALP object is a deterministically encoded CBOR structure
   signed with COSE, carrying under one signature its content identity,
   its originating signer, a closed effect label that is an
   authorization input rather than a hint, optional approval and audit
   bindings, and its causal derivation.  Objects are transport-
   independent: the identical signed object is carried, with identical
   object-level guarantees, over the N-PAMP substrate, QUIC, WebSocket,
   or HTTP.  N-AALP defines a frozen envelope, a post-quantum signature
   profile (pure ML-DSA by default, with an optional Ed25519+ML-DSA
   composite), a self-certifying identity with key rotation, a single-
   use approval ledger, a hash-chained audit and causal- ordering model
   with a federated higher tier, native streaming with a single per-
   stream commitment, foreign-protocol carriage by class, and twenty
   tiered channel surfaces.  This document is an Independent Submission
   and does not represent IETF consensus.

Status of This Memo

   This Internet-Draft is submitted in full conformance with the
   provisions of BCP 78 and BCP 79.

   Internet-Drafts are working documents of the Internet Engineering
   Task Force (IETF).  Note that other groups may also distribute
   working documents as Internet-Drafts.  The list of current Internet-
   Drafts is at https://datatracker.ietf.org/drafts/current/.

   Internet-Drafts are draft documents valid for a maximum of six months
   and may be updated, replaced, or obsoleted by other documents at any
   time.  It is inappropriate to use Internet-Drafts as reference
   material or to cite them other than as "work in progress."

   This Internet-Draft will expire on 10 March 2027.

Sammartano                Expires 10 March 2027                 [Page 1]
Internet-Draft                   N-AALP                   September 2026

Copyright Notice

   Copyright (c) 2026 IETF Trust and the persons identified as the
   document authors.  All rights reserved.

   This document is subject to BCP 78 and the IETF Trust's Legal
   Provisions Relating to IETF Documents (https://trustee.ietf.org/
   license-info) in effect on the date of publication of this document.
   Please review these documents carefully, as they describe your rights
   and restrictions with respect to this document.

Table of Contents

   1.  Introduction  . . . . . . . . . . . . . . . . . . . . . . . .   3
     1.1.  Scope . . . . . . . . . . . . . . . . . . . . . . . . . .   4
     1.2.  Non-Goals . . . . . . . . . . . . . . . . . . . . . . . .   4
   2.  Conventions and Terminology . . . . . . . . . . . . . . . . .   4
   3.  Architecture  . . . . . . . . . . . . . . . . . . . . . . . .   5
   4.  Object Model  . . . . . . . . . . . . . . . . . . . . . . . .   5
     4.1.  Deterministic encoding  . . . . . . . . . . . . . . . . .   6
     4.2.  The object body . . . . . . . . . . . . . . . . . . . . .   6
     4.3.  Content identity  . . . . . . . . . . . . . . . . . . . .   7
       4.3.1.  Multihash length-octet worked example . . . . . . . .   7
     4.4.  Extensions and versioning . . . . . . . . . . . . . . . .   8
   5.  Cryptographic Constructions . . . . . . . . . . . . . . . . .   9
     5.1.  Signing . . . . . . . . . . . . . . . . . . . . . . . . .   9
     5.2.  Algorithms and profiles . . . . . . . . . . . . . . . . .  10
   6.  Identity  . . . . . . . . . . . . . . . . . . . . . . . . . .  12
   7.  Effects and Authorization . . . . . . . . . . . . . . . . . .  12
   8.  Approval  . . . . . . . . . . . . . . . . . . . . . . . . . .  13
   9.  Audit, Causal Graph, and Ordering . . . . . . . . . . . . . .  15
   10. Delivery  . . . . . . . . . . . . . . . . . . . . . . . . . .  16
   11. Streaming . . . . . . . . . . . . . . . . . . . . . . . . . .  17
   12. Object State Machines . . . . . . . . . . . . . . . . . . . .  17
     12.1.  Delivery state machine . . . . . . . . . . . . . . . . .  18
     12.2.  Stream state machine . . . . . . . . . . . . . . . . . .  19
     12.3.  Approval state machine . . . . . . . . . . . . . . . . .  21
     12.4.  Reconcile state machine  . . . . . . . . . . . . . . . .  22
     12.5.  Timers . . . . . . . . . . . . . . . . . . . . . . . . .  23
     12.6.  Clock skew and validity windows  . . . . . . . . . . . .  24
     12.7.  Cancel . . . . . . . . . . . . . . . . . . . . . . . . .  24
     12.8.  Deadline . . . . . . . . . . . . . . . . . . . . . . . .  25
   13. Transport Bindings  . . . . . . . . . . . . . . . . . . . . .  25
   14. Foreign Carriage by Class . . . . . . . . . . . . . . . . . .  25
   15. Channel Surfaces  . . . . . . . . . . . . . . . . . . . . . .  26
   16. Additive Object Families  . . . . . . . . . . . . . . . . . .  26
     16.1.  Collaboration and Rooms Membership . . . . . . . . . . .  27
     16.2.  Multi-Hop Delegation Grant . . . . . . . . . . . . . . .  28

Sammartano                Expires 10 March 2027                 [Page 2]
Internet-Draft                   N-AALP                   September 2026

     16.3.  MCP Tool-Call Binding  . . . . . . . . . . . . . . . . .  29
     16.4.  Description and Directory  . . . . . . . . . . . . . . .  30
     16.5.  Name Bindings and A2A Task Transitions . . . . . . . . .  30
     16.6.  Governed Negotiation . . . . . . . . . . . . . . . . . .  31
     16.7.  Advisory Risk Labels . . . . . . . . . . . . . . . . . .  32
     16.8.  Flow Continuations . . . . . . . . . . . . . . . . . . .  32
     16.9.  Governed-Decision Records and Transparency Log
             Primitives  . . . . . . . . . . . . . . . . . . . . . .  33
     16.10. Portable Egress Evidence . . . . . . . . . . . . . . . .  35
     16.11. Manufacturing Physical-Hazard Claims and
             Authorizations  . . . . . . . . . . . . . . . . . . . .  35
   17. Security Considerations . . . . . . . . . . . . . . . . . . .  36
     17.1.  Trust-decision closure sovereignty . . . . . . . . . . .  44
   18. Privacy Considerations  . . . . . . . . . . . . . . . . . . .  45
   19. IANA Considerations . . . . . . . . . . . . . . . . . . . . .  46
     19.1.  Media type application/vnd.bubblefish.naalp+cbor . . . .  46
     19.2.  N-AALP Channel registry  . . . . . . . . . . . . . . . .  47
     19.3.  N-AALP Object Kind registries  . . . . . . . . . . . . .  47
     19.4.  N-AALP Effect registry . . . . . . . . . . . . . . . . .  51
     19.5.  N-AALP Carriage Protocol Id registry . . . . . . . . . .  51
     19.6.  N-AALP Error Code registry . . . . . . . . . . . . . . .  51
     19.7.  N-AALP Extension Key registry  . . . . . . . . . . . . .  57
     19.8.  N-AALP Carriage Content Type registry  . . . . . . . . .  58
     19.9.  N-AALP Trust-Decision Input Class registry . . . . . . .  58
     19.10. COSE algorithms  . . . . . . . . . . . . . . . . . . . .  59
     19.11. Registration criteria for the RFC-Required registries  .  59
   20. Implementation Status . . . . . . . . . . . . . . . . . . . .  60
   21. Conformance . . . . . . . . . . . . . . . . . . . . . . . . .  60
   22. Specification License . . . . . . . . . . . . . . . . . . . .  61
   23. Normative References  . . . . . . . . . . . . . . . . . . . .  61
   24. Informative References  . . . . . . . . . . . . . . . . . . .  62
   Appendix A.  Collected CDDL . . . . . . . . . . . . . . . . . . .  63
   Appendix B.  Acknowledgments  . . . . . . . . . . . . . . . . . . 103
   Author's Address  . . . . . . . . . . . . . . . . . . . . . . . . 103

1.  Introduction

   Autonomous agents increasingly exchange consequential messages --
   tool invocations, memory writes, capability delegations, settlements
   -- across trust and organizational boundaries.  Existing agent
   protocols secure the transport connection but leave the individual
   message un-signed, its effect on the world undeclared, and its
   authorization implicit.  N-AALP makes the object, not the connection,
   the unit of security and governance.

   N-AALP is the application layer above the N-PAMP substrate [NPAMP]:
   N-PAMP provides the post-quantum secure channel, channel identifiers,
   and foreign-protocol Bridge; N-AALP provides the signed, effect-

Sammartano                Expires 10 March 2027                 [Page 3]
Internet-Draft                   N-AALP                   September 2026

   labeled, audited object that rides any transport.  The two compose
   but N-AALP does not require N-PAMP: the same object is valid over
   QUIC, WebSocket, or HTTP.

1.1.  Scope

   This document specifies: the object envelope and its deterministic
   CBOR encoding (# Object Model); the COSE signing constructions and
   crypto-agile profiles (# Cryptographic Constructions); self-
   certifying identity and key lifecycle (# Identity); the closed effect
   vocabulary and effect-to-authorization rule (# Effects and
   Authorization); the approval object and single-use consume ledger (#
   Approval); the audit receipt chain, causal graph, and tiered ordering
   (# Audit, Causal Graph, and Ordering); delivery stages (# Delivery);
   native streaming (# Streaming); the four transport bindings and the
   confidentiality boundary (# Transport Bindings); foreign carriage by
   class (# Foreign Carriage by Class); the twenty tiered channel
   surfaces (# Channel Surfaces); and the higher-tier additive object
   families -- rooms membership, multi-hop delegation, MCP tool-call
   binding, description and directory, name bindings and A2A task
   transitions, governed negotiation, advisory risk labels, flow
   continuations, governed- decision records and transparency log
   primitives, portable egress evidence, and manufacturing physical-
   hazard claims (# Additive Object Families).  The document classifies
   these surfaces by status (# Conformance): the spine and each
   channel's frozen baseline surface are normative and required for
   conformance, while the higher tiers are experimental and OPTIONAL.
   The classification is editorial and does not narrow implementation
   coverage.

1.2.  Non-Goals

   N-AALP does not define a transport handshake, key exchange, or record
   layer; those are the substrate's (N-PAMP's, or the underlying TLS/
   QUIC's).  It does not define agent reasoning, planning, or model
   behavior.  It does not replace the foreign protocols it carries; it
   wraps them.

2.  Conventions and Terminology

   The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
   "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and
   "OPTIONAL" in this document are to be interpreted as described in
   [BCP14] (RFC2119) (RFC8174) when, and only when, they appear in all
   capitals, as shown here.

   The following terms are used:

Sammartano                Expires 10 March 2027                 [Page 4]
Internet-Draft                   N-AALP                   September 2026

   Object:  a deterministically encoded CBOR map, signed with COSE, that
      is the unit of N-AALP security and governance.

   Content id:  the multihash of the SHA-384 of an object's canonical
      body excluding its own id field; it binds the object's bytes.

   Signer id:  a self-certifying identifier derived from a public
      signing key (# Identity); no certificate authority is involved.

   Effect:  one closed value stating what an object does to the world,
      aligned with the N-PAMP Bridge SafetyLabel and used as an
      authorization input (# Effects and Authorization).

   Channel:  one of twenty application surfaces, identified by an N-PAMP
      channel id (# Channel Surfaces).

   Carriage:  wrapping a foreign protocol's message octet-for-octet
      inside a signed N-AALP object (# Foreign Carriage by Class).

3.  Architecture

   N-AALP separates three layers that MUST NOT be conflated:

   1.  The object (this document): self-secured, transport-independent.

   2.  The transport: provides confidentiality, connection
       authentication, and framing; N-PAMP is the reference confidential
       transport, but QUIC, WebSocket, and HTTP are equally valid
       carriers of the identical object.

   3.  The application: the twenty channel surfaces, each a thin body
       over the one object model.

   Object-level guarantees (integrity, identity, non-repudiation,
   effect, audit) are always present regardless of transport.
   Confidentiality, forward secrecy, and connection authentication are
   transport-provided and conditional (# Transport Bindings).

4.  Object Model

   Every top-level wire structure this document defines -- the object
   body below, its COSE signature wrapper, the identity, approval,
   audit, delivery, streaming, flow-continuation, carriage, and
   additive-family records (# Additive Object Families) -- is collected
   as a single reachable root, naalp-artifact, in the CDDL module
   (Appendix A).  The union exists only so a CDDL validator sees every
   production as reachable from one entry point; it carries no
   independent wire meaning of its own, and a concrete instance is

Sammartano                Expires 10 March 2027                 [Page 5]
Internet-Draft                   N-AALP                   September 2026

   always validated against the specific production for its kind, not
   against the union.

4.1.  Deterministic encoding

   All N-AALP structures are encoded as deterministic CBOR per [RFC8949]
   Section 4.2.1: shortest-form integer and length encoding, major-type
   map keys sorted in bytewise-lexicographic order of their encoded
   form, no indefinite-length items, and no duplicate keys.  A non-
   canonical encoding of any structure defined here MUST be rejected.

   [RFC8949] Section 4.2.2 leaves the integer/float question, and
   [RFC9052] Section 3 the empty protected header, to the protocol;
   N-AALP resolves each as a MUST-reject so that one logical object has
   exactly one encoding.  A CBOR float (major type 7) MUST NOT appear in
   any object body field, ext value, or cext value, and a decoder MUST
   reject a major-type-7 item as non-canonical.  An empty COSE protected
   header MUST be the zero-length byte string 0x40; the redundant 0x41A0
   form (a byte string wrapping an empty map) MUST be rejected as non-
   canonical, before the header is interpreted.  A map with duplicate
   keys MUST be rejected at the decoder ([RFC8949] Section 5.6).

4.2.  The object body

   The signed payload is the object body, a CBOR map, expressed here in
   CDDL [RFC8610]:

   naalp-object = {
     1 : bstr,      ; id: multihash(0x20, SHA-384(body-without-1))
     2 : uint,      ; kind (per channel surface)
     3 : 0..19,     ; channel id
     4 : uint,      ; tier (0 = baseline)
     5 : bstr,      ; signer: self-certifying signer id
     6 : uint,      ; created: epoch ms (advisory)
     7 : effect,    ; closed effect value
     8 : [* bstr],  ; causes: content ids; may be empty
     9 : profile,   ; crypto profile
     10 : any,      ; body: kind-specific, validated by the surface
     ? 11 : { * uint => any },  ; ext: non-critical; unknown ignored
     ? 12 : { * uint => any },  ; cext: critical; unknown => reject
     ? 13 : tstr,   ; audience: consuming-authority binding;
                    ; omitted when empty (see below)
     ? 14 : uint,   ; suite: signed signature-suite selector;
                    ; present iff composite alg (see below)
   }
   effect = &( read_only:0, idempotent_write:1,
               non_idempotent_write:2, destructive:3 )
   profile = &( public:1, enterprise:2, sovereign:3 )

Sammartano                Expires 10 March 2027                 [Page 6]
Internet-Draft                   N-AALP                   September 2026

   Fields 4 (tier) and 9 (profile) are independent axes with distinct
   meanings and MUST NOT be conflated. profile selects the cryptographic
   signature floor (# Cryptographic Constructions) that bounds which
   signature strength a verifier accepts for the object. tier selects
   the channel's capability depth (0 = baseline; higher values are named
   per channel, # Channel Surfaces) under the one frozen envelope.  The
   two are set independently: a higher channel tier does not raise the
   signature floor, and a higher crypto profile does not unlock channel
   capability.

4.3.  Content identity

   The id (field 1) is multihash(0x20, SHA-384(C)) where C is the
   deterministic CBOR encoding of the body with field 1 removed, and
   0x20 is the multiformats code for SHA-384.  A verifier recomputes the
   content id and MUST reject a mismatch (ContentIdMismatch).  Because
   the id binds the exact bytes, altering any field changes the id.

4.3.1.  Multihash length-octet worked example

   A multihash is unsigned-varint(code) || unsigned-varint(digest-
   length) || digest, per the multiformats multihash and unsigned-varint
   specifications. unsigned-varint is a base-128 (LEB128-style)
   encoding: a value under 128 encodes as exactly one octet equal to
   that value.  Both integers a content id ever carries are under 128
   (32 and 48), so both octets are single-byte:

octet 0        : 0x20  -- unsigned-varint(32); sha2-384 multicodec code
octet 1        : 0x30  -- unsigned-varint(48); a 48-octet SHA-384 digest
octets 2..49   : the 48-octet SHA-384 digest

   Using the FIPS 180-4 SHA-384 known-answer digest for the ASCII input
   "abc" (shown below), the 50-octet content id is:

   SHA-384("abc"):
     cb00753f45a35e8bb5a03d699ac65007272c32ab0eded163
     1a8b605a43ff5bed8086072ba1e7cc2358baeca134c825a7

   content id:
     2030cb00753f45a35e8bb5a03d699ac65007272c32ab0eded1
     631a8b605a43ff5bed8086072ba1e7cc2358baeca134c825a7

   The two prefix octets are derived from the unsigned-varint algorithm
   applied to 32 and 48, not asserted as a fixed literal; the same
   algorithm produces a two-octet encoding (0xac 0x02) for a value at or
   above 128 (e.g. 300), which is how a future digest algorithm with a
   multicodec code or digest length at or above 128 would be carried
   without changing this framing.  A conformance oracle and grading gate

Sammartano                Expires 10 March 2027                 [Page 7]
Internet-Draft                   N-AALP                   September 2026

   for this construction, cross-checked against the multiformats spec
   and NIST FIPS 180-4 SHA-384 known-answer values independent of any
   N-AALP encoder, ship with the reference implementation (tools/
   multihash_oracle.py, scripts/gates/gate_multihash.py).

4.4.  Extensions and versioning

   The protected header carries naalp-version, which tracks the
   *envelope object grammar* -- the top-level numbered fields of naalp-
   object.  The rule is mechanical: adding or changing a top-level
   envelope field moves the version; adding an ext/cext key (a key
   inside the field-11 or field-12 maps) never does. naalp-version 1 was
   the previous version, which lacked the audience and suite fields;
   this document specifies *naalp-version 2*, anchored by two envelope
   additions -- the top-level audience field (field 13) and the suite
   field (field 14).  A verifier MUST reject an object whose naalp-
   version it does not support (UnsupportedVersion).

   audience (field 13, a text string) names the one endpoint or channel-
   scope identity an object is bound to.  It is omitted when empty, so a
   no-audience object encodes byte-identically to a naalp-version 1
   object and its content id is unchanged.  A _consume-once_ kind -- one
   whose acceptance spends a single-use ledger resource (the consume
   ledger, see Approval) -- MUST carry an audience naming its one
   consuming authority.  The audience is checked by that consuming
   authority at the moment it would spend the object, before the single-
   use compare-and-set and outside core object verification, so that an
   in-transit relay, ordering authority, or auditor can still verify an
   object addressed to someone else.  An object whose audience is not
   the checking authority -- or a consume-once object that omits it --
   is rejected WrongAudience, with no ledger entry and no state change
   (fail-closed).

   suite (field 14, a uint) is the signed selector for the object's
   signature suite.  It is PRESENT if and only if the object is signed
   with the opt-in composite algorithm (the composite COSE alg id in the
   private-use range, see Signing) and ABSENT for a pure ML-DSA object,
   so a pure object encodes byte-identically to a naalp-version 1 object
   carrying neither field 13 nor field 14 and its content id is
   unchanged.  Value 1 selects the COMPSIG-MLDSA65-Ed25519-SHA512
   composite suite (Public/Enterprise); value 2 is RESERVED for the ML-
   DSA-44 edge suite.  Because suite is a signed body field it cannot be
   stripped or altered without invalidating the signature; a suite value
   that disagrees with the COSE algorithm is rejected (SuiteMismatch).
   Turning the composite on, or changing the default suite in a later
   profile, is a suite-registry change, not a wire break.

Sammartano                Expires 10 March 2027                 [Page 8]
Internet-Draft                   N-AALP                   September 2026

   Field 11 (ext) carries non-critical extensions a verifier that does
   not recognize them MUST ignore.  Field 12 (cext) carries critical
   extensions a verifier that cannot honor them MUST reject the whole
   object (fail-closed).  Three extension keys are defined in this
   revision and ride this mechanism without moving the version.  Key 13
   (a key inside the ext/cext maps -- a distinct namespace from the top-
   level audience field 13), recheck, names by id the procedure a
   verifier runs to re-check the body claim, from a closed set -- 1
   recompute-content-id, 2 verify-cose-sign1, 3 walk-causes, 4 replay-
   consume-check; carried in ext an unrecognized id is ignored, in cext
   it is rejected fail-closed (UnknownCriticalExt).  Key 14, signer-
   counter, is an OPTIONAL forward-only per-signer position carried only
   in the non-critical ext map; it is a duplication-_detection_ aid,
   never a verification gate, and because ext is part of the signed
   payload it is covered by the signer's own signature.  Key 15,
   producing-boundary, is an OPTIONAL per-object disclosure of the trust
   boundary that produced the object and whether that boundary observed
   the described event first-hand or is relaying a report of it: a small
   map of boundary (a party identifier in the same bstr form as the
   object signer), kind (a closed enum -- 1 observed, 2 reported), and
   an OPTIONAL reporting-boundary (bstr) present only when kind is
   reported and absent under observed.  It rides the non-critical ext
   map, so a verifier that does not recognize it -- or reads a malformed
   value (no boundary, a kind outside the enum, or a reporting-boundary
   under observed) -- ignores the entry and the object still verifies;
   placing it in cext is an unrecognized critical key rejected fail-
   closed (UnknownCriticalExt).  Because ext is part of the signed
   payload the disclosure is covered by the signer's own signature: it
   is a claim the signer makes about itself, naming whose observational
   domain the object rests on and whether first-hand or relayed, and
   does not by itself establish that the named boundary is honest or
   that its clock is authoritative outside its own domain (# Security
   Considerations).  Higher channel tiers add capability by defining new
   kind codes and, at higher tiers, new ext/cext keys; the envelope
   grammar itself changes only with the version.

5.  Cryptographic Constructions

5.1.  Signing

   An object is signed with COSE_Sign1 [RFC9052] over the deterministic-
   CBOR object body as the payload.  The protected header carries the
   COSE algorithm and a pre-parse routing copy of the signer, profile,
   and protocol version under a text-string label.  A verifier MUST
   reject an object whose header signer/profile copies disagree with
   body fields 5 and 9 (HeaderBodyMismatch).  On the wire the object is
   a tagged COSE_Sign1 (CBOR tag 18).  The default and mandatory-to-
   implement signature is pure ML-DSA; a deployment MAY opt in to a

Sammartano                Expires 10 March 2027                 [Page 9]
Internet-Draft                   N-AALP                   September 2026

   hybrid, which is a single COSE_Sign1 (tag 18) whose signature value
   is one non-separable IETF LAMPS composite of an ML-DSA and an Ed25519
   signature -- not two separate signatures -- selected by the signed
   suite field (field 14, below).

   An N-AALP object's signature wrapper (naalp-signed-object) is
   therefore one of exactly two tagged COSE structures: the COSE_Sign1
   (tag 18) form above, or COSE_Sign (tag 98), a multi-signature form
   this revision uses for exactly two cases -- the OPTIONAL legacy two-
   signature Ed25519+ML-DSA hybrid (not required by the Standard
   profile; (# Security Considerations) discusses why the single-
   COSE_Sign1 composite above is preferred to it), and the Rotation
   object's co-signature (# Identity).  A COSE_Sign carries the same
   protected, unprotected, and payload positions as COSE_Sign1 plus a
   signatures array of two or more COSE_Signature elements, each an
   independent [protected, unprotected, signature] triple with its own
   per-signer protected header {1 => cose-alg}; this per-element header
   is distinct from the COSE_Sign body's own protected header.  The
   unprotected header position in both structures is the generic COSE
   header map ([RFC9052] Section 3); this revision defines no N-AALP-
   specific unprotected-header parameter.

5.2.  Algorithms and profiles

   The mandatory-to-implement signature algorithm is pure ML-DSA
   [FIPS204] using the deterministic variant (rnd = 0) so two
   implementations produce byte-identical signatures.  This determinism
   is a producer and cross-implementation-parity property, not a
   security requirement: [FIPS204] permits either the deterministic or
   the hedged (randomized) signing variant, and a production signer MAY
   use the hedged variant.  A conforming verifier MUST accept any
   signature that is valid under the object's declared algorithm and
   profile floor regardless of whether it was produced deterministically
   or with per-signature randomness; the deterministic variant is
   required only for generating the conformance corpus and its byte-
   identical cross-implementation vectors (# Conformance).  The
   composite's classical leg is Ed25519 [RFC8032] [RFC9864].  Within the
   COSE algorithm framework [RFC9053], the pure ML-DSA and Ed25519
   suites reuse the code points registered for ML-DSA [RFC9964] and
   Ed25519 [RFC9864]; the opt-in composite is named by a single COSE
   algorithm id in the COSE private-use range (integers < -65536), which
   N-AALP owns provisionally until IANA assigns a public composite code
   point, so adopting the eventual public id is a registry swap rather
   than a wire break.  Three profiles select a signature floor:

Sammartano                Expires 10 March 2027                [Page 10]
Internet-Draft                   N-AALP                   September 2026

             +============+=======+==========================+
             | profile    | value | signature floor          |
             +============+=======+==========================+
             | public     | 1     | ML-DSA-65 (NIST level 3) |
             +------------+-------+--------------------------+
             | enterprise | 2     | ML-DSA-65 (NIST level 3) |
             +------------+-------+--------------------------+
             | sovereign  | 3     | ML-DSA-87 (NIST level 5) |
             +------------+-------+--------------------------+

                                  Table 1

   The closed cose-alg identifiers this revision defines are: ml-dsa-44
   (-48, NIST level 2, reserved for an optional edge/light tier and
   never a Public/Enterprise/Sovereign default), ml-dsa-65 (-49, NIST
   level 3, the Public/Enterprise floor), ml-dsa-87 (-50, NIST level 5,
   the Sovereign floor), ed25519 (-19, classical, an opt-in composite
   leg only), compsig-mldsa65-ed25519 (-65537, the opt-in Public/
   Enterprise LAMPS composite above), and compsig-mldsa44-ed25519
   (-65538, an edge composite suite that is registered but not
   implemented in this revision).  An unrecognized algorithm identifier
   is rejected UnknownAlg.

   A verifier for a profile MUST reject a signature below the profile's
   floor (ProfileDowngrade) and an unknown algorithm (UnknownAlg).  The
   opt-in Ed25519+ML-DSA composite is a single COSE_Sign1 whose LAMPS
   composite value is valid only when both components verify against the
   shared message representative; because the two components are bound
   into one non-separable value, a stripped-leg object has no valid
   signature at all (the strongest level of the LAMPS composite non-
   separability spectrum: strong non-separability with simultaneous
   verification).  A signed suite field (field 14) that disagrees with
   the signature algorithm is rejected (SuiteMismatch), and a Sovereign
   verifier refuses a composite object outright (CompositeRefused),
   since Sovereign signs with pure ML-DSA-87 and carries no classical
   leg.  Digests use SHA-384 [FIPS180].

   The public and enterprise profiles carry an identical object-
   signature floor: both require ML-DSA-65 (NIST level 3), both permit
   the opt-in composite, and both use SHA-384 digests.  They are not
   distinguished by object cryptography.  The distinction is one of
   deployment policy -- the confidential transport an object composes
   with: an enterprise deployment mandates the higher N-PAMP transport
   profile, while a public deployment MAY compose with either the
   Standard or the higher profile.  A verifier applies the same object-
   signature-floor check to both; the profile value records the
   deployment posture, not a different object-crypto strength.

Sammartano                Expires 10 March 2027                [Page 11]
Internet-Draft                   N-AALP                   September 2026

6.  Identity

   The signer id (object field 5) is self-certifying: multibase(base32,
   multihash(0x12, SHA-256(multicodec(mc, pubkey)))), identical in form
   to the N-PAMP PeerHandle, where mc is the key-type code: 0xed
   (ed25519-pub), 0x1211 (mldsa-65-pub), 0x1212 (mldsa-87-pub).  These
   three values are N-AALP's own normative constants for signer-id
   derivation (sourced from the multiformats table, 2026-08-19); a
   verifier MUST derive mc from exactly these three values, independent
   of the live upstream multiformats table (# Security Considerations).
   A verifier recomputes the id from the key and MUST reject a mismatch
   (SignerMismatch).  No certificate authority is involved.

   Key lifecycle records are signed with the same COSE crypto: a
   Rotation is co-signed by both the old and new key -- carried as a
   COSE_Sign (tag 98) structure whose two COSE_Signature elements are
   the old-key and new-key signatures (# Cryptographic Constructions); a
   Rotation encoded as a single-signature COSE_Sign1 (tag 18) is
   rejected RotationUnauthorized.  A Revocation is signed by the revoked
   key or a deployer-configured recovery key (a Revocation signed by
   neither is rejected, fail-closed); a foreign-identity link is cross-
   signed by the foreign identity's key.  Identity strings that carry
   human text MUST be Unicode NFC (NonNFC otherwise).  A receipt signed
   under a superseded key remains attributable to the durable identity
   thread across rotations.

7.  Effects and Authorization

   Every object carries, under signature, one value from a closed four-
   value effect vocabulary aligned 1:1 with the N-PAMP Bridge
   SafetyLabel: read_only (0), idempotent_write (1),
   non_idempotent_write (2), destructive (3).  The values form a lattice
   with destructive at the top.

   An unrecognized effect value MUST be treated as destructive and MUST
   NOT fail open.  Unlike a SafetyLabel that "describes intent and does
   not replace authorization", the N-AALP effect IS an authorization
   input: an endpoint grants a maximum effect (a capability) to an
   authenticated signer id, and an object is authorized only if its
   effect does not exceed the grant (EffectNotAuthorized otherwise).  No
   layer MUST treat transport metadata, a foreign header, or a client-
   supplied name as an authorization identity; the authorizing principal
   is the object's signature-verified signer id.

   An object MAY carry an optional signed safety label (a non-critical
   ext) { risk, scope }; it is an accountable claim attributable to the
   signer, not a guarantee that the content is safe.

Sammartano                Expires 10 March 2027                [Page 12]
Internet-Draft                   N-AALP                   September 2026

8.  Approval

   An Approval object binds, under signature, the content id of the
   exact canonical argument object it approves, so approving one action
   cannot authorize another (ApprovalMismatch if the args are mutated).
   It carries the approver signer id, the granted effect, an anti-replay
   nonce, and an expiry.

   The consume ledger is a durable, hash-chained set keyed by approval
   content id.  Consume is an atomic compare-and-set: the first consumer
   appends a ledger entry and wins; a second consume for the same
   approval id is rejected (AlreadyConsumed).  Atomicity is provided by
   a write-ahead log written before the acknowledgment and a single-
   writer-per-approval-id discipline; under concurrency exactly one
   consumer succeeds.  An approval past its expiry is rejected
   (ApprovalExpired).  An approval-required-but-not-granted outcome is a
   distinct signed non-success result, never a silent success or denial.

   The consume ledger is on the path for a single-use approval spend
   only, not for every object.  An object that consumes no approval -- a
   read-only object, or any object that is verified but not spent -- is
   checked from its own signed bytes with no ledger access, so ordinary
   verification stays available under partition.  Only the spend of an
   approval reaches the ledger; a partition that makes the ledger
   unreachable denies that spend fail-closed (# Security Considerations)
   and denies nothing else.  Placing the ledger on every object's path
   would make the protocol unavailable under partition for read-only and
   other non-spending objects, which this design specifically avoids.

   At the baseline tier, an executor that cannot reach the consume
   ledger SHALL deny the spend (fail-closed): local spend-and-reconcile-
   later is not a baseline behavior, and a consumer that spends locally
   while the ledger is unreachable is non-conforming.  Federated
   ordering over identical signed objects, which relaxes this at a
   bounded and stated cost, is a named higher tier only (# Audit, Causal
   Graph, and Ordering); see (# Security Considerations) for the
   exposure model that governs the higher tier.

Sammartano                Expires 10 March 2027                [Page 13]
Internet-Draft                   N-AALP                   September 2026

   Each consume is recorded as a hash-chained ledger entry: { seq, prev,
   approval_id, by }, where prev is the SHA-384 of the previous entry
   (the genesis prev is 48 zero bytes) and by is the consuming signer
   id; the head after an entry is SHA-384(entry), so editing any entry
   breaks the next entry's linkage and is detectable on replay
   (LedgerCorrupt).  This chaining format is what the single-writer-per-
   approval-id property above rests on as a mechanism, not merely an
   operational discipline: the write-ahead log persists an entry before
   acknowledging it, and the first-append-wins compare-and-set is what
   makes exactly one consumer's entry extend the chain for a given
   approval id, with every later append for that id rejected
   (AlreadyConsumed) rather than merely discouraged.

   Each consume also mints a *consume receipt* (naalp-consume-receipt),
   a wire object distinct from the ledger entry above: { ledger,
   approval_id, position }, signed by the consuming ledger's own key
   over exactly those bytes, and minted by the same first-append-wins
   compare-and-set -- the first consume of an approval id assigns
   exactly one position and mints exactly one receipt; a second consume
   mints nothing (AlreadyConsumed).  Because the position is under the
   ledger's own signature rather than the requester's, the requester
   cannot forge it, and the receipt is the normative, independently-
   verifiable artifact by which a third party detects a double spend
   without trusting either party to the spend.

   At the federated tier, cross-authority single-consume is specified by
   issuance-time audience binding, not by a mandated cross-authority
   consensus protocol: a consensus mechanism between ordering
   authorities is explicitly out of scope for this specification.  A
   consume-once object -- one whose acceptance spends this ledger --
   MUST carry a signed audience naming its one consuming authority (#
   Object Model); any authority other than the named one rejects it
   WrongAudience before consume logic runs, so an object addressed
   elsewhere can never reach this ledger's compare-and-set.  The
   residual case a partitioned federation still allows is the named
   authority's own ledger state forking -- two ledger-signed receipts
   issued against one approval id from divergent state.  Two such
   receipts contradict on comparison by any third party holding both,
   since neither party to the spend could have produced the other's
   ledger signature; this contradiction is ConsumeFork, the detected
   double spend, bounded in exposure by the spent approval's own expiry
   (# Security Considerations).

   The delivery guarantee this ledger provides therefore has a scope
   boundary, stated here explicitly.  On a single reachable authority
   the guarantee is prevention: exactly-once, by the compare-and-set
   above.  Across a federation the guarantee is weaker and is stated as
   such: a double consume remains a verifiable wire violation --

Sammartano                Expires 10 March 2027                [Page 14]
Internet-Draft                   N-AALP                   September 2026

   prevented before the fact by WrongAudience for any misdirected
   object, and detected after the fact by ConsumeFork for the residual
   same-authority fork -- never a consensus-based exactly-once
   guarantee, because this specification fixes invariants over signed
   bytes and does not mandate any cross-authority consensus topology.

   The approval object's full state machine -- pending, approved,
   consumed, expired, its timer, and the clock-skew rule governing
   not_after -- is specified normatively in (# Object State Machines).

9.  Audit, Causal Graph, and Ordering

   An ordering authority records each accepted object by appending a
   signed Receipt { prev, obj, seq, at } where prev is the SHA-384 of
   the previous receipt body (genesis is zero) and obj is the object
   content id.  The chain is tamper-evident: reordering, omission, or
   substitution breaks a prev link or a seq (ChainBroken).  The
   authority MUST NOT mutate the origin object to order it; ordering is
   an outer signed layer.

   Every object MAY name its causes by content id (field 8).  This is a
   signed partial order: an edge "A causes B" is proven by B's signature
   over A's content id, checkable offline with no ordering authority
   present.  An object MUST NOT name a cause it could not have seen (a
   cause whose ordering position exceeds the effect's, or a cycle),
   which is rejected (CausalViolation).  A total order is a policy
   layered over this partial order.

   A receiver applies the causal graph, not merely stores it: a receiver
   SHALL NOT apply an object's effect before it has applied the effects
   of that object's already-received causes (the causes named by content
   id in field 8).  An object naming a cause the receiver has not yet
   received is held *pending* -- a state distinct from CausalViolation
   -- for a bounded interval: the receiver neither applies nor rejects
   it.  It is resolved when the named cause is applied, which lifts the
   hold, or by timeout once the bounded interval elapses, which rejects
   the object.  Pending and CausalViolation answer different questions:
   CausalViolation is a cause the object could not have seen -- a
   future-cause or a cycle -- and is rejected outright and immediately;
   pending is a cause the receiver has simply not received yet, which
   gives the receiver no basis to reject the object, so an object is
   never rejected merely for arriving before a cause that is itself
   still in flight.  The bound on the hold interval is a timer value,
   fixed normatively by this document's per-object-kind timer
   specification.

Sammartano                Expires 10 March 2027                [Page 15]
Internet-Draft                   N-AALP                   September 2026

   An independent auditor detects equivocation -- two receipts by one
   authority at one seq naming different objects -- from the signed
   receipts alone (Equivocation) and expresses the finding as a non-
   repudiable ForkProof carrying the accused authority's own two
   signatures over the two conflicting receipt bodies, plus an external
   counter binding the proof against replay or reorder.  A verifier
   accepts a ForkProof only when the signer is named, the two receipts
   share one seq, name different objects, and both signatures verify
   under the accused key, and rejects it whole otherwise
   (ForkProofInvalid, or ReceiptUnsigned for a signature that does not
   verify).  This is a draft-01 change (it supersedes draft-00's
   signatureless fork proof, which an accused could repudiate).  A
   receipt whose signature does not verify is rejected
   (ReceiptUnsigned).

   Ordering is tiered.  The baseline tier is a single authority's
   monotonic receipt chain.  The higher tier is federated: multiple
   independent authorities each order their own scope, and a signed
   Reconcile object records their deterministic merge.  Because both
   tiers order the identical signed objects, moving to federated
   ordering requires no envelope change.

   The federated merge SHALL produce a deterministic total order: a
   topological linearization of the union of the per-authority causal
   graphs above (the signed partial order over field 8), with ties --
   pairs the causal graph does not order relative to each other --
   broken by object content id in bytewise ascending order.  The tie-
   break is fixed by this document, not left to an implementation's
   choice: because the linearization depends only on the union causal
   graph and this fixed tie-break, and not on which authority reconciles
   first or the order the objects arrived in, two conforming reconcilers
   reconciling the identical set of objects SHALL produce the identical
   total order.

   The receive-side pending-cause hold introduced above, the federated
   reconcile machine, and their timers are specified normatively in (#
   Object State Machines).

10.  Delivery

   Delivery is four distinct, monotonic, separately-observable stages,
   each a signed delivery update naming the object content id and the
   stage reached: persisted_origin (0), accepted_relay (1),
   persisted_target (2), presented (3).  There is no single "sent" flag.
   An endpoint MUST durably persist an object before emitting the
   acknowledgment that advances its stage (persist-before-acknowledge),
   so a crash immediately after an acknowledgment loses nothing.  A
   stage earlier than the one already reached is rejected

Sammartano                Expires 10 March 2027                [Page 16]
Internet-Draft                   N-AALP                   September 2026

   (StageOutOfOrder).  A relay that holds an object only in transit MAY
   write an audit trail over content ids while retaining no payload.

   The full delivery state machine, including the idempotent-repeat and
   legal-skip cases and its stage-advance timer, is specified
   normatively in (# Object State Machines).

11.  Streaming

   A native stream is three signed objects plus unsigned chunks.
   StreamOpen binds the stream identity, effect, and (where it causes an
   effect) approval; a stream whose effect is not authorized is refused
   before any chunk.  Chunks are raw data frames; they are not
   individually signed.  Per-chunk authentication before StreamCommit is
   a property of the specific transport in use, not of the N-AALP
   object: over N-PAMP, the Stream channel's AEAD authenticates every
   chunk to the peer (# Transport Bindings); over a transport without an
   equivalent per-frame guarantee, a chunk consumed before StreamCommit
   is unauthenticated at the object layer.  StreamCommit carries a
   single rolling SHA-384 over the chunks in absolute-offset order,
   making the whole stream non-repudiable with one signature; altering
   any delivered byte invalidates it (StreamDigestMismatch).  This
   rolling digest, together with any optional signed StreamCheckpoint,
   is the object-level mechanism that binds the chunk sequence,
   transport-independent and identical across N-PAMP and non-N-PAMP
   transports.  A StreamCheckpoint confirms only a contiguous prefix
   through its stated offset, never the stream's end.  The same three
   objects map onto QUIC streams, WebSocket messages, and HTTP chunked/
   event streams; the commitment verifies identically across transports.

   The full stream state machine, including the illegal-reuse cases
   after StreamCommit, is specified normatively in (# Object State
   Machines).

12.  Object State Machines

   This section collects the normative event x state tables governing
   the four N-AALP objects whose correct handling depends on accumulated
   history rather than being decidable from one signed object in
   isolation: delivery (# Delivery), streaming (# Streaming), approval
   (# Approval), and the reconcile record (# Audit, Causal Graph, and
   Ordering).  Each table is total: every (state, event) pair a
   conforming implementation can encounter resolves to exactly one
   Reaction, either a transition to a next state (-> NextState) or a
   rejection under a named error (reject (ErrorName)).  A (state, event)
   pair not listed in a table is rejected under that table's stated
   default error, so no combination is left undefined.  Every rejection
   under these machines is fail-closed: the triggering object is refused

Sammartano                Expires 10 March 2027                [Page 17]
Internet-Draft                   N-AALP                   September 2026

   whole, its named error is returned, and no state change occurs.
   Every transition below presupposes the triggering object has already
   passed the envelope-layer checks -- signature verification and
   content-id recomputation (# Cryptographic Constructions, # Object
   Model) -- before this table is consulted; an envelope-layer failure
   (BadSignature, ContentIdMismatch) is rejected there and never reaches
   these tables.

12.1.  Delivery state machine

   The delivery machine (# Delivery) has states persisted_origin,
   accepted_relay, persisted_target, and presented, ordered 0 through 3.
   Its one event is a delivery update reporting a stage S'; relative to
   the machine's current state (the highest stage already reached for
   the object), the update is classified advance(S') when S' is strictly
   greater than the current stage, repeat(S') when S' equals it, and
   regress(S') when S' is strictly less than it. advance(S') transitions
   directly to S', not merely to the next stage in sequence: a stage MAY
   be skipped (for example a relay-less delivery path observing
   persisted_origin followed directly by persisted_target, with no
   accepted_relay in between), because skipping a stage is not a
   regression -- only regress(S') is. repeat(S') -- the same stage
   reported a second time, such as a redelivered acknowledgment -- is
   accepted idempotently and leaves the state unchanged; it is not an
   error and produces no new observable state.

Sammartano                Expires 10 March 2027                [Page 18]
Internet-Draft                   N-AALP                   September 2026

       +==================+=============+==========================+
       | State            | Event       | Reaction                 |
       +==================+=============+==========================+
       | persisted_origin | advance(S') | -> S'                    |
       +------------------+-------------+--------------------------+
       | persisted_origin | repeat(S')  | -> persisted_origin      |
       +------------------+-------------+--------------------------+
       | accepted_relay   | advance(S') | -> S'                    |
       +------------------+-------------+--------------------------+
       | accepted_relay   | repeat(S')  | -> accepted_relay        |
       +------------------+-------------+--------------------------+
       | accepted_relay   | regress(S') | reject (StageOutOfOrder) |
       +------------------+-------------+--------------------------+
       | persisted_target | advance(S') | -> presented             |
       +------------------+-------------+--------------------------+
       | persisted_target | repeat(S')  | -> persisted_target      |
       +------------------+-------------+--------------------------+
       | persisted_target | regress(S') | reject (StageOutOfOrder) |
       +------------------+-------------+--------------------------+
       | presented        | repeat(S')  | -> presented             |
       +------------------+-------------+--------------------------+
       | presented        | regress(S') | reject (StageOutOfOrder) |
       +------------------+-------------+--------------------------+

                                  Table 2

   The machine's initial state for an object is established by that
   object's first delivery update: the first update records the stage it
   reports and cannot regress, because no earlier stage has yet been
   reached for that object; the table above governs every update after
   the first.

   Any (state, event) pair not listed above is rejected with
   StageOutOfOrder.

12.2.  Stream state machine

   The stream machine (# Streaming) has states idle (no stream open for
   this stream id), open, committed, and abandoned (a terminal state an
   open stream enters when its idle/commit timer expires; see # Timers),
   and events StreamOpen, chunk, StreamCheckpoint, and StreamCommit.

Sammartano                Expires 10 March 2027                [Page 19]
Internet-Draft                   N-AALP                   September 2026

        +===========+====================+========================+
        | State     | Event              | Reaction               |
        +===========+====================+========================+
        | idle      | StreamOpen (effect | -> open                |
        |           | authorized)        |                        |
        +-----------+--------------------+------------------------+
        | idle      | StreamOpen (effect | reject                 |
        |           | not authorized)    | (EffectNotAuthorized)  |
        +-----------+--------------------+------------------------+
        | open      | chunk              | -> open                |
        +-----------+--------------------+------------------------+
        | open      | StreamCheckpoint   | -> open                |
        +-----------+--------------------+------------------------+
        | open      | StreamCommit       | -> committed           |
        |           | (digest matches)   |                        |
        +-----------+--------------------+------------------------+
        | open      | StreamCommit       | reject                 |
        |           | (digest mismatch)  | (StreamDigestMismatch) |
        +-----------+--------------------+------------------------+
        | open      | StreamOpen         | reject                 |
        |           |                    | (StreamStateError)     |
        +-----------+--------------------+------------------------+
        | committed | chunk              | reject                 |
        |           |                    | (StreamStateError)     |
        +-----------+--------------------+------------------------+
        | committed | StreamCheckpoint   | reject                 |
        |           |                    | (StreamStateError)     |
        +-----------+--------------------+------------------------+
        | committed | StreamCommit       | reject                 |
        |           |                    | (StreamStateError)     |
        +-----------+--------------------+------------------------+
        | abandoned | StreamOpen         | reject                 |
        |           |                    | (StreamStateError)     |
        +-----------+--------------------+------------------------+
        | abandoned | chunk              | reject                 |
        |           |                    | (StreamStateError)     |
        +-----------+--------------------+------------------------+
        | abandoned | StreamCheckpoint   | reject                 |
        |           |                    | (StreamStateError)     |
        +-----------+--------------------+------------------------+
        | abandoned | StreamCommit       | reject                 |
        |           |                    | (StreamStateError)     |
        +-----------+--------------------+------------------------+

                                  Table 3

Sammartano                Expires 10 March 2027                [Page 20]
Internet-Draft                   N-AALP                   September 2026

   Any (state, event) pair not listed above is rejected with
   StreamStateError, which names a stream-state violation: an object
   arriving for a stream whose current state does not admit it -- a
   second StreamOpen on an already-open stream, or any chunk,
   StreamCheckpoint, or StreamCommit after the stream has committed or
   been abandoned.  A committed or abandoned stream id is terminal: it
   is never re-admitted, so a StreamOpen naming it is rejected
   StreamStateError rather than opening a fresh stream.  A chunk that
   exceeds its granted flow-control credit is refused at the transport,
   not the object, layer (NPAMP-STREAM FlowControlError, # Transport
   Bindings): that rejection is a property of the specific transport in
   use and is distinct from the state-machine violations in this table,
   which apply uniformly across every transport binding.

12.3.  Approval state machine

   The approval machine (# Approval) has states pending, approved,
   consumed, and expired, and events approve, consume, and expiry (the
   passing of not_after; see Clock skew and validity windows, below).
   ApprovalHeld is not a fifth state: it is the distinct signed non-
   success result an action requiring this approval receives while the
   machine is in pending, never a silent success or denial.  An action
   requiring an approval for which no Approval object naming its exact
   args has ever been signed is refused ApprovalRequired at the point of
   use, independent of this table.

             +==========+=========+==========================+
             | State    | Event   | Reaction                 |
             +==========+=========+==========================+
             | pending  | approve | -> approved              |
             +----------+---------+--------------------------+
             | approved | consume | -> consumed              |
             +----------+---------+--------------------------+
             | approved | expiry  | -> expired               |
             +----------+---------+--------------------------+
             | consumed | consume | reject (AlreadyConsumed) |
             +----------+---------+--------------------------+
             | expired  | consume | reject (ApprovalExpired) |
             +----------+---------+--------------------------+

                                  Table 4

   An args-content-id mismatch -- the presented args do not hash to the
   content id the Approval object binds -- is rejected ApprovalMismatch
   regardless of state and takes precedence over every cell in this
   table, because content binding is checked before any state-dependent
   reaction is evaluated.  Where an approval is both past not_after and
   already present in the consume ledger, expiry takes precedence over

Sammartano                Expires 10 March 2027                [Page 21]
Internet-Draft                   N-AALP                   September 2026

   consumption: a consume request MUST be checked against not_after
   before the ledger is consulted, so such a request is rejected
   ApprovalExpired, never AlreadyConsumed, and the ledger is left
   untouched by the rejected request.

   Any (state, event) pair not listed above is rejected with
   ApprovalRequired.

12.4.  Reconcile state machine

   The reconcile machine (# Audit, Causal Graph, and Ordering) governs
   the production of one federated Reconcile record.  States: collecting
   (per-authority receipt chains are being gathered), linearized (the
   deterministic total order has been computed), verified.  Events: add-
   chain (a per-authority receipt chain is added to the merge),
   linearize (the deterministic linearization is computed over the
   accumulated chains), verify (an independent recomputation is compared
   against a claimed total order).

   +============+===============================+=====================+
   | State      | Event                         | Reaction            |
   +============+===============================+=====================+
   | collecting | add-chain (valid link, no     | -> collecting       |
   |            | equivocation)                 |                     |
   +------------+-------------------------------+---------------------+
   | collecting | add-chain (broken prev/seq    | reject              |
   |            | link)                         | (ChainBroken)       |
   +------------+-------------------------------+---------------------+
   | collecting | add-chain (two receipts, one  | reject              |
   |            | seq, different objects)       | (Equivocation)      |
   +------------+-------------------------------+---------------------+
   | collecting | add-chain (receipt signature  | reject              |
   |            | does not verify)              | (ReceiptUnsigned)   |
   +------------+-------------------------------+---------------------+
   | collecting | linearize (union causal graph | -> linearized       |
   |            | acyclic, no future-cause)     |                     |
   +------------+-------------------------------+---------------------+
   | collecting | linearize (cycle or future-   | reject              |
   |            | cause in the merged graph)    | (CausalViolation)   |
   +------------+-------------------------------+---------------------+
   | linearized | verify (independent           | -> verified         |
   |            | recomputation agrees)         |                     |
   +------------+-------------------------------+---------------------+
   | linearized | verify (independent           | reject              |
   |            | recomputation disagrees)      | (ReconcileMismatch) |
   +------------+-------------------------------+---------------------+

                                 Table 5

Sammartano                Expires 10 March 2027                [Page 22]
Internet-Draft                   N-AALP                   September 2026

   ReconcileMismatch is the one new error name this section introduces:
   a verifier that independently re-runs the deterministic linearization
   (# Audit, Causal Graph, and Ordering) over the identical set of
   objects and obtains a total order different from the one the
   Reconcile record claims has found a violation of the fixed
   determinism property that section states, and rejects the record
   whole.

   Any (state, event) pair not listed above is rejected: a fault in an
   individual per-authority receipt chain is rejected under its own
   already-registered name (ChainBroken, Equivocation, or
   ReceiptUnsigned), a cycle or future-cause in the merged causal graph
   is rejected CausalViolation, and a disagreeing linearization is
   rejected ReconcileMismatch.

12.5.  Timers

   Every timer named in this section has a name, a start condition, a
   clear condition, and a named reaction on expiry.  This document
   specifies each timer's behavior but not its duration: the interval a
   timer runs for is a deployment and local-policy parameter, and no
   timer in this section carries a protocol-mandated default duration.
   The hard numeric bounds this document does impose on the wire -- the
   per-stream chunk-count limit (TooManyChunks, # Streaming) and the
   decoder resource limits in the CDDL (# Collected CDDL) -- are stated
   where they are enforced, not here.

   Delivery stage-advance timer:  starts when a delivery update advances
      an object's state to any stage before presented; clears when a
      later update reports presented (or, per the Delivery table above,
      a repeat or a further advance) for the same object; on expiry, the
      stalled delivery is reported to the sender as undelivered
      (NotDelivered) without changing the object's last durably-recorded
      stage -- expiry ends the wait, not the recorded progress.

   Stream idle/commit timer:  starts when a StreamOpen transitions the
      stream machine to open; clears when a StreamCommit transitions it
      to committed; on expiry, the stream transitions open -> abandoned
      and is rejected StreamStateError. abandoned is terminal (# Object
      State Machines): no later chunk, StreamCheckpoint, or StreamCommit
      for the stream is admitted, and its stream id MUST NOT be reopened
      -- a StreamOpen naming an abandoned id is rejected
      StreamStateError, never re-admitted as a fresh stream.  No chunk
      delivered without an eventual StreamCommit is non-repudiable (#
      Streaming), so an abandoned stream commits nothing.

   Approval not_after timer:  starts when an Approval object is signed;

Sammartano                Expires 10 March 2027                [Page 23]
Internet-Draft                   N-AALP                   September 2026

      clears when the approval is consumed (# Approval) while still
      valid; on expiry, the approval transitions approved -> expired per
      the Approval table above, and any further consume is rejected
      ApprovalExpired.

   Pending-cause hold timer:  starts when an object is received naming a
      cause (# Audit, Causal Graph, and Ordering) the receiver has not
      yet received, putting the object into the held pending state
      described there; clears when the named cause is applied, which
      lifts the hold and allows the held object's own effect to be
      applied; on expiry, the held object is rejected and its effect is
      never applied.  This timer is the bounded interval that section
      states the pending-cause hold is "resolved ... by timeout once the
      bounded interval elapses."

12.6.  Clock skew and validity windows

   An Approval's not_after (# Approval) is judged against the action's
   authoritative ordering position -- its receipt seq/at where a receipt
   exists (# Audit, Causal Graph, and Ordering) -- and, only where no
   receipt yet exists for the action, its advisory created timestamp
   stands in as the best available position for this one purpose (#
   Object Model); this narrow fallback does not make created reliable
   ordering evidence for any other purpose (# Security Considerations).
   In neither case is validity judged against any participant's own wall
   clock: there is exactly one clock in this check -- the authoritative
   ordering position -- so wall-clock skew between the approver, the
   consumer, and any relay never enters the determination of whether
   not_after has passed.  This document does not define a numeric clock-
   skew tolerance: a validity check is a single deterministic comparison
   against one authoritative position, not a comparison between two
   participants' clocks, so no tolerance is required by this design, and
   none is introduced.

12.7.  Cancel

   A cancel object -- TaskCancel (0x0011/2), Cancel (0x000E/3), or a
   channel-specific cancel object elsewhere in (# Channel Surfaces) --
   MUST propagate a real abort to the work it names: an implementation
   that flips a status field to a canceled state without actually
   stopping the underlying work has not canceled it, and reporting the
   canceled status in that condition is a false report and is non-
   conforming.  Once an object's status has reached a terminal canceled
   state, no later transition MAY leave it: a terminal-absorbing guard
   MUST ensure that a status update completing the same work after
   cancellation (for example a late completed transition arriving after
   canceled) is dropped, not applied, so a race between an abort and an
   in-flight completion can never overwrite the canceled outcome.  This

Sammartano                Expires 10 March 2027                [Page 24]
Internet-Draft                   N-AALP                   September 2026

   is the general terminal-state rule already stated elsewhere for an
   imported task lifecycle -- a terminal state has no out-edge and no
   transition may leave it -- applied here to cancellation specifically;
   it is not a new rule.

12.8.  Deadline

   Effecting objects are time-bounded today by their required approval's
   not_after, judged at the action's authoritative ordering position as
   stated above (# Approval).  A distinct, per-object signed deadline
   field is out of scope for this revision and is noted here for a
   future revision.

13.  Transport Bindings

   A binding carries exactly one signed object as one message unit, with
   identical object semantics over N-PAMP, QUIC, WebSocket, and HTTP.
   The object is self-secured; the binding adds only framing and, from
   the transport, confidentiality and connection authentication.  The
   media type is application/vnd.bubblefish.naalp+cbor (one object per
   representation).

   The confidentiality boundary is normative: an object marked sensitive
   MUST NOT be emitted in cleartext over a non-confidential transport;
   the binding refuses it (ConfidentialTransportRequired) and directs
   the deployment to a confidential transport.  A transport lacking peer
   authentication where policy requires it is refused
   (PeerUnauthenticated).

14.  Foreign Carriage by Class

   N-AALP carries a foreign agent protocol by wrapping its message,
   octet-for-octet, in a signed carriage object interpreted by a
   carriage class:

   naalp-carriage-body = {
     1 : uint,      ; protocol_id (N-AALP protocol registry)
     2 : carriage-class,   ; 0 JSONRPC .. 5 OPAQUE
     3 : uint,      ; content_type (foreign encoding)
     4 : bstr,      ; correlation token
     5 : tstr,      ; method (advisory routing key)
     6 : bstr,      ; foreign message, carried octet-for-octet
   }
   carriage-class = &( jsonrpc:0, http:1, msg:2,
                       stream:3, doc:4, opaque:5 )

Sammartano                Expires 10 March 2027                [Page 25]
Internet-Draft                   N-AALP                   September 2026

   The foreign field is carried verbatim and MUST NOT be re-serialized,
   canonicalized, summarized, or rewritten.  For every carriage class,
   N-AALP treats the foreign message as opaque octets: it never decodes
   or parses the foreign payload, and it binds those octets by hash
   under the carriage object's content id and signature.  A verifier
   checks the payload by recomputing that content id over the carried
   bytes, never by interpreting the foreign format, so a tampered
   payload is rejected on the content-id check before any foreign parser
   could run.  This rule is normative for every carriage class -- each
   foreign binding is carriage by class, so no binding adds a foreign-
   format parser to the verify path.  The carriage object's signer
   remains the authority: a foreign protocol's identity, header, or
   metadata MUST NOT become an N-AALP authorization identity.  The
   OPAQUE class carries any protocol, including an undefined one, on an
   experimental protocol id with no registration.  A below-foreign
   failure uses a defined structured error and MUST NOT report an
   undelivered message as delivered; an N-AALP semantic a foreign
   protocol cannot represent surfaces a typed mapping error, never a
   silent drop.

15.  Channel Surfaces

   N-AALP defines twenty channel surfaces (channel ids 0x0000..0x0013):
   Control, Memory, Capability, Identity, Governance, Immune,
   Federation, Settlement, Compliance, Sensory, Telemetry, Audit,
   Stream, Bridge, Commerce, Interaction, Discovery, Workflow,
   Knowledge, and Spatial.  Each surface adds only object kind codes and
   their declared effects over the one object model; it introduces no
   channel-local encoding, signature, or identity.  Every channel has a
   complete frozen baseline surface.  Higher tiers add capability under
   the frozen envelope through the tier field and critical/non-critical
   extensions.  The complete kind/effect table is the N-AALP Channel and
   Object Kind registries (# IANA Considerations).

16.  Additive Object Families

   This section documents the higher-tier (tier 1+) object families this
   revision adds.  None of them introduces a new envelope field,
   encoding, signature form, identity mechanism, or effect value: each
   family reuses the frozen naalp-object envelope (# Object Model), the
   closed effect lattice (# Effects and Authorization), the content-id
   framing (# Object Model), and, where a family is receipt-chained, the
   audit receipt chain construction unchanged (# Audit, Causal Graph,
   and Ordering).  A baseline verifier that has not licensed a family's
   tier rejects its kind as UnknownKind (# Object Model), consistent
   with the tier model (# Object Model, # Channel Surfaces).  Every
   capability in this section carries experimental status under the
   tiering rule of (# Conformance): it is OPTIONAL, and an

Sammartano                Expires 10 March 2027                [Page 26]
Internet-Draft                   N-AALP                   September 2026

   implementation that omits it is still conforming.

16.1.  Collaboration and Rooms Membership

   A room's membership is a first-class signed object, not implicit
   connection state.  A membership change is carried as a naalp-room-op
   -- a naalp-object whose body (field 10) is { room, op, epoch,
   subject, role } -- on the Governance channel (0x0004). op selects one
   of the closed room-op-code operations: create (0), add_member (1),
   remove_member (2), change_role (3), or add_owner (4). subject (the
   affected member's signer id) MUST be Unicode NFC (NonNFC otherwise).
   role is one of the closed member-role values: member (0), admin (1),
   or owner (2).

   A room-op object is CURSOR-OCCUPYING and RECEIPT-CHAINED: each
   accepted op is ordered at a cursor by an ordering authority's naalp-
   receipt over the op's content id, weaving membership into the append-
   only audit chain (# Audit, Causal Graph, and Ordering) the same way
   any other object is ordered.  It is EPOCH-BUMPING: epoch carries the
   membership epoch the op is built against, and each accepted op
   increments the room's epoch; an op built against a superseded epoch
   is rejected StaleEpoch.  Ownership is multi-owner and ADD-ONLY:
   add_owner adds an owner, but an owner is never removed (remove_member
   naming an owner is rejected OwnerImmutable) and never demoted
   (change_role refusing to lower an owner's role is rejected
   RoleInvalid), so a room's owner count is monotonically at least one
   and a room can never become ownerless. remove_member naming an
   unknown member, or add_member/change_role naming an already-present
   or already-absent member as the operation requires, is rejected
   MemberExists or MemberUnknown as appropriate; an op whose fields do
   not match its declared op code is RoomOpMismatch; an op value outside
   the closed set is OpUnknown.

Sammartano                Expires 10 March 2027                [Page 27]
Internet-Draft                   N-AALP                   September 2026

   A naalp-principal-binding maps a stable semantic principal id to a
   durable Handle (a signer id): { principal, handle, epoch, prev }.
   principal MUST be Unicode NFC.  It is kept as a per-principal SHA-384
   hash chain -- prev carries the prior binding's head (48 bytes;
   genesis is 48 zero bytes) -- the same chaining shape as the audit
   receipt chain and the consume ledger, so an omitted or substituted
   binding is detectable the same way.  A delivery addresses the
   semantic principal id and resolves it to the Handle at send time: a
   durable naming layer above a connection-scoped peer handle.  A rebind
   (a new binding for an already-bound principal) is authorized only by
   a verified rotation from the current Handle to the new one; a rebind
   naming an unrelated key is rejected RebindUnauthorized.  Binding a
   principal id already bound is PrincipalExists; resolving an unbound
   principal is PrincipalUnknown.  The membership op-authorization,
   epoch guard, owner-immutability, and rebind-continuity rules above
   are endpoint behaviors graded against the non-circular oracle, not
   wire productions in their own right.

16.2.  Multi-Hop Delegation Grant

   A naalp-delegation-grant is a normal naalp-object -- an independent
   COSE_Sign1 whose issuer is the verified envelope signer (field 5),
   never a body field -- carried as Capability-channel (0x0002) kind
   DelegationGrant (kind 4), tier 1.  The object's own envelope effect
   (field 7) is non_idempotent_write (issuing a grant); the body's
   effect_cap field is a SEPARATE ceiling the grant confers on its
   subject, never the object's own effect.  The body is { subject,
   effect_cap, max_depth, not_before, not_after, ?scope }: subject (the
   delegatee's signer id) MUST be Unicode NFC; effect_cap (the closed
   effect lattice) MUST NOT exceed the parent grant's own ceiling, else
   CapExceedsParent; max_depth bounds how many FURTHER delegation hops
   are permitted below this grant (0 means the subject may act but not
   re-delegate); not_before/not_after bound the grant's validity window
   (GrantNotYetValid / GrantExpired); the OPTIONAL scope (Unicode NFC
   when present) narrows the grant to a resource scope that a child
   grant's scope MUST be contained within, else CapExceedsParent.

   A DelegationGrant reuses the existing Capability-channel delegation
   substrate rather than a parallel mechanism: its delegation parent is
   named by content id in the envelope's causes field (# Object Model)
   as the UNIQUE cause resolving to a Capability authority object
   (CapIssue, CapDelegate, or another DelegationGrant) whose subject/
   holder equals this grant's issuer.  A root grant -- one whose issuer
   is in the verifier's trust-anchor set -- names no such cause; a grant
   naming two or more is rejected ChainBroken.  A malformed grant body
   is GrantMalformed; a grant whose chain of authority does not
   terminate at a trusted root is UntrustedChainRoot; a chain exceeding
   the accumulated max_depth bound is DelegationDepthExceeded; a revoked

Sammartano                Expires 10 March 2027                [Page 28]
Internet-Draft                   N-AALP                   September 2026

   grant is GrantRevoked.  The invariant that delegated authority only
   ever shrinks across every hop -- on effect, scope, and depth -- is
   stated as a closure-sovereignty property in (# Security
   Considerations).

16.3.  MCP Tool-Call Binding

   An MCP (Model Context Protocol) tool call is CARRIED, not adopted:
   its bytes are unchanged, and its unenforced, untrusted annotation
   hints are mapped to the closed four-value effect lattice by a
   published table for which the wrapping signer is accountable -- a
   false declaration is attributable to that key.  The wrapper (naalp-
   mcp-tool-call) is a Bridge-channel (0x000D) tier-1 kind McpToolCall
   (kind 1), a named escalation over the frozen baseline Carriage kind
   (0, # Foreign Carriage by Class) under the unchanged envelope.  Its
   body is { tool, args, annotations }: tool and args carry the MCP tool
   definition and call-argument bytes octet-for-octet (never re-
   serialized); annotations (naalp-mcp-annotations) is the wrapping
   signer's transcription of the tool's MCP ToolAnnotations.

   The object's own envelope effect (field 7) is the wrapping signer's
   DECLARED effect.  A verifier independently recomputes the annotation-
   derived effect from the carried annotations and enforces the MORE
   SEVERE of the two values -- an unknown or disagreeing input collapses
   UP, never down.  A declared effect below the annotation-derived
   effect is rejected EffectUnderDeclared; an annotation set that maps
   outside the closed lattice is rejected MalformedAnnotation, never
   defaulted to benign.  Each annotation field (readOnlyHint,
   destructiveHint, idempotentHint, openWorldHint) is an OPTIONAL mcp-
   hint -- the uint 1 (true) or 0 (false); a value outside {0,1}
   transcribes no boolean and is rejected.  MCP is boolean-typed in JSON
   but the N-AALP spine carries no CBOR boolean, so an ABSENT hint takes
   the MCP-documented default: readOnlyHint false, destructiveHint TRUE
   (the fail-closed default, matching the "absent effect on a state-
   changing object defaults to destructive" rule), idempotentHint false,
   openWorldHint true.  A present 0 and an absent hint therefore encode
   to DIFFERENT bytes even where they resolve to the same effect.
   openWorldHint is carried for accountability only -- it is an ADVISORY
   risk signal that never enters the effect lattice.

   naalp-mcp-call-binding ({ tool_id, args_id }) is the value an
   approval binds: tool_id and args_id are the content ids of the tool
   and argument bytes respectively.  Because the binding names BOTH the
   tool description and the arguments by content id, a changed tool
   description or a changed argument set yields a different call content
   id, invalidating a prior approval bound to the old one.  A malformed
   tool-call body is ToolCallMalformed.

Sammartano                Expires 10 March 2027                [Page 29]
Internet-Draft                   N-AALP                   September 2026

16.4.  Description and Directory

   A signed, OFFLINE-VERIFIABLE description and discovery layer, carried
   on N-AALP's own signed object: the authority is the SIGNATURE OVER
   THE BYTES, never the connection or host that served them, so a signed
   description re-verifies byte-identically when an unrelated host
   serves the same bytes (a bearer credential, not a fetched document).
   A naalp-description ({ service, operations }) lists a service's
   operations, each a naalp-description-operation ({ name, effect,
   requires_approval }) carrying its effect (the closed lattice) and an
   approval declaration: requires_approval (desc-approval-flag, the uint
   1/0 -- the spine carries no CBOR boolean) outside {0,1} is rejected
   MalformedApprovalFlag.

   A naalp-directory ({ directory, version, members }) is a signed
   collection whose members are content ids (the same list-of-content-
   ids shape the causal partial order uses), carrying a monotonic per-
   signer version so two versions can be compared.  Two conflicting
   versions from ONE signer -- the SAME directory and version but
   DIFFERENT members -- are a FORK, detected at the FIRST-DIFFERING
   member position and reported DirForkProofInvalid, the same way the
   audit ForkProof reports the position of an equivocation (# Audit,
   Causal Graph, and Ordering).

   A naalp-description-import ({ importer, format, foreign, operations
   }) carries a FOREIGN description format -- an A2A Agent Card, an ANP
   Agent Description, or an AGNTCY Agent Badge, selected from the closed
   naalp-description-format registry (a2a-agent-card 1, anp-agent-
   description 2, agntcy-agent-badge 3; an unrecognized value is
   UnknownDescriptionFormat) -- octet-for-octet in foreign (carriage,
   not adoption: the foreign bytes MUST NOT be re-serialized,
   canonicalized, or rewritten) as a signed attestation binding the
   foreign bytes' content id AND an N-AALP effect mapping (operations)
   for the described operations. importer is the wrapping signer id and
   is the SOLE authorization identity: a verifier recomputes the self-
   certifying signer id from the verifying key and requires importer to
   equal it (ImporterMismatch otherwise), so a foreign identity embedded
   in foreign NEVER becomes an N-AALP authorization identity -- the
   confused-deputy rule the MCP profile above also applies.  A malformed
   description body is DescMalformed.

16.5.  Name Bindings and A2A Task Transitions

   Two receipt-CHAINED, OFFLINE-WALKABLE surfaces reusing the audit
   receipt-chain construction unchanged: the head of each object is SHA-
   384(body), the genesis prev is 48 zero bytes, seq is monotonic, and
   the body carries the prior head in prev, so editing or omitting a
   record breaks the next record's linkage.

Sammartano                Expires 10 March 2027                [Page 30]
Internet-Draft                   N-AALP                   September 2026

   A naalp-name-binding ({ name, signer, seq, prev }) maps a durable,
   human-readable name to a signer id and chains onto the prior binding
   for that name.  A key ROTATION for a name is a NEW binding at the
   next seq naming the new signer; a binding is dated by its chain
   position (seq), not by the envelope's advisory created field.  A
   name's history is walkable offline; a deleted or omitted binding
   leaves a detectable HOLE at the first-broken position, reported
   NameChainBroken; two bindings by ONE authority at the SAME (name,
   seq) naming DIFFERENT signers are a FORK, reported
   NameForkProofInvalid at that seq.  A malformed binding is
   NameMalformed; a binding signed under a key that does not match the
   claimed signer is VerifierKeyMismatch.

   A naalp-task-transition ({ task, card, from, to, seq, prev }) is one
   signed, receipt-chained A2A (Agent2Agent) task-lifecycle state
   transition.  The task-state set -- submitted (0), working (1), input-
   required (2), auth-required (3), completed (4), canceled (5), failed
   (6), rejected (7) -- is an IMPORTED vocabulary (carriage, not
   adoption): the A2A specification Section 4.1.3 defines these eight
   states and their terminal/interrupted categories NORMATIVELY (start =
   submitted; terminal = {completed, canceled, failed, rejected};
   interrupted = {input-required, auth-required}), and N-AALP's legal-
   edge table is DERIVED from those documented category rules and
   enforced by the endpoint, not by this wire production, which carries
   only the from/to state values. card is the content id of the A2A
   Agent Card attestation (a naalp-description-import with format a2a-
   agent-card) binding the task profile to an agent/operation; a
   transition carrying a card other than the profile's bound card is
   rejected ForeignCard.  An illegal edge, a non-contiguous from, a
   transition out of a terminal state, or a gap or reorder in the chain
   is rejected fail-closed IllegalTransition or TaskChainBroken, with
   the violating position reported.

16.6.  Governed Negotiation

   Three signed surfaces reusing the closed effect lattice, the content-
   id framing, and the causal partial order (causes) unchanged: offer,
   counter, and accept are SIGNED, CAUSALLY-LINKED messages, each naming
   its predecessor(s) by content id in causes (the same shape the causal
   partial order uses).  Each SELECTS a profile from the CLOSED, PRE-
   REGISTERED negotiation-profile set -- baseline (0), streaming (1), or
   batch (2) -- never a free-form capability string and never a runtime-
   generated handler; an unknown profile is rejected UnknownProfile.

   The three productions -- naalp-negotiation-offer ({ negotiation,
   role, profile, causes }), naalp-negotiation-counter, and naalp-
   negotiation-accept -- are distinguished by a fixed role literal from
   the closed negotiation-role set (offer 0, counter 1, accept 2), so an

Sammartano                Expires 10 March 2027                [Page 31]
Internet-Draft                   N-AALP                   September 2026

   offer body never validates against the accept production and vice
   versa; a role value outside the set, or a body whose fixed-literal
   field disagrees with its production, is rejected UnknownRole
   (NotOffer/NotAccept name the specific offer/accept-shape mismatch).
   An offer is the root of the exchange and carries no causes; a counter
   chains onto the offer or a prior counter; an accept MUST DESCEND from
   its offer along the causes DAG, enforced by the endpoint
   (NotDescended otherwise).  A malformed negotiation body is
   NegMalformed.

16.7.  Advisory Risk Labels

   A naalp-risk-label ({ code, critical }) carries one label: code
   (risk-code, an open uint -- a closed standard vocabulary plus a
   private/experimental extensible range, enforced by the endpoint and a
   registry the same way the per-signer counter's value space is open, #
   Object Model) and critical (risk-critical, the per-carriage must-
   understand flag: 1 critical, 0 advisory -- the spine carries no CBOR
   boolean).  A naalp-labeled-object ({ effect, labels }) carries an
   object's effect together with a set of risk labels.  The critical-
   extension rule (# Object Model) applies to labels the same way it
   applies to ext/cext: an unknown CRITICAL label is rejected
   UnknownCriticalRisk, and an unknown non-critical one is ignored; a
   critical flag outside {0,1} is MalformedCriticalFlag.  LOAD-BEARING
   INVARIANT: a risk label is an ADVISORY dimension, NEVER a fifth
   effect -- carrying a label never changes the object's effect class,
   and the closed four-value effect lattice (# Effects and
   Authorization) is untouched by this family.

16.8.  Flow Continuations

   A long-running flow costs exactly two full ML-DSA signatures --
   FlowOpen and FlowCommit -- regardless of the number of intermediate
   steps, generalizing native streaming (# Streaming) from a byte stream
   to a flow of typed steps. naalp-flow-open ({ flow_id, effect_ceiling,
   approvals }) is a fully signed naalp-object that fixes the flow's
   effect ceiling and its approval bindings; its authority is
   reconstructable from its own bytes alone.  Its head (SHA-384 of the
   body) anchors the chain, and its content id is carried by every child
   object as flow_open_id; a continuation naming a different
   flow_open_id than the one it chains from is rejected WrongFlow.

   A naalp-continuation ({ flow_open_id, seq, effect, payload_id, prev
   }) is a cheap, UNSIGNED hash-chain link: its head is SHA-384(body),
   and prev is the previous link's head (the FlowOpen's own head for seq
   0).  Its effect MUST NOT exceed the FlowOpen's effect_ceiling, else
   AboveCeiling. payload_id is the content id of that step's payload,
   carried separately so the continuation itself stays small.  A naalp-

Sammartano                Expires 10 March 2027                [Page 32]
Internet-Draft                   N-AALP                   September 2026

   flow-checkpoint ({ flow_open_id, through_seq, head }) confirms a
   contiguous prefix of the chain through through_seq; a dropped or
   reordered link short of that prefix is GapDetected. naalp-flow-commit
   ({ flow_open_id, final_head }) binds the FINAL chain head under the
   second full signature, closing the flow; a missing or altered link
   relative to the committed final_head is CommitMismatch.  The four
   body shapes (3, 5, 3, and 2 fields respectively) are structurally
   distinct, so domain separation between them needs no additional tag.

16.9.  Governed-Decision Records and Transparency Log Primitives

   This family carries the accountability triple natively -- UNIQUE
   SELECTION, GOVERNED-AT-T, and BINDING-FIXED-BY-T -- as three signed,
   additive sibling productions; none moves naalp-version.

   An ordering-disclosure ({ basis, ?boundary, ?mechanism, ?relation })
   states what, if anything, establishes a record's order relative to
   the event it concerns, and from which observational domain, via the
   closed ordering-basis set: correspondence-only (0) -- the weakest
   claim, ON PURPOSE, meaning a record that says nothing about ordering,
   and an existing record whose ordering field is ABSENT, are BOTH read
   as correspondence-only (a verifier MUST NEVER infer a stronger
   ordering claim from silence); single-boundary (1) -- one covering
   boundary (boundary, a signer id) attests the order; or external-
   mechanism (2) -- mechanism names an external sequencing mechanism and
   OPTIONAL relation binds this record under it (for example, the
   content id of a naalp-checkpoint-root the record is included under).
   Field presence is fail-closed and native: correspondence-only
   requires keys 2-4 absent; single-boundary requires key 2 present and
   3-4 absent; external-mechanism requires key 3 present (4 optional)
   and 2 absent; any other combination is OrderingDisclosureMalformed.
   Whether an external mechanism's operator is genuinely distinct from
   both parties is a structural deployment fact checkable in substance
   later, not a claim the wire itself can close.  A term-disposition ({
   kind, ?source }) reuses the producing-boundary kind codes (1
   observed, 2 reported; # Object Model) to state whether one term of a
   record was observed first-hand or is relayed from source; a code
   outside {1,2} or a source present under observed is malformed.
   enforcement-disposition is a closed pair: enforced (1) or advised
   (2).

   A naalp-decision-record ({ action, governing, ?consume, outcome,
   ordering, ?terms, ?enforcement }) is the SIGNED record a governed
   decision point emits stating that it decided about action under a
   CLOSED, uniquely selected condition set. governing names that set in
   the clear as content ids -- may be empty when the decision is
   governed by standing policy alone, naming that policy object's
   content id instead (UNIQUE SELECTION: identification and availability

Sammartano                Expires 10 March 2027                [Page 33]
Internet-Draft                   N-AALP                   September 2026

   together).  The OPTIONAL consume names the naalp-consume-receipt that
   spent the governing authority at decision time (GOVERNED-AT-T): it is
   PRESENT for an allow that consumed a single-use authority and MUST be
   ABSENT for deny/hold, since a refusal consumes nothing (a deny/hold
   body carrying a consume reference is DecisionMalformed). outcome
   reuses the closed gw-decision set (# Security Considerations).
   ordering is MANDATORY -- the record states its ordering basis or
   states correspondence-only; there is no silent default, and an
   unrecognized basis value is UnknownOrderingBasis.  The OPTIONAL terms
   map keys per-term dispositions by THIS record's own field numbers
   1..5 (a key outside that set is TermDispositionMalformed), and the
   OPTIONAL enforcement states whether the producer enforces the outcome
   or only advises it -- the producer's own unverifiable self-account.
   The record is deliberately CLOCK-FREE: it carries no claimed time,
   and both time properties above are POSITIONAL, never a self-asserted
   timestamp; the signature binds THE DECISION, not a retrieval of it.

   A naalp-checkpoint-root ({ log, size, root, prev, at }, an RFC
   9162-style construction) is a log operator's SIGNED Merkle tree head
   over a leaf set of record content ids -- the NEITHER-PARTY ANCHOR
   PRIMITIVE (BINDING-FIXED-BY-T).  Tree construction follows [RFC9162]
   Section 2.1: leaf hash = HASH(0x00 || leaf), interior node =
   HASH(0x01 || left || right), instantiated with SHA-384 (48-byte
   heads); the 0x00/0x01 prefixes supply leaf/node domain separation.
   Checkpoints chain by prev (genesis 48 zero bytes), so a withheld or
   reordered checkpoint breaks a link, reported CheckpointMalformed on a
   structurally invalid checkpoint.  A naalp-witness-cosign ({ witness,
   root, at }) COUNTERSIGNS one exact checkpoint by content id; the wire
   carries the cosignature, while whether the witness's observational
   domain is genuinely distinct from both parties is a structural
   deployment fact a later verifier checks in substance -- the wire hook
   for the neither-party property, stated honestly as a hook rather than
   a guarantee.  A cosignature naming a root that does not match the
   checkpoint it purports to cover is WitnessRootMismatch.

   A naalp-inclusion-proof ({ root, leaf, index, path }) proves that a
   leaf existed in the tree a named naalp-checkpoint-root commits to
   (RFC 9162 Section 2.1.3.1 path recomputation, SHA-384 profiled):
   recording a content id as a leaf under a witnessed checkpoint
   establishes existed-no-later-than-the-checkpoint, closing the
   BINDING-FIXED-BY-T leg.  Verification recomputes the path bottom-up
   from leaf at position index using the sibling hashes in path and
   compares the result against root, fail-closed InclusionProofInvalid
   on any mismatch.

Sammartano                Expires 10 March 2027                [Page 34]
Internet-Draft                   N-AALP                   September 2026

16.10.  Portable Egress Evidence

   A naalp-egress-attestation ({ binding, digest, effect, audience, at,
   ?ordering }) is a SIGNED attestation a gateway or sidecar emits that
   an object of a given effect class, bound to a given audience, crossed
   an egress boundary at a given time -- third-party re-serve, payload-
   free. binding selects one of the closed egress-binding values:
   content-bound (0), where digest is the crossed object's own content
   id, or content-free (1), where digest is a hiding commitment SHA-
   384(content_id || salt), openable later only by the gateway revealing
   the content id and salt out of band. effect is the crossed object's
   effect class and audience is its bound destination (empty-permitted).
   The OPTIONAL ordering (an ordering-disclosure above) states the
   attestation's ordering basis; its absence is read correspondence-
   only, never a stronger claim.  A malformed attestation is
   EgMalformed; an unrecognized binding value is UnknownEgressBinding.

16.11.  Manufacturing Physical-Hazard Claims and Authorizations

   hazard is a dimension ORTHOGONAL to effect: effect (# Effects and
   Authorization) is DATA reversibility (can the state change be
   undone); hazard is PHYSICAL danger -- a data-reversible action may
   still be a high physical hazard (for example, a tool re-approaching a
   work envelope).  The two are never merged, and neither is derived
   from the other.  A hazard CLAIM (naalp-hazard-claim) rides as the
   critical cext key 16 on the acting object (# Object Model); a hazard
   AUTHORIZATION (naalp-hazard-authorization) is a standalone
   Governance-channel (0x0004) kind 7 object, referenced by the acting
   object's causes.  All numeric bounds in this family are fixed-point
   integers (signed millimeters for position, unsigned millimeters-per-
   second for speed) -- no floats, per the spine's deterministic-CBOR
   subset (# Object Model) -- and map keys are 1-based.

   hazard-class is a CLOSED 0..4 enum: none (0), tool-actuation (1),
   thermal (2), energy-release (3), motion-in-shared-space (4).  This
   closed set carries a DECODE-TIME rule mirroring effect's unknown-
   value handling: an absent or unrecognized raw hazard value MUST
   normalize to the HIGHEST class (4), never to none or a weaker value,
   so a missing declaration fails safe (HazardUnknown when no claim
   exists at all; else HazardNotCovered against a lower-class grant) --
   a rule CDDL cannot itself express, since it governs the absence or
   invalidity of a raw wire value, so it is stated here as a MUST on the
   decoder. spatial-bounds ({ frame, axes }) names a coordinate frame
   (frame, which MUST be Unicode NFC, NonNFC otherwise) plus a signed
   axis-aligned bounding region in that frame: axes MUST be non-empty
   and every [min, max] entry MUST satisfy min <= max, else
   HazardMalformed.  The frame id is integrator-defined; N-AALP requires
   only that a claim's frame id equal the authorization's for

Sammartano                Expires 10 March 2027                [Page 35]
Internet-Draft                   N-AALP                   September 2026

   containment to be checkable. hazard-window ({ not_before, not_after
   }) is a validity window in the spine's epoch-ms convention. hazard-
   envelope ({ spatial, speed_bound, window }) is the full physical
   envelope a claim or authorization bounds itself by; all three fields
   are MANDATORY -- a silently absent axis, speed, or window is a
   MALFORMED envelope (HazardMalformed), never treated as
   "unconstrained," which would fail OPEN in a physical-safety context.

   naalp-hazard-claim ({ class, envelope }) and naalp-hazard-
   authorization ({ class, envelope }) share the identical { hazard-
   class, hazard-envelope } shape; both fields are mandatory in each,
   else HazardMalformed.  Coverage of a claim by an authorization
   requires an EXACT class match AND full containment of the claim's
   envelope in the authorization's: the frame id equal; the same axis
   count and order; every claim axis inside the matching authorization
   axis; the claim's speed_bound no greater than the authorization's;
   and the claim's window a sub-interval of the authorization's window.
   Any single failing dimension denies the WHOLE claim
   (HazardNotCovered) -- there is no partial authorization.

17.  Security Considerations

   Mandatory-to-implement algorithms and post-quantum rationale: N-AALP
   signs with ML-DSA [FIPS204], a post-quantum signature, because N-AALP
   objects (receipts, approvals, audit chains) are long-lived non-
   repudiable records subject to store-now-verify-later forgery risk
   from a future cryptographically relevant quantum computer; a
   classical-only signature on such records would be a latent forgery
   exposure.  An optional Ed25519+ML-DSA composite provides defense-in-
   depth during the transition; it is a single non-separable LAMPS
   composite, so it is accepted only when both components verify and a
   stripped object has no valid signature at all.  Pure ML-DSA is SUF-
   CMA; the opt-in composite is EUF-CMA but not SUF-CMA, which is not
   load-bearing because N-AALP never keys a security decision off raw
   signature bytes.

   Downgrade and negotiation: algorithm agility is expressed by the COSE
   algorithm identifier bound under the signature and checked against
   the profile floor; a signature below the floor is rejected, so
   agility cannot become a downgrade.

   Replay and reordering: approvals bind a nonce and expiry and are
   single-use through the consume ledger; the audit receipt chain binds
   each object into a hash chain so reordering, omission, and
   substitution are detectable; delivery stages are monotonic.

Sammartano                Expires 10 March 2027                [Page 36]
Internet-Draft                   N-AALP                   September 2026

   Identity and trust: the signer id is a pure function of the public
   key, so a forged id cannot recompute; there is no certificate
   authority to compromise.  Compromise of a signing key is bounded by
   rotation and revocation, and attribution survives rotation.  A non-
   injective or forgeable identity function would collapse this
   property; the SHA-256 multihash over the multicodec-tagged key
   provides collision and second-preimage resistance.

   External code-point stability: the key-type codes 0xed, 0x1211, and
   0x1212 that signer-id derivation uses (# Identity) originate in the
   external multiformats table, a registry N-AALP does not govern.  If
   that upstream table ever reassigned one of these three codes to a
   different meaning, an implementation that resolved mc by looking the
   key type up in the live table would derive a different signer id than
   an implementation that used the value current when it was built,
   silently splitting the identity space.  N-AALP closes this dependency
   by pinning all three values as its own normative constants (#
   Identity) rather than by indirection through the upstream table, so
   signer-id derivation stays fixed under this specification regardless
   of any later upstream reassignment.

   Effect and authorization: the effect is an authorization input, not a
   hint; an unrecognized effect fails closed to destructive;
   authorization is never derived from transport metadata or a foreign
   principal.  This closes the gap a pure intent label leaves open.

   Effect inflation as an availability risk (accepted and stated): the
   effect lattice has an abuse direction.  A malicious wrapping signer
   can mark ordinary actions destructive so that everything demands an
   approval and throughput collapses, and attribution identifies who did
   it only after the fact.  N-AALP does not prevent this on the wire and
   does not pretend the lattice has no abuse direction; it is an
   accepted risk, mitigated operationally by attribution -- every object
   binds to a signer id -- together with per-signer rate limiting
   applied by the deployment.  Rate limiting is a deployment control
   rather than a wire field, stated here as an operational obligation,
   not a format guarantee.

   Continuation compromise, honest limit: a node compromised inside an
   open flow can keep emitting continuations up to the ceiling.  The
   ceiling bounds the damage.  It does not prevent it.  The flow's
   effect ceiling caps the severity any continuation can reach, so the
   damage is bounded to actions within that ceiling; but until the flow
   is closed or the compromised key is revoked, the compromised node
   keeps acting within it.  This limit is stated plainly here rather
   than left for a reviewer to infer.

Sammartano                Expires 10 March 2027                [Page 37]
Internet-Draft                   N-AALP                   September 2026

   Denial of service: an object requires one signature verification and
   one deterministic decode; verification is fail-closed and performed
   before any state change or effect.  Streaming amortizes one signature
   over many chunks.  Implementations SHOULD bound object and stream
   sizes by policy.

   Cost-ordered verification (cheapest checks first): a verifier SHALL
   perform its checks in increasing order of cost and reject on the
   cheapest failing check before it performs the signature verification.
   The cheap checks -- deterministic decode, content-id recomputation,
   field-range checks, protected-header/body agreement and version,
   critical-extension recognition, and kind/channel dispatch -- all run
   before the ML-DSA signature verification, which is the most expensive
   step and is therefore last.  Because the expensive step is last, a
   flood of mismatched or malformed objects is rejected on a cheap check
   and cannot force a signature verification on attacker-controlled
   bytes; the cost of rejecting garbage is bounded by the cheap checks,
   not by the post-quantum signature.

   Confidentiality: object-level guarantees do not include
   confidentiality; a sensitive object MUST use a confidential transport
   (# Transport Bindings), enforced by refusal.

   Offline verification proves validity-at-issue, not current unspent-
   ness: a signature verified offline proves an approval was well-formed
   and authorized when it was issued; it does NOT prove the approval is
   still unspent.  Spent-or-unspent is state held at the consume ledger
   (# Approval), not a property of the object's bytes.  A verifier that
   treats a syntactically valid, unexpired approval as spendable without
   consulting the ledger has confused attributability at the moment of
   issue with current spendability.

   Exposure and reconciliation cadence: a relying party that accepts a
   consume receipt during a network partition, before that receipt has
   been compared against the receipt sets held by other parties, is
   exposed to a conflicting spend it cannot yet see.  Its exposure is a
   function of its own reconciliation cadence -- the window between
   accepting a receipt and next comparing its receipt set against the
   others -- multiplied by the value at risk in that window (the rate,
   in value per unit time, at which double-spendable value is being
   accepted).  N-AALP makes no liveness promise here: the format does
   not bound how quickly a conflicting spend elsewhere becomes visible,
   and it is the relying party, not the format, that lowers its exposure
   by reconciling more often.  Cadence is a parameter the exposed party
   sets, not a guarantee the format provides.

Sammartano                Expires 10 March 2027                [Page 38]
Internet-Draft                   N-AALP                   September 2026

   Worked exposure example: a party reconciles on a 3,600-second (one
   hour) cadence and, within one such window, accepts approvals whose
   combined double-spendable value arrives at a value at risk of $5,000
   per second.  Its worst-case exposure across one unreconciled window
   is (value at risk) x (window length) = $5,000/s x 3,600 s =
   $18,000,000 that could be double-spent before the next comparison
   detects the conflict.  Cutting the reconciliation cadence to 60
   seconds cuts the window length, and the exposure with it, by 60x, to
   $300,000.  The exposure figure is set entirely by the party's own
   cadence and value at risk; the object bytes do not change, and the
   protocol computes none of it.

   Baseline consume under an unreachable ledger: at the baseline tier,
   an executor that cannot reach the consume ledger SHALL deny the spend
   (this is the normative rule of (# Approval), restated here for its
   security weight).  Local spend-and-reconcile-later is not a baseline
   behavior; a consumer that spends locally while the ledger is
   unreachable is non-conforming.  This is the fail-closed choice --
   under partition the baseline refuses rather than risk an undetected
   double spend -- and federated ordering over identical signed objects,
   which trades this refusal for the bounded exposure modeled above, is
   a named higher tier only.

   Attributable versus checkable: a signature makes a statement
   attributable to a signer -- it binds the bytes to a key -- but
   attributability is not the same as checkability.  A statement is
   checkable only if a stranger who trusts no one can re-derive the
   claim for themselves.  A checkable claim (a) says what it is about,
   (b) carries the evidence it rests on, directly or by content id, and
   (c) names the procedure that re-checks it.  N-AALP already delivers
   (a) and (b) for its structural claims: the content id recomputes from
   the bytes, so anyone can confirm the id names these exact bytes, and
   the causes field is a signed partial order a stranger can walk
   offline.  An object that carries a body claim without naming the
   procedure that re-checks it is attributable only, and this
   specification says so plainly: absent (c), a relying party has the
   signer's word, not an independent re-derivation.

   The per-signer forward-only counter is detection, not prevention:
   N-AALP MAY define a forward-only per-signer counter that a signer
   increments on each object.  Its purpose is detection, not prevention:
   it exists to detect key duplication, not to stop it.  A counter a
   signer writes about itself proves nothing on its own, because once a
   key is duplicated both the legitimate holder and the thief emit
   locally consistent, monotonic sequences, and neither sequence
   contradicts the other in isolation.  The duplication becomes provable
   only when two conflicting sequences bearing the same signer id
   physically meet somewhere the attacker cannot suppress; until that

Sammartano                Expires 10 March 2027                [Page 39]
Internet-Draft                   N-AALP                   September 2026

   meeting the counter has detected nothing.  The counter's value is
   therefore contingent on a reachability property the wire cannot
   guarantee -- that the conflicting evidence reaches a common observer
   -- and this specification states that dependency rather than implying
   the counter prevents duplication.  The sharper contradiction,
   authored by neither the requester nor a thief, is carried by the
   ledger-signed consume receipt (# Approval), not by the self-authored
   counter.

   Correspondence is not precedence: the causal graph (# Audit, Causal
   Graph, and Ordering) and parent-by-content-id let a stranger
   establish record order offline -- an object that names another as a
   cause existed no later than its effect, within the two-party
   construction that produced them.  That is not cross-trust-boundary
   event precedence.  Each boundary's observational domain is
   authoritative only within itself, so ordering two boundaries' events
   against each other requires an ordering authority whose observational
   domain is neither party; the baseline single-authority ordering (#
   Audit, Causal Graph, and Ordering) does not guarantee an authority
   that is neither party, so cross-boundary precedence is a higher-tier
   or deployment property, not a baseline guarantee.  The OPTIONAL
   producing-boundary disclosure (ext key 15, # Object Model) makes the
   one fact an object can honestly assert explicit -- whose domain
   observed the event, and whether first-hand or relayed -- and a
   relying party that needs precedence across a boundary composes it
   with an independent ordering authority.  One such construction is a
   Transparency Service as defined in [RFC9943], whose own Section 9.1
   (Ordering of Signed Statements) states that a relying party cannot
   assume the registration order matches the issuance order unless the
   service's registration policy advertises it, and whose Section 9.2
   (Accuracy of Statements) states that registering a statement only
   proves it was produced, not that it is accurate -- the same limit,
   stated by an independent standard.

Sammartano                Expires 10 March 2027                [Page 40]
Internet-Draft                   N-AALP                   September 2026

   Custody continuity and rotation dating: a valid signature proves the
   signer held the private seed at signing time and nothing more; it
   does not prove continuous custody. draft-01 does not solve rotation-
   continuity, because a successor (rotation) statement signed by an old
   key can be forged by a thief who holds that old key, and the forged
   handoff verifies.  What the design provides instead is dating after
   the fact.  The created timestamp (field 6) is advisory only and MUST
   NOT be relied on as ordering evidence; the receipt-chain position is
   the record of when a statement happened (# Audit, Causal Graph, and
   Ordering).  A rotation statement is dated by where it lands in the
   receipt chain, the same as any other object.  On discovery of a theft
   there is a specific receipt position to cut at -- a cut position --
   before which the history is still provable from the original
   signatures.  Because the mandatory signatures are post-quantum (ML-
   DSA), the pre-cut history stays checkable for years after the
   compromised keys are gone.

   Worked custody timeline: at receipt position 100 a key K is used
   legitimately.  At position 140 the key is stolen and the thief
   immediately signs a rotation from K to the thief's own key K'.  At
   position 200 the theft is discovered.  The relying party sets the cut
   position at 140 -- the earliest position it can attribute to the
   thief, or, where that is uncertain, the last position it can vouch
   for.  Every object at receipt position below 140 remains verifiable
   from its original ML-DSA signature and its receipt-chain position,
   independent of K's later compromise; objects at position 140 and
   after, including the forged rotation, fall outside the cut and are
   not trusted on K's authority.  The forged handoff still verified as
   bytes -- dating does not prevent it -- but the receipt-chain position
   gives the relying party a defined cut position and a pre-cut history
   it can still stand on.

   The never-signs-again case: if the legitimate holder never signs
   again after a theft, the case is undecidable from the signer's own
   bytes: as far as the signer's own signatures can prove, the thief is
   that identity from the moment of theft onward, because every
   subsequent signature verifies under the stolen key and there is no
   later legitimate signature to contradict it.  Anything that resolves
   this works from statements other parties make -- counterparty
   acknowledgments, obligations that settled, an observer outside the
   thief's reach -- and N-AALP carries exactly those as checkable signed
   objects.  The weighing of that outside evidence is left to the
   relying party, to whoever decides to transact, and is not a property
   the wire computes.  N-AALP does not pick a trust graph: this revision
   deliberately encodes no trust-weighting scheme into the object,
   keeping the line between what the protocol carries -- checkable
   evidence, and refusal when required evidence is missing -- and what
   the deployment decides -- who to believe -- where it belongs.

Sammartano                Expires 10 March 2027                [Page 41]
Internet-Draft                   N-AALP                   September 2026

   Third-party trust statements are carriage, not adjudication: N-AALP
   carries third-party trust statements -- attestations, reputation
   assertions, and external-registry references such as an ERC-
   8004-style identity or reputation registry record -- as checkable
   signed objects, each naming its subject and carrying the external
   record it references by content id, so a relying party re-derives the
   reference for itself rather than trusting the connection that
   delivered it.  The wire carries these statements and weighs none of
   them: no wire field scores a trust statement, ranks two conflicting
   attestations, or selects among registries, because the protocol takes
   no position on which trust statement outranks which.  A carried
   reputation or registry reference therefore verifies -- its content-id
   recomputes and its signature checks -- without the protocol computing
   any score from it; which statement to believe remains a decision for
   the deployment, not one the wire performs.

   Payment import, user-interface consent, and portable gateway evidence
   add guarantees around imported and human-in-the-loop actions without
   introducing a new effect, ledger, or policy mechanism.  A payment
   instruction issued in a foreign format -- an AP2 mandate, an Agentic
   Commerce Protocol delegated token, an x402 payload -- is carried
   octet-for-octet and imported as a single-use approval: imported
   payment instructions become single-use approvals bound to the amount,
   currency, payee, and the carried payload's content id, so a wrong
   amount or payee no longer matches the approval and a replayed payment
   authorization is rejected by the consume ledger.  The imported format
   (naalp-payment-format) is one of a closed, registered set -- an AP2
   mandate, an Agentic Commerce Protocol delegated token, or an x402
   payload -- and an unrecognized format is rejected
   UnknownPaymentFormat; the value an approval binds (naalp-payment-
   charge-binding) carries the same fields as the import (naalp-payment-
   import) with the foreign payload replaced by its content id, so the
   binding names the exact value approved without re-embedding the
   foreign bytes.  A user-interface approval binds the exact action
   shown by content id, with the shown tool-lifecycle events (naalp-ui-
   event) receipt-chained so the shown sequence is provable and an
   omitted event is detected at its position; an action other than the
   one shown and approved has a different content id and is refused.
   The shown-event stream is one of a closed vocabulary -- shown, args-
   shown, approved, or rejected (ui-event-kind) -- and an event outside
   that set is rejected UnknownUIEventKind; a malformed event body is
   UIMalformed and a broken receipt chain is UIChainBroken.  A gateway
   decision (naalp-gateway-decision) is portable evidence whose
   authority is the signature over its bytes, not the connection that
   delivered it, so it re-verifies identically when a party other than
   the gateway serves it; it carries the decision, the action it is
   about, and the deciding policy's identity as an opaque name, and
   defines no policy language.  The decision is one of a closed

Sammartano                Expires 10 March 2027                [Page 42]
Internet-Draft                   N-AALP                   September 2026

   vocabulary -- allow, deny, or hold (gw-decision); an unrecognized
   value is rejected UnknownGatewayDecision, and a malformed body is
   GwMalformed.  A gateway decision MAY additionally carry an ordering
   disclosure (# Additive Object Families) and, where the decision was
   made over foreign-protocol evidence, a naalp-foreign-profile-pin
   naming the foreign evidence profile's identifier and the specific
   revision pinned at decision time, so a later revision of that foreign
   profile cannot be silently substituted for the one the decision
   actually evaluated.

   Signing outside the page context (browser and WebMCP bindings): where
   N-AALP signing is exposed to a web page -- for example a WebMCP-style
   in-browser binding -- the signing operation MUST be performed outside
   the page script context, in an isolated signer (a browser-extension
   background context, a distinct origin, or a platform key store) that
   the page cannot script.  The page MAY request a signature over a
   named object but never holds the signing key or the signing routine,
   so a compromised or malicious page can request but never forge a
   signature and cannot exfiltrate the key.  A binding that signs inside
   the page script context is non-conforming.

   What N-AALP does NOT defend against: it does not provide
   confidentiality by itself (that is the transport's); it cannot force
   an ordering authority to deliver events it chooses to withhold (a
   chain reveals equivocation and omission-of-known-events but cannot
   compel delivery); it does not provide cross-trust-boundary event
   precedence at the baseline tier (the causal graph proves record
   order, not event precedence across trust boundaries -- see the
   correspondence-is-not-precedence discussion above); it does not
   police the semantic correctness of a carried foreign message beyond
   octet-exact carriage; it does not prove an offline-verified approval
   is still unspent (that is consume-ledger state, bounded by the
   reconciliation cadence and exposure model above); it does not make a
   self-authored per-signer counter proof of anything until two
   conflicting sequences meet where the attacker cannot suppress them;
   it does not solve rotation-continuity or the never-signs-again theft
   from the signer's own bytes (it provides dating and a cut position,
   not prevention); and it does not defend against a signer that is
   itself authorized and malicious (it makes that signer's actions
   attributable and auditable, not impossible).

Sammartano                Expires 10 March 2027                [Page 43]
Internet-Draft                   N-AALP                   September 2026

17.1.  Trust-decision closure sovereignty

   A relying party's decision to act on an authenticated party's object
   is trustworthy only when that decision depends only on inputs outside
   the authenticated party's influence -- transitively, so that an
   input's own inputs are inputs.  Where the authenticated party does
   influence an input, that influence MUST take one of exactly three
   safe shapes: verifiable, attenuating, or committed.  A verifiable
   influence is a fixed function of bytes the party cannot forge and is
   recomputed by the relying party; an attenuating influence can only
   reduce the party's own authority; a committed influence is mixed with
   an independent contribution the party cannot bias.  An input safe in
   none of the three, and not otherwise checkable, is treated as
   unverified and MUST fail closed.  This property is already enforced
   across N-AALP's identity, encoding, conformance, delegation,
   approval, and negotiation requirements; the paragraphs below close
   the remaining inputs.

   Verification MUST be deterministic: an implementation performs
   verification as deterministic code whose control flow does not depend
   on unverified content, and no part of an object under verification
   reaches a model or inference component before it is deterministically
   accepted.  This keeps an agent-native relying party -- one whose
   evaluator is itself a model -- from having its trust decision steered
   by the very bytes it is judging.

   A refusal or deny outcome is a signed, attributable, fail-closed
   record, and a refusal returns only a coarse outcome to the
   authenticated party -- a single value from a closed vocabulary
   together with the content id of the signed record, and nothing more.
   Discriminating detail is carried only in the signed record an auditor
   reads, so that repeated refusals cannot serve an adaptive party as an
   oracle.  A party-visible outcome that carries discriminating detail,
   or omits the record content id, is a refusal detail leak.

   A standalone judgment that a credential is in force at the present
   moment rests on time the party cannot supply.  A credential's
   present-moment freshness is judged against a clock the authenticated
   party does not provide, and the ordering authority is structurally
   distinct from the party being authenticated, so the party whose
   credential would expire is never itself the source of the time
   against which expiry is judged.

   Where a verdict or approval travels beyond the context that produced
   it, a portable verdict names the context in which it is valid, and a
   relying party checks that named context at use, so a verdict sound
   for one context cannot be replayed into another the party chose.
   Naming a context is optional -- an approval that names no context is

Sammartano                Expires 10 March 2027                [Page 44]
Internet-Draft                   N-AALP                   September 2026

   unrestricted by the issuer's choice, and a deployment MAY require one
   by local policy -- but the check is mandatory when a context is
   present.

   Delegated authority only ever shrinks: derived authority is non-
   increasing across every hop of a delegation chain, on effect, scope,
   and depth, whether the chain is read leaf-to-root or root-to-leaf; a
   hop that would raise authority denies the whole chain.

18.  Privacy Considerations

   N-AALP objects are signed and content-addressed, and are often long-
   lived, which creates two privacy tensions the format addresses
   explicitly: correlation of identical content, and erasure of personal
   data from records that are immutable by design.

   Salted body option: because the content id is a deterministic hash of
   the body, two objects with identical logical content produce an
   identical content id and are trivially correlatable across contexts.
   N-AALP therefore offers an optional body salt so that identical
   logical content does not yield a correlatable content id; a signer
   that must avoid cross-context linkage includes a fresh random salt in
   the body, carried under the signature like any other field.

   Hash-only personal data: an object that must reference a person
   SHOULD NOT carry the personal data in the clear.  Personal data is
   carried only as a salted one-way hash of the datum, so the object
   binds to the person without disclosing the identifier; the plaintext
   and its salt are held off the record by the party that needs them.

   Erasure resolution against immutable records: a signed, hash-chained
   record cannot have bytes removed without breaking the chain, which
   appears to conflict with an erasure (right-to-be-forgotten)
   obligation.  N-AALP resolves this without mutating the signed record:
   because personal data is present only as a salted hash, erasure is
   resolved by destroying the off-chain preimage and its salt, leaving
   the signed record intact but its hashed personal data unlinkable to
   any person.  The signature and the audit chain stay valid; what is
   destroyed is the ability to reverse the hash to a person, which is
   exactly the property erasure requires.

Sammartano                Expires 10 March 2027                [Page 45]
Internet-Draft                   N-AALP                   September 2026

19.  IANA Considerations

   This document is an Independent Submission.  All registries requested
   below use registration policies permitted on the Independent stream,
   requiring no IETF Review or Standards Action: the media type
   registers into the existing IANA Media Types registry under [RFC6838]
   (that registry's Expert Review), and each new registry this document
   creates uses RFC Required (First Come First Served in the standards
   range) per [RFC8126] -- an ISE-permissible policy.  Numeric values
   shown are the values this specification defines; where IANA
   assignment is requested the placeholder TBD is used.

19.1.  Media type application/vnd.bubblefish.naalp+cbor

   IANA is requested to register the following media type in the vendor
   tree ([RFC6838] Section 3.2), using the +cbor structured syntax
   suffix defined in [RFC8949] and registered in the IANA Structured
   Syntax Suffixes registry (whose mechanism is established by [RFC6838]
   and populated by [RFC6839]).  The vnd.bubblefish. facet designates
   BubbleFish Technologies, Inc. as the producing organization; a
   vendor-tree registration is submitted directly to IANA and undergoes
   Expert Review ([RFC6838] Section 3.2), requiring no IESG approval or
   IETF standards action:

   *  Type name: application

   *  Subtype name: vnd.bubblefish.naalp+cbor

   *  Required parameters: none

   *  Optional parameters: none

   *  Encoding considerations: binary (CBOR per [RFC8949])

   *  Security considerations: see (# Security Considerations) of this
      document

   *  Interoperability considerations: objects are deterministic CBOR;
      see (# Object Model)

   *  Published specification: this document

   *  Applications that use this media type: autonomous-agent
      application-layer messaging

   *  Fragment identifier considerations: as specified for application/
      cbor

Sammartano                Expires 10 March 2027                [Page 46]
Internet-Draft                   N-AALP                   September 2026

   *  Additional information: Magic number(s): none; File extension(s):
      .naalp; Macintosh file type code(s): none

   *  Person & email address to contact for further information: the
      author (front matter)

   *  Intended usage: COMMON

   *  Restrictions on usage: none

   *  Author: S.  Sammartano

   *  Change controller: the author (BubbleFish Technologies, Inc.)

19.2.  N-AALP Channel registry

   IANA is requested to create the "N-AALP Channels" registry.
   Registration policy: RFC Required (First Come First Served in the
   standards range) -- an ISE-permissible policy; a successor RFC
   provides the stable public specification and a non-colliding Channel
   Id.  Columns: Channel Id (uint 0..19), Name, Reference.  Initial
   contents: the twenty channels of (# Channel Surfaces), ids
   0x0000..0x0013, this document.

19.3.  N-AALP Object Kind registries

   IANA is requested to create, per channel, an "N-AALP Object Kinds
   (channel N)" registry.  Registration policy: RFC Required (First Come
   First Served in the standards range) -- an ISE-permissible policy.
   Columns: Kind Code (uint), Name, Effect (one of the four closed
   effect names, or "variable"), Reference.  The initial contents are
   the sixty-five baseline kinds below, enumerated here (channel, code,
   kind, effect) so an implementer building from only this document has
   the complete set:

   +================+======+===================+======================+
   | Channel        | Code | Kind              | Effect               |
   +================+======+===================+======================+
   | 0x0000 Control |    0 | Hello             | read_only            |
   +----------------+------+-------------------+----------------------+
   | 0x0000 Control |    1 | Bye               | idempotent_write     |
   +----------------+------+-------------------+----------------------+
   | 0x0000 Control |    2 | Ack               | read_only            |
   +----------------+------+-------------------+----------------------+
   | 0x0000 Control |    3 | Error             | read_only            |
   +----------------+------+-------------------+----------------------+
   | 0x0001 Memory  |    0 | MemoryOffer       | idempotent_write     |
   +----------------+------+-------------------+----------------------+

Sammartano                Expires 10 March 2027                [Page 47]
Internet-Draft                   N-AALP                   September 2026

   | 0x0001 Memory  |    1 | MemoryAccept      | idempotent_write     |
   +----------------+------+-------------------+----------------------+
   | 0x0001 Memory  |    2 | MemoryWrite       | non_idempotent_write |
   +----------------+------+-------------------+----------------------+
   | 0x0001 Memory  |    3 | MemoryRead        | read_only            |
   +----------------+------+-------------------+----------------------+
   | 0x0001 Memory  |    4 | MemoryExpire      | destructive          |
   +----------------+------+-------------------+----------------------+
   | 0x0001 Memory  |    5 | MemoryRevoke      | destructive          |
   +----------------+------+-------------------+----------------------+
   | 0x0002         |    0 | CapIssue          | non_idempotent_write |
   | Capability     |      |                   |                      |
   +----------------+------+-------------------+----------------------+
   | 0x0002         |    1 | CapDelegate       | non_idempotent_write |
   | Capability     |      |                   |                      |
   +----------------+------+-------------------+----------------------+
   | 0x0002         |    2 | CapRevoke         | destructive          |
   | Capability     |      |                   |                      |
   +----------------+------+-------------------+----------------------+
   | 0x0002         |    3 | CapLookup         | read_only            |
   | Capability     |      |                   |                      |
   +----------------+------+-------------------+----------------------+
   | 0x0003         |    0 | Rotation          | non_idempotent_write |
   | Identity       |      |                   |                      |
   +----------------+------+-------------------+----------------------+
   | 0x0003         |    1 | Revocation        | destructive          |
   | Identity       |      |                   |                      |
   +----------------+------+-------------------+----------------------+
   | 0x0003         |    2 | ForeignLink       | idempotent_write     |
   | Identity       |      |                   |                      |
   +----------------+------+-------------------+----------------------+
   | 0x0003         |    3 | KeyAnnounce       | read_only            |
   | Identity       |      |                   |                      |
   +----------------+------+-------------------+----------------------+
   | 0x0004         |    0 | PolicyPublish     | non_idempotent_write |
   | Governance     |      |                   |                      |
   +----------------+------+-------------------+----------------------+
   | 0x0004         |    1 | Approval          | non_idempotent_write |
   | Governance     |      |                   |                      |
   +----------------+------+-------------------+----------------------+
   | 0x0004         |    2 | ApprovalHeld      | read_only            |
   | Governance     |      |                   |                      |
   +----------------+------+-------------------+----------------------+
   | 0x0004         |    3 | Consume           | non_idempotent_write |
   | Governance     |      |                   |                      |
   +----------------+------+-------------------+----------------------+
   | 0x0005 Immune  |    0 | AnomalyReport     | read_only            |
   +----------------+------+-------------------+----------------------+

Sammartano                Expires 10 March 2027                [Page 48]
Internet-Draft                   N-AALP                   September 2026

   | 0x0005 Immune  |    1 | Quarantine        | destructive          |
   +----------------+------+-------------------+----------------------+
   | 0x0005 Immune  |    2 | QuarantineLift    | non_idempotent_write |
   +----------------+------+-------------------+----------------------+
   | 0x0006         |    0 | AuthorityAnnounce | read_only            |
   | Federation     |      |                   |                      |
   +----------------+------+-------------------+----------------------+
   | 0x0006         |    1 | ScopeReceipt      | non_idempotent_write |
   | Federation     |      |                   |                      |
   +----------------+------+-------------------+----------------------+
   | 0x0007         |    0 | SettleIntent      | non_idempotent_write |
   | Settlement     |      |                   |                      |
   +----------------+------+-------------------+----------------------+
   | 0x0007         |    1 | SettleReceipt     | non_idempotent_write |
   | Settlement     |      |                   |                      |
   +----------------+------+-------------------+----------------------+
   | 0x0007         |    2 | SettleReject      | idempotent_write     |
   | Settlement     |      |                   |                      |
   +----------------+------+-------------------+----------------------+
   | 0x0008         |    0 | ComplianceRecord  | non_idempotent_write |
   | Compliance     |      |                   |                      |
   +----------------+------+-------------------+----------------------+
   | 0x0008         |    1 | ComplianceQuery   | read_only            |
   | Compliance     |      |                   |                      |
   +----------------+------+-------------------+----------------------+
   | 0x0008         |    2 | ComplianceReport  | read_only            |
   | Compliance     |      |                   |                      |
   +----------------+------+-------------------+----------------------+
   | 0x0009 Sensory |    0 | Observation       | read_only            |
   +----------------+------+-------------------+----------------------+
   | 0x0009 Sensory |    1 | Subscribe         | idempotent_write     |
   +----------------+------+-------------------+----------------------+
   | 0x0009 Sensory |    2 | Unsubscribe       | idempotent_write     |
   +----------------+------+-------------------+----------------------+
   | 0x000A         |    0 | Metric            | read_only            |
   | Telemetry      |      |                   |                      |
   +----------------+------+-------------------+----------------------+
   | 0x000A         |    1 | HealthReport      | read_only            |
   | Telemetry      |      |                   |                      |
   +----------------+------+-------------------+----------------------+
   | 0x000B Audit   |    0 | Receipt           | non_idempotent_write |
   +----------------+------+-------------------+----------------------+
   | 0x000B Audit   |    1 | AuditQuery        | read_only            |
   +----------------+------+-------------------+----------------------+
   | 0x000B Audit   |    2 | ForkProof         | read_only            |
   +----------------+------+-------------------+----------------------+
   | 0x000C Stream  |    0 | StreamOpen        | variable             |
   +----------------+------+-------------------+----------------------+

Sammartano                Expires 10 March 2027                [Page 49]
Internet-Draft                   N-AALP                   September 2026

   | 0x000C Stream  |    1 | StreamCommit      | read_only            |
   +----------------+------+-------------------+----------------------+
   | 0x000C Stream  |    2 | StreamCheckpoint  | read_only            |
   +----------------+------+-------------------+----------------------+
   | 0x000D Bridge  |    0 | Carriage          | variable             |
   +----------------+------+-------------------+----------------------+
   | 0x000E         |    0 | Offer             | read_only            |
   | Commerce       |      |                   |                      |
   +----------------+------+-------------------+----------------------+
   | 0x000E         |    1 | Order             | non_idempotent_write |
   | Commerce       |      |                   |                      |
   +----------------+------+-------------------+----------------------+
   | 0x000E         |    2 | Fulfil            | non_idempotent_write |
   | Commerce       |      |                   |                      |
   +----------------+------+-------------------+----------------------+
   | 0x000E         |    3 | Cancel            | destructive          |
   | Commerce       |      |                   |                      |
   +----------------+------+-------------------+----------------------+
   | 0x000F         |    0 | Elicit            | read_only            |
   | Interaction    |      |                   |                      |
   +----------------+------+-------------------+----------------------+
   | 0x000F         |    1 | Respond           | idempotent_write     |
   | Interaction    |      |                   |                      |
   +----------------+------+-------------------+----------------------+
   | 0x000F         |    2 | Confirm           | non_idempotent_write |
   | Interaction    |      |                   |                      |
   +----------------+------+-------------------+----------------------+
   | 0x0010         |    0 | DiscoveryRecord   | read_only            |
   | Discovery      |      |                   |                      |
   +----------------+------+-------------------+----------------------+
   | 0x0010         |    1 | DiscoveryQuery    | read_only            |
   | Discovery      |      |                   |                      |
   +----------------+------+-------------------+----------------------+
   | 0x0011         |    0 | TaskCreate        | non_idempotent_write |
   | Workflow       |      |                   |                      |
   +----------------+------+-------------------+----------------------+
   | 0x0011         |    1 | TaskInput         | non_idempotent_write |
   | Workflow       |      |                   |                      |
   +----------------+------+-------------------+----------------------+
   | 0x0011         |    2 | TaskCancel        | destructive          |
   | Workflow       |      |                   |                      |
   +----------------+------+-------------------+----------------------+
   | 0x0011         |    3 | TaskResult        | non_idempotent_write |
   | Workflow       |      |                   |                      |
   +----------------+------+-------------------+----------------------+
   | 0x0012         |    0 | Assert            | non_idempotent_write |
   | Knowledge      |      |                   |                      |
   +----------------+------+-------------------+----------------------+

Sammartano                Expires 10 March 2027                [Page 50]
Internet-Draft                   N-AALP                   September 2026

   | 0x0012         |    1 | Retract           | destructive          |
   | Knowledge      |      |                   |                      |
   +----------------+------+-------------------+----------------------+
   | 0x0012         |    2 | KnowledgeQuery    | read_only            |
   | Knowledge      |      |                   |                      |
   +----------------+------+-------------------+----------------------+
   | 0x0013 Spatial |    0 | FrameDefine       | idempotent_write     |
   +----------------+------+-------------------+----------------------+
   | 0x0013 Spatial |    1 | Pose              | read_only            |
   +----------------+------+-------------------+----------------------+
   | 0x0013 Spatial |    2 | StateUpdate       | read_only            |
   +----------------+------+-------------------+----------------------+
   | 0x0013 Spatial |    3 | SnapshotQuery     | read_only            |
   +----------------+------+-------------------+----------------------+

                                 Table 6

19.4.  N-AALP Effect registry

   IANA is requested to create the "N-AALP Effects" registry.
   Registration policy: RFC Required -- an ISE-permissible policy; this
   closed set is not expected to grow, and any addition (via a successor
   RFC) MUST preserve the fail-closed lattice.  Columns: Value (0..3),
   Name, Reference.  Initial contents: read_only 0, idempotent_write 1,
   non_idempotent_write 2, destructive 3, this document.

19.5.  N-AALP Carriage Protocol Id registry

   IANA is requested to create the "N-AALP Carriage Protocol Ids"
   registry, a one-octet space partitioned: standards 0x01-0x0F (RFC
   Required / First Come First Served -- an ISE-permissible policy),
   experimental 0x10-0x7F (no registration), private 0x80-0xFF (no
   registration).  Columns: Protocol Id, Name, Carriage Class,
   Reference.  Initial standards-range contents: 0x01 MCP (JSONRPC),
   0x02 A2A (JSONRPC), 0x03 HTTP (HTTP), 0x04 WebSocket (STREAM), this
   document.

19.6.  N-AALP Error Code registry

   A fail-closed rejection reason is carried on the wire by a *naalp-
   error object* -- a Control/Error object (channel 0x0000, kind 3,
   effect read_only; an error report effects nothing) whose body is the
   map { 1: code (uint), 2: name (tstr), ?3: detail (tstr), ?4: subject
   (bstr content id) } (Appendix A). code is the numeric error code;
   name is its registered name; optional detail is a non-normative human
   diagnostic with no security meaning; optional subject is the content
   id (Section 2.3) of the object the error is about.

Sammartano                Expires 10 March 2027                [Page 51]
Internet-Draft                   N-AALP                   September 2026

   Two dual-carriage rules make the code/name pair unambiguous and
   forward-compatible:

   *  A receiver that recognizes code MUST require name to equal the
      registered name for that code; a code/name disagreement is
      rejected Malformed.  (This is the strengthening direction: the
      numeric code is authoritative and the name cannot contradict it.)

   *  A code outside the receiver's registry snapshot MUST NOT be fatal:
      it is opaque (the name is diagnostic only and no semantics are
      inferred), so a receiver interoperates with a peer that emits a
      later-registered code.

   IANA is requested to create the "N-AALP Error Codes" registry.
   Registration policy: *RFC Required* (First Come First Served in the
   standards range) -- an ISE-permissible policy.  The value space is a
   uint: *1-0x7FFF* is the standards range (RFC Required / FCFS),
   *>=0x8000* is private-use (no registration), and *0 is reserved* and
   MUST NOT appear on the wire.  Columns: Code, Name, Retryable,
   Reference.  Retryable is yes only when an unmodified retry of the
   same object can later succeed because of a transient or environmental
   change (with no object or configuration change); every deterministic
   verification or decode failure is therefore non-retryable (the fail-
   closed default), and the only registered transient is NotDelivered.
   The reference for every initial value is this document.

   Initial contents (assigned sequentially in the order below; the same
   order is the naalp-error-code production of Appendix A):

           +======+===============================+===========+
           | Code | Name                          | Retryable |
           +======+===============================+===========+
           |    1 | NonCanonical                  |     no    |
           +------+-------------------------------+-----------+
           |    2 | DepthExceeded                 |     no    |
           +------+-------------------------------+-----------+
           |    3 | Malformed                     |     no    |
           +------+-------------------------------+-----------+
           |    4 | ContentIdMismatch             |     no    |
           +------+-------------------------------+-----------+
           |    5 | HeaderBodyMismatch            |     no    |
           +------+-------------------------------+-----------+
           |    6 | UnsupportedVersion            |     no    |
           +------+-------------------------------+-----------+
           |    7 | UnknownCriticalExt            |     no    |
           +------+-------------------------------+-----------+
           |    8 | UnknownKind                   |     no    |
           +------+-------------------------------+-----------+

Sammartano                Expires 10 March 2027                [Page 52]
Internet-Draft                   N-AALP                   September 2026

           |    9 | RangeError                    |     no    |
           +------+-------------------------------+-----------+
           |   10 | NonNFC                        |     no    |
           +------+-------------------------------+-----------+
           |   11 | WrongAudience                 |     no    |
           +------+-------------------------------+-----------+
           |   12 | TooLarge                      |     no    |
           +------+-------------------------------+-----------+
           |   13 | TooManyCauses                 |     no    |
           +------+-------------------------------+-----------+
           |   14 | TooManyExtensions             |     no    |
           +------+-------------------------------+-----------+
           |   15 | TooManyChunks                 |     no    |
           +------+-------------------------------+-----------+
           |   16 | UnknownAlg                    |     no    |
           +------+-------------------------------+-----------+
           |   17 | KeyAlgMismatch                |     no    |
           +------+-------------------------------+-----------+
           |   18 | ProfileDowngrade              |     no    |
           +------+-------------------------------+-----------+
           |   19 | HybridIncomplete              |     no    |
           +------+-------------------------------+-----------+
           |   20 | SuiteMismatch                 |     no    |
           +------+-------------------------------+-----------+
           |   21 | CompositeRefused              |     no    |
           +------+-------------------------------+-----------+
           |   22 | BadSignature                  |     no    |
           +------+-------------------------------+-----------+
           |   23 | SignerMismatch                |     no    |
           +------+-------------------------------+-----------+
           |   24 | RotationUnauthorized          |     no    |
           +------+-------------------------------+-----------+
           |   25 | KeyRevoked                    |     no    |
           +------+-------------------------------+-----------+
           |   26 | EffectNotAuthorized           |     no    |
           +------+-------------------------------+-----------+
           |   27 | UnauthenticatedPrincipal      |     no    |
           +------+-------------------------------+-----------+
           |   28 | MalformedSafetyLabel          |     no    |
           +------+-------------------------------+-----------+
           |   29 | ApprovalRequired              |     no    |
           +------+-------------------------------+-----------+
           |   30 | ApprovalMismatch              |     no    |
           +------+-------------------------------+-----------+
           |   31 | ApprovalExpired               |     no    |
           +------+-------------------------------+-----------+
           |   32 | AlreadyConsumed               |     no    |
           +------+-------------------------------+-----------+

Sammartano                Expires 10 March 2027                [Page 53]
Internet-Draft                   N-AALP                   September 2026

           |   33 | ConsumeFork                   |     no    |
           +------+-------------------------------+-----------+
           |   34 | ConsumeForkInvalid            |     no    |
           +------+-------------------------------+-----------+
           |   35 | ConsumeReceiptUnsigned        |     no    |
           +------+-------------------------------+-----------+
           |   36 | LedgerCorrupt                 |     no    |
           +------+-------------------------------+-----------+
           |   37 | LedgerUnsigned                |     no    |
           +------+-------------------------------+-----------+
           |   38 | AudienceMismatch              |     no    |
           +------+-------------------------------+-----------+
           |   39 | FreshnessSelfAsserted         |     no    |
           +------+-------------------------------+-----------+
           |   40 | UnknownRefusalOutcome         |     no    |
           +------+-------------------------------+-----------+
           |   41 | RefusalDetailLeak             |     no    |
           +------+-------------------------------+-----------+
           |   42 | ChainBroken                   |     no    |
           +------+-------------------------------+-----------+
           |   43 | Equivocation                  |     no    |
           +------+-------------------------------+-----------+
           |   44 | CausalViolation               |     no    |
           +------+-------------------------------+-----------+
           |   45 | ReceiptUnsigned               |     no    |
           +------+-------------------------------+-----------+
           |   46 | ForkProofInvalid              |     no    |
           +------+-------------------------------+-----------+
           |   47 | StageOutOfOrder               |     no    |
           +------+-------------------------------+-----------+
           |   48 | StreamDigestMismatch          |     no    |
           +------+-------------------------------+-----------+
           |   49 | StreamStateError              |     no    |
           +------+-------------------------------+-----------+
           |   50 | ConfidentialTransportRequired |     no    |
           +------+-------------------------------+-----------+
           |   51 | PeerUnauthenticated           |     no    |
           +------+-------------------------------+-----------+
           |   52 | NotDelivered                  |    yes    |
           +------+-------------------------------+-----------+
           |   53 | MappingError                  |     no    |
           +------+-------------------------------+-----------+
           |   54 | EffectDeclarationMismatch     |     no    |
           +------+-------------------------------+-----------+
           |   55 | StateTransitionError          |     no    |
           +------+-------------------------------+-----------+
           |   56 | CapExceedsParent              |     no    |
           +------+-------------------------------+-----------+

Sammartano                Expires 10 March 2027                [Page 54]
Internet-Draft                   N-AALP                   September 2026

           |   57 | TransformCycle                |     no    |
           +------+-------------------------------+-----------+
           |   58 | InputGateBypass               |     no    |
           +------+-------------------------------+-----------+
           |   59 | TaskStateError                |     no    |
           +------+-------------------------------+-----------+
           |   60 | ScopeOverlapConflict          |     no    |
           +------+-------------------------------+-----------+
           |   61 | ReconcileMismatch             |     no    |
           +------+-------------------------------+-----------+
           |   62 | WrongFlow                     |     no    |
           +------+-------------------------------+-----------+
           |   63 | SeqGap                        |     no    |
           +------+-------------------------------+-----------+
           |   64 | AboveCeiling                  |     no    |
           +------+-------------------------------+-----------+
           |   65 | GapDetected                   |     no    |
           +------+-------------------------------+-----------+
           |   66 | CommitMismatch                |     no    |
           +------+-------------------------------+-----------+
           |   67 | ContMalformed                 |     no    |
           +------+-------------------------------+-----------+
           |   68 | GrantExpired                  |     no    |
           +------+-------------------------------+-----------+
           |   69 | GrantNotYetValid              |     no    |
           +------+-------------------------------+-----------+
           |   70 | GrantRevoked                  |     no    |
           +------+-------------------------------+-----------+
           |   71 | UntrustedChainRoot            |     no    |
           +------+-------------------------------+-----------+
           |   72 | DelegationDepthExceeded       |     no    |
           +------+-------------------------------+-----------+
           |   73 | GrantMalformed                |     no    |
           +------+-------------------------------+-----------+
           |   74 | NameMalformed                 |     no    |
           +------+-------------------------------+-----------+
           |   75 | NameChainBroken               |     no    |
           +------+-------------------------------+-----------+
           |   76 | NameForkProofInvalid          |     no    |
           +------+-------------------------------+-----------+
           |   77 | IllegalTransition             |     no    |
           +------+-------------------------------+-----------+
           |   78 | TaskChainBroken               |     no    |
           +------+-------------------------------+-----------+
           |   79 | ForeignCard                   |     no    |
           +------+-------------------------------+-----------+
           |   80 | DescMalformed                 |     no    |
           +------+-------------------------------+-----------+

Sammartano                Expires 10 March 2027                [Page 55]
Internet-Draft                   N-AALP                   September 2026

           |   81 | MalformedApprovalFlag         |     no    |
           +------+-------------------------------+-----------+
           |   82 | DirForkProofInvalid           |     no    |
           +------+-------------------------------+-----------+
           |   83 | ImporterMismatch              |     no    |
           +------+-------------------------------+-----------+
           |   84 | UnknownDescriptionFormat      |     no    |
           +------+-------------------------------+-----------+
           |   85 | VerifierKeyMismatch           |     no    |
           +------+-------------------------------+-----------+
           |   86 | NegMalformed                  |     no    |
           +------+-------------------------------+-----------+
           |   87 | UnknownRole                   |     no    |
           +------+-------------------------------+-----------+
           |   88 | UnknownProfile                |     no    |
           +------+-------------------------------+-----------+
           |   89 | NotDescended                  |     no    |
           +------+-------------------------------+-----------+
           |   90 | NotOffer                      |     no    |
           +------+-------------------------------+-----------+
           |   91 | NotAccept                     |     no    |
           +------+-------------------------------+-----------+
           |   92 | MalformedCriticalFlag         |     no    |
           +------+-------------------------------+-----------+
           |   93 | UnknownCriticalRisk           |     no    |
           +------+-------------------------------+-----------+
           |   94 | ReferenceMismatch             |     no    |
           +------+-------------------------------+-----------+
           |   95 | MalformedAnnotation           |     no    |
           +------+-------------------------------+-----------+
           |   96 | EffectUnderDeclared           |     no    |
           +------+-------------------------------+-----------+
           |   97 | EffectOutsideLattice          |     no    |
           +------+-------------------------------+-----------+
           |   98 | ToolCallMalformed             |     no    |
           +------+-------------------------------+-----------+
           |   99 | PayMalformed                  |     no    |
           +------+-------------------------------+-----------+
           |  100 | UnknownPaymentFormat          |     no    |
           +------+-------------------------------+-----------+
           |  101 | GwMalformed                   |     no    |
           +------+-------------------------------+-----------+
           |  102 | UnknownGatewayDecision        |     no    |
           +------+-------------------------------+-----------+
           |  103 | UIMalformed                   |     no    |
           +------+-------------------------------+-----------+
           |  104 | UIChainBroken                 |     no    |
           +------+-------------------------------+-----------+

Sammartano                Expires 10 March 2027                [Page 56]
Internet-Draft                   N-AALP                   September 2026

           |  105 | UnknownUIEventKind            |     no    |
           +------+-------------------------------+-----------+
           |  106 | ActionSubstituted             |     no    |
           +------+-------------------------------+-----------+
           |  107 | UINoConsent                   |     no    |
           +------+-------------------------------+-----------+
           |  108 | StaleEpoch                    |     no    |
           +------+-------------------------------+-----------+
           |  109 | Unauthorized                  |     no    |
           +------+-------------------------------+-----------+
           |  110 | OwnerImmutable                |     no    |
           +------+-------------------------------+-----------+
           |  111 | MemberExists                  |     no    |
           +------+-------------------------------+-----------+
           |  112 | MemberUnknown                 |     no    |
           +------+-------------------------------+-----------+
           |  113 | OwnerExists                   |     no    |
           +------+-------------------------------+-----------+
           |  114 | RoleInvalid                   |     no    |
           +------+-------------------------------+-----------+
           |  115 | RoomOpMismatch                |     no    |
           +------+-------------------------------+-----------+
           |  116 | OpUnknown                     |     no    |
           +------+-------------------------------+-----------+
           |  117 | PrincipalUnknown              |     no    |
           +------+-------------------------------+-----------+
           |  118 | PrincipalExists               |     no    |
           +------+-------------------------------+-----------+
           |  119 | RebindUnauthorized            |     no    |
           +------+-------------------------------+-----------+

                                 Table 7

19.7.  N-AALP Extension Key registry

   IANA is requested to create the "N-AALP Extension Keys" registry, the
   shared key namespace for the non-critical ext (object field 11) and
   critical cext (field 12) maps, so two independent extensions cannot
   collide on a key.  Registration policy: RFC Required (First Come
   First Served in the standards range) -- an ISE-permissible policy.
   Columns: Key (uint), Name, Maps (ext or ext|cext), Reference.
   Initial contents:

Sammartano                Expires 10 March 2027                [Page 57]
Internet-Draft                   N-AALP                   September 2026

         +=====+====================+===========+===============+
         | Key | Name               | Maps      | Reference     |
         +=====+====================+===========+===============+
         |   1 | safety-label       | ext       | this document |
         +-----+--------------------+-----------+---------------+
         |  13 | recheck            | ext\|cext | this document |
         +-----+--------------------+-----------+---------------+
         |  14 | signer-counter     | ext       | this document |
         +-----+--------------------+-----------+---------------+
         |  15 | producing-boundary | ext       | this document |
         +-----+--------------------+-----------+---------------+
         |  16 | naalp-hazard-claim | cext      | this document |
         +-----+--------------------+-----------+---------------+

                                 Table 8

19.8.  N-AALP Carriage Content Type registry

   IANA is requested to create the "N-AALP Carriage Content Types"
   registry for the content_type field (naalp-carriage-body field 3),
   the foreign encoding an OPAQUE-class object carries.  It is a one-
   octet space partitioned: standards 0x00-0x0F (RFC Required / First
   Come First Served -- an ISE-permissible policy), experimental
   0x10-0x7F (no registration), private 0x80-0xFF (no registration).
   Columns: Content Type (uint), Name, Reference.  Initial standards-
   range contents:

              +==============+==============+===============+
              | Content Type | Name         | Reference     |
              +==============+==============+===============+
              |            0 | json         | this document |
              +--------------+--------------+---------------+
              |            1 | octet-stream | this document |
              +--------------+--------------+---------------+
              |            2 | text         | this document |
              +--------------+--------------+---------------+

                                  Table 9

19.9.  N-AALP Trust-Decision Input Class registry

   IANA is requested to create the "N-AALP Trust-Decision Input Classes"
   registry, the closed set of input classes a relying party's decision
   to act may key on, each classified by the safe shape its influence
   must take -- verifiable, attenuating, or committed -- so that a party
   cannot influence a decision except through one of those shapes, or
   the decision fails closed (see the trust-decision-closure-sovereignty
   subsection of the Security Considerations).  Registration policy: RFC

Sammartano                Expires 10 March 2027                [Page 58]
Internet-Draft                   N-AALP                   September 2026

   Required (First Come First Served in the standards range) -- an ISE-
   permissible policy.  Columns: Class (uint), Name, Safe shape,
   Reference.  Initial contents:

     +=======+=========================+=============+===============+
     | Class | Name                    | Safe shape  | Reference     |
     +=======+=========================+=============+===============+
     |     1 | identifier              | verifiable  | this document |
     +-------+-------------------------+-------------+---------------+
     |     2 | object-parse            | verifiable  | this document |
     +-------+-------------------------+-------------+---------------+
     |     3 | object-identity         | verifiable  | this document |
     +-------+-------------------------+-------------+---------------+
     |     4 | conformance-expectation | verifiable  | this document |
     +-------+-------------------------+-------------+---------------+
     |     5 | verification-procedure  | verifiable  | this document |
     +-------+-------------------------+-------------+---------------+
     |     6 | delegated-authority     | attenuating | this document |
     +-------+-------------------------+-------------+---------------+
     |     7 | approved-action         | committed   | this document |
     +-------+-------------------------+-------------+---------------+
     |     8 | negotiated-parameters   | committed   | this document |
     +-------+-------------------------+-------------+---------------+
     |     9 | validity-clock          | committed   | this document |
     +-------+-------------------------+-------------+---------------+
     |    10 | use-context             | committed   | this document |
     +-------+-------------------------+-------------+---------------+

                                  Table 10

19.10.  COSE algorithms

   N-AALP reuses the existing IANA COSE Algorithms registry for ML-DSA
   [RFC9964] and Ed25519 [RFC9864] and requests no new COSE code points.

19.11.  Registration criteria for the RFC-Required registries

   The Independent stream appoints no Designated Expert, so the RFC-
   Required registries above are self-administered: a registration is
   made by a successor RFC (or by First Come First Served in the
   standards range) and MUST satisfy the same four criteria a reviewer
   would otherwise confirm: (1) a stable, publicly available
   specification documents the value; (2) the value does not collide
   with an existing entry; (3) the name is protocol-neutral and carries
   no vendor product name; and (4) for object kinds, the declared effect
   is one of the closed set and preserves the fail-closed model.

Sammartano                Expires 10 March 2027                [Page 59]
Internet-Draft                   N-AALP                   September 2026

20.  Implementation Status

   RFC-Editor: please remove this section and the reference to [RFC7942]
   before publication.

   This section records the status of known implementations at the time
   of posting, per [RFC7942].  Listing here does not imply endorsement.

   Two independent reference implementations exist, in Go and in Rust,
   from a single codebase but separate language runtimes.  For every
   construction carrying a security or interoperability claim
   (deterministic CBOR and content id; COSE_Sign1 and the ML-DSA/Ed25519
   profiles; the object envelope; signer id; effect authorization;
   approval and the consume ledger; audit chain, causal graph, and
   federated reconcile; delivery; streaming; transport bindings; foreign
   carriage; and the twenty channel surfaces), the two implementations
   produce byte-identical output and are cross-validated against an
   independent oracle whose expected values come from the relevant RFC,
   FIPS, or NIST vector or a from-scratch constructor, never from the
   implementation under test.  A runnable conformance harness grades
   every construction and validates the CDDL module against the
   committed vectors.  Coverage and known gaps are tracked in the
   project's parity ledger.

21.  Conformance

   A conforming implementation MUST implement the object model, the
   signing constructions, identity, effects and authorization, and the
   baseline surfaces of every channel, and MUST reject a non-conforming
   object whole with its named error and no state change (fail-closed).
   Conformance is demonstrated against the machine-gradable vector
   corpus and the CDDL module (Appendix A).  This specification
   recommends, but does not require for Independent-stream publication,
   two independent interoperating implementations; two exist (#
   Implementation Status).

   This specification tiers its surfaces by editorial status, so a first
   conforming implementation is not asked to build the whole surface at
   once.  The normative surface required for conformance is the spine --
   the object model, the signing constructions, identity, effects and
   authorization, approval and the single-use consume ledger, the
   baseline audit receipt chain, delivery, the per-stream commitment,
   the transport bindings, and the carriage-never-decodes rule --
   together with the frozen baseline surface (tier 0) of every channel.
   Every capability an object gains above tier 0, including the
   federated higher tier of ordering and any higher channel tier carried
   through the tier field and critical or non-critical extensions, has
   experimental status: it is OPTIONAL, it MAY change in a later

Sammartano                Expires 10 March 2027                [Page 60]
Internet-Draft                   N-AALP                   September 2026

   revision, and an implementation that omits it is still conforming.
   An implementation that does provide such a capability MUST provide it
   exactly as specified, and a verifier that does not recognize a
   critical extension MUST reject the object fail-closed (# Object
   Model).  This tiering is editorial: it bounds what conformance
   requires, not what the reference implementations provide, which is
   the full surface across all ten reference languages (# Implementation
   Status).

22.  Specification License

   This specification may be implemented by anyone, royalty-free.  This
   right to implement is granted independently of the license of any
   reference implementation (the reference code is licensed separately).
   Contributions to this document are subject to BCP 78 and the IETF
   Trust's Legal Provisions Relating to IETF Documents.

23.  Normative References

   [BCP14]    Best Current Practice 14,
              <https://www.rfc-editor.org/info/bcp14>.
              At the time of writing, this BCP comprises the following:

              Bradner, S., "Key words for use in RFCs to Indicate
              Requirement Levels", BCP 14, RFC 2119,
              DOI 10.17487/RFC2119, March 1997,
              <https://www.rfc-editor.org/info/rfc2119>.

              Leiba, B., "Ambiguity of Uppercase vs Lowercase in RFC
              2119 Key Words", BCP 14, RFC 8174, DOI 10.17487/RFC8174,
              May 2017, <https://www.rfc-editor.org/info/rfc8174>.

   [FIPS180]  National Institute of Standards and Technology, "Secure
              Hash Standard (SHS) (FIPS 180-4)", 2015.

   [FIPS204]  National Institute of Standards and Technology, "Module-
              Lattice-Based Digital Signature Standard (FIPS 204)",
              2024.

   [RFC6838]  Freed, N., Klensin, J., and T. Hansen, "Media Type
              Specifications and Registration Procedures", BCP 13,
              RFC 6838, DOI 10.17487/RFC6838, January 2013,
              <https://www.rfc-editor.org/rfc/rfc6838>.

   [RFC8032]  Josefsson, S. and I. Liusvaara, "Edwards-Curve Digital
              Signature Algorithm (EdDSA)", RFC 8032,
              DOI 10.17487/RFC8032, January 2017,
              <https://www.rfc-editor.org/rfc/rfc8032>.

Sammartano                Expires 10 March 2027                [Page 61]
Internet-Draft                   N-AALP                   September 2026

   [RFC8126]  Cotton, M., Leiba, B., and T. Narten, "Guidelines for
              Writing an IANA Considerations Section in RFCs", BCP 26,
              RFC 8126, DOI 10.17487/RFC8126, June 2017,
              <https://www.rfc-editor.org/rfc/rfc8126>.

   [RFC8610]  Birkholz, H., Vigano, C., and C. Bormann, "Concise Data
              Definition Language (CDDL): A Notational Convention to
              Express Concise Binary Object Representation (CBOR) and
              JSON Data Structures", RFC 8610, DOI 10.17487/RFC8610,
              June 2019, <https://www.rfc-editor.org/rfc/rfc8610>.

   [RFC8949]  Bormann, C. and P. Hoffman, "Concise Binary Object
              Representation (CBOR)", STD 94, RFC 8949,
              DOI 10.17487/RFC8949, December 2020,
              <https://www.rfc-editor.org/rfc/rfc8949>.

   [RFC9052]  Schaad, J., "CBOR Object Signing and Encryption (COSE):
              Structures and Process", STD 96, RFC 9052,
              DOI 10.17487/RFC9052, August 2022,
              <https://www.rfc-editor.org/rfc/rfc9052>.

   [RFC9053]  Schaad, J., "CBOR Object Signing and Encryption (COSE):
              Initial Algorithms", RFC 9053, DOI 10.17487/RFC9053,
              August 2022, <https://www.rfc-editor.org/rfc/rfc9053>.

   [RFC9864]  Jones, M.B. and O. Steele, "Fully-Specified Algorithms for
              JSON Object Signing and Encryption (JOSE) and CBOR Object
              Signing and Encryption (COSE)", RFC 9864,
              DOI 10.17487/RFC9864, October 2025,
              <https://www.rfc-editor.org/rfc/rfc9864>.

   [RFC9964]  Prorock, M. and O. Steele, "ML-DSA for JSON Object Signing
              and Encryption (JOSE) and CBOR Object Signing and
              Encryption (COSE)", RFC 9964, DOI 10.17487/RFC9964, May
              2026, <https://www.rfc-editor.org/rfc/rfc9964>.

24.  Informative References

   [NPAMP]    Sammartano, S., "N-PAMP: Native Post-Quantum Agent
              Messaging Protocol", Work in Progress, Internet-Draft,
              draft-bubblefish-npamp (work in progress), 2026,
              <https://datatracker.ietf.org/doc/html/draft-bubblefish-
              npamp (work in progress)>.

   [RFC6839]  Hansen, T. and A. Melnikov, "Additional Media Type
              Structured Syntax Suffixes", RFC 6839,
              DOI 10.17487/RFC6839, January 2013,
              <https://www.rfc-editor.org/rfc/rfc6839>.

Sammartano                Expires 10 March 2027                [Page 62]
Internet-Draft                   N-AALP                   September 2026

   [RFC7942]  Sheffer, Y. and A. Farrel, "Improving Awareness of Running
              Code: The Implementation Status Section", BCP 205,
              RFC 7942, DOI 10.17487/RFC7942, July 2016,
              <https://www.rfc-editor.org/rfc/rfc7942>.

   [RFC9162]  Laurie, B., Messeri, E., and R. Stradling, "Certificate
              Transparency Version 2.0", RFC 9162, DOI 10.17487/RFC9162,
              December 2021, <https://www.rfc-editor.org/rfc/rfc9162>.

   [RFC9943]  Birkholz, H., Delignat-Lavaud, A., Fournet, C., Deshpande,
              Y., and S. Lasker, "An Architecture for Trustworthy and
              Transparent Digital Supply Chains", RFC 9943,
              DOI 10.17487/RFC9943, June 2026,
              <https://www.rfc-editor.org/rfc/rfc9943>.

Appendix A.  Collected CDDL

   This appendix is the complete and normative CDDL module for the
   N-AALP byte-level wire format.  It defines the object body, effect,
   and profile productions of (# Object Model) and the carriage body of
   (# Foreign Carriage by Class), together with the COSE wrapper,
   protected header, identity records, safety label, approval and
   consume records, receipt, delivery update, stream objects, and the
   federated reconcile record.  A byte-identical copy is maintained with
   the reference implementation and machine-validated against the
   conformance vectors.  Where a CDDL excerpt elsewhere in this document
   differs from this appendix, this appendix is authoritative.

   ; draft-bubblefish-naalp-01 -- Native Agentic Application Layer
   ; Protocol: the complete CDDL wire-format module (RFC 8610). The copy
   ; in Appendix A of the Internet-Draft is normative; the copy
   ; maintained with the reference implementation is a byte-identical
   ; mirror, machine-validated for well-formedness and against the
   ; conformance vector corpus.
   ;
   ; This module is complete: the object body, the effect, profile, and
   ; channel vocabularies, the COSE_Sign1 / COSE_Sign wrapper (RFC 9052
   ; Section 4), the protected header, the identity records, the safety
   ; label, the approval and consume records, the receipt and ForkProof,
   ; the delivery update, the stream objects, the carriage body, the
   ; channel-registry note, the federated reconcile record, and the
   ; collaboration/rooms membership records (room op + principal
   ; binding) -- all reachable from the `naalp-artifact` root.
   ;
   ; All instances are deterministic CBOR per RFC 8949 Section 4.2.1
   ; (shortest heads, map keys ascending by encoded bytes, no indefinite
   ; lengths, no duplicate keys). A non-canonical encoding of any
   ; production here is rejected.

Sammartano                Expires 10 March 2027                [Page 63]
Internet-Draft                   N-AALP                   September 2026

   ; ---- Collected root -----------------------------------------------
   ; The set of top-level N-AALP artifacts this module defines, as a
   ; single reachable root so a CDDL tool sees no unreferenced rule.
   ; Each concrete instance is validated against the specific production
   ; for its kind (the conformance harness targets the rule per
   ; construction), not against this union; the union exists only for
   ; reachability.
   naalp-artifact = naalp-object
     / naalp-signed-object / naalp-protected-header
     / naalp-rotation / naalp-revocation / naalp-foreign-link
     / naalp-safety-label
     / naalp-approval / naalp-approval-held / naalp-consume-entry
     / naalp-consume-receipt
     / naalp-receipt / naalp-fork-proof / naalp-delivery-update
     / naalp-stream-open / naalp-stream-commit / naalp-stream-checkpoint
     / naalp-carriage-body / naalp-reconcile
     / naalp-room-op / naalp-principal-binding
     / naalp-delegation-grant
     / recheck-procedure / signer-counter
     / naalp-mcp-tool-call / naalp-mcp-annotations
     / naalp-mcp-call-binding / mcp-hint
     / naalp-flow-open / naalp-continuation / naalp-flow-checkpoint
     / naalp-flow-commit
     / naalp-description / naalp-directory / naalp-description-import
     / naalp-name-binding / naalp-task-transition
     / naalp-negotiation-offer / naalp-negotiation-counter
     / naalp-negotiation-accept
     / negotiation-role
     / naalp-risk-label / naalp-labeled-object / naalp-trust-ref
     / naalp-payment-import / naalp-payment-charge-binding
     / naalp-payment-format
     / naalp-ui-event / ui-event-kind
     / naalp-gateway-decision / gw-decision
     / naalp-refusal / refusal-outcome
     / naalp-error / naalp-error-code
     / trust-decision-input-class
     / naalp-decision-record / ordering-basis
     / naalp-checkpoint-root / naalp-witness-cosign / naalp-inclusion-proof
     / naalp-egress-attestation / egress-binding
     / naalp-foreign-profile-pin
     / naalp-hazard-claim / naalp-hazard-authorization
     / hazard-class / hazard-envelope / spatial-bounds / hazard-window

   ; Decoder resource bounds -- CDDL cannot express element counts,
   ; nesting depth, or octet size (RFC 8610 restricts none of these), so
   ; these are MUST-level limits every decoder enforces fail-closed, not
   ; this schema: object octet size <= 1 MiB (TooLarge, on raw bytes
   ; before parse); |causes| (field 8) <= 1024 (TooManyCauses); |ext|

Sammartano                Expires 10 March 2027                [Page 64]
Internet-Draft                   N-AALP                   September 2026

   ; (11) and |cext| (12) <= 64 each (TooManyExtensions); CBOR nesting
   ; depth <= 16 with the outermost item at depth 1 (DepthExceeded);
   ; stream chunk count <= 2^20 (TooManyChunks, native streaming below).
   ; The maxima are wire constants, projected identically into all ten
   ; ports so one port cannot accept what another refuses. The object
   ; body -- the map that is signed as the COSE_Sign1 payload.
   naalp-object = {
     1 : bstr,
     ; id -- content id: multihash(0x20, SHA-384(body-without-1))
     2 : uint,
     ; kind -- object kind code (per channel surface)
     3 : channel-id,
     ; channel -- N-PAMP channel id
     4 : uint,
     ; tier -- channel capability tier (0 = baseline)
     5 : bstr,
     ; signer -- self-certifying signer id
     6 : uint,
     ; created -- signer's claimed creation time, epoch ms (advisory)
     7 : effect,
     ; effect -- closed effect value
     8 : [* bstr],
     ; causes -- content ids of causing objects; may be empty
     9 : profile,
     ; profile -- crypto profile
     10 : any,
     ; body -- kind-specific body, validated by the channel surface
     ? 11 : { * uint => any },
     ; ext -- non-critical extensions; unknown keys ignored
     ? 12 : { * uint => any },
     ; cext -- critical extensions; any unknown key => reject
     ? 13 : tstr,
     ; audience -- endpoint/channel-scope id the object is bound to.
     ; OMITTED when empty -- a no-audience object encodes byte-
     ; identically to a draft-00 object. MANDATORY for consume-once
     ; kinds (enforced by channel-surface validation, not this
     ; cardinality). A verifier rejects an object whose audience is not
     ; itself: WrongAudience. This is object-map FIELD 13 (a top-level
     ; envelope field) -- the genuine draft-01 envelope addition that
     ; anchors naalp-version 2. DISTINCT namespace from ext/cext KEY 13
     ; (recheck) below, which is a key INSIDE the field-11/12 maps, not
     ; a top-level object field.
     ? 14 : uint,
     ; suite -- signed suite declaration: PRESENT iff the object's alg
     ; is the composite id -65537; ABSENT (byte-identical to a pure
     ; object) for a pure ML-DSA object. Value 1 = COMPSIG-MLDSA65-
     ; Ed25519-SHA512. Top-level object FIELD 14 -- DISTINCT namespace
     ; from ext key 14 (signer-counter) INSIDE the field-11/12 maps

Sammartano                Expires 10 March 2027                [Page 65]
Internet-Draft                   N-AALP                   September 2026

     ; below.
     ; The ext (11) / cext (12) extension-KEY namespace is a single
     ; registry (RFC Required / FCFS) so two implementers assigning keys
     ; cannot COLLIDE -- a critical-ext collision is a denial; the
     ; registry_drift gate asserts key uniqueness + agreement with the
     ; per-capability registries. The currently-registered keys are 1
     ; safety-label (ext), 13 recheck (ext/cext), 14 signer-counter
     ; (ext), 15 producing-boundary (ext), 16 naalp-hazard-claim
     ; (cext): ext/cext key 13 = recheck: it
     ; names the body claim's re-check procedure by id
     ; (recheck-procedure below). In ext (11) it is may-ignore (an
     ; unknown id ignored); in cext (12) it is must-understand (an
     ; unknown id => UnknownCriticalExt, the same rule).
     ; ext key 14 = signer-counter: an OPTIONAL forward-only per-signer
     ; position (signer-counter below). It rides the NON-CRITICAL ext
     ; map (11)
     ; ONLY -- a detection aid, not a verification gate -- so it is
     ; may-ignore; placing it in cext (12) is an unrecognized critical
     ; key => UnknownCriticalExt (the same rule). It is covered by the
     ; SIGNER's own COSE_Sign1 signature (ext is part of the signed
     ; body). Detection, not prevention (# Security Considerations). ext
     ; key 15 = producing-boundary: an OPTIONAL per-object disclosure
     ; (naalp-producing-boundary below). of the trust boundary that
     ; emitted the object and whether that boundary OBSERVED the event
     ; first-hand or RELAYED a report of it. It rides the NON-CRITICAL
     ; ext map (11) ONLY -- a disclosure, not a verification gate -- so
     ; it is may-ignore (a verifier that does not understand it, or
     ; reads a malformed value, ignores the entry and the object still
     ; verifies); placing it in cext (12) is an unrecognized critical
     ; key => UnknownCriticalExt (the same rule). It is covered by the
     ; SIGNER's own COSE_Sign1 signature (ext is part of the signed
     ; body), so it is SELF-ASSERTED; it establishes record-order /
     ; observational domain, NOT cross-boundary event precedence (#
     ; Security Considerations).
     ; cext key 16 = naalp-hazard-claim: an OPTIONAL critical
     ; must-understand physical-hazard claim (naalp-hazard-claim below) --
     ; the hazard dimension orthogonal to effect (physical danger, not
     ; data reversibility). It rides the CRITICAL cext map (12) ONLY: a
     ; safety gate, so a verifier that has not implemented Component F
     ; rejects the WHOLE object (UnknownCriticalExt) rather than letting a
     ; hazardous action through unchecked -- the fail-closed direction,
     ; the OPPOSITE of producing-boundary's may-ignore ext placement. It
     ; is covered by the SIGNER's own COSE_Sign1 signature (cext is part
     ; of the signed body).
   }

   ; Closed effect vocabulary, aligned 1:1 with the N-PAMP Bridge
   ; SafetyLabel. An unrecognized effect is treated as destructive,

Sammartano                Expires 10 March 2027                [Page 66]
Internet-Draft                   N-AALP                   September 2026

   ; never fail-open.
   effect = &(
     read_only:            0,
     idempotent_write:     1,
     non_idempotent_write: 2,
     destructive:          3,
   )

   ; Crypto profiles -- one wire, per-profile row.
   profile = &(
     public:     1,
     enterprise: 2,
     sovereign:  3,
   )

   ; N-PAMP channel ids 0x0000..0x0013 -- the twenty channels.
   channel-id = 0..19

   ; ---- COSE signing wrapper (RFC 9052) ------------------------------
   ; On the wire, an N-AALP object is a tagged COSE structure whose
   ; payload is the deterministic-CBOR `naalp-object` body above. A
   ; single signature uses COSE_Sign1 (tag 18) -- either a pure ML-DSA
   ; signature (per profile) or the opt-in classical-bridge signature: a
   ; single COSE_Sign1 under the private-use composite alg id -65537
   ; whose signature value is the IETF LAMPS composite mldsaSig(3309) ||
   ; tradSig(64). COSE_Sign (tag 98, multiple signatures) carries two
   ; roles: the legacy two-signature Ed25519+ML-DSA hybrid (OPTIONAL;
   ; not required by the Standard profile), and the Rotation object
   ; co-signature (channel 3 / kind 0; old-key then new-key legs, both
   ; required); a channel-3/kind-0 object MUST be tag 98, and a tag-18
   ; single-signature rotation is rejected RotationUnauthorized. Signing
   ; is the FIPS 204 deterministic variant (rnd = 0) so two
   ; implementations produce byte-identical signatures.
   ;

   naalp-signed-object = COSE_Sign1_Tagged / COSE_Sign_Tagged

   COSE_Sign1_Tagged = #6.18(COSE_Sign1)
   COSE_Sign1 = [
     protected   : bstr,
     ; serialized protected header {1 => cose-alg}; empty => zero-length
     ; bstr 0x40 (reject the 0x41A0 bstr-wrapped-empty-map form)
     unprotected : cose-header,
     payload     : bstr,
     ; the deterministic-CBOR naalp-object body (the signed payload)
     signature   : bstr,
   ]

Sammartano                Expires 10 March 2027                [Page 67]
Internet-Draft                   N-AALP                   September 2026

   COSE_Sign_Tagged = #6.98(COSE_Sign)
   ; optional hybrid (Ed25519 + ML-DSA)
   COSE_Sign = [
     protected   : bstr,
     ; body protected header: empty for the legacy hybrid; for a
     ; Rotation object (channel 3/kind 0) the enriched naalp header {1:
     ; newKeyAlg, "naalp": {...}}
     unprotected : cose-header,
     payload     : bstr,
     signatures  : [+ COSE_Signature],
   ]
   COSE_Signature = [
     protected   : bstr,
     ; serialized per-signer header {1 => cose-alg}
     unprotected : cose-header,
     signature   : bstr,
   ]

   cose-header = { * (int / tstr) => any }

   ; COSE algorithm ids. ML-DSA from RFC 9964; Ed25519 from RFC 9864.
   ; SLH-DSA (FIPS 205) is reserved, addable with no envelope change
   ; once its COSE code point is assigned.
   cose-alg = &(
     ml-dsa-44: -48,
     ; NIST level 2 -- optional edge/light tier only, never a
     ; Public/Enterprise/Sovereign default
     ml-dsa-65: -49,
     ; NIST level 3 -- Public / Enterprise default (MTI)
     ml-dsa-87: -50,
     ; NIST level 5 -- Sovereign default / mandate
     ed25519:   -19,
     ; classical, opt-in composite leg only
     compsig-mldsa65-ed25519: -65537,
     ; opt-in LAMPS composite (Public/Enterprise) -- COSE private-use,
     ; N-AALP provisional
     compsig-mldsa44-ed25519: -65538,
     ; edge composite suite -- RESERVED (registered, not implemented
     ; this wave)
   )

   ; ---- object envelope protected header -----------------------------
   ; A COSE_Sign1 over an N-AALP object uses this protected header: the
   ; COSE `alg` plus a pre-parse routing copy of the signer, profile,
   ; and naalp-version, carried under a text-string label ("naalp"). A
   ; tstr label cannot collide with any integer-labeled standard COSE
   ; header parameter (RFC 9052 Section 3.1). A verifier MUST reject an
   ; object whose header signer/profile copies disagree with the body's

Sammartano                Expires 10 March 2027                [Page 68]
Internet-Draft                   N-AALP                   September 2026

   ; field 5 / field 9 (HeaderBodyMismatch). An empty protected header
   ; is a zero-length bstr (RFC 9052 Section 3); the N-AALP object
   ; header is never empty (it always carries alg + "naalp"). Per this
   ; disposition, the redundant 0x41A0 encoding of an empty protected
   ; header (a bstr wrapping an empty map) MUST be rejected as
   ; NonCanonical, at every protected-header parse site, before the
   ; header is interpreted.
   naalp-protected-header = {
     1 : cose-alg,
     ; COSE algorithm id
     "naalp" : naalp-header-meta,
   }
   naalp-header-meta = {
     1 : bstr,
     ; signer -- copy of object body field 5
     2 : profile,
     ; profile -- copy of object body field 9
     3 : uint,
     ; naalp-version (draft-01: 2; draft-00 was 1 -- anchored by the
     ; audience envelope field)
   }

   ; ---- identity + key lifecycle -------------------------------------
   ; The signer id (envelope field 5) is a self-certifying multibase
   ; string, identical in form to the N-PAMP PeerHandle: signer =
   ; multibase(base32, multihash(0x12, SHA-256(multicodec(mc, pubkey))))
   ; mc is a multiformats key-type code: 0xed (ed25519-pub), 0x1211
   ; (mldsa-65-pub), 0x1212 (mldsa-87-pub) -- all draft status; 0x12
   ; (sha2-256) is permanent. base32 is RFC 4648 lowercase without
   ; padding (multibase prefix "b"). A verifier recomputes the id from
   ; the key and rejects a mismatch (SignerMismatch); no CA.
   ;
   ; Identity-channel (0x0003) lifecycle record bodies (carried in
   ; envelope field 10 by the channel surface):
   naalp-rotation = {
   ; co-signed by BOTH the old and new key
     1 : tstr,
     ; old -- prior signer id
     2 : tstr,
     ; new -- successor signer id
     3 : uint,
     ; not_before (epoch ms)
   }
   naalp-revocation = {
   ; signed by the key it revokes (or a recovery key)
     1 : tstr,
     ; key -- the signer id being revoked
     2 : uint,

Sammartano                Expires 10 March 2027                [Page 69]
Internet-Draft                   N-AALP                   September 2026

     ; not_after (epoch ms)
   }
   naalp-foreign-link = {
   ; cross-signed by the FOREIGN identity's key
     1 : tstr,
     ; controls -- the N-AALP signer id
     2 : tstr,
     ; foreign_id -- foreign identifier; MUST be NFC (else NonNFC)
     3 : uint,
     ; not_after (epoch ms)
   }

   ; ---- effect authorization + safety label --------------------------
   ; The effect (object body field 7) is the closed four-value set
   ; defined above
   ; (read_only/idempotent_write/non_idempotent_write/destructive),
   ; aligned 1:1 with the N-PAMP Bridge SafetyLabel u8 (NPAMP draft-01
   ; 10_bridge_framework Section 7): 0x00..0x03, an identity map, so
   ; carriage over the Bridge is loss-free. The values form a LATTICE
   ; with destructive at the top.
   ;
   ; The effect is an AUTHORIZATION INPUT, not a hint -- closing the gap
   ; N-PAMP names and leaves open ("describes intent and does not
   ; replace authorization"). An endpoint grants a maximum effect (a
   ; capability) to an AUTHENTICATED signer id, and an object is
   ; authorized iff effect <= granted (the lattice); otherwise it is
   ; denied (EffectNotAuthorized). An effect value the evaluator does
   ; not recognize is treated as destructive and MUST NOT fail open. No
   ; layer authorizes from transport metadata, a foreign header, or a
   ; client-supplied name (UnauthenticatedPrincipal). This is endpoint
   ; policy, not a wire production: the wire carries only the effect
   ; value (field 7).
   ;
   ; The OPTIONAL safety label is a signed, non-critical ext entry under
   ; ext key 1 (object body field 11). It is attributable to the
   ; object's signer and auditable; it is an ACCOUNTABLE CLAIM, NOT a
   ; guarantee that the content is safe.
   naalp-safety-label = {
   ; ext[1]
     1 : tstr,
     ; risk -- an accountable risk claim (e.g. "elevated")
     2 : tstr,
     ; scope -- what the object affects (e.g. "billing-records")
   }

   ; ---- approval + single-use consume ledger -------------------------
   ; An Approval binds, UNDER SIGNATURE, the content id of the exact
   ; canonical argument object it approves. Because the args are named

Sammartano                Expires 10 March 2027                [Page 70]
Internet-Draft                   N-AALP                   September 2026

   ; by content id, mutating any argument changes that id and the
   ; approval no longer matches (ApprovalMismatch). The approval is not
   ; valid across sessions/contexts (it carries a nonce) nor after
   ; not_after (ApprovalExpired), and once consumed it is dead. These
   ; record bodies are signed with the crypto over deterministic CBOR;
   ; wrapping them as Governance-channel (0x0004) objects.
   naalp-approval = {
     1 : bstr,
     ; approves -- content id of the exact args object
     2 : tstr,
     ; approver -- approver signer id
     3 : effect,
     ; grant -- the granted effect class
     4 : bstr,
     ; nonce -- anti-replay nonce
     5 : uint,
     ; not_after -- expiry, epoch ms
     ? 6 : tstr,
     ; audience -- OPTIONAL valid-context; field omitted = unrestricted
     ; by the issuer's explicit choice; when present, a relying party
     ; checks it at use and rejects AudienceMismatch on mismatch. An
     ; empty string is not a distinct value -- omit field 6 to mean
     ; absent.
   }
   ; A held outcome -- approval required but not yet granted -- is a
   ; DISTINCT signed non-success result, never a silent success or
   ; denial.
   naalp-approval-held = {
     1 : bstr,
     ; approves -- content id of the args whose approval is pending
     2 : tstr,
     ; reason -- accountable explanation
   }
   ; PARTY-VISIBLE COARSE REFUSAL. A refusal returned to the
   ; authenticated party carries ONLY a single value from a closed
   ; vocabulary and the content id of the full signed record -- a
   ; reference, not the reason. Every discriminating detail lives only
   ; in that full signed record (a naalp-approval-held, a
   ; naalp-gateway-decision, or an audit event), resolvable by a party
   ; authorized to read it, so repeated refusals cannot serve an
   ; adaptive party as an oracle. A party-visible refusal that carries
   ; discriminating detail, or omits the record content id, is a
   ; RefusalDetailLeak. An outcome outside the closed set is
   ; UnknownRefusalOutcome.
   refusal-outcome = &(
     denied:       0,
     ; the action is refused
     held:         1,

Sammartano                Expires 10 March 2027                [Page 71]
Internet-Draft                   N-AALP                   September 2026

     ; the action requires a further step not yet taken
     unverifiable: 2,
     ; required evidence did not verify
   )
   naalp-refusal = {
     1 : refusal-outcome,
     ; outcome -- the coarse, party-visible outcome (closed set)
     2 : bstr,
     ; record -- content id of the full signed record carrying the
     ; detail
   }
   ; N-AALP ERROR OBJECT (Control/Error surface: channel 0x0000, kind
   ; 3). The body of a Control/Error object. It reports one fail-closed
   ; rejection reason as BOTH a numeric `code` (field 1) and its
   ; registered `name` (field 2), plus an OPTIONAL free-text `detail`
   ; (field 3) and an OPTIONAL `subject` content id (field 4, the object
   ; the error is about). The Control/Error kind has effect read_only
   ; (kind table) -- an error report effects nothing. Field 1 is `code :
   ; uint`, deliberately NOT the naalp-error-code enum below, so a code
   ; from a LATER-registered or private-use point still validates
   ; against this grammar (the open, RFC-Required registry).
   ; DUAL-CARRIAGE: a receiver that KNOWS `code` MUST find `name` equal
   ; to the registered name for that code, else it rejects `Malformed`
   ; (the strengthening direction); a `code` it does NOT know is opaque
   ; and non-fatal (name diagnostic only, no semantics inferred), for
   ; forward compatibility. The authoritative name<->code taxonomy is
   ; the naalp-error-code enum below.
   naalp-error = {
     1 : uint,
     ; code -- registered error code (standards 1..0x7FFF; private
     ; >=0x8000)
     2 : tstr,
     ; name -- the registered name for `code` (MUST agree; else
     ; Malformed)
     ? 3 : tstr,
     ; detail -- OPTIONAL non-normative human diagnostic (no security
     ; meaning)
     ? 4 : bstr,
     ; subject -- OPTIONAL content id of the object the error is about
   }
   ; N-AALP ERROR CODES registry (# IANA). Registration policy RFC
   ; Required / FCFS in the standards range 1..0x7FFF; >=0x8000 is
   ; private-use, no registration; 0 is reserved and MUST NOT appear on
   ; the wire. The naalp-error body above binds `code` as a bare uint,
   ; NOT this enum, so the registry can grow without breaking CDDL
   ; validation of a future or private code. This enum is the
   ; authoritative error-code taxonomy.
   ;

Sammartano                Expires 10 March 2027                [Page 72]
Internet-Draft                   N-AALP                   September 2026

   naalp-error-code = &(
     NonCanonical: 1,
     DepthExceeded: 2,
     Malformed: 3,
     ContentIdMismatch: 4,
     HeaderBodyMismatch: 5,
     UnsupportedVersion: 6,
     UnknownCriticalExt: 7,
     UnknownKind: 8,
     RangeError: 9,
     NonNFC: 10,
     WrongAudience: 11,
     TooLarge: 12,
     TooManyCauses: 13,
     TooManyExtensions: 14,
     TooManyChunks: 15,
     UnknownAlg: 16,
     KeyAlgMismatch: 17,
     ProfileDowngrade: 18,
     HybridIncomplete: 19,
     SuiteMismatch: 20,
     CompositeRefused: 21,
     BadSignature: 22,
     SignerMismatch: 23,
     RotationUnauthorized: 24,
     KeyRevoked: 25,
     EffectNotAuthorized: 26,
     UnauthenticatedPrincipal: 27,
     MalformedSafetyLabel: 28,
     ApprovalRequired: 29,
     ApprovalMismatch: 30,
     ApprovalExpired: 31,
     AlreadyConsumed: 32,
     ConsumeFork: 33,
     ConsumeForkInvalid: 34,
     ConsumeReceiptUnsigned: 35,
     LedgerCorrupt: 36,
     LedgerUnsigned: 37,
     AudienceMismatch: 38,
     FreshnessSelfAsserted: 39,
     UnknownRefusalOutcome: 40,
     RefusalDetailLeak: 41,
     ChainBroken: 42,
     Equivocation: 43,
     CausalViolation: 44,
     ReceiptUnsigned: 45,
     ForkProofInvalid: 46,
     StageOutOfOrder: 47,

Sammartano                Expires 10 March 2027                [Page 73]
Internet-Draft                   N-AALP                   September 2026

     StreamDigestMismatch: 48,
     StreamStateError: 49,
     ConfidentialTransportRequired: 50,
     PeerUnauthenticated: 51,
     NotDelivered: 52,
     MappingError: 53,
     EffectDeclarationMismatch: 54,
     StateTransitionError: 55,
     CapExceedsParent: 56,
     TransformCycle: 57,
     InputGateBypass: 58,
     TaskStateError: 59,
     ScopeOverlapConflict: 60,
     ReconcileMismatch: 61,
     WrongFlow: 62,
     SeqGap: 63,
     AboveCeiling: 64,
     GapDetected: 65,
     CommitMismatch: 66,
     ContMalformed: 67,
     GrantExpired: 68,
     GrantNotYetValid: 69,
     GrantRevoked: 70,
     UntrustedChainRoot: 71,
     DelegationDepthExceeded: 72,
     GrantMalformed: 73,
     NameMalformed: 74,
     NameChainBroken: 75,
     NameForkProofInvalid: 76,
     IllegalTransition: 77,
     TaskChainBroken: 78,
     ForeignCard: 79,
     DescMalformed: 80,
     MalformedApprovalFlag: 81,
     DirForkProofInvalid: 82,
     ImporterMismatch: 83,
     UnknownDescriptionFormat: 84,
     VerifierKeyMismatch: 85,
     NegMalformed: 86,
     UnknownRole: 87,
     UnknownProfile: 88,
     NotDescended: 89,
     NotOffer: 90,
     NotAccept: 91,
     MalformedCriticalFlag: 92,
     UnknownCriticalRisk: 93,
     ReferenceMismatch: 94,
     MalformedAnnotation: 95,

Sammartano                Expires 10 March 2027                [Page 74]
Internet-Draft                   N-AALP                   September 2026

     EffectUnderDeclared: 96,
     EffectOutsideLattice: 97,
     ToolCallMalformed: 98,
     PayMalformed: 99,
     UnknownPaymentFormat: 100,
     GwMalformed: 101,
     UnknownGatewayDecision: 102,
     UIMalformed: 103,
     UIChainBroken: 104,
     UnknownUIEventKind: 105,
     ActionSubstituted: 106,
     UINoConsent: 107,
     StaleEpoch: 108,
     Unauthorized: 109,
     OwnerImmutable: 110,
     MemberExists: 111,
     MemberUnknown: 112,
     OwnerExists: 113,
     RoleInvalid: 114,
     RoomOpMismatch: 115,
     OpUnknown: 116,
     PrincipalUnknown: 117,
     PrincipalExists: 118,
     RebindUnauthorized: 119,
     EgMalformed: 120,
     UnknownEgressBinding: 121,
     DecisionMalformed: 122,
     UnknownOrderingBasis: 123,
     OrderingDisclosureMalformed: 124,
     TermDispositionMalformed: 125,
     CheckpointMalformed: 126,
     WitnessRootMismatch: 127,
     InclusionProofInvalid: 128,
     ForeignProfileMalformed: 129,
     HazardMalformed: 130,
     HazardNotCovered: 131,
     HazardUnknown: 132,
   )
   ; TRUST-DECISION INPUT-CLASS REGISTRY. The open,
   ; RFC Required / FCFS registry of the decision inputs the closure
   ; property governs, each classified by its safe shape (verifiable /
   ; attenuating / committed). It grows input-by-input as new
   ; architectures mint new inputs, without reopening the property.
   ;
   trust-decision-input-class = &(
     identifier:               1,
     ; the identifier a decision keys on (verifiable)
     object-parse:             2,

Sammartano                Expires 10 March 2027                [Page 75]
Internet-Draft                   N-AALP                   September 2026

     ; the object bytes and their parse (verifiable)
     object-identity:          3,
     ; the object content id (verifiable)
     conformance-expectation:  4,
     ; the expected conformance value (verifiable)
     verification-procedure:   5,
     ; the evaluator's own procedure (verifiable)
     delegated-authority:      6,
     ; authority derived across a delegation hop (attenuating)
     approved-action:          7,
     ; which action an approval authorizes (committed)
     negotiated-parameters:    8,
     ; the negotiated profile and parameters (committed)
     validity-clock:           9,
     ; when a credential's validity is judged (committed)
     use-context:              10,
     ; the context a portable verdict is valid in (committed)
   )
   ; The consume ledger is a durable, hash-chained set keyed by the
   ; approval content id. Consume is an atomic compare-and-set: the
   ; first append for an approval id wins; a second is rejected
   ; (AlreadyConsumed). The head after an entry is SHA-384(entry); the
   ; entry carries the prior head in field 2, so editing any entry
   ; breaks the next entry's linkage (LedgerCorrupt on replay). The
   ; genesis head is 48 zero bytes. Atomicity = the store's write-ahead
   ; log (persist-before-acknowledge) + a single-writer-per-approval-id
   ; discipline.
   naalp-consume-entry = {
     1 : uint,
     ; seq -- ledger sequence position
     2 : bstr,
     ; prev -- prior chain head (48 bytes; genesis = zero)
     3 : bstr,
     ; approval_id -- the approval content id being consumed
     4 : tstr,
     ; by -- consumer signer id
   }

   ; The ledger-signed consume receipt -- draft-01 addition. It moves
   ; the anti-double-spend counter OFF the requester and ONTO the
   ; consuming ledger (the ordering authority): the receipt binds the
   ; approval content id to the LEDGER's own forward-only position and
   ; is SIGNED BY THE LEDGER KEY over these exact bytes. The requester
   ; cannot forge the ledger's position or signature, so a partition
   ; that spends one approval twice leaves TWO ledger-signed receipts
   ; against ONE approval id, each carrying a position drawn from forked
   ; state -- a contradiction authored by neither the requester nor a
   ; thief, provable on comparison (ConsumeFork; the surfaced evidence

Sammartano                Expires 10 March 2027                [Page 76]
Internet-Draft                   N-AALP                   September 2026

   ; carries both receipts and both ledger signatures). It does not
   ; PREVENT the second spend; it makes the double-spend detectable in
   ; bytes neither party could repudiate, and the approval's expiry
   ; bounds the exposure window. Keyed by approval content id,
   ; first-append-wins: on one reachable ledger the first consume
   ; assigns exactly one position and one receipt; a byte-identical
   ; re-emission is a benign duplicate, and a second receipt with a
   ; DIFFERENT position (or a DIFFERENT ledger) is a detected fork.
   ; Wrapping receipts as Audit-channel (0x000B) objects. This does not
   ; alter naalp-consume-entry (the ledger's internal hash-chained
   ; entry, above).
   naalp-consume-receipt = {
     1 : bstr,
     ; ledger -- the consuming ledger's signer id (the ordering
     ; authority)
     2 : bstr,
     ; approval_id -- the approval content id consumed (the
     ; compare-and-set key)
     3 : uint,
     ; position -- the ledger's forward-only position bound to this
     ; consume
   }

   ; ---- audit chain + causal graph + tiered ordering -----------------
   ; An ordering authority records each accepted object by appending a
   ; signed Receipt, signed by the authority with the crypto over the
   ; deterministic-CBOR body. The chain is tamper-evident: the head
   ; after a receipt is SHA-384(receipt body), the genesis prev is 48
   ; zero bytes, and the body carries the prior head in field 1 -- so
   ; any reorder, omission, or substitution breaks a `prev` link
   ; (ChainBroken) or duplicates a `seq`. The authority NEVER mutates
   ; the origin object to order it; ordering is an outer signed layer
   ; and the object's own signature stays valid. `at` is the authority's
   ; time anchor, evidence a verifier checks independently of the
   ; signer's clock. An independent auditor detects equivocation -- two
   ; receipts by one authority at one `seq` naming different objects --
   ; from the signed receipts alone and mints a non-repudiable
   ; naalp-fork-proof (below, draft-01) carrying both of the accused's
   ; signatures. Wrapping receipts as Audit-channel (0x000B) objects;
   ; the federation (higher) tier that reconciles multiple authorities
   ; over the shared causal graph -- both tiers order the identical
   ; signed objects, so federation needs no wire change.
   naalp-receipt = {
     1 : bstr,
     ; prev -- hash of the previous receipt body (48 bytes; genesis =
     ; zero)
     2 : bstr,
     ; obj -- content id of the accepted object (never the object

Sammartano                Expires 10 March 2027                [Page 77]
Internet-Draft                   N-AALP                   September 2026

     ; itself)
     3 : uint,
     ; seq -- monotonic sequence position within this authority's chain
     4 : uint,
     ; at -- authority time anchor, epoch ms
   }

   ; ForkProof -- the auditor's NON-REPUDIABLE equivocation proof.
   ; CHANGED IN draft-01 (SUPERSEDES draft-00's ForkProof): draft-00's
   ; fork proof named the two conflicting receipts but carried NEITHER
   ; conflicting signature, so an accused signer could deny the fork.
   ; draft-01's ForkProof carries the accused authority's OWN two
   ; signatures -- sig-a over body-a and sig-b over body-b, two
   ; validly-signed receipts by ONE authority at ONE seq naming
   ; DIFFERENT objects -- making the proof self-contained and
   ; non-repudiable: any third party verifies both signatures against
   ; the accused key with no further evidence. `ext-counter` is an
   ; external monotonic counter bound into the proof so a replayed or
   ; reordered proof is detectable. The two embedded bodies are
   ; naalp-receipt encodings (the exact bytes each signature covers).
   ; Verify accepts iff signer is present, the two bodies share one seq,
   ; name different objects, and BOTH signatures verify under the
   ; accused key; it is rejected whole (fail-closed) otherwise.
   naalp-fork-proof = {
     1 : bstr,
     ; signer -- accused authority signer id (envelope field-5 form)
     2 : uint,
     ; ext-counter -- external monotonic counter bound into the proof
     3 : bstr,
     ; body-a -- receipt A body (naalp-receipt det-CBOR); sig-a's input
     4 : bstr,
     ; sig-a -- the accused authority's signature over body-a
     5 : bstr,
     ; body-b -- receipt B body (naalp-receipt det-CBOR); obj !=
     ; body-a's
     6 : bstr,
     ; sig-b -- the accused authority's signature over body-b
   }

   ; The causal graph is not a distinct wire object: an edge "A causes
   ; B" is carried by B's object body field 8 (`causes`, an array of
   ; content ids) and proven by B's own signature. It is a signed
   ; partial order, checkable offline with no ordering authority
   ; present; a total order is a policy layered over it. A cause an
   ; effect could not have seen -- a present cause at a later ordering
   ; position, or a cycle -- is rejected (CausalViolation).

   ; ---- delivery stages + persist-before-ack + switchboard -----------

Sammartano                Expires 10 March 2027                [Page 78]
Internet-Draft                   N-AALP                   September 2026

   ; Delivery is four distinct, monotonic, separately-observable stages
   ; -- there is no single "sent" boolean. Each stage is a signed
   ; delivery.update naming the target object's content id and the stage
   ; reached. Stages advance in order; observing a stage earlier than
   ; the one already reached is StageOutOfOrder. An endpoint MUST
   ; durably persist an object (write-ahead log fsync) BEFORE emitting
   ; the acknowledgment that advances its stage, so a crash immediately
   ; after an acknowledgment loses nothing (persist-before-ack). The
   ; live switchboard (two connections held open, objects passed through
   ; both directions concurrently) and the content-free relay (a relay
   ; holding objects only in transit still writes a valid audit trail
   ; over content ids) are behavioural properties of an endpoint/relay,
   ; not additional wire objects. Wrapping delivery.update as a
   ; Delivery-channel object.
   delivery-stage = &(
     persisted_origin: 0,
     ; object durably persisted at the origin
     accepted_relay:   1,
     ; accepted by a relay in transit
     persisted_target: 2,
     ; durably persisted at the target
     presented:        3,
     ; presented to the target application
   )
   naalp-delivery-update = {
     1 : bstr,
     ; obj -- content id of the object whose delivery this reports
     2 : delivery-stage,
     ; stage -- the stage reached (0..3)
     3 : uint,
     ; at -- observer time, epoch ms
   }

   ; ---- native streaming + per-stream commitment ---------------------
   ; A native stream runs on the N-PAMP Stream channel 0x000C, distinct
   ; from foreign streamed carriage (0x000D) -- N-AALP never carries a
   ; foreign protocol on 0x000C. The chunks are raw data frames the
   ; transport AEAD already authenticates; they are NOT signed
   ; individually (per-chunk ML-DSA would be ruinous). Instead three
   ; signed objects govern the stream. StreamOpen binds the stream's
   ; identity, effect, and -- where it causes an effect -- its approval;
   ; a stream whose effect is not authorized is refused BEFORE any
   ; chunk. StreamCommit carries a single rolling SHA-384 over the
   ; chunks in absolute-offset order (a bare 48-octet digest), making
   ; the whole stream non-repudiable with one signature, not N; altering
   ; any delivered byte invalidates it (StreamDigestMismatch). Optional
   ; StreamCheckpoints let a verifier confirm a prefix (digest_so_far =
   ; SHA-384 of the prefix through that offset) without waiting for the

Sammartano                Expires 10 March 2027                [Page 79]
Internet-Draft                   N-AALP                   September 2026

   ; end. The same three objects map onto QUIC / WS / HTTP native
   ; streaming and the commitment verifies identically. Full-duplex is
   ; inherent Wrapping these as Stream-channel objects.
   naalp-stream-open = {
     1 : bstr,
     ; stream_id
     2 : effect,
     ; effect -- the stream's effect class
     ? 3 : bstr,
     ; approval -- content id of the approval binding (present iff
     ; effecting)
     4 : uint,
     ; substream -- NPAMP-STREAM sub-stream id
   }
   naalp-stream-commit = {
     1 : bstr,
     ; stream_id
     2 : bstr,
     ; digest -- rolling SHA-384 over the complete ordered stream (48
     ; octets)
   }
   naalp-stream-checkpoint = {
     1 : bstr,
     ; stream_id
     2 : uint,
     ; through_offset -- absolute offset the prefix ends at
     3 : bstr,
     ; digest_so_far -- SHA-384 over the prefix through_offset (48
     ; octets)
   }

   ; ---- N-AALP-CONT flow continuation --------------------------------
   ; A long-running flow costs two full ML-DSA signatures (FlowOpen +
   ; FlowCommit) regardless of the number of continuations, generalizing
   ; native streaming from a byte stream to a flow of typed steps.
   ; FlowOpen fixes the effect ceiling + approval bindings and is a
   ; signed N-AALP object whose authority is reconstructable from its
   ; bytes alone; its head = SHA-384(body) anchors the chain and its
   ; content-id (multihash(0x20, SHA-384(body))) is carried by every
   ; child object. A Continuation is a cheap UNSIGNED hash-chain link
   ; (head = SHA-384(body); prev = the previous head, the FlowOpen head
   ; for seq 0) whose effect MUST be <= the ceiling (AboveCeiling
   ; otherwise). A Checkpoint confirms a contiguous prefix (a
   ; dropped/reordered link is GapDetected). FlowCommit binds the final
   ; chain head under the second full signature (CommitMismatch on a
   ; missing/altered link). Domain separation is structural: the four
   ; body shapes (3 / 5 / 3 / 2 fields) are distinct.
   naalp-flow-open = {

Sammartano                Expires 10 March 2027                [Page 80]
Internet-Draft                   N-AALP                   September 2026

     1 : bstr,
     ; flow_id
     2 : effect,
     ; effect_ceiling -- the max effect any continuation may cause
     3 : [* bstr],
     ; approvals -- content-ids of the approvals authorizing the flow
   }
   naalp-continuation = {
     1 : bstr,
     ; flow_open_id -- content-id of the FlowOpen (WrongFlow if
     ; mismatched)
     2 : uint,
     ; seq -- 0-based position in the chain
     3 : effect,
     ; effect -- this step's effect; MUST be <= the FlowOpen ceiling
     4 : bstr,
     ; payload_id -- content-id of this step's payload
     5 : bstr,
     ; prev -- the previous link head (FlowOpen head for seq 0) (48
     ; octets)
   }
   naalp-flow-checkpoint = {
     1 : bstr,
     ; flow_open_id
     2 : uint,
     ; through_seq -- the contiguous prefix ends at this seq
     3 : bstr,
     ; head -- chain head after the prefix (48 octets)
   }
   naalp-flow-commit = {
     1 : bstr,
     ; flow_open_id
     2 : bstr,
     ; final_head -- chain head over the whole ordered sequence (48
     ; octets)
   }

   ; ---- transport bindings -------------------------------------------
   ; A transport binding adds NO new wire object: it carries exactly one
   ; signed N-AALP object (any production above) as one message unit,
   ; byte-for-byte, over N-PAMP / QUIC / WebSocket / HTTP, with
   ; identical object semantics. The media type is
   ; `application/vnd.bubblefish.naalp+cbor` (one object per
   ; representation), registered in the IANA Considerations. The object
   ; is self-secured; the binding adds only framing and, from the
   ; transport, confidentiality and connection authentication. The
   ; confidentiality boundary is NORMATIVE: an object marked sensitive
   ; MUST NOT be emitted in cleartext over a non-confidential transport

Sammartano                Expires 10 March 2027                [Page 81]
Internet-Draft                   N-AALP                   September 2026

   ; -- the binding refuses it (ConfidentialTransportRequired) and
   ; directs the deployment to a confidential transport (N-PAMP is the
   ; reference confidential transport). A transport lacking peer
   ; authentication where policy requires it is refused
   ; (PeerUnauthenticated). These are endpoint behaviours, not wire
   ; productions.

   ; ---- foreign carriage by class ------------------------------------
   ; N-AALP carries a foreign protocol by wrapping its message,
   ; octet-for-octet, in a signed N-AALP carriage object interpreted by
   ; a carriage CLASS. The carriage body is a normal N-AALP object body
   ; (envelope field 10): signed, effect-labeled, identity-bound,
   ; audited. The `foreign` field is carried VERBATIM and MUST NOT be
   ; re-serialized, canonicalized, summarized, or rewritten; N-AALP
   ; metadata is carried around it, never inside it. The carriage
   ; object's signer remains the authority -- a foreign identity NEVER
   ; becomes an N-AALP authorization identity. The OPAQUE class carries
   ; any protocol, including an undefined one, on an experimental
   ; protocol id with no registration. protocol_id ranges: standards
   ; 0x01-0x0F (RFC Required / FCFS), experimental 0x10-0x7F (no
   ; registration), private 0x80-0xFF. content_type (field 3) is the
   ; foreign ENCODING, an OPEN registry ("N-AALP Carriage Content
   ; Types"): standard encodings 0x00-0x0F (RFC Required / FCFS),
   ; experimental 0x10-0x7F and private 0x80-0xFF take no registration
   ; (0 json, 1 octet-stream, 2 text). Over N-PAMP the raw `foreign`
   ; octets ride an N-PAMP Bridge frame of the matching class
   ; byte-exact.
   naalp-carriage-class = &(
     jsonrpc: 0,
     ; any JSON-RPC 2.0 protocol (MCP, A2A core)
     http:    1,
     ; any HTTP-semantics protocol
     msg:     2,
     ; any message-passing / performative protocol
     stream:  3,
     ; any event/streaming foreign reply
     doc:     4,
     ; capability/schema documents (agent cards, tool catalogs)
     opaque:  5,
     ; any declared-content-type payload, incl. undefined protocols
   )
   naalp-carriage-body = {
     1 : uint,
     ; protocol_id -- N-AALP registry
     2 : naalp-carriage-class,
     ; class -- 0 JSONRPC .. 5 OPAQUE
     3 : uint,
     ; content_type -- foreign encoding (open registry)

Sammartano                Expires 10 March 2027                [Page 82]
Internet-Draft                   N-AALP                   September 2026

     4 : bstr,
     ; correlation -- exchange correlation token
     5 : tstr,
     ; method -- advisory routing key (foreign op name)
     6 : bstr,
     ; foreign -- the foreign message, carried octet-for-octet
   }

   ; ---- the twenty channel surfaces, baseline tier -------------------
   ; A channel surface adds NO new encoding, signature, or identity: it
   ; only assigns `kind` codes (object body field 2), each scoped by the
   ; `channel` id (field 3), and binds each kind to a declared `effect`
   ; (field 7). All twenty channels (0x0000..0x0013) and their baseline
   ; kinds are enumerated in the machine-readable registry (65 kinds). A
   ; fixed-effect kind's object MUST carry exactly its declared effect
   ; (EffectDeclarationMismatch otherwise); a variable-effect kind
   ; (Stream StreamOpen, Bridge Carriage) takes the carried/stream
   ; action's effect, authorized at run time by the effect lattice. An
   ; object on an unregistered (channel, kind) is rejected
   ; (UnknownKind). Each channel's baseline body is a spine production
   ; already defined above -- Identity rotation/
   ; revocation/foreign-link, Governance approval/held/consume, Audit
   ; receipt/fork-proof, delivery-update, Stream open/commit/checkpoint,
   ; Bridge carriage -- or a thin channel-specific body carried in
   ; object body field 10; the surface introduces no new wire
   ; production, only the kind/effect/state vocabulary. Higher tiers
   ; (tier 1+) are the higher-tier surfaces below.

   ; ---- Higher tiers: federated ordering + the tier model ------------
   ; The channel tier is envelope field 4; tier = 0 is the frozen
   ; baseline (all twenty channels). A higher tier (tier 1+) adds
   ; capability WITHOUT changing the baseline envelope, effect
   ; vocabulary, identity model, or audit chain: a baseline-tier
   ; verifier accepts a higher-tier object's spine and IGNORES an
   ; unknown higher-tier NON-critical extension (field 11), while an
   ; unknown CRITICAL extension (field 12) it cannot honor is rejected
   ; fail-closed (UnknownCriticalExt) -- the same field-11/field-12
   ; mechanism defined in the protected header. No new wire field is
   ; introduced for tiering.
   ;
   ; Federated ordering (the Federation channel higher tier, tier 1):
   ; multiple independent authorities each issue baseline receipts over
   ; their own scope, and a signed Reconcile object records a
   ; DETERMINISTIC merge of their receipt chains over the shared causal
   ; graph -- a topological linearization of the union causal DAG
   ; tie-broken by object content id (bytewise ascending). Because the
   ; order depends only on the causal graph, any split of the same
   ; objects across authorities reconciles to the same order, so moving

Sammartano                Expires 10 March 2027                [Page 83]
Internet-Draft                   N-AALP                   September 2026

   ; from single-authority to federated ordering requires NO envelope or
   ; object change. ScopeOverlapConflict (an object claimed by two
   ; authorities) is an operator error at baseline and is resolved by
   ; the merge at tier 1 (the object is ordered once).
   naalp-reconcile = {
     1 : [+ tstr],
     ; authorities -- the ordering authorities' signer ids reconciled
     2 : [+ bstr],
     ; order -- the deterministic total order, object content ids
   }

   ; ---- Collaboration / rooms membership (higher tier, tier 1) -------
   ; A Phase-3 ADDITIVE higher-tier surface over the frozen baseline
   ; envelope, effect vocabulary, identity model, and audit chain -- it
   ; introduces NO new wire mechanism, only tier-1 kinds on the
   ; Governance channel (0x0004; membership ops) and the Identity
   ; channel (0x0003; the principal registry), so it reuses the
   ; naalp-object envelope, the naalp-receipt chain, and the identity
   ; records unchanged. A baseline verifier that has not licensed the
   ; tier rejects a room kind as UnknownKind (fail-closed), consistent
   ; with the tier model above. It builds three recorded decisions: #4a
   ; Membership carriage -- a membership change is a first-class SIGNED
   ; naalp-object whose body (field 10) is a naalp-room-op. It is
   ; CURSOR-OCCUPYING and RECEIPT-CHAINED: each accepted op is ordered
   ; at a cursor by an ordering authority's naalp-receipt over the op's
   ; content id (multihash(0x20, SHA-384(op body))), weaving membership
   ; into the append-only audit chain. It is EPOCH-BUMPING: the op
   ; carries the membership epoch it is built against (field 3); each
   ; accepted op increments the room's epoch, so a superseded-epoch op
   ; is rejected (StaleEpoch). Ops:
   ; create/add_member/remove_member/change_role/add_owner. #4b O2
   ; ownership -- multi-owner, ADD-ONLY: add_owner adds an owner; an
   ; owner is never removed (remove_member refuses an owner) nor demoted
   ; (change_role refuses to lower an owner), so the owner count is
   ; monotonically >= 1 (a room can never become ownerless). #3 Delivery
   ; Model B -- a naalp-principal-binding maps a stable semantic
   ; principal id to a durable Handle (a signer id), kept as a
   ; per-principal SHA-384 chain (head = SHA-384(body), prior head in
   ; field 4, genesis = 48 zero bytes). A delivery addresses the
   ; semantic id and resolves it to the Handle at send time -- a durable
   ; naming layer above the connection-scoped N-PAMP PeerHandle. A
   ; rebind is authorised only by a verified rotation from the current
   ; handle to the new handle; a rebind to an unrelated key is refused.
   ; The membership op-authorisation, epoch guard, owner-immutability,
   ; and rebind continuity are endpoint behaviours (graded by two
   ; implementations against the non-circular oracle), not wire
   ; productions.
   naalp-room-op = {

Sammartano                Expires 10 March 2027                [Page 84]
Internet-Draft                   N-AALP                   September 2026

     1 : bstr,
     ; room -- room id
     2 : room-op-code,
     ; op -- membership operation
     3 : uint,
     ; epoch -- membership epoch this op is built against (bumps on
     ; accept)
     4 : tstr,
     ; subject -- affected member signer id (the creator, for create);
     ; NFC
     5 : member-role,
     ; role -- the role assigned to the subject
   }
   room-op-code = &(
     create:        0,
     add_member:    1,
     remove_member: 2,
     change_role:   3,
     add_owner:     4,
   )
   member-role = &(
     member: 0,
     admin:  1,
     owner:  2,
   )
   naalp-principal-binding = {
     1 : tstr,
     ; principal -- the stable semantic principal id (MUST be NFC)
     2 : tstr,
     ; handle -- the current durable Handle (a signer id) it resolves to
     3 : uint,
     ; epoch -- monotonic per-principal binding epoch (0 for first bind)
     4 : bstr,
     ; prev -- prior per-principal chain head (48 bytes; genesis = zero)
   }

   ; ---- multi-hop agent-delegation grant -- draft-01 addition --------
   ; A DelegationGrant is a NORMAL N-AALP object (envelope): an
   ; independent COSE_Sign1 whose ISSUER is the verified envelope signer
   ; (field 5), NEVER a body field. It is a Capability-channel (0x0002)
   ; kind DelegationGrant (kind 4), tier 1 -- a named escalation adding
   ; MULTI-HOP capability under the frozen baseline envelope; a verifier
   ; that has not licensed the tier rejects the kind as UnknownKind
   ; (fail-closed). The object's OWN effect (envelope field 7) is
   ; non_idempotent_write (issuing a grant); effect_cap below is the
   ; SEPARATE ceiling it confers on the subject. It REUSES the
   ; CapDelegate substrate -- parent-by-content-id in `causes` and
   ; CapExceedsParent attenuation -- rather than a parallel mechanism

Sammartano                Expires 10 March 2027                [Page 85]
Internet-Draft                   N-AALP                   September 2026

   ; (D5). The delegation PARENT (the grant or CapIssue that authorised
   ; THIS grant's issuer) is named by content id in envelope field 8
   ; (`causes`): the UNIQUE cause resolving to a Capability authority
   ; object (CapIssue kind 0, CapDelegate kind 1, DelegationGrant kind
   ; 4) whose subject/holder == this grant's issuer; a root grant
   ; (issuer in the verifier's trust-anchor set) has none, two-or-more
   ; is ChainBroken. scope is OPTIONAL: an absent field 6 is
   ; unconstrained (an empty scope is not a distinct value).
   naalp-delegation-grant = {
     1 : tstr,
     ; subject -- delegatee agent id (agent B), signer-id form; MUST be
     ; NFC
     2 : effect,
     ; effect_cap -- MAX effect conveyed (the lattice); child <= parent
     ; else CapExceedsParent
     3 : uint,
     ; max_depth -- max FURTHER delegation hops below this grant (0 =
     ; act, not re-delegate)
     4 : uint,
     ; not_before -- validity-window start, epoch ms (GrantNotYetValid
     ; before)
     5 : uint,
     ; not_after -- validity-window end, epoch ms (GrantExpired after)
     ? 6 : tstr,
     ; scope -- OPTIONAL NFC resource scope; child scope MUST be
     ; contained else CapExceedsParent
   }

   ; ---- The checkable minimum: recheck procedure (draft-01 addition) -
   ; A signature makes a body claim ATTRIBUTABLE; a claim is CHECKABLE
   ; only if a stranger can re-derive it without trusting the speaker,
   ; which requires the object to NAME the procedure a verifier runs to
   ; re-check it. That naming is carried as extension key 13 (see
   ; naalp-object above): the VALUE is a recheck-procedure id into this
   ; CLOSED registry. In the non-critical ext map (field 11) it is
   ; may-ignore (an unknown id ignored); in the critical cext map (field
   ; 12) it is must-understand and an unknown id is rejected
   ; (UnknownCriticalExt, the critical-extension rule reaching the
   ; procedure it names). A known id verifies in either map. There is no
   ; boolean on the wire -- placement (ext vs cext) is the criticality
   ; signal (the N-AALP spine carries no CBOR booleans). recheck is an
   ; ext-key (key 13) and does NOT move naalp-version -- the version is
   ; anchored by the top-level audience envelope field.
   ;
   recheck-procedure = &(
     recompute-content-id: 1,
     ; recompute the content id from the body and compare
     verify-cose-sign1:    2,

Sammartano                Expires 10 March 2027                [Page 86]
Internet-Draft                   N-AALP                   September 2026

     ; verify the COSE_Sign1 signature under the signer key
     walk-causes:          3,
     ; walk the signed causal partial order offline
     replay-consume-check: 4,
     ; replay the single-use consume ledger for the approval
   )

   ; ---- The per-signer forward-only counter (draft-01 addition) ------
   ; A signer MAY carry a forward-only counter it increments on each
   ; object, to DETECT key duplication -- NOT to prevent it. It is
   ; carried as extension key 14 in the object's NON-CRITICAL ext map
   ; (field 11, may-ignore), covered by the SIGNER's own COSE_Sign1
   ; signature -- the deliberate contrast with the LEDGER-signed
   ; naalp-consume-receipt position. The value is a bare forward-only
   ; position; ANY 64-bit uint is valid (a large value is not an error,
   ; it must decode as a 64-bit unsigned position without rounding). The
   ; field is OPTIONAL: an absent counter is valid. It is
   ; DETECTION-only: a single self-authored sequence proves nothing;
   ; duplication is flagged only when two conflicting sequences bearing
   ; ONE signer id physically meet where the attacker cannot suppress
   ; one (# Security Considerations). Placing the counter in the
   ; critical cext map is an unrecognized critical key
   ; (UnknownCriticalExt). No wire-version bump: this reuses the ext
   ; mechanism (a new ext-key assignment, not a change to an existing
   ; object body), so naalp-version stays at 2.
   signer-counter = uint

   ; ---- The NAALP-MCP binding profile (draft-01 addition) ------------
   ; An MCP tool call is CARRIED (its bytes unchanged -- carriage, not
   ; adoption), its unenforced, untrusted annotation hints are mapped to
   ; the closed four-effect lattice by a PUBLISHED table, and the
   ; WRAPPING SIGNER is accountable for that mapping (a false
   ; declaration is attributable to that key). The wrapper is a
   ; Bridge-channel (0x000D) tier-1 kind McpToolCall (kind 1) -- a named
   ; escalation over the frozen baseline Carriage kind (0), under the
   ; frozen envelope; a baseline verifier that has not licensed the tier
   ; rejects it as UnknownKind (fail-closed). Its OWN envelope effect
   ; (field 7) is the wrapping signer's DECLARED effect; a verifier
   ; independently recomputes the annotation-derived effect from the
   ; carried annotations and enforces the MORE SEVERE of the two (the
   ; good-regulator attenuator -- an unknown or disagreeing input
   ; collapses UP, never down). A declared effect BELOW the
   ; annotation-derived effect is rejected (EffectUnderDeclared); an
   ; annotation set that maps outside the lattice is rejected
   ; (MalformedAnnotation), never defaulted to benign.
   ;
   ;
   ; The MCP ToolAnnotations are booleans in JSON, but the N-AALP spine

Sammartano                Expires 10 March 2027                [Page 87]
Internet-Draft                   N-AALP                   September 2026

   ; carries NO CBOR boolean Each hint is transcribed as the uint 1
   ; (true) / 0 (false); an ABSENT hint is the MCP documented default,
   ; applied by the mapping (readOnlyHint default false, destructiveHint
   ; default true, idempotentHint default false, openWorldHint default
   ; true). destructiveHint's default of TRUE is why an un-annotated
   ; write maps to destructive -- the same fail-closed rule as N-AALP's
   ; "absent effect on a state-changing object => destructive". A
   ; present 0 and an absent hint encode to DIFFERENT bytes (empty !=
   ; absent) though they may resolve to the same effect. A hint value
   ; outside {0,1} is rejected (it transcribes no boolean).
   ; openWorldHint (key 4) is carried for accountability but is an
   ; ADVISORY risk signal ONLY -- it never enters the effect lattice
   ; (risk dimensions ride as advisory labels, not effects).
   mcp-hint = 0..1
   ; a JSON boolean hint transcribed to the spine: 1 = true, 0 = false
   naalp-mcp-annotations = {
   ; the wrapping signer's transcription of the tool's MCP annotations
     ? 1 : mcp-hint,
     ; readOnlyHint (absent => MCP default false)
     ? 2 : mcp-hint,
     ; destructiveHint (absent => MCP default true; the fail-closed
     ; default)
     ? 3 : mcp-hint,
     ; idempotentHint (absent => MCP default false)
     ? 4 : mcp-hint,
     ; openWorldHint (absent => MCP default true; ADVISORY, not an
     ; effect)
   }
   naalp-mcp-tool-call = {
   ; the wrapper body (envelope field 10); its OWN effect is field 7
     1 : bstr,
     ; tool -- the MCP tool definition bytes, carried octet-for-octet
     2 : bstr,
     ; args -- the MCP tool-call argument bytes, carried octet-for-octet
     3 : naalp-mcp-annotations,
     ; annotations -- the signer's transcription; the mapping is over
     ; these
   }
   ; The approval binds the content id of this call binding. Because it
   ; names BOTH the tool id and the args id by content id, a changed
   ; tool DESCRIPTION (new tool_id) OR changed ARGUMENTS (new args_id)
   ; yields a new call content id, invalidating a prior approval bound
   ; to the old one.
   naalp-mcp-call-binding = {
     1 : bstr,
     ; tool_id -- content id of the tool bytes: multihash(0x20,
     ; SHA-384(tool))
     2 : bstr,

Sammartano                Expires 10 March 2027                [Page 88]
Internet-Draft                   N-AALP                   September 2026

     ; args_id -- content id of the args bytes: multihash(0x20,
     ; SHA-384(args))
   }

   ; ---- signed description / directory primitive (draft-01 addition) -
   ; A signed, OFFLINE-VERIFIABLE description and discovery layer
   ; carried on N-AALP's own signed object: the authority is the
   ; SIGNATURE OVER THE BYTES, never the connection or host that served
   ; them, so a signed description re-verifies byte-identically when an
   ; unrelated host serves the same bytes (a bearer credential, not a
   ; fetched document). It introduces NO new envelope, encoding,
   ; signature, identity, or audit mechanism: each object below is an
   ; ordinary COSE_Sign1 over a deterministic-CBOR body, reusing the
   ; closed effect lattice and the content-id framing. The head of each
   ; object is SHA-384(body); its content-id is multihash(0x20,
   ; SHA-384(body)).
   ;
   ; A naalp-description lists a service's operations, each a
   ; naalp-description-operation carrying its effect (lattice) and an
   ; approval declaration. requires_approval is the uint 1/0 -- the
   ; N-AALP spine carries no CBOR boolean; a value outside {0,1} is
   ; rejected (MalformedApprovalFlag), never defaulted. A
   ; naalp-directory is a signed collection whose members are
   ; content-ids (the same list-of-content-ids shape the causal partial
   ; order uses); it carries a monotonic per-signer version so two
   ; versions can be compared. Two conflicting versions from ONE signer
   ; -- the SAME directory and version but DIFFERENT members -- are a
   ; FORK, detected at the FIRST-DIFFERING member position, the same way
   ; the audit fork proof reports the position of an equivocation.
   ;
   ; A naalp-description-import carries a FOREIGN description format (an
   ; A2A Agent Card, an ANP Agent Description, an AGNTCY Agent Badge)
   ; octet-for-octet in `foreign` (carriage, not adoption -- the foreign
   ; bytes MUST NOT be re-serialized, canonicalized, or rewritten) as a
   ; signed attestation that binds the foreign bytes' content-id
   ; (multihash(0x20, SHA-384(foreign))) AND an N-AALP effect mapping
   ; (`operations`) for the described operations. The `importer` is the
   ; wrapping signer id and is the SOLE authorization identity: a
   ; verifier recomputes the self-certifying signer id from the
   ; verifying key and requires `importer` to equal it (ImporterMismatch
   ; otherwise), so a foreign identity embedded in `foreign` NEVER
   ; becomes an N-AALP authorization identity -- the confused-deputy
   ; rule of the MCP profile and foreign carriage.
   ;
   naalp-description-operation = {
     1 : tstr,
     ; name -- operation name (advisory routing key)
     2 : effect,

Sammartano                Expires 10 March 2027                [Page 89]
Internet-Draft                   N-AALP                   September 2026

     ; effect -- the operation's effect class (lattice)
     3 : desc-approval-flag,
     ; requires_approval -- 1 requires an approval, 0 otherwise (no CBOR
     ; bool)
   }
   desc-approval-flag = 0..1
   ; a boolean transcribed to the spine: 1 = requires approval, 0 = not
   naalp-description = {
     1 : bstr,
     ; service -- opaque service id
     2 : [* naalp-description-operation],
     ; operations -- the listed operations
   }
   naalp-description-format = &(
     a2a-agent-card:        1,
     ; A2A Agent Card
     anp-agent-description: 2,
     ; ANP Agent Description
     agntcy-agent-badge:    3,
     ; AGNTCY Agent Badge
   )
   naalp-directory = {
     1 : bstr,
     ; directory -- opaque directory id
     2 : uint,
     ; version -- monotonic per-signer version
     3 : [* bstr],
     ; members -- content-ids of the member objects (the causal-order
     ; shape)
   }
   naalp-description-import = {
     1 : bstr,
     ; importer -- the wrapping signer id; the SOLE authorization
     ; identity
     2 : naalp-description-format,
     ; format -- the foreign description format code
     3 : bstr,
     ; foreign -- the foreign description bytes, carried octet-for-octet
     4 : [* naalp-description-operation],
     ; operations -- the N-AALP effect mapping the importer attests
   }

   ; ---- name bindings + the signed A2A task-state profile (draft-01 ad
   ; Two receipt-CHAINED, OFFLINE-WALKABLE surfaces reusing the audit
   ; receipt chain unchanged: the head of each object is SHA-384(body),
   ; the genesis prev is 48 zero bytes, seq is monotonic, and the body
   ; carries the prior head in `prev`, so editing or omitting a record
   ; breaks the next record's linkage. They add NO new envelope,

Sammartano                Expires 10 March 2027                [Page 90]
Internet-Draft                   N-AALP                   September 2026

   ; encoding, signature, identity, or audit mechanism: each object is
   ; an ordinary COSE_Sign1 over a deterministic-CBOR body, reusing the
   ; content-id framing.
   ;
   ; A naalp-name-binding maps a name to a signer id and CHAINS onto the
   ; prior binding for that name. A key ROTATION is a NEW binding at the
   ; next seq naming the new signer. A binding is DATED BY ITS CHAIN
   ; POSITION (seq); the envelope's `created` field (naalp-object field
   ; 6) is advisory only. A name's history is WALKABLE offline (the
   ; signer succession); a deleted/omitted binding leaves a detectable
   ; HOLE at the first-broken position (gap-evident, as the audit chain
   ; / directory fork report position); two bindings by ONE authority at
   ; the SAME (name, seq) naming DIFFERENT signers are a FORK, reported
   ; at that seq (the same way the audit fork proof reports an
   ; equivocation position).
   naalp-name-binding = {
     1 : tstr,
     ; name -- the name being bound (a durable, human-readable name)
     2 : bstr,
     ; signer -- the signer id the name maps to at this position
     ; (signer-id form)
     3 : uint,
     ; seq -- monotonic per-name chain position; seq 0 is the genesis
     ; binding
     4 : bstr,
     ; prev -- the prior binding's head (48 bytes; genesis = 48 zero
     ; bytes)
   }

   ; A naalp-task-transition is one signed, receipt-CHAINED A2A
   ; (Agent2Agent) task-lifecycle state transition. The A2A TaskState
   ; set is an IMPORTED vocabulary (carriage, not adoption): the A2A
   ; specification (Section 4.1.3) defines the eight states and the
   ; terminal/interrupted categories NORMATIVELY (start = submitted;
   ; terminal = {completed, canceled, failed, rejected}; interrupted =
   ; {input- required, auth-required}) and leaves the exact legal edges
   ; to implementations; N-AALP's legal-edge table is DERIVED from those
   ; documented category rules and is enforced by the endpoint, not by
   ; this wire production (the wire carries only the from/to state
   ; values). `card` is the content-id of the A2A Agent Card attestation
   ; (a naalp-description-import with format a2a-agent-card) that binds
   ; the task profile to an agent/operation; a transition carrying a
   ; card other than the profile's bound card is rejected (ForeignCard).
   ; An illegal edge, a non-contiguous `from`, a transition out of a
   ; terminal state, or a gap/reorder in the chain is detected
   ; fail-closed (IllegalTransition / TaskChainBroken), position
   ; reported.
   ;

Sammartano                Expires 10 March 2027                [Page 91]
Internet-Draft                   N-AALP                   September 2026

   task-state = &(
     submitted:      0,
     ; acknowledged, not yet started (the start state)
     working:        1,
     ; actively processed
     input-required: 2,
     ; interrupted, awaiting client input
     auth-required:  3,
     ; interrupted, awaiting authentication
     completed:      4,
     ; terminal success
     canceled:       5,
     ; terminal, canceled before completion
     failed:         6,
     ; terminal, finished with an error
     rejected:       7,
     ; terminal, the agent declined the task
   )
   naalp-task-transition = {
     1 : bstr,
     ; task -- the task id (opaque)
     2 : bstr,
     ; card -- content-id of the bound A2A Agent Card attestation
     3 : task-state,
     ; from -- the source state
     4 : task-state,
     ; to -- the target state
     5 : uint,
     ; seq -- monotonic per-task chain position; seq 0's from =
     ; submitted
     6 : bstr,
     ; prev -- the prior transition's head (48 bytes; genesis = zero)
   }

   ; ---- governed negotiation, advisory risk labels, and trust (draft-0
   ; Three signed surfaces reusing the closed effect lattice, the
   ; content-id framing, and the causal partial order (`causes`)
   ; UNCHANGED: each object is an ordinary COSE_Sign1 over a
   ; deterministic-CBOR body. head = SHA-384(body); content-id =
   ; multihash(0x20, SHA-384(body)).
   ;
   ; GOVERNED NEGOTIATION. offer / counter / accept are SIGNED,
   ; CAUSALLY-LINKED messages: each names its predecessor(s) by
   ; content-id in `causes` (the same list-of-content-ids shape the
   ; causal partial order uses). Each SELECTS a profile from the CLOSED,
   ; PRE-REGISTERED negotiation-profile set -- the negotiation selects a
   ; pre-registered profile, never a free-form capability string and
   ; never a runtime-generated handler. The three productions are

Sammartano                Expires 10 March 2027                [Page 92]
Internet-Draft                   N-AALP                   September 2026

   ; distinguished by a fixed `role` literal (0/1/2), so an offer body
   ; never validates against the accept production and vice-versa. An
   ; accept MUST DESCEND from its offer along the `causes` DAG (enforced
   ; by the endpoint, NotDescended otherwise); an unknown profile
   ; (UnknownProfile) or role is rejected fail-closed. The
   ; machine-readable role/profile source is the negotiation-role /
   ; negotiation-profile enums below.
   negotiation-role = &(
     offer:   0,
     ; the initiating offer (the root; no causes)
     counter: 1,
     ; a counter chaining onto the offer or a prior counter
     accept:  2,
     ; the accept; it MUST descend from its offer
   )
   negotiation-profile = &(
     baseline:  0,
     ; the baseline capability profile
     streaming: 1,
     ; the native-streaming capability profile
     batch:     2,
     ; the batched-delivery capability profile
   )
   naalp-negotiation-offer = {
     1 : bstr,
     ; negotiation -- opaque negotiation id (ties the exchange together)
     2 : 0,
     ; role -- offer (fixed literal 0)
     3 : negotiation-profile,
     ; profile -- the selected pre-registered profile (closed set)
     4 : [* bstr],
     ; causes -- content-ids of predecessors (empty for an offer)
   }
   naalp-negotiation-counter = {
     1 : bstr,
     ; negotiation
     2 : 1,
     ; role -- counter (fixed literal 1)
     3 : negotiation-profile,
     ; profile
     4 : [* bstr],
     ; causes -- names the offer or a prior counter
   }
   naalp-negotiation-accept = {
     1 : bstr,
     ; negotiation
     2 : 2,
     ; role -- accept (fixed literal 2)

Sammartano                Expires 10 March 2027                [Page 93]
Internet-Draft                   N-AALP                   September 2026

     3 : negotiation-profile,
     ; profile -- the AGREED pre-registered profile
     4 : [* bstr],
     ; causes -- descends from the offer along this chain
   }

   ; ADVISORY RISK LABELS. A naalp-risk-label is one carried label
   ; {code, critical}; a naalp-labeled-object carries an effect (the
   ; lattice) together with a set of risk labels. The vocabulary is a
   ; closed standard set -- sensitive/egress (gating), reversible
   ; (informing) -- plus a private/experimental extensible range, so
   ; `code` is an open uint and the known set is enforced by the
   ; endpoint + registry (as the signer-counter is an open uint).
   ; `critical` is the per-carriage must-understand flag (uint 1/0 --
   ; the spine carries no CBOR boolean); the critical-extension rule
   ; rejects an unknown CRITICAL label (UnknownCriticalRisk) and ignores
   ; an unknown non-critical one. LOAD-BEARING INVARIANT: a risk label
   ; is an ADVISORY dimension, NEVER a fifth effect -- carrying a label
   ; does not change the object's effect class (the closed effect
   ; lattice is untouched).
   risk-code = uint
   ; a risk-label code (standard set + private/experimental extensible
   ; range)
   risk-critical = 0..1
   ; per-carriage must-understand flag: 1 = critical, 0 = advisory (no
   ; CBOR bool)
   naalp-risk-label = {
     1 : risk-code,
     ; code -- the risk-label code
     2 : risk-critical,
     ; critical -- the must-understand flag
   }
   naalp-labeled-object = {
     1 : effect,
     ; effect -- the effect class (field 7); the effect class derives
     ; from this ALONE -- risk labels never alter it
     2 : [* naalp-risk-label],
     ; labels -- the advisory risk labels carried on the object
   }

   ; TRUST. A naalp-trust-ref carries a THIRD-PARTY trust statement as a
   ; CHECKABLE signed object: `reference` is the content-id of an
   ; EXTERNAL registry record (an ERC-8004-style reputation/identity
   ; registry record). A verifier CONFIRMS the reference by recomputing
   ; that content-id over the external bytes; the signature checks. But
   ; NO wire field WEIGHS the statement -- there is no score, rank, or
   ; ordering on the wire; the protocol carries trust statements and
   ; does not weigh them, and which to believe is left to the relying

Sammartano                Expires 10 March 2027                [Page 94]
Internet-Draft                   N-AALP                   September 2026

   ; party.
   naalp-trust-ref = {
     1 : bstr,
     ; registry -- opaque external-registry identifier (e.g.
     ; "erc-8004:reputation")
     2 : bstr,
     ; reference -- content-id of the referenced external record
     3 : bstr,
     ; subject -- the subject the statement is about (opaque id)
   }

   ; ---- payment import, UI consent, and portable gateway evidence (dra
   ; Three signed surfaces reusing the closed effect lattice, the
   ; content-id framing, the approval + single-use consume ledger, and
   ; the receipt chain UNCHANGED: each object is an ordinary COSE_Sign1
   ; over a deterministic-CBOR body. head = SHA-384(body); content-id =
   ; multihash(0x20, SHA-384(body)). These are NEW productions, not
   ; changes to an existing object body, so naalp-version stays at 2.
   ;
   ; PAYMENT IMPORT. A naalp-payment-import carries a foreign payment
   ; payload -- an AP2 mandate, an Agentic Commerce Protocol delegated
   ; token, an x402 payload -- octet-for-octet in `foreign` (carriage,
   ; not adoption; the foreign bytes MUST NOT be re-serialized,
   ; canonicalized, or rewritten), and turns it into a value-bearing
   ; charge N-AALP governs with its OWN added guarantees. `format`
   ; selects the imported FORMAT from the closed naalp-payment-format
   ; registry; an unknown format is rejected (UnknownPaymentFormat). The
   ; naalp-payment-charge-binding names the exact value an approval
   ; binds by content-id -- including the foreign payload's content-id
   ; (`foreign_id`, the carriage binding) -- so a wrong
   ; amount/payee/currency OR a substituted foreign payload yields a
   ; different content-id and no longer matches the approval
   ; (ApprovalMismatch). A payment spend is a non_idempotent_write spent
   ; SINGLE-USE through the consume ledger (AlreadyConsumed on replay).
   ; There is NO fifth effect and NO payment-specific ledger. There is
   ; no boolean on the wire.
   naalp-payment-format = &(
     ap2-mandate:         1,
     ; AP2 mandate
     acp-delegated-token: 2,
     ; Agentic Commerce Protocol delegated token
     x402-payload:        3,
     ; x402 payload
   )
   naalp-payment-import = {
     1 : naalp-payment-format,
     ; format -- the imported payment format (closed registry)
     2 : uint,

Sammartano                Expires 10 March 2027                [Page 95]
Internet-Draft                   N-AALP                   September 2026

     ; amount -- the charge amount in minor units
     3 : tstr,
     ; currency -- the charge currency code (e.g. "USD")
     4 : bstr,
     ; payee -- the payee id (opaque)
     5 : uint,
     ; not_after -- the charge expiry, epoch ms
     6 : bstr,
     ; foreign -- the imported payment payload, carried octet-for-octet
   }
   ; The charge-binding is the payment-import's fields with `foreign`
   ; replaced by its content-id (`foreign_id`); it shares the import's
   ; 6-field shape by design and is distinguished by position and
   ; semantics (the value an approval binds), not by CDDL structure. It
   ; is a hashing input, not itself an on-wire signed object (only
   ; naalp-payment-import is signed as an envelope body).
   naalp-payment-charge-binding = {
   ; the exact value an approval binds by content-id
     1 : naalp-payment-format,
     ; format
     2 : uint,
     ; amount
     3 : tstr,
     ; currency
     4 : bstr,
     ; payee
     5 : uint,
     ; not_after
     6 : bstr,
     ; foreign_id -- content-id of the foreign payload: multihash(0x20,
     ; SHA-384(foreign))
   }

   ; UI CONSENT BINDING. A naalp-ui-event is one shown tool-lifecycle
   ; event (AG-UI style) in a user- interface event stream,
   ; receipt-CHAINED by the chain construction: head = SHA-384(body),
   ; genesis prev = 48 zero bytes, monotonic seq, prior head carried in
   ; `prev`, so editing or omitting an event breaks the next event's
   ; linkage (a detectable hole with position). `kind` is the closed
   ; ui-event-kind set; `action` is the content-id of the exact action
   ; bytes shown to the user. A human approval (a naalp-approval) binds
   ; the shown-and-approved action's content-id, and the action actually
   ; executed MUST hash to that same content-id -- a SUBSTITUTED action
   ; has a different content-id and is rejected (ActionSubstituted).
   ; There is no boolean on the wire.
   ui-event-kind = &(
     shown:      0,
     ; the action / tool call was shown (rendered) to the user

Sammartano                Expires 10 March 2027                [Page 96]
Internet-Draft                   N-AALP                   September 2026

     args-shown: 1,
     ; the arguments were shown to the user
     approved:   2,
     ; the user approved the shown action
     rejected:   3,
     ; the user rejected the shown action
   )
   naalp-ui-event = {
     1 : bstr,
     ; session -- UI session id (ties the stream together)
     2 : ui-event-kind,
     ; kind -- the event kind (closed set)
     3 : bstr,
     ; action -- content-id of the exact action bytes shown at this step
     4 : uint,
     ; seq -- monotonic per-session chain position; seq 0 is the genesis
     ; event
     5 : bstr,
     ; prev -- the prior event's head (48 bytes; genesis = zero)
   }

   ; PORTABLE GATEWAY EVIDENCE. A naalp-gateway-decision is a SIGNED
   ; decision object an enforcement gateway of ANY vendor emits as
   ; portable evidence. Its authority is the SIGNATURE OVER THE BYTES,
   ; never the connection or host that served them, so it verifies
   ; offline and RE-VERIFIES IDENTICALLY when served by a party OTHER
   ; than the gateway (the third-party re-serve property). This is the
   ; EVIDENCE FORMAT ONLY -- it defines NO policy language. `decision`
   ; is the closed gw-decision set; `action` is the content-id of the
   ; action decided about; `policy` is the opaque identity of the
   ; deciding policy (a name, not a program); `effect` is the effect
   ; class of the action. An unknown decision code is rejected
   ; (UnknownGatewayDecision). The gateway is the SIGNER (envelope field
   ; 5); a verifier resolves its key offline from the self-certifying
   ; signer id and checks the signature over the bytes.
   gw-decision = &(
     allow: 0,
     ; the gateway allows the action
     deny:  1,
     ; the gateway denies the action
     hold:  2,
     ; the gateway holds the action pending a further step
   )
   naalp-gateway-decision = {
     1 : gw-decision,
     ; decision -- the decision outcome (closed set)
     2 : bstr,
     ; action -- content-id of the action decided about

Sammartano                Expires 10 March 2027                [Page 97]
Internet-Draft                   N-AALP                   September 2026

     3 : bstr,
     ; policy -- the deciding policy's opaque identity (NOT a policy
     ; language)
     4 : effect,
     ; effect -- the effect class of the action
     ? 5 : ordering-disclosure,
     ; ordering (R1) -- OPTIONAL. ABSENT is read correspondence-only,
     ; never a stronger claim. The mandatory fields 1-4 are validated
     ; FIRST: a body failing a mandatory-field check is GwMalformed
     ; regardless of any optional 5/6, so a look-alike whose field 1 is
     ; not the gw-decision uint stays GwMalformed.
     ? 6 : naalp-foreign-profile-pin,
     ; foreign-profile (R8) -- OPTIONAL; present iff the decision was over
     ; foreign-protocol evidence. Pins the foreign evidence profile's
     ; identifier AND revision at decision time (bind the reference, not
     ; just the class).
   }
   naalp-foreign-profile-pin = {
     1 : tstr,
     ; id -- the foreign evidence profile identifier, an ABSOLUTE URI
     ; (opaque per-protocol ids drift at the mapping)
     2 : tstr,
     ; revision -- the profile revision pinned at decision time
   }

   ; ===== EVIDENCE-RECORD FAMILY (R1 ordering + S1 DecisionRecord +
   ; S3 CheckpointRoot). All additive sibling productions; naalp-version
   ; stays 2. The accountability triple, carried natively:
   ; unique-selection + governed-at-T + binding-fixed-by-T. =====

   ; ORDERING BASIS (R1): what, if anything, establishes
   ; decision->effect / record->event ORDER, and from which
   ; observational domain. The weakest claim is the ZERO value ON
   ; PURPOSE: a record that says nothing, and an existing record whose
   ; optional ordering field is ABSENT, are both read as
   ; correspondence-only -- a verifier MUST NEVER infer a stronger
   ; ordering claim from silence (fail-closed reading direction).
   ; external-mechanism NAMES the mechanism; whether its operator is
   ; genuinely distinct from both parties is a structural deployment fact
   ; checkable in substance at T+n, not a claim the wire can close.
   ordering-basis = &(
     correspondence-only: 0,
     single-boundary:     1,
     external-mechanism:  2,
   )
   ordering-disclosure = {
     1 : ordering-basis,
     ? 2 : bstr,

Sammartano                Expires 10 March 2027                [Page 98]
Internet-Draft                   N-AALP                   September 2026

     ; boundary -- the single covering boundary (signer-id form); present
     ; iff basis = single-boundary
     ? 3 : bstr,
     ; mechanism -- the external sequencing mechanism's identity; present
     ; iff basis = external-mechanism
     ? 4 : bstr,
     ; relation -- the log relation binding this record under the
     ; mechanism (e.g. the content id of the naalp-checkpoint-root the
     ; record is included under); present only when basis =
     ; external-mechanism
   }
   ; Well-formedness (fail-closed, native): correspondence-only -> keys
   ; 2/3/4 absent; single-boundary -> key 2 present, 3/4 absent;
   ; external-mechanism -> key 3 present (4 optional), 2 absent. Any
   ; violation is OrderingDisclosureMalformed on the whole record.

   term-disposition = {
     1 : uint,
     ; kind -- 1 observed / 2 reported (reuses the producing-boundary
     ; kind codes)
     ? 2 : bstr,
     ; source -- the boundary the term was received from; present iff
     ; kind = reported
   }

   enforcement-disposition = &(
     enforced: 1,
     advised:  2,
   )

   ; THE GOVERNED-DECISION RECORD (S1). A naalp-decision-record is the
   ; SIGNED record a governed decision point emits that it decided about
   ; an action under a CLOSED, uniquely-selected condition set. It is the
   ; carrier for the T/T+n accountability triple: UNIQUE SELECTION (field
   ; 2, the governing set in the clear as content ids -- identification
   ; AND availability); GOVERNED-AT-T (field 3, the consume-receipt spent
   ; at decision time -- decision-time consumption, not
   ; identity-to-the-act); BINDING-FIXED-BY-T (established off-record by
   ; inclusion under a witnessed naalp-checkpoint-root). The record is
   ; deliberately CLOCK-FREE: it carries no claimed time; both time
   ; properties are POSITIONAL, never a self-asserted timestamp. The
   ; signature binds THE DECISION, not a retrieval of it.
   naalp-decision-record = {
     1 : bstr,
     ; action -- content id of the action decided about
     2 : [* bstr],
     ; governing -- the CLOSED governing condition set, content ids, in
     ; the clear; may be empty (a decision governed by standing policy

Sammartano                Expires 10 March 2027                [Page 99]
Internet-Draft                   N-AALP                   September 2026

     ; alone names that policy object's cid here)
     ? 3 : bstr,
     ; consume -- content id of the naalp-consume-receipt that spent the
     ; governing authority at decision time. PRESENT for an allow that
     ; consumed a single-use authority; ABSENT for deny/hold (a refusal
     ; consumes nothing). A deny/hold body carrying a consume ref is
     ; rejected DecisionMalformed -- nothing was consumed.
     4 : gw-decision,
     ; outcome -- allow / deny / hold (reuses the closed gw-decision set)
     5 : ordering-disclosure,
     ; ordering -- MANDATORY (R1 folded in from the start): the record
     ; states its ordering basis or states correspondence-only; there is
     ; no silent default
     ? 6 : { * uint => term-disposition },
     ; terms -- OPTIONAL per-term observed-vs-reported dispositions, keyed
     ; by THIS record's own field numbers (1..5). A key outside the field
     ; set is TermDispositionMalformed (fail-closed).
     ? 7 : enforcement-disposition,
     ; enforcement -- OPTIONAL: whether the producer ENFORCES the outcome
     ; or only ADVISES it (the producer's own unverifiable self-account).
   }

   ; THE NEITHER-PARTY ANCHOR PRIMITIVE (S3, RFC 9162-style). A
   ; naalp-checkpoint-root is a log operator's SIGNED Merkle tree head
   ; over a leaf set of record content ids. Tree construction follows RFC
   ; 9162 Section 2.1: leaf hash = HASH(0x00 || leaf), interior node =
   ; HASH(0x01 || left || right), instantiated with the profile hash
   ; SHA-384 (48-byte heads), the 0x00/0x01 prefixes supplying leaf/node
   ; domain separation. Checkpoints chain by prev (genesis = 48 zero
   ; bytes) so a withheld or reordered checkpoint breaks a link.
   naalp-checkpoint-root = {
     1 : bstr,
     ; log -- the log operator's signer id
     2 : uint,
     ; size -- leaf count at this checkpoint
     3 : bstr,
     ; root -- the Merkle tree head over the leaf set (48 bytes)
     4 : bstr,
     ; prev -- the prior checkpoint root value (48 bytes; genesis zero)
     5 : uint,
     ; at -- the log's time anchor, epoch ms (advisory)
   }

   ; A witness COUNTERSIGNS one exact checkpoint by content id. The wire
   ; carries the cosignature; whether the witness's observational domain
   ; is genuinely distinct from both parties is a structural deployment
   ; fact a T+n verifier checks in substance -- the wire hook for the
   ; neither-party property, stated honestly as a hook.

Sammartano                Expires 10 March 2027               [Page 100]
Internet-Draft                   N-AALP                   September 2026

   naalp-witness-cosign = {
     1 : bstr,
     ; witness -- the witness's signer id
     2 : bstr,
     ; root -- content id of the exact naalp-checkpoint-root cosigned
     3 : uint,
     ; at -- the witness's own time anchor, epoch ms (advisory)
   }

   ; Inclusion proof: a leaf existed in the tree the root commits to (RFC
   ; 9162 Section 2.1.3.1 path recomputation, SHA-384-profiled). Record
   ; cid as a leaf under a witnessed checkpoint = existed-no-later-than
   ; the checkpoint (the binding-fixed-by-T leg). Verification recomputes
   ; the path bottom-up and compares against the named root, fail-closed
   ; (InclusionProofInvalid).
   naalp-inclusion-proof = {
     1 : bstr,
     ; root -- content id of the naalp-checkpoint-root proven against
     2 : bstr,
     ; leaf -- the included record's content id (the leaf value)
     3 : uint,
     ; index -- the leaf's 0-based position in the tree
     4 : [* bstr],
     ; path -- the audit path, leaf-to-root sibling hashes (48 bytes each)
   }

   ; PORTABLE EGRESS EVIDENCE (E6.3). A naalp-egress-attestation is a
   ; SIGNED attestation a gateway/sidecar emits that an object of a given
   ; effect class, bound to a given audience, crossed an egress boundary
   ; at a given time -- third-party re-serve, payload-free. content_bound:
   ; digest is the crossed object's T1 content id. content_free: digest is
   ; a hiding commitment SHA-384(content_id || salt), openable later by
   ; the gateway revealing (content_id, salt).
   egress-binding = &(
     content-bound: 0,
     content-free:  1,
   )
   naalp-egress-attestation = {
     1 : egress-binding,
     ; binding -- content_bound vs content_free (closed set)
     2 : bstr,
     ; digest -- content id (content-bound) or commitment (content-free)
     3 : effect,
     ; effect -- the effect class of the crossed object
     4 : bstr,
     ; audience -- the bound destination (empty-permitted)
     5 : uint,
     ; at -- the gateway's egress timestamp, epoch ms

Sammartano                Expires 10 March 2027               [Page 101]
Internet-Draft                   N-AALP                   September 2026

     ? 6 : ordering-disclosure,
     ; ordering -- OPTIONAL (R1); ABSENT is read correspondence-only
   }

   ; MANUFACTURING PHYSICAL-HAZARD (Mfg-F). `hazard` is a dimension
   ; ORTHOGONAL to `effect`: effect (field 7) is DATA reversibility (can
   ; the state change be undone); hazard is PHYSICAL danger -- a
   ; data-reversible action may still be a high physical hazard (e.g. a
   ; tool re-approaching a work envelope). The two are never merged and
   ; neither is derived from the other. A hazard CLAIM rides as the
   ; critical cext key 16 (naalp-hazard-claim) on the acting object; a
   ; hazard AUTHORIZATION is a standalone Governance (0x0004) kind 7
   ; object (naalp-hazard-authorization), referenced by the acting
   ; object's `causes`. Coverage: EXACT class match AND full containment
   ; of the claim envelope in the grant envelope (frame id equal; same
   ; axis count and order; every claim axis inside the matching grant
   ; axis; claim speed_bound <= grant speed_bound; claim window a
   ; sub-interval of the grant window); any single failing dimension
   ; denies the whole claim (HazardNotCovered). All numeric bounds are
   ; fixed-point integers (signed mm; unsigned mm/s) -- no floats, per the
   ; spine's deterministic-CBOR subset. Map keys are 1-based.
   ;
   ; hazard-class is a CLOSED 0..4 enum. A DECODE-TIME rule (like effect's
   ; unknown->destructive): an absent or unrecognized raw hazard value
   ; MUST normalize to the HIGHEST class (4, motion-in-shared-space) --
   ; never to none(0) or a weaker value -- so a missing declaration fails
   ; safe (HazardUnknown when no claim exists; else HazardNotCovered
   ; against a lower-class grant). CDDL cannot see the absence or
   ; invalidity of a raw wire value, so this is a MUST on the decoder, not
   ; this grammar.
   hazard-class = &(
     none:                   0,
     tool-actuation:         1,
     thermal:                2,
     energy-release:         3,
     motion-in-shared-space: 4,
   )

   ; A named coordinate frame plus a signed axis-aligned bounding region
   ; in that frame, integer millimeters. `axes` MUST be non-empty and
   ; every entry MUST satisfy min <= max (HazardMalformed otherwise). The
   ; frame id is integrator-defined; N-AALP requires only that a claim's
   ; frame id equal the grant's for containment to be checkable.
   spatial-bounds = {
     1 : tstr,                        ; frame -- MUST be Unicode NFC
                                       ; (NonNFC else)
     2 : [ + [min: int, max: int] ],  ; axes -- per-axis [min,max], mm,
                                       ; signed

Sammartano                Expires 10 March 2027               [Page 102]
Internet-Draft                   N-AALP                   September 2026

   }

   ; A validity window in the epoch-ms convention of the spine.
   hazard-window = {
     1 : uint,   ; not_before -- epoch ms
     2 : uint,   ; not_after  -- epoch ms
   }

   ; The full physical envelope a hazard claim or authorization bounds
   ; itself by. All three fields MANDATORY: a silently-absent axis, speed,
   ; or window is a MALFORMED envelope (HazardMalformed), never
   ; "unconstrained" (which would fail OPEN in a physical-safety context).
   hazard-envelope = {
     1 : spatial-bounds,   ; spatial
     2 : uint,             ; speed_bound -- max instantaneous speed, mm/s
     3 : hazard-window,    ; window
   }

   ; A signed physical-hazard claim, carried as cext key 16 on the acting
   ; object. `class` and `envelope` are BOTH mandatory (HazardMalformed
   ; otherwise).
   naalp-hazard-claim = {
     1 : hazard-class,     ; class    -- the declared hazard class
     2 : hazard-envelope,  ; envelope -- the bounds this claim asserts
   }

   ; A signed physical-hazard authorization (a grant): a standalone
   ; Governance (0x0004) kind 7 object. Same {class, envelope} shape as
   ; the claim; coverage is the exact-class-match + full-containment rule
   ; above (any failing dimension => HazardNotCovered).
   naalp-hazard-authorization = {
     1 : hazard-class,     ; class    -- the class this authorization covers
     2 : hazard-envelope,  ; envelope -- the bounds this authorization covers
   }

Appendix B.  Acknowledgments

   N-AALP builds on the N-PAMP substrate.

Author's Address

   Shawn Sammartano
   BubbleFish Technologies, Inc.
   Email: naalp-editor@bubblefish.sh

Sammartano                Expires 10 March 2027               [Page 103]