2026/07/08 33.3k words

Transformer System #numinens#transformer#kv-cache#pagedattention#vllm#vattention#prefix-caching#radixattention#memory-management#serving

M5.3 - KV Memory Layout and Exact Reuse: PagedAttention, vAttention, and Prefix Caches

M5.3 - KV Memory Layout and Exact Reuse: PagedAttention, vAttention, and Prefix Caches

0x00 Historical Introduction And Owner Contract

M5.1 established that a K/V cache is persistent request state rather than an anonymous optimization tensor. M5.2 then made request membership an iteration-level decision:

observe immutable request frontiers
choose legal prefill intervals and decode rows
ask foreign subsystems whether the work is feasible
run one model iteration
publish completed service and cache progress
repeat

That loop still lacks a physical answer. A scheduler may estimate future K/V pressure and decide that a request should run, but those decisions do not create an address, reserve a real block, establish ownership, or prove that an old prefix is reusable.

The owner question is:

How does a serving runtime turn one logically continuous K/V sequence into versioned physical storage that can be allocated, shared, reused, mutated, and reclaimed exactly under concurrent requests?

M5.3’s thesis is that K/V memory efficiency is not only a tensor-size problem. It is an address, ownership, identity, index, and execution-reuse problem. PagedAttention, vAttention, prefix caching, RadixAttention, Prompt Cache, Hydragen, and ChunkAttention do not all solve the same one of those problems. The article will compare them only after naming the object and invariant each one owns.

0x00A From Rectangular Reservation To Dynamic Physical State

The simplest K/V implementation begins with an attractive invariant:

one request owns one contiguous tensor
the tensor has room for the request's maximum sequence length
token position t maps to a fixed stride from one base address

This layout makes addressing easy. If T_max,r token positions are reserved for request r, every layer knows where any possible future K/V row would live. The unresolved problem is that autoregressive serving does not know how many of those future rows will become useful.

request A may stop after 12 output tokens
request B may continue for 700
request C may arrive while both are running
request D may share 2,000 prompt tokens with A

The maximum length is an admission bound, not a realized allocation need. A rectangular reservation converts output uncertainty into held physical capacity. Requests finish at different iterations, contiguous holes appear in different sizes, and another request can be rejected even when the sum of free bytes looks sufficient. Related requests can also duplicate the same prefix state because their private rectangular ranges have no shared ownership object.

This is the historical transition recovered from A24: the K/V tensor formula alone does not explain serving capacity. The runtime also needs a memory manager whose allocation unit follows current committed state more closely than an uncertain maximum output.

PagedAttention, introduced by Kwon et al. with vLLM, borrows the operating system distinction between logical and physical memory. A request retains one logical token order, while a block table maps consecutive logical K/V blocks to physical blocks that need not be adjacent. New physical capacity can be acquired as the sequence grows, and physical blocks can be returned or shared without moving the entire logical sequence.

The analogy is useful but incomplete:

operating-system page table:
    virtual address -> physical frame

PagedAttention request block table:
    logical token block -> physical K/V block

additional serving obligations:
    valid-token tail
    per-layer or cache-group layout
    reference ownership
    copy-on-write before divergence
    compatibility identity before cross-request reuse
    kernel-visible translation metadata

vAttention later preserves a contiguous virtual K/V range and maps physical GPU pages on demand. It attacks the same reservation/fragmentation pressure with a different kernel boundary: PagedAttention exposes block indirection to a paged attention kernel, whereas vAttention tries to preserve ordinary contiguous virtual indexing. The detailed comparison belongs to Loop 8; the historical point is that dynamic physical commitment does not require one universal virtual layout.

Neither design, by itself, proves that two requests may share K/V. Paging answers where bytes live. Exact prefix reuse asks whether the bytes mean the same computation under the new request’s model, positions, transforms, adapter, representation, and isolation domain. Prefix indexes then ask how to find the longest matching reusable object. Hydragen and ChunkAttention add yet another question: can shared-prefix attention work be organized differently even when the mathematical output remains exact?

0x00B Five Contracts That Must Not Collapse

The phrase “K/V cache reuse” is too broad for implementation. This article uses five separate contracts:

ContractOwner questionExample mechanismWhat it does not prove
addressHow does logical token position resolve to storage?PagedAttention block table; vAttention virtual mappingthat another request may read the bytes
ownershipWho may read, append, fork, copy, release, or evict storage?refcounts, copy-on-write, allocator generationsemantic compatibility
identityAre old K/V rows exactly valid for this request?cache ABI/compatibility manifest and prefix keyhow a match is discovered or scheduled
indexHow is the longest reusable object found and protected?block-hash chain; RadixAttention treethat the scheduler should run the request now
execution reuseWhich compatible attention work is reused or shared?prefix hit, Prompt Cache, Hydragen, ChunkAttentiona universal speedup under every workload

These distinctions create four negative rules that remain active throughout the article:

allocation is not identity:
    owning a block does not make foreign K/V compatible

identity is not an index:
    a compatibility rule does not locate the longest match

an index hit is not a scheduling decision:
    M5.3 reports the hit; M5.2 decides when the request runs

storage reuse is not execution reuse:
    sharing bytes, skipping prefill, and batching shared-prefix attention
    are different savings with different baselines

All mechanisms in M5.3 are exact under their declared compatibility and algorithm contracts: they preserve the legal K/V history and attention result. Changing which old positions remain visible is a different operation owned by M5.4.

0x00C The Missing Object: KVPhysicalState

The article owns one conceptual object:

KVPhysicalState
    identity:
        allocator epoch
        request and publication generation
        logical cache ABI and compatibility namespace

    address state:
        cache groups
        logical-block or virtual-page mappings
        physical block/page handles
        valid-token tail

    ownership state:
        request references
        shared-prefix references
        mutable private tail
        cached, locked, and evictable state

    exact-reuse state:
        concrete prefix keys
        hash-chain or radix-index entries
        runtime-admissible reusable length

    transaction boundary:
        immutable prefix-match receipt
        immutable allocation/release receipt
        committed mutation or explicit failure

This is a teaching object, not a claim that vLLM, SGLang, or vAttention exposes one class with these fields. Later loops will map each field to paper contracts and pinned source observations, while keeping rewrite-derived safety fields explicitly labeled.

The direction of authority is:

M5.1 logical cache intent
    + M5.2 selected work and allocation intent
    + M5.7/M5.8/M8.6 declared cache representation
        -> M5.3 validates identity and mutates physical state
            -> PrefixMatchReceipt / AllocationReceipt / ReleaseResult
                -> M5.2 may make its next policy decision

The scheduler never turns intent into ownership by declaration. M5.3 publishes physical feasibility only after the allocator transaction commits.

0x00D Owner Contract: Consumes, Owns, And Defers

M5.1 logical cache state, M5.2 allocation intent, and declared cache representations enter M5.3; M5.3 owns versioned physical mappings, ownership, exact prefix identity, and immutable receipts while scheduling, lossy retention, tier movement, phase placement, and representation design remain separate owners

M5.3 may consume a fact without inheriting the mechanism that produced it. It may mention a downstream constraint without becoming that article’s owner.

SurfaceM5.3 relationshipAuthoritative owner
logical cache identity, request generation, committed frontier, append/fork/truncate/release intentconsumes factual state and mutation intentM5.1
selected token intervals, admission/preemption decision, future reservation intent, fairness, and SLO policyconsumes requests and returns feasibility; defers policyM5.2
logical-to-physical mapping, physical allocation, valid tails, references, COW, exact prefix identity, lookup index, and reclamationowns and derivesM5.3
online-softmax partial-state algebra and generic decode-kernel reductionconsumes exact merge/address interfaces; defers derivationM4.3 and M4.5
lossy retention, token visibility, merging, and approximation-quality policyrecords a foreign visibility contract but defers policyM5.4
offload, promotion, prefetch, retrieval, fallback, and tier transfermay publish an exact transferable object but defers movementM5.5
prefill/decode worker assignment, topology, remote directory, and inter-worker transfermay expose mapping/identity facts but defers placementM5.6
MHA/MQA/GQA and MLA cache representationparameterizes cache groups and ABI but defers architecture derivationM5.7 and M5.8
adapter routing, residency, and adapter-aware batching/kernel policyconsumes adapter identity only; defers serving mechanismM6.5
speculative candidates, acceptance, correction, and temporary branch algorithmmay allocate/fork temporary state but defers algorithmM7
K/V quantization, scales, calibration, kernels, and quality gatesconsumes a declared representation and byte profile; defers quantizationM8.6

This boundary permits M5.3 to derive a Hydragen or ChunkAttention merge schedule without re-owning online softmax. It permits a radix index to return a longest prefix hit without choosing service order. It permits an inactive session to have exact identity without explaining CPU, SSD, or remote transfer.

0x00E Source Continuity And Corrections

A24 and A25 provide the handwritten source spine. The reconstruction preserves their mechanism depth while tightening five shorthand statements:

Source-level shorthandM5.3 contract
”K/V cache memory is tokens * bytes_per_token”that is useful logical payload; physical capacity, tail waste, metadata, and unique shared blocks are separate ledgers
”PagedAttention is virtual memory for K/V”it is an analogy with a request block table, valid-tail, cache-group, ownership, and kernel-address contract that must be derived explicitly
”same prefix means cache hit”token equality is necessary but not sufficient; semantic compatibility, isolation namespace, concrete key, and runtime full/partial-block policy are separate
”RadixAttention schedules shared prefixes”the radix index publishes match and ownership facts; M5.2 owns service order and must preserve any theorem’s workload/capacity assumptions
”all prefix reuse avoids the same work”storage sharing, cached-prefill reuse, schema reuse, and shared-prefix execution are different contracts

The article will use primary papers for PagedAttention, vAttention, SGLang, Prompt Cache, Hydragen, ChunkAttention, and CachedAttention. Runtime claims are scoped to immutable source revisions: vLLM v0.23.0 at 0fc695fc6d1d82e9a5ac6835ac8e4e1c83703665, and the dereferenced SGLang v0.5.11 commit 612785ffdcaf35552f1ed433a981d596ca9fe900.

Those revisions are evidence anchors, not deployment recommendations. Paper speedups remain source-reported unless this repository later adds a declared hardware, workload, runtime, raw-sample, numerical-validation, and profiler manifest.

0x01 Claim Status And Scope

ClaimStatusEvidenceRewrite-safe wording
PagedAttention is an exact memory-layout mechanism.Source-local and externally verifiedA24 and PagedAttention/vLLM”It stores logical K/V blocks in non-contiguous physical memory; it does not drop K/V tokens.”
Block tables are the core address-translation object.Source-local and externally verifiedA24 and PagedAttention/vLLM”The kernel maps a request’s logical block index to a physical KV block before reading K/V.”
Refcount and copy-on-write enable exact sharing.Source-local and externally verifiedPagedAttention/vLLM”Shared prefix blocks can be read by multiple sequences; diverging writes require private blocks.”
vAttention solves a different layout problem from PagedAttention.Source-local and externally verifiedA24 and vAttention”It preserves contiguous virtual KV layout while allocating physical memory on demand.”
Automatic prefix caching is exact only under a strict contract.Source-local, externally verified, and rewrite interpretationvLLM APC docs, SGLang/RadixAttention”Same tokens are not enough; model, position, preprocessing, adapters, and cache semantics must match.”
RadixAttention indexes reusable prefixes.Source-local and externally verifiedA25 and SGLang”A radix tree maps token-prefix segments to cached K/V and supports lookup, insertion, and eviction.”
Address, ownership, identity, index, and execution reuse are separate contracts.Rewrite interpretation grounded in primary systemsM5.3 owner audit and the compared paper contracts”A valid physical mapping does not establish compatibility, and a compatible index hit does not choose service order.”
KVPhysicalState is the article’s conceptual owner object.Rewrite interpretationM5.1/M5.2 handoff and M5.3 evidence contract”It groups the versioned mapping, ownership, exact-reuse identity, index state, and allocator receipts without claiming one runtime class has that shape.”
A scheduler reservation intent is not a physical allocation.Rewrite interpretation with pinned runtime supportM5.2 owner contract and vLLM scheduler/KV-manager boundary”Only a committed allocator result establishes physical capacity and ownership.”
Exact prefix reuse includes multiple distinct savings.Source-local, externally verified, and rewrite interpretationA25, Prompt Cache, Hydragen, and ChunkAttention”Storage reuse, skipped prefill, and shared-prefix execution require separate baselines and mechanisms.”

The article’s main distinction:

layout:
    preserve all K/V, change where it lives

exact reuse:
    preserve all semantics, skip recomputing a prefix already known to match

lossy retention:
    change which old K/V remains visible

M5.3 covers the first two. M5.4 covers the third.

0x01A Immutable Cache ABI, Layout, Identity, And Isolation

Loop 1 separated address, ownership, identity, index, and execution reuse. The next question is mechanical:

Which immutable facts must match before a runtime may interpret old K/V bytes, place them in a physical map, or return them as an exact prefix hit?

“The tokens match” is not an adequate answer. The same token IDs can produce different K/V when weights, adapters, upstream transforms, side inputs, or positions differ. Equal byte counts can describe incompatible layouts. A correct block hash can still cross an administrative boundary if isolation is not enforced outside the hash table.

This article therefore uses five records with different writers:

RecordQuestionUpdate authority
M5.1 LogicalCacheABIWhat mathematical K/V row does this cache mean?model/artifact and logical serving configuration
M5.3 CacheLayoutManifestHow are those rows represented and addressable here?physical cache planner at engine initialization
M5.3 CacheCompatibilityManifestWhich semantic and physical facts must match for exact reuse?cache publication/admission boundary
runtime ConcretePrefixKeyWhich indexed candidate corresponds to this full token block?pinned prefix-cache implementation
deployment CacheIsolationNamespaceWhich administrative domain may discover and reuse the candidate?tenant/deployment control plane

These records are immutable for one published cache generation. Changing an owned field produces a successor identity; it does not mutate the meaning of already-published blocks in place.

A request first enters an authorized cache namespace, then passes semantic cache ABI and physical layout compatibility gates before a concrete full-block key may identify a candidate; fields omitted from the runtime key can still reject reuse, so only the final validated and referenced object yields a prefix-match receipt

The concrete key narrows the search. It does not replace semantic, physical, or isolation compatibility.

Consume M5.1’s Logical Cache ABI; Do Not Re-Derive It

M5.1 already derives the logical cache ABI from:

artifact identity:
    base weights
    active adapter set
    weight transforms

logical cache schema:
    K/V axes
    local head ownership
    storage representation

position contract:
    cache positions
    RoPE/position semantics
    legal visibility interpretation

It also separates exact token/side-input prefix identity from tokenizer and chat-template provenance. M5.3 consumes cache_abi_sha256 and the exact input identity. Repeating the full model-to-row derivation here would create two authorities for the same semantic object.

M5.3 adds a physical projection because one logical ABI can have more than one legal realization:

same logical K/V row
    -> contiguous rectangular allocation
    -> PagedAttention blocks
    -> vAttention virtual range plus mapped physical pages
    -> a tiered or quantized representation declared by another owner

Logical compatibility is necessary. Physical interpretability is an additional requirement.

CacheLayoutManifest: How The Bytes Can Be Addressed

The article-local layout record is:

CacheLayoutManifest
    schema_version
    manifest_id
    logical_cache_abi_sha256
    model_generation

    cache_groups[]:
        cache_group_id
        layer interval or explicit layer IDs
        K/V heads local to this shard
        head dimension
        storage dtype
        tensor axis order
        stride/layout identity

    physical_mode:
        rectangular | paged_blocks | virtual_pages

    token_block_size or physical_page_bytes
    scheduler_block_size
    hash_block_size
    tensor-parallel world size and rank
    quantization schema or none
    position-contract identity
    allocator revision

The manifest is not a block table. It freezes how to interpret every later block-table or page-map entry. For example:

same block_id + different cache_group_id:
    different physical K/V object

same byte count + different TP rank:
    different locally owned K/V heads

same scalar bytes + different dtype or quantization schema:
    different numerical interpretation

same token block size + different axis/stride identity:
    different address calculation

Later allocator loops will attach mutable physical handles to this immutable layout generation. They may recycle block IDs, but they may not reinterpret a live block under a different manifest.

CacheCompatibilityManifest: The Semantic Reuse Gate

The compatibility record combines the M5.1 facts with M5.3’s physical and administrative facts:

CacheCompatibilityManifest
    cache_abi_sha256
    cache_layout_sha256
    model_generation
    adapter_identity
    weight_transform_identity
    position_contract_sha256
    exact token IDs for the covered interval
    input-side-data identity
    cache-isolation namespace and generation
    cache salt
    publication generation

    provenance, recorded but not necessarily equality-bearing:
        tokenizer revision
        chat-template revision
        request ID
        sampling and stopping policy

The last group matters for audit and replay, but not every provenance field changes already-computed K/V. If two text-only requests have the same exact token IDs under the same cache ABI, a tokenizer-version label alone does not change those model inputs. Likewise, request ID, temperature, and stop strings govern ownership or future token choice; putting them in semantic compatibility would prohibit safe cross-request reuse.

The exclusion rule must not be inverted. A multimodal feature, prompt embedding, adapter, transform, or position change can alter hidden states or projected K/V without changing placeholder token IDs. Those identities are equality-bearing.

Conceptually:

def semantic_cache_compatible(producer, consumer):
    require_equal(producer.cache_abi_sha256, consumer.cache_abi_sha256)
    require_equal(producer.cache_layout_sha256, consumer.cache_layout_sha256)
    require_equal(producer.model_generation, consumer.model_generation)
    require_equal(producer.adapter_identity, consumer.adapter_identity)
    require_equal(producer.weight_transform_identity,
                  consumer.weight_transform_identity)
    require_equal(producer.position_contract_sha256,
                  consumer.position_contract_sha256)
    require_equal(producer.covered_token_ids, consumer.covered_token_ids)
    require_equal(producer.input_side_data_identity,
                  consumer.input_side_data_identity)
    require_equal(producer.cache_isolation_namespace,
                  consumer.cache_isolation_namespace)
    require_equal(producer.cache_salt, consumer.cache_salt)
    require_equal(producer.publication_generation,
                  consumer.publication_generation)
    return compatible

This is the article’s normative compatibility contract. It is not a verbatim vLLM or SGLang function.

ConcretePrefixKey: A Runtime Projection, Not The Whole Truth

An index needs a compact key. At pinned vLLM v0.23.0, the source-observed full-block projection is approximately:

block_hash = Hash(
    parent_block_hash,
    full_block_token_ids,
    extra_keys_or_none,
)

lookup_key = block_hash || cache_group_id

The observed extra-key generators include:

LoRA name
multimodal feature identifier and its offset relative to the block
cache salt on the first block
SHA-256 of prompt embeddings covered by the block

The implementation computes hashes only for full blocks in this path. It can use a hash granularity distinct from a cache group’s physical block size, and adds the cache-group ID to the lookup key. These are source observations at the named revision, not a universal prefix-cache schema.

Important semantic fields are not all literal inputs to every per-block hash:

Compatibility factIn the pinned block projection?How correctness can be enforced
parent prefix and exact full-block token IDsyeshash-chain ancestry
LoRA identityyes, by LoRA name in extra keysconcrete key plus admission policy
multimodal identity/positionyes, by identifier and relative offsetconcrete key plus side-input validation
prompt embeddingsyes, by per-block content hashconcrete key
cache isolation saltfirst block; inherited through parent hashnamespace/key ancestry
cache-group identityappended to lookup keyphysical group lookup
model generation and weight transformsnot necessarily repeated per blockprocess/cache generation and reset boundary
position contractnot necessarily a literal key fieldsemantic compatibility gate and namespace
dtype, shard, axis layout, quantization schemanot necessarily a literal key fieldCacheLayoutManifest and separate pools/namespaces

This creates a critical counterexample:

same parent hash + same block tokens + same concrete extras
    -> same concrete candidate key

different position contract or physical layout
    -> semantic compatibility rejects reuse

The hash table proposes a candidate. The compatibility and isolation records decide whether the candidate is legal to expose.

CacheIsolationNamespace: Reuse Is Also An Authorization Decision

Exact numerical compatibility does not grant cross-tenant authority. The namespace contract includes:

deployment or cluster cache namespace
tenant/isolation-domain identity
namespace generation
unguessable cache salt where supported
model/cache generation
publication policy

At the pinned vLLM revision, cache_salt is included in the first block’s extra keys; every descendant hash inherits that distinction through its parent hash. This is useful defense, but the deployment still owns authentication, salt issuance, namespace separation, and cache event exposure. A hash field is not a complete authorization system.

The legal order is:

1. enter the authorized cache namespace
2. validate logical ABI and physical layout generation
3. derive the concrete key and find a candidate
4. validate equality-bearing compatibility facts
5. lock/reference the physical object
6. return an immutable PrefixMatchReceipt

Lookup before authorization can leak whether another tenant used a prefix, even if bytes are never returned. Isolation therefore gates discovery, not only the final K/V read.

Source-To-Tensor Rejection Trace

Suppose producer and consumer have the same 16 token IDs. Four independent changes still make reuse illegal:

adapter mismatch:
    adapter changes hidden states or effective W_K/W_V
    -> K/V values differ

position-contract mismatch:
    the same hidden key row receives a different positional transform
    -> key semantics differ

TP-rank or cache-group mismatch:
    identical shape can name a different subset of K/V heads
    -> bytes have different ownership

storage-dtype or quantization-schema mismatch:
    identical raw bytes decode under a different numerical representation
    -> physical interpretation differs

Multimodal and prompt-embedding mismatches fail earlier in the input-to-hidden trace. Equal placeholder tokens do not imply equal side-input vectors.

Executable Compatibility And Negative Fixtures

The article-local Loop 2 oracle evaluates all candidates against one immutable producer manifest. Its expected distinctions are:

