<?xml version='1.0' encoding='UTF-8'?>
<rfc version="3" docName="draft-li-mlc-inference-acceleration-00" category="std" consensus="true" submissionType="IETF" ipr="trust200902" tocInclude="true" tocDepth="3" sortRefs="true" symRefs="true" xml:lang="en">

  <front>
    <title abbrev="SDCP">Speculative Decoding Coordination Protocol (SDCP) for Distributed Inference with Multi-Level Caches</title>
    <seriesInfo name="Internet-Draft" value="draft-li-mlc-inference-acceleration-00"/>

    <author fullname="Zhiqiang Li" initials="Z." surname="Li">
      <organization>China Mobile</organization>
      <address>
        <postal><city>Beijing</city><code>100053</code>
        <country>China</country></postal>
        <email>lizhiqiangyjy@chinamobile.com</email>
      </address>
    </author>
    <author fullname="Zongpeng Du" initials="Z." surname="Du">
      <organization>China Mobile</organization>
      <address>
        <postal><city>Beijing</city><code>100053</code>
        <country>China</country></postal>
        <email>duzongpeng@chinamobile.com</email>
      </address>
    </author>
    <author fullname="Junjie Wang" initials="J." surname="Wang">
      <organization>Centec</organization>
      <address>
        <postal><city>Shanghai</city><code>201203</code>
        <country>China</country></postal>
        <email>wangjj@centec.com</email>
      </address>
    </author>
    <author fullname="Wei Cheng" initials="W." surname="Cheng">
      <organization>Centec</organization>
      <address>
        <postal><city>Shanghai</city><code>201203</code>
        <country>China</country></postal>
        <email>chengw@centec.com</email>
      </address>
    </author>
    <author fullname="Ying Zhao" initials="Y." surname="Zhao">
      <organization>Centec</organization>
      <address>
        <postal><city>Shanghai</city><code>200000</code>
        <country>China</country></postal>
        <email>zhaoying@centec.com</email>
      </address>
    </author>
    <author fullname="Chunhao Zhao" initials="C." surname="Zhao">
      <organization>SAIA</organization>
      <address>
        <postal><city>Shanghai</city><code>200125</code>
        <country>China</country></postal>
        <email>chunhao.zhao@sh-aia.com</email>
      </address>
    </author>
    <author fullname="Xun Sun" initials="X." surname="Sun">
      <organization>Inesa</organization>
      <address>
        <postal><city>Shanghai</city><code>200030</code>
        <country>China</country></postal>
        <email>sunxun@inesa.com</email>
      </address>
    </author>

    <date year="2026" month="November" day="2"/>
    <area>Applications and Real-Time</area>
    <keyword>speculative decoding</keyword>
    <keyword>draft model</keyword>
    <keyword>verification</keyword>
    <keyword>distributed inference</keyword>
    <keyword>multi-level cache</keyword>
    <keyword>CBOR</keyword>

    <abstract>
      <t>Speculative decoding accelerates language model inference: a small
      draft model proposes several tokens and the large target model
      verifies them in one forward pass.  In large deployments, draft models
      and the target model run on separate, independently scaled instances
      that exchange state through a multi-level cache.  This document
      specifies the Speculative Decoding Coordination Protocol (SDCP), with
      which a router assigns requests to draft instances by load, draft
      instances submit proposals that reference draft state in the cache,
      and a verifier, the only party that commits output, checks proposals
      under a registered acceptance rule, returns the accepted tokens and
      the next-round speculation limit, and escalates persistently rejected
      sessions to a reduced speculation length, another draft model, or
      decoding by the target model itself depending on its load.  SDCP
      defines a session contract, a committed-prefix digest chain, CBOR
      messages carried over HTTP, idempotent rounds, and epoch fencing for
      recovery.</t>
    </abstract>
  </front>

  <middle>

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

      <section anchor="background">
        <name>Background</name>
        <t>Autoregressive decoding produces one token per forward pass of
        the target model.  Each pass reads all model weights and the whole
        KV cache, so decoding is limited by memory bandwidth and leaves
        compute idle.  Speculative decoding
        <xref target="LEVIATHAN"/> <xref target="CHEN"/> lets a cheaper draft
        model propose M tokens, which the target model then scores in a
        single pass.  The longest acceptable prefix of the proposal is kept,
        and the target model contributes one more token, so each target pass
        yields between 1 and M+1 tokens.  With the speculative sampling rule,
        the output follows exactly the distribution of the target model.
        Some models are trained with built-in multi-token prediction heads
        that serve as drafters <xref target="DEEPSEEKV3"/>.</t>
      </section>

      <section anchor="problem">
        <name>Problem Statement</name>
        <t>When drafting and verification run in one process, the
        coordination is internal.  Large deployments separate them: several
        draft model instances, possibly of different sizes, serve many
        concurrent requests and feed one or more target-model verifier
        instances, and both exchange token state and KV caches through a
        multi-level cache spanning accelerator memory, host memory, and
        networked storage <xref target="I-D.li-kvcache-efficient-storage"/>.
        In that setting the following must be agreed between independently
        implemented components:</t>
        <ul>
          <li>how requests are assigned to draft instances according to their
          load, so that the requests of one batch can use different
          drafters;</li>
          <li>how many tokens a drafter proposes, given its history of
          accepted proposals, its load, and the bandwidth available to the
          cache;</li>
          <li>how a proposal refers to draft state in the cache instead of
          carrying it, so that the verifier can assemble large verification
          batches from many drafters;</li>
          <li>which acceptance rule the verifier applies, and how the rule
          can follow user preferences;</li>
          <li>what happens when proposals keep being rejected: reduce the
          speculation length, switch to another drafter, let the target model
          decode by itself if it has spare capacity, or fail; and</li>
          <li>how one authoritative output is maintained across retries,
          concurrent proposals, and instance failures.</li>
        </ul>
      </section>

      <section anchor="overview">
        <name>Protocol Overview</name>
        <t>SDCP addresses these needs with the following elements:</t>
        <ul>
          <li>an immutable Session Contract that fixes the models, the
          acceptance rule, limits, and the escalation policy
          (<xref target="contract"/>);</li>
          <li>a committed-prefix digest chain that every proposal must
          extend, which makes stale or forked proposals detectable
          (<xref target="digest"/>);</li>
          <li>assignment, proposal, verdict, and output messages in CBOR
          <xref target="RFC8949"/>, described in CDDL <xref target="RFC8610"/>
          and exchanged over HTTP (<xref target="messages"/>);</li>
          <li>a verification procedure with registered acceptance rules
          (<xref target="verification"/>); and</li>
          <li>speculation-length control and load-aware escalation
          (<xref target="control"/>).</li>
        </ul>
        <t>The verifier is the sole commit authority.  Drafters, routers, and
        caches can fail or misbehave without changing the committed output,
        except as discussed in <xref target="security"/>.</t>
      </section>

      <section anchor="scope">
        <name>Scope</name>
        <t>SDCP does not define model architectures, sampling kernels,
        batching algorithms, or client-facing inference APIs.  It assumes a
        multi-level cache that stores and serves opaque objects named by URI
        and supports leases, such as KVSP
        <xref target="I-D.li-kvcache-efficient-storage"/>.  Draft-model
        training, tree-structured speculation, and multiple verifiers per
        session are out of scope for this version.</t>
      </section>
    </section>

    <section anchor="conventions">
      <name>Conventions and Definitions</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 14
      <xref target="RFC2119"/> <xref target="RFC8174"/> when, and only
      when, they appear in all capitals, as shown here.</t>
      <dl newline="false" spacing="normal">
        <dt>Target model:</dt><dd>The model whose output distribution the
        service promises.</dd>
        <dt>Draft model:</dt><dd>A cheaper model, or auxiliary prediction
        head, that proposes tokens.</dd>
        <dt>Router:</dt><dd>The component that admits requests, creates
        sessions, and assigns them to drafters.</dd>
        <dt>Drafter:</dt><dd>An instance that runs a draft model.</dd>
        <dt>Verifier:</dt><dd>An instance that runs the target model and
        commits output.</dd>
        <dt>Multi-Level Cache (MLC):</dt><dd>Storage for prompts, KV caches,
        and draft artifacts across memory and storage tiers, reachable by
        all instances.</dd>
        <dt>Session:</dt><dd>One generation task, identified by a 16-octet
        identifier.</dd>
        <dt>Committed prefix:</dt><dd>The prompt followed by all output
        tokens committed so far; its length in output tokens is n.</dd>
        <dt>Round:</dt><dd>One proposal and its verdict.  Rounds of a session
        are numbered from 1.</dd>
        <dt>Speculation length (M):</dt><dd>The number of tokens in a
        proposal.</dd>
        <dt>Acceptance rule:</dt><dd>The algorithm that decides how many
        proposed tokens are kept (<xref target="rules"/>).</dd>
        <dt>Epoch:</dt><dd>A counter that identifies the current verifier
        authority of a session (<xref target="recovery"/>).</dd>
      </dl>
    </section>

    <section anchor="architecture">
      <name>Architecture</name>
      <figure anchor="fig-arch">
        <name>SDCP Roles</name>
        <artwork type="ascii-art">
            requests                        output tokens
  Client -----------&gt; +--------+          +-------------&gt; Client
                      | Router |          |
                      +--------+          |
        assignment  /    |     \  events  |
                   v     |      \         |
          +-----------+  |  +-----------+-+---+
          | Drafter 1 |  |  |    Verifier     |
          +-----------+  |  |  (target model) |
          +-----------+  |  +--------+--------+
          | Drafter 2 |--+--proposal-&gt;|verdict
          +-----+-----+     &lt;---------+
                |                     |
                v  draft KV, q rows   v  target KV, commits
          +-------------------------------------+
          |          Multi-Level Cache          |
          +-------------------------------------+
