<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE rfc [
  <!ENTITY nbsp    "&#160;">
  <!ENTITY zwsp   "&#8203;">
  <!ENTITY nbhy   "&#8209;">
  <!ENTITY wj     "&#8288;">
]>

<rfc xmlns:xi="http://www.w3.org/2001/XInclude"
     docName="draft-song-anp-ans-00"
     category="exp"
     ipr="trust200902"
     submissionType="independent"
     xml:lang="en"
     version="3">

  <front>
    <title abbrev="ANS">Agent Name System (ANS)</title>

    <seriesInfo name="Internet-Draft" value="draft-song-anp-ans-00"/>

    <author fullname="Jinke Song" initials="J." surname="Song">
      <organization abbrev="HKUST">Dept. of CSE, Hong Kong University of Science and Technology</organization>
      <address>
        <email>ink@chatchat.space</email>
      </address>
    </author>

    <author fullname="Mu Yuan" initials="M." surname="Yuan">
      <organization abbrev="CUHK">Dept. of IE, The Chinese University of Hong Kong</organization>
      <address>
        <email>muyuan@cuhk.edu.hk</email>
      </address>
    </author>

    <date year="2026" month="March" day="25"/>

    <area>art</area>
    <workgroup>Independent Submission</workgroup>

    <keyword>agent</keyword>
    <keyword>name</keyword>
    <keyword>resolution</keyword>
    <keyword>discovery</keyword>
    <keyword>URI</keyword>

    <abstract>
      <t>
        This document defines the Agent Name System (ANS), a
        name registration and resolution protocol for autonomous
        AI agents in the Agent Network Protocol (ANP) suite.
        ANS maps agent:// URIs to network-layer peer identifiers,
        providing the binding between human-readable agent names
        and the cryptographic peer identities used by the Agent
        Internet Protocol (AIP) for datagram delivery.
      </t>
      <t>
        ANS defines a Name Record format, four AITP method names
        for name operations (ans.register, ans.resolve,
        ans.unregister, ans.lookup), a multi-layer resolution
        algorithm, and two dissemination mechanisms (GossipSub
        announcements and DHT storage).  ANS supports three
        addressing modes — unicast, anycast, and channel — over
        a single URI syntax.
      </t>
      <t>
        ANS is intentionally a narrow name-binding layer: it maps
        names to peers and tags, but defers capability description
        to the Agent Description Protocol (ADP), reputation and
        ranking to companion protocols, and economic anti-spam
        mechanisms to deployment profiles.
      </t>
    </abstract>
  </front>

  <middle>

    <!-- ============================================================ -->
    <!--  SECTION 1 — INTRODUCTION                                     -->
    <!-- ============================================================ -->

    <section anchor="introduction">
      <name>Introduction</name>

      <section anchor="problem-statement">
        <name>Problem Statement</name>
        <t>
          Agents in a decentralized network need stable,
          human-readable names that can be resolved to the
          cryptographic peer identifiers used for datagram
          delivery.  The Agent Internet Protocol (AIP)
          <xref target="I-D.song-anp-aip"/> defines agent://
          URIs as the addressing scheme for datagrams, but AIP
          itself does not specify how a name such as
          "agent://translator-zh-en" is bound to a particular
          peer or how that binding is disseminated across the
          network.
        </t>
        <t>
          Without a name system, agents must exchange raw
          cryptographic peer identifiers — opaque strings that
          are neither memorable nor semantic.  A name system
          provides the indirection layer that allows agent
          names to persist across peer-identity rotations,
          enables human operators to refer to agents by
          meaningful labels, and supports anycast routing where
          a single name resolves to the best available instance.
        </t>
      </section>

      <section anchor="scope">
        <name>Scope</name>
        <t>
          This document is one of four core Internet-Drafts in
          the Agent Network Protocol (ANP) suite: AIP
          <xref target="I-D.song-anp-aip"/> (datagram
          delivery), AITP <xref target="I-D.song-anp-aitp"/>
          (invocation transport), ANS (this document, name
          system), and ADP <xref target="I-D.song-anp-adp"/>
          (description and discovery).  The four drafts are
          designed to co-evolve as a self-contained protocol
          suite; no additional specification is required for
          baseline interoperability.  AIP's local-resolver
          semantic extension <bcp14>MAY</bcp14> be backed by
          an implementation that consults ADP discovery services
          for ranked capability matching; ANS core provides
          name-to-peer binding but does not itself perform
          ranked semantic discovery.
        </t>
        <t>
          ANS is a name-layer protocol within the ANP suite.
          It sits between the human-facing name space and the
          peer-identity layer used by AIP.
        </t>
        <t>This document specifies:</t>
        <ol>
          <li>The agent:// URI syntax as used by ANS,
              refining the base grammar defined in AIP with
              namespace, version, and addressing-mode
              semantics.  AIP remains the scheme authority
              (<xref target="I-D.song-anp-aip"/>); ANS
              defines name-layer interpretation only.</li>
          <li>The Name Record format — a JSON object that binds
              an agent:// name to a peer identifier, skill tags,
              and temporal metadata.</li>
          <li>Four AITP method names (ans.register, ans.resolve,
              ans.unregister, ans.lookup) for name operations
              over the Agent Invocation Transport Protocol (AITP)
              <xref target="I-D.song-anp-aitp"/>.</li>
          <li>A multi-layer resolution algorithm (local cache,
              persistent store, DHT, peer-assisted query).</li>
          <li>Two dissemination mechanisms: GossipSub
              announcements for real-time propagation and DHT
              records for persistent storage.</li>
          <li>The name lifecycle: registration, freshness,
              renewal, ownership, transfer, expiration, and
              release.</li>
        </ol>
        <t>This document does not cover:</t>
        <ol>
          <li>Agent capability description — specified by the
              Agent Description Protocol (ADP)
              <xref target="I-D.song-anp-adp"/>.</li>
          <li>Ranked capability discovery — the five-factor
              scoring algorithm is defined in ADP
              <xref target="I-D.song-anp-adp"/>.</li>
          <li>Economic mechanisms for name registration (token
              burn, auction, pricing) — these are
              deployment-specific policies.</li>
          <li>DNS-based discovery (DNS-SD, well-known URIs) —
              discussed informatively in
              <xref target="appendix-web-discovery"/>.</li>
          <li>Agent identity, key management, or credential
              issuance — these belong to AIP and deployment-
              context mechanisms.</li>
        </ol>
      </section>

      <section anchor="positioning">
        <name>Positioning</name>
        <t>
          ANS is to agent:// URIs what DNS is to domain names:
          a name-to-address resolution service.  ANS differs
          from DNS in three respects: (1) registrations are
          self-certified via Ed25519 signatures rather than
          delegated to registrars; (2) resolution is
          peer-to-peer (DHT + gossip) rather than hierarchical;
          (3) the name space supports anycast and channel
          addressing modes natively.  Of these three modes,
          only unicast and anycast names are registered;
          channel names are derived from the URI syntax and
          map deterministically to GossipSub topics without
          creating a Name Record
          (see <xref target="channel-resolution"/>).
        </t>
        <t>
          Unlike ADP's adp.discover, which ranks agents by a
          multi-factor scoring algorithm, ANS's ans.lookup
          performs tag-based filtering without scoring — a
          narrow-waist lookup analogous to DNS SRV queries.
          The two protocols are complementary: ANS provides
          name→peer binding; ADP provides capability→ranking.
        </t>
      </section>

      <section anchor="design-rationale">
        <name>Design Rationale</name>
        <t>
          ANS is justified when the following conditions hold:
        </t>
        <ol>
          <li>
            <t><strong>Agents need stable, human-readable
            identifiers.</strong></t>
            <t>
              Cryptographic peer IDs (e.g., 12D3KooW...) are
              unsuitable for human reference, configuration
              files, and documentation.  A name layer
              provides stability across peer-ID rotation.
            </t>
          </li>
          <li>
            <t><strong>Multiple resolution paths improve
            availability.</strong></t>
            <t>
              A single DHT lookup may fail due to network
              partition.  A layered resolution stack (local
              cache → persistent store → DHT → peer-assisted
              RPC) maximizes the probability of successful
              resolution.
            </t>
          </li>
          <li>
            <t><strong>Anycast requires a name-to-set
            mapping.</strong></t>
            <t>
              When multiple instances serve the same logical
              service, the name system must resolve a single
              name to a set of candidates.  Instance selection
              is then delegated to the caller or to a
              companion ranking protocol (ADP).
            </t>
          </li>
        </ol>
      </section>

      <section anchor="assumptions">
        <name>Assumptions</name>
        <t>ANS assumes:</t>
        <ol>
          <li>An AIP module providing agent:// datagram delivery
              with Ed25519-signed peer identities.</li>
          <li>An AITP module capable of REQUEST/RESPONSE
              exchanges with the method names defined in this
              document.</li>
          <li>A GossipSub implementation supporting topic-based
              pub/sub (e.g., libp2p GossipSub v1.1).</li>
          <li>A Kademlia DHT implementation supporting
              namespace-prefixed key-value storage.</li>
          <li>Name Record documents are UTF-8 encoded JSON
              (<xref target="RFC8259"/>).</li>
        </ol>
      </section>

      <section anchor="adjacent-specs">
        <name>Relationship to Adjacent Specifications</name>
        <t>
          ANS occupies a narrow role in the ANP suite.  This
          section clarifies the boundary between ANS and its
          sibling protocols to prevent misattribution of
          responsibilities.
        </t>
        <dl>
          <dt>Agent Internet Protocol (AIP)
              <xref target="I-D.song-anp-aip"/></dt>
          <dd>
            AIP owns the agent:// URI scheme registration,
            the Ed25519 peer-identity model, and datagram
            delivery.  ANS consumes the URI scheme and peer
            identities defined by AIP; it does not redefine
            them.  The ABNF in <xref target="abnf"/> is a
            name-layer profile of the AIP base grammar,
            adding namespace, instance, and channel
            semantics for registration and resolution.
            The agent:// URI scheme registration belongs to
            AIP, not ANS.
          </dd>
          <dt>Agent Invocation Transport Protocol (AITP)
              <xref target="I-D.song-anp-aitp"/></dt>
          <dd>
            AITP provides the reliable REQUEST/RESPONSE
            transport over which ANS method calls are
            carried.  AITP is a pure bearer: it provides
            segment framing, flow control, and status codes,
            but has no awareness of name semantics.  ANS
            defines its own method names (ans.*) and
            error detail bodies; AITP carries them unchanged.
          </dd>
          <dt>Agent Description Protocol (ADP)
              <xref target="I-D.song-anp-adp"/></dt>
          <dd>
            ADP defines Agent Cards (rich capability
            descriptions) and the adp.discover method
            (five-factor ranked discovery).  ANS provides
            the narrower primitive: name-to-peer binding
            and tag-based lookup without scoring.  The two
            protocols are complementary — ANS resolves
            names, ADP ranks capabilities — and
            <bcp14>SHOULD</bcp14> be deployed together.
          </dd>
          <dt>Web-Native Discovery Profiles</dt>
          <dd>
            DNS-SD (<xref target="RFC6763"/>), .well-known
            URIs (<xref target="RFC8615"/>), and mDNS
            (<xref target="RFC6762"/>) are informative
            bridging mechanisms described in
            <xref target="appendix-web-discovery"/>.  They
            are deployment profiles, not part of the ANS
            core protocol.  An ANS implementation is
            fully conformant without supporting any web-
            native discovery profile.
          </dd>
        </dl>
      </section>

      <section anchor="requirements-language">
        <name>Requirements Language</name>
        <t>
          The key words "<bcp14>MUST</bcp14>",
          "<bcp14>MUST NOT</bcp14>",
          "<bcp14>REQUIRED</bcp14>", "<bcp14>SHALL</bcp14>",
          "<bcp14>SHALL NOT</bcp14>", "<bcp14>SHOULD</bcp14>",
          "<bcp14>SHOULD NOT</bcp14>",
          "<bcp14>RECOMMENDED</bcp14>",
          "<bcp14>NOT RECOMMENDED</bcp14>",
          "<bcp14>MAY</bcp14>", and
          "<bcp14>OPTIONAL</bcp14>" in this document are to be
          interpreted as described in BCP&nbsp;14
          <xref target="RFC2119"/>
          <xref target="RFC8174"/> when, and only when, they
          appear in all capitals, as shown here.
        </t>
      </section>
    </section>

    <!-- ============================================================ -->
    <!--  SECTION 2 — TERMINOLOGY                                      -->
    <!-- ============================================================ -->

    <section anchor="terminology">
      <name>Terminology</name>

      <dl>
        <dt>Name Record</dt>
        <dd>
          A JSON object that binds an agent:// name to a peer
          identifier, skill tags, and temporal metadata.  The
          Name Record is the unit of registration and
          resolution in ANS.
        </dd>

        <dt>Peer ID</dt>
        <dd>
          The cryptographic identifier of a network node,
          derived from its Ed25519 public key.  Used by AIP
          for datagram routing.
        </dd>

        <dt>Namespace</dt>
        <dd>
          An optional organizational prefix in an agent:// URI
          that groups related agent names (e.g., "nlp" in
          "agent://nlp/translator").
        </dd>

        <dt>Addressing Mode</dt>
        <dd>
          One of three resolution semantics for an agent://
          URI: unicast (resolve to a specific instance),
          anycast (resolve to the best available instance of
          a service), or channel (map to a pub/sub topic for
          multicast delivery).
        </dd>

        <dt>Owner</dt>
        <dd>
          The peer that first registered a Name Record.
          Ownership is immutable: only the Owner may update
          or transfer the record.
        </dd>

        <dt>Sequence Number</dt>
        <dd>
          A strictly monotonically increasing integer in a
          Name Record, used to order updates and prevent
          replay of stale records.
        </dd>
      </dl>
    </section>

    <!-- ============================================================ -->
    <!--  SECTION 3 — agent:// URI SYNTAX                              -->
    <!-- ============================================================ -->

    <section anchor="uri-syntax">
      <name>agent:// URI Syntax</name>

      <t>
        The agent:// URI scheme identifies agents in the ANP
        network.  AIP <xref target="I-D.song-anp-aip"/> defines
        the base agent:// scheme and its core parsing rules.
        This section defines the ANS-specific naming
        interpretation and constraints used for registration
        and resolution.  AIP <xref target="I-D.song-anp-aip"/>
        is the scheme authority and defines the base
        agent:// syntax and wire encoding; the grammar below
        is a compatible profile that adds namespace, instance,
        version, and addressing-mode semantics on top of the
        AIP base grammar.
      </t>

      <section anchor="abnf">
        <name>ABNF Grammar</name>
        <t>
          The following ABNF (<xref target="RFC5234"/>) defines
          the syntax of agent:// URIs.  The grammar uses the
          core rules from <xref target="RFC5234"/> Appendix B
          and the generic URI components from
          <xref target="RFC3986"/>.
        </t>
        <artwork type="abnf"><![CDATA[
agent-uri     = "agent://" agent-path [ "@" version ]
agent-path    = service-path / channel-path

; Service addressing (unicast or anycast)
service-path  = [ namespace "/" ] name [ "/" instance ]

; Channel addressing (trailing "/" required)
channel-path  = [ namespace "/" ] name "/"

namespace     = identifier
name          = identifier
instance      = identifier
version       = 1*( ALPHA / DIGIT / "." / "-" )

identifier    = lo-alpha-digit *( lo-alpha-digit / "-" )
lo-alpha-digit = %x61-7A / DIGIT   ; a-z / 0-9
]]></artwork>
        <t>
          Constraints:
        </t>
        <ul>
          <li>Each "identifier" segment <bcp14>MUST</bcp14>
              be 1 to 63 octets.</li>
          <li>The total agent-path (excluding "agent://")
              <bcp14>MUST NOT</bcp14> exceed 255 octets, matching
              the AIP MaxURILen.</li>
          <li>Identifiers <bcp14>MUST</bcp14> be lowercase
              ASCII letters, digits, and hyphens.
              Underscores are <bcp14>NOT RECOMMENDED</bcp14>;
              implementations <bcp14>MAY</bcp14> normalize
              underscores to hyphens on input.</li>
          <li>An identifier <bcp14>MUST NOT</bcp14> start or
              end with a hyphen.</li>
        </ul>
      </section>

      <section anchor="addressing-modes">
        <name>Addressing Modes</name>
        <t>
          An agent:// URI carries one of three addressing modes,
          determined by syntactic inspection of the path:
        </t>

        <table anchor="tbl-modes">
          <name>Addressing Modes</name>
          <thead>
            <tr>
              <th>Mode</th>
              <th>URI Pattern</th>
              <th>Resolution Semantics</th>
            </tr>
          </thead>
          <tbody>
            <tr>
              <td>Unicast</td>
              <td>agent://[ns/]name/instance</td>
              <td>Resolve to exactly one peer: the named
                  instance.</td>
            </tr>
            <tr>
              <td>Anycast</td>
              <td>agent://[ns/]name</td>
              <td>Resolve to one or more peers registered
                  under the service name; the caller or a
                  companion protocol selects among
                  candidates.</td>
            </tr>
            <tr>
              <td>Channel</td>
              <td>agent://[ns/]name/</td>
              <td>Map to a GossipSub topic; datagrams are
                  delivered to all subscribers.  Channel
                  names are derived, not registered — no
                  Name Record is stored.  See
                  <xref target="channel-resolution"/>.</td>
            </tr>
          </tbody>
        </table>

        <t>
          Implementations <bcp14>MUST</bcp14> detect the
          addressing mode using the following algorithm:
        </t>
        <artwork type="ascii-art"><![CDATA[
if path ends with "/"           → Channel
else if path contains instance  → Unicast
else                            → Anycast
]]></artwork>
        <t>
          An agent:// URI with no namespace and no instance
          (e.g., "agent://translator-zh-en") is Anycast.
          This preserves backward compatibility with the flat
          names used by existing implementations.
        </t>
      </section>

      <section anchor="uri-examples">
        <name>Examples</name>
        <artwork type="ascii-art"><![CDATA[
# Anycast — route to any available translator
agent://translator-zh-en

# Anycast — namespace-scoped
agent://nlp/translator

# Unicast — specific instance
agent://nlp/translator/zh-en-01

# Unicast — versioned
agent://nlp/translator/zh-en-01@1.2.0

# Channel — multicast to all subscribers
agent://finance/market-updates/
]]></artwork>
      </section>

      <section anchor="uri-normalization">
        <name>Normalization</name>
        <t>
          Implementations <bcp14>MUST</bcp14> normalize
          agent:// URIs before registration, resolution, and
          comparison by:
        </t>
        <ol>
          <li>Converting the scheme and all identifier segments
              to lowercase.</li>
          <li>Removing any trailing whitespace.</li>
        </ol>
        <t>
          The normalized form retains the "agent://" prefix.
          Implementations that need a prefix-stripped key for
          DHT or database storage <bcp14>MAY</bcp14> derive
          it internally, but the canonical wire-format value
          is always the full URI.
        </t>
        <t>
          Two URIs are considered equal if their normalized
          forms are byte-identical.
        </t>
      </section>
    </section>

    <!-- ============================================================ -->
    <!--  SECTION 4 — NAME RECORD                                      -->
    <!-- ============================================================ -->

    <section anchor="name-record">
      <name>Name Record</name>

      <t>
        A Name Record is a JSON object (<xref target="RFC8259"/>)
        that binds an agent:// name to a network peer and its
        metadata.  Name Records are the unit of registration,
        dissemination, and resolution in ANS.
      </t>

      <t>
        The following structural rules apply to every Name
        Record:
      </t>
      <ol>
        <li>A Name Record <bcp14>MUST</bcp14> be a single
            JSON object (<xref target="RFC8259"/>)
            encoded in UTF-8.</li>
        <li>A Name Record <bcp14>MUST NOT</bcp14> contain
            duplicate member names.</li>
        <li>A Name Record <bcp14>MUST NOT</bcp14> contain
            members outside this specification unless they
            are placed inside the "extensions" object
            (see <xref target="extensions"/>).</li>
        <li>Implementations <bcp14>MUST</bcp14> ignore
            unknown top-level members for forward
            compatibility, but <bcp14>MUST</bcp14> preserve
            them when re-serializing the record (e.g.,
            during gossip relay).</li>
      </ol>

      <section anchor="record-fields">
        <name>Record Fields</name>

        <table anchor="tbl-record-fields">
          <name>Name Record Fields</name>
          <thead>
            <tr>
              <th>Field</th>
              <th>Type</th>
              <th>Req</th>
              <th>Description</th>
            </tr>
          </thead>
          <tbody>
            <tr>
              <td>name</td>
              <td>string</td>
              <td>MUST</td>
              <td>
                The complete agent:// URI, including the
                scheme prefix.  E.g.,
                "agent://nlp/translator" or
                "agent://translator-zh-en".
                Implementations that need a prefix-stripped
                key for storage or DHT lookups
                <bcp14>SHOULD</bcp14> derive it internally;
                the wire-format and object-model value is
                always the full URI.
              </td>
            </tr>
            <tr>
              <td>peer_id</td>
              <td>string</td>
              <td>MUST</td>
              <td>
                The registrant's cryptographic peer identifier,
                as used by AIP for datagram routing.
              </td>
            </tr>
            <tr>
              <td>namespace</td>
              <td>string</td>
              <td>MAY</td>
              <td>
                The namespace segment extracted from the name
                (e.g., "nlp").  Redundant with "name" but
                enables efficient namespace-scoped queries.
              </td>
            </tr>
            <tr>
              <td>skills</td>
              <td>array</td>
              <td>MAY</td>
              <td>
                A JSON array of strings, each a lowercase
                skill tag (e.g., ["translation","nlp"]).
                Duplicate entries <bcp14>SHOULD</bcp14> be
                removed on input.  Used for tag-based
                lookup (ans.lookup).
              </td>
            </tr>
            <tr>
              <td>description</td>
              <td>string</td>
              <td>MAY</td>
              <td>
                Free-text description of the agent's purpose.
                Used for full-text search.
              </td>
            </tr>
            <tr>
              <td>version</td>
              <td>string</td>
              <td>MAY</td>
              <td>
                Semantic version string of the agent's
                capability set (e.g., "1.2.0").
              </td>
            </tr>
            <tr>
              <td>ttl</td>
              <td>integer</td>
              <td>MAY</td>
              <td>
                Time-to-live in seconds.  Default: 3600.
                Consumers <bcp14>SHOULD</bcp14> consider the
                record stale after this duration.
              </td>
            </tr>
            <tr>
              <td>registered_at</td>
              <td>string</td>
              <td>MUST</td>
              <td>
                Registration timestamp in RFC 3339 format
                (<xref target="RFC3339"/>).
              </td>
            </tr>
            <tr>
              <td>expires_at</td>
              <td>string</td>
              <td>MUST</td>
              <td>
                Expiration timestamp in RFC 3339 format.
                Records past this time <bcp14>MUST</bcp14>
                be treated as expired and
                <bcp14>SHOULD</bcp14> be removed from
                caches.
              </td>
            </tr>
            <tr>
              <td>owner_id</td>
              <td>string</td>
              <td>MUST</td>
              <td>
                The peer_id of the first registrant.
                Immutable after initial registration.
                Only the Owner may update or transfer the
                record.
              </td>
            </tr>
            <tr>
              <td>seq</td>
              <td>integer</td>
              <td>MUST</td>
              <td>
                Monotonically increasing sequence number.
                Receivers <bcp14>MUST</bcp14> reject records
                with a seq value less than or equal to the
                locally stored seq for the same name.  See
                <xref target="seq-numbers"/>.
              </td>
            </tr>
            <tr>
              <td>signature</td>
              <td>string</td>
              <td>MUST</td>
              <td>
                Ed25519 signature (<xref target="RFC8032"/>)
                over the canonical record bytes.  See
                <xref target="signature-computation"/>.
                Encoded as unpadded Base64url
                (<xref target="RFC4648"/> §5).
              </td>
            </tr>
            <tr>
              <td>extensions</td>
              <td>object</td>
              <td>MAY</td>
              <td>
                A JSON object carrying deployment-specific
                extension data.  See
                <xref target="extensions"/>.
              </td>
            </tr>
          </tbody>
        </table>
      </section>

      <section anchor="signature-computation">
        <name>Signature Computation</name>
        <t>
          The signature field authenticates the Name Record and
          binds it to the registrant's Ed25519 key pair.  The
          signature is computed as follows:
        </t>
        <ol>
          <li>Construct the signing input by concatenating the
              following fields in order, each encoded as UTF-8
              with a newline (0x0A) separator:
              name, peer_id, namespace,
              skills (JSON-serialized array, e.g.,
              '["nlp","translation"]'; empty array '[]' if
              absent), description,
              version, ttl (decimal string), registered_at,
              expires_at, owner_id, seq (decimal string).</li>
          <li>Compute the Ed25519 signature
              (<xref target="RFC8032"/>) over the signing
              input using the registrant's private key.</li>
          <li>Encode the 64-byte signature as unpadded
              Base64url (<xref target="RFC4648"/> §5).</li>
        </ol>
        <t>
          Receivers <bcp14>MUST</bcp14> verify the signature
          before accepting a Name Record. Verification
          requires the Ed25519 public key corresponding to the
          peer_id.  Implementations <bcp14>MUST</bcp14> reject
          records whose signature does not verify, whose
          peer_id does not correspond to the signing key, or
          whose owner_id does not match the peer_id (for
          initial registrations) or the stored owner_id
          (for updates).
        </t>
      </section>

      <section anchor="seq-numbers">
        <name>Sequence Numbers</name>
        <t>
          The seq field provides replay protection and
          consistent ordering of Name Record updates.
        </t>
        <ul>
          <li>The initial registration <bcp14>MUST</bcp14>
              set seq to 1.</li>
          <li>Each subsequent update <bcp14>MUST</bcp14>
              increment seq by at least 1.</li>
          <li>Receivers <bcp14>MUST</bcp14> reject a record
              if its seq is less than or equal to the seq of
              the currently stored record for the same
              name.</li>
          <li>Receivers <bcp14>MUST</bcp14> reject a record
              if the seq value is unreasonably large
              (implementation-defined threshold) to prevent
              seq-space exhaustion attacks.</li>
        </ul>
      </section>

      <section anchor="extensions">
        <name>Extension Mechanism</name>
        <t>
          The "extensions" field provides a stable mounting
          point for deployment-specific data that does not
          belong in the core Name Record.  Examples include
          anti-spam proof tokens, pricing metadata, transfer
          receipts, and deployment-policy hints.
        </t>
        <ul>
          <li>The value of "extensions" <bcp14>MUST</bcp14>
              be a JSON object.</li>
          <li>Each key within "extensions"
              <bcp14>SHOULD</bcp14> be a reverse-domain or
              URN-namespaced identifier to avoid collisions
              (e.g., "com.example.antispam").</li>
          <li>Implementations <bcp14>MUST</bcp14> preserve
              extension entries they do not understand when
              re-serializing or relaying a Name Record.</li>
          <li>Implementations <bcp14>MUST</bcp14> ignore
              extension entries they do not understand when
              processing a Name Record.</li>
          <li><t>The "extensions" object is excluded from
              the signature computation
              (<xref target="signature-computation"/>).
              This is an intentional design trade-off:
              the core name-binding fields (name, peer_id,
              owner_id, seq, timestamps) are signed and
              tamper-evident — these fields fully cover the
              name-to-identity binding and temporal
              validity, so core record integrity does not
              depend on extensions.  Extensions are left
              unsigned to allow deployment-local annotations
              and relay-added metadata (e.g., hop count,
              ingestion timestamp) that the originator
              cannot predict at signing time.</t>
              <t>Consequently, any peer on the relay path
              may add, modify, or remove extension entries.
              Deployment profiles that require stronger
              integrity for specific extensions
              <bcp14>SHOULD</bcp14> define an inner
              signature field within their own extension
              namespace.</t></li>
        </ul>
      </section>

      <section anchor="validation-rules">
        <name>Validation Rules</name>
        <t>
          Implementations <bcp14>MUST</bcp14> validate Name
          Records on receipt, whether from ans.register
          requests, GossipSub messages, or DHT retrieval.
          The following rules apply:
        </t>

        <table anchor="tbl-validation">
          <name>Name Record Validation Rules</name>
          <thead>
            <tr>
              <th>ID</th>
              <th>Rule</th>
              <th>Level</th>
            </tr>
          </thead>
          <tbody>
            <tr>
              <td>VAL-01</td>
              <td>"name" conforms to the agent:// ABNF
                  (<xref target="abnf"/>).</td>
              <td>MUST</td>
            </tr>
            <tr>
              <td>VAL-02</td>
              <td>"peer_id" is non-empty and is a
                  syntactically valid peer identifier.</td>
              <td>MUST</td>
            </tr>
            <tr>
              <td>VAL-03</td>
              <td>"owner_id" is non-empty.  For initial
                  registrations, owner_id = peer_id.
                  For updates, owner_id matches the
                  stored value.</td>
              <td>MUST</td>
            </tr>
            <tr>
              <td>VAL-04</td>
              <td>"expires_at" is strictly after
                  "registered_at", and "expires_at" is
                  in the future at time of receipt.</td>
              <td>MUST</td>
            </tr>
            <tr>
              <td>VAL-05</td>
              <td>"ttl" is a positive integer (> 0).
                  Default 3600 if absent.</td>
              <td>MUST</td>
            </tr>
            <tr>
              <td>VAL-06</td>
              <td>"seq" is an integer >= 1.  For updates,
                  seq is strictly greater than the stored
                  seq.</td>
              <td>MUST</td>
            </tr>
            <tr>
              <td>VAL-07</td>
              <td>"skills" entries are unique, lowercase
                  strings.  Duplicates are removed
                  silently.</td>
              <td>SHOULD</td>
            </tr>
            <tr>
              <td>VAL-08</td>
              <td>"namespace", if present, matches the
                  namespace segment extracted from
                  "name".</td>
              <td>MUST</td>
            </tr>
            <tr>
              <td>VAL-09</td>
              <td>"signature" verifies per
                  <xref target="signature-computation"/>.
              </td>
              <td>MUST</td>
            </tr>
            <tr>
              <td>VAL-10</td>
              <td>The addressing mode implied by "name"
                  is consistent with the operation
                  context.  Channel names (trailing "/")
                  are derived, not registered, and
                  <bcp14>MUST NOT</bcp14> be submitted
                  to ans.register
                  (see <xref target="channel-resolution"/>).
              </td>
              <td>MUST</td>
            </tr>
          </tbody>
        </table>

        <t>
          Records that fail any MUST-level rule
          <bcp14>MUST</bcp14> be rejected.  Records that
          fail a SHOULD-level rule <bcp14>SHOULD</bcp14> be
          accepted after corrective normalization (e.g.,
          deduplicating skills).
        </t>
      </section>
    </section>

    <!-- ============================================================ -->
    <!--  SECTION 5 — PROTOCOL OPERATIONS                              -->
    <!-- ============================================================ -->

    <section anchor="operations">
      <name>Protocol Operations</name>

      <t>
        ANS defines four AITP method names for name operations.
        Each method uses an AITP REQUEST/RESPONSE exchange; the
        request and response bodies are JSON objects.
      </t>

      <section anchor="op-register">
        <name>ans.register — Register a Name</name>
        <t>
          An agent sends a REQUEST with Method = "ans.register"
          to bind an agent:// name to its peer identity.
          Only Unicast and Anycast names may be registered;
          Channel names are derived from the URI syntax and
          <bcp14>MUST NOT</bcp14> be submitted to
          ans.register (see <xref target="channel-resolution"/>).
        </t>
        <dl>
          <dt>Request body</dt>
          <dd>
            A Name Record as defined in
            <xref target="name-record"/>.  All MUST fields
            <bcp14>MUST</bcp14> be present.
          </dd>
          <dt>Response body (Status = OK)</dt>
          <dd>
            <t>A JSON object with the following fields:</t>
            <ul>
              <li>"registered": boolean — true if the record
                  was accepted.</li>
              <li>"name": string — the normalized name.</li>
              <li>"seq": integer — the accepted sequence
                  number.</li>
              <li>"expires_at": string — the accepted
                  expiration timestamp.</li>
            </ul>
          </dd>
          <dt>Error responses</dt>
          <dd>
            <ul>
              <li>INVALID_REQUEST (6) — malformed record,
                  invalid signature, or constraint violation
                  (e.g., name syntax, field length).</li>
              <li>UNAUTHORIZED (5) — the sender is not the
                  owner of an existing record with the same
                  name.</li>
              <li>BUSY (8) — the receiver has reached its
                  capacity for stored Name Records.</li>
            </ul>
          </dd>
        </dl>
        <t>
          The receiver <bcp14>MUST</bcp14> perform the
          following validation before accepting a registration:
        </t>
        <ol>
          <li>Verify the agent:// name conforms to the ABNF
              in <xref target="abnf"/>.</li>
          <li>Verify the Ed25519 signature per
              <xref target="signature-computation"/>.</li>
          <li>If a record with the same name already exists,
              verify that the request's owner_id matches the
              stored owner_id and that the request's seq is
              strictly greater than the stored seq.</li>
          <li>If no record exists, set the owner_id to the
              sender's peer_id.</li>
          <li>Verify that expires_at is in the future and
              that ttl is positive.</li>
        </ol>
        <t>
          Registration <bcp14>MAY</bcp14> additionally require
          a deployment-specific anti-spam mechanism such as
          proof-of-work, token expenditure, or rate limiting.
          Such mechanisms are outside the scope of this
          specification.
        </t>
      </section>

      <section anchor="op-resolve">
        <name>ans.resolve — Resolve a Name</name>
        <t>
          A caller sends a REQUEST with Method = "ans.resolve"
          to look up the Name Record(s) bound to an agent://
          name.
        </t>
        <dl>
          <dt>Request body</dt>
          <dd>
            <t>A JSON object with the following fields:</t>
            <ul>
              <li>"name": string (<bcp14>MUST</bcp14>) — the
                  full agent:// URI to resolve.</li>
            </ul>
          </dd>
          <dt>Response body (Status = OK)</dt>
          <dd>
            <t>A JSON object with a uniform envelope
            containing three fields:</t>
            <ul>
              <li>"mode": string (<bcp14>MUST</bcp14>) —
                  one of "unicast", "anycast", or
                  "channel".</li>
              <li>"records": array (<bcp14>MUST</bcp14>) —
                  matching Name Records.  For Unicast: at
                  most one element.  For Anycast: zero or
                  more elements, ordered by seq descending.
                  For Channel: empty array.</li>
              <li>"topic": string or null
                  (<bcp14>MUST</bcp14>) — the GossipSub
                  topic string for Channel mode; null for
                  Unicast and Anycast.</li>
              <li>"source": string (<bcp14>MAY</bcp14>) —
                  when present, indicates the resolution
                  layer that produced the result.  Values
                  are drawn from: "local" (in-memory
                  cache), "store" (persistent database),
                  "dht" (Kademlia DHT), "peer"
                  (peer-assisted RPC).  Omitted if
                  unknown.</li>
            </ul>
          </dd>
          <dt>Error responses</dt>
          <dd>
            INVALID_REQUEST (6) if the name is malformed.
          </dd>
        </dl>
        <t>
          If the receiver does not have the requested record
          in its local store, it <bcp14>MAY</bcp14> attempt
          resolution via the DHT or peer-assisted query before
          returning an empty records array.
        </t>
      </section>

      <section anchor="op-unregister">
        <name>ans.unregister — Remove a Name</name>
        <t>
          An agent sends a REQUEST with Method =
          "ans.unregister" to remove its Name Record.
        </t>
        <dl>
          <dt>Request body</dt>
          <dd>
            <t>A JSON object with the following fields:</t>
            <ul>
              <li>"name": string (<bcp14>MUST</bcp14>) — the
                  agent:// name to unregister.</li>
              <li>"signature": string (<bcp14>MUST</bcp14>)
                  — Ed25519 signature over the UTF-8 string
                  "unregister:" concatenated with the
                  normalized name.</li>
            </ul>
          </dd>
          <dt>Response body (Status = OK)</dt>
          <dd>
            A JSON object: { "unregistered": true }.
          </dd>
          <dt>Error responses</dt>
          <dd>
            <ul>
              <li>UNAUTHORIZED (5) — the sender is not the
                  owner.</li>
              <li>INVALID_REQUEST (6) — invalid signature or
                  name not found.</li>
            </ul>
          </dd>
        </dl>
        <t>
          The receiver <bcp14>MUST</bcp14> verify that the
          signature is valid and that the sender's peer_id
          matches the stored owner_id before removing the
          record.  Upon successful unregistration, the
          receiver <bcp14>SHOULD</bcp14> propagate the
          removal via GossipSub (see
          <xref target="gossipsub-dissemination"/>).
        </t>
      </section>

      <section anchor="op-lookup">
        <name>ans.lookup — Tag-Based Name Lookup</name>
        <t>
          A caller sends a REQUEST with Method = "ans.lookup"
          to find agents by skill tags.  Unlike ADP's
          adp.discover, ans.lookup is a narrow-waist filter:
          it returns all matching records without scoring or
          ranking.
        </t>
        <dl>
          <dt>Request body</dt>
          <dd>
            <t>A JSON object with the following fields:</t>

            <table anchor="tbl-lookup-request">
              <name>ans.lookup Request Fields</name>
              <thead>
                <tr>
                  <th>Field</th>
                  <th>Type</th>
                  <th>Description</th>
                </tr>
              </thead>
              <tbody>
                <tr>
                  <td>tags</td>
                  <td>string[]</td>
                  <td>Skill tags to match (at least one
                      <bcp14>SHOULD</bcp14> be provided).
                  </td>
                </tr>
                <tr>
                  <td>namespace</td>
                  <td>string</td>
                  <td>Optional namespace filter.</td>
                </tr>
                <tr>
                  <td>limit</td>
                  <td>integer</td>
                  <td>Maximum results.  Default: 10.</td>
                </tr>
              </tbody>
            </table>
          </dd>
          <dt>Response body (Status = OK)</dt>
          <dd>
            <t>A JSON object with a "results" array.  Each
            element contains:</t>
            <ul>
              <li>"record": the matching Name Record.</li>
              <li>"matched_tags": string[] — tags that
                  contributed to the match.</li>
            </ul>
          </dd>
          <dt>Error responses</dt>
          <dd>
            INVALID_REQUEST (6) if the query is malformed.
          </dd>
        </dl>
        <t>
          A Name Record matches if at least one of the query
          tags appears in the record's skills array (after
          normalization).  Implementations <bcp14>SHOULD</bcp14>
          normalize tags to lowercase and apply alias
          resolution (e.g., "py" → "python") before matching.
        </t>
        <t>
          When the total number of matching records exceeds the
          AIP maximum message size (65535 octets), implementations
          <bcp14>SHOULD</bcp14> truncate the result set to "limit"
          entries and return only complete records that fit within
          a single response datagram.  Callers that need additional
          results <bcp14>MAY</bcp14> issue subsequent queries with
          an "offset" parameter (application-level pagination) or
          use an AITP STREAM exchange for large result sets, as
          discussed in AITP <xref target="I-D.song-anp-aitp"/>.
        </t>
      </section>

      <section anchor="method-summary">
        <name>Method Summary</name>

        <table anchor="tbl-methods">
          <name>ANS AITP Methods</name>
          <thead>
            <tr>
              <th>Method</th>
              <th>Direction</th>
              <th>Purpose</th>
            </tr>
          </thead>
          <tbody>
            <tr>
              <td>ans.register</td>
              <td>Agent → Peer/Directory</td>
              <td>Bind a name to a peer identity</td>
            </tr>
            <tr>
              <td>ans.resolve</td>
              <td>Caller → Peer/Directory</td>
              <td>Look up name → peer binding</td>
            </tr>
            <tr>
              <td>ans.unregister</td>
              <td>Agent → Peer/Directory</td>
              <td>Remove a name binding</td>
            </tr>
            <tr>
              <td>ans.lookup</td>
              <td>Caller → Peer/Directory</td>
              <td>Tag-based name filter (no ranking)</td>
            </tr>
          </tbody>
        </table>
      </section>
    </section>

    <!-- ============================================================ -->
    <!--  SECTION 6 — ERROR HANDLING                                   -->
    <!-- ============================================================ -->

    <section anchor="error-handling">
      <name>Error Handling</name>

      <t>
        ANS methods reuse AITP status codes for transport-level
        outcome (e.g., OK, INVALID_REQUEST, UNAUTHORIZED).
        In addition, ANS defines a structured error detail
        body that provides protocol-specific reason codes.
      </t>

      <section anchor="error-envelope">
        <name>Error Detail Envelope</name>
        <t>
          When an ANS method returns an AITP error status, the
          response body <bcp14>SHOULD</bcp14> include the
          following JSON object:
        </t>
        <artwork type="ascii-art"><![CDATA[
{
  "code":   "ANS-1002",
  "title":  "invalid-signature",
  "detail": "Ed25519 signature verification failed for
              name 'agent://nlp/translator'.",
  "name":   "agent://nlp/translator"
}
]]></artwork>
        <t>Fields:</t>
        <dl>
          <dt>code</dt>
          <dd>An ANS error code from
              <xref target="tbl-error-codes"/>.
              <bcp14>MUST</bcp14> be present.</dd>
          <dt>title</dt>
          <dd>A short, stable, machine-readable slug.
              <bcp14>MUST</bcp14> be present.</dd>
          <dt>detail</dt>
          <dd>A human-readable explanation.
              <bcp14>MAY</bcp14> be present.</dd>
          <dt>name</dt>
          <dd>The agent:// name that triggered the error,
              if applicable.
              <bcp14>MAY</bcp14> be present.</dd>
        </dl>
      </section>

      <section anchor="error-codes">
        <name>ANS Error Codes</name>

        <table anchor="tbl-error-codes">
          <name>ANS Error Code Registry</name>
          <thead>
            <tr>
              <th>Code</th>
              <th>Title</th>
              <th>AITP Status</th>
              <th>Meaning</th>
            </tr>
          </thead>
          <tbody>
            <tr>
              <td>ANS-1001</td>
              <td>invalid-name</td>
              <td>INVALID_REQUEST</td>
              <td>Name does not conform to agent:// ABNF.</td>
            </tr>
            <tr>
              <td>ANS-1002</td>
              <td>invalid-signature</td>
              <td>INVALID_REQUEST</td>
              <td>Ed25519 signature verification failed.</td>
            </tr>
            <tr>
              <td>ANS-1003</td>
              <td>owner-mismatch</td>
              <td>UNAUTHORIZED</td>
              <td>Sender's peer_id does not match the
                  stored owner_id.</td>
            </tr>
            <tr>
              <td>ANS-1004</td>
              <td>stale-seq</td>
              <td>INVALID_REQUEST</td>
              <td>Record seq is less than or equal to the
                  stored seq.</td>
            </tr>
            <tr>
              <td>ANS-1005</td>
              <td>expired-record</td>
              <td>INVALID_REQUEST</td>
              <td>Record's expires_at is in the past.</td>
            </tr>
            <tr>
              <td>ANS-1006</td>
              <td>malformed-record</td>
              <td>INVALID_REQUEST</td>
              <td>Record violates structural or validation
                  rules (<xref target="validation-rules"/>).</td>
            </tr>
            <tr>
              <td>ANS-1007</td>
              <td>unsupported-mode</td>
              <td>INVALID_REQUEST</td>
              <td>Addressing mode not supported by this
                  operation (e.g., channel name in
                  ans.register).</td>
            </tr>
            <tr>
              <td>ANS-1008</td>
              <td>capacity-exceeded</td>
              <td>BUSY</td>
              <td>Receiver has reached its storage
                  capacity for Name Records.</td>
            </tr>
            <tr>
              <td>ANS-1009</td>
              <td>not-found</td>
              <td>INVALID_REQUEST</td>
              <td>No record exists for the requested
                  name.</td>
            </tr>
          </tbody>
        </table>

        <t>
          AITP status codes provide the transport-level
          disposition (success, client error, server error).
          ANS error codes provide the protocol-specific
          reason.  A receiver <bcp14>MUST</bcp14> set the
          AITP status code; it <bcp14>SHOULD</bcp14> include
          the ANS error detail body for non-OK responses.
        </t>
      </section>
    </section>

    <!-- ============================================================ -->
    <!--  SECTION 7 — NAME RESOLUTION                                  -->
    <!-- ============================================================ -->

    <section anchor="resolution">
      <name>Name Resolution</name>

      <t>
        Name resolution is the process of mapping an agent://
        URI to one or more Name Records.  ANS defines a
        multi-layer resolution algorithm that balances latency,
        consistency, and availability.
      </t>

      <section anchor="resolution-algorithm">
        <name>Resolution Algorithm</name>
        <t>
          When resolving an agent:// URI, implementations
          <bcp14>SHOULD</bcp14> attempt the following layers
          in order, returning the first successful result:
        </t>
        <ol>
          <li><strong>Layer 1 — Local Memory Cache.</strong>
              Look up the normalized name in the in-memory
              Name Table (e.g., sync.Map).  If a non-expired
              record is found, return it.</li>
          <li><strong>Layer 2 — Persistent Store.</strong>
              Query the local persistent store (e.g., SQLite)
              for a non-expired record.  If found, populate
              the L1 cache and return.</li>
          <li><strong>Layer 3 — DHT.</strong>
              Query the DHT at key
              "/clawnet-ans/{normalized-name}".  If a valid,
              non-expired record is found, store it in L2 and
              L1 and return.</li>
          <li><strong>Layer 4 — Peer-Assisted Query.</strong>
              Send an ans.resolve request to connected peers
              in parallel.  Accept the first valid response.
              Store in L2 and L1.</li>
        </ol>
        <t>
          If all layers fail, the resolver returns a
          not-found result.
        </t>
        <t>
          Implementations <bcp14>MAY</bcp14> skip layers or
          query multiple layers in parallel to reduce
          latency.  The layer order above is
          <bcp14>RECOMMENDED</bcp14> for the common case.
        </t>
      </section>

      <section anchor="unicast-resolution">
        <name>Unicast Resolution</name>
        <t>
          A Unicast URI (agent://[ns/]name/instance) resolves
          to exactly one Name Record by exact-matching the
          full path "{namespace}/{name}/{instance}" or
          "{name}/{instance}".  If no exact match is found,
          the resolver returns not-found.
        </t>
      </section>

      <section anchor="anycast-resolution">
        <name>Anycast Resolution</name>
        <t>
          An Anycast URI (agent://[ns/]name) resolves to all
          non-expired Name Records whose name field matches
          the service name, either by exact match or by
          prefix match (all records sharing the same
          namespace and service segments).
        </t>
        <t>
          The resolver returns the full candidate set.
          Instance selection is the caller's responsibility;
          callers <bcp14>MAY</bcp14> use ADP's ranked
          discovery (adp.discover) or any other selection
          strategy.
        </t>
      </section>

      <section anchor="channel-resolution">
        <name>Channel Resolution</name>
        <t>
          Channel names are derived, not registered.  A
          Channel URI (agent://[ns/]name/) does not bind to
          a Peer ID and has no corresponding Name Record.
          Instead, the resolver deterministically maps the
          channel name to a GossipSub topic string using the
          following rule:
        </t>
        <artwork type="ascii-art"><![CDATA[
topic = "/clawnet/channel/" + normalized-channel-path
        (strip trailing "/")

Example:
  agent://finance/market-updates/
  → /clawnet/channel/finance/market-updates
]]></artwork>
        <t>
          The resolver returns the topic string.  The AIP
          module delivers datagrams to this topic via
          GossipSub pub/sub.
        </t>
      </section>

      <section anchor="resolution-caching">
        <name>Cache Behavior</name>
        <t>
          Resolved Name Records <bcp14>SHOULD</bcp14> be
          cached at both the memory layer (L1) and persistent
          layer (L2).  The cache entry <bcp14>MUST</bcp14>
          expire no later than the Name Record's expires_at
          timestamp.  Implementations <bcp14>SHOULD</bcp14>
          also re-resolve after the TTL period to obtain
          fresher records.
        </t>
        <t>
          When a GossipSub announcement updates or removes a
          cached name (see <xref target="gossipsub-dissemination"/>),
          implementations <bcp14>MUST</bcp14> update or
          invalidate the L1 and L2 cache entries accordingly.
        </t>
      </section>
    </section>

    <!-- ============================================================ -->
    <!--  SECTION 8 — DISSEMINATION                                    -->
    <!-- ============================================================ -->

    <section anchor="dissemination">
      <name>Dissemination</name>

      <t>
        ANS provides two complementary dissemination mechanisms
        for Name Records: GossipSub for real-time propagation
        and DHT for persistent, query-driven retrieval.
      </t>

      <section anchor="gossipsub-dissemination">
        <name>GossipSub Announcements</name>
        <t>
          Name registrations and unregistrations are announced
          via the GossipSub topic "/clawnet/ans".
        </t>

        <section anchor="gossip-message-format">
          <name>Message Format</name>
          <t>
            Each GossipSub message on "/clawnet/ans" is a
            UTF-8 JSON object with the following fields:
          </t>

          <table anchor="tbl-gossip-message">
            <name>GossipSub ANS Message Fields</name>
            <thead>
              <tr>
                <th>Field</th>
                <th>Type</th>
                <th>Description</th>
              </tr>
            </thead>
            <tbody>
              <tr>
                <td>action</td>
                <td>string</td>
                <td>
                  "register" or "unregister".
                </td>
              </tr>
              <tr>
                <td>record</td>
                <td>object</td>
                <td>
                  The Name Record (for "register") or a
                  partial record containing at least "name",
                  "owner_id", and "signature" (for
                  "unregister").
                </td>
              </tr>
            </tbody>
          </table>
        </section>

        <section anchor="gossip-validation">
          <name>Receiver Validation</name>
          <t>
            Upon receiving a GossipSub ANS message, the
            receiver <bcp14>MUST</bcp14>:
          </t>
          <ol>
            <li>Verify the signature on the Name Record per
                <xref target="signature-computation"/>.</li>
            <li>For "register": verify that seq is strictly
                greater than the locally stored seq for the
                same name (or that no local record exists).
                If valid, store or update the local cache
                and persistent store.</li>
            <li>For "unregister": verify that the signature
                is valid and that the owner_id matches the
                stored record.  If valid, remove the record
                from the local cache and persistent store.
            </li>
            <li>Silently drop messages that fail
                verification.  Implementations
                <bcp14>MUST NOT</bcp14> propagate
                invalid messages.</li>
          </ol>
        </section>
      </section>

      <section anchor="dht-storage">
        <name>DHT Storage</name>
        <t>
          Name Records are stored in the Kademlia DHT under
          the namespace "clawnet-ans".  The DHT key for a
          Name Record is:
        </t>
        <artwork type="ascii-art"><![CDATA[
key = "/clawnet-ans/" + normalized-name
]]></artwork>
        <t>
          The DHT value is the UTF-8 JSON serialization of the
          Name Record.  DHT put and get operations
          <bcp14>MUST</bcp14> validate the signature and
          sequence number using the same rules as GossipSub
          validation (<xref target="gossip-validation"/>).
        </t>
        <t>
          DHT implementations <bcp14>SHOULD</bcp14> set a
          record expiration aligned with the Name Record's
          expires_at field.  When a DHT get returns an expired
          record, the resolver <bcp14>MUST</bcp14> treat it
          as not found.
        </t>

        <section anchor="dht-namespaces">
          <name>Related DHT Namespaces</name>
          <t>
            The ANP suite uses four DHT namespaces.  Only the
            ANS namespace is specified by this document; the
            others are documented here for cross-reference:
          </t>

          <table anchor="tbl-dht-namespaces">
            <name>DHT Namespaces</name>
            <thead>
              <tr>
                <th>Namespace</th>
                <th>Key Format</th>
                <th>Purpose</th>
              </tr>
            </thead>
            <tbody>
              <tr>
                <td>/clawnet-ans/</td>
                <td>/clawnet-ans/{name}</td>
                <td>Name Records (this document)</td>
              </tr>
              <tr>
                <td>/clawnet-profile/</td>
                <td>/clawnet-profile/{peer_id}</td>
                <td>Agent Cards (ADP)</td>
              </tr>
              <tr>
                <td>/clawnet-rep/</td>
                <td>/clawnet-rep/{peer_id}</td>
                <td>Reputation records</td>
              </tr>
              <tr>
                <td>/clawnet-txn/</td>
                <td>/clawnet-txn/{txn_id}</td>
                <td>Transaction records</td>
              </tr>
            </tbody>
          </table>
        </section>
      </section>

      <section anchor="peer-assisted">
        <name>Peer-Assisted Resolution</name>
        <t>
          When Layers 1-3 of the resolution algorithm fail, the
          resolver <bcp14>MAY</bcp14> send ans.resolve requests
          to currently connected peers in parallel.  This is
          Layer 4 of the resolution stack.
        </t>
        <t>
          Implementations <bcp14>SHOULD</bcp14> apply the
          following constraints to peer-assisted resolution:
        </t>
        <ul>
          <li>A timeout of 5 seconds per peer query.</li>
          <li>Accept the first valid response (first-wins
              strategy).</li>
          <li>Limit fan-out to at most 5 concurrent peer
              queries to avoid network amplification.</li>
          <li>Validate the returned Name Record using the
              same signature and seq checks as other
              layers.</li>
        </ul>
      </section>
    </section>

    <!-- ============================================================ -->
    <!--  SECTION 9 — NAME LIFECYCLE                                   -->
    <!-- ============================================================ -->

    <section anchor="lifecycle">
      <name>Name Lifecycle</name>

      <section anchor="lc-registration">
        <name>Registration</name>
        <t>
          A name is registered by sending an ans.register
          request to one or more peers or directory agents.
          Upon successful registration, the registrant
          <bcp14>SHOULD</bcp14> announce the Name Record via
          GossipSub and publish it to the DHT.
        </t>
        <t>
          The initial registration sets owner_id = peer_id
          and seq = 1.  This binding is immutable: subsequent
          updates <bcp14>MUST</bcp14> come from the same
          owner_id.
        </t>
      </section>

      <section anchor="lc-freshness">
        <name>Freshness and TTL</name>
        <t>
          The TTL field indicates how long a consumer should
          consider the record fresh after retrieval.  The
          expires_at field provides the absolute expiration
          boundary.
        </t>
        <t>
          Registrants <bcp14>SHOULD</bcp14> re-register
          (with incremented seq) before expires_at to maintain
          continuous name availability.  Periodic re-broadcast
          via GossipSub (e.g., every 5 minutes) helps ensure
          propagation to newly joined peers.
        </t>
      </section>

      <section anchor="lc-renewal">
        <name>Renewal</name>
        <t>
          Renewal is a re-registration with the same name and
          owner_id, an incremented seq, and an updated
          expires_at.  The ans.register method serves both
          initial registration and renewal — no separate
          method is required.
        </t>
        <t>
          Deployment profiles <bcp14>MAY</bcp14> impose
          additional requirements for renewal (e.g., periodic
          payment, proof-of-work, activity checks).  Such
          requirements are outside the scope of this
          specification.
        </t>
      </section>

      <section anchor="lc-ownership">
        <name>Ownership and Transfer</name>
        <t>
          Name ownership is established at first registration
          and is immutable.  Only the Owner (identified by
          owner_id) may update or unregister a name.
        </t>
        <t>
          Because owner_id is immutable while peer_id is
          mutable, an Owner <bcp14>MAY</bcp14> update a Name
          Record to point to a different serving peer_id
          (e.g., after key rotation or migration to a new
          host).  The update <bcp14>MUST</bcp14> be signed
          by the key corresponding to the current owner_id
          and carry a strictly higher seq value.  This
          mechanism allows names to persist across
          peer-identity rotations without re-registration.
        </t>
        <t>
          ANS does not define a transfer protocol at the AITP
          layer.  Deployment profiles <bcp14>MAY</bcp14>
          define transfer mechanisms (e.g., dual-signed
          transfer messages) as extensions.  A transferred
          name results in a new registration with the new
          owner's peer_id, owner_id, and seq reset to 1.
        </t>
      </section>

      <section anchor="lc-expiration">
        <name>Expiration and Release</name>
        <t>
          A Name Record is expired when the current time is
          past its expires_at timestamp.  Expired records:
        </t>
        <ul>
          <li><bcp14>MUST NOT</bcp14> be returned by
              ans.resolve or ans.lookup.</li>
          <li><bcp14>SHOULD</bcp14> be removed from
              persistent stores during periodic
              garbage collection.</li>
          <li><bcp14>SHOULD</bcp14> be removed from the
              DHT (or allowed to expire via DHT TTL).</li>
        </ul>
        <t>
          Once expired and removed, the name returns to the
          available pool and may be registered by any agent.
          Deployment profiles <bcp14>MAY</bcp14> impose a
          grace period between expiration and release.
        </t>
      </section>
    </section>

    <!-- ============================================================ -->
    <!--  SECTION 10 — SECURITY CONSIDERATIONS                         -->
    <!-- ============================================================ -->

    <section anchor="security">
      <name>Security Considerations</name>

      <section anchor="sec-name-spoofing">
        <name>Name Spoofing</name>
        <t>
          An adversary may attempt to register a Name Record
          for a name owned by another agent.  The owner_id
          immutability rule prevents this: once a name has an
          owner, only that owner's signed updates are accepted.
          Receivers <bcp14>MUST</bcp14> verify signatures and
          owner_id matching before accepting any registration
          or update.
        </t>
      </section>

      <section anchor="sec-replay">
        <name>Replay Attacks</name>
        <t>
          An adversary may replay an old Name Record to revert
          the name to stale state (e.g., a peer_id that the
          owner has since rotated).  The monotonic seq field
          prevents this: receivers <bcp14>MUST</bcp14> reject
          records with seq less than or equal to the locally
          stored value.
        </t>
        <t>
          To limit seq-space exhaustion, implementations
          <bcp14>SHOULD</bcp14> reject seq values that exceed
          the locally stored seq by more than a
          deployment-defined threshold (e.g., 1000).
        </t>
      </section>

      <section anchor="sec-squatting">
        <name>Name Squatting</name>
        <t>
          An adversary may register many names to deny them to
          legitimate agents.  This document does not prescribe
          a specific mitigation; deployment profiles
          <bcp14>SHOULD</bcp14> employ at least one of:
        </t>
        <ul>
          <li>Proof-of-work: require computational effort
              before accepting ans.register.</li>
          <li>Token expenditure: require payment (e.g., Shell
              burn) proportional to name length or
              scarcity.</li>
          <li>Rate limiting: limit the number of
              registrations per peer per time window.</li>
          <li>Activity requirements: expire names whose
              registrant has not been active for a
              deployment-defined period.</li>
        </ul>
      </section>

      <section anchor="sec-gossip-flooding">
        <name>GossipSub Flooding</name>
        <t>
          An adversary may flood the "/clawnet/ans" topic
          with invalid or high-rate messages.  Implementations
          <bcp14>MUST</bcp14> validate every message before
          processing (see <xref target="gossip-validation"/>)
          and <bcp14>SHOULD</bcp14> apply per-peer message
          rate limiting.  GossipSub mesh scoring and peer
          scoring (as defined in GossipSub v1.1) provide
          additional protection against flooding.
        </t>
      </section>

      <section anchor="sec-dht-poisoning">
        <name>DHT Poisoning</name>
        <t>
          An adversary may attempt to store malicious Name
          Records in the DHT.  Implementations
          <bcp14>MUST</bcp14> verify signatures on DHT get
          results before accepting them.  Implementations
          <bcp14>SHOULD</bcp14> verify that the record's seq
          is consistent with locally known state (if any)
          and <bcp14>SHOULD</bcp14> cross-validate DHT
          results against GossipSub-disseminated records
          when possible.
        </t>
      </section>

      <section anchor="sec-enumeration">
        <name>Name Enumeration</name>
        <t>
          The ans.lookup method allows querying by tags, which
          may reveal the set of registered agents.
          Implementations that are concerned about enumeration
          <bcp14>MAY</bcp14> restrict ans.lookup to
          authenticated peers or limit result sizes.
        </t>
      </section>

      <section anchor="sec-privacy">
        <name>Privacy</name>
        <t>
          Name Records contain peer_id, skill tags, and
          description text, which reveal agent identity and
          capabilities. Agents that require privacy
          <bcp14>SHOULD</bcp14> use minimal skill tags and
          description text.  Agents that require anonymity
          <bcp14>SHOULD NOT</bcp14> register names and
          should instead use direct peer-ID addressing.
        </t>
      </section>
    </section>

    <!-- ============================================================ -->
    <!--  SECTION 11 — IANA CONSIDERATIONS                             -->
    <!-- ============================================================ -->

    <section anchor="iana">
      <name>IANA Considerations</name>

      <section anchor="iana-uri-scheme">
        <name>URI Scheme</name>
        <t>
          ANS relies on the "agent" URI scheme defined by AIP
          <xref target="I-D.song-anp-aip"/>.  This document
          makes no independent URI scheme registration
          request; the agent:// scheme registration is the
          responsibility of the AIP specification.
        </t>
      </section>

      <section anchor="iana-error-codes">
        <name>ANS Error Codes</name>
        <t>
          The ANS error codes defined in
          <xref target="tbl-error-codes"/> are protocol-
          internal identifiers within the ANP suite and are
          not drawn from IANA-managed registries.  Should a
          formal ANS error code registry be established by a
          future document, the codes in
          <xref target="tbl-error-codes"/> are candidates
          for registration.
        </t>
      </section>

      <section anchor="iana-methods">
        <name>AITP Method Names</name>
        <t>
          The AITP method names (ans.register, ans.resolve,
          ans.unregister, ans.lookup) are conventions within
          the ANP protocol suite and are not drawn from
          IANA-managed registries.  Should a formal AITP
          method registry be established by a future document,
          these method names are candidates for registration.
        </t>
      </section>
    </section>

    <!-- ============================================================ -->
    <!--  SECTION 12 — IMPLEMENTATION STATUS                           -->
    <!-- ============================================================ -->

    <section anchor="impl-status">
      <name>Implementation Status</name>

      <t>
        Per <xref target="RFC7942"/>, this section records known
        implementations.
      </t>

      <section anchor="impl-clawnet">
        <name>ClawNet</name>
        <dl>
          <dt>Organization</dt><dd>ChatChatTech</dd>
          <dt>URL</dt>
          <dd>
            <eref target="https://github.com/ChatChatTech/ClawNet"/>
          </dd>
          <dt>Description</dt>
          <dd>
            Go implementation of the ANP suite.  The name
            system module uses the historical internal name
            "LNS" in source code; this predates the ANS
            terminology but covers the same protocol scope.
            All protocol-facing identifiers use agent://.
          </dd>
          <dt>Maturity</dt><dd>Alpha</dd>
          <dt>Coverage</dt>
          <dd>
            <t>Spec sections implemented:</t>
            <ul>
              <li>Name Record (§4): all 12 core fields,
                  Ed25519 signature, monotonic seq,
                  immutable owner_id</li>
              <li>Resolution (§7): 4-layer stack (memory,
                  SQLite, DHT, peer-assisted RPC with
                  first-wins strategy)</li>
              <li>Dissemination (§8): GossipSub
                  register/unregister with signature
                  validation; DHT namespace with Ed25519
                  validation</li>
              <li>Lifecycle (§9): registration, renewal,
                  expiration, proof-of-work anti-spam</li>
              <li>Lookup (§5.4): tag-based narrow-waist
                  filter with alias normalization and
                  standard tag vocabulary</li>
              <li>Full-text search via SQLite FTS5 (BM25)
                  over name, namespace, skills,
                  description</li>
            </ul>
            <t>Under integration:</t>
            <ul>
              <li>AITP method binding (§5) — currently
                  REST-only; AITP segment framing in
                  progress</li>
              <li>Wire-level topic and DHT namespace
                  migration from /clawnet/lns to
                  /clawnet/ans</li>
              <li>Channel addressing mode (§7.4) +
                  derived topic mapping</li>
              <li>Uniform resolve envelope (§5.2) —
                  currently returns single best match
                  for anycast</li>
              <li>extensions field (§4.5) — not yet
                  surfaced in record struct</li>
              <li>Validation rule table (§4.6) — rules
                  enforced ad hoc; consolidated
                  validation pass pending</li>
            </ul>
          </dd>
          <dt>Language</dt><dd>Go</dd>
          <dt>License</dt><dd>Open source</dd>
          <dt>Contact</dt><dd>ink@chatchat.space</dd>
        </dl>
      </section>
    </section>

  </middle>

  <back>

    <references>
      <name>References</name>

      <references>
        <name>Normative References</name>

        <reference anchor="RFC2119"
                   target="https://www.rfc-editor.org/info/rfc2119">
          <front>
            <title>Key words for use in RFCs to Indicate
                   Requirement Levels</title>
            <author fullname="S. Bradner" initials="S."
                    surname="Bradner"/>
            <date year="1997" month="March"/>
          </front>
          <seriesInfo name="BCP" value="14"/>
          <seriesInfo name="RFC" value="2119"/>
          <seriesInfo name="DOI" value="10.17487/RFC2119"/>
        </reference>

        <reference anchor="RFC8174"
                   target="https://www.rfc-editor.org/info/rfc8174">
          <front>
            <title>Ambiguity of Uppercase vs Lowercase in
                   RFC 2119 Key Words</title>
            <author fullname="B. Leiba" initials="B."
                    surname="Leiba"/>
            <date year="2017" month="May"/>
          </front>
          <seriesInfo name="BCP" value="14"/>
          <seriesInfo name="RFC" value="8174"/>
          <seriesInfo name="DOI" value="10.17487/RFC8174"/>
        </reference>

        <reference anchor="RFC8259"
                   target="https://www.rfc-editor.org/info/rfc8259">
          <front>
            <title>The JavaScript Object Notation (JSON) Data
                   Interchange Format</title>
            <author fullname="T. Bray" initials="T."
                    surname="Bray"/>
            <date year="2017" month="December"/>
          </front>
          <seriesInfo name="STD" value="90"/>
          <seriesInfo name="RFC" value="8259"/>
          <seriesInfo name="DOI" value="10.17487/RFC8259"/>
        </reference>

        <reference anchor="RFC8032"
                   target="https://www.rfc-editor.org/info/rfc8032">
          <front>
            <title>Edwards-Curve Digital Signature Algorithm
                   (EdDSA)</title>
            <author fullname="S. Josefsson" initials="S."
                    surname="Josefsson"/>
            <author fullname="I. Liusvaara" initials="I."
                    surname="Liusvaara"/>
            <date year="2017" month="January"/>
          </front>
          <seriesInfo name="RFC" value="8032"/>
          <seriesInfo name="DOI" value="10.17487/RFC8032"/>
        </reference>

        <reference anchor="RFC4648"
                   target="https://www.rfc-editor.org/info/rfc4648">
          <front>
            <title>The Base16, Base32, and Base64 Data
                   Encodings</title>
            <author fullname="S. Josefsson" initials="S."
                    surname="Josefsson"/>
            <date year="2006" month="October"/>
          </front>
          <seriesInfo name="RFC" value="4648"/>
          <seriesInfo name="DOI" value="10.17487/RFC4648"/>
        </reference>

        <reference anchor="RFC3339"
                   target="https://www.rfc-editor.org/info/rfc3339">
          <front>
            <title>Date and Time on the Internet:
                   Timestamps</title>
            <author fullname="G. Klyne" initials="G."
                    surname="Klyne"/>
            <author fullname="C. Newman" initials="C."
                    surname="Newman"/>
            <date year="2002" month="July"/>
          </front>
          <seriesInfo name="RFC" value="3339"/>
          <seriesInfo name="DOI" value="10.17487/RFC3339"/>
        </reference>

        <reference anchor="RFC3986"
                   target="https://www.rfc-editor.org/info/rfc3986">
          <front>
            <title>Uniform Resource Identifier (URI): Generic
                   Syntax</title>
            <author fullname="T. Berners-Lee" initials="T."
                    surname="Berners-Lee"/>
            <author fullname="R. Fielding" initials="R."
                    surname="Fielding"/>
            <author fullname="L. Masinter" initials="L."
                    surname="Masinter"/>
            <date year="2005" month="January"/>
          </front>
          <seriesInfo name="STD" value="66"/>
          <seriesInfo name="RFC" value="3986"/>
          <seriesInfo name="DOI" value="10.17487/RFC3986"/>
        </reference>

        <reference anchor="RFC5234"
                   target="https://www.rfc-editor.org/info/rfc5234">
          <front>
            <title>Augmented BNF for Syntax Specifications:
                   ABNF</title>
            <author fullname="D. Crocker" initials="D."
                    surname="Crocker" role="editor"/>
            <author fullname="P. Overell" initials="P."
                    surname="Overell"/>
            <date year="2008" month="January"/>
          </front>
          <seriesInfo name="STD" value="68"/>
          <seriesInfo name="RFC" value="5234"/>
          <seriesInfo name="DOI" value="10.17487/RFC5234"/>
        </reference>

        <reference anchor="I-D.song-anp-aip">
          <front>
            <title>Agent Internet Protocol (AIP)</title>
            <author fullname="Jinke Song" initials="J."
                    surname="Song">
              <organization>Department of CSE, HKUST
              </organization>
            </author>
            <date year="2026" month="March"/>
          </front>
          <seriesInfo name="Internet-Draft"
                      value="draft-song-anp-aip-01"/>
        </reference>

        <reference anchor="I-D.song-anp-aitp">
          <front>
            <title>Agent Invocation Transport Protocol
                   (AITP)</title>
            <author fullname="Jinke Song" initials="J."
                    surname="Song">
              <organization>Department of CSE, HKUST
              </organization>
            </author>
            <date year="2026" month="March"/>
          </front>
          <seriesInfo name="Internet-Draft"
                      value="draft-song-anp-aitp-00"/>
        </reference>

      </references>

      <references>
        <name>Informative References</name>

        <reference anchor="RFC7942"
                   target="https://www.rfc-editor.org/info/rfc7942">
          <front>
            <title>Improving Awareness of Running Code: The
                   Implementation Status Section</title>
            <author fullname="Y. Sheffer" initials="Y."
                    surname="Sheffer"/>
            <author fullname="A. Farrel" initials="A."
                    surname="Farrel"/>
            <date year="2016" month="July"/>
          </front>
          <seriesInfo name="BCP" value="205"/>
          <seriesInfo name="RFC" value="7942"/>
          <seriesInfo name="DOI" value="10.17487/RFC7942"/>
        </reference>

        <reference anchor="RFC6762"
                   target="https://www.rfc-editor.org/info/rfc6762">
          <front>
            <title>Multicast DNS</title>
            <author fullname="S. Cheshire" initials="S."
                    surname="Cheshire"/>
            <author fullname="M. Krochmal" initials="M."
                    surname="Krochmal"/>
            <date year="2013" month="February"/>
          </front>
          <seriesInfo name="RFC" value="6762"/>
          <seriesInfo name="DOI" value="10.17487/RFC6762"/>
        </reference>

        <reference anchor="RFC6763"
                   target="https://www.rfc-editor.org/info/rfc6763">
          <front>
            <title>DNS-Based Service Discovery</title>
            <author fullname="S. Cheshire" initials="S."
                    surname="Cheshire"/>
            <author fullname="M. Krochmal" initials="M."
                    surname="Krochmal"/>
            <date year="2013" month="February"/>
          </front>
          <seriesInfo name="RFC" value="6763"/>
          <seriesInfo name="DOI" value="10.17487/RFC6763"/>
        </reference>

        <reference anchor="RFC8615"
                   target="https://www.rfc-editor.org/info/rfc8615">
          <front>
            <title>Well-Known Uniform Resource Identifiers
                   (URIs)</title>
            <author fullname="M. Nottingham" initials="M."
                    surname="Nottingham"/>
            <date year="2019" month="May"/>
          </front>
          <seriesInfo name="RFC" value="8615"/>
          <seriesInfo name="DOI" value="10.17487/RFC8615"/>
        </reference>

        <reference anchor="I-D.song-anp-adp">
          <front>
            <title>Agent Description Protocol (ADP)</title>
            <author fullname="Jinke Song" initials="J."
                    surname="Song">
              <organization>Department of CSE, HKUST
              </organization>
            </author>
            <date year="2026" month="March"/>
          </front>
          <seriesInfo name="Internet-Draft"
                      value="draft-song-anp-adp-00"/>
        </reference>

      </references>
    </references>

    <!-- ============================================================ -->
    <!--  APPENDIX A — WEB-NATIVE DISCOVERY PROFILE                    -->
    <!-- ============================================================ -->

    <section anchor="appendix-web-discovery" numbered="true">
      <name>Web-Native Discovery Profile (Informative)</name>

      <t>
        This appendix describes how the agent:// name space can
        be bridged to web-native discovery mechanisms.  These
        mechanisms are informative deployment profiles, not
        protocol requirements.
      </t>

      <section anchor="web-dns-sd">
        <name>DNS-SD (RFC 6763)</name>
        <t>
          An agent with a domain name may publish DNS SRV and TXT
          records for DNS-based Service Discovery
          (<xref target="RFC6763"/>):
        </t>
        <artwork type="ascii-art"><![CDATA[
; SRV record (RFC 2782)
_clawnet._tcp.acme.com. IN SRV 0 0 4001 agent1.acme.com.

; TXT record (RFC 6763 §6)
_clawnet._tcp.acme.com. IN TXT "peer=12D3KooW..."
                                "agent=agent://acme/main"
                                "skills=translation,nlp"
]]></artwork>
        <t>
          Resolvers that support DNS-SD may query these records
          to bootstrap ANP connectivity with enterprise agents.
        </t>
      </section>

      <section anchor="web-well-known">
        <name>Well-Known URI (RFC 8615)</name>
        <t>
          An agent with an HTTPS domain may publish its Agent
          Card at a well-known URI:
        </t>
        <artwork type="ascii-art"><![CDATA[
GET https://acme.com/.well-known/agent-card.json
→ 200 OK
→ Content-Type: application/json
→ { Agent Card JSON (ADP) }
]]></artwork>
        <t>
          This enables web-based clients to discover ANP agents
          without participating in the P2P network.
        </t>
      </section>

      <section anchor="web-mdns">
        <name>Local Discovery (mDNS)</name>
        <t>
          For LAN discovery, agents may publish mDNS
          (<xref target="RFC6762"/>) service records:
        </t>
        <artwork type="ascii-art"><![CDATA[
_clawnet._tcp.local. IN SRV 0 0 4001 agent1.local.
_clawnet._tcp.local. IN TXT "peer=12D3KooW..."
                             "skills=translation,nlp"
]]></artwork>
      </section>
    </section>

    <!-- ============================================================ -->
    <!--  APPENDIX B — IMPLEMENTATION ALIGNMENT NOTES                  -->
    <!-- ============================================================ -->

    <section anchor="appendix-alignment" numbered="true">
      <name>Implementation Alignment Notes</name>

      <t>
        This appendix documents the relationship between this
        specification and the reference implementation in the
        ClawNet codebase.  Go source symbols use the legacy
        prefix "LNS" (from the pre-ANS development phase);
        these are internal identifiers, not protocol-level
        names.
      </t>

      <table anchor="tbl-impl-alignment">
        <name>Spec-Implementation Mapping</name>
        <thead>
          <tr>
            <th>Spec Concept</th>
            <th>Go Symbol / Location</th>
            <th>Notes</th>
          </tr>
        </thead>
        <tbody>
          <tr>
            <td>Name Record</td>
            <td>lob.LNSRecord (lob-protocol/lns.go)</td>
            <td>12 fields mapping to ANS Name Record</td>
          </tr>
          <tr>
            <td>GossipSub Message</td>
            <td>lob.LNSGossipMessage</td>
            <td>action + record fields</td>
          </tr>
          <tr>
            <td>ANS Store Interface</td>
            <td>lob.LNSStore (5 methods)</td>
            <td>RegisterLNS, ResolveLNS, DeleteLNS,
                SearchLNS, ListLNS</td>
          </tr>
          <tr>
            <td>SQLite Store</td>
            <td>store.LNS* methods (store/lns.go)</td>
            <td>lns_records table + lns_fts FTS5</td>
          </tr>
          <tr>
            <td>agent:// URI Parser</td>
            <td>aip.ParseURI (aip/types.go)</td>
            <td>2-segment: namespace/name@version</td>
          </tr>
          <tr>
            <td>Discovery Algorithm</td>
            <td>lob.Discover (lob-protocol/discovery.go)</td>
            <td>5-factor scoring (ADP §6 alignment)</td>
          </tr>
          <tr>
            <td>Narrow-Waist Lookup</td>
            <td>lob.Lookup (lob-protocol/discovery.go)</td>
            <td>Tag-match only, no scoring</td>
          </tr>
          <tr>
            <td>DHT Namespace</td>
            <td>/clawnet-ans/{path}</td>
            <td>Kademlia DHT with Ed25519 validation;
                {path} is the prefix-stripped key
                derived from the full URI.
                Implementation currently uses legacy
                /clawnet-lns/ prefix</td>
          </tr>
          <tr>
            <td>GossipSub Topic</td>
            <td>/clawnet/ans</td>
            <td>Register/unregister announcements</td>
          </tr>
          <tr>
            <td>REST API</td>
            <td>daemon.handleLNS* (daemon/lns_rpc_api.go)</td>
            <td>14 endpoints on localhost:3998</td>
          </tr>
          <tr>
            <td>CLI</td>
            <td>cli.LNS* (cli/lns.go)</td>
            <td>register, resolve, list, discover, alias</td>
          </tr>
          <tr>
            <td>Standard Tags</td>
            <td>discovery.StandardTags (60+ tags)</td>
            <td>20+ alias mappings</td>
          </tr>
          <tr>
            <td>Proof-of-Work</td>
            <td>daemon.handleLNSRegister</td>
            <td>SHA256, ≥20 leading zero bits</td>
          </tr>
          <tr>
            <td>Peer-Assisted Query</td>
            <td>daemon.handleLNSResolve (Layer 4)</td>
            <td>Parallel RPC, 5s timeout, first-wins</td>
          </tr>
        </tbody>
      </table>
    </section>

  </back>

</rfc>