Candidate changeSemantic resultConcrete teaching-key relationReason
no changeacceptequalexact compatible block
request ID / sampling policy onlyacceptequalownership and future policy are excluded
tokenizer provenance only, exact IDs unchangedacceptequalprovenance explains input production but does not change the given IDs
adapter namerejectdifferentK/V-producing state and LoRA-name extra key differ
adapter revision under the same namerejectmay remain equalrevision is semantic state even when the runtime projects only the name
multimodal side inputrejectdifferenthidden input and concrete extra differ
cache saltrejectdifferent at the root chainfirst-block isolation extra differs
namespace identity or generation, salt unchangedrejectmay remain equalauthorization state is not necessarily a block-key field
publication generationrejectmay remain equalan old immutable publication cannot be relabeled as current
token IDrejectdifferentblock content differs
position contractrejectmay remain equalsemantic field is not guaranteed in the concrete key
dtype, quantization schema, TP rank, or cache group schemarejectmay remain equalphysical ABI differs outside the token hash
partial block in a full-block-only pathreject before lookupno keyruntime policy cannot publish that candidate

The checked artifact is generated by docs/numinens-evidence/m5-3-kv-layout-exact-reuse/cache_identity_oracle.py. It is a synthetic compatibility contract, not a replay of vLLM’s full cache manager and not a cache-hit-rate measurement. Its canonical-JSON SHA-256 is a teaching projection, not an exact runtime reproduction of vLLM’s serializer or in-memory key type.

Invalidation Produces A Successor Namespace

When model weights, adapters, transforms, position semantics, representation, or shard ownership change, the runtime must not relabel old blocks as new:

freeze old namespace for its still-live owners
stop publishing old entries to new lookups
advance model/cache/namespace generation
create a new layout and compatibility manifest
admit new requests only against the successor generation
reclaim old physical state after its legal references reach zero

Pinned vLLM exposes a prefix-cache reset path, including an RLHF-oriented weight-update use case. The article’s successor-namespace rule is broader and normative: reset, process replacement, separate pools, or generation-scoped directories are implementation choices as long as stale K/V cannot become a new-generation hit.

Loop 2 freezes identity and interpretation only. Loop 3 derives physical byte accounting; Loop 4 traces addresses; Loop 5 owns allocator mutation; Loop 6 deepens full/partial-block keys and the full-prompt-hit edge.

0x02 The Rectangular KV Mistake

M5.1 owns the logical K/V payload. M5.3 must turn that payload into a physical accounting convention before it can compare rectangular and paged allocators. Otherwise allocated_KV can silently mean useful rows, request capacity, unique blocks, or the entire provisioned pool.

0x02A Derive One Physical Row Before Counting Blocks

Let cache group contain cache-producing layers on this worker, locally owned K/V heads, head width , and stored scalar widths and bytes. One token contributes

key scalars and the same number of value scalars. Therefore the local bytes for one token in group are

and the worker-local row is

The familiar factor appears only when K and V use the same scalar width:

Renderer-safe contract:

B_row,g [bytes / token / local rank]
    = L_g * H_kv,g_local * d_h,g * (b_K,g + b_V,g)

B_row,rank [bytes / token / local rank]
    = sum_g B_row,g

This article’s Loop 2 layout has 32 layers, 4 local K/V heads, width 128, and two bytes per FP16 K or V scalar:

B_row,rank
    = 32 * 4 * 128 * (2 + 2)
    = 65,536 bytes
    = 64 KiB per token on one TP rank

With two disjoint K/V-head shards, the corresponding model-wide conceptual row is 128 KiB. That multiplication is valid for this declared even head partition. It is not a license to multiply arbitrary pipeline replicas, offloaded copies, or heterogeneous cache groups by world size.

0x02B Rectangular Reservation Is A Reference Ledger

For live requests , let be committed rows and be the contiguous capacity reserved for that request. Then

and

The subscript ref matters: if three requests reference the same exact prefix, their logical payload counts that prefix three times. It describes the three request views, not necessarily three physical copies.

Rectangular reservation couples admission to unknown future output length. Choosing a large makes the request expensive before those rows exist; choosing a small value risks growth, relocation, or rejection. This reservation slack is an additive byte quantity. External fragmentation is not: it depends on where free extents lie and on the size of the next contiguous request.

0x02C Paged Request Capacity Is Not Pool Capacity

For a token block size , request needs

block-table references. Counting every request independently gives

The request-view tail is

This is useful for block-table and no-sharing baselines. It is not unique physical memory when block IDs are shared.

A preallocated block pool has another ledger. If equal-sized blocks are physically provisioned, unique blocks are reachable, and remain reusable, then

Idle pool bytes are not fragmentation by themselves. They are provisioned capacity available to future allocations. A deployment may reserve most free device memory for the K/V pool at startup even while only a subset of its blocks is owned by current requests.

0x02D Sharing Requires A Unique-Physical Ledger

Let be the physical block IDs referenced by request and

Request references and unique physical objects are therefore

If unique physical block contains initialized token rows, then

and

Two different savings ledgers now become visible:

logical payload deduplicated
    = M_logical,ref - M_materialized,unique

request-reference capacity avoided by sharing
    = M_paged,ref - M_capacity,unique

They need not be equal. A shorter request can reference only nine visible rows of a block that a longer request has fully materialized. Its request view has seven unused slots, but those seven slots are not unique physical tail waste: they contain valid rows owned by the longer exact-prefix view.

0x02E Metadata Is Parameterized, Located, And Separate

K/V payload dominates many configurations, but a complete allocator ledger also names its indexing and ownership records. With record sizes in bytes per record:

M_meta [bytes]
    = I_map  [bytes / map entry]  * N_request_block_refs [entries]
    + I_desc [bytes / descriptor] * N_pool_blocks [descriptors]
    + I_hash [bytes / hash entry] * N_cached_hashes [entries]
    + I_tail [bytes / request]    * N_live_requests [requests]
    + I_free [bytes / queue item] * N_free_blocks [items]
    + M_fixed [bytes]

The formula is dimensional; the constants are not universal. A Python object, a packed C++ descriptor, a GPU integer block table, and a hash-map entry have different sizes and may live in different address spaces. The Loop 3 fixture’s 482 bytes is deliberately synthetic and placement-unspecified. It validates counting, not vLLM object size or measured GPU use.

0x02F Fragmentation Is A Taxonomy, Not One Subtraction

QuantityDerivable from lengths and mappings?Additive byte ledger?Meaning
rectangular reservation slackyesyesreserved request rows not yet useful
paged request-view tailyesyes, only in the reference baselineunused logical view slots
unique physical tailyes, with unique block stateyesuninitialized capacity in reachable physical blocks
idle pool capacityyes, with pool stateyesreusable provisioned blocks, not necessarily waste
metadataonly with record counts and sizesyes within a declared address spacetables, descriptors, hashes, queues, fixed state
external fragmentationno, needs allocator extents and a candidate sizeno universal additive valueenough total free bytes may exist without one usable extent
duplicate prefix storageonly with sharing identityyes relative to a declared no-sharing baselinerepeated physical materialization of equal rows

A synthetic contiguous arena makes the external case concrete:

arena             = 12 MiB
allocated extents =  9 MiB
free extents      = [1 MiB, 2 MiB]
candidate         =  2.5 MiB contiguous

total free        = 3 MiB
largest free      = 2 MiB
contiguous result = reject

The descriptive ratio

is 1/3 for that snapshot. It is not another 1 MiB to add to reservation slack. Under the synthetic 1 MiB block pool, the same candidate needs three blocks; five interchangeable free blocks can satisfy it without contiguity. The ratio is defined only when M_total_free > 0. A full arena has no free extent distribution to summarize, so the implementation reports the ratio as not_applicable rather than dividing by zero or silently assigning a perfect fragmentation score.

0x02G Expected Tail Waste Needs A Distribution

Let terminal occupancy be uniform on . Unused slots are , so

Thus

For P=16 and B_row=64 KiB, that is 7.5 slots = 480 KiB per independent terminal block. The fixture observes 15 unique tail slots because its longest request ends one row into a block. An expectation under a uniform offset model is not a prediction for that trace. Real prompt/output length histograms, alignment rules, prefix sharing, and partial-block publication all change the distribution.

Three nested-prefix requests have 74 logical token references and 144 rectangular reservation slots; paging reduces their request-view capacity to 96 slots, exact sharing collapses six block references into three unique blocks with 48 physical slots, and an eight-block provisioned pool separates three live blocks from five reusable free blocks while metadata remains a separate parameterized ledger

Reference views, unique physical objects, and the provisioned pool answer different capacity questions. None may silently replace another.

That distinction explains four failures of coarse contiguous allocation:

  • internal reservation slack: a request reserves more rows than it uses;
  • external fragmentation: free memory exists but not in a useful contiguous shape;
  • over-reservation: uncertain future lengths consume admission capacity early;
  • duplication: related sequences materialize identical prefix K/V separately.

The PagedAttention paper frames this as the serving bottleneck: KV cache is huge, dynamic, and waste-prone; inefficient management limits batch size. The paper reports that existing systems in its experiments used only a fraction of KV-cache memory for actual token states, with the rest lost to reserved, internal, or external waste.

PagedAttention paper measurement separating useful token-state memory from reservation, internal fragmentation, and external fragmentation

Source: Efficient Memory Management for Large Language Model Serving with PagedAttention, Figure 2. In the paper’s experiment, the three Orca allocation variants devote only 20.4%-38.2% of KV memory to token states, while vLLM reports 96.3%. Those percentages are workload- and implementation-specific; the durable result is that allocation policy can dominate the gap between live payload and reserved memory.

The green region is the payload the model actually needs. Orange, red, and gray are different allocator losses. This is why the next mechanism figure is not merely an operating-system analogy: it addresses measured serving capacity that the tensor payload formula alone misses.

PagedAttention paper example of reserved slots, internal fragmentation, and external fragmentation in contiguous KV-cache allocation

Source: Efficient Memory Management for Large Language Model Serving with PagedAttention, Figure 3. The slot counts are the paper’s illustrative requests; the reusable distinction is among reserved future capacity, unusable space inside allocations, and holes between allocations.

The figure’s categories form the paper’s measured or illustrated allocator breakdown. In a local analytical ledger, reservation slack and unique block tail have direct byte identities; external holes require an allocator snapshot and candidate extent. Treating all three as reserved - useful would double count different mechanisms.

0x03 PagedAttention: Logical Blocks, Physical Blocks

PagedAttention borrows the virtual-memory idea, but “physical block 7” is not yet an address. A complete read names a request snapshot, cache group, model layer, K or V tensor, local K/V head, token position, and head-dimension lane. The block table resolves only one step in that chain.

logical K/V coordinate:
    (request snapshot, token position, model layer, K/V, local head, lane)

physical read coordinate:
    (cache group, pool identity, pool generation, physical block,
     physical slot, layer-local index, token offset, K/V base, head, lane)

This distinction is not ornamental. Treating a block number as a byte address can select the wrong cache group, wrong pool generation, wrong layer stride, or wrong K/V base while remaining numerically in bounds.

0x03A Logical Order And Physical Identity

The first abstraction is still simple:

logical token order:
    block 0, block 1, block 2, ...

physical storage:
    block 17, block 04, block 22, ...

The request still has a normal ordered sequence. The allocator no longer has to find one large contiguous range. However, a reusable physical identity must be scoped more strongly than an integer:

PhysicalRef_g =
    (cache_group_id, pool_id, pool_generation, physical_block_id)

The group says which layers and representation the block belongs to. The pool and generation prevent a stale block ID from silently naming a recycled object. The physical block ID names ownership inside that namespace. A later descriptor resolves it to a current pool slot.

PagedAttention block tables preserve request-local logical order while mapping to non-contiguous physical KV blocks

The paper’s worked translation shows the actual metadata boundary more precisely. Logical blocks preserve token order, each block-table entry names a physical block, and the # filled field records the valid tail length. The example also shows why a kernel cannot derive an address from token_pos alone: logical block 0 maps to physical block 7 while logical block 1 maps to physical block 1.

PagedAttention paper example translating logical KV blocks through a block table into non-contiguous physical GPU blocks

Source: Kwon et al., PagedAttention, Figure 6. The prompt, generated tokens, block size, and physical block IDs are illustrative. The durable contract is the logical-block, physical-block, and valid-tail translation that the attention kernel must follow.

The paper establishes logical-to-physical block translation. The following two-group byte-address trace is a synthetic Transformer System contract, not a claim about the paper’s tensor strides or one production backend.

0x03B Block Maps Are Cache-Group State

The Loop 4 fixture refines each all-layer block in Loop 3 into one physical block per cache group. It deliberately uses two non-identical groups:

GroupModel layersLocal K/V headsAxis order after K/V baseRow bytes16-token block bytes
g0[0,24)4[physical_slot, layer_local, head, token_offset, dim]48 KiB768 KiB
g1[24,32)4[layer_local, physical_slot, token_offset, head, dim]16 KiB256 KiB

Their storage still reconciles exactly to Loop 3:

row bytes on rank 0       = 48 KiB + 16 KiB = 64 KiB/token
16-token block bundle     = 768 KiB + 256 KiB = 1 MiB

The Loop 3 1 MiB physical block was therefore an accounting bundle across cache groups, not a promise that every layer occupies one contiguous extent. With g1’s layer-major layout, one allocator block slot is strided across layers.

For base request A, the group tables are:

Logical blockTokensLoop 3 bundleg0 physical ID -> slotg1 physical ID -> slot
00..151001000 -> 72000 -> 1
116..311011001 -> 22001 -> 6
2321021002 -> 52002 -> 3

Each request snapshot carries one table per cache group. In this fixture all groups use P=16, so the tables have the same number of logical rows. That is a fixture choice, not a universal K/V-cache law. A runtime supporting group-specific block sizes needs group-specific quotient/remainder arithmetic.

At pinned vLLM v0.23.0, the source keeps a list of block tables and computes slot mappings per K/V cache group. Its CPU and GPU implementations also carry group-specific block sizes, table pointers, and table strides. Those are pinned source observations. The exact tensor axis orders and base addresses in this section remain synthetic.

0x03C Token Position To Group Table Entry

Let model layer resolve to exactly one cache group . Define its group-local layer index:

For group block size , logical token position becomes:

The request’s versioned group table resolves logical block :

g       = unique cache group containing model_layer
layer_g = model_layer - group.layer_start
j_g     = token_position // group.block_size
o_g     = token_position % group.block_size
p_g     = request.block_tables[g][j_g] at table version v

The lookup is legal only after checking:

0 <= token_position < request.context_length
0 <= j_g < len(request.block_tables[g])
PhysicalRef_g exists in the named pool generation
o_g < descriptor.valid_rows

The first bound is request visibility. The final bound is physical materialization. They are separate contracts, especially under sharing.

0x03D A Slot ID Is Not A Byte Address

Many runtimes flatten a block slot and in-block offset into a token-slot ID:

slot_id = physical_slot * block_size + token_offset

Pinned vLLM v0.23.0 contains this shape in its block-table slot-mapping helpers, with additional context-parallel handling in the pinned source. The slot ID answers which token row in a group pool. It does not yet answer which layer, K or V tensor, local head, dimension lane, dtype, or byte base to read. Calling slot_id a GPU address erases the backend ABI.

0x03E Axis Order Produces Strides, Then Bytes

For one K or V tensor in group , let the declared axis order have dimensions . Under a row-major teaching layout, element strides are derived from the dimensions to the right:

For coordinate vector , the element and byte offsets are:

Finally, with separate K and V bases:

stride[a]       = product(shape[b] for b > a)
element_offset  = sum(coordinate[a] * stride[a])
byte_offset     = scalar_bytes * element_offset
byte_address    = base_address[K_or_V] + byte_offset

An interleaved K/V layout would add a kv_kind axis instead. A packed or vectorized backend could use different strides. The formula stays valid only after the layout manifest supplies the actual dimensions and axis order.

0x03F One Complete Checked Address

Trace request A at token t=16, model layer 24, K head 1, dimension 5:

1. layer 24 selects g1, whose layer range is [24,32)
2. layer_local = 24 - 24 = 0
3. logical_block = 16 // 16 = 1
4. token_offset  = 16 % 16 = 0
5. A.g1.table[v=5][1] -> physical block 2001
6. descriptor(2001) -> pool generation 7, physical slot 6, valid_rows 16
7. slot_id = 6 * 16 + 0 = 96
8. g1 K shape = [8 layers, 8 slots, 16 tokens, 4 heads, 128 dims]
9. g1 strides = [65536, 8192, 512, 128, 1] elements
10. coordinate = [0, 6, 0, 1, 5]

Therefore:

element_offset = 49,285
byte_offset    = 98,570
K base         = 4,311,744,512
byte address   = 4,311,843,082

The checked output also proves slot_id=96 and byte_address=4,311,843,082 are different quantities.

A logical K/V coordinate for request A token 16 and layer 24 selects cache group one, divides the token into logical block one and offset zero, resolves physical block 2001 and pool slot six through group-specific block table version five, derives slot ID 96, then applies the group-one K tensor shape and strides to produce byte address 4311843082; a parallel cache-group panel shows why group zero uses a different table, pool, and axis order

0x03G Request Visibility Dominates Shared Physical Capacity

Request B contains 25 visible tokens and shares bundle 101 with longer request A. In g1, token 24 resolves to logical block 1, offset 8, physical block 2001. That physical block has 16 committed rows because A materialized tokens 16 through 31. B may still read only offsets 0 through 8:

B context length                  = 25
B last-block visible rows         = 9
shared physical block valid rows  = 16

token 24 -> offset 8  -> legal for B
token 25 -> offset 9  -> reject: outside B's logical context

Checking only offset < physical.valid_rows would leak later rows from A into B’s attention history. The safe order is:

request visibility -> table bounds -> physical identity -> physical validity

The reverse failure also matters: if the request says a row is visible but the physical descriptor has not committed it, the read must fail rather than consume stale or uninitialized bytes.

0x03H Crossing A Block Boundary Consumes A Published Successor

Request C initially has 16 tokens and one block per group at table version 2. Appending token 16 crosses the P=16 boundary. Loop 4 does not allocate or publish blocks; Loop 5 owns that transaction. Instead, this trace consumes an already-published successor snapshot:

StateContextTable versiong0 tableg1 table
predecessor C162[1000][2000]
published successor173[1000,1003][2000,2003]

For the new token:

logical block = 16 // 16 = 1
token offset  = 16 % 16 = 0

g0: physical block 1003 -> slot 0 -> slot_id 0
g1: physical block 2003 -> slot 4 -> slot_id 64

The table version must change atomically with the published mapping and valid row state. How reservation, copy-on-write, commit, and rollback produce that successor belongs to Loop 5.

0x03I Reference Translator And Rejection Order

def resolve_kv_address(snapshot, request_id, token, layer, kind, head, lane):
    request = snapshot.requests[request_id]
    assert 0 <= token < request.context_length

    group = unique_group_containing(layer)
    layer_local = layer - group.layer_start
    logical_block = token // group.block_size
    token_offset = token % group.block_size

    table = request.block_tables_by_group[group.id]
    assert logical_block < len(table)
    physical_id = table[logical_block]

    desc = group.descriptor(
        pool_id=group.pool_id,
        pool_generation=group.pool_generation,
        physical_block_id=physical_id,
    )
    assert token_offset < desc.valid_rows
    assert 0 <= head < group.kv_heads_local
    assert 0 <= lane < group.head_dim

    slot_id = desc.physical_slot * group.block_size + token_offset
    coordinate = {
        "physical_slot": desc.physical_slot,
        "layer_local": layer_local,
        "kv_head_local": head,
        "token_offset": token_offset,
        "head_dim": lane,
    }
    element_offset = dot(
        reorder(coordinate, group.axis_order),
        row_major_strides(group.shape),
    )
    byte_address = group.base[kind] + group.scalar_bytes * element_offset
    assert group.base[kind] <= byte_address < group.end[kind]
    return slot_id, byte_address

This oracle rejects layer gaps, duplicate axes, table-length drift, unknown or stale physical identities, slot reuse, cross-group bundle mismatch, invalid tails, out-of-range coordinates, overlapping tensor ranges, stale successor versions, and frozen-address drift.

0x03J Layout Choices Change The Translator

ChoiceAddress consequenceWhat this article requires
one dense table per groupfixed row stride and sentinel/capacity entriesgroup ID, request row, table version, legal logical length
CSR/ragged block liststable row becomes indices[indptr[r]+j]immutable request ordering and segment bounds
block-major tensorone physical slot may own contiguous layer extentsexact block/layer/head/token/dim strides
layer-major tensorone allocator block is strided across layer tensorsdo not equate block capacity with one contiguous extent
separate K and Vtwo base addresses, no K/V axiskind-specific base and range
interleaved K/Vone base plus K/V axiskind stride in the manifest
contiguous virtual K/Vordinary virtual offset; OS/GPU page tables map backing storagevirtual reservation and page-commit contract, deepened in the vAttention loop
gathered compact viewread translator feeds a temporary contiguous tensorgather ownership, traffic, and synchronization must be measured

M4.3 owns the generic online-softmax state and exact merge proof. M4.5 owns decode-kernel layouts, split planning, vectorization, and backend selection. M5.3 owns the storage map and the immutable metadata that lets a selected backend find exact K/V rows. Loop 4 therefore proves the address, not that any one axis order is fastest.

The durable invariants are:

Logical token order is contiguous.
Physical KV blocks need not be contiguous.
Block tables are cache-group and request-snapshot state.
Physical identities are scoped by pool and generation.
Request visibility is stricter than shared physical validity.
A slot ID is not a byte address.
Byte arithmetic is legal only under the declared axis/stride ABI.

The address trace consumes Loop 3’s accounting rather than redefining it:

one physical block [bytes / local rank]
    = P [tokens / block] * B_row [bytes / token / local rank]

live unique capacity
    = N_unique * P * B_row

provisioned pool capacity
    = N_pool * P * B_row

The maximum unique tail in one reachable partial block is (P - 1) * B_row. Summing that bound once per request is valid only for an unshared request-view baseline; shared mappings require the union of physical block IDs.

0x04 Allocator Lifecycle: Ownership Is A Transaction

Loop 4 consumed an immutable predecessor map and an immutable successor map. The allocator’s job is to create that successor without exposing any half-mutated state. That is a stronger requirement than “pop a block from a free list.”

For one logical mutation, the allocator may have to coordinate:

request generation and table version
cache-group-specific physical handles
physical generations and valid-row frontiers
strong references and temporary leases
weak cache-index identity
free / eviction queue membership
copy completion
successor publication
rollback or compensating repair