</artwork>
      </figure>
      <t>The router creates a session at a verifier, which computes or loads
      the KV cache of the prompt, and assigns the session to a drafter.  The
      drafter proposes tokens to the verifier.  The verifier answers each
      proposal with a verdict that both commits output and steers the next
      round.  Draft state that is large, such as the draft model's KV cache
      and probability rows, stays in the MLC and is referenced by URI.</t>
    </section>

    <section anchor="session">
      <name>Session Model</name>

      <section anchor="contract">
        <name>Session Contract</name>
        <t>The Session Contract is fixed when the session is created:</t>
        <sourcecode type="cddl">
contract = {
  target:      hash32,          ; SHA-256 of target model weights
  tokenizer:   hash32,          ; SHA-256 of tokenizer definition
  ? drafters:  [+ hash32],      ; permitted draft models
  rule:        uint,            ; acceptance rule (registry), fixed
  ? sampling:  sampling,
  m_max:       uint .le 64,     ; upper bound on M
  max_new:     uint,            ; maximum output tokens
  stop:        [* uint],        ; stop tokens
  low_rounds:  uint .ge 1,      ; R, escalation period
  ? low_ratio: uint .le 100,    ; percent, default 0
  fallback:    [+ ladder],      ; escalation ladder
  ? self_load: uint .le 100,    ; max verifier load for self-decode
  ? self_max:  uint,            ; max tokens per self-decode period
  ? scope:     bstr .size 16    ; KVSP Scope ID of cache objects
}
sampling = {
  ? temperature_milli: uint,    ; temperature x 1000
  ? top_k:             uint,
  ? top_p_milli:       uint .le 1000,
  ? seed:              uint
}
hash32 = bstr .size 32
action = a-continue / a-reduce / a-switch /
         a-self-decode / a-finish / a-fail
ladder = a-reduce / a-switch / a-self-decode / a-fail
a-continue    = 0
a-reduce      = 1
a-switch      = 2
a-self-decode = 3
a-finish      = 4
a-fail        = 5
</sourcecode>
        <t>The contract digest is the SHA-256 of the contract encoded with the
        core deterministic encoding of <xref target="RFC8949" section="4.2.1"/>,
        prefixed with a domain separator:</t>
        <artwork>
   contract_digest = SHA-256( "SDCP-CONTRACT-1" || 0x00 ||
                              deterministic_cbor(contract) )
</artwork>
        <t>The sampling profile defines the target distribution p used by
        the acceptance rule: p is the target model's next-token distribution
        after applying temperature, top-k, and top-p in that order; a
        temperature of zero selects the most probable token (ties broken in
        favor of the smallest token identifier).  An absent "drafters" member
        permits any draft model that the router's local policy allows.  The
        router can change the sampling profile at a round boundary
        (<xref target="policy"/>); such updates are carried separately from
        the contract, which, including the acceptance rule, is never
        modified.  The contract digest is computed once, over the contract as
        created.  A contract that contains a key not defined by this document
        <bcp14>MUST</bcp14> be rejected with problem type "sdcp-bad-contract", so that all
        parties compute the contract digest over the same content.</t>
      </section>

      <section anchor="digest">
        <name>Committed-Prefix Digest Chain</name>
        <t>The verifier maintains a digest over the committed prefix.  For a
        prompt of P tokens t[0..P-1] and committed output tokens o[1..n]:</t>
        <artwork>
   d[0] = SHA-256( "SDCP-PREFIX-1" || 0x00 ||
                   contract_digest || uint32(P) ||
                   uint32(t[0]) || ... || uint32(t[P-1]) )
   d[k] = SHA-256( d[k-1] || uint32(o[k]) )   for k = 1..n