The scheduler in M5.2 supplies intent and budgets. M5.3 decides whether the physical transition commits and returns an immutable receipt. A scheduler decision is not ownership until this transaction succeeds.

0x04A Committed State And Transaction State Are Different Axes

The article uses these derived teaching states:

Derived stateStrong refsCache keyFree queueMeaning
FREE0noyesreusable storage with no reusable identity
EVICTABLE0yesyescached bytes that may be reclaimed for allocation
LIVE_PRIVATE1nonoone request owns the block
LIVE_SHARED>1nonoseveral request maps reach the block
CACHED_PRIVATE1yesnolive owner plus reusable full-block identity
CACHED_SHARED>1yesnoshared live block plus reusable identity

RESERVED, COPYING, and READY_TO_PUBLISH are transaction phases, not committed ownership states. An unpublished block must never be reachable from a request map.

This taxonomy is Rewrite interpretation. Pinned vLLM v0.23.0 exposes a narrower KVCacheBlock: block_id, ref_cnt, an optional full-block hash, free-queue links, and a null-block flag. Its free queue contains both unused blocks and zero-ref cached eviction candidates. It does not expose the generation and lease fields used by the stronger teaching protocol below.

0x04B Derive Refcounts From Reachability

Let be committed request maps and active leases. For a generation-fenced handle :

Renderer-safe form:

refcount(handle)
    = committed request-map references
    + active read/write leases

The Loop 5 model treats a cache-index entry as a weak identity reference. It does not increase refcount. Therefore:

refcount == 0 and cache_key is None  -> FREE
refcount == 0 and cache_key exists   -> EVICTABLE

This matches the important shape of pinned vLLM’s behavior: free_blocks returns zero-ref blocks to the free queue without necessarily deleting their hash, while allocating such a block evicts the old cached identity before reuse.

The invariant is not “every cached block has a positive refcount.” It is:

and every committed request-reachable handle has .

0x04C The Operation Set

The state machine needs more than allocate and free:

OperationPhysical effectPublication effect
allocatereserve one block bundle across cache groupscreate a new request map
appendwrite a private tail, allocate a boundary bundle, or COW a shared tailadvance logical length and table version
forkincrement refs on an immutable mapping snapshotpublish a new request map
touchretain cached full blocks; remove zero-ref hits from the free queuepublish a request map over the hit
cacheattach identity only to complete eligible blockspublish cache-index entries
copy_on_writereserve destinations, copy valid rows, append new rowreplace one request’s tail bundle
truncaterelease only suffix mappingspublish a shorter successor map
cancelrelease all request references after cancellationremove request map with a cancellation receipt
releasedecrement request ownership; zero-ref blocks enter free/eviction orderremove a finished request map
evictremove weak cached identitydoes not revoke live request ownership
rollbackreturn unpublished reservations and leasespreserve the exact committed predecessor

The PagedAttention paper’s implementation discussion reduces decoding algorithms to fork, append, and free, then uses a fused block-copy kernel for COW copies. The table above is a systems expansion around that paper contract: it names cache publication, rollback, stale generations, and multi-group atomicity explicitly.

0x04D Transaction And Receipt

@dataclass(frozen=True)
class AllocationTxn:
    transaction_id: str
    expected_allocator_epoch: int
    request_id: str
    expected_request_generation: int
    expected_table_version: int
    operation: str
    touched_handles: tuple[PhysicalBlockHandle, ...]
    reserved_handles: tuple[PhysicalBlockHandle, ...]
    publication_state: str

@dataclass(frozen=True)
class AllocationReceipt:
    transaction_id: str
    predecessor_digest: str
    successor_digest: str
    useful_new_rows: int
    new_physical_blocks: int
    copied_rows: int
    copy_payload_bytes: int
    refcount_deltas: tuple
    allocator_epoch_after: int
    outcome: str

The receipt records physical fact, not policy intent. M5.2 may consume outcome, available capacity, and retry information; it still owns admission, preemption, fairness, and service order.

0x04E Append Has Three Physical Paths

For token position , block size , logical block , and offset :

o == 0
    -> reserve a new bundle, write row 0, publish one new table entry per group

o > 0 and every tail handle has one strong owner
    -> acquire a unique writer, write row o, publish valid_rows=o+1

o > 0 and the tail bundle is shared
    -> copy-on-write the bundle, append row o, then publish replacement handles

For cache groups , the new physical capacity at a boundary is:

The Loop 5 fixture keeps and reuses Loop 3’s row split:

group 0 row = 48 KiB
group 1 row = 16 KiB
bundle row   = 64 KiB
bundle block = 16 * 64 KiB = 1 MiB

The groups have separate pools and handles. Publishing only group 0 is not a smaller success; it is an invalid half-bundle successor.

0x04F Rollback Has A Boundary

Let be the committed predecessor and the successor. Before publication, a failed transaction must satisfy:

Renderer-safe form:

before publication:
    rollback must restore the exact predecessor digest

after publication:
    do not erase history with rollback
    publish a compensating successor transaction instead

The checked trace injects failure after reserving the group-0 destination but before reserving group 1. It returns the reservation, publishes no request, does not increment allocator epoch 43, and reproduces the predecessor state hash exactly.

0x04G Source-Observed Runtime Versus Normative Protocol

ConcernPagedAttention paperPinned vLLM v0.23.0Loop 5 teaching contract
Sharingblock refs and COW for sampling/beam searchrequest block lists and ref_cntrequest-map reachability equation
Allocationdynamic physical blocksget_new_blocks pops free/evictable blocksreserve every group before publication
Cache hitshared/cached physical blockstouch removes zero-ref hit from free queue and increments ref_cntweak cache identity becomes a strong request ref
Freefree blocks whose refs reach zerodecrement refs, append zero-ref blocks to free queueimmutable release receipt and reachability reconciliation
Recyclepaper-level physical block reuseold hash is evicted before allocationgeneration increments and stale handles reject
Concurrency fencenot specified as this schemano source-observed generation/lease fieldsgeneration, source lease, predecessor version, atomic successor

Do not attribute the rightmost column to vLLM. It is the article’s explicit linearizability model.

0x04H Allocation Is Not Kernel Execution

The layout win is not free. Paged kernels consume the group tables and physical handles produced here; M4.5 owns generic read-side kernel tiling and reduction. PagedAttention trades address-translation and allocator complexity for dynamic allocation and sharing. vAttention makes a different choice: contiguous virtual tensors with physical pages committed on demand. Loop 8 owns that lifecycle comparison.

0x05 Refcounts, Copy-On-Write, And Linearizable Publication

Block tables make exact sharing possible. If two sequences share a prefix, their logical blocks may resolve to the same physical handles:

A: [17@4, 04@9, 22@3]
D: [17@4, 04@9, 22@3]

refcount[17@4] = 2
refcount[04@9] = 2
refcount[22@3] = 2

Reading shared immutable rows is safe. Appending into the shared final block is not. The PagedAttention paper’s parallel-sampling example copies only the affected tail block when one sample diverges; after that refcount drops, the remaining unique owner can keep the original block.

Reference counts and copy-on-write keep shared prefix KV exact when one sequence diverges

0x05A Derive Copy Cost And Amplification

Suppose the shared tail contains valid rows and one new row is appended. For group-local row bytes :

Copying reads and writes those rows, then append writes one new row:

Relative to an ordinary one-row append:

Renderer-safe form:

copy_payload       = valid_tail_rows * bundle_row_bytes
COW traffic        = copy read + copy write + append write
COW amplification  = 2 * valid_tail_rows + 1

In the checked trace, r=2 and one bundle row is 64 KiB:

copy payload       = 2 * 64 KiB = 128 KiB
read + copy write  = 256 KiB
append write       = 64 KiB
total COW traffic  = 320 KiB
amplification      = 320 / 64 = 5x
new capacity       = 1 MiB across both cache groups

1 MiB is capacity reserved, not bytes copied. Conflating those quantities would overstate COW traffic.

0x05B One Complete Two-Group COW Trace

Request A first appends privately at token 33:

A predecessor: context=33, table_version=5
tail handles:  g0=1002@9, g1=2002@12
tail rows:     1
refs:          1 per group

write offset 1
publish: context=34, table_version=6, tail rows=2

A is then forked to D. Every mapped handle gains one strong request reference, so the tail bundle becomes shared. D’s append at token 34 cannot mutate it in place:

predecessor D tail:  g0=1002@9,  g1=2002@12, rows=2, refs=2
reserved successor: g0=1003@12, g1=2003@6
copy rows:           [0, 2)
append row:          offset 2
published D tail:    g0=1003@12, g1=2003@6, rows=3, refs=1
old tail refs:       2 -> 1
D successor:         context=35, table_version=2
allocator epoch:     43 -> 44
A copy-on-write append transaction validates request D's versioned shared tail, reserves one destination block in each of two cache groups, copies two valid rows, writes the new row, atomically publishes both replacement handles and refcount deltas, then later recycles the released destination with incremented generations so a stale writer is rejected

0x05C Publication Order Is The Correctness Proof

1. validate allocator epoch, request generation, and table version
2. load expected source handles including physical generations
3. reserve every cache-group destination as unpublished
4. retain source handles while copy is in flight
5. copy exactly the predecessor's valid rows
6. write the appended row into every group destination
7. validate destination data frontiers
8. atomically publish successor tables, logical length, and refcount deltas
9. release temporary source leases

Step 8 is the linearization point. A reader sees either the complete predecessor or the complete successor. It cannot see D mapped to group-0’s new block and group-1’s old block, and it cannot see valid_rows=3 before row 2 is valid.

0x05D Reference Transaction

def cow_append(req, expected_generation, expected_table_version, new_rows):
    predecessor = req.snapshot()
    require(predecessor.request_generation == expected_generation)
    require(predecessor.table_version == expected_table_version)

    source = predecessor.tail_bundle
    source_leases = allocator.retain_read_bundle(source)
    if source_leases is None:
        return STALE_BLOCK_GENERATION

    destinations = allocator.reserve_unpublished_bundle()
    if destinations is None:
        source_leases.release()
        return OUT_OF_MEMORY

    try:
        for group in req.cache_groups:
            copy_rows(
                src=source_leases[group],
                dst=destinations[group],
                rows=predecessor.valid_tail_rows,
            )
            write_row(destinations[group], predecessor.valid_tail_rows, new_rows[group])

        require(all_groups_data_valid(destinations))

        with req.mapping_transaction(expected=predecessor):
            successor = predecessor.replace_tail(
                destinations,
                valid_tail_rows=predecessor.valid_tail_rows + 1,
            )
            allocator.publish_bundle_and_ref_deltas(
                successor=successor,
                add_refs=destinations,
                drop_refs=source,
            )
    except BeforePublication:
        allocator.rollback_unpublished_bundle(destinations)
        return ROLLED_BACK
    finally:
        source_leases.release()

    return AllocationReceipt.from_successor(successor)

The with block is a specification boundary, not a claim about a particular language lock or database transaction in vLLM.

0x05E Truncate, Cancel, Release, Cache, And Evict Are Not Synonyms

truncate(D, 32)
    removes only D's suffix bundle
    decrements destination refs to zero
    returns 1003@12 and 2003@6 to their free queues

allocate(F, 16)
    reuses those block IDs
    increments generations to 1003@13 and 2003@7
    rejects the stale D writer holding @12 and @6

release(A)
    removes A's strong request references
    full cached blocks become EVICTABLE, not identity-free

touch(G, cached block 0)
    removes the zero-ref cached blocks from free queues
    increments refs and publishes G's map

evict(cached block 1)
    removes weak cached identity
    does not revoke a live request mapping

cancel and normal release share physical reference mechanics in the fixture, but their receipts differ because the service-level reason differs. truncate may remove only a suffix. Removing an interior logical block would break position continuity and is rejected.

0x05F Stale IDs Are An ABA Problem

The physical integer 1003 appears twice:

1003@12 -> D's COW destination -> truncated and freed
1003@13 -> F's new allocation

Comparing only block_id would let a delayed D operation mutate F’s lifetime. The normative handle therefore includes generation:

@dataclass(frozen=True)
class PhysicalBlockHandle:
    pool_id: str
    cache_group_id: int
    block_id: int
    generation: int

Pinned vLLM’s KVCacheBlock does not contain this generation field. The field is a recommended stale-handle defense in the teaching model, not a source-local description of vLLM v0.23.0.

0x05G Failure Lab

The oracle rejects 22 malformed transitions. The highest-risk failures are:

FailureWhy it is invalidRequired result
shared-tail in-place appendanother request still reads that blockforce COW
publish before copy-validreader can observe partial destination rowsreject before publication
half-bundle publicationcache groups describe different logical statereject atomically
source release during copysource can be recycled before copy completesretain source lease
stale request/table generationmutation was derived from an old snapshotreject and retry
stale block generationrecycled ID belongs to another lifetimereject without mutation
refcount underflow or duplicate releaseownership ledger no longer reconcilesreject explicitly
rollback reservation leakfailed transaction consumes invisible capacityrestore predecessor digest
rollback after publicationerases a committed history edgerequire compensating transaction
cached partial blockkey claims more reusable rows than are validcache only eligible full blocks
live block on free queueallocator may hand out reachable storagefail invariant check
cache index to recycled generationidentity points at unrelated bytesinvalidate stale index entry

After every committed transition, the executable evidence recomputes refs from request-map reachability, checks every free queue, verifies cross-group valid rows, and hashes the complete committed state. Failed and rejected operations must preserve the predecessor hash.

0x06 vAttention: Virtual Reservation, Physical Commit, And Use

PagedAttention and vAttention begin from the same uncertainty: a request’s final context length is unknown, yet every decode step needs all committed K/V rows. They do not solve it at the same address boundary.

PagedAttention exposes non-contiguous logical blocks and a user-space block table to a paged attention kernel. vAttention reserves a large contiguous virtual K/V range, creates a pool of physical page handles separately, and maps those handles into only the request ranges needed at runtime. The GPU page table performs the final translation. That distinction is the thesis of the vAttention paper, not a claim that memory management disappears.

vAttention paper contrast showing dynamically allocated K/V blocks, user-space block tables, virtual memory, operating-system page tables, and physical pages

Source: vAttention Figure 1. The figure argues that PagedAttention adds a user-space translation layer before ordinary virtual-to-physical translation. The performance comparisons in that paper remain source-reported; this article uses the figure only to establish the address boundary.

The owner question for this section is stricter:

When is a virtual K/V address reserved, physically backed, safe for a kernel to use, semantically owned by one request generation, eligible for retained capacity reuse, unmapped, and finally released?

0x06A Reservation Is Not Commit, And Commit Is Not Valid K/V

Let one worker host:

L       transformer layers
B       maximum simultaneous request slots
T_max   maximum context rows per request
H_kv    local K/V heads after tensor-parallel sharding
d_h     elements per K/V head
b       bytes per element
G       physical page-group bytes

One token row in one K or V tensor at one layer occupies:

Renderer-safe form:

B_tensor,row = H_kv * d_h * b

If the implementation uses one K tensor and one V tensor per layer, one request page frontier advances across 2L tensors. Assuming G is divisible by the one-tensor row size, each mapped page holds:

The virtual extent reserved for one request in one tensor must cover T_max rows and respect page granularity:

Therefore the worker’s virtual reservation is:

This number may be very large. Reserved address space is not resident HBM. It is address-space occupancy, not physical K/V residency. The paper’s Yi-34B example deliberately reserves terabytes of virtual address space while allocating physical K/V pages on demand.

The pinned vAttention prototype also creates physical handles ahead of time. If N_handle handles of G bytes exist, the physical pool is:

Creating a physical handle is still not the same operation as mapping it into a request’s virtual range. For the per-layer K/V layout, one request-page bundle consumes:

For request slot r with target length T_r, the minimum complete mapped frontier is:

Four ledgers are now visible:

M_VA           = reserved virtual address ranges
M_phys,pool    = created physical page handles
M_mapped       = handles currently mapped into request ranges
M_active,valid = K/V rows actually produced for active requests

Mapped backing must reconcile as:

The physical pool separately reconciles as:

No term in either equation is M_VA. Counting the reservation as resident HBM would recreate the exact accounting error that decoupled VMM is meant to avoid.

0x06B The Runtime Lifecycle Has Two State Machines

The paper’s API sequence is:

init
    reserve virtual tensors
    create physical pages, initially unmapped

alloc_reqid
    bind an inactive request slot to a new request

step(sequence_lengths)
    ensure every active request frontier is physically backed

model.forward
    read and append K/V through the virtual tensors

free_reqid
    mark the request slot inactive
    unmap now, or retain mappings for later reuse

shutdown
    unmap, release physical handles, free virtual ranges

That sequence contains two related but non-identical state machines:

virtual range:
    UNRESERVED -> VA_RESERVED -> VA_RELEASED

physical handle:
    CREATED_FREE -> MAPPED(slot, tensor, page) -> CREATED_FREE -> RELEASED

A request generation adds a third semantic axis:

slot 0 / generation 1 / owner A / valid rows 0..4
slot 0 / generation 2 / owner C / valid rows initially empty

The virtual address and even its physical backing may survive the handoff. The old request’s K/V validity does not.

vAttention Figure 5 showing empty virtual ranges, on-demand physical mappings, deferred reclamation after R1 exits, and reuse of the retained range when R3 arrives

Source: vAttention Figure 5, retained from A24. R3 receives a request slot with existing physical backing. The figure demonstrates mapping-capacity reuse; it does not establish that R1 and R3 have equal tokens, model state, positions, or K/V values.

The pinned prototype makes that distinction concrete. free_batch_idx marks a slot inactive by setting its tracked sequence length to zero; mapped pages may remain. alloc_new_batch_idx(seqlen) prefers a fitting inactive slot whose retained mapping already covers the new request. The new request must still write its own K/V rows.

0x06C Contiguous Address First, Hardware Translation Second

For a separate tensor X_ell, where X is K or V and ell is the local layer, let base(X,ell) be that tensor’s virtual base. A row-major scalar at request slot r, token t, head h, and lane d has virtual address:

Define the byte offset within the request subrange:

Then:

The runtime must have mapped virtual page q for every required K/V-layer tensor before use. Hardware translation then resolves:

(virtual tensor, request slot, page q)
    -> physical handle
    -> handle base + delta

Unlike Loop 4’s PagedAttention path, the attention kernel does not first query a request K/V block table. It still needs a request-slot mapping such as FlashAttention’s cache_batch_idx when continuous batching leaves holes in the larger virtual tensor.

Side-by-side PagedAttention and vAttention address traces, followed by a checked D generation 3 V1 scalar resolving virtual byte 1870 through page 2 to physical handle H11 at byte 14

The checked synthetic scalar is D@3 / V1 / (t=8,h=1,d=3):

B_tensor,row = 2 * 4 * 2 = 16 B
u = 8*16 + 1*4*2 + 3*2 = 142 B
q = floor(142 / 64) = 2
delta = 142 mod 64 = 14 B

base(V1) = 3 * (3 slots * 192 B) = 1728 B
A_VA = 1728 + 0*192 + 142 = 1870 B

page-table mapping:
    (slot 0, V1, q=2) -> H11
physical location:
    H11 + 14 B

The synthetic address proves the contract shape, not a production pointer. The 64 B page is intentionally synthetic. The paper describes standard CUDA VMM at 2 MiB granularity and a modified open-source NVIDIA UVM driver for 64 KiB, 128 KiB, and 256 KiB page groups. The tiny fixture is an executable algebra oracle, not a supported production configuration.

0x06D Map Before Use: Synchronous And Asynchronous Paths

The simplest safe path is synchronous:

def step_sync(active_requests):
    for req in active_requests:
        needed = ceil_div(req.target_tokens, tokens_per_page)
        while req.mapped_pages < needed:
            handles = reserve_complete_KV_layer_bundle()
            map_bundle_at_contiguous_frontier(req.slot, handles)

    receipt = publish_mapped_frontiers()
    assert receipt.ready_before_use
    return receipt

The paper observes that decode growth is predictable one iteration ahead: each decode request adds at most one token in an iteration. Its optimization maps a future page group in a background thread while the preceding iteration runs. That overlap changes timing, not the dependency:

receipt = step_async(next_sequence_lengths)

# Other work may overlap, but a kernel cannot cross the new frontier yet.
await receipt.mapping_complete
assert receipt.covers(request_generation, target_tokens)
model.forward(cache_batch_idx=receipt.request_slots)

The checked oracle uses a stronger normative publication rule: all K and V pages across the worker’s local layers for one request frontier become visible as one MappedFrontierReceipt. The pinned prototype performs concrete VMM map operations; it does not define this named atomic receipt class. The stronger contract is useful because a kernel observing K0:q without V1:q would see a shape-consistent pointer range whose physical backing is incomplete.

Prefill and decode also stress the mapper differently:

PhaseDemand shapeSafe integration
prefillone request may need many page groups immediatelymap current prompt requirement before forward; retained/eager pages may reduce critical-path work
decodeeach active request grows predictably by one tokenprepare a future boundary asynchronously, then await before crossing it
request finishlogical owner disappears immediatelyunmap now or retain backing under an inactive slot
pressurefree-handle pool cannot satisfy growthreclaim inactive retained pages, retry map, or return failure to the scheduler

Mapping failure is a physical-feasibility result. M5.2 still owns which request to preempt, delay, or reject.

0x06E Delayed Reclamation Reuses Capacity, Not Prefix Identity

Deferred reclamation avoids immediate unmap/remap latency. Mapped backing is reusable capacity, not an exact-prefix hit:

A@1 maps slot 0 pages [0,1]
A completes
slot 0 becomes inactive, pages [0,1] remain mapped
C@2 receives slot 0 and needs only page [0]
no new mapping is required

Three facts must remain separate:

virtual address reused:       yes
physical mapping reused:      yes
old K/V values reusable:      no

On C@2 allocation, the oracle sets valid_tokens = 0, increments the slot generation, and records old_KV_semantically_valid = false. C’s prefill writes its own rows before any attention step may read them. Exact prefix reuse would require Loop 2’s compatibility manifest and Loop 6/7’s indexed identity and ownership receipts; vAttention slot reuse supplies none of those proofs.

Deferred pages also create a deliberate tradeoff. They can remove map calls from a later prefill, but consume mapped backing that another request may need. Under pressure, the runtime can unmap an inactive slot’s highest page, return its complete K/V-layer handle bundle to the pool, and map that bundle at an active request’s contiguous frontier.

0x06F One Checked VMM Lifecycle And Byte Reconciliation

The fixture uses:

L=2, B=3, T_max=12, H_kv=2, d_h=4, b=2 B, G=64 B

B_tensor,row = 2*4*2 = 16 B
P_tokens = 64/16 = 4 tokens/page
R = ceil(12*16/64)*64 = 192 B/request/tensor
M_VA = 2*2*3*192 = 2304 B

N_handle=12
M_phys,pool = 12*64 = 768 B
B_page-bundle = 2*2*64 = 256 B
Checked vAttention lifecycle separating 2304 bytes of virtual reservation, a 768-byte physical handle pool, complete K/V-layer page mappings, retained capacity reuse across request generations, on-demand reclamation, and final cleanup

Selected states reconcile exactly:

Stateactive validactive mapped slackinactive retainedmapped backingfree handlesphysical pool
A valid 5, B valid 4576 B192 B0 B768 B0 B768 B
free A, retain two bundles256 B0 B512 B768 B0 B768 B
C valid 4 on A’s old slot512 B256 B0 B768 B0 B768 B
reclaim C’s unused tail256 B0 B256 B512 B256 B768 B
D valid 9 after reclaiming B576 B192 B0 B768 B0 B768 B
all requests free, eager reclaim0 B0 B0 B0 B768 B768 B
worker released0 B0 B0 B0 B0 B0 B

The 24-operation trace performs five page-bundle maps and five unmaps. Two new requests benefit from retained mappings. D’s asynchronous growth from eight to nine tokens finds no free handles, reclaims B’s inactive page bundle, maps it as D’s page q=2, awaits readiness, and only then commits token row 8.

The complete report and 20 negative cases live in docs/numinens-evidence/m5-3-kv-layout-exact-reuse/.

0x06G Design Choices: The Mechanism Is Not One Fixed Policy

ChoiceOption AOption BWhat changes
kernel address pathPagedAttention block tablecontiguous virtual tensorkernel ABI and runtime metadata
mapping schedulesynchronous current demandasynchronous predicted decode growthcritical-path latency and readiness synchronization
completed requesteager unmapdeferred reclamationfree-handle capacity versus future map avoidance
new requestallocate from empty slotbest-fit retained mappingprefill map work, not semantic identity
page granularitystandard CUDA VMM 2 MiBpaper’s custom smaller page groupsinternal tail waste, map-call count, driver requirement
tensor organizationseparate K/V per layerprototype megacache varianthandle bundle shape, token/page derivation, and kernel ABI

Smaller pages reduce internal waste but increase mapping granularity and may require non-standard driver support. Larger pages reduce the number of page operations but can retain or strand more unused physical bytes. The paper’s timings and throughput results are useful source-reported evidence for its tested A100/H100 software stack; they are not a universal ranking against every modern PagedAttention runtime.

vAttention is also not “no memory manager.” The pinned implementation still tracks request slots, sequence lengths, mapped-page frontiers, physical handle pools, background work, reclamation, and cleanup. What changes is which translation is explicit in the attention-kernel interface.

0x06H Source-Observed Prototype Versus Normative Protocol

PropertyPinned vAttention observationThis article’s stronger teaching contract
revisionMicrosoft vattention commit ef3fff25...fixture hash binds that revision record
virtual allocationcuMemAddressReserve, page-aligned tensor/request extentsimmutable worker manifest and checked M_VA
physical poolcuMemCreate handles reserved separatelyexplicit handle partition: mapped or free
page frontiermapped pages and current sequence lengths tracked separatelycomplete per-request K/V-layer bundle receipt
request reusebest-fit inactive batch index; mapped pages may survive free_batch_idxgeneration increment, valid_tokens=0, semantic-reset assertion
map timingsync and background manager pathsreadiness receipt required before use
reclaiminactive overcommit can be unmapped and handles returneddeterministic highest-page reclaim and byte reconciliation
production statusresearch Sarathi-Serve integration with stated environment limitsno feature-parity or deployment-readiness claim

The prototype source also contains a megacache path and research-facing integration code. Those are valuable design alternatives, not permission to generalize the exact fixture tensor organization or publication semantics to every vAttention deployment.

0x06I Failure Lab

FailureBroken invariantRequired result
count virtual reservation as HBMaddress space and physical residency collapsereject ledger
map only some K/V-layer pagesrequest frontier is physically incompletereject publication
expose a non-contiguous page frontierordinary contiguous dereference can enter a holereject mapping
use before async receiptkernel may fault or read unmapped backingblock execution
unmap an active required pagecommitted visible history loses backingreject unmap
reuse retained bytes as a prefix hitold request identity leaks into new generationreset validity; require recomputation
alias one handle into two ordinary mutable mappingswrites can corrupt another virtual rangereject ownership
free unknown or duplicate requestslot lifecycle no longer reconcilesreject transition
release worker with active requestsreachable K/V loses backingreject shutdown
configure unsupported granularityVMM allocation contract cannot be satisfiedfail initialization

The executable oracle rejects all 20 malformed fixtures by named reason. It does not benchmark CUDA VMM, reproduce the prototype exactly, decide scheduler preemption, or claim that retained mappings imply exact prefix reuse.

0x07 Prefix Caching: Reuse Is A Contract

Prefix caching begins with a simple question and immediately splits into four:

have we already computed an exact semantic prefix?
which part of that prefix is present in this index snapshot?
which indexed rows may this runtime policy return?
which prompt rows still need execution and physical capacity?

The answers are not generally equal. vLLM’s automatic-prefix-caching design describes the operational objective as reusing K/V for a shared prompt prefix and skipping its repeated prefill. That can reduce repeated prefill work and TTFT. It does not remove decode work for later generated tokens, and a miss still follows the ordinary prefill path.

Loop 2 already froze authorization, semantic compatibility, physical layout, and the narrower concrete-key projection. Loop 6 consumes those records. It does not re-decide whether another model generation, adapter, position contract, cache representation, or isolation namespace is compatible.

0x07A Four Prefix Lengths, Not One Hit Count

Let:

S_prompt   = request prompt length
S_sem      = longest semantically exact token prefix
S_indexed  = longest contiguous compatible prefix present in the index
S_cap      = maximum prefix the execution path is allowed to reuse
S_runtime  = prefix rows actually returned by the runtime
S_recompute = S_prompt - S_runtime

The invariant chain is:

Renderer-safe form:

0 <= S_runtime <= min(S_sem, S_indexed, S_cap) <= S_prompt
S_recompute = S_prompt - S_runtime

For a logits-producing generative request, the pinned vLLM path sets:

The reason is dataflow, not cache identity. K/V rows alone do not contain the final hidden state needed by the LM head. If every prompt row came only from cache, the path still needs a valid execution that produces next-token logits. This cap assumes S_prompt >= 1. Empty-input handling belongs to the request and model interface; it must not enter this subtraction as an unsigned or negative prefix length.

The pinned full-attention lookup also returns block-aligned hits. For block size :

Renderer-safe form:

S_runtime_full =
    P * floor(min(S_sem, S_indexed, S_prompt - 1) / P)

This equation follows in three steps:

  1. semantic compatibility limits the maximum exact prefix;
  2. the index can return only the contiguous entries it actually contains;
  3. the logits cap removes at least the final prompt row, then the full-block policy rounds the remaining length down to a multiple of .

Do not replace the last step with S_prompt - 1. That would silently claim partial-block reuse in a path whose source contract returns complete blocks.

0x07B Derive The Parent Hash Chain

Split the token sequence into cache-key blocks . Let contain only the runtime’s declared extra-key projection for block . The incremental chain is:

The pinned vLLM v0.23.0 source computes this shape from the parent block hash, the current full-block token tuple, and optional extra keys. Observed extras include LoRA name, multimodal identifiers with block-relative offsets, first-block cache_salt, and prompt-embedding hashes. Cache-group ID is then combined with the block hash for lookup.

That is a concrete runtime projection, not the whole CacheCompatibilityManifest. Model generation, complete cache ABI, tensor layout, and namespace generation may be enforced by process lifetime, namespace selection, reset, or validation outside the block digest. Do not attribute the article’s larger manifest tuple to the pinned hash serializer.

Why recurse through ? Suppose block contains the same local tokens in two requests but block differs. The K/V for depends on the earlier hidden-state path, so a local-block-only key is insufficient. Under the collision-resistance assumption:

X_j changes
    -> h_j changes
    -> h_(j+1) consumes a different parent
    -> every later descendant hash changes

The Loop 6 fixture changes token position 37, inside logical block 2. The semantic match ends at row 37, but the full-block runtime can return only the two complete ancestor blocks: 32 rows. Blocks after the first miss are not independent cache candidates.

def hash_full_blocks(request, P, hash_fn):
    parent = None
    hashes = []

    for start in range(0, len(request.tokens), P):
        stop = start + P
        if stop > len(request.tokens):
            break  # pinned path hashes full blocks only

        extras = runtime_extra_keys(request, start, stop)
        parent = hash_fn(parent, tuple(request.tokens[start:stop]), extras)
        hashes.append(parent)

    return hashes

0x07C Lookup Is A Contiguous, All-Group Trace

A valid lookup is not “find every digest that happens to exist.” It walks the ancestry in order and stops at the first missing or incompatible block. With multiple cache groups, the same logical prefix frontier must be physically available for every group required by the model.

def longest_full_block_hit(request, manifest, namespace, index, policy):
    authorize(namespace)                    # before cache-existence timing
    require_compatible(manifest)

    max_hit = len(request.tokens) - 1 if request.requires_logits else len(request.tokens)
    max_blocks = max_hit // policy.alignment_tokens
    matched = []

    for block_hash in hash_full_blocks(request, policy.block_size, policy.hash_fn):
        if len(matched) == max_blocks:
            break

        group_entries = index.lookup_all_groups(block_hash)
        if group_entries is None:
            break
        if not generations_are_current(group_entries):
            break

        matched.append(group_entries)

    return len(matched) * policy.block_size, matched

lookup_all_groups is important. A digest present for the upper-layer cache group but absent for the lower-layer group is not a partial success for an ordinary full-model forward pass. Hybrid cache managers can impose additional alignment and convergence rules; at the pinned revision, the coordinator monotonically reduces candidate length until the participating cache-group types agree on one common hit.

The output is an immutable match receipt, not a scheduling command. M5.2 may consume its work and capacity deltas; it still owns admission, service order, fairness, and SLO policy.

0x07D Full Blocks Versus Immutable Partial Tails

The article compares two valid design families. Only the first is attributed to the pinned vLLM path.

ContractFull-block-only policyImmutable-partial-tail alternative
publishable key unitexactly rowsfull blocks plus one declared tail frontier
tail identityabsent from indexparent, tail tokens, valid_rows, policy ID, extras
runtime alignment rowspotentially one row
complete-hit recomputecan expand to one entire blockcan remain one row if execution supports it
append into indexed tailtail was not shared from indexforbidden under old key; emit successor/COW intent
metadata/index pressurelowerhigher; more frontiers and mutation states
source status herepinned vLLM source-observedrewrite interpretation and alternative design

For an immutable partial tail with valid rows:

Renderer-safe form:

h_tail = hash(parent_hash, tail_tokens[0:valid_rows], valid_rows,
              partial_policy_id, extra_keys)

Including valid_rows prevents a two-row frontier and a three-row frontier from sharing identity accidentally. Appending under the same key would make the key lie about the object. A partial-tail hit followed by a divergent write therefore emits copy_valid_partial_rows to Loop 5, which owns reservation, COW, publication, and rollback.

The fixture makes this difference concrete for a 50-token prompt and :

QuantityFull-block-onlyImmutable partial tail
semantic exact prefix50 rows50 rows
logits cap49 rows49 rows
runtime hit48 rows49 rows
prompt rows recomputed2 rows1 row
new block bundles requested11
valid tail rows copied before a write01

The partial design reuses one more row, but it does not make mutation free. It trades an extra identity/frontier and COW handoff for the saved execution row.

0x07E The Complete-Prompt-Hit Edge

The most dangerous shorthand is:

all prompt tokens cached -> zero prompt work

For the pinned generative path, that is false. Consider exactly three cached blocks:

P                  = 16 tokens
S_prompt           = 48 tokens
S_sem              = 48 tokens
S_indexed          = 48 tokens
S_cap              = 47 tokens
S_runtime          = 16 * floor(47 / 16) = 32 tokens
S_recompute        = 48 - 32 = 16 tokens
new block bundles  = ceil(16 / 16) = 1

The source comment explicitly notes that obtaining logits can trigger recomputation of an entire block because num_computed_tokens must remain block aligned. “Recompute the last token” describes the semantic need; it does not imply that the current implementation always executes only one row.

For a 50-token prompt with three cached full blocks, the same policy yields:

S_cap              = 49
S_runtime          = 16 * floor(49 / 16) = 48
S_recompute        = 2
new block bundles  = ceil(2 / 16) = 1

The physical allocation is block granular even though only two rows are useful at this moment. With local row bytes KiB and block bundle bytes MiB, the useful recompute payload is 128 KiB while the requested new capacity is one 1 MiB bundle. Those are separate ledgers.

An exact 48-token semantic and indexed prompt match passes through a logits cap of 47 tokens and a 16-token alignment rule, producing a 32-token runtime hit, 16 recomputed prompt rows, and one newly allocated block bundle; an alternative immutable partial-tail path is shown separately and is not attributed to vLLM

The fixture also covers a one-block prompt. With , the cap is 15 and full-block alignment reduces the reusable prefix to zero. The entire 16-row block is recomputed. This is an edge contract, not a claim that prefix caching is generally ineffective.

0x07F Collision Resistance Is Not Isolation

Three different controls are easy to collapse:

ControlQuestionFailure if omitted
semantic compatibilitywould these rows be the same forward computation?numerically wrong K/V reuse
collision resistance or witness checkdid two different key inputs map to one digest?false candidate identity
namespace authorization and saltmay this requester discover or reuse the object?cross-domain reuse or timing disclosure

The vLLM v0.23.0 design documents SHA-256 as the default hashing family and offers a deterministic CBOR serialization option for cross-environment keys. That makes accidental digest collision extremely unlikely; it is still a cryptographic assumption, not a mathematical proof that two inputs cannot collide. The Loop 6 negative fixture forces an artificial equal digest over different token witnesses to exercise an optional secondary-witness policy. Do not claim that the pinned runtime performs that synthetic witness audit.

cache_salt is injected into the first block and inherited by descendants through the parent chain. It separates agreed trust groups and mitigates cache-timing disclosure across them. It is not encryption, and a salt by itself does not replace authorization. The safe order is:

authorize namespace
    -> validate namespace generation and semantic manifest
    -> derive/lookup concrete key
    -> validate entry generation and all-group handles
    -> publish PrefixMatchReceipt

Lookup before authorization can reveal cache existence through latency. A model update, adapter replacement, or isolation reset must produce a successor namespace/generation or reset the index; retaining old entries under a new semantic world is not exact reuse.

0x07G PrefixMatchReceipt And Failure Closure

The receipt freezes what was proved and what remains to execute:

@dataclass(frozen=True)
class PrefixMatchReceipt:
    request_id: str
    request_generation: int
    index_snapshot_id: str
    index_publication_generation: int
    compatibility_manifest_sha256: str
    namespace_id: str
    namespace_generation: int
    policy_id: str
    semantic_match_tokens: int
    runtime_hit_tokens: int
    prompt_rows_recomputed: int
    matched_group_handles: tuple
    new_block_bundles: int
    copy_valid_partial_rows: int
    logits_path: str
    receipt_sha256: str

The allocation derivation, assuming no already-owned writable tail slots, is:

Renderer-safe form:

N_new = ceil(S_recompute / P)
M_new_capacity = N_new * P * B_row

If a request already owns writable tail capacity, the allocator may need fewer new blocks. If the hit ends inside an immutable shared tail, the receipt emits a copy-row intent instead. Loop 5 resolves both cases transactionally; Loop 6 does not mutate a block table while looking up identity.

The executable failure lab rejects:

Invalid stateWhy it is invalid
adapter, ABI, layout, position, or model-generation mismatchtoken equality does not prove equal K/V computation
namespace or salt mismatchcandidate is outside the authorized reuse domain
non-root key omits parent hashlocal block identity is detached from causal ancestry
block 2 returned without block 1prefix matches must be contiguous
partial key omits valid_rowsindexed frontier is ambiguous
partial entry returned by full-only policyruntime policy and receipt disagree
one cache-group handle missingfull-model physical state is incomplete
entry points to recycled generationdigest identifies stale physical lifetime
forced equal digest with different witnesscollision-hardening check rejects candidate
runtime hit exceeds semantic matchcache returned rows not proved exact
47-row hit under 16-row full alignmentreceipt violates runtime granularity
full prompt hit with no recompute/logits pathnext-token logits have no producer
two recompute rows request zero blocksfloor was used where block capacity needs ceiling
partial tail appended under unchanged keyimmutable identity no longer describes bytes

The checked artifact evaluates eight positive traces and 22 malformed cases. It is a deterministic contract oracle, not a hit-rate, latency, or allocator- contention benchmark.

0x08 RadixAttention: Prefix Tree As A Cache Index

A hash table answers a fixed-block identity question. A radix tree answers a different question:

Across all exact token sequences retained by this runtime, what is the longest reusable prefix of this request, which physical K/V slots realize it, and how can that mapping survive concurrent insertions and reclamation?

A25 introduced RadixAttention as the point where prefix reuse stops being a lookup trick and becomes persistent runtime state. SGLang retains both prompt and generated K/V, maps variable-length token segments to K/V slot tensors, splits segments when a new common boundary appears, protects paths used by running requests, and reclaims cached leaves under memory pressure. The paper uses one-token pages. The Loop 7 teaching trace also uses page_size = 1 so the split algebra is visible; larger page policies must align every exposed boundary to their declared granularity.

A radix tree maps token-prefix segments to cached KV blocks so the runtime can reuse the longest exact prefix and compute only the suffix

The SGLang paper follows that data structure through nine mutations rather than showing only one steady-state tree. New requests split edges at newly exposed common prefixes, accessed nodes remain cache hits, new suffixes are inserted, and least-recently-used leaves are evicted when capacity is needed. This is the missing operational point: the prefix index is persistent scheduler state, not a static diagram built once from a batch.

SGLang paper sequence of RadixAttention prefix-tree insertions, splits, cache hits, and LRU evictions across nine request events

Source: Zheng et al., SGLang, Figure 3. Green nodes are newly added, blue nodes are cached nodes accessed at that time point, and orange dashed nodes are evicted. The scenarios cover two chats, few-shot queries, and self-consistency sampling; they illustrate the runtime operations, not a universal eviction policy for every prefix-cache workload.

0x08A A Compressed Edge Owns Equal Token And Slot Segments

For a non-root node , define the incoming compressed edge as:

Exact ownership requires:

where X_v[i] is the token at this path position and S_v[i] is the physical token-slot index containing that token’s K/V rows. In the pinned SGLang TreeNode, these objects are key and value. They are not interchangeable: the token segment establishes prefix identity, while the value tensor locates K/V storage.

Renderer-safe form:

edge(v) = (token_ids[v], kv_slot_ids[v])
len(token_ids[v]) == len(kv_slot_ids[v])

The complete key and slot path to terminal node are concatenations over its non-root ancestors:

The tree is therefore also a physical ownership ledger. For pool slot set , tree-owned slots , request-private unpublished slots , and free slots :

Loop 7’s committed snapshots contain no request-private suffix after each transaction, so the checked identity simplifies to:

tree_owned_tokens + free_slots = pool_slots

A request’s prefix_indices are references to tree-owned slots. They are not a second owner and must not be added again. Lock references protect the path; they do not clone its K/V tensors.

0x08B Compressed-Edge Match May Be A Mutation

At node , let the unconsumed request suffix be . The edge comparison is:

There are three cases:

ResultMeaningTree action
lcp = 0no child selected by the next tokenstop at parent
lcp = len(X_v)whole compressed edge matchesappend S_v, descend
0 < lcp < len(X_v)match ends or diverges inside the edgesplit at lcp, return the exposed shared prefix

This last case is why prefix lookup is not necessarily read-only. The pinned SGLang match_prefix documentation and _match_prefix_helper explicitly allow one split when the match ends inside a stored segment.

def match_compressed(root, query):
    node = root
    matched_slots = []
    offset = 0

    while offset < len(query):
        child = node.children.get(query[offset])
        if child is None:
            break

        m = lcp(child.token_ids, query[offset:])
        assert m > 0                         # child selector invariant

        if m < len(child.token_ids):
            shared = split_edge(child, m)    # structural mutation
            matched_slots.extend(shared.kv_slot_ids)
            node = shared
            offset += m
            break

        matched_slots.extend(child.kv_slot_ids)
        node = child
        offset += m

    return node, tuple(matched_slots), offset

In operation r02, the tree initially owns one edge:

tokens = [10, 11, 12, 13, 20, 21]
slots  = [ 1,  2,  3,  4,  5,  6]

The query [10, 11, 12, 99] has lcp = 3. The split is not a copy of K/V payload; it is a partition of the same ordered ownership:

For m = 3:

shared edge: tokens [10, 11, 12] -> slots [1, 2, 3]
old suffix:  tokens [13, 20, 21] -> slots [4, 5, 6]

concatenate before = concatenate after
no slot allocated, copied, freed, or duplicated

The split must also reparent the old child, replace the parent’s selector, and preserve any active lock count on both the newly exposed prefix and the old suffix. Splitting only the token key would make the tree look correct while returning the wrong physical rows.

0x08C Insert, Duplicate Release, And Request Publication

Insertion traverses exactly like lookup. If the request diverges after cached tokens, only its suffix becomes a new edge. When a completed producer arrives with freshly allocated input slots , the first values are duplicates of slots already owned by the tree:

The tree retains S_new; the allocator releases S_duplicate. Operation r05 inserts the second chat branch:

incoming tokens = [10, 11, 12, 13, 30, 31]
incoming slots  = [ 7,  8,  9, 10, 11, 12]
cached prefix   = 4 tokens

release duplicate input slots = [7, 8, 9, 10]
publish new branch             = [30, 31] -> [11, 12]

The existing [13, 20, 21] -> [4, 5, 6] edge is split again at one token:

[13]     -> [4]       shared by both chats
[20,21]  -> [5,6]     old chat branch
[30,31]  -> [11,12]   new chat branch

This is not reference-count-free deduplication. The prefix index takes responsibility for the retained slots, duplicate request-local slots return to the pool, and every transition must leave exactly one owner.

Finished and unfinished requests have different publication paths in the pinned source:

PathSource-observed sequenceOwnership consequence
finishedinsert committed aligned token/slot pairs; free duplicate prefix and unaligned tail; release old terminal lockrequest disappears while retained edges become cache state
unfinished/chunkedinsert current aligned frontier; free duplicates; rematch; rewrite request prefix indices; move lock to new terminalrunning request continues on the newly published path

Operation r07 exercises the second path. req-chat-a already references six tree slots, computes tokens [22, 23] into slots [13, 14], inserts one new edge, then moves its lock from node 1 to node 5. The update is represented as one stronger teaching transaction:

def publish_unfinished(req, append_tokens, append_slots):
    predecessor = validate_tree_and_request(req)
    reserve(append_slots)

    full_tokens = path_tokens(req.last_node) + append_tokens
    full_slots = path_slots(req.last_node) + append_slots
    prefix_len = insert(full_tokens, full_slots)
    free(full_slots[req.cache_protected_len:prefix_len])

    new_last, new_prefix_slots, matched = match_compressed(root, full_tokens)
    assert matched == len(full_tokens)

    dec_lock_ref(req.last_node)
    inc_lock_ref(new_last)
    publish_request_prefix(req, new_last, new_prefix_slots)
    return RadixMutationReceipt(predecessor, committed_tree_version())

The ordering above is a normative Transformer System contract. The pinned source exposes the individual insert, free, rematch, request-table write, and lock-move steps; it must not be cited as publishing the article’s one atomic versioned receipt.

0x08D Lock References Protect Paths, Not Just Leaves

Continuous batching cannot evict a prefix used by a running request. If active lease terminates at node , the derived reference count for node is:

The pinned inc_lock_ref and dec_lock_ref walk from the terminal node to the root. If two running requests share a system-prompt edge, that ancestor has two references even when their leaves differ. A split under an active request must copy the old child’s lock count onto the newly exposed parent because the shared prefix has become part of every formerly protected path.

Define source-shaped token ledgers:

Only a subset of the second quantity is reclaimable immediately:

An unlocked internal node still owns evictable cache state, but it cannot be deleted before its descendants without disconnecting their keys. This is why evictable_size and the current leaf-victim set answer different questions.

0x08E Leaf-Safe Eviction Is Recursive And Whole-Edge

The SGLang paper uses least-recently-used leaf eviction. The pinned v0.5.11 runtime also exposes LFU, FIFO, MRU, FILO, priority, and segmented-LRU strategies. The radix invariant is unlocked leaf first; victim ranking is a policy choice.

def evict_tokens(target):
    heap = rank(unlocked_leaf_nodes())
    released = 0

    while released < target and heap:
        leaf = heap.pop()
        assert leaf.lock_ref == 0
        assert not leaf.children

        free_kv_slots(leaf.kv_slot_ids)
        parent = delete_leaf_edge(leaf)
        released += len(leaf.kv_slot_ids)

        if parent is not root and not parent.children and parent.lock_ref == 0:
            heap.push(parent)       # newly exposed leaf

    return released

Eviction is whole-edge. A target of one token can release more than one if the selected compressed edge contains several tokens. Operation r14 asks for three rows and releases exactly three in two steps:

evict leaf [60]    -> free slot [20]
parent [50, 51] is now an unlocked leaf
evict that parent  -> free slots [15, 16]

Locked chat paths survive both eviction calls. After their leases are released, r17 removes [22, 23] first, exposes [20, 21] as a leaf, then removes that parent. This is the allocator consequence of the paper’s visual sequence: an ancestor becomes reclaimable only after its last child disappears.

The paper’s scheduling theorem must remain scoped. For an offline fixed batch, a radix tree built from that request set, and cache capacity at least the maximum request length, DFS visits each edge once and reaches the lower bound:

Longest-shared-prefix-first is equivalent to a DFS order under those assumptions. The paper explicitly separates online arrivals, unpredictable output lengths, and starvation. The theorem is not an optimality result for online SLOs, fairness, arbitrary capacity, or unknown decode growth; those decisions remain in M5.2.

0x08F One Checked Mutation And Ownership Trace

The executable fixture uses 24 physical token slots and 18 committed operations. The high-value transitions are:

OperationsTree/lock mutationSlot result
r01-r03insert chat A; short query splits six-token edge at three; lock then finishtree owns slots 1-6; no split copy
r04-r08lock chat A; second chat splits at token 13; publish unfinished A; move locks; finish Bduplicate slots 7-10 freed; branches own 5,6, 11,12, 13,14
r09-r12insert two few-shot branches; split [50,51,52]; lock chat B branch; touch [60]duplicate slots 18,19 freed; few-shot tree owns 15,16,17,20
r13-r14LRU leaf then newly exposed parent evictionfree 17, then 20,15,16; locked chats untouched
r15-r17finish both chats; recursively evict old chat-A suffixfree 13,14, then 5,6
r18match and lock surviving chat-B path; emit handoffpath slots [1,2,3,4,11,12]; suffix interval [6,7)

The final reconciliation is:

pool slots            = 24
tree-owned slots      = 6
free slots            = 18
active private slots  = 0

6 + 18 = 24

protected tree tokens = 6
evictable tree tokens = 0

Across the full trace:

edge splits                    = 3
duplicate input slots released = 6
eviction calls                 = 3
evicted compressed edges       = 5
evicted token slots            = 8

Every operation hashes its predecessor and successor states. Every committed successor re-derives child selectors, token/slot equality, path locks, slot disjointness, and the complete pool partition.

A compressed radix edge is split into aligned token and KV-slot segments, active request locks protect every node on two chat paths, unlocked few-shot leaves are evicted recursively, and a surviving six-token path becomes an immutable scheduler handoff while all 24 physical slots reconcile

0x08G Immutable Scheduler Handoff, Not A Schedule

The final match returns an immutable physical fact:

@dataclass(frozen=True)
class RadixSchedulerHandoffReceipt:
    request_id: str
    request_generation: int
    tree_version: int
    tree_state_sha256: str
    matched_tokens: int
    prefix_slot_ids: tuple[int, ...]
    path_node_ids: tuple[int, ...]
    terminal_node_id: int
    suffix_interval: tuple[int, int]
    lock_lease_id: str
    lock_required_until_scheduler_disposition: bool
    scheduler_owner: Literal["M5.2"]
    policy_decision: None
    receipt_sha256: str

For req-handoff:

request generation = 4
tree version       = 18
matched tokens     = 6
path nodes         = [2, 3, 4]
prefix slots       = [1, 2, 3, 4, 11, 12]
suffix interval    = [6, 7)
terminal node      = 4
lock lease         = lease-req-handoff-v18
policy_decision    = none

M5.2 may use this receipt with request deadlines, fairness state, prefill/decode budgets, output uncertainty, and overload policy. It may choose FCFS, LPM, DFS-weight, or another declared policy. M5.3 does not sort the waiting queue. If M5.2 admits the request, it retains or exchanges the lock under an explicit transaction. If it rejects or defers the request, it must release the lease. Using an unlocked receipt after tree mutation is a stale-read bug.

The current prefill and capacity estimates still remain separate:

prompt_tokens_to_compute = S_prompt - matched_tokens
new_useful_KV_bytes = prompt_tokens_to_compute * B_row

new_physical_blocks =
    ceil(max(prompt_tokens_to_compute - free_private_tail_slots, 0) / P)

new_physical_capacity_bytes = new_physical_blocks * P * B_row

The receipt freezes physical evidence; Loop 5 performs allocation/COW, and M5.2 decides whether and when to request it.

0x08H Source-Observed Runtime Versus Normative Protocol

ContractPinned SGLang v0.5.11Loop 7 teaching protocol
edge valuecompressed RadixKey plus slot-index tensortyped token/slot arrays with whole-pool reconciliation
matchpage-align, update access metadata, split if needed, return indices and terminal nodesame core algorithm plus versioned predecessor/successor receipt
publicationfinished/unfinished methods insert, free duplicates, update request fields, move locksone auditable transaction boundary
locksterminal-to-root lock_ref increments/decrementsre-derived from active immutable leases after every operation
evictionconfigured strategy ranks unlocked leaves; allocator frees node.valuedeterministic LRU fixture with generation-independent slot IDs
schedulingLPM/DFS-weight and cache-agnostic alternatives exist in scheduler codereceipt contains no policy decision and hands to M5.2

Do not attribute RadixMutationReceipt, tree-version hashing, complete pool partition checks, or the synthetic 24-slot trace to SGLang. Conversely, do not reduce the pinned source to the teaching model: v0.5.11 includes page alignment, host/hierarchical state, EAGLE bigram keys, priorities, multiple eviction strategies, K/V events, and scheduler paths outside this loop.

0x08I Failure Lab

Invalid state or transitionFailureRequired response
token and slot segment lengths differpath token resolves to no unique K/V slotreject state
two sibling edges share a first-token selectortraversal is ambiguousreject mutation
one slot appears on two edgesphysical K/V has two tree ownersreject publication
tree-owned slot remains on free listallocator may overwrite reachable K/Vstop allocation
split offset is zero or the full edge lengthcreates empty/duplicate structural edgereject split
split partitions key but not valuereturned slots no longer match tokensreject successor
lock count differs from active terminal pathsprotected/evictable ledger is falserebuild or fail closed
locked node selected for evictionrunning request loses required K/Vreject victim
internal node selected before descendantschild paths become disconnectedevict leaves only
duplicate producer slots are not releasedpool leaks capacity after cache insertionreconcile insertion receipt
request finishes without decrementing path locksdead cache becomes permanently protectedreject finish receipt
handoff tree version is staleslots may have been evicted or reassignedrematch under current snapshot
handoff slots do not equal terminal pathscheduler receives unrelated physical rowsreject receipt
handoff hash changes without recomputationsupposedly immutable evidence was alteredreject receipt

The negative fixture checks 18 malformed states, operations, and receipts. It includes locked-leaf eviction, internal-node eviction, lock underflow, owned slot reuse, stale version, path-slot mismatch, suffix mismatch, and receipt tampering. This is an exactness oracle, not a latency or cache-hit benchmark.

0x09 Block Size Is A Cost Vector

Paged allocation replaces uncertain whole-request reservation with a discrete granularity choice, but “block size” is overloaded. Loop 10 separates four objects before evaluating any sensitivity:

SymbolObjectOwned byWhat the unit bounds
allocator blockcache managerallocation, tail waste, publication, COW
kernel blockattention backendtable traversal, thread geometry, vector packing
physical page groupGPU VMM/runtimemap/unmap granularity and physical tail
shared-prefix chunkprefix tree/execution kernelcoverage interval, partial-state count, shared work shape

They may be equal in one implementation. Equality is not part of the semantic contract. A runtime may allocate 32-token blocks while exposing 16-token kernel blocks, or retain a contiguous virtual tensor whose physical page group contains hundreds of token rows without exposing that page group to the attention kernel at all.

0x09A The Cost Vector Cannot Be Collapsed Before Measurement

No one scalar objective is portable across runtimes:

C(P_a, P_k, G, P_c; workload, backend) = (
    unique tail bytes,
    request-map and block-descriptor metadata,
    full-block prefix-hit granularity,
    allocator transitions,
    copy-on-write capacity,
    kernel block-table traversal and packing,
    VMM page-group tail and mapping operations,
    shared-prefix chunk visits and partial states
)

The first two components are executable in Loop 3. Hash publication is deepened in Loop 6, copy-on-write in Loop 5, and kernel addressing in Loop 4. Keeping the vector open prevents this section from choosing a block size with a fabricated weighted score.

0x09B Derive Storage, Metadata, And Hit Granularity Separately

The checked fixture holds these facts constant:

request lengths        = [33, 25, 16]
relationship           = every shorter sequence is an exact prefix of A
local row bytes        = 64 KiB
provisioned pool       = 128 token slots
metadata record sizes = synthetic constants declared in the fixture

For request length , allocator block size , and row payload :

Request-view tail counts every map independently. Under the nested-prefix fixture, unique physical capacity instead follows only the longest materialized path:

Renderer-safe fallback:

request_blocks(r) = ceil(T_r / P_a)
request_tail(r)   = request_blocks(r) * P_a - T_r
unique_blocks     = ceil(max_r T_r / P_a)
unique_tail       = unique_blocks * P_a - max_r T_r

The synthetic metadata ledger is not “metadata proportional to blocks” in the abstract. It names each declared record family:

Changing only gives:

tokensBlock bytesRequest refsUnique blocksRequest-view tailUnique tailPool descriptorsSynthetic metadata
4256 KiB2096 slots3 slots321,522 B
8512 KiB11514 slots7 slots16830 B
161 MiB6322 slots15 slots8482 B
322 MiB4254 slots31 slots4310 B
644 MiB31118 slots31 slots2214 B

At P=4, unique tail is only 3 * 64 KiB = 192 KiB, but the fixed 128-slot pool needs 32 descriptors and the three request maps contain 20 entries. At P=32, metadata falls, while one unique partial block leaves 31 * 64 KiB = 1.9375 MiB uninitialized. Request-view tail is larger still because it counts the shorter prefix views independently.

The table’s sharing assumption describes storage identity, not a claim that a specific runtime will publish or match every partial prefix at every candidate block size. Full-block prefix-cache policy can reduce runtime-admissible hits even when an abstract exact-prefix storage layout is possible.

Smaller blocks generally improve tail granularity and copy-on-write bounds but increase maps, descriptors, hash entries, transitions, and kernel traversal. Larger blocks reverse those pressures. Dtype packing, cache-group alignment, hardware page behavior, and measured kernel performance still have to join the decision before a deployment chooses .

Full-block-only prefix publication adds a different staircase. If A’s 33-token path exists before exact-prefix requests B and C of lengths 25 and 16, and neither needs next-token logits (so the 0x07A logits cap does not apply), the reusable lengths are

Full-block hit across B+CRecomputed prompt tailImmutable-partial-tail alternative
440 tokens1 token41 tokens reusable
840 tokens1 token41 tokens reusable
1632 tokens9 tokens41 tokens reusable
320 tokens41 tokens41 tokens reusable
640 tokens41 tokens41 tokens reusable

The table and the cost-vector figure at the end of 0x09C count these uncapped hits, which isolate block granularity. A logits-producing generative request takes the 0x07A cap first:

For the full-block hit across B+C then becomes 36, 32, 16, 0 and 0 tokens, and the recomputed prompt tail 5, 9, 25, 41 and 41 tokens. The immutable-partial-tail alternative is capped too, as in 0x07D, and reuses 39 tokens (24 for B, 15 for C). At , C is the one-block edge of 0x07E: its cap of 15 rows aligns down to zero, and its whole block is recomputed.

This does not prove partial-tail publication is preferable. It exchanges recomputation for a stronger immutable-frontier identity and, after a branch, copy-on-write work.

0x09C Copy-On-Write Has Useful-Byte And Capacity Amplification

Let two requests share 20 tokens and diverge at the next append. The valid shared-tail rows are

When , the prefix ends at a block boundary and the divergent request can allocate a fresh block without copying a tail. Otherwise one exact COW path copies useful rows but reserves one private block of rows:

Valid shared tailCopy trafficDestination capacityCapacity/useful row
4000boundary
84 rows512 KiB512 KiB2.0x
164 rows512 KiB1 MiB4.0x
3220 rows2.5 MiB2 MiB1.6x
6420 rows2.5 MiB4 MiB3.2x

Copy traffic counts source read plus destination write; destination capacity counts the newly owned block. They answer different questions. The exact values depend on where a branch falls, so an average COW cost requires the workload’s branch-offset distribution, not just its mean prompt length.

Four, sixteen, and sixty-four token blocks move physical tail, metadata, kernel table lookup, shared partial-state, prefix-recompute, and copy-on-write ledgers in opposite directions; only sixteen is supported by the pinned vLLM launcher among the three displayed examples.

0x0A What A Paged Decode Kernel Actually Loops Over

The exact translator in 0x03 resolves one scalar. A decode kernel hoists the same metadata and traverses bounded block segments rather than repeating every check for every lane:

For context length and kernel block size :

If a long row is split into reduction partitions of tokens and divides :

The first quantity counts kernel-visible block-table traversal. The second controls independent partial states and a later reduction. Allocator blocks, kernel blocks, and reduction partitions are therefore three separate levels.

def paged_decode_one_row(q, snapshot, request_id, layer, kv_head):
    request = snapshot.requests[request_id]
    group = unique_group_containing(layer)
    block_size = group.block_size
    table = request.block_tables_by_group[group.id]
    state = empty_online_softmax_state()
    num_blocks = ceil_div(request.context_length, block_size)

    for logical_block in range(num_blocks):
        physical_id = table[logical_block]
        desc = group.descriptor(group.pool_generation, physical_id)

        valid_rows = block_size
        if logical_block == num_blocks - 1:
            valid_rows = request.context_length % block_size or block_size
        assert valid_rows <= desc.valid_rows

        K = load_group_tile(group, "K", layer, kv_head, desc, valid_rows)
        V = load_group_tile(group, "V", layer, kv_head, desc, valid_rows)
        scores = q @ K.T * scale
        state = online_attention_update(state, scores, V)

    return finalize(state)

0x0AA Pinned vLLM Source Trace: BLOCK_SIZE Changes The Kernel

At pinned revision 0fc695fc..., the libtorch-stable paged-attention source does not treat BLOCK_SIZE as an inert runtime label. It is a compile-time template parameter that participates in:

num_seq_blocks          = ceil(seq_len / BLOCK_SIZE)
num_blocks_per_partition = PARTITION_SIZE / BLOCK_SIZE
thread_group_size       = max(warp_size / BLOCK_SIZE, 1)
tokens_per_thread_group = ceil(BLOCK_SIZE / warp_size)
value vector width      = min(16 / sizeof(scalar), BLOCK_SIZE)

The kernel first chooses the request row of block_tables, reads physical_block_number = block_table[block_idx], and then combines that number with kv_block_stride, kv_head_stride, and the in-block offset. That is the code-level form of the 0x03 address derivation.

For the checked , , warp size 32, FP16 scalar fixture:

Sequence blocks / table readsFull-partition blocksThread groupValue-vector tokensPinned V1 launcher
451312884unsupported
82576448supported
161293228supported
32651618supported
6433818unsupported

All five rows have five long-context partitions. They do not have the same block-table traffic or thread geometry. The pinned V1 launcher instantiates only 8, 16, and 32; its source says other listed sizes were omitted to reduce compilation time. That is a source-revision observation, not a claim that every vLLM backend supports exactly those sizes.

The vAttention paper reports normalized vLLM paged-decode runtime for token block sizes 16, 32, 64, and 128 on Llama-3-8B with one A100. These are source-reported measurements, not Loop 10 oracle results.

Source: Prabhu et al., vAttention, Figure 3. The figure establishes that block-size performance can be non-monotonic and backend-specific; it does not establish a universal best block size.

0x0AB Ragged Requests Create A Second Traversal Ledger

For request block counts , a dense rectangular staging table with rows and columns contains

Using lengths [64,63,17,1]:

Per-request blocksDense cellsUsedPaddingDense table bytes
4[16,16,5,1]643826256 B
8[8,8,3,1]322012128 B
16[4,4,2,1]1611564 B
32[2,2,1,1]86232 B
64[1,1,1,1]44016 B

The byte totals are tiny because the fixture has four requests. The scaling law is the point: a few long rows can set n_max for every short row. Compact or ragged table encodings can reduce padding but introduce offsets, lengths, packing work, or more irregular lookup. This article records the address and byte contract; M5.2 owns which requests become co-resident.

0x0AC Allocator Blocks May Be Split For A Kernel

The pinned vllm/v1/worker/block_table.py receives allocator block_size and kernel_block_size separately. Its supported hybrid direction is

Allocator block ID expands to

For P_a=32, P_k=16, allocator IDs [3,7] become kernel IDs [6,7,14,15]. The physical payload did not duplicate, but the kernel-visible table gained twice as many entries. For P_a=64, P_k=16, one allocator ID expands to four kernel IDs.

The reverse direction is not a free mapping. A kernel block larger than an allocator block would require a guarantee that several separately allocated objects form the exact contiguous layout expected by that kernel, or a gather path with a different ABI. The pinned helper therefore rejects a kernel size that does not divide the allocator size.

Paged attention traverses a request block table and physical descriptors, hybrid layout splits allocator blocks into smaller kernel blocks, vAttention uses contiguous virtual offsets and GPU page tables, and prefix-tree execution traverses immutable chunks and exact partial states.

Production kernels vectorize across requests, heads, blocks, and dimensions. They may split one long context across workers and reduce partial states as M4.5 derives. The implementation path remains:

request snapshot
    -> cache-group table and pool generation
    -> physical descriptor and bounded tile
    -> online softmax state

At minimum, a batched paged kernel needs:

request generation and block-table version
context length and number of logical blocks per group
group table, pool identity/generation, and physical descriptors
request-visible tail and physical valid length
K/V head mapping
layer-local index, K/V bases, axis order, shapes, and strides
position or mask limits

Variable-length batching therefore has two kinds of raggedness:

ragged token lengths
ragged physical block lists

The kernel must not read padding slots in a partially filled block as valid history. Those slots may contain stale data from a recycled physical block.

Append And Copy-On-Write Edge Case

Suppose requests A and B share a 20-token prefix with block size 16:

shared full block:
    positions 0..15

shared partial block:
    positions 16..19
    free slots 20..31

If A and B generate different token 20 values, both cannot append into the same partial block. Copy-on-write must occur before the first divergent append, even though the block is not full.

def append_token(req, k_row, v_row):
    tail = req.block_table[-1]

    if tail.has_free_slot() and refcount[tail] == 1:
        return write_next_slot(tail, k_row, v_row)

    if tail.has_free_slot() and refcount[tail] > 1:
        private_tail = copy_valid_prefix_of_block(tail)
        replace_tail_mapping(req, private_tail)
        return write_next_slot(private_tail, k_row, v_row)

    new_block = allocate_block()
    req.block_table.append(new_block)
    return write_next_slot(new_block, k_row, v_row)