</artwork>
        <t>uint32() is four octets in network byte order and SHA-256 is
        defined in <xref target="RFC6234"/>.  A proposal states the length n
        and digest d[n] of the prefix it extends.  Because d[n] depends on
        every committed token, a proposal built on a different or outdated
        prefix is detected without comparing token lists.</t>
      </section>
    </section>

    <section anchor="messages">
      <name>Messages and Resources</name>

      <section anchor="http">
        <name>HTTP Usage</name>
        <t>SDCP is an HTTP application following BCP 56
        <xref target="RFC9205"/>.  Each role has a base URI configured by the
        operator; SDCP defines no well-known URI.  HTTP/2
        <xref target="RFC9113"/> or HTTP/3 <xref target="RFC9114"/> over TLS
        1.3 <xref target="RFC8446"/> with mutual certificate authentication
        is <bcp14>REQUIRED</bcp14>.  Message bodies use the media type
        "application/sdcp+cbor".  Errors use Problem Details
        <xref target="RFC9457"/>; clients handle unlisted status codes by
        class <xref target="RFC9110"/>.</t>
        <table anchor="tbl-res">
          <name>SDCP Resources</name>
          <thead>
            <tr><th>Role</th><th>Method and Path</th><th>Body</th><th>Response</th></tr>
          </thead>
          <tbody>
            <tr><td>Verifier</td><td>POST sessions</td><td>session-open</td><td>session-state</td></tr>
            <tr><td>Verifier</td><td>PUT sessions/{id}/drafter</td><td>assignment</td><td>session-state</td></tr>
            <tr><td>Verifier</td><td>POST proposals</td><td>proposal</td><td>verdict</td></tr>
            <tr><td>Verifier</td><td>GET sessions/{id}/output?from=n</td><td>none</td><td>output</td></tr>
            <tr><td>Verifier</td><td>POST sessions/{id}/policy</td><td>policy</td><td>session-state</td></tr>
            <tr><td>Drafter</td><td>POST assignments</td><td>assignment</td><td>none (204)</td></tr>
            <tr><td>Router</td><td>PUT instances/{id}/status</td><td>status</td><td>none (204)</td></tr>
            <tr><td>Router</td><td>POST events</td><td>event</td><td>none (204)</td></tr>
          </tbody>
        </table>
        <t>{id} in session paths is the base64url encoding without padding
        <xref target="RFC4648"/> of the session identifier.</t>
      </section>

      <section anchor="cddl">
        <name>Message Definitions</name>
        <sourcecode type="cddl">
session-id = bstr .size 16
cache-ref  = tstr                       ; URI of an MLC object

session-open = {
  session: session-id, epoch: uint, contract: contract,
  prompt: [* uint] / cache-ref,         ; tokens or MLC reference
  ? prompt_kv: cache-ref,               ; target KV of the prompt
  commit_log: cache-ref,                ; durable commit records
  ? resume: {                           ; present on failover
    round: uint, committed: uint, digest: hash32,
    committed_tokens: cache-ref,
    ? target_kv: cache-ref
  }
}
session-state = {
  session: session-id, epoch: uint, round: uint,
  committed: uint, digest: hash32, ? state: uint
}
assignment = {
  session: session-id, epoch: uint, contract: contract,
  verifier: tstr,                       ; verifier base URI
  drafter: tstr,                        ; drafter base URI
  prompt: [* uint] / cache-ref,
  round: uint,                          ; last round with a verdict
  ? sampling: sampling,                 ; current profile, if updated
  committed: uint, digest: hash32,
  ? committed_tokens: cache-ref,        ; committed output so far
  m_init: uint
}
proposal = {
  session: session-id, epoch: uint, round: uint,
  drafter: tstr,                        ; drafter base URI
  base: uint, base_digest: hash32,
  tokens: [+ uint],                     ; M proposed tokens
  ? q_rows: cache-ref,                  ; draft rows, for rule 2
  ? draft_kv: cache-ref,
  status: status
}
verdict = {
  session: session-id, epoch: uint, round: uint,
  accepted: uint,                       ; a, 0 &lt;= a &lt;= M
  emitted: [* uint],                    ; tokens committed this round
  committed: uint, digest: hash32,      ; new n and d[n]
  action: action, m_cap: uint,
  low: uint,                            ; consecutive low rounds
  load: uint .le 100                    ; verifier load, percent
}
output = {
  session: session-id, epoch: uint, from: uint, tokens: [* uint],
  final: bool, ? finish: action
}
status = {
  instance: tstr, role: 1 / 2,          ; 1 drafter, 2 verifier
  load: uint .le 100, queue: uint,
  ? accept_milli: uint .le 1000,        ; EWMA of a/M x 1000
  ? cache_mbps: uint,                   ; available MLC bandwidth
  ttl_ms: uint
}
event = {
  session: session-id, epoch: uint,
  kind: action, committed: uint, digest: hash32
}
policy = { session: session-id, from_round: uint,
           sampling: sampling }