Copying one valid tail block preserves exactness. Copying the entire request cache would preserve exactness too, but would erase much of the sharing benefit.

0x0B Exact Prefix Reuse Has Multiple Execution Designs

Prefix caching is often taught as one mechanism:

find token-prefix hit -> reuse K/V -> prefill suffix

A25 distinguishes several systems because they optimize different repeated work. The distinction matters most after prefill. Two requests can reference the same exact K/V rows and still make an ordinary decode kernel read those rows once per request:

storage reuse:
    one physical shared-prefix K/V object

ordinary decode execution:
    request 0 reads the object
    request 1 reads the object again
    request 2 reads the object again

Loop 6 proved whether the rows are semantically reusable. Loop 7 proved how a prefix tree indexes and protects them. Loop 9 begins only after those receipts exist. Its owner question is narrower:

Given an immutable batch snapshot whose sequence paths reference exact shared K/V chunks, how can a kernel partition shared-prefix and unique-suffix attention, execute each partition in a useful shape, and merge the partial states into exactly the same attention row?

This is execution reuse. It is neither a new cache-identity rule nor a scheduling policy.

0x0BA One Score Row, Disjoint Key Partitions, One Denominator

For one query row , let sequence ‘s legal keys be partitioned into disjoint sets:

may be a global system-prompt prefix. A second partition may be shared only by one subtree, and the final partition may be private to the request. The score for key row is

The full row is not the average of the local outputs. Each independently computed partition must preserve its softmax mass alongside its output information. The general common-denominator proof and stable LSE merge are owned by M4.3, section 0x09E. M5.3 consumes that merge; its additional contract is that each sequence’s chunk path covers the legal keys exactly once, using the same query row, score convention, mask, and immutable execution snapshot.

The partition API carries the canonical state, including its valid-key count:

For a valid partition, the adapter to Hydragen’s LSE/output coordinates is:

The consumer keeps the coordinate conversion explicit without rederiving the upstream merge:

LSE_p = m_p + log(l_p)
O_p   = u_p / l_p

# Merge valid partial states with the M4.3 LSE/output operator.
# Never average independently normalized prefix and suffix outputs.

The empty partition is a two-sided identity, not a valid row with . Branch on valid before any expression resembling .

The canonical online state, Hydragen LSE state, and ChunkAttention partial state retain equivalent partition mass and output information, while averaging local normalized outputs loses the denominator.

0x0BB The Execution Snapshot Is A Tensor Contract

The partition identity is valid only for one immutable execution snapshot:

tree version and tree-state digest
sequence order
query row for each sequence
ordered chunk path for each sequence
chunk identity digest and coverage interval
K/V shape, head mapping, dtype, scale, and position contract
shared/private execution threshold

The Loop 9 fixture uses one decode query per sequence:

Q: [B=4, H_q=1, T_q=1, d_qk=2]
each K_chunk: [T_chunk, H_kv=1, d_qk=2]
each V_chunk: [T_chunk, H_kv=1, d_v=3]
scale denominator: sqrt(2)
numeric oracle: binary64

Production kernels may use GQA head expansion, FP16/BF16 inputs, FP32 state, quantized K/V, or different axis orders. Those are cache-ABI fields, not details to infer from a tensor’s rank. The checked fixture deliberately keeps one head and tiny widths so every path and state is inspectable.

Its tree is:

C0_global, 2 K/V rows, covers sequence indices [0,4)
├── C1_left_shared, 1 row, covers [0,2)
│   ├── C3_private_S0, 2 rows, covers [0,1)
│   └── C4_private_S1, 1 row, covers [1,2)
└── C2_right_shared, 2 rows, covers [2,4)
    ├── C5_private_S2, 1 row, covers [2,3)
    └── C6_private_S3, 1 row, covers [3,4)

The half-open intervals are not decorative. They let a chunk-first kernel map one chunk to a contiguous query-row range. Reordering active sequences without rebuilding those intervals would make the metadata stale even if the K/V bytes were unchanged.

Cache Lookup Reuse

Paged prefix caching and RadixAttention primarily answer:

Which exact prefix K/V blocks already exist?
Which requests or tree edges reference them?
When should they be retained or evicted?

They reduce repeated K/V projection and prompt prefill for a matching prefix. They do not automatically optimize repeated reads of a shared prefix during every decode step.

0x0BC Hydragen: Batch Queries Over Identical Shared K/V

Hydragen starts from a batch whose requests share prefix K/V but have unique suffixes. For request r:

K_r = [K_shared ; K_suffix_r]
V_r = [V_shared ; V_suffix_r]

An ordinary per-request decode schedule sees a matrix-vector product against the shared prefix for every request. Hydragen concatenates or reshapes the queries that share that K/V object and turns the shared part into a larger matrix operation:

shared:
    Q_shared [B_group, T_q, H_q, d_h]
    K_shared [T_shared, H_kv, d_h]
    V_shared [T_shared, H_kv, d_v]
    -> O_shared [B_group, T_q, H_q, d_v]
    -> LSE_shared [B_group, T_q, H_q]

unique:
    Q_unique [B_group, T_q, H_q, d_h]
    K_unique [B_group, T_unique, H_kv, d_h]
    V_unique [B_group, T_unique, H_kv, d_v]
    -> O_unique, LSE_unique

merge:
    (O_shared, LSE_shared) + (O_unique, LSE_unique)
    -> O_exact

The systems gain is not that one query avoids attending to its prefix. Every query still has the same logical query-key pairs. The gain is that shared K/V can be loaded and reused while several query rows are processed, changing matrix-vector-shaped work into matrix-matrix-shaped work.

def hydragen_level(Q_group, K_shared, V_shared, K_unique, V_unique):
    O_shared, LSE_shared = attention_with_lse(
        Q_group,
        broadcast_shared(K_shared, group=Q_group.shape[0]),
        broadcast_shared(V_shared, group=Q_group.shape[0]),
    )
    O_unique, LSE_unique = attention_with_lse(
        Q_group, K_unique, V_unique
    )
    return merge_lse(
        [O_shared, O_unique],
        [LSE_shared, LSE_unique],
    )

The Hydragen repository’s pinned hydragen/attention.py makes the state contract concrete: its Torch path stacks partition outputs and LSE tensors, subtracts the maximum LSE, exponentiates the differences, and uses the resulting masses to combine outputs. Its Triton path specializes the two-partition merge. The implementation also supports multiple shared levels; a group size at one level may divide a larger group at another level.

def hierarchical_hydragen(snapshot):
    per_sequence = [[] for _ in snapshot.sequences]

    for chunk in snapshot.chunks_in_tree_order:
        begin, end = chunk.coverage
        Q_group = snapshot.Q[begin:end]
        O, LSE = attention_with_lse(Q_group, chunk.K, chunk.V)

        for local_row, sequence in enumerate(range(begin, end)):
            per_sequence[sequence].append((O[local_row], LSE[local_row]))

    return [
        merge_lse(outputs, lses)
        for outputs, lses in map(unzip, per_sequence)
    ]

The teaching pseudocode exposes one logical call per chunk. A production Hydragen implementation can fuse, reshape, or use variable-length kernels; the invariant is the same disjoint score partition and LSE-aware merge.

Hydragen separates shared-prefix and unique-suffix attention, batches queries over shared K/V, and merges the exact partition outputs. Source figure retained from A25; originally based on the Hydragen paper.

Hydragen derives the whole-row denominator from partition denominators before rescaling partial outputs. Source figure retained from A25; notation is supplemented by the renderer-safe derivation above.

0x0BD ChunkAttention: Prefix Tree Plus Two-Phase Kernel

ChunkAttention couples a prefix-aware K/V tree to a different execution schedule. Each ChunkInfo in the pinned repository binds one chunk to a half-open sequence-index interval:

(chunk pointer, seq_idx_begin, seq_idx_end)

The runtime classifies chunks by coverage. A shared chunk enters the chunk-first phase; a private or below-threshold chunk stays in the sequence-first phase. The threshold is a tunable implementation decision, not a semantic distinction.

chunk-first phase:
    traverse chunks shared by several sequences
    batch those sequences' queries against one shared K/V chunk
    save partial online-softmax states

sequence-first phase:
    load each sequence's shared partial states
    traverse its private suffix chunks
    merge every partial state into the final row
def build_chunk_first_metadata(chunks, threshold):
    begins, ends, offsets = [], [], []
    partial_rows = 0

    for chunk in chunks:
        begin, end = chunk.coverage
        if end - begin <= threshold:
            continue
        begins.append(begin)
        ends.append(end)
        offsets.append(partial_rows)
        partial_rows += end - begin

    return begins, ends, offsets, partial_rows


for chunk_id, begin, end, offset in shared_chunk_metadata:
    Q_group = Q[begin:end]
    partial[offset:offset + end - begin] = partial_attention_state(
        Q_group, chunks[chunk_id].K, chunks[chunk_id].V
    )

for request in active_requests:
    state = empty_state()
    for chunk in request.path:
        if chunk.was_materialized_chunk_first:
            part = partial[chunk.offset + request.index - chunk.begin]
        else:
            part = partial_attention_state(
                request.q, chunk.K, chunk.V
            )
        state = merge_online_states(state, part)
    output[request] = finalize(state)

The pinned CUDA source constructs begins, ends, and offsets on the host, transfers the metadata, allocates

attns:    [partial_rows, H_q, d_v]
maxsums:  [2, partial_rows, H_q]

and then lets sequence-first execution load the saved partial output, maximum, and denominator state. In that source revision, partial outputs use the output scalar type while maximum and sum use float. This is a source observation, not a recommendation that every implementation use the same dtype split.

Why materialize partial states rather than directly accumulate into the final sequence output? Materialization gives chunk-first work independent output rows and avoids parent/child update ordering or atomic reduction inside the shared phase. It costs temporary memory and a later read. A direct-reduction alternative could reduce that buffer, but then synchronization, deterministic merge order, and write ownership become first-class kernel contracts.

ChunkAttention maps one prefix tree to chunk-first shared work and sequence-first completion. Source figure retained from A25; originally based on the ChunkAttention paper.

0x0BE One Checked Four-Sequence Trace

The executable fixture runs three attention schedules over the same immutable tree:

reference:
    concatenate each sequence path
    evaluate one monolithic attention row

Hydragen coordinate:
    batch all queries covered by each chunk
    emit (normalized output, LSE)
    merge the three path partitions

ChunkAttention coordinate:
    materialize shared (u, m, l) partial rows
    compute private leaf state during sequence-first
    merge the three path partitions

For every sequence, both partitioned schedules match the monolithic output within absolute error in the binary64 oracle. That is rounding-level agreement in the fixture, not a claim of bitwise equality across GPU kernels, dtypes, or reduction orders.

The work and payload ledgers are:

LedgerPer-request baselineShared executionDifference
Logical query-key pairs19190
K/V rows read from the conceptual physical tree19109 fewer duplicate reads
K/V payload at 10 bytes per toy row190 B100 B90 B avoided
Shared partial rows088 materialized
Shared partial buffer0112 B112 B temporary
Valid binary state merges082 per sequence

The row and temporary-state formulas are:

Renderer-safe checked substitution:

logical pairs        = 19
unique physical rows = 10
saved duplicate reads = 19 - 10 = 9

one toy K/V row = (d_qk + d_v) * 2 B
                = (2 + 3) * 2 = 10 B

baseline K/V payload = 19 * 10 B = 190 B
shared K/V payload   = 10 * 10 B = 100 B

partial rows = coverage(C0) + coverage(C1) + coverage(C2)
             = 4 + 2 + 2 = 8
partial row  = d_v * 2 B + max * 4 B + sum * 4 B
             = 3 * 2 + 8 = 14 B
partial buffer = 8 * 14 B = 112 B

The K/V-read ledger is a conceptual payload model: it excludes query reads, output writes, metadata, cache-line effects, kernel launches, partial-state traffic, and hierarchy behavior. It proves what the fixture counts; it does not predict latency.

A four-sequence prefix tree is executed first by three shared chunk batches and then by four private sequence completions, with exact partial-state offsets, K/V-row payload, and merge counts.

0x0BF Design Choices Are Workload And Kernel Contracts

ChoiceBenefitCost or constraint
Ordinary per-sequence decodesimple integration; no partial buffershared K/V read once per sequence
One shared prefix plus private suffixsimple Hydragen decompositionmisses deeper hierarchical sharing
Hierarchical Hydragen levelsshares work at several tree verticesgroup geometry, varlen metadata, and more merges
Chunk-first materializationindependent shared work; simple sequence completiontemporary output/max/sum buffer and reread
Direct shared-state reductionmay reduce temporary trafficserialization, atomics, ownership, and merge-order constraints
Coverage threshold avoids batching tiny groupsworkload- and hardware-specific tuning
FP32 state with lower-precision outputstronger normalizer stabilitymore state bytes and conversion behavior

No method dominates by name. The useful regime depends on shared-prefix length, suffix length, group size, hierarchy shape, K/V dtype, query/head geometry, kernel support, memory bandwidth, temporary-state traffic, and scheduler stability. Hydragen and ChunkAttention paper speedups remain source-reported results under their reported workloads and hardware.

Storage and execution mechanisms are composable only if their contracts align:

Loop 6/7:
    exact identity + protected tree path + immutable snapshot

Loop 9:
    coverage metadata + tensor ABI + exact state merge

M5.2:
    whether compatible requests are co-resident and ordered together

M4.5 / backend:
    whether a supported kernel exists for the chosen geometry

0x0BG Source-Observed Runtime Versus Normative Protocol

StatementStatus
Hydragen partitions shared and unique attention and merges using LSE metadata.Externally verified from the paper and pinned repository.
The pinned Hydragen source has Torch and Triton LSE-combine paths.Source-observed at commit 1ea2255d....
ChunkAttention binds chunks to contiguous sequence-index intervals and runs two phases.Externally verified from the paper and pinned repository.
The pinned ChunkAttention source builds begins/ends/offsets and FP output plus float max/sum buffers.Source-observed at commit dde08ce9....
The Loop 9 tree produces 190 B versus 100 B of conceptual K/V payload and 112 B of temporary partial state.Fixture-verified rewrite interpretation.
The oracle replays either CUDA or Triton implementation.False.
The fixture reproduces paper throughput or establishes a universal method ranking.False.

The executable oracle imports M4.3’s pinned online-state implementation rather than silently copying its merge. It also binds the Loop 6 prefix-reuse report and Loop 7 radix-runtime report by SHA-256. Identity, index mutation, allocator state, and scheduling are therefore consumed as immutable inputs.

0x0BH Failure Lab

FailureWhat went wrongRequired rejection or repair
Average locally normalized outputspartition masses differretain denominator or LSE and mass-weight the outputs
Drop LSE from Hydragen stateabsolute softmax mass is gonereject missing_partition_mass
Treat normalized output as state coordinate mismatchconvert coordinates explicitly
Child coverage escapes parenttree path and query group disagreereject coverage_not_nested
Non-contiguous coverage metadataone interval cannot name the covered rowsreorder/rebuild snapshot or use a different index representation
Path omits or reorders an ancestorpartitions no longer describe the sequencereject path_parent_mismatch
Chunk identity digest differs from path receiptK/V partition is stale or foreignreject chunk_identity_mismatch
Same token appears in two path chunksscore sets are not disjointreject duplicate_token_partition
Tree version changes after metadata buildbegin/end/offset rows may address another treereject stale_execution_snapshot
Empty partition marked validinvalid exponent arithmetic can followuse explicit empty identity state
Partial buffer is one row shorta shared query has no saved statereject before sequence-first launch
Kernel reads a shared chunk for an uncovered sequencecross-request state leak and wrong outputcoverage and path checks must dominate launch

0x0BI Loop 10: Shared Work Is Invariant, Traversal Is Not

Loop 9 proved exact state equivalence for one fixed tree. Loop 10 varies the shared-prefix chunk size while holding the logical attention problem constant:

batch B                  = 8
shared prefix S          = 64 tokens
private suffixes U_r     = [8,8,8,8,16,16,16,16]
K/V row payload          = 512 B
partial output width     = 128 FP16 values
partial normalizer state = two FP32 scalars

Ordinary per-sequence execution processes

An idealized exact shared-prefix schedule reads the shared K/V rows once:

For the fixture:

logical K/V rows = 8*64 + 96 = 608
unique K/V rows  = 64 + 96   = 160
saved row reads  = 448

baseline payload = 608 * 512 B = 304 KiB
shared payload   = 160 * 512 B = 80 KiB
saved payload    = 224 KiB

Those row counts do not depend on chunk size. Traversal and temporary state do. For chunk size :

If every shared chunk covers all queries and is materialized separately:

Shared-prefix chunksOrdinary chunk visitsShared schedule visitsAvoided visitsPartial rowsPartial buffer
4161524011212833,792 B
887620566416,896 B
164401228328,448 B
322241014164,224 B
641169782,112 B

Larger chunks reduce metadata and partial-state rows in this regular workload. They do not create more shared K/V savings: the same 448 duplicate row reads are avoidable at every size. If the actual prefix boundaries are irregular, larger chunks may instead reduce exact matches or force a private remainder. The chunk-size decision therefore needs the prefix-length and branch-position distribution, not only one average shared-prefix length.

0x0BJ Physical Page Groups Are Not Paged-Kernel Blocks

vAttention keeps a per-layer K or V tensor virtually contiguous. For one tensor row of bytes and physical page-group size :

is the number of token rows backed by one page group, provided divisibility holds. A request of rows needs

The source-reported vAttention Table 8 gives Llama-3-8B, TP-1 one-layer K or V rows of 2,048 bytes. The checked arithmetic is:

Tokens/page groupTail at 33 tokensTail at 1,024Tail at 1,025
64 KiB3262 KiB062 KiB
128 KiB6462 KiB0126 KiB
256 KiB128190 KiB0254 KiB
2 MiB1,0241,982 KiB02,046 KiB

The 1,024-token row deliberately lands on every page-group boundary. The 1,025th token exposes the staircase again. TP changes the local row width and therefore changes tokens per page; a page-group size cannot be translated into tokens without the tensor manifest.

The kernel-visible address path remains different:

PagedAttention:
    token -> user block table -> physical K/V block -> tensor strides

vAttention:
    token -> contiguous virtual offset -> GPU page-table translation

The Loop 10 oracle assigns zero user-space K/V block-table lookups to the vAttention path. It does not claim zero hardware translation, zero TLB misses, or zero runtime mapping work.

Source-reported vAttention Figure 14 left panel comparing FlashAttention-2 prefill runtime with 2 MiB and 64 KiB page groups on Llama-3-8B.

Source-reported vAttention Figure 14 right panel comparing FlashAttention-2 decode runtime with 2 MiB and 64 KiB page groups on Llama-3-8B.

Source: Prabhu et al., vAttention, Figure 14. The authors report that 64 KiB pages did not materially degrade these tested kernels relative to 2 MiB pages. That observation is tied to their models, kernels, hardware, driver path, and access pattern; it is not a universal theorem that page size cannot affect TLB behavior.

0x0BK Workload Regimes Change Which Ledger Matters

Workload regimePressure exposed by smaller granularityPressure exposed by larger granularityMeasurement needed
many short independent requeststable entries, descriptors, allocation transitionsphysical tail capacityadmitted batch and tail distribution
one long request per batchmany block-table traversalsbackend tile/cache behaviorkernel latency by context/head/dtype
ragged batch with one long requestdense table padding and stagingfewer cells but coarser tailstable build/copy time and decode latency
repeated full-block prefixesmore hash/index objectsfewer admissible hit boundarieshit, recompute, and retained-byte curves
branches inside partial tailssmall COW destination boundslarge private destination capacitybranch-offset and COW traffic distribution
large shared-prefix groupsmore chunk metadata and partial rowscoarse prefix boundariesgroup size, prefix length, partial traffic
contiguous VMM allocationmore map objects with small larger physical tail with large map latency, overlap, tail, TLB counters
allocator/backend size mismatchwider kernel-visible tables after splittingunsupported gather/coalescing directiondispatch support and fallback rate

This table deliberately does not assign a winner. M5.3 can reject an invalid combination and expose its ledgers. M5.2 owns which requests run together; M4.5 owns generic backend kernel selection and measured reduction strategy.

0x0BL A Measurement Protocol, Not A Magic Default

A defensible tuning pass holds semantic work constant and changes one contract at a time:

1. Freeze model/cache ABI:
   layers, local KV heads, head width, dtype/scales, positions, TP, backend.

2. Freeze workload trace:
   prompt/decode lengths, arrival order, prefix groups, branch offsets.

3. Enumerate legal tuples:
   (P_a, P_k, G, P_c) that pass allocator, kernel, VMM, and identity checks.

4. Reconcile structural ledgers:
   tail, metadata, hit/recompute, COW, table cells, visits, partial state.

5. Benchmark isolated kernels:
   prefill/decode separately; report context, batch, heads, dtype, hardware.

6. Replay end to end:
   measure TTFT, inter-token latency, goodput, memory headroom, fallbacks.

7. Hand candidates to M5.2:
   scheduling/admission policy chooses under its SLO and fairness contract.

Required observability includes:

allocator_block_size and kernel_block_size by cache group
kernel dispatch selected/rejected/fallback reason
request refs, unique blocks, valid tails, metadata bytes
full-block hit tokens and recomputed prompt-tail tokens
COW copied rows, traffic bytes, and destination capacity
dense/used/padded block-table cells and transfer bytes
shared group size, chunk visits, partial rows and state bytes
VMM page-group size, mapped groups, ready frontier, map latency

Without those counters, a throughput change cannot be attributed to memory capacity, a different admitted batch, kernel geometry, table preparation, shared-prefix locality, or mapping overhead.

0x0BM Source-Observed Contract Versus Checked Interpretation

StatementStatus
PagedAttention uses fixed-token K/V blocks and a block table for non-contiguous placement.Externally verified.
The pinned vLLM BlockTable can split one allocator block into smaller kernel blocks when divisibility holds.Source-observed at 0fc695fc....
The pinned libtorch-stable paged kernel templates traversal/vector geometry on BLOCK_SIZE.Source-observed at 0fc695fc....
The pinned V1 launcher instantiates block sizes 8, 16, and 32.Source-observed for that launcher and revision only.
vAttention separates contiguous virtual addressing from physical page-group allocation.Externally verified and source-observed.
The vAttention paper reports page-group and paged-kernel block-size sensitivity.Source-reported benchmark evidence.
Loop 10’s five-size rows predict GPU latency.False. They are structural accounting.
The vAttention figures were reproduced locally.False. They are retained source figures.
One tuple is universally optimal.False.

0x0BN Granularity And Traversal Failure Lab

FailureConsequenceRequired response
Use P without naming allocator/kernel/page/chunkincomparable formulas share one symboldeclare all four granularities
Kernel block does not divide allocator blockhybrid IDs cannot preserve source layoutreject backend tuple
Kernel block exceeds allocator blockseparate allocations are assumed contiguousreject or provide a different gather ABI
Launch unsupported pinned block sizeno compiled specialization exists on that pathdispatch another backend or fail explicitly
Partition size is not divisible by kernel blockfull-partition block count is fractionalselect legal partitioning or tail-aware implementation
Full-block hit is not alignedruntime claims rows it did not publishcap to complete compatible blocks
Dense table has fewer cells than used entriestable write/address overflowreject before staging
Tail rows equal or exceed block sizeinvalid frontierreject manifest/state
Copy boundary tail as if partialunnecessary COW and false traffic ledgerallocate a fresh block
Copy fewer rows than the valid shared taildestination loses prefix statereject COW receipt
Count COW capacity as copy trafficmemory and bandwidth ledgers are conflatedreport both separately
Count shared K/V savings once per chunk visittoken-row savings change falsely with keep logical rows invariant
Drop chunk partial-state bytesshared execution appears freecharge output/max/mass writes and rereads
Convert page bytes to tokens without row widthmodel/TP-dependent granularity is wrongbind tensor manifest first
Attribute user block-table lookup to vAttention kerneladdress contracts are conflateduse virtual offset + hardware translation path
Generalize paper TLB observationhardware/workload claim exceeds evidencekeep source-reported scope
Choose a winner from synthetic visitsno latency model was measuredrun isolated and end-to-end benchmarks
Tune with a different workload per candidateblock-size effect is confoundedfreeze immutable trace and ABI

CachedAttention / AttentionStore: Reuse Across Inactive Sessions

Inactive-session reuse begins with an M5.3 question: does the resumed turn match an exact token prefix and cache ABI? CachedAttention/AttentionStore is included here because its reusable session state consumes that identity contract.

The hierarchy itself is not an M5.3 mechanism. GPU/host/storage residency, layer-wise prefetch, asynchronous saving, promotion visibility, and the recompute-versus-resume ledger now live in M5.5. M5.3 hands M5.5 a compatible cache key and covered token interval; M5.5 decides where the bytes live and when they are legal to read.

0x0C Paper-By-Contract And Operational Closure

It is tempting to put every K/V optimization into one table headed by latency or hit rate. That comparison is malformed before it starts. PagedAttention owns physical block placement. vAttention owns virtual-to-physical mapping. Prompt Cache declares reusable modules before requests arrive. RadixAttention discovers exact prefixes at runtime. Hydragen and ChunkAttention reuse attention work inside an active execution geometry. CachedAttention preserves compatible session history across inactive periods.

Those systems can coexist because they do not all own the same object. The first comparison question is therefore:

What object is reusable or mutable, who names it, and for how long is that name valid?

Only after that contract is explicit can a runtime compare traffic, TTFT, throughput, or hit rate.

0x0CA Seven Papers, Five Contract Lanes

The paper registry separates five lanes:

physical layout:
    PagedAttention, vAttention

declared modular reuse:
    Prompt Cache

runtime-discovered prefix reuse:
    RadixAttention

active execution reuse:
    Hydragen, ChunkAttention

inactive-session reuse:
    CachedAttention / earlier AttentionStore wording
Seven K/V systems arranged into physical layout, declared module reuse, runtime prefix discovery, active execution reuse, and inactive-session reuse lanes, with each lane naming its owned object and the contract it hands to another owner

Storage And Discovery Contracts

DesignOwned or reused objectHow the object is foundMutation and lifetime
PagedAttentionfixed-token physical K/V blocks and block-table referencesruntime allocation; an exact sequence may share block referencesallocate, append, fork/share, COW, release, evict during the serving-cache lifetime
vAttentioncontiguous virtual K/V range plus on-demand physical page groupsrequest-slot virtual range and mapping frontierreserve, map, write, retain capacity, reclaim, unmap, release
Prompt Cacheprecomputed attention states for named prompt modulesschema and PML declaration before ordinary request lookuppopulate on schema load; validate and compose when a derived prompt arrives
RadixAttentioncompressed token-prefix edges aligned with K/V slot segmentslongest exact root-to-edge match at runtimematch/split, insert, path lock, release ownership, evict unlocked leaves
CachedAttentioncompatible historical K/V for one inactive sessionsession reactivation plus exact identity and covered-history validationsave, fetch, partially prefill the new turn, publish the extended session

Execution Contracts

DesignKernel-visible contractAvoided workContract it does not prove
PagedAttentionblock table resolves non-contiguous physical blocksreservation waste and duplicate physical storage; exact sharing can skip repeated prefix prefillsemantic authorization or a universal block size
vAttentioncontiguous virtual offset; GPU page tables resolve backingcustom user-space paged address traversalsemantic reuse of retained mappings
Prompt Cachedeclared module states appear at schema-assigned positionsrepeated attention-state computation for common modulesarbitrary-position concatenation or automatic prefix discovery
RadixAttentionimmutable receipt names token path and K/V slotsrepeated exact-prefix prefill and lookup duplicationonline SLO-optimal scheduling
Hydragenone shared K/V partition plus private suffix partitionsduplicate shared-prefix K/V reads and small matrix-vector work across a batchpersistent cache indexing or admission policy
ChunkAttentionchunk ranges, sequence membership, partial-state ABIduplicate shared-prefix storage/reads under a compatible active request treefree temporary state or a universal chunk size
CachedAttentioncompatible historical interval must be resident before userepeated multi-turn historical prefillfree hierarchy movement or M5.3 ownership of tier placement

The table is not a leaderboard. In particular:

  • Prompt Cache and RadixAttention differ in who declares reuse.
  • PagedAttention and vAttention differ in what address the kernel sees.
  • Hydragen and ChunkAttention differ in how an active shared-prefix execution is partitioned.
  • CachedAttention changes lifetime and placement, not the exactness requirement for the reused history.

The alternatives can compose only through receipts. A declared Prompt Cache module can still be stored in paged blocks. A radix-tree hit can feed a Hydragen batch. An inactive session can be restored into a paged or virtual layout. Composition does not erase any intermediate identity, ownership, mapping, or execution gate.

0x0CB Prompt Cache: Declared Reuse Is Not Prefix Discovery

A25 introduced Prompt Cache because not every reusable segment is most naturally discovered as a longest prefix. System messages, templates, and documents may be known before requests arrive. Prompt Cache makes those segments explicit as prompt modules inside a schema.

The retained paper figure first separates three mechanisms. Autoregressive generation recomputes prior state, ordinary K/V caching retains the current request history, and Prompt Cache imports precomputed states for declared segments that may recur across prompts.

Source-retained Prompt Cache figure comparing autoregressive generation, ordinary K/V caching, and reuse of precomputed prompt-module attention states; this is a paper mechanism illustration, not a local benchmark

The hard part is positional identity. A module cannot be moved to arbitrary positions merely because its text is unchanged. The schema assigns relative locations and may leave gaps so parameters or uncached text can occupy their declared slots. This can produce discontinuous position IDs in the assembled prompt. Reuse is exact only under the position contract on which the cached states were computed.

The paper’s schema/module example makes that assembly visible:

Source-retained Prompt Cache schema and PML composition figure showing named modules, parameters, empty schema slots, cached module states, newly computed text, and the assembled prompt positions; the figure is retained from A25 and the Prompt Cache paper

One typed teaching contract is:

@dataclass(frozen=True)
class PromptModuleReceipt:
    schema_id: str
    schema_generation: int
    module_id: str
    module_parameters_digest: str
    token_ids: tuple[int, ...]
    position_ids: tuple[int, ...]
    semantic_manifest_digest: str
    layout_manifest_digest: str
    namespace_id: str
    namespace_generation: int
    physical_refs: tuple[PhysicalRef, ...]

The receipt has two independent equal-length sequences:

Matching module text while changing the position sequence is not a hit:

where is the token sequence, is the position sequence, is the schema/generation contract, and is the semantic cache ABI. The product is Boolean conjunction, not a probability model.

def assemble_declared_prompt(prompt, schema, module_cache, namespace):
    authorize(namespace)                         # before cache lookup
    parsed = parse_pml(prompt)
    require(parsed.schema_id == schema.schema_id)
    require(parsed.schema_generation == schema.generation)

    segments = []
    for item in parsed.items_in_prompt_order:
        declared = schema.resolve(item.module_id)
        positions = declared.positions_for(item.parameters)

        if item.is_cached_module:
            receipt = module_cache.lookup(
                schema=schema.identity,
                module=item.module_id,
                parameters=item.parameters,
            )
            require(receipt.token_ids == tokenize(item.rendered_text))
            require(receipt.position_ids == positions)
            require_compatible(receipt, namespace, current_cache_abi())
            acquire_leases(receipt.physical_refs)
            segments.append(receipt)
        else:
            segments.append(compute_at_positions(item, positions))

    return concatenate_in_declared_position_order(segments)

This is a paper-by-contract alternative, not a recommendation that every prompt adopt PML. It transfers complexity from online prefix discovery to schema authoring, module population, position reservation, invalidation, and application integration.

ChoiceBenefitTransferred cost or failure
schema-declared modulesreuse can include known non-prefix segmentsschema/version lifecycle and position planning
runtime-discovered exact prefixesno application schema requiredlookup/index mutation and dependence on observed prefix overlap
fixed module positionscached states have stable positional meaninggaps and discontinuous positions must be supported correctly
recompute moved modulesimple correctness fallbackloses the intended reuse for that segment

0x0CC CachedAttention: Inactive Lifetime Is A Cross-Article Handoff

The paper now titled CachedAttention appeared with AttentionStore terminology in an earlier version and in A25’s retained figure. Its central observation is that a multi-turn session often discards historical K/V when it becomes inactive, then recomputes the same history when the next user turn arrives.

Source-retained AttentionStore or CachedAttention figure comparing repeated full-history prefill with loading compatible historical K/V and prefilling only the new turn; hierarchy transfer and speed are source mechanisms, not local measurements

For a session with historical interval and new user tokens , the logical work boundary is:

The article does not infer latency from these token counts. Loading rows from another tier can be slower than recomputation for some hardware, models, or queue states. M5.3 emits:

SessionReuseReceipt:
    authorized session and tenant identity
    model/cache semantic digest
    physical representation/layout digest
    exact covered token interval [0, H)
    position/truncation contract
    publication generation
    source-tier object identity

M5.5 then owns:

tier location and directory
fetch/prefetch timing
promotion and demotion
layer-wise loading
asynchronous saving
fallback to recomputation
scheduler-aware tier placement

The ownership handoff is M5.3 identity receipt -> M5.5 placement, loading, and fallback; neither side may silently reinterpret the other’s receipt.

A matching session ID is therefore only one field. Reusing a prior turn after an adapter change, model replacement, position-contract change, cache quantizer change, namespace rotation, or incomplete save is a compatibility failure even if the conversation label is unchanged.

0x0CD One Reuse Attempt Is A Versioned Concurrency Protocol

Loops 2-10 introduced versions at their local ownership boundaries. Loop 11 closes them into one use receipt. For the checked synthetic path, the evidence tuple is:

with namespace generation , semantic and layout digests, index and tree versions, physical-pool generation, ready mapping frontier, and execution snapshot version. These coordinates do not necessarily live in one runtime struct. They are the evidence that must remain mutually consistent.

The use gate is:

An index match with is not an executable hit.

A versioned exact-reuse transaction authorizes before lookup, validates semantic and layout identity, acquires leases, validates index tree and pool generations, waits for mapping readiness, freezes an execution snapshot, executes, then releases or atomically publishes a successor; concurrent eviction, namespace rotation, and mapping lag are rejection paths

The checked transaction order is:

1. authorize namespace before any cache-existence lookup
2. build semantic/layout key and validate namespace generation
3. lookup candidate; retain collision witness if policy requires it
4. acquire path and physical-object leases
5. validate index version, tree version, pool generation, valid frontiers
6. validate declared-module positions or session interval when applicable
7. wait until physical mapping covers every dereferenced row
8. freeze immutable execution snapshot and kernel ABI
9. execute
10. release leases, or publish one complete COW successor atomically
def acquire_executable_reuse(request, expected, runtime):
    runtime.auth.authorize(request.principal, expected.namespace_id)

    candidate = runtime.index.lookup(expected.concrete_key)
    require(candidate.namespace_generation == expected.namespace_generation)
    require(candidate.semantic_digest == expected.semantic_digest)
    require(candidate.layout_digest == expected.layout_digest)
    verify_collision_witness(candidate, expected)

    leases = runtime.ownership.acquire(candidate.path_and_physical_refs)
    require(leases.cover(candidate.path_and_physical_refs))
    require(runtime.index.version == expected.index_version)
    require(runtime.tree.version == expected.tree_version)
    require_all_pool_generations(candidate, expected.pool_generations)
    require_all_valid_frontiers(candidate, expected.covered_interval)

    runtime.mapper.wait_ready(candidate.required_mapping_frontier)
    snapshot = runtime.execution.freeze(candidate, leases)
    require(snapshot.version == expected.execution_snapshot_version)

    return ExecutableReuseReceipt(candidate, leases, snapshot)

Race Closure

RaceUnsafe interleavingRequired fence or recovery
lookup versus evictioncandidate is found, then its last physical object is recycledacquire lease before use; generation mismatch rejects stale receipt
reader versus COW appendreader observes one cache group before successor publication and another afterimmutable predecessor plus atomic multi-group successor publication
radix split versus delayed matchcompressed edge mutates after match but before slot consumptiontree version and path lease; retry from root on mismatch
virtual slot reuse versus delayed kernelold request generation dereferences retained mapping under a new ownerrequest-slot generation and execution snapshot validation
namespace rotation versus cache lookupold object is exposed under a successor tenant/model namespaceauthorize first; generation-scoped index; reject stale generation
Prompt Cache module invalidation versus assemblyschema positions or module text change after module lookupschema generation and module receipt; recompute or repopulate
session save versus resumeresumed request observes partially persisted historypublish covered interval only after complete save; otherwise recompute
execution sharing versus tree mutationHydragen/ChunkAttention coverage changes during kernel executionfreeze immutable execution snapshot; mutate only in a successor version

The paper sources motivate the individual mechanisms. The unified transaction is a checked rewrite interpretation. The Loop 11 oracle validates ordering and rejection reasons; it does not prove a production implementation linearizable under real threads.

0x0CE Security Isolation Is Part Of Exactness

K/V bytes are derived from private prompt content. A numerically exact hit in the wrong tenant is a security failure. Security is therefore not an optional layer applied after cache correctness.

Authorization Before Lookup

The safe order is:

authenticate principal
    -> authorize cache namespace
    -> validate namespace generation
    -> construct or expose candidate lookup
    -> validate semantic/layout compatibility
    -> acquire reusable object

Looking up first and rejecting later can still disclose cache existence through hit/miss timing or counters.

Salt, Hash, Authorization, And Witness Are Different Controls

The vLLM prefix-caching documentation describes cache_salt entering the first block hash so requests sharing a trust group can reuse one another’s blocks. That is a useful isolation key. It is not authentication, authorization, namespace revocation, or a guarantee that every timing channel is closed.

ControlQuestion answeredWhat it does not answer
authenticationwho is making the request?which cache namespace is allowed
authorizationmay this principal discover and reuse this namespace?whether candidate bytes are compatible
namespace generationis this authorization/cache epoch current?whether two key inputs collided
cache saltshould otherwise equal prefixes enter the same hash ancestry?principal identity and access policy
cryptographic digestis accidental or adversarial key collision sufficiently hard under the selected policy?semantic/layout compatibility omitted from the key
collision witnessdid this candidate preserve the exact key material expected by the policy?ownership or physical liveness

Revocation And Purge

A purge cannot mean only “delete the hash-table entry.” A strict namespace revocation protocol is:

1. stop admitting requests to namespace generation g
2. advance the authorized namespace generation to g+1
3. invalidate index candidates from g
4. wait for or cancel live leases from g
5. release or overwrite physical objects according to the threat model
6. remove external-tier copies through the M5.5 directory
7. emit completion only when no executable receipt from g remains

Whether released memory must be zeroed immediately depends on allocator and hardware isolation. The invariant is narrower and mandatory: stale bytes must never become visible to a new owner merely because a physical ID or virtual slot was recycled.

Telemetry Hygiene

Metrics need stable low-cardinality identifiers, not raw prompts, token lists, or unsalted concrete cache keys. The checked fixture rejects both raw_prompt_in_metrics and unsalted_cache_key_in_metrics. Debug traces that must preserve a witness need access controls, retention limits, and an explicit incident workflow; they should not silently become normal metrics.

0x0CF Observability Must Reconcile State

A single prefix hit rate cannot identify the failing contract. Loop 11 uses a monotone funnel:

The checked synthetic counts are:

requests                 12
authorized lookups       11   (1 authorization rejection)
candidate matches         9   (2 index misses)
compatible matches        7   (2 semantic/layout rejections)
current generations       6   (1 stale generation)
leased objects            6
mapping-ready receipts    5   (1 mapping frontier lag)
current snapshots         4   (1 stale execution snapshot)
executed hits              4

Every difference has one rejection bucket. Reporting only 4/12 as a hit rate hides whether the workload stopped sharing prefixes, an adapter changed, the allocator recycled objects, mappings lagged, or a concurrent mutation invalidated the snapshot.

An observability funnel reduces twelve requests through authorization, candidate, compatibility, generation, lease, mapping, snapshot, and execution gates, while allocator partition, refcount reconciliation, mapping lag, and security counters identify the failed contract

Reconciliation Gauges

For a snapshot whose allocator states are declared mutually exclusive:

The fixture checks:

12 = 3 free + 2 evictable + 5 live + 2 reserved/copying

Refcounts need a reachability oracle:

where derived references include request maps and active leases under the Loop 5 convention. The checked snapshot has . A nonzero value is not a performance metric; it is an ownership-integrity alert.

Mapping readiness is similarly directional:

The checked path has . A positive lag blocks execution even if virtual addresses are reserved and candidate identity is exact.

Counter Families And Alert Meaning

FamilyMinimum dimensionsDiagnostic meaning
identityauthorized lookups, candidate/compatible/current hits, rejection reasonworkload miss versus compatibility or stale-state rejection
securitycross-namespace rejects, stale namespace generation, salt-policy rejects, purge leasesisolation policy operation without exposing prompt material
allocatorfree, evictable, live, reserved/copying blocks; allocation failures; COW rows/bytescapacity exhaustion, lock pressure, transaction backlog
ownershiprecorded and derived refs, leases, stale-handle rejectsleak, undercount, delayed user, or ABA attempt
index/treelookup depth, splits, inserts, version retries, locked-eviction rejectsmetadata pressure and concurrent mutation
mappingrequired/ready frontier, map latency/failures, retained inactive bytesVMM readiness versus identity or allocator pressure
executionlogical and unique K/V rows, partial-state bytes, merge rejects, kernel fallbackstorage hit versus actual shared execution
inactive sessioncompatible history bytes, covered interval, promotion wait, recompute fallbackM5.3 identity outcome handed to M5.5 placement

Useful alerts are joint predicates, not isolated thresholds:

allocator exhaustion:
    free == 0 and evictable == 0 and allocation_failures rising

locked-cache pressure:
    free == 0 and evictable > 0 and locked_eviction_rejects rising

reference leak:
    recorded_refcount - derived_refcount != 0 after grace interval

mapping stall:
    required_frontier > ready_frontier and map_wait_age > SLO budget

compatibility churn:
    candidate_matches stable and compatible_matches falling

stale receipt race:
    candidate_matches stable and generation/version rejects rising

security boundary pressure:
    cross_namespace_rejects or stale_namespace_rejects rising

M5.2 owns the SLO budget and service response. M5.3 owns the factual counters that tell M5.2 why an otherwise attractive request is not physically executable.

0x0CG Cumulative Failure Closure

Loops 2-10 already carried negative fixtures for identity, accounting, addressing, allocator lifecycle, exact-prefix reuse, radix mutation, vAttention mapping, shared-prefix execution, and granularity sensitivity. Loop 11 binds all nine prior reports and fixture hashes before adding its own failures:

Loop 2-10 negative cases = 184
Loop 11 negative cases   = 27
cumulative checked cases = 211

This number is not coverage of every production failure. It proves that the named teaching contracts have deterministic rejection paths and that Loop 11 did not silently replace earlier evidence.

Failure classDetectable invariantRecovery or containment
unauthorized lookupauthorization gate must precede candidate lookupreject without exposing cache existence
namespace/schema/session mismatchcurrent identity and generation equal receiptreject; select current namespace/schema/session state
semantic or layout mismatchcompatibility digests equalrecompute into a compatible cache object
collision witness mismatchwitness equals expected key materialreject candidate; invalidate and investigate index entry
stale index/tree/pool generationevery version equals frozen receiptrelease leases and retry lookup from current root
expired or incomplete leaselease covers every path/object consumedreject execution; reacquire from current state
mapping failure or lagready frontier covers required intervalwait, retry mapping, or hand recomputation/tier fallback to policy owner
locked evictioneviction target has no active path/object leasechoose another victim or reject allocation
incomplete COWcopy and appended writes finish before atomic publicationrollback unpublished destination
non-atomic group publicationall cache groups switch in one successorrollback before publication; compensate after publication
Prompt Cache position mismatchtoken and declared position sequences matchrecompute module at current positions or repopulate schema
incomplete inactive-session historycovered interval and save generation matchfetch complete object or recompute missing history
raw prompt/key telemetrymetrics contain no prompt material or unsalted keydrop field, rotate affected identifiers, audit access
pool partition mismatchexclusive state counts sum to provisioned poolstop allocation, reconcile descriptors and queues
refcount discrepancystored refs equal request reachability plus leasesquarantine blocks; repair ownership before recycling