</sourcecode>
        <t>The contract, sampling, hash32, and action types are defined in
        <xref target="contract"/>.  Unknown map keys <bcp14>MUST</bcp14> be ignored, except
        in the contract (<xref target="contract"/>).  A receiver that
        encounters an unknown action value <bcp14>MUST</bcp14> treat it as "fail".</t>
        <t>The "q_rows" object holds, for each proposed position, the draft
        distribution from which the proposed token was sampled, as a row of V
        IEEE 754 binary32 values in little-endian order, where V is the
        vocabulary size; rows are concatenated in position order.  The
        drafter <bcp14>MUST</bcp14> sample each proposed token from exactly the row it
        publishes.</t>
      </section>
    </section>

    <section anchor="procedures">
      <name>Procedures</name>

      <section anchor="open">
        <name>Session Creation and Assignment</name>
        <t>The router selects a verifier and sends session-open with epoch 1
        and a commit_log reference in the MLC.  The verifier validates the
        contract (it <bcp14>MUST</bcp14> refuse a contract whose target digest does not match
        its model), computes or loads the KV cache of the prompt, computes
        d[0], and answers with session-state (round 0, committed 0).</t>
        <t>The router then selects a drafter whose model is permitted by the
        contract.  It first informs the verifier with PUT
        sessions/{id}/drafter, and then sends the assignment, carrying the
        current round, committed length, and digest, to the drafter.  The
        verifier accepts proposals only from the drafter named in the latest
        assignment it has received.  Drafter selection is a local policy
        based on the drafters' status reports, for example preferring
        drafters with low load and queue and high recent acceptance.  The
        router <bcp14>MUST NOT</bcp14> assign sessions to an instance whose status has
        expired.  Each instance reports status at intervals shorter than its
        ttl_ms.</t>
      </section>

      <section anchor="drafting">
        <name>Drafting and Proposal</name>
        <t>A drafter holding an assignment prepares its own KV cache for the
        committed prefix (by computation or by loading from the MLC) and
        generates M tokens, with 1 &lt;= M &lt;= min(m_max, m_cap), where
        m_cap is the limit from the last verdict (m_init before the first).
        It writes the draft artifacts the verifier may need to the MLC and
        holds leases on them until it receives the verdict of the round.  It
        then sends a proposal with base and base_digest equal to the
        committed length and digest it last learned, and round equal to the
        last verdict's round plus one.</t>
        <t>A drafter <bcp14>MUST NOT</bcp14> have more than one outstanding proposal per
        session.  It <bcp14>MAY</bcp14> prepare the next proposal speculatively, assuming
        full acceptance, but sends it only after the verdict confirms that
        assumption.</t>
        <t>Choice of M is local to the drafter.  The following rule is
        <bcp14>RECOMMENDED</bcp14>.  Let alpha be the drafter's exponentially weighted
        estimate of the per-token acceptance probability for the session,
        t_d the time to draft one token (including writing its artifacts at
        the cache bandwidth currently available), and t_v the expected
        verification time.  The expected number of tokens committed per
        round is (1 - alpha^(M+1)) / (1 - alpha) for alpha &lt; 1, and M + 1
        for alpha = 1 <xref target="LEVIATHAN"/>; the drafter chooses the M
        within its limits that maximizes that quantity divided by (M * t_d +
        t_v).  A loaded drafter thereby proposes fewer tokens, and a drafter
        whose cache bandwidth is scarce does the same.</t>
      </section>

      <section anchor="verification">
        <name>Verification and Commit</name>
        <t>On receiving a proposal, the verifier performs these steps:</t>
        <ol>
          <li>Authorization: the authenticated client <bcp14>MUST</bcp14> be the drafter
          named in the latest assignment the verifier received for the
          session; otherwise respond 403 with problem type
          "sdcp-not-assigned".</li>
          <li>Fencing: if epoch differs from the session epoch, respond 409
          with problem type "sdcp-stale-epoch".</li>
          <li>Idempotency: if a verdict for this round already exists, return
          it unchanged; if the round is being verified for an identical
          earlier request, wait for that verdict and return it.</li>
          <li>Base check: if base is not the committed length or base_digest
          is not d[base], respond 409 with problem type "sdcp-stale-base"
          and the current session-state, so that the drafter can
          resynchronize.  If round is not the last round plus one, respond
          409 likewise.</li>
          <li>Preconditions of the rule: if the acceptance rule needs draft
          probabilities, the verifier <bcp14>MUST</bcp14> have obtained the rows for every
          proposed position, and checked that q[i](x[i]) is not zero for every
          position, before drawing any random value.  If it cannot
          obtain them, it rejects the round with problem type
          "sdcp-q-unavailable" and commits nothing.  Obtaining them first is
          necessary because abandoning a round only after a rejection was
          observed would bias the output distribution.  The verifier <bcp14>MAY</bcp14>
          fetch the rows concurrently with scoring.</li>
          <li>Scoring: the verifier computes the target distributions
          p[1..M+1] for the positions following the committed prefix,
          normally by a single forward pass over the proposed tokens using the
          target KV cache of the committed prefix.  It <bcp14>MAY</bcp14> batch proposals of
          many sessions into one pass.</li>
          <li>Acceptance: it applies the contract's acceptance rule
          (<xref target="rules"/>), yielding a accepted tokens and one
          additional token.  It truncates the emitted tokens after the first
          stop token and at max_new.</li>
          <li>Commit: it appends the emitted tokens to the committed prefix,
          updates n and d[n], and appends a commit record (epoch, round,
          emitted tokens, n, and d[n]) to the session's commit_log
          (<xref target="commitlog"/>); only after that append succeeds does it
          send the verdict and make the tokens available as output.  If the
          append fails because the log has been fenced, the verifier <bcp14>MUST</bcp14>
          discard the round, release no output, and stop serving the
          session.  The commit and the recording of the verdict <bcp14>MUST</bcp14> be atomic
          with respect to concurrent proposals for the session.</li>
          <li>Control: it determines action and m_cap as specified in
          <xref target="control"/>.</li>
        </ol>
        <t>After the verdict, the drafter <bcp14>MUST</bcp14> discard its draft state for
        proposed positions beyond the accepted ones and <bcp14>MAY</bcp14> release its
        leases.  Its KV cache for the accepted tokens remains valid.  The
        verifier <bcp14>MAY</bcp14> publish the target KV cache of committed tokens to the
        MLC so that another verifier can take over the session.</t>
      </section>

      <section anchor="rules">
        <name>Acceptance Rules</name>
        <t>Rules are registered (<xref target="iana-rules"/>).  This document
        defines two.  In both, p[i] is the target distribution at proposed
        position i, x[i] the proposed token, and positions are evaluated in
        order.</t>
        <dl newline="true">
          <dt>Rule 1, greedy:</dt>
          <dd><t>x[i] is accepted if it equals argmax p[i], where ties are
          broken in favor of the smallest token identifier.  Evaluation stops
          at the first position that is not accepted.  The additional token is
          argmax p[a+1].  The output is identical to greedy decoding of the
          target model as computed by the verifier's scoring passes, whatever
          the drafter proposes.</t></dd>
          <dt>Rule 2, speculative sampling:</dt>
          <dd><t>For each position, draw r uniformly from [0, 1).  Accept x[i]
          if r &lt; min(1, p[i](x[i]) / q[i](x[i])), where q[i] is the row of
          q_rows for position i, that is, the draft distribution from which
          x[i] was sampled.  At the first rejected position, the additional
          token is drawn from the normalized residual distribution max(0, p[i]
          - q[i]).  If all M tokens are accepted, the additional token is drawn
          from p[M+1].  With exact q values, the output has the distribution
          of the target model <xref target="LEVIATHAN"/>
          <xref target="CHEN"/>.  The proposal <bcp14>MUST</bcp14> carry q_rows; a proposal
          for which q[i](x[i]) is zero is rejected, before any random draw,
          with problem type "sdcp-bad-proposal".</t>
          <t>The verifier's random values <bcp14>MUST</bcp14> be independent of those the
          drafter used.  When the sampling profile contains a seed, the
          verifier derives each value from HMAC-SHA-256
          <xref target="RFC2104"/> keyed with the seed (as eight octets in
          network byte order) over "SDCP-VERIFY-1" || 0x00 || session ||
          uint32(round) || uint32(i) || uint8(purpose), where purpose is 0 for
          the acceptance test and 1 for drawing the additional token, taking
          the first 53 bits of the result divided by 2^53.  Drafters <bcp14>MUST NOT</bcp14>
          use this derivation for their own sampling.  Without a seed, the
          verifier uses a cryptographically secure random number
          generator.</t></dd>
        </dl>
      </section>

      <section anchor="control">
        <name>Speculation Control and Escalation</name>

        <section anchor="mcap">
          <name>Speculation Limit</name>
          <t>Each verdict carries m_cap, the largest M the drafter may use in
          the next round, with 1 &lt;= m_cap &lt;= m_max.  The verifier lowers
          m_cap when its own load makes long proposals costly, and as
          specified for the "reduce" action below.  It <bcp14>SHOULD</bcp14> restore m_cap
          gradually (for example by one per round) when rounds are no longer
          low and its load permits.</t>
        </section>

        <section anchor="escalation">
          <name>Low Rounds and Escalation</name>
          <t>A round is low if 100 * a &lt; low_ratio * M, or, when low_ratio
          is zero or absent, if a = 0.  The verifier keeps three counters per
          session, all starting at zero: c, the number of consecutive low
          rounds; g, the number of consecutive rounds that are not low; and
          j, the position in the contract's fallback list.  After a low round,
          c is incremented and g reset; after a round that is not low, c is
          reset and g incremented, and when g reaches R, where R is
          low_rounds, j is reset to zero.  When c reaches R, the verifier applies entry j of
          the fallback list (skipping entries that are not permitted, as
          described for self_decode, and advancing j past every entry it
          applies or skips), then resets c to zero.  If no entry remains, it
          applies "fail".  Otherwise it applies "continue".  The fallback list
          <bcp14>MUST</bcp14> contain only the actions reduce, switch, self_decode, and fail;
          j persists across a change of drafter and across a self-decoding
          period.  The actions are:</t>
          <dl newline="false">
            <dt>continue (0):</dt><dd>The drafter proceeds with the next
            round.</dd>
            <dt>reduce (1):</dt><dd>The verifier sets m_cap to max(1,
            floor(m_cap / 2)) and the drafter proceeds.</dd>
            <dt>switch (2):</dt><dd>The verifier sends an event to the router,
            which assigns the session to another drafter with a permitted
            model; the current drafter <bcp14>MUST</bcp14> stop proposing for the
            session.</dd>
            <dt>self_decode (3):</dt><dd>The verifier decodes the session
            itself with the target model.  This action is permitted only if
            the contract contains self_load and the verifier's current load
            does not exceed it; otherwise the verifier skips it and applies
            the next entry of the fallback list.  Each token committed during
            self-decoding is recorded as a round of its own, with no proposal,
            so round numbers stay consecutive.  During self-decoding the
            verifier commits
            tokens one at a time, publishes them as output, and stops after
            self_max tokens (if present) or when its load exceeds self_load;
            it then sends an event so that the router assigns a drafter
            again.</dd>
            <dt>finish (4):</dt><dd>Generation has ended because of a stop
            token or max_new.</dd>
            <dt>fail (5):</dt><dd>The verifier ends the session with an
            error.</dd>
          </dl>
          <t>Because self_decode is conditional on the verifier's load, the
          same fallback list leads to self-decoding on a lightly loaded
          verifier and to the next entry, such as switch, on a busy one.</t>
        </section>
      </section>

      <section anchor="policy">
        <name>Sampling Policy Updates</name>
        <t>The router can change the sampling profile of a session, for
        example to follow a preference stated by the user.  It sends a policy
        message with from_round greater than the current round.  The verifier
        applies the new profile to rounds numbered from_round and later, and
        the router includes it in the "sampling" member of subsequent
        assignments; the contract in those assignments is unchanged.  The acceptance
        rule cannot be changed.  Committed output is never changed by a
        policy update.</t>
      </section>

      <section anchor="output">
        <name>Output Delivery</name>
        <t>Committed tokens are delivered with GET output?from=n, which
        returns the tokens committed at output indices n and later, waiting
        up to a server-chosen time if none are available.  Only tokens whose
        commit record has been written are returned.  Indices are stable and
        every output message carries the session epoch, so a front end that
        retries never duplicates or loses tokens, and a front end that
        receives output with a lower epoch than one it has seen discards it.
        The final output message has final set to true and finish set to
        "finish" or "fail".</t>
      </section>

      <section anchor="commitlog">
        <name>Commit Log</name>
        <t>The commit_log is an MLC object to which records are appended with a
        conditional operation, for example an HTTP PUT with If-Match on the
        current entity tag <xref target="RFC9110"/>, so that an append succeeds
        only if no other append has happened since the writer last read the
        log.  Each record carries the epoch of its writer.  A commit record
        appended by a verifier <bcp14>MUST</bcp14> carry the session's current epoch and
        follow the last record it wrote.  A fence record carries only an
        epoch; after a fence record with epoch E+1, appends carrying an epoch
        lower than E+1 <bcp14>MUST</bcp14> fail.  If the MLC cannot enforce this rule, the
        verifier <bcp14>MUST</bcp14> read the log after its conditional append and treat its
        append as failed if a fence record with a higher epoch precedes its
        own record.</t>
      </section>

      <section anchor="recovery">
        <name>Failure Handling and Recovery</name>
        <ul>
          <li>Drafter failure: when a drafter's status expires, the router
          reassigns its sessions.  The new drafter starts from the committed
          prefix in the assignment.  Proposals from the failed drafter are
          rejected because it is no longer the assigned drafter.</li>
          <li>Verifier failure: the router first appends a fence record with
          the new epoch to the commit_log, so that the old verifier, even if it
          is only partitioned, can no longer commit or release output; it
          then reads the last commit record and opens the session at a new
          verifier with that epoch and the "resume" member carrying that round,
          committed length, digest, and the target KV cache from the MLC if
          available.  It then informs the verifier of the drafter and sends a
          new assignment.  Proposals carrying an older epoch are rejected, and
          front ends discard output carrying an older epoch, so a recovered
          old verifier cannot extend the session.</li>
          <li>Lost messages: proposals and their verdicts are idempotent per
          round, so a drafter retries a proposal whose verdict it did not
          receive.</li>
        </ul>
      </section>
    </section>

    <section anchor="errors">
      <name>Error Handling</name>
      <table anchor="tbl-problems">
        <name>SDCP Problem Types</name>
        <thead>
          <tr><th>Type suffix</th><th>Status</th><th>Meaning</th></tr>
        </thead>
        <tbody>
          <tr><td>sdcp-stale-epoch</td><td>409</td><td>Epoch is not current</td></tr>
          <tr><td>sdcp-stale-base</td><td>409</td><td>Proposal does not extend the committed prefix</td></tr>
          <tr><td>sdcp-q-unavailable</td><td>409</td><td>Draft probabilities required by the rule are unavailable</td></tr>
          <tr><td>sdcp-bad-contract</td><td>422</td><td>Contract invalid or not supported</td></tr>
          <tr><td>sdcp-limit</td><td>422</td><td>Proposal violates m_cap or m_max</td></tr>
          <tr><td>sdcp-session-closed</td><td>410</td><td>Session has finished or failed</td></tr>
          <tr><td>sdcp-bad-proposal</td><td>422</td><td>Proposal inconsistent with its draft distributions</td></tr>
          <tr><td>sdcp-not-assigned</td><td>403</td><td>Drafter is not assigned to the session</td></tr>
        </tbody>
      </table>
      <t>The type URI is "https://iana.org/assignments/sdcp#" followed by the
      suffix.  These types are specific to SDCP and are therefore registered
      in an SDCP registry rather than in the "HTTP Problem Types" registry
      (<xref target="RFC9457" section="4.2"/>).  Problem details for "sdcp-stale-base" include
      the member "session_state" carrying the current committed length and
      digest.</t>
    </section>

    <section anchor="ops">
      <name>Operational Considerations</name>
      <ul>
        <li>Batch windows: a verifier that waits to fill a batch adds that
        wait to every round.  Windows of a fraction of the target model's
        forward-pass time are typical.</li>
        <li>Cache placement: draft artifacts are short-lived and <bcp14>SHOULD</bcp14> be
        placed in the fastest tier that both drafter and verifier can
        reach.</li>
        <li>Monitoring: implementations <bcp14>SHOULD</bcp14> report the mean accepted
        length, the distribution of M, escalation counts by action,
        stale-base rejections, and self-decoded tokens.</li>
        <li>Incremental deployment: a verifier can serve sessions without
        drafters by decoding itself, so SDCP can be introduced one drafter
        pool at a time.</li>
      </ul>
    </section>

    <section anchor="security">
      <name>Security Considerations</name>
      <t>All exchanges use mutual TLS, and every role authorizes requests by
      authenticated identity: only the router opens sessions and assigns
      drafters, and only the assigned drafter submits proposals.</t>
      <t>Integrity of output.  Under the greedy rule, the committed output
      depends only on the target model and the committed prefix; a malicious
      drafter can waste verifier capacity but cannot change the output.
      Under speculative sampling, the drafter supplies q, and a drafter that
      reports false probabilities can bias the output (for example, by
      reporting a small q for tokens it wants accepted).  Speculative
      sampling <bcp14>MUST</bcp14> therefore be used only with drafters that are trusted
      to the same degree as the verifier; with other drafters the greedy
      rule <bcp14>MUST</bcp14> be used.</t>
      <t>Denial of service.  Proposals cost a forward pass.  Verifiers <bcp14>MUST</bcp14>
      enforce m_cap and <bcp14>SHOULD</bcp14> rate-limit rounds per session and per
      drafter.  The escalation ladder also bounds the work a poorly matched
      or hostile drafter can cause.</t>
      <t>Cache objects.  References in proposals point to the MLC; the
      verifier <bcp14>MUST</bcp14> fetch them only from caches it trusts for the session's
      scope, so that a proposal cannot direct the verifier to arbitrary
      URIs.</t>
      <t>Privacy.  Prompts, KV caches, and outputs are user data.  The
      privacy considerations of <xref target="I-D.li-kvcache-efficient-storage"/>
      apply to all MLC objects of a session.</t>
    </section>

    <section anchor="iana">
      <name>IANA Considerations</name>
      <section anchor="iana-media">
        <name>Media Type</name>
        <t>IANA is requested to register the media type
        "application/sdcp+cbor" in the "Media Types" registry
        <xref target="RFC6838"/>: Type name: application; Subtype name:
        sdcp+cbor; Required parameters: N/A; Optional parameters: N/A;
        Encoding considerations: binary; Security considerations: see
        <xref target="security"/> of RFC XXXX; Interoperability
        considerations: none; Published specification: RFC XXXX;
        Applications that use this media type: distributed inference
        systems using speculative decoding; Fragment identifier
        considerations: the syntax and semantics of fragment identifiers
        specified for "application/cbor" apply; Additional information:
        Deprecated alias names for this type: N/A, Magic number(s): N/A,
        File extension(s): N/A, Macintosh file type code(s): N/A; Person and
        email address to contact: IETF &lt;iesg@ietf.org&gt;; Intended usage:
        COMMON; Restrictions on usage: none; Author: IETF; Change controller:
        IETF.</t>
      </section>
      <section anchor="iana-registries">
        <name>SDCP Registries</name>
        <t>IANA is requested to create a registry group named "Speculative
        Decoding Coordination Protocol (SDCP)" at
        "https://www.iana.org/assignments/sdcp" with the registries below.
        For the numeric registries, values 0-191 are assigned by
        Specification Required <xref target="RFC8126"/> and values 192-255
        are reserved for Private Use.  The designated experts should check
        that a new acceptance rule states whether it preserves the target
        distribution and what trust it requires in drafters.</t>
        <section anchor="iana-problems">
          <name>SDCP Problem Types</name>
          <t>Columns: Type Suffix, Title, Recommended HTTP Status Code,
          Reference.  The type URI is "https://iana.org/assignments/sdcp#"
          followed by the suffix.  Initial contents: the entries of
          <xref target="tbl-problems"/>, with reference RFC XXXX.  Policy:
          Specification Required.</t>
        </section>
        <section anchor="iana-rules">
          <name>SDCP Acceptance Rules</name>
          <t>Initial contents: 0 Reserved; 1 greedy; 2 speculative-sampling;
          each with reference RFC XXXX.  A registration <bcp14>MUST</bcp14> specify the
          acceptance test, the additional token, and the information a
          proposal must carry.</t>
        </section>
        <section anchor="iana-actions">
          <name>SDCP Actions</name>
          <t>Initial contents: 0 continue; 1 reduce; 2 switch; 3 self_decode;
          4 finish; 5 fail.</t>
        </section>
      </section>
    </section>
  </middle>

  <back>
    <references>
      <name>References</name>
      <references>
        <name>Normative References</name>
        <reference anchor="RFC2104" target="https://www.rfc-editor.org/info/rfc2104">
  <front>
    <title>HMAC: Keyed-Hashing for Message Authentication</title>
    <author fullname="H. Krawczyk" initials="H." surname="Krawczyk"/>
    <author fullname="M. Bellare" initials="M." surname="Bellare"/>
    <author fullname="R. Canetti" initials="R." surname="Canetti"/>
    <date month="February" year="1997"/>
    </front>
  <seriesInfo name="RFC" value="2104"/>
  <seriesInfo name="DOI" value="10.17487/RFC2104"/>
</reference>
        <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 month="March" year="1997"/>
    </front>
  <seriesInfo name="BCP" value="14"/>
  <seriesInfo name="RFC" value="2119"/>
  <seriesInfo name="DOI" value="10.17487/RFC2119"/>
</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 month="October" year="2006"/>
    </front>
  <seriesInfo name="RFC" value="4648"/>
  <seriesInfo name="DOI" value="10.17487/RFC4648"/>
</reference>
        <reference anchor="RFC6234" target="https://www.rfc-editor.org/info/rfc6234">
  <front>
    <title>US Secure Hash Algorithms (SHA and SHA-based HMAC and HKDF)</title>
    <author fullname="D. Eastlake 3rd" initials="D." surname="Eastlake 3rd"/>
    <author fullname="T. Hansen" initials="T." surname="Hansen"/>
    <date month="May" year="2011"/>
    </front>
  <seriesInfo name="RFC" value="6234"/>
  <seriesInfo name="DOI" value="10.17487/RFC6234"/>
</reference>
        <reference anchor="RFC6838" target="https://www.rfc-editor.org/info/rfc6838">
  <front>
    <title>Media Type Specifications and Registration Procedures</title>
    <author fullname="N. Freed" initials="N." surname="Freed"/>
    <author fullname="J. Klensin" initials="J." surname="Klensin"/>
    <author fullname="T. Hansen" initials="T." surname="Hansen"/>
    <date month="January" year="2013"/>
    </front>
  <seriesInfo name="BCP" value="13"/>
  <seriesInfo name="RFC" value="6838"/>
  <seriesInfo name="DOI" value="10.17487/RFC6838"/>
</reference>
        <reference anchor="RFC8126" target="https://www.rfc-editor.org/info/rfc8126">
  <front>
    <title>Guidelines for Writing an IANA Considerations Section in RFCs</title>
    <author fullname="M. Cotton" initials="M." surname="Cotton"/>
    <author fullname="B. Leiba" initials="B." surname="Leiba"/>
    <author fullname="T. Narten" initials="T." surname="Narten"/>
    <date month="June" year="2017"/>
    </front>
  <seriesInfo name="BCP" value="26"/>
  <seriesInfo name="RFC" value="8126"/>
  <seriesInfo name="DOI" value="10.17487/RFC8126"/>
</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 month="May" year="2017"/>
    </front>
  <seriesInfo name="BCP" value="14"/>
  <seriesInfo name="RFC" value="8174"/>
  <seriesInfo name="DOI" value="10.17487/RFC8174"/>
</reference>
        <reference anchor="RFC8446" target="https://www.rfc-editor.org/info/rfc8446">
  <front>
    <title>The Transport Layer Security (TLS) Protocol Version 1.3</title>
    <author fullname="E. Rescorla" initials="E." surname="Rescorla"/>
    <date month="August" year="2018"/>
    </front>
  <seriesInfo name="RFC" value="8446"/>
  <seriesInfo name="DOI" value="10.17487/RFC8446"/>
</reference>
        <reference anchor="RFC8610" target="https://www.rfc-editor.org/info/rfc8610">
  <front>
    <title>Concise Data Definition Language (CDDL): A Notational Convention to Express Concise Binary Object Representation (CBOR) and JSON Data Structures</title>
    <author fullname="H. Birkholz" initials="H." surname="Birkholz"/>
    <author fullname="C. Vigano" initials="C." surname="Vigano"/>
    <author fullname="C. Bormann" initials="C." surname="Bormann"/>
    <date month="June" year="2019"/>
    </front>
  <seriesInfo name="RFC" value="8610"/>
  <seriesInfo name="DOI" value="10.17487/RFC8610"/>
</reference>
        <reference anchor="RFC8949" target="https://www.rfc-editor.org/info/rfc8949">
  <front>
    <title>Concise Binary Object Representation (CBOR)</title>
    <author fullname="C. Bormann" initials="C." surname="Bormann"/>
    <author fullname="P. Hoffman" initials="P." surname="Hoffman"/>
    <date month="December" year="2020"/>
    </front>
  <seriesInfo name="STD" value="94"/>
  <seriesInfo name="RFC" value="8949"/>
  <seriesInfo name="DOI" value="10.17487/RFC8949"/>
</reference>
        <reference anchor="RFC9110" target="https://www.rfc-editor.org/info/rfc9110">
  <front>
    <title>HTTP Semantics</title>
    <author fullname="R. Fielding" initials="R." role="editor" surname="Fielding"/>
    <author fullname="M. Nottingham" initials="M." role="editor" surname="Nottingham"/>
    <author fullname="J. Reschke" initials="J." role="editor" surname="Reschke"/>
    <date month="June" year="2022"/>
    </front>
  <seriesInfo name="STD" value="97"/>
  <seriesInfo name="RFC" value="9110"/>
  <seriesInfo name="DOI" value="10.17487/RFC9110"/>
</reference>
        <reference anchor="RFC9113" target="https://www.rfc-editor.org/info/rfc9113">
  <front>
    <title>HTTP/2</title>
    <author fullname="M. Thomson" initials="M." role="editor" surname="Thomson"/>
    <author fullname="C. Benfield" initials="C." role="editor" surname="Benfield"/>
    <date month="June" year="2022"/>
    </front>
  <seriesInfo name="RFC" value="9113"/>
  <seriesInfo name="DOI" value="10.17487/RFC9113"/>
</reference>
        <reference anchor="RFC9114" target="https://www.rfc-editor.org/info/rfc9114">
  <front>
    <title>HTTP/3</title>
    <author fullname="M. Bishop" initials="M." role="editor" surname="Bishop"/>
    <date month="June" year="2022"/>
    </front>
  <seriesInfo name="RFC" value="9114"/>
  <seriesInfo name="DOI" value="10.17487/RFC9114"/>
</reference>
        <reference anchor="RFC9205" target="https://www.rfc-editor.org/info/rfc9205">
  <front>
    <title>Building Protocols with HTTP</title>
    <author fullname="M. Nottingham" initials="M." surname="Nottingham"/>
    <date month="June" year="2022"/>
    </front>
  <seriesInfo name="BCP" value="56"/>
  <seriesInfo name="RFC" value="9205"/>
  <seriesInfo name="DOI" value="10.17487/RFC9205"/>
</reference>
        <reference anchor="RFC9457" target="https://www.rfc-editor.org/info/rfc9457">
  <front>
    <title>Problem Details for HTTP APIs</title>
    <author fullname="M. Nottingham" initials="M." surname="Nottingham"/>
    <author fullname="E. Wilde" initials="E." surname="Wilde"/>
    <author fullname="S. Dalal" initials="S." surname="Dalal"/>
    <date month="July" year="2023"/>
    </front>
  <seriesInfo name="RFC" value="9457"/>
  <seriesInfo name="DOI" value="10.17487/RFC9457"/>
</reference>
      </references>
      <references>
        <name>Informative References</name>
        <reference anchor="I-D.li-kvcache-efficient-storage" target="https://datatracker.ietf.org/doc/html/draft-li-kvcache-efficient-storage-00">
          <front>
            <title>Key-Value (KV) Cache Storage Protocol (KVSP): Indexing, Placement, Prefetch, and Migration for Distributed Inference</title>
            <author initials="Z." surname="Li" fullname="Zhiqiang Li"/>
            <author initials="Z." surname="Du" fullname="Zongpeng Du"/>
            <author initials="J." surname="Wang" fullname="Junjie Wang"/>
            <author initials="W." surname="Cheng" fullname="Wei Cheng"/>
            <author initials="Y." surname="Zhao" fullname="Ying Zhao"/>
            <author initials="C." surname="Zhao" fullname="Chunhao Zhao"/>
            <author initials="X." surname="Sun" fullname="Xun Sun"/>
            <date year="2026" month="November" day="2"/>
          </front>
          <seriesInfo name="Internet-Draft" value="draft-li-kvcache-efficient-storage-00"/>
        </reference>
        <reference anchor="LEVIATHAN" target="https://proceedings.mlr.press/v202/leviathan23a.html">
          <front>
            <title>Fast Inference from Transformers via Speculative Decoding</title>
            <author initials="Y." surname="Leviathan" fullname="Yaniv Leviathan"/>
            <author initials="M." surname="Kalman" fullname="Matan Kalman"/>
            <author initials="Y." surname="Matias" fullname="Yossi Matias"/>
            <date year="2023" month="July"/>
          </front>
          <refcontent>Proceedings of the 40th International Conference on Machine Learning (ICML), PMLR 202</refcontent>
        </reference>
        <reference anchor="CHEN" target="https://arxiv.org/abs/2302.01318">
          <front>
            <title>Accelerating Large Language Model Decoding with Speculative Sampling</title>
            <author initials="C." surname="Chen" fullname="Charlie Chen"/>
            <author initials="S." surname="Borgeaud" fullname="Sebastian Borgeaud"/>
            <author initials="G." surname="Irving" fullname="Geoffrey Irving"/>
            <author initials="J.-B." surname="Lespiau" fullname="Jean-Baptiste Lespiau"/>
            <author initials="L." surname="Sifre" fullname="Laurent Sifre"/>
            <author initials="J." surname="Jumper" fullname="John Jumper"/>
            <date year="2023" month="February"/>
          </front>
          <refcontent>arXiv:2302.01318</refcontent>
        </reference>
        <reference anchor="DEEPSEEKV3" target="https://arxiv.org/abs/2412.19437">
          <front>
            <title>DeepSeek-V3 Technical Report</title>
            <author><organization>DeepSeek-AI</organization></author>
            <date year="2024" month="December"/>
          </front>
          <refcontent>arXiv:2412.19437</refcontent>
        </reference>
      </references>
    </references>

    <section anchor="vectors" numbered="true">
      <name>Test Vectors</name>
      <t>A contract with greedy rule, m_max 8, max_new 256, stop token 2,
      low_rounds 3, and fallback ladder [reduce, switch, self_decode, fail],
      with target and tokenizer digests equal to the KVSP test vector
      digests, has the following deterministic CBOR encoding (143
      octets):</t>
      <artwork>
a8 64 72 75 6c 65 01 64 73 74 6f 70 81 02 65 6d
5f 6d 61 78 08 66 74 61 72 67 65 74 58 20 25 4e
52 8c 66 9a 20 84 c9 72 72 98 ca cb 83 e8 85 4e
0a 6f f8 0e 2b f1 80 96 b9 dc e0 f7 eb da 67 6d
61 78 5f 6e 65 77 19 01 00 68 66 61 6c 6c 62 61
63 6b 84 01 02 03 05 69 74 6f 6b 65 6e 69 7a 65
72 58 20 9f 42 a7 a2 9d ca 30 63 ad 26 d7 be 7f
e6 a9 30 fa 38 af b1 a7 03 e4 f7 ff 53 8d b4 e1
33 b1 9c 6a 6c 6f 77 5f 72 6f 75 6e 64 73 03
</artwork>
      <t>For the prompt [1, 2, 3, 4] and committed output tokens 17 and 42:</t>
      <artwork>
contract_digest = bcae60a92c622b03fa1c229bac9f5654
                  076957e2f1a8bedcb3549ce4a6328e1f
d[0]            = 186b373698d5baf27716830811ffa641
                  4887dd0a4f9d13db6c00e19bdb57b76e
d[1]            = 3372e0fd91b77611c3502da5b0a5c8a5
                  1540e055d7abdd0d1bcf91110e142c1c
d[2]            = 469bbe77ceb5b1540a4d61d826a3117e
                  357e097c5ac20271306633559fccdf1f
</artwork>
      <t>Example round under the greedy rule: committed n = 2; the drafter
      proposes [7, 9, 11] (M = 3); the target argmax tokens at the three
      positions are 7, 9, and 13, and at the fourth position 5.  Then a = 2,
      the additional token is 13 (the correction at the first mismatch),
      emitted = [7, 9, 13], and the new committed length is 5.  The round is
      not low, so c is reset and the action is "continue".</t>
    </section>

    <section anchor="acknowledgments" numbered="false">
      <name>Acknowledgments</name>
      <t>The authors thank colleagues working on disaggregated inference
      serving for discussions on separating drafting from verification.</t>
    </section>
  </back>
</rfc>