The final failure rule is:

Fallback may lose reuse, but it may not weaken identity, ownership, mapping, or execution exactness.

Recomputation is often the safest fallback. Reusing a stale or unauthorized object to preserve hit rate is not graceful degradation.

0x0CH Source-Observed Contract Versus Unified Protocol

StatementStatus
Prompt Cache declares reusable prompt modules in a schema and preserves a position contract.Externally verified; retained source figures from A25.
CachedAttention, earlier AttentionStore wording, preserves inactive-session history and partially prefills a resumed turn.Externally verified; hierarchy and transfer remain M5.5.
vLLM documents per-request cache_salt as an optional prefix-cache isolation mechanism.Official-documentation observation; not a complete authorization claim.
PagedAttention, vAttention, RadixAttention, Hydragen, and ChunkAttention own the mechanisms described in their rows.Externally verified and, where stated earlier, pinned-source observed.
All seven papers implement the Loop 11 version tuple.False. The tuple is a checked rewrite interpretation.
The synthetic funnel is a production hit-rate measurement.False. It is an observability reconciliation fixture.
The oracle stress-tested concurrency or security.False. It checked structural ordering and 27 deterministic rejections.
One design is universally best.False. The owned object, lifetime, workload, kernel, hierarchy, and policy coordinate differ.

Exact reuse designs differ in whether they change physical layout, declare modules, discover prefixes, share active execution, or preserve inactive sessions

0x0D Worked Ledger

TP-Local Checked Reconciliation

The executable fixture binds to the Loop 2 layout rather than copying geometry into an unrelated calculator:

32 cache layers
4 local K/V heads on TP rank 0 of 2
head width 128
FP16 K and FP16 V

B_row,rank = 64 KiB / token
P = 16 tokens / block
B_block,rank = 1 MiB / physical block

Three requests form a nested exact-prefix family:

RequestLive rowsRectangular reservationPhysical block mapRequest-view tail
A3364[100, 101, 102]15 slots
B2548[100, 101]7 slots
C1632[100]0 slots

The rectangular reference ledger is:

logical request rows = 33 + 25 + 16 = 74
logical payload      = 74 * 64 KiB = 4.625 MiB

reserved rows        = 64 + 48 + 32 = 144
reserved bytes       = 144 * 64 KiB = 9 MiB
reservation slack    = 70 * 64 KiB = 4.375 MiB

Paging without deduplicating request references gives six block-table entries:

request-view slots    = 6 * 16 = 96
request-view capacity = 6 MiB
request-view tail     = (96 - 74) * 64 KiB = 1.375 MiB

But the union of block IDs is only {100, 101, 102}. Blocks 100 and 101 are full; block 102 contains one valid row:

unique materialized rows = 16 + 16 + 1 = 33
unique useful payload    = 33 * 64 KiB = 2.0625 MiB

unique physical slots    = 3 * 16 = 48
unique capacity          = 3 MiB
unique physical tail     = 15 * 64 KiB = 0.9375 MiB

This is why the 22 request-view tail slots cannot be labeled physical waste. Seven of B’s non-visible block positions contain valid rows materialized for A; the same is true for C’s shorter view. The checked identities are:

9 MiB = 4.625 MiB logical references + 4.375 MiB rectangular slack
6 MiB = 4.625 MiB logical references + 1.375 MiB request-view tail
3 MiB = 2.0625 MiB unique materialized + 0.9375 MiB unique tail
6 MiB = 3 MiB unique capacity + 3 MiB reference capacity avoided by sharing
4.625 MiB = 2.0625 MiB unique materialized + 2.5625 MiB deduplicated payload

The physical pool contains eight provisioned blocks:

pool provisioned = 8 * 1 MiB = 8 MiB
live unique       = 3 * 1 MiB = 3 MiB
idle reusable     = 5 * 1 MiB = 5 MiB

The fixture separately charges six 4-byte request-map entries, eight 32-byte block descriptors, two 24-byte cached-hash entries, three 2-byte valid-tail records, five 4-byte free-queue entries, and 128 fixed bytes:

M_meta = 24 + 256 + 48 + 6 + 20 + 128 = 482 synthetic bytes

Those record sizes are test inputs, not measurements and not a claim about their CPU/GPU placement. The oracle rejects 14 one-field failures, including a fixture that counts all six request references as six unique blocks.

Model-Wide Capacity-Pressure Illustration

The older running example uses a model-wide rather than TP-local convention:

L     = 32
H_kv  = 8
d_h   = 128
bytes = 2

One token’s K/V across all layers:

L * 2 * H_kv * d_h * bytes
= 32 * 2 * 8 * 128 * 2
= 131,072 bytes
= 128 KiB

If a block holds 16 tokens, the all-layer conceptual block payload is:

16 * 128 KiB = 2 MiB

Real systems may block per layer, head group, or backend-specific layout. This ledger is a capacity-pressure example, not a literal vLLM memory struct.

A 4096-token prompt has:

4096 / 16 = 256 blocks

Its all-layer K/V payload is:

4096 * 128 KiB = 512 MiB

If another request has an exact 3072-token prefix hit:

hit blocks = 3072 / 16 = 192 blocks

prefill tokens skipped = 3072
new prompt tokens to compute = S_prompt - 3072

The benefit is not just memory. The prefill compute for those 3072 tokens is skipped, which can improve TTFT. But if the response generates 1024 new tokens, decoding then grows the cache by up to 1024 more rows. Under M5.1’s ordinary stop the final emitted token is never processed as an input row, so 1023 rows are appended; only M5.1’s optional repair append adds the 1024th:

future decode growth <=
    1024 * 128 KiB
  = 128 MiB

ordinary stop:
    1023 * 128 KiB
  = 127.875 MiB

That growth still has to be admitted, allocated, and scheduled.

0x0E What M5.3 Does Not Claim

MisconceptionCorrection
”PagedAttention compresses K/V.”No. It reduces allocation waste and enables sharing; the logical K/V values still exist.
”vAttention is the same as PagedAttention.”No. vAttention keeps a contiguous virtual layout and relies on physical allocation on demand.
”A 12 TB virtual reservation consumes 12 TB of HBM.”No. Virtual address reservation, created physical handles, mapped backing, and valid K/V are separate ledgers.
”A free physical handle is already mapped.”No. Handle creation and request-range mapping are different VMM operations.
”free_reqid must immediately unmap every page.”No. vAttention may retain inactive mappings and reuse that capacity for a later request slot.
”Retained vAttention pages are a prefix-cache hit.”No. Slot generation changes and valid rows reset; exact semantic reuse still requires the Loop 2 and Loop 6/7 contracts.
”Asynchronous mapping removes synchronization.”No. Mapping work may overlap, but the required frontier must be ready before a kernel dereferences it.
”Prefix reuse is fuzzy matching.”No. It is exact reuse of token-prefix K/V under a strict forward-pass contract.
”APC speeds up all generation.”It skips repeated prefill work; long decode-heavy responses may see little benefit.
”RadixAttention is long-context eviction.”No. It is an exact prefix-indexing/reuse mechanism. Eviction policy only decides what cached exact state remains retained.
”A cache hit means no memory pressure.”No. The hit may keep blocks resident and future decode still grows.
”Block size is only an implementation detail.”No. It changes internal waste, metadata pressure, kernel indexing, and copy-on-write granularity.
”Allocator block size and kernel block size must match.”Not always. The pinned vLLM block table can split one allocator block into smaller kernel blocks when divisibility holds, increasing kernel-visible entries.
”A CUDA page group is a PagedAttention block.”No. A page group is physical VMM granularity; a paged-kernel block is a user-visible attention layout unit.
”Fewer block-table reads proves a faster kernel.”No. Thread geometry, vectorization, cache behavior, context, dtype, and hardware still require measurement.
”Smaller chunks save more shared-prefix K/V rows.”Not in the fixed Loop 10 workload. Logical row savings stay constant while traversal, match boundaries, and partial-state bytes change.
”The vAttention page-size result proves small pages never hurt.”No. It is a source-reported result for the paper’s tested kernels, models, hardware, and driver path.
”A physical block ID is a byte address.”No. It is meaningful only inside a cache-group pool generation; a descriptor, K/V base, and tensor strides still resolve the byte.
”A flattened slot ID identifies one scalar.”No. It identifies a token row in one group pool; layer, K/V kind, head, lane, dtype, and layout remain unresolved.
”Shared physical validity defines every request’s visible history.”No. Each request’s context frontier is checked before the shared block’s committed-row bound.
”Every cache group uses the same block map and strides.”No. The immutable manifest must declare each group’s table, pool, layer range, representation, and physical ABI.
”Refcount zero means the bytes have no cache value.”Not necessarily. A zero-ref full block may remain indexed and evictable until allocation reclaims it.
”A cache key owns a block.”Not in the Loop 5 model. The cache index is a weak identity reference; request maps and active leases are strong references.
”An equal block digest proves an authorized exact hit.”No. The digest proposes an indexed candidate; namespace authorization, semantic/layout compatibility, physical generation, all-group availability, and collision policy remain separate gates.
”A complete prompt hit means zero prompt execution.”Not necessarily. The execution path still needs logits; under the pinned full-block alignment contract, one semantic final-token recomputation can expand to an entire block.
”Partial-tail reuse is a free extension of full-block caching.”No. The valid frontier must be part of immutable identity, and a divergent write returns to the allocator’s COW transaction. The partial-tail policy in this article is not attributed to vLLM.
”COW copies the whole request cache.”No. Block-granular COW copies only the shared mutable tail bundle, although that bundle may span several cache groups.
”The block ID protects against delayed writers.”No. Recycling creates an ABA hazard; the normative handle also carries pool, group, and generation.
”Rollback can undo any failure.”Only before successor publication. After the linearization point, repair requires another committed transaction.
”A radix-tree match is always read-only.”No. A match that ends inside a compressed edge may split that edge while preserving aligned token/slot ownership and active locks.
”Locking the terminal leaf protects a running request.”No. Every node on the terminal-to-root path contributes required K/V and must remain protected.
”Longest-prefix lookup decides which request runs next.”No. M5.3 emits immutable match and ownership evidence; M5.2 owns service order, fairness, deadlines, and overload policy.
”Sharing K/V storage automatically shares decode-time attention work.”No. An ordinary kernel may reread one shared object for every request; execution reuse needs compatible batch geometry and a partition-aware kernel.
”Partial attention outputs can be averaged.”No. A normalized local output has lost absolute softmax mass; exact merging must retain a denominator, LSE, or equivalent online state.
”ChunkAttention’s temporary partial buffer is free.”No. It trades duplicate shared-prefix K/V reads for partial-output and normalizer writes, rereads, metadata, and a second execution phase.
”Prompt Cache is automatic prefix caching with another name.”No. Prompt Cache declares reusable modules and their position contract in a schema; runtime prefix indexes discover observed exact prefixes.
”The same Prompt Cache module text can be inserted at any position.”No. Tokens, schema generation, parameters, and assigned position IDs are part of the reusable-state contract.
”A matching conversation ID is enough to restore CachedAttention state.”No. The tenant, model/cache ABI, representation, covered interval, position contract, and publication generation must still be compatible.
”cache_salt authenticates and authorizes a requester.”No. It partitions hash ancestry under the documented mechanism; authentication, authorization, namespace lifecycle, and telemetry hygiene remain separate controls.
”Prefix hit rate identifies why reuse failed.”No. Authorization, candidate, compatibility, generation, lease, mapping, snapshot, and execution counters need separate denominators and rejection buckets.
”The Loop 11 oracle proves the runtime is linearizable and secure.”No. It checks structural ordering and deterministic fixture rejection; real concurrency stress and security testing remain deployment work.

0x0F Boundary To Later M5

M5.3 gives M5.4-M5.8 the memory object they will modify:

ArticleWhat changesM5.3 boundary
M5.4 long-context policieswhich old K/V remains logically visible after retention, merging, or compressionlayout/reuse is exact; retention may be lossy
M5.5 retrieval and offloadwhich preserved rows are resident, promoted, or retrieved for one stepexact cache identity and covered intervals feed tier and retrieval transactions
M5.6 P/D disaggregationwhich worker owns or receives K/Vblock tables and prefix hits become placement metadata
M5.7 MQA/GQAhow many full K/V heads exist per tokenarchitecture changes H_kv before layout handles it
M5.8 MLAwhich latent representation is retainedlayout handles latent plus RoPE rows and their kernel ABI

The systems arc is:

M5.1:
    define K/V state

M5.2:
    schedule next work under KV pressure

M5.3:
    allocate, address, share, and exactly reuse K/V

M5.4:
    decide whether all old K/V remains visible

0x10 Publish Gate

0x10A Final Formula Closure

The final registry contains 78 formulas from Loops 3-11. Loop 12 adds no new mechanism equation. It checks that every registered formula has a unique ID, units, an accounting or validity convention, and an article location. The audit also makes the edge conditions explicit:

Formula familyRequired domain or identity ruleFailure if omitted
external-fragmentation snapshotM_total_free > 0; otherwise report not_applicabledivision by zero or a misleading score for a full arena
generative prefix capS_prompt >= 1 before S_cap = S_prompt - 1negative or wrapped prefix length
online-softmax partitioneach numerator and denominator sum uses the same legal key set; empty states branch before normalizationduplicated, missing, or undefined probability mass
COW capacity amplificationr > 0; block-boundary append is a separate pathdivision by zero and conflation of append modes
allocator/kernel expansionP_k divides P_a in the checked split directionfabricated contiguous kernel blocks
VMM page conversionpage bytes are divisible by the declared tensor-row bytes in the checked fixturefractional token rows per mapped page
pool-state reconciliationfree, evictable, live, and reserved-or-copying buckets are mutually exclusivedouble-counted physical capacity

The code blocks remain accessibility fallbacks, not second formulas with a different convention. The final audit rejects an empty rendered math node, unbalanced display delimiters, duplicate formula IDs, or a registered formula without units and a convention.

0x10B Final Source And Figure Closure

The source ledger now distinguishes four evidence classes:

Evidence classCountWhat it can support
primary papers7paper mechanisms and source-reported evaluations
pinned runtime repositories5revision-scoped implementation observations only
official versioned documentation1vLLM prefix-cache salting behavior at the named documentation version
source figures15mechanism or source-reported sensitivity, never a local reproduction

All 15 source figures have explicit provenance entries. The 16 custom desktop/mobile visual pairs are original reconstructions tied to local fixtures; they do not inherit a paper’s benchmark claim. The final audit also checks that every external primary URL appears in the article, every pinned revision is named, and every local source or figure exists.

0x10C Final Rendering Closure

The publication check operates on both Markdown and the generated page. It requires balanced math delimiters outside code fences, non-empty generated math/tex nodes, resolved desktop and mobile images, accessible SVG role/title/desc metadata, and generated targets for every local article link. A successful Astro build is necessary but not sufficient: the generated M5.3 page must pass the artifact audit after the build.

0x10D Final Cross-Article Boundary Closure

OwnerContract consumed or deferred by M5.3Boundary result
M4.3generic online-softmax state and exact merge proofconsumed; not re-owned
M4.5one/few-query split geometry, reduction workspace, backend admissionconsumed; storage mapping remains M5.3
M5.1logical request/cache ABI and committed frontierimmutable input
M5.2admission, service order, fairness, SLOs, and preemptionexplicitly deferred
M5.3physical mapping, ownership, exact identity/index, and exact reuse receiptsowned here
M5.4lossy retention, merge, and legal visible historyexplicitly deferred
M5.5tier placement, promotion, retrieval, and fallbackexplicitly deferred
M5.6prefill/decode placement and inter-worker K/V transferexplicitly deferred
M5.7 and M5.8K/V representation geometryparameterizes the layout; derivation deferred
M6.5adapter identity, loading, routing, and batchingidentity consumed; runtime policy deferred
M7.1 and later M7 variantstemporary branches, acceptance, correction, and rollback intentphysical fork receipt owned here; algorithm deferred
M8.6quantized K/V representation, scales, kernels, and quality policyrepresentation consumed; quantizer deferred

This table follows the current roadmap numbering: the decode-kernel owner is M4.5. It also prevents exact physical reuse from silently absorbing scheduling, lossy retention, hierarchy movement, architecture, speculation, or quantization policy.

GateStatus
PagedAttention is framed as exact layout, not compressionpass
Token-to-group, quotient/remainder, block-table, slot, stride, and byte-address derivations are explicitpass
Two non-identical cache groups reconcile exactly to Loop 3 row and block bytespass
Physical identity includes cache group, pool, generation, and block IDpass
Slot ID and byte address are kept distinctpass
Request visibility is checked before shared physical validitypass
Block-boundary append consumes a versioned successor produced by the Loop 5 transaction modelpass
Pinned vLLM source observations are separated from the synthetic tensor layoutpass
Refcounts are recomputed from request reachability plus active leasespass
FREE, EVICTABLE, live, cached, reserved, and copying states are not collapsedpass
Private-tail, boundary, and shared-tail COW append paths are distinguishedpass
COW payload, traffic, capacity, and amplification are dimensioned separatelypass
COW uses generation-fenced handles, source leases, and atomic multi-group publicationpass
Failed pre-publication transactions reproduce the predecessor digest exactlypass
Post-publication repair requires a compensating successor transactionpass
Truncate, cancel, release, cache, touch, free, and evict have separate effectspass
Recycled block IDs increment generation and reject stale writerspass
Pinned vLLM allocator observations are separated from the stronger teaching protocolpass
vAttention virtual reservation, physical handles, mapped backing, and valid K/V are separate ledgerspass
Virtual and physical byte formulas reconcile on a checked fixturepass
Request-slot generation and retained mapping capacity are separated from semantic prefix identitypass
Synchronous and asynchronous map-before-use paths expose a readiness boundarypass
PagedAttention and vAttention are compared by kernel-visible address contractpass
Pinned vAttention prototype observations are separated from the stronger teaching receipt protocolpass
Synthetic 64-byte pages are not presented as a production CUDA granularitypass
Unmap, physical-handle release, and virtual-range release are distinct cleanup stepspass
Prefix reuse exactness contract is explicitpass
Incremental block hashes include parent-prefix identity and partial-tail policypass
Semantic, indexed, capped, runtime-hit, and recomputed lengths remain separatepass
Full-block-only behavior is source-observed while immutable partial tails are labeled as an alternativepass
Complete-prompt-hit logits recomputation and block alignment are derived numericallypass
Collision resistance, semantic compatibility, and namespace isolation are separate controlspass
Prefix lookup emits an immutable receipt and hands mutation back to Loop 5pass
Every compressed edge has equal-length token and physical-slot segmentspass
Mid-edge matching splits token and slot segments at the same offset without copying K/Vpass
Radix lock references are re-derived from all active terminal-to-root pathspass
Eviction selects unlocked leaves and recursively exposes parents without disconnecting descendantspass
The offline DFS lower-bound theorem is not generalized to online SLO or fairness policypass
Scheduler handoff freezes tree version, path slots, suffix interval, and lock lease while leaving policy_decision = nonepass
RadixAttention is separated from lossy retentionpass
Numeric block ledger is includedpass
Block-size fragmentation and metadata tradeoff are derivedpass
Paged-kernel traversal and partial-tail safety are explicitpass
Allocator block, kernel block, VMM page group, and shared-prefix chunk are separate contractspass
Full-block prefix-hit loss and immutable-partial-tail alternative are reconciled across five sizespass
COW useful rows, read/write traffic, and destination capacity are separate ledgerspass
Pinned vLLM hybrid allocator-to-kernel block mapping is traced and checkedpass
Pinned paged-kernel traversal, partition, thread-group, and value-vector geometry are tracedpass
Ragged block-table used, padded, and transferred cells are derivedpass
Shared K/V row savings stay invariant while chunk visits and partial-state bytes varypass
vAttention page bytes are converted to tokens only through a model/TP-local tensor rowpass
Paper latency and page-size figures are labeled source-reported, not locally reproducedpass
Workload sensitivity and measurement protocol do not select an M5.2 scheduling policypass
Hydragen coordinate adapter consumes the M4.3 canonical merge proofpass
ChunkAttention begins, ends, offsets, partial rows, and sequence completion are tracedpass
Monolithic, Hydragen-coordinate, and ChunkAttention-coordinate outputs agree in the checked fixturepass
Logical pairs, unique physical K/V rows, avoided duplicate reads, and temporary state have separate ledgerspass
Empty partition, stale tree, invalid coverage, duplicate token, and missing mass failures reject explicitlypass
Hydragen, ChunkAttention, and inactive-session identity are comparedpass
Inactive-session tiering and promotion are handed to M5.5pass
Seven papers are compared by owned object, discovery, mutation, execution, and lifetime rather than by a mixed leaderboardpass
Prompt Cache schema/module identity and position sequences are explicitpass
CachedAttention historical identity is separated from M5.5 hierarchy placement and transferpass
Authorization precedes cache-existence lookuppass
Salt, hash, collision witness, namespace generation, and authorization are separate controlspass
Index, tree, pool, mapping, and execution-snapshot versions close one checked use transactionpass
Locked eviction, stale receipt, mapping lag, incomplete COW, and telemetry exposure have deterministic rejection pathspass
Hit-funnel differences reconcile to named rejection bucketspass
Allocator partition, refcount discrepancy, and mapping-frontier lag reconcile in the checked telemetry snapshotpass
Raw prompts and unsalted concrete cache keys are excluded from normal metricspass
Three A25 source figures are retained with source-mechanism rather than local-measurement captionspass
184 prior negative fixtures plus 27 Loop 11 fixtures close to 211 deterministic rejection casespass
The unified protocol is labeled rewrite interpretation rather than attributed to one paperpass
M5.4/M5.5/M5.6/M5.7/M5.8 boundaries are explicitpass
All 78 registered formulas have unique IDs, units, conventions, and audited edge guardspass
Seven primary papers, five pinned runtimes, one official documentation source, and 15 source figures reconcilepass
Sixteen responsive custom visual pairs and all local article links pass the generated-artifact auditpass
M4.3 online-state ownership and M4.5 decode-kernel ownership are not conflatedpass
Loop 12 adds audit closure without reopening M5.3 mechanismspass

References

Local source articles:

External sources: