2026/07/13 37.9k words

Transformer System #numinens#transformer#lora#adapter-serving#punica#s-lora#vllm#batching#paging#kv-cache#scheduling#inference

M6.5 - Multi-Adapter Serving: Kernels, Residency, Batching, and KV Compatibility

M6.5 - Multi-Adapter Serving: Kernels, Residency, Batching, and KV Compatibility

0x00 Overview: A Small Adapter Creates A Large Runtime Contract

M6.3 defined a low-rank update. M6.4 compared ways to train and parameterize it. Neither article answers the production question:

How can one resident base model serve requests for many adapters without corrupting request state or fragmenting every batch by adapter identity?

0x00A The Runtime Problem Predates LoRA

Parameter-efficient training and parameter-efficient serving are different problems. Reducing the task-specific artifact from a complete model copy to a small parameter set does not tell an inference engine how to register that state, batch requests that select different states, place those states in memory, or preserve them across an autoregressive request.

The systems lineage makes this separation clearer:

StageTask-specific objectShared opportunityNew systems problem
full fine-tuningone complete model per tasklittle after deploymentmodel copies, swaps, and fragmented capacity
early parameter-efficient transferprompts, bottlenecks, masks, biases, or deltasone frozen backboneheterogeneous task operators and artifact registration
PetSregistered PET type plus task parameterstask-agnostic base operatorscoordinated task batching and operator dispatch
LoRAtwo low-rank factors and scaling metadata per targetone large base projectionheterogeneous low-rank execution inside one batch
Punica and S-LoRAmany independently identified LoRA objectsone resident base modelsegmented kernels, residency, paging, and adapter-aware scheduling
stateful generationadapter identity plus request-local historybatched prefill and decodeadapter/KV compatibility, in-flight lifetime, and safe version changes

PetS is the important pre-LoRA systems ancestor here. It does not define LoRA and does not implement a modern decoder-only serving stack. It identifies the more general decomposition that later LoRA systems inherit: shared model operators, task-specific parameter objects, a registry/loader, a scheduler, and a specialized operator library. In other words, making task state small exposes a systems interface; it does not remove one.

PetS task registry, parameter repository, scheduler, and parameter-efficient operator library

Source: PetS, USENIX ATC 2022, Figure 4, reproduced from the official open-access paper. PetS serves several parameter-efficient methods and predates LoRA-specific multi-tenant systems. The figure establishes historical task-state decomposition; it is not evidence for Punica, S-LoRA, PEFT, or vLLM implementation details.

LoRA then gives the task-specific branch a particularly regular algebraic shape. Punica asks how different LoRA factors can share the base projection without a launch per adapter. S-LoRA asks how a much larger collection of adapter objects can coexist with dynamic KV state and tensor parallelism. Modern runtimes such as vLLM expose adapter identity through request, residency, kernel-metadata, and load/unload interfaces. These are related responses to different bottlenecks, not interchangeable names for one system.

0x00B Owner And Boundary Contract

M6.5 consumes six completed contracts instead of deriving them again:

Consumed ownerContract used hereWhat M6.5 must not reteach
M6.3vanilla LoRA factors, target modules, checkpoint identity, merge semanticsordinary LoRA forward/backward and checkpoint construction
M6.4method-specific representation and compatibility axesthe variant catalog and its training recipes
M6.7rank, subspace, optimization, and retention diagnosticslow-rank theory or rank-selection claims
M5.1request-local KV append, commit, and release lifecyclethe basic autoregressive cache state machine
M5.2admission, iteration planning, batching, fairness, and preemptionthe generic continuous-batching scheduler
M5.3physical KV pages, cache identity, copy-on-write, and exact reusegeneric PagedAttention allocation and prefix reuse

This article owns the adapter-specific serving extension:

adapter registry identity and revision
request -> adapter selection
homogeneous and segmented adapter execution
adapter device/host residency and page lifetime
adapter-aware admission, pinning, eviction, and hotswap
adapter + KV + prefix compatibility
runtime telemetry, failure detection, and recovery

It defers learned routing, sharing, and continual composition to M6.9, and it defers general quantized packaging, deployment evaluation, release, and rollback to M8. A scheduler decision appears here only when adapter state changes its feasibility or correctness. A KV mechanism appears here only when adapter provenance changes cache identity or object lifetime.

0x00C Evidence And Claim-Status Contract

StatusMeaning in this article
Source-localThe hand-written A22 source or another completed Transformer System owner supplies terminology, context, or a consumed contract; it is not independent verification.
Externally verifiedA primary paper or official proceedings source supports the scoped claim.
Official implementationA revision-pinned project source demonstrates one concrete API, state layout, or execution path; it is not a universal runtime contract.
Rewrite interpretationA Transformer System derivation, invariant, toy trace, or design recommendation assembled from the frozen sources.
Source-reportedA benchmark, scale, or latency result reported by its authors and not reproduced here.
UncertainA version-, hardware-, workload-, or method-dependent claim that remains explicitly unresolved.

Loop 1 freezes LoRA v2, the official PetS paper, Punica v1, the S-LoRA MLSys paper, and revision-pinned Punica, S-LoRA, PEFT, and vLLM source trees. Later loops may execute bounded local oracles against those contracts. This article does not claim to reproduce a source benchmark, validate a production deployment, or prove that one runtime policy is optimal.

One base model with request-scoped adapter and KV state

During training, an adapter can look like a small pair of tensors saved beside a base-model identifier. Serving changes the unit of analysis. Requests arrive concurrently, select different adapters, contribute different numbers of prompt or decode rows, and retain KV state across iterations. The runtime must make adapter identity part of execution ownership.

The naive story is:

load one base model
load a small adapter
select adapter per request

The actual system must coordinate:

base-model residency
adapter metadata and compatibility
GPU/CPU adapter placement
heterogeneous low-rank kernels
continuous batching
request KV ownership
prefill/decode scheduling
hotswap and eviction safety
latency and memory SLOs

This article treats an adapter as live serving state, not as a file attached after the model has already been scheduled. Punica and S-LoRA are useful because they expose two different parts of that state: heterogeneous adapter kernels and a memory system for many adapter/KV objects.

M5.2 owns the ordinary iteration plan, queue policy, admission, fairness, and completed-service accounting. M6.5 consumes that plan and adds adapter identity, residency, and kernel feasibility; it does not redefine continuous batching.

0x01 Prerequisites: From One Adapter To Multi-Tenant Execution

0x01A The Single-Adapter Baseline

For one linear layer and one adapter:

there are two common deployment modes:

merged:
    materialize W' = W + sBA
    run one ordinary base-shaped projection

live:
    keep W shared
    execute the low-rank branch for each forward pass

Merged execution is simple when one adapter is fixed, but it creates a different effective base weight for each adapter. Keeping hundreds of merged copies would duplicate the base model. Live execution preserves one shared base, but adapter identity now affects every targeted layer.

0x01B Why Ordinary Batching Assumes Shared Weights

An ordinary dense batch works because every row uses the same matrix:

If row groups use different adapters, only the base term remains homogeneous:

The batch therefore contains:

one shared large GEMM:
    every row uses W

many heterogeneous low-rank operations:
    row j uses the factors, rank, and scale for adapter a_j

Splitting the entire batch by adapter wastes the shared base-model opportunity. Running a Python loop over adapters preserves correctness but creates many tiny launches. Multi-adapter serving needs a kernel interface that consumes row-to-adapter metadata directly or groups rows while retaining an inverse permutation.

0x01C Four State Lifetimes Must Be Separated

Serving one separately fine-tuned model per task duplicates the base weights and fragments accelerator capacity. Live adapters introduce a hierarchy instead:

State classExamplesLifetime
shared model statebase weights, tokenizer/config, common kernelsworker or deployment
adapter statefactors, rank, scale, target modules, base revisionresidency/cache entry
request stateadapter identity, sampling state, KV handlerequest
scheduler stateactive rows, adapter reservations, page ownershipiteration and queue

Correctness requires these lifetimes to agree. Evicting an adapter while a kernel still references its device slot is a use-after-free. Reusing a KV prefix under a different K/V-changing adapter is semantic cache corruption. Loading the right adapter file against the wrong base revision is a checkpoint compatibility failure.

0x01D Residency Is Different From Adapter Size

An adapter may be tiny relative to the base model and still miss a latency objective. A cold request can require:

registry lookup
    -> host or object-store read
    -> validation and tensor materialization
    -> host-to-device transfer
    -> device-slot publication
    -> first kernel use

The relevant quantities are not only bytes per adapter:

GPU-resident adapter capacity
host-resident cache capacity
cold-load latency and transfer bandwidth
number of distinct adapters per iteration
rank distribution and kernel workspace
in-flight references that prevent eviction

Adapter placement is therefore a cache and admission problem, not merely a file-loading API.

0x01E Prefill, Decode, And KV State Change The Batch Shape

Prefill can contribute many rows from one request, so an adapter may own a useful matrix-matrix sub-batch. Decode often contributes one row per active request, creating many tiny adapter segments:

prefill:
    request a -> [S_a,d] rows

decode:
    request a -> [1,d] row per iteration

Meanwhile the KV cache persists across iterations. Directly adapting K or V makes cache dependence obvious, but target-module names alone are not a proof of compatibility. An adapter applied to an earlier attention output or MLP can change the residual stream that later layers project into K/V, so later cached tensors can still depend on the adapter. The safe general contract is to include adapter provenance in request and prefix-cache identity, then permit reuse only when end-to-end equivalence is explicitly proven.

This connects three schedulers that are often designed separately:

token scheduler:
    which prefill/decode rows run now?

adapter residency policy:
    are the required factors resident and pinned?

KV allocator:
    can request history grow without colliding with adapter memory?

0x01F Runtime State Contract

A request needs at least:

request_id
base_model_id
base_revision
adapter_id
adapter_revision
adapter_method
target_modules
rank_by_module
scaling_by_module
adapter_dtype
quantization compatibility
KV cache handle
sampling state

The worker needs:

base model shards
adapter registry
GPU-resident adapter pages
host-resident adapter store
adapter kernel metadata
KV page allocator
active batch composition
in-flight adapter references

Correctness invariant:

Every forward row must use the adapter state and KV history associated with that request at that position.

An adapter is small compared with the base model, but selecting the wrong adapter is a semantic corruption just like reading another request’s KV pages.

0x01G Immutable Runtime Manifest: Identity Before Residency

The field list above is necessary but not yet a contract. A path can be overwritten. A human revision label can be reused. An integer adapter ID can identify a catalog entry without identifying the bytes behind that entry. A GPU slot can keep the same index while its contents change. Two ranks can load shape-compatible tensors that implement different global updates.

That is why a multi-adapter runtime needs several identities rather than one overloaded adapter_id:

RecordAnswersMust remain distinct from
base execution ABIWhich exact base weights, configuration, transforms, and target-module map define the shared operator?model name or deployment URL
adapter artifact identityWhich method, module specifications, scales, and tensor bytes define the learned delta?catalog alias, file path, or integer slot ID
adapter semantic ABIWhich base-plus-adapter mathematical function is requested?the physical layout chosen by one worker
local kernel ABIWhich converted tensor orientation, dtype, packing, and local shard may this kernel consume?the global adapter artifact
request bindingWhich request attempt selected which semantic base/adapter contract?reusable prefix identity or scheduler row index
K/V and prefix bindingUnder which model-state and exact input contract were persistent rows produced?request ownership, residency, or sampling policy
slot bindingWhich worker slot generation and pointer-table generation currently publish the adapter?semantic adapter identity
generation snapshotWhich catalog, request, slot, batch plan, and cache snapshots were observed together?one universal mutable counter

The distinction is operational. Reloading the same adapter bytes into another slot changes physical execution ownership but not the mathematical prefix identity. Replacing bytes behind the same adapter name changes semantic identity even if the path, slot, tensor shapes, and rank stay unchanged.

Deriving Artifact And Execution Identities

Let canonical mean a deterministic serialization with sorted object keys, stable module order, explicit integer and string types, and no pointer or path values. The base execution ABI is:

Renderer-safe fallback:

H_base = SHA256(canonical({
    model_weights_sha256,
    model_config_sha256,
    weight_transform_sha256,
    target_module_map_sha256,
}))

The tokenizer and chat template remain input provenance in M5.1. They do not change a base projection once exact token IDs and side inputs are fixed, so they are not silently folded into this weight ABI.

For adapter module , freeze the logical specification:

The module record includes its canonical base-module name, input/output dimensions, rank, scaling rule, logical axes, and hashes of the factor bytes. It is not enough to record one global rank: rank can differ by module, and two rank- tensors can target different projections.

module_spec[m]:
    canonical base-module name
    target role
    base weight shape [d_out, d_in]
    rank r_m
    alpha numerator and scaling rule
    logical A axes [rank, input]
    logical B axes [output, rank]
    A tensor content hash
    B tensor content hash

The immutable adapter artifact identity is then:

The ordered module sequence is canonicalized by module name before hashing. The catalog namespace, display name, URI, and human revision are recorded for provenance and authorization, but the bytes and interpretation define H_artifact. A registry may map several aliases to the same artifact or one alias to a newer artifact; neither mapping changes content identity.

The global mathematical function requested by a client is represented by:

H_adapter_semantic = SHA256(canonical({
    H_base,
    H_artifact,
    activation_policy_sha256,
}))

Ordinary always-on LoRA can use a fixed activation-policy digest. A method with an invocation boundary or request-dependent activation needs a different digest even if its factor files match.

Logical Factors Are Not Physical Kernel Layouts

The artifact uses the mathematical orientation above. A kernel may not. In the pinned Punica implementation, LoraWeight.wa is stored as [layer, rank, input], while wb is stored as [layer, rank, output] for its expand path even though the logical matrix is [output, rank]. BatchedLoraWeight then publishes pointer arrays for those converted objects. This is one official implementation trace, not a universal storage convention.

The local kernel ABI must therefore bind the semantic artifact to its conversion and shard:

For a column-parallel base projection with two tensor-parallel ranks, one possible local contract is:

global logical update:
    A_m [r_m, d_in]       replicated
    B_m [d_out, r_m]      sharded over output

rank q local kernel storage:
    A_q [r_m, d_in]
    B_q [r_m, d_out / 2]  physical [rank, output_shard]
    output range [q * d_out/2, (q + 1) * d_out/2)

This does not claim that every runtime must replicate or store in that orientation. It states that whichever choice is made must be explicit and must reproduce the global update. Loop 6 compares the placement alternatives and communication consequences; Loop 2 freezes the fields those comparisons are allowed to vary.

Request, Slot, K/V, And Prefix Projections

The request binds semantic state:

request_binding = SHA256(canonical({
    request_namespace,
    request_id,
    attempt,
    lineage_id,
    H_base,
    H_adapter_semantic,
    generation_policy_sha256,
}))

The request ID and attempt prevent a delayed completion from being published into another attempt. The generation policy belongs to request replay and sampling-state ownership. It does not by itself change K/V already computed for an exact prefix.

M6.5 exports H_adapter_semantic to the M5.1 cache manifest as part of its adapter/weight-transform identity. M5.1 then derives the K/V ABI from the full model, representation, position, visibility, and local shard contract, and M5.3 owns the concrete prefix directory and block keys. The safe composition is:

M6.5 adapter semantic ABI
    -> M5.1 artifact_identity.adapter_set_sha256
    -> M5.1 cache_abi_sha256
    -> M5.1/M5.3 prefix_identity_sha256

For exact prefix reuse:

The prefix key deliberately excludes:

request_id and request attempt:
    ownership is not mathematical compatibility

adapter slot index and slot generation:
    physical residency can change without changing model semantics

sampling policy and RNG offset:
    they choose future tokens, not K/V for an already exact prefix

catalog path or human adapter name:
    aliases are not content identity

It includes the adapter semantic ABI through the cache ABI. A target-module name heuristic is not a replacement: an upstream adapted projection can change hidden states that later layers project into K/V.

A physical launch needs a different binding:

slot_binding = SHA256(canonical({
    worker_epoch,
    device_id,
    slot_index,
    slot_generation,
    pointer_table_generation,
    H_adapter_semantic,
    H_kernel_local,
}))

The scheduler snapshots this binding when it constructs kernel metadata. A late launch with the right adapter name but an old slot generation must fail. A reload of the same artifact into a new slot generation invalidates stale pointers but does not invalidate a semantic prefix produced under the same cache ABI.

Generation Is A Vector, Not One Counter

Several independent generations advance for different reasons:

GenerationAdvances whenProtects against
catalog revisionan alias or authorization record is republishedresolving a name to an unintended artifact
request attempta request is retried or replayed as a new attemptdelayed completion from an older attempt
slot generationa physical adapter slot is republisheduse-after-replace of resident factors
pointer-table generationkernel pointer/offset metadata is rebuiltstale addresses after compaction or replacement
batch-plan generationrow-to-request/adapter segmentation is republishedexecuting an old row map with a new active batch
cache snapshot generationcommitted K/V state advances or rolls backstale append, rollback, or publication
RNG snapshot generationsampling state advancesreplaying or skipping random draws

There is no meaningful comparison such as slot_generation >= cache_generation. They live in different namespaces. A launch snapshot records the exact tuple it observed and validates each component against its owner before publication.

def validate_launch(row, request, adapter, slot, cache, plan):
    assert row.request_binding == request.binding_sha256
    assert request.base_abi == adapter.base_abi
    assert request.adapter_semantic_abi == adapter.semantic_abi

    assert row.slot_binding == slot.binding_sha256
    assert slot.adapter_semantic_abi == adapter.semantic_abi
    assert slot.local_kernel_abi == row.local_kernel_abi

    assert row.plan_generation == plan.generation
    assert row.cache_snapshot_generation == cache.generation
    assert cache.adapter_semantic_abi == adapter.semantic_abi

These assertions are a correctness oracle, not a proposed hot-path Python implementation. A production engine can use packed integers and generation arrays as long as those compact fields reconstruct the same comparisons.

Worked Rank-And-Shard Identity Trace

Consider a synthetic adapter over two [8, 8] column-parallel projections:

q_proj: rank 2, alpha 4,  A [2,8], B [8,2]
v_proj: rank 4, alpha 8,  A [4,8], B [8,4]
dtype:  2 bytes/scalar
TP:     2 ranks; A replicated, B output-sharded

The global logical artifact contains:

or bytes. Each TP rank stores all of but half of each :

or bytes per rank and bytes across two ranks. The cluster residency exceeds the unique artifact payload because the factors are replicated. This is an analytical fixture, not a measured allocator total; alignment, page rounding, pointer tables, and workspace are deferred.

Now bind request req-17, attempt 0, to the artifact and publish it in worker slot 3, slot generation 11. A reload of identical bytes into slot generation 12 produces:

same H_artifact
same H_adapter_semantic
same cache ABI and eligible semantic prefix identity
different slot_binding
different pointer-table and launch snapshot requirements

Changing only the v_proj rank from to , changing one factor byte, or retargeting it to k_proj changes H_artifact, therefore the semantic ABI and cache ABI. Keeping the alias customer-blue does not preserve compatibility.

A multi-adapter runtime derives separate semantic, local-kernel, request, cache-prefix, and physical-slot identities, then validates their generation-stamped bindings at launch

Executable Manifest And Negative Fixtures

The article-local oracle serializes this synthetic example and rejects single-field mutations. Its negative fixtures include:

base or adapter digest drift
duplicate or unsorted module records
rank, alpha, logical-shape, or tensor-hash drift
local factor orientation or TP output-range drift
request-to-adapter mismatch
slot artifact, slot generation, or pointer-table mismatch
cache-to-adapter mismatch
prefix projection drift
cross-namespace generation mismatch
logical versus local residency-ledger drift

The evidence lives in:

docs/numinens-evidence/m6-5-multi-adapter-serving-runtime/
    runtime_identity_manifest.json
    invalid_runtime_identity_fixtures.json
    runtime_identity_manifest.py
    test_runtime_identity_manifest.py

Passing this oracle proves only that the declared identities, tensor shapes, hash projections, generation references, and analytical bytes are internally consistent. It does not load an adapter, allocate GPU memory, execute a segmented kernel, validate an engine API, or measure latency. Those claims belong to later loops.

0x02 One Base Projection, Many Adapter Projections

For request group :

The base matrix is shared. Adapter factors vary.

If a batch contains token rows:

X:
    [N, d_in]

adapter_ids:
    [N]

sequence/request metadata:
    maps every row to its owner

The base projection can run as one ordinary GEMM:

The adapter branch is heterogeneous:

where is the adapter assigned to row .

0x02A Naive Homogeneous Grouping

A straightforward implementation groups rows by adapter:

def adapter_branch_by_group(X, adapter_ids, registry):
    output = zeros([X.shape[0], registry.d_out])

    for adapter_id, row_ids in group_rows(adapter_ids):
        adapter = registry[adapter_id]
        Xi = X[row_ids]

        hidden = Xi @ adapter.A.T
        delta = hidden @ adapter.B.T
        output[row_ids] = adapter.scale * delta

    return output

This is correct if metadata and scatter order are correct. It can be inefficient when:

many adapters appear in one iteration
each adapter owns only a few rows
decode contributes one row per active request
kernel-launch overhead dominates tiny GEMMs
rank varies across adapters

Continuous batching can create exactly that shape: a large shared base batch and many tiny adapter-specific sub-batches.

0x02B Segmented Heterogeneous Kernels

Segmented LoRA execution over a heterogeneous adapter batch

Punica introduces a CUDA kernel design for batching operations belonging to different LoRA models. Its serving insight is that the base GEMM remains shared while low-rank work needs a multi-tenant primitive. The paper’s operator and the archived v1.1.0 wrapper use contiguous row intervals. A later indexed Triton path in vLLM v0.12.0 uses a stable row-index permutation instead. Both are segmented execution, but their metadata and ownership contracts are not interchangeable.

For a linear layer with row segment assigned to adapter :

Punica names the heterogeneous primitive SGMV, Segmented Gather Matrix-Vector multiplication. The low-rank branch is two SGMV launches:

SGMV-shrink:
    [N_a,d_in] x [d_in,r_a] -> [N_a,r_a]

SGMV-expand:
    [N_a,r_a] x [r_a,d_out] -> [N_a,d_out]

Segmented Gather Matrix-Vector multiplication over adapter-specific row segments

Source: Punica v1, Figure 3. SGMV groups request segments by adapter-specific weight pointers while preserving their output row ranges. This is Punica’s kernel contract, not a generic name for every heterogeneous LoRA kernel.

“Matrix-vector” describes the decode-heavy thin-row regime; the segmented operator handles multiple rows and adapters. The segment table determines which LoRA weight pointer each row range uses.

A generic segmented runtime needs enough information to identify:

original rows and active adapter rows
either contiguous row segments or indexed row groups
adapter-specific A/B pointers
fixed-rank kernel shape for this Loop 3 contract
semantic scale placement
the output row updated by every grouped row

That list is intentionally broader than one kernel API. The pinned Punica add_lora_sgmv_cutlass wrapper receives two pointer vectors, an int32 offset vector, one layer index, and one scalar rank:

wa_ptr: [S] int64
wb_ptr: [S] int64
offsets: [S + 1] int32, offsets[0] = 0, offsets[-1] = B
lora_rank: one scalar for the whole call

Y[offsets[i]:offsets[i+1]] +=
    X[offsets[i]:offsets[i+1]]
    @ deref(wa_ptr[i])
    @ deref(wb_ptr[i])

The wrapper does not receive arbitrary gather indices, an inverse permutation, a rank table, or a per-adapter scale table. The caller must already present rows in contiguous segment order. By contrast, vLLM v0.12.0 constructs token_indices_sorted_by_lora_ids, active_lora_ids, num_tokens_per_lora, and lora_token_start_loc; its Triton shrink and expand kernels load the original row indices from that sorted-index vector. That indexed path can preserve the original physical input/output layout without first materializing a packed X_grouped tensor.

The common semantic invariants are:

row j reads only adapter a_j
every active row is represented exactly once
base-only rows contribute zero adapter delta
fixed rank and factor orientation match the selected kernel ABI
segment offsets and pointer-table lengths agree
output row j is restored to request order
padding cannot contribute numerically
the adapter delta is added to, not substituted for, the base output

The exact Punica kernel primitive and current framework implementations are version-specific. The stable systems idea is to batch heterogeneous low-rank operations rather than launch one tiny GEMM pair per adapter.

Three implementation families expose the tradeoff:

Adapter branchWeight movementLaunch patternFailure at high adapter cardinality
Python/host loopreads each adapter in placetwo or more launches per adapterlaunch serialization and tiny GEMMs
gather + batched matmulmaterializes or gathers per-row weightsgather plus BMM for each factorduplicated weight traffic and temporary buffers
contiguous segmented kernelfollows offsets and one factor pointer per contiguous segmentone shrink and one expand launch across segmentscaller must first construct a compatible row order
indexed segmented kernelfollows stable grouped row indices and active-adapter metadatashrink and expand cover multiple adapter groupsindirect row access and launch-grid waste can matter

Punica’s paper compares SGMV with loop and Gather-BMM baselines and identifies the extra gather/materialization I/O as a central cost. Those measurements are source-reported for its kernels and hardware; the architectural conclusion is the adapter pointer table should be consumed as close to the GEMM as possible.

Punica’s paper constructs segment indices after arranging the batch and says that consecutive requests sharing one LoRA model are grouped when possible. The pinned model wrapper forms the offset vector as a cumulative sum of per-adapter row lengths. This is the precise reason that segment metadata must be consistent with row ordering:

segment_offsets = [0, n0, n0+n1, ...]
adapter_ids = [adapter_for_segment_0, adapter_for_segment_1, ...]

for s in range(num_segments):
    rows = X[segment_offsets[s]:segment_offsets[s + 1]]
    adapter = adapter_table[adapter_ids[s]]
    # SGMV handles these segments in one device kernel, not this host loop.

If continuous batching interleaves rows from the same adapter, the runtime must either sort/group rows and retain the mapping back to their owners, form multiple contiguous segments that may repeat a pointer, or select an indexed kernel. A contiguous segment-offset kernel cannot silently consume arbitrary row order.

0x02C Five Row Coordinates Must Not Be Collapsed

The word “row” is overloaded in a serving runtime. The following coordinates can happen to agree in a homogeneous batch, but they are different objects:

CoordinateSymbolProduced byConsumed byTypical failure if confused
scheduler rowcontinuous-batch plannerbase GEMM and request bookkeepingresult is published to the wrong request
request/sequence ownerrequest and attention metadataattention mask, K/V append, logits ownershipadapter grouping is mistaken for an attention boundary
active-adapter rowbase-only compactionlow-rank plannera base-only row receives an update or an active row disappears
segment-local rowstable grouping or indexed metadatashrink and expand kernelsrow reads the wrong factor pointer
output rowscatter map or indexed kerneladditive projection outputnumerically correct delta lands in the wrong row

Request boundaries and adapter segments answer different questions. Two requests can use the same adapter and share one adapter segment while retaining different attention/K/V ownership. One request’s prefill rows can also be split by a planner without changing its adapter identity. M6.5 therefore forbids deriving attention visibility from the adapter permutation.

Let the scheduler-order input be

where adapter ID zero denotes the base-only path in this article’s fixture. Define the active set and its stable adapter-grouped permutation:

The gather matrix is a useful derivation device:

No production kernel needs to materialize . It makes two correctness conditions visible: each row of contains one 1, and each active scheduler row appears in exactly one column selected by . Those conditions are the injectivity and coverage checks in the executable oracle.

The Loop 3 fixture uses:

N = 8, d_in = 4, r = 2, d_out = 3
adapter IDs in scheduler order:
    [1, 2, 1, 0, 2, 2, 1, 0]

active rows in scheduler order:
    [0, 1, 2, 4, 5, 6]

stable adapter-grouped permutation g:
    [0, 2, 6, 1, 4, 5]

segment adapter IDs:
    [1, 2]

segment offsets o:
    [0, 3, 6]

The original batch is deliberately not adapter-contiguous:

Scheduler row RequestAdapter Compact/grouped positionSegment
0req-a10adapter 1
1req-b23adapter 2
2req-a11adapter 1
3req-c0—base only
4req-b24adapter 2
5req-d25adapter 2
6req-e12adapter 1
7req-c0—base only

Notice that rows 0 and 2 belong to the same request, but row 6 does not; all three still share adapter segment 1. Conversely, base-only rows 3 and 7 share a request but never enter the compact low-rank path.

0x02D From Row Ownership To CSR-Like Segment Metadata

For segment , define adapter ID and half-open offsets . The segment contract is:

The metadata resembles compressed sparse row indirection:

grouped row indices g:   [0, 2, 6, 1, 4, 5]
segment offsets o:       [0,       3,       6]
segment adapter IDs c:   [1,       2]
A pointer labels:        [A1,      A2]
B pointer labels:        [B1,      B2]

Its invariants are stronger than “the lengths look plausible”:

o[0] == 0
o[-1] == len(g) == N_active
o[t] < o[t+1] for this no-empty-segment contract
len(c) == len(A_ptr) == len(B_ptr) == len(o) - 1
g is injective, in bounds, and covers exactly the active rows
all rows in segment t have adapter ID c[t]
every pointer label resolves under the admitted local-kernel ABI
launch generations equal the admitted slot, pointer-table, and plan generations

There are two valid physical realizations.

Contiguous interval realization. Materialize or schedule X_grouped = X[g], call a Punica-like operator with offsets [0,3,6], then scatter the packed result through g. The pinned Punica wrapper itself only sees contiguous intervals and pointers; the gather/scatter is an outer runtime responsibility if scheduler order was not already compatible.

Indexed realization. Leave and in scheduler order. Pass g, adapter counts, start locations, and active adapter IDs to a kernel that uses the indexed scheduler rows as its row-address vector. vLLM v0.12.0 follows this family. Its metadata preparation uses a stable sort over token LoRA IDs. It includes a -1 no-LoRA sentinel group rather than compacting those rows:

token_lora_mapping:
    [1, 2, 1, -1, 2, 2, 1, -1]

stable sorted row indices:
    [3, 7, 0, 2, 6, 1, 4, 5]

active_lora_ids:
    [-1, 1, 2]

num_tokens_per_lora:
    [2, 3, 3]

lora_token_start_loc:
    [0, 2, 5, 8]

The pinned shrink and expand kernels read row addresses from the sorted-index vector and early-exit a launch slice whose LoRA ID is -1. “Compact away base-only rows” and “retain a sentinel segment” are therefore alternative metadata encodings, not different LoRA mathematics.

0x02E Exact Shrink, Expand, And Scatter Trace

The fixture uses logical factor axes:

Its adapter factors and semantic scales are:

After gathering active rows through , the packed input is:

The fixed-rank shrink stage applies one pointer to each interval:

which produces:

The expand stage applies the corresponding pointer and semantic scale:

so:

Two row calculations expose both scales. Scheduler row 2 uses adapter 1:

Scheduler row 1 uses adapter 2:

Scatter is not optional bookkeeping. Define the scheduler-order delta as zeros and add each packed row back through :

The result is:

Rows 3 and 7 remain exactly zero in the adapter branch. For the fixture’s base matrix , the final additive output is:

Eight scheduler-order rows are compacted into six adapter-active rows, stably grouped into two fixed-rank segments, processed through shrink and expand tensors, and scattered back while base-only rows retain zero adapter deltas

The visual and matrices expose the same contract. The source-reported Punica figure explains the operator family; this program’s own trace proves the row coordinates, exact shapes, and scatter relation for one synthetic case.

0x02F Scale Placement And Physical Factor Layout

The semantic update is invariant under several exact-arithmetic factorizations:

That equality does not make scale placement an ignorable runtime detail. It affects artifact hashes, converted tensor bytes, kernel arguments, accumulator range, rounding order, and hotswap compatibility. A manifest must record whether the scale is:

passed as a launch scalar
stored per adapter in a table
folded into A
folded into B
applied by an outer epilogue

The pinned implementations illustrate why versioned code traces matter:

Pinned pathLogical/physical factor surfaceScale surfaceRow-address surface
Punica add_lora_bgmvstacked A [*,L,R,H1], B [*,L,H2,R]one scalar argumentone weight index per row
Punica add_lora_sgmv_cutlasspointer target A [L,H1,R], B [L,R,H2]no scale argumentcontiguous offsets [S+1]
Punica custom shrink + CUTLASS expandstored A [L,R,H1], B [L,R,H2]; shrink interprets A.Tno scale argumentcontiguous offsets [S+1]
vLLM v0.12.0 Triton shrink/expandstacked adapter factors plus row-index metadataone scalar on shrinkstable sorted original-row indices

Therefore the conceptual scale_table from an abstract heterogeneous API must not be projected onto the pinned Punica SGMV wrapper. For the fixture’s per-adapter scales, a compatible contiguous implementation could fold each scale into its object before publishing the pointer table. The exact oracle proves that this preserves rational outputs. It does not claim bitwise identity in FP16/BF16 because changing scale placement can change rounding and overflow behavior.

Likewise, the pinned Punica wrapper carries one lora_rank scalar and its model integration takes the rank from the first adapter. Loop 3 therefore uses one rank for both adapters. Different ranks require padding, bucketed launches, rank-specialized kernels, or a genuinely heterogeneous rank ABI; Loop 4 owns that comparison.

0x02G Executable Equivalence Oracle

The canonical planner can be written independently of a CUDA API:

def build_fixed_rank_plan(row_adapter_ids, base_id, registry):
    active_rows = [
        row for row, adapter_id in enumerate(row_adapter_ids)
        if adapter_id != base_id
    ]
    permutation = sorted(
        active_rows,
        key=lambda row: row_adapter_ids[row],
    )  # stable

    segment_adapter_ids = []
    offsets = [0]
    for grouped_row, original_row in enumerate(permutation):
        adapter_id = row_adapter_ids[original_row]
        if not segment_adapter_ids or adapter_id != segment_adapter_ids[-1]:
            if segment_adapter_ids:
                offsets.append(grouped_row)
            segment_adapter_ids.append(adapter_id)
    offsets.append(len(permutation))

    assert all(registry[a].rank == registry[segment_adapter_ids[0]].rank
               for a in segment_adapter_ids)
    return permutation, segment_adapter_ids, offsets

The contiguous reference makes gather and scatter explicit:

def contiguous_segmented_lora(X, plan, registry, d_out):
    grouped_X = X[plan.permutation]
    grouped_delta = zeros([len(plan.permutation), d_out])

    for segment, adapter_id in enumerate(plan.segment_adapter_ids):
        lo = plan.offsets[segment]
        hi = plan.offsets[segment + 1]
        adapter = registry[adapter_id]

        Z = grouped_X[lo:hi] @ adapter.A.T
        grouped_delta[lo:hi] = adapter.scale * (Z @ adapter.B.T)

    delta = zeros([X.shape[0], d_out])
    delta[plan.permutation] += grouped_delta
    return delta

An indexed kernel implements the same equations while reading and writing plan.permutation rows directly. It need not allocate grouped_X or execute the Python loop. The pseudocode is an oracle, not a proposed fast path.

The repository evidence bundle freezes the fixture and its failure surface:

docs/numinens-evidence/m6-5-multi-adapter-serving-runtime/
    segmented_tensor_fixture.json
    invalid_segmented_tensor_fixtures.json
    segmented_tensor_oracle.py
    test_segmented_tensor_oracle.py

It uses exact rational arithmetic and proves:

per-row reference == host-grouped reference == segmented reference
split contiguous segments with repeated pointers preserve output
folding each semantic scale into B preserves exact output
reordering scheduler rows and rebuilding metadata preserves row-UID semantics
base-only rows receive an exactly zero adapter delta
all 46 malformed metadata/tensor/generation fixtures fail closed

It also records a hard claim ceiling. Passing the oracle does not execute CUDA or Triton, validate the Punica or vLLM wrappers, measure performance, or prove a production scheduler safe.

0x02H Execution Alternatives And Dispatch Boundary

“Segmented” is not one universally best kernel. The planner should select an execution family under an explicit compatibility and cost contract:

FamilyRow addressingWeight representationAttractive regimeMain cost or risk
per-row BGMV/indexedone adapter index per rowstacked same-shape weightsone-row decode, modest active adapter setrepeated pointer/weight traffic and fixed shape requirements
host loop by adapterhost or graph launches one group at a timeordinary factorsfew adapters with substantial rows eachlaunch serialization and tiny GEMMs
gather + BMMmaterialized per-row or per-group weightsdense gathered temporariesframework portability and easy reference implementationduplicated weight traffic and temporary memory
contiguous SGMVCSR-like offsets and pointersone pointer per segmentplanner can make adapter rows contiguousgather/scatter or scheduling constraints move outside kernel
indexed segmented Tritonstable grouped row indicesstacked/pointer factorsinterleaved rows without packed input materializationindirect access, launch-grid waste, backend-specific limits

The choice depends on row count, adapter cardinality, rank, target projection, dtype, graph-capture constraints, and how much metadata changes each iteration. It cannot be inferred from adapter parameter count alone.

Failure boundaries for this Loop 3 contract are mechanical:

FaultShape may still look validConsequenceRequired response
duplicate or missing row in gyesdouble update or silent omissionreject plan before launch
base-only row included under adapter pointeryeswrong model semanticsreject mapping
offset/pointer count mismatchsometimeswrong pointer or out-of-bounds intervalreject launch metadata
stale pointer-table generationyesuse-after-evict or wrong adapter objectfence and rebuild plan
logical/physical factor orientation mismatchoftenwrong numbers with legal GEMM shapesreject local kernel ABI
scale applied twice or not appliedyessystematic output errorbind scale placement to artifact conversion
grouped result not scatteredyescorrect values assigned to wrong requestsfail row-UID reconciliation
adapter grouping reused as attention groupingyescross-request visibility or K/V corruptionkeep attention metadata independent

This closes the fixed-rank tensor contract. It does not yet choose how one iteration combines prefill and decode rows, nor how different ranks coexist. Those are the owner questions of Loop 4 and Sections 0x03/0x06.

0x03 Prefill And Decode Have Different Adapter Shapes

The same request changes operator shape over its lifetime. During prefill, one request contributes a sequence of token rows. During ordinary one-token decode, it contributes one row to the current iteration:

The low-rank branch is therefore matrix-matrix work in prefill and approaches matrix-vector work in decode:

This is not merely a performance distinction. A runtime must expand one request-level adapter identity to every token row in that request’s prefill, while assigning exactly one current row during one-token decode.

0x03A Three Coordinate Systems Define A Mixed Iteration

Let the iteration admit prefill requests and decode requests. If prefill request contributes rows, then:

A Punica-style phase-major packing puts all prefill rows before all decode rows. Prefill request boundaries are represented by an exclusive prefix sum:

The first decode row is therefore at doff = T_pre, and decode request owns row . These coordinates coexist:

CoordinateQuestion answeredMay be shared?
request/sequence interval which rows may attend within one prefill sequence?never across requests
phase interval or which attention kernel and K/V action apply?fixed for one launch plan
adapter run or indexed groupwhich , , rank, and scale apply to a row?may cross the phase boundary

The last row is the subtle case. Two adjacent rows can share an adapter while belonging to different requests and different attention phases. Adapter coalescing does not license attention visibility.

0x03B Exact Five-Request Mixed-Batch Trace

Use five scheduler-order requests:

Scheduler requestPhaseIteration rowsAdapterLogical rank
p0prefill3a2
p1prefill2b3
d0decode1a2
d1decode1base only0
d2decode1c1

Within each phase, the scheduler may reorder requests if it records the inverse mapping. Put p1 before p0, then append decode rows in scheduler order:

packed request order: [p1, p0, d0, d1, d2]

row:       0   1   2   3   4 | 5    6      7
request:  p1  p1  p0  p0  p0 | d0   d1     d2
phase:   pre pre pre pre pre | dec  dec    dec
adapter:   b   b   a   a   a |  a   base    c
rank:      3   3   2   2   2 |  2    0      1

The phase metadata is:

prefill_indptr = [0, 2, 5]
doff           = 5
decode_count   = 3

The contiguous adapter runs are instead:

segment_adapter = [b, a, base, c]
segment_offsets = [0, 2, 6, 7, 8]

Adapter a deliberately spans rows 2:6: rows 2:5 are the p0 prefill, while row 5 is d0 decode. One segmented projection can reuse a’s factor pointers across that boundary. Attention must still split at doff = 5 and must still respect prefill_indptr = [0,2,5].

Two prefill requests and three decode requests are packed into eight rows; independent phase and attention metadata separate at row five while one rank-two adapter segment crosses that boundary, and logical ranks one, two, and three map to exact-rank or zero-padded execution paths

0x03C Request Identity Must Expand To Token Identity

Let request own adapter . The row-level mapping is not a request list; it is an expansion by the number of rows contributed in this iteration:

For the fixture:

request adapters in packed order = [b, a, a, base, c]
row adapter mapping             = [b, b, a, a, a, a, base, c]

Incrementing an adapter run once per prefill request instead of once per prefill token produces legal-looking offsets whose final value is the number of requests rather than . The failure is detectable before launch:

for sentinel-inclusive contiguous runs, or:

for base-compacted indexed execution.

The archived Punica TUI example is useful source evidence for phase-first, adapter-aware request ordering, but it is not used here as a correctness oracle: its lora_lens construction increments once per request while its prefill input flattens every prompt token. The article therefore derives and tests row expansion independently instead of copying that prototype logic.

0x03D One Dense Projection, Two Attention Paths, Several Adapter Paths

The dense projection can consume the full packed matrix:

The attention layer cannot treat the same matrix as one sequence. A Punica-style model path slices the projected Q/K/V tensors at doff:

qkv = dense_projection_with_adapter_delta(X)

q_pre, k_pre, v_pre = qkv[:doff]
prefill_attention(q_pre, k_pre, v_pre, prefill_indptr)

q_dec, k_dec, v_dec = qkv[doff:]
append_decode_kv(k_dec, v_dec, decode_request_handles)
decode_attention(q_dec, decode_request_handles)

The adapter branch has more implementation choices:

PathPrefill shapeDecode shapeRank contractMetadata contract
request loop GEMM GEMVexact per requestrequest slices
S-LoRA-styleMBGMMMBGMVper-adapter rank plus max-rank workspacerequest starts, lengths, rank table, page locations
vLLM v0.12.0-styleindexed grouped rowsindexed grouped rowsresident slots padded to configured max_lora_ranktoken mapping, stable sorted indices, counts, starts
pinned Punica SGMV wrappercontiguous segmented rowscontiguous segmented rowsone fixed rank argumentpointer vector plus offsets
rank bucketsone launch per prefill/rank bucketone launch per decode/rank bucketfixed rank inside each bucketgather/scatter per bucket

These are alternative physical schedules for the same row-wise function. They are not interchangeable ABIs.

0x03E Sampling Rows Need Their Own Inverse Map

The model produces one logit row per packed token, but a normal iteration emits one next-token distribution per request. For prefill request , select its last packed token; for decode request , select its only current row:

Because the fixture reordered p1 before p0, restoring scheduler request order [p0,p1,d0,d1,d2] requires:

packed sampling rows  = [4, 1, 5, 6, 7]
scheduler output slots = [p0,p1,d0,d1,d2]

The adapter scatter map and sampling-row map are different objects. The former returns every adapter delta to one packed token row; the latter selects and reorders five logit rows for five requests.

0x03F Fragmentation Is Phase-Conditional

For adapter and phase , define:

The ordinary adapter concentration ratio is:

It can hide phase behavior. A popular adapter may have a useful prefill GEMM while appearing as isolated one-row decode work. Record at least:

distinct adapters per phase and iteration
prefill rows and requests per adapter
decode rows and requests per adapter
contiguous runs before and after legal within-phase reordering
rank histogram by phase
adapter branch time by phase
gather/scatter and metadata-build time
padded-rank work / true-rank work

0x03G Mixed-Batch Construction Contract

def build_mixed_iteration(prefills, decodes):
    # Reordering is allowed only with an explicit request-output inverse map.
    ordered_prefills = adapter_aware_order(prefills)
    ordered_decodes = stable_decode_order(decodes)

    rows = []
    request_ids = []
    phases = []
    adapter_ids = []
    prefill_indptr = [0]

    for req in ordered_prefills:
        for token_position, row in enumerate(req.prefill_rows):
            rows.append(row)
            request_ids.append(req.request_id)
            phases.append("prefill")
            adapter_ids.append(req.adapter_id)
        prefill_indptr.append(len(rows))

    doff = len(rows)
    for req in ordered_decodes:
        rows.append(req.current_row)
        request_ids.append(req.request_id)
        phases.append("decode")
        adapter_ids.append(req.adapter_id)

    assert prefill_indptr[-1] == doff
    assert len(rows) == doff + len(ordered_decodes)
    assert len(rows) == len(request_ids) == len(phases) == len(adapter_ids)

    sample_rows = derive_last_prefill_and_decode_rows(
        prefill_indptr, doff, ordered_prefills, ordered_decodes
    )
    return freeze_launch_plan(rows, request_ids, phases, adapter_ids, sample_rows)

This builder freezes metadata once per model invocation. Every layer consumes the same row ownership. Kernel-local pointer tables may differ by target module, but they must bind to the same batch-plan generation.

0x04 Adapter Memory Is A Residency Problem

For one adapter :

where:

T_a:
    target modules in adapter a

r_a,m:
    rank for module m

b_a,m:
    bytes per adapter parameter

Total served memory is not only:

It includes:

Renderer-safe ledger:

M_worker =
    M_base
  + M_resident_adapters
  + M_KV
  + M_activations
  + M_workspaces
  + M_fragmentation

Adapter size may be small enough that thousands fit in host memory while only a subset fit comfortably in GPU memory alongside KV.

0x04A Residency Hierarchy

object store / local disk:
    durable adapter checkpoints

host memory:
    warm adapter cache

pinned host staging:
    transfer-ready pages

GPU memory:
    active or likely-soon adapter factors

kernel pointer table:
    addresses and shape metadata for current iteration

Lifecycle:

registered
    -> host_resident
        -> transfer_pending
            -> gpu_resident
                -> referenced_by_batch
                    -> idle_gpu_resident
                        -> evictable

An adapter can be evicted only when no in-flight batch, queued request with reservation, or asynchronous kernel still references its storage.

0x04B Load-Time Ledger

If adapter has size and effective host-to-device bandwidth :

Small adapters can still suffer latency from fixed overheads, synchronization, and allocator behavior.

Cold-start TTFT:

This is why adapter residency belongs in admission control, not only in a background cache.

0x04C Residency Is A State Machine, Not A Boolean

“Loaded” hides at least six different claims. A checkpoint can be present in host memory while no GPU slot exists. Device pages can be reserved while a DMA copy is incomplete. A copy can be complete while no current pointer table is allowed to name it. A published adapter can be idle but still pinned by a queued reservation or referenced by an asynchronous launch.

Use an explicit object state:

absent
    -> host_ready
        -> reserved
            -> loading
                -> validated
                    -> published
                        -> active
                            -> idle
                                -> retiring
                                    -> absent

The state names are a rewrite contract, not an API copied from S-LoRA or vLLM. They make the safety conditions visible:

StateDevice pages assigned?Pointer-table entry visible?New batch may bind?
host_readynonono
reservedyesnono
loadingyesnono
validatedyesnono
publishedyesyesyes
activeyesyesalready bound
idleyesyesyes
retiringyes until reclaimedno for new bindsno

Two transitions are especially important:

publication:
    validated bytes + complete page table + immutable adapter identity
    -> one generation-stamped visible mapping

retirement:
    stop new binds
    -> wait for references, pins, reservations, and device events
    -> unpublish
    -> reclaim pages

Publishing an adapter before its final copy or validation completes creates a shape-correct use-after-partial-load bug. Freeing it after removing only a host catalog entry creates a device use-after-free bug.

The pinned vLLM v0.12.0 code provides a useful but different concrete model. It separates registered adapters, bounded by max_cpu_loras, from active GPU slots, bounded by max_loras. Its LRU worker loads and validates a new adapter before removing the oldest registered adapter, while its LRU manager can pin registered and active cache entries. Those implementation facts license the separation of registration, activation, and eviction; they do not prove the transaction protocol derived here.

0x04D Derive Page Demand From Tensors, Not From Rank Alone

Let one primitive vector page hold elements of bytes each:

For a tensor with elements, a vector-page upper bound is:

Therefore a general adapter page ledger is:

This formula is deliberately more general than “rank takes pages.” S-LoRA’s paper observes that one compatible LoRA weight tensor of shape occupies vector pages. A complete adapter can contain two factors, several target modules, and every transformer layer.

The final archived S-LoRA code makes a stronger source-specific packing choice. Its allocator owns key and value buffers for every layer. One allocator index selects one hidden-width row in both buffers at every layer, so the bytes behind one index are:

where the factor is the paired key/value storage reused for LoRA -like factors, and is the number of layers. In the pinned attention path, load_adapters reserves 4 * rank such indices for the four (q,k,v,o) projection groups:

and the corresponding payload represented by those slots is:

This is a trace of one archived implementation, not a universal LoRA page formula. MLP adapters, unmatched factor widths, quantized factors, tensor parallel shards, and another allocator change the count.

Renderer-safe derivation:

primitive vector page bytes = H * bytes_per_element

general adapter pages =
    sum over target modules (
        ceil(rank * d_in / H)
      + ceil(d_out * rank / H)
    )

pinned S-LoRA paired multi-layer slot bytes =
    2 * layers * H * bytes_per_element

pinned S-LoRA q/k/v/o attention slots =
    4 * rank

0x04E Reserve, Copy, Validate, Then Publish

The load path is a transaction over identity, pages, bytes, and visibility:

def prepare_adapter(txn, artifact, request, pool):
    validate_semantic_and_kernel_abi(artifact, request)
    demand = derive_adapter_and_kv_page_demand(artifact, request)

    victims = choose_eligible_idle_adapters(pool, demand.shortfall)
    reservation = pool.reserve_atomically(demand.total, victims)

    try:
        mark_retiring_and_block_new_pins(victims, txn.generation)
        copy_from_trusted_host_source(artifact, reservation.adapter_pages)
        await_copy_event()
        validate_digest_layout_dtype_and_generation(artifact, reservation)

        # One visibility point: kernels must see either the old table or this
        # complete new table, never a partially written mapping.
        publish_adapter_mapping(
            adapter_id=artifact.id,
            pages=reservation.adapter_pages,
            generation=txn.generation,
        )
        pin_for_request(artifact.id, request.attempt_id)
        commit_kv_reservation(request.attempt_id, reservation.kv_pages)
        finalize_victim_eviction(victims)
        return admission_success(reservation)
    except Exception:
        unpublish_if_visible(artifact.id, txn.generation)
        release_request_pins_and_kv_reservation(request.attempt_id)
        cancel_or_wait_transaction_events(reservation)
        pool.release_nonvictim_pages(reservation)
        restore_retired_victims_from_trusted_host_source(
            victims, reservation.victim_pages
        )
        pool.restore_victim_ownership_atomically(
            victims, reservation.victim_pages
        )
        raise

The pseudocode orders concepts, not CUDA calls. A production implementation must also define stream/event ordering, lock or single-threaded ownership, metadata durability, and what happens if compensating restoration itself fails.

The archived S-LoRA loader allocates non-contiguous indices, extends adapter metadata, and then copies factors, optionally on a prefetch stream. That code is valuable evidence for the physical design, but it does not expose this full transaction protocol. The derived protocol is intentionally stricter.

0x04F Reference, Pin, Event, Reservation, And Generation Counts

An idle adapter is not automatically evictable. Define:

refcount(a):
    admitted or running request attempts bound to adapter a

pin_count(a):
    explicit policy pins, operator pins, or administrative pins

queued_reservations(a):
    accepted queue entries whose admission assumes a remains resident

inflight_events(a):
    device copies or kernels that may still access a's pages

published_generation(a):
    generation encoded in the pointer table used by a launch snapshot

Then an adapter is eligible for retirement only if:

LRU, LFU, size-aware, or deadline-aware policy may rank only the objects that pass this predicate. Recency is not a safety proof.

0x05 Unified Paging: Adapter Pages And KV Pages Compete

Adapter residency and KV pages share the worker memory budget

S-LoRA stores adapters in main memory, fetches active adapters to GPU, and proposes Unified Paging to manage dynamic adapter weights with different ranks together with KV tensors of varying sequence lengths.

S-LoRA unified memory pool for KV pages and adapter pages

Source: S-LoRA v3, Figure 3. S-LoRA places variable-length KV state and variable-rank adapter weights in one paged pool. Sharing a page allocator reduces fragmentation but does not make adapter and KV ownership or lifetimes identical.

The two objects differ:

ObjectSize changes whenLifetime
adapter pagesadapter is loaded, converted, or evictedshared across requests using that adapter
KV pagesrequest prefills or decodesprivate or prefix-shared under M5 rules

But both compete for the same device memory.

S-LoRA’s page-shape observation is more specific than “put both in one allocator.” For hidden-width-like dimension :

one KV tensor:
    [sequence_length,h]
    -> sequence_length vector pages

one LoRA factor with compatible orientation:
    [rank,h]
    -> rank vector pages

A statically reserved device buffer is divided into vector-sized pages. Page tables reconstruct non-contiguous KV sequences and non-contiguous adapter factors. The allocator can therefore place adapter and KV pages in the same pool without requiring each variable-size object to occupy one contiguous region.

This does not make their lifetimes identical:

adapter page:
    shared by requests using adapter a
    retained or evicted by adapter popularity/residency policy

KV page:
    owned by one request or a valid prefix-sharing relation
    grows as accepted tokens are appended

Reference counts and eviction eligibility must preserve those ownership rules even when the physical page allocator is unified.

S-LoRA’s heterogeneous kernels are coupled to this layout: they operate on non-contiguous adapter pages and varying ranks directly. A fallback that first copies every adapter into a contiguous padded tensor changes the bandwidth, workspace, and fragmentation ledger.

Let:

An admission decision must consider the joint pressure.

Bad independent policies:

adapter cache:
    fills all spare memory with warm adapters

KV allocator:
    assumes spare memory is available for request growth

result:
    decode request cannot append KV
    or adapter load forces emergency KV eviction/preemption

Joint policy sketch:

def can_admit(req, worker):
    adapter_need = worker.adapter_cache.incremental_bytes(req.adapter_id)
    kv_need = estimate_request_kv_bytes(req)
    reserve = worker.decode_growth_reserve

    required = adapter_need + kv_need + reserve
    if required > worker.free_unreserved_bytes:
        return False, "joint_adapter_kv_capacity"

    if not worker.kernel_supports(req.adapter_metadata):
        return False, "adapter_kernel_contract"

    return True, "ok"

That sketch answers only whether enough unreserved bytes appear to exist. A safe implementation must prove which pages are free, which objects may be retired, which generations are visible, and whether every partial transition can be rolled back.

0x05A One Pool Does Not Mean One Ownership Rule

Let the shared pool contain allocator slots:

Every slot must occur in exactly one physical state. Object ownership is a second relation:

physical page state:
    free | reserved(txn) | owned(object, generation)

adapter ownership:
    many request attempts may reference one immutable published generation

KV ownership:
    one request attempt or one explicitly valid prefix-sharing relation
    owns each page under M5's cache contract

The common allocator can reduce external fragmentation because both object classes draw non-contiguous slots from one free set. It cannot reuse one slot simultaneously, make adapter pages request-private, or make request KV pages adapter-global.

The byte conservation equation follows from the slot geometry:

The equation is an allocator invariant. It excludes base weights, activations, workspace outside the pool, host copies, page tables, and allocator metadata.

0x05B Exact Sixteen-Slot Admission Fixture

Use a deliberately small S-LoRA-compatible paired-slot fixture:

hidden width H:       8 elements
layers L:             2
element bytes b:      2
slot bytes:           2 * L * H * b = 64 bytes
total slots:          16
pool payload:         16 * 64 = 1,024 bytes

initial ownership:
    slots  0..3   KV request r0      active and pinned
    slots  4..7   adapter a          refcount 1, pin_count 1
    slots  8..11  adapter b          idle, unpinned, host-backed
    slots 12..15  free

The incoming request r1 uses a rank-one (q/k/v/o) attention adapter c in the pinned S-LoRA-style layout:

adapter c:              4 * rank = 4 slots = 256 bytes
initial request KV:                       2 slots = 128 bytes
decode-growth reserve:                    2 slots = 128 bytes
total transaction demand:                 8 slots = 512 bytes

free now:                                4 slots = 256 bytes
eligible reclaim from adapter b:          4 slots = 256 bytes
free + reclaimable:                       8 slots = 512 bytes

Adapter b is the only legal victim. Request r0’s KV and adapter a fail the pin/reference predicate even though their pages are physically adjacent.

A sixteen-slot unified pool retires one idle adapter, reserves adapter and KV pages atomically, publishes only validated adapter pages, and restores the old generation on injected failure

Successful transaction:

1. validate adapter c identity, target set, rank, dtype, and local kernel ABI
2. derive demand: adapter 4 + initial KV 2 + growth KV 2 = 8 slots
3. prove adapter b is eligible; mark it retiring and block new pins
4. atomically reserve slots 8..15 for transaction tx7
5. copy c into slots 8..11; wait for the copy event; validate digest/layout
6. publish c generation 1 with page table [8,9,10,11]
7. pin c for request attempt r1#1
8. commit r1 KV reservation [12,13,14,15]
9. finalize b's eviction and generation tombstone

final conservation:
    KV r0       4
    adapter a   4
    adapter c   4
    KV r1       4
    total      16

This fixture is intentionally at the capacity boundary. It reveals any policy that double-counts victim pages, forgets the growth reserve, or publishes c before validation.

0x05C Joint Admission Inequality

For request , define:

P_a,incremental(q):
    zero when the exact required adapter generation is already resident;
    otherwise pages needed for its local physical representation

P_KV,initial(q):
    pages needed to admit the prompt/prefill state under M5's rules

P_KV,growth(q):
    reserved decode growth under the configured admission horizon

P_guard(q):
    pool-local safety margin; external kernel workspace is accounted outside

P_reclaimable:
    pages owned only by victims that satisfy the full eviction predicate

Admission requires:

and the same comparison in bytes:

The inequality is necessary, not sufficient. It does not prove:

the adapter artifact is valid
the chosen backend supports its physical ABI
the load can finish before the request deadline
the victim can be restored if the transaction fails
the host/device transfer path has capacity
the future request trace fits the growth horizon

M5 owns the algorithm that estimates P_KV,initial and P_KV,growth. M6.5 consumes those numbers and combines them with adapter residency.

0x05D Victim Eligibility, Ranking, And Reuse Are Separate Steps

Eviction has three contracts:

  1. Eligibility is a hard safety predicate.
  2. Ranking chooses among eligible objects.
  3. Reuse decides when old pages may be overwritten.
def eligible(adapter, live_launch_generations):
    return (
        adapter.state in {"published", "idle"}
        and adapter.refcount == 0
        and adapter.pin_count == 0
        and adapter.queued_reservations == 0
        and adapter.inflight_events == 0
        and adapter.generation not in live_launch_generations
        and adapter.host_source_verified
    )

def choose_victims(adapters, pages_needed):
    candidates = [a for a in adapters if eligible(a, live_generations())]
    candidates.sort(key=lambda a: (a.last_touch, -len(a.pages), a.adapter_id))

    victims, reclaimed = [], 0
    for adapter in candidates:
        victims.append(adapter)
        reclaimed += len(adapter.pages)
        if reclaimed >= pages_needed:
            return victims
    raise AdmissionError("INSUFFICIENT_ELIGIBLE_PAGES")

This example ranks by LRU, then prefers a larger object, then uses stable identity as a deterministic tie-break. LFU, cost-aware, deadline-aware, or reuse-aware ranking is also possible. None may bypass eligibility.

Once a victim is marked retiring, new binds must fail or retry against a new generation. Its pages become reusable only after the last event/reference fence. Merely deleting an entry from a Python dictionary is not a device lifetime barrier.

0x05E Publication Is One Atomic Visibility Point

A kernel launch must snapshot a self-consistent tuple:

The adapter becomes usable only after:

all reserved pages contain validated bytes
all pointer-table entries name those pages
rank, scale, dtype, target, and shard metadata match the artifact
the copy-complete event happens-before pointer publication
the published generation matches the batch-plan snapshot

Readers may observe either the previous complete mapping or the next complete mapping. They may not observe a new generation with old pages, old metadata with new pages, or a half-written pointer table.

Possible implementations include:

double-buffered pointer tables + generation flip
copy-on-write metadata object + atomic handle publication
single-threaded engine ownership + stream event + generation check
lock-protected table update + launch snapshot fence

The choice is runtime-specific. The invariant is not.

0x05F Partial-Failure Rollback Is Compensating Work

Suppose the copy of adapter c fails after slots 8..11 have overwritten the retired adapter b. Releasing the transaction bitmap is insufficient: the old published bytes no longer exist in those slots.

Required rollback trace:

before failure:
    b retired and unpublished
    slots 8..15 reserved by tx7
    c copy incomplete
    c never published
    r1 KV reservation not committed

rollback:
    cancel/wait tx7 device events
    remove every unpublished c mapping and request pin
    release r1 KV reservation
    reload b from its verified host backing into slots 8..11
    validate b and publish fresh fixture generation b@g5
    return slots 12..15 to free

after rollback:
    r0 KV and adapter a unchanged
    adapter b@g5 resident again under a new generation
    adapter c absent
    request r1 not admitted
    pool conservation restored to 16 slots

This is compensating rollback, not free atomicity. It assumes a trusted host source for b and does additional I/O. A runtime that cannot guarantee that restoration should avoid overwriting victim pages before commit, reserve a shadow region, or reject the admission.

Failure after publication is a different transaction boundary. The runtime must first prevent new binds, drain or abort every request that observed the new generation, then retire it. It cannot silently pretend publication never happened.

0x05G Physical Design Alternatives

Unified vector paging is one design point:

DesignFragmentation / capacity propertyLoad and kernel consequenceFailure consequence
unified adapter + KV vector pagesflexible shared capacity; one class can pressure the otherkernels gather non-contiguous adapter and KV rowsjoint admission and cross-class starvation control required
separate adapter and KV poolshard isolation and simpler ownership accountingstranded capacity if one pool is idleadapter churn cannot consume KV reserve, but resizing is operational work
fixed max-rank GPU slotspredictable pointer arithmetic and bounded active setrank padding wastes storage/work; slot count is explicitactivation fails when no legal slot exists
host-warm cache + device LRUmany registered adapters, bounded active setmiss adds load/activation latencyinvalid new artifact should be rejected before destructive eviction
load per batch, offload after batchminimal idle device residencytransfer and synchronization can dominatesimple lifetime, poor reuse under repeated adapters
shadow-copy then publishstrongest pre-publication rollbackneeds temporary duplicate capacityold generation remains intact until commit

The pinned S-LoRA paper/code support the first and fifth rows, including prefetch overlap. The pinned vLLM v0.12.0 manager illustrates separate registered and active capacities plus LRU/pinning behavior. The remaining rows are design alternatives used to expose the contract, not claims that either source implements them exactly.

0x05H Executable Residency Oracle

The checked-in Loop 5 oracle replays the sixteen-slot fixture with exact integer accounting. It verifies:

slot conservation and unique ownership
S-LoRA-compatible slot-byte derivation
incremental adapter + initial KV + growth KV demand
full victim-eligibility predicate
deterministic victim choice
atomic reservation coverage
copy -> validate -> publish ordering
generation-fenced pointer visibility
success-state ownership
copy-failure compensating rollback
digest-failure rollback
negative mutations for double ownership, stale generations, illegal victims,
premature publication, missing host backing, and leaked reservations

It allocates no GPU memory, performs no DMA, executes no CUDA or Triton kernel, and measures no latency or throughput. Its result is a state/page/byte proof, not a production allocator benchmark.

0x06 Rank Heterogeneity Is A Kernel Shape

Two adapters can target the same modules but use different ranks:

adapter A:
    q_proj rank 8

adapter B:
    q_proj rank 64

For one row, branch FLOPs are approximately:

Rank ratio:

for identical matrix shapes.

A heterogeneous batch can therefore have per-row adapter work differing by 8x even though every request uses “LoRA.”

0x06A Logical Rank And Physical Rank Are Different Fields

Let be adapter ‘s logical rank and let be the physical rank of a static slot or intermediate. A max-rank implementation can embed the logical factors in zero-padded physical tensors:

The padded update is algebraically identical:

Zero padding is therefore an exact representation transform over exact arithmetic. It is not permission to leave stale values in the padded tails. Both factor tails must be zeroed when a resident slot is reset or overwritten.

The pinned vLLM v0.12.0 linear wrapper follows this family of contracts: it allocates resident A/B slots at configured max_lora_rank, zeros a slot before copying, and copies each logical factor into a leading slice. Its indexed Triton shrink and expand operators then obtain rank from the physical stacked tensor. That is a versioned implementation choice, not a universal vLLM or Punica ABI.

0x06B True-Rank And Padded-Rank Ledgers

For active row using adapter , the branch’s conceptual multiply-add count is:

If every active row executes physical rank :

The arithmetic padding ratio and wasted rank-row count are:

For the mixed fixture, seven rows use adapters. Adapter b owns two rank-3 rows, adapter a owns four rank-2 rows, and adapter c owns one rank-1 row:

With , , and :

true-rank branch FLOPs   ~= 2 * 15 * (3 + 2) = 150
padded-rank branch FLOPs ~= 2 *  7 * 3 * (3 + 2) = 210
padding ratio             = 210 / 150 = 1.4x
logical rank-row values   = 15
padded intermediate       = 7 * 3 = 21 values
wasted rank-row values    = 6

This ledger counts logical matmul work. It does not predict latency: a padded kernel can still beat several smaller launches, and a ragged kernel can pay indexing, masking, and load-imbalance costs.

0x06C Exact Variable-Rank Tensor Trace

Use these logical factor orientations:

For the eight packed rows from Section 0x03B, the exact ragged shrink rows are:

The empty row is base-only. After expansion and semantic scale, the adapter delta in packed-row order is:

The executable Loop 4 oracle computes the same through four paths:

per-row exact-rank reference
phase-split prefill/decode execution
rank-bucketed gather/compute/scatter
max-rank zero-padded indexed execution

It also reorders the two prefill requests, rebuilds every dependent mapping, and proves equality by immutable row UID and scheduler request ID.

0x06D Runtime Design Alternatives

StrategyUseful propertyCost or constraintFail-closed requirement
pad to configured maximumone static storage and kernel rankextra resident bytes, intermediate values, and workzero both A and B tails; reject
bucket by rankexact shapes and predictable kernelsmore launches, gathers, scatters, and phase fragmentationscatter by immutable row UID
fully heterogeneous kernelone launch can consume per-adapter ranksrank-aware masking, pointer arithmetic, and uneven workvalidate rank table against factor/page extents
exact request loopsimplest semantic oraclepoor launch amortization at high adapter cardinalitypreserve packed output mapping
convert at admissionnormalize artifacts to supported ranks/layoutsnew artifact bytes and possible approximation if rank changesbind a new local-kernel ABI digest
cap supported rankbounded workspace and compiled shapesrejects otherwise valid artifactsreject before residency/launch

S-LoRA’s paper names separate heterogeneous kernels: MBGMM for prefill sequences and MBGMV for one-token decode. Its pinned code carries per-adapter rank and page-location metadata while allocating an intermediate at the maximum rank in the active adapter set. The pinned Punica wrapper instead takes one rank from the first batched adapter. A mixed-rank Punica invocation must therefore be rejected or partitioned into compatible launches; the paper’s separate rank-8/16/32/64 microbenchmarks do not prove same-launch rank heterogeneity.

0x06E Rank-Aware Dispatch Contract

def choose_adapter_path(batch, backend):
    ranks = sorted({row.logical_rank for row in batch.active_rows})

    if backend.supports_per_adapter_rank_table:
        return heterogeneous_launch(batch, rank_table=ranks)

    if backend.uses_zero_padded_slots:
        if max(ranks, default=0) > backend.max_lora_rank:
            raise AdmissionError("rank_exceeds_physical_slot")
        assert_all_padding_zero(batch.resident_slots)
        return padded_indexed_launch(batch, physical_rank=backend.max_lora_rank)

    if backend.requires_one_fixed_rank:
        if len(ranks) == 1:
            return fixed_rank_launch(batch, rank=ranks[0])
        return [
            fixed_rank_launch(bucket, rank=rank)
            for rank, bucket in stable_rank_buckets(batch)
        ]

    raise AdmissionError("no_compatible_rank_execution_path")

Rank is not inferred from a display name, one arbitrary adapter, or an intermediate tensor’s allocated width. The launch snapshot binds logical rank, physical rank, factor extents, slot generation, and batch-plan generation.

0x06F Tensor-Parallel Placement Must Follow The Base Projection

A multi-GPU base model adds another compatibility axis. The LoRA branch must produce the same partitioned output layout as the base projection it augments. Replicating every adapter factor on every tensor-parallel rank is a valid design alternative, but it duplicates residency and can introduce collectives that the base path did not need.

S-LoRA instead aligns adapter-factor partitions with a Megatron-style two-layer MLP. The first base matrix is column-parallel, the second is row-parallel, and the adapter communicates rank-width intermediates before placing its output in the same coordinates as the base path.

S-LoRA tensor-parallel partition strategy for batched LoRA

Source: S-LoRA, Figure 4. The base and LoRA branches use matching output partitions. Low-rank intermediates are gathered or reduced, and the adapter output gather is fused with the base path’s final reduction. This is the paper’s schedule, not a universal layout for every tensor-parallel runtime.

0x06F1 Reconcile Factor Orientation Before Sharding

This article has used the common checkpoint orientation:

S-LoRA writes the same row-major operator as , with:

Nothing has changed mathematically. The names have moved with the transpose. This reconciliation must happen before interpreting a paper figure or slicing a checkpoint. Otherwise a locally valid shard can represent the wrong global operator.

0x06F2 Derive The First, Column-Parallel Projection

Let the first base matrix be:

Its adapter factors are and . S-LoRA splits the rank axis of and the output axis of :

Each rank first owns only a slice of the bottleneck:

An all-gather concatenates those slices on the rank axis:

Every device can then produce its output shard:

The proof is a block-matrix identity:

The gather is not optional. Without it, a rank either has a shape mismatch or must silently use only matching diagonal rank blocks, dropping cross-shard terms.

0x06F3 Derive The Second, Row-Parallel Projection

The first projection leaves its activation sharded:

For , the base rank owns . Its adapter uses:

The local shrink result is a partial sum, not a shard of the final bottleneck:

Therefore the collective is addition:

Each rank expands into one output slice:

Let insert that slice into columns of a zero tensor. The base path already needs a full-width all-reduce over its partial outputs . Add the disjoint adapter slice before that collective:

The final reduction sums overlapping base partials while acting like an all-gather for the disjoint adapter slices. This is the fusion meant by Figure 4; it does not mean the earlier rank-width all-reduce disappeared.

0x06F4 Exact Two-Rank Tensor Trace

The Loop 6 fixture sets token rows, , , and FP16 payloads. For the first projection, the local rank slices are:

Gathering along the bottleneck axis gives:

The two local output shards concatenate to the unsharded reference:

For the second projection, the two local bottleneck partials are:

Their sum is:

After the two output shards are inserted into disjoint columns, the adapter result is:

The same final all-reduce combines the base partials and those disjoint slices:

The fixture proves equality using exact integer arithmetic. It does not execute NCCL, measure overlap, or establish that this schedule is best on current hardware.

0x06F5 Weight Residency And Communication Are Separate Ledgers

Both projection adapters are fully sharded in the S-LoRA paper schedule:

Object on rank Local shapeReplicated?
no
no
no
no

For the exact FP16 fixture, the two adapters occupy 32 bytes per rank and 64 bytes across the two-rank group. Replicating all four global factors would occupy 64 bytes per rank and 128 bytes across the group. Cluster bytes and per-rank resident bytes answer different questions; neither includes allocator metadata or temporary collective buffers.

For a ring-style logical traffic ledger, one rank receives pieces of a all-gather:

A reduce-scatter followed by all-gather moves:

Three Q/K/V gathers plus one output-projection reduction yield the S-LoRA paper’s additional traffic:

The existing base output all-reduce moves:

Hence:

For and , the ratio is about . In the deliberately small fixture, and , so the added 30 FP16 payload bytes per rank are the existing 24-byte base payload. The toy case validates the formula; it is not chosen to make the ratio look favorable.

These terms count logical elements per rank. Multiply by bytes per element for payload bytes. They omit protocol headers, link topology, collective algorithm, startup, synchronization, temporary buffers, and overlap. The source schedule has four additional collective calls before any Q/K/V fusion: three all-gathers and one rank-width all-reduce. Small payload does not imply small latency when startup dominates. M4 owns the general collective performance model.

0x06F6 The Paper Schedule And Archived Code Are Different Evidence

S-LoRA Section 6 and Figure 4 specify the tensor-parallel design above. The final archived repository does not provide a revision-pinned executable confirmation of that design: LoraTpPartAdapter.__init__ contains assert world_size == 1. The loader still contains hidden-axis slicing code, but the guard prevents treating that code snapshot as a working multi-rank adapter path.

This distinction changes the claim:

externally verified paper claim:
    S-LoRA proposes the TP partition and communication schedule above

official-code observation at archived revision c1ddf48:
    the adapter constructor rejects world_size != 1

not established here:
    that the archived code executes Figure 4 end to end
    that the schedule is optimal on another engine or topology

The runtime manifest must therefore bind the implementation actually deployed, not merely the paper whose schedule inspired it:

global adapter contract:
    module key and base execution ABI digest
    checkpoint factor orientation and semantic scale
    global A/B shapes and logical rank

physical TP contract:
    TP degree and rank ID
    each factor's shard axis, interval, and local shape
    divisibility, uneven-shard, or padding rule
    collective kind, tensor axis, reduction operation, and order
    which adapter operation is fused into which base collective
    storage dtype, collective dtype, accumulation dtype
    implementation revision and local-kernel ABI digest

A shape-correct adapter can still be placement-wrong. Swapping gather order, concatenating partial sums, reducing an output shard that should remain sharded, or pairing a factor with another TP degree can all produce plausible local tensors while changing the global update.

FaultWhy local shapes can surviveGlobal failure
omit first rank-axis all-gatherslice both factors on rank axiscross-rank bottleneck terms disappear
concatenate second partialsconcatenation is shape-valid after padding is replaced by unrelated coordinates
reduce with MAX or averagecollective shape is unchangedadapter magnitude is wrong
use stale shard manifestlocal extents may matchrows or columns belong to another TP degree/version
publish one rank earlyeach rank has valid local pointersone request observes a mixed adapter generation
Two-rank LoRA tensor-parallel trace followed by a versioned shared-basis adapter collection

The left half follows one adapter through rank-axis gather, bottleneck reduction, and base-collective fusion. The right half separates collection-shared bases from adapter-specific cores and makes the basis/core generation an explicit runtime identity.

0x06G Compress The Adapter Collection, Not Each Adapter Independently

M6.3 and M6.4 treat each adapter as an independent low-rank update. High-cardinality serving creates another option: change the representation of the collection. This is an offline approximation problem followed by a new runtime operator and artifact contract. It is not ordinary LoRA training, and it does not make each adapter independently portable.

Compress then Serve comparison of adapter memory, CPU-to-GPU transfer time, and one-module forward time

Source: Compress then Serve, final ICML 2025 paper, Figure 5. The paper measures memory over all 96 Mistral LoRA modules, while transfer and forward timing use one module. Joint representations reduce collection memory and transfer time in this experiment; the forward-time panel does not show a corresponding single-module latency reduction. These are source-reported results, not a benchmark reproduced by this article.

0x06G1 One SVD Cannot Solve A Shared-Basis Collection

For adapters with updates:

Compress then Serve jointly approximates them as:

with shared bases:

U:       [d_out,R]       shared by a collection or cluster
V:       [d_in,R]        shared by a collection or cluster
Sigma_i: [R,R] or [R]    adapter-specific core

The collection objective is:

This is not one SVD of one matrix. and must be shared across all terms, while every adapter keeps a different core. The paper studies two important constrained families:

LayoutPer-adapter stateShared stateMain tradeoff
JD-Fullmore expressive adapter-specific transform
JD-Diagmuch smaller adapter payload, stronger shared-basis constraint

In JD-Full, and each is unconstrained. For fixed orthonormal , expand one term:

The last term is nonnegative, so the optimal core is:

Substitution turns basis fitting into captured-energy maximization:

With fixed, define:

The best contains the top eigenvectors of this positive-semidefinite matrix. With fixed:

and takes its top eigenvectors. Alternating these two updates decreases the reconstruction objective. Parenthesizing through avoids requiring one persistent matrix per adapter.

JD-Diag instead sets:

and leaves unconstrained. Then:

Every adapter is restricted to the span of shared rank-one atoms. JD-Full can use all cross atoms . The diagonal form saves state by changing the approximation family, not by losslessly repacking a full core. The paper solves JD-Diag by coordinate descent over , , and the diagonal cores.

0x06G2 Exact Full-Core Reconstruction And A Diagonal Counterexample

The Loop 6 fixture uses:

and three full cores:

Each update is exactly , so JD-Full has zero squared Frobenius reconstruction error. The vectorized updates are linearly independent:

A rank-2 JD-Diag collection lies in the span of only two shared rank-one atoms. It therefore cannot reconstruct these three independent updates exactly for any choice of shared . Keeping the displayed bases and dropping the off-diagonal core entries gives a concrete squared residual of 27. That number is a fixture witness, not the globally optimal JD-Diag error; the span-rank argument is what proves nonzero optimal error.

The paper’s broader result is similarly conditional: JD-Full is lossless only when covers the joint column and row spaces of the collection. With noisy, independently trained adapters, that required rank can approach the sum of individual ranks. Joint decomposition is generally lossy at useful compression ranks.

0x06G3 Derive Parameter Break-Even, Not Just Compression Ratios

Let and let each source adapter have rank . Ordinary LoRA requires:

The joint representations require:

JD-Full saves parameters only if:

When , the break-even collection size is:

If the denominator is non-positive, no collection size can make JD-Full smaller under this count. Similarly, JD-Diag requires:

when .

For the exact fixture, , , and :

ordinary LoRA: 36 parameters / 72 FP16 bytes
JD-Full:       24 parameters / 48 FP16 bytes
JD-Diag:       18 parameters / 36 FP16 bytes
minimum integer n that saves parameters: 2 for either representation

For a larger illustrative ledger with , , , and :

ordinary LoRA:  131,072,000 parameters
JD-Full:          1,286,144 parameters
JD-Diag:            294,144 parameters

These are representation counts, not a promised compression ratio at fixed quality. The required shared rank , decomposition error, adapter diversity, metadata, dtype, and quantization determine whether the representation is acceptable.

The ledger is for one adapted matrix shape. A full-model count must sum the shared bases and adapter cores over every adapted module and layer.

For equal-rank clusters, the payload count is:

The final paper’s GPU ledger adds one cluster assignment per adapter:

The assignment is metadata, not a floating-point weight in every possible implementation. Keeping both ledgers prevents a compact paper formula from silently becoming a universal memory-layout claim.

0x06G4 The Runtime Operator Has Three Ownership Stages

For row-major token state :

Shape trace:

ordinary LoRA:
    X:[N,d_in] -> X A_i^T:[N,r] -> output:[N,d_out]

joint decomposition:
    X:[N,d_in] -> X V:[N,R]
                 -> core Sigma_i:[N,R]
                 -> shared U^T:[N,d_out]

For the fixture input:

Adapter then produces:

Rows sharing one collection or cluster can use one ordinary projection shape for . Their cores remain adapter-specific. JD-Diag makes the middle stage an elementwise multiply; JD-Full needs a small grouped operation. The final shared stage again has one basis shape per cluster.

The path has three algebraic stages instead of ordinary LoRA’s two, and can exceed . Lower resident bytes therefore do not automatically imply lower TPOT. The final paper explicitly reports large memory and transfer reductions without a corresponding one-module forward-latency reduction in its timing experiment.

Tensor parallelism and collection compression are not independent. The shared bases need the same physical shard contract as the projection they replace, while each core must be paired with that exact basis generation. A basis-shared batch can still require cluster grouping before its TP collectives.

0x06G5 Offline Conversion Is A Training And Evaluation Boundary

The paper compresses a set of already trained LoRAs. The decomposition has access to adapter weights; it does not jointly fine-tune the base model. Its experiments normalize every to unit Frobenius norm before fitting and restore the original norms for reconstruction and evaluation. They limit the main alternating runs to ten iterations rather than claiming full convergence.

An operational conversion pipeline is:

def build_collection_bundle(source_adapters, base_abi, module_key, config):
    frozen = freeze_ordered_source_set(source_adapters)
    for adapter in frozen:
        validate_base_module_orientation_scale(adapter, base_abi, module_key)

    deltas, norms = [], []
    for adapter in frozen:
        delta = adapter.semantic_scale * adapter.B @ adapter.A
        norm = frobenius_norm(delta)
        require(norm > 0)
        deltas.append(delta / norm)
        norms.append(norm)

    if config.method == "JD-Full":
        U, V, cores = alternating_top_eigenspaces(
            deltas,
            rank=config.shared_rank,
            max_iterations=config.max_iterations,
        )
    elif config.method == "JD-Diag":
        U, V, cores = coordinate_descent_diagonal_cores(deltas, config)
    else:
        raise UnsupportedRepresentation(config.method)

    restored_cores = [norm * core for norm, core in zip(norms, cores)]
    metrics = evaluate_candidate(
        frozen,
        U,
        V,
        restored_cores,
        reconstruction_manifest=config.reconstruction_suite,
        task_manifest=config.held_out_task_suite,
    )
    require_release_thresholds(metrics, config.release_policy)

    return emit_immutable_collection_bundle(
        source_set=frozen,
        base_abi=base_abi,
        module_key=module_key,
        bases=(U, V),
        cores=restored_cores,
        metrics=metrics,
    )

Frobenius reconstruction error is a proxy, not a substitute for downstream evaluation. The paper reports a nonlinear relation between reconstruction and task performance. Rank, cluster count, iteration count, normalization, and release thresholds therefore belong to an immutable experiment manifest.

0x06G6 Clustering Trades Shared Residency For A Smaller Local Subspace

If one basis cannot approximate a diverse collection, adapters can be clustered. Cluster owns while each adapter owns and a cluster assignment. That changes scheduler and artifact state:

The paper initializes clustering by fitting one joint basis and running k-means on the resulting cores. It then alternates two operations:

fit step:
    refit one JD model independently inside each current cluster

assignment step:
    assign each adapter to the cluster with minimum reconstruction error

stop:
    no assignment changes, or a declared iteration/validation limit is reached

More clusters increase shared-basis residency and can fragment runtime batches, but can reduce reconstruction error at a fixed per-cluster rank. The paper reports JD-Full without clustering as effective up to roughly 100 adapters in its evaluated collection and uses clustering at larger scales. That is a source-reported recommendation for its tasks and hardware, not a universal threshold.

0x06G7 A Core Is Meaningless Without Collection Identity

adapter identity:
    base revision
    ordered source adapter set and source digests
    module key, orientation, semantic scale, and base execution ABI
    decomposition method and rank R
    optimizer, normalization, rank, cluster count, and evaluation manifest
    collection and basis version
    cluster ID
    Sigma_i revision
    basis and core digests

scheduler affinity:
    prefer rows sharing a resident basis/cluster
    but do not violate queueing and SLO limits to maximize affinity

Adding, removing, or retraining one adapter can require reclustering or recomputing shared bases. A compressed core is therefore not independently meaningful. Loading with the wrong version is as incorrect as loading LoRA factors against the wrong base model.

Publication must be generation-atomic:

freeze source set
-> validate base/module/orientation/scale
-> fit bases and cores offline
-> evaluate reconstruction and held-out task metrics
-> emit immutable bundle
-> load complete bundle into a staging generation
-> validate basis/core/kernel digests on every TP rank
-> publish one collection generation atomically
-> retire the old generation after its last reference

Publishing a new basis before all matching cores are ready creates a mixed operator even when every tensor has the expected shape.

0x06G8 Method Alternatives And Paper Contracts

RepresentationShared statePer-adapter stateRuntime middle stageMain limit
original LoRAnonetwo adapter-specific projectionsresidency and transfer scale linearly with
per-adapter SVDnonereduced-rank factors per adaptertwo adapter-specific projectionscannot amortize bases across the collection
JD-Diagelementwise coreonly shared rank-one atoms
JD-Fullsmall grouped matrix multiplylarger cores; useful rank can grow with diversity
clustered JD-Full plus assignmentgroup by cluster, then by adapter coremore shared residency and scheduling fragmentation
keep original and pageno approximationoriginal factorsexisting Punica/S-LoRA/vLLM pathload/offload pressure remains

The final paper uses custom vLLM changes and Punica-style grouped operations, and publishes pseudocode for an A -> Sigma -> B path. No revision-pinned official implementation is used as evidence here: the authors’ public code link resolves to the Lots-of-LoRAs model/data organization, not a source tree for the modified serving runtime. Paper pseudocode and measured results remain paper evidence.

Source-reported results include experiments with up to 1000 trained LoRAs and a serving sweep to 1024 unique adapters. The paper reports about throughput improvement over its matched-memory vLLM multi-LoRA baseline at the largest setting and about 80% of the no-LoRA/single-merged-model throughput. Those numbers depend on the selected rank/cluster setting, quality threshold, request trace, model, implementation, and hardware. They are not a prediction for this blog’s toy fixture or another runtime.

0x06G9 Collection Compression Failure Lab

FailureDetectionRequired response
wrong source factor orientation or scalereconstruct source under manifest before fittingreject conversion
one core paired with stale basisbasis/core digest or generation mismatchreject admission/launch
source set changes under same collection versionordered source-set digest differscreate a new collection version
parameter savings claimed with non-positive break-even denominatorevaluate symbolic inequalityreport no count-model break-even
JD-Diag assumed as expressive as JD-Fullcompare collection span and validation errorraise rank, use full cores, or cluster
low reconstruction error treated as quality proofheld-out task manifest absentblock release
lower bytes treated as lower TPOTruntime measurement absentkeep latency claim unverified
one TP rank publishes new basis earlydistributed generation snapshot differsfail closed and roll back staging generation

0x06H Executable Loop 6 Oracle

The repository fixture closes the bounded algebraic and metadata contract:

two-rank first projection:
    shard A on rank axis and B on output axis
    all-gather bottleneck slices
    prove concatenated output equals X A B

two-rank second projection:
    shard input/A on input axis and B on output axis
    all-reduce bottleneck partials
    fuse disjoint adapter output slices into the base final all-reduce

three-adapter collection:
    prove JD-Full reconstruction and runtime output exactly
    prove collection span rank 3 exceeds rank-2 JD-Diag capacity
    derive parameter counts and integer break-even points
    bind source adapters, bases, cores, TP ABI, and generations

Fifty-eight negative fixtures reject source overclaims, wrong axes, missing or reordered collective contracts, malformed shards, non-orthonormal full bases, stale source/core/basis digests, mixed collection generations, and empirical claims outside the oracle’s evidence surface.

0x07 Merge, Unmerge, And Hotswap Are Different Operations

The word merge is overloaded. A framework can add one delta into one layer, remove adapter wrappers from an entire model, replace tensors in an allocated adapter slot, or publish a new serving generation. Those operations do not have the same rollback, concurrency, or identity contract.

0x07A Operation Taxonomy And Object Identity

OperationWeight state after the operationAdapter factors retained?Request-time selection?Canonical rollback
live adapterimmutable base plus selected factorsyesyesstop selecting the adapter
merge_adapterdelta added to wrapped base layersyesno for merged adapterarithmetic unmerge, with precision caveat
arithmetic unmergestored delta subtracted from current base tensorsyesrestoredreload clean base when exactness matters
merge_and_unloadmerged plain-model modulesno LoRA wrappersnoreload immutable base artifact
unloadplain-model modules without adding deltawrappers removednoreload adapter to restore adaptation
framework hotswapfactor tensors replaced inside one adapter name/slotyesadapter remains liveload old factors again
runtime generation swapcatalog publishes a new immutable slot handleold generation retires lateryespublish another generation
immutable merged releasenew full checkpoint or deployment artifactnot required at runtimenorelease/traffic rollback

The identities differ as well. A live adapter revision is not a merged base revision, and a mutable resident slot is not the semantic adapter artifact:

Changing any field creates a different executable object even if a human-facing alias remains tenant-a.

0x07B Derive Live And Merged Equivalence

Let requests be rows of , use the checkpoint orientation , and let and . The live branch is

Associativity gives

Therefore a merged weight

produces

This is an algebraic identity over one consistent arithmetic and tensor orientation. It does not prove equality after independently rounding the live and merged paths, dequantizing a base, changing accumulation dtype, omitting a target module, or applying a different scale convention.

0x07B1 Exact Old And New Adapter Trace

The Loop 7 fixture uses

The old rank-two adapter has and produces

For , both the live and merged operators return

The new adapter has logical rank one but occupies a physical rank-two slot. Its second row of and second column of are zero, so padding cannot inherit bytes from the old adapter. With :

The operator shape remains rank two; the semantic work remains rank one. This is the same logical-rank versus physical-capacity distinction established in Loop 4, now applied to slot replacement.

0x07C Arithmetic Unmerge Is Not Exact Rollback

In exact arithmetic, subtracting the same delta recovers the base:

A stored tensor does not execute exact real arithmetic. Let denote one rounding or quantization step. A representative merge/unmerge path is

There is no identity requiring . A binary16 scalar counterexample is enough:

clean base:                  2048
delta:                          1
binary16 merge:              2048 + 1 -> 2048
binary16 arithmetic unmerge: 2048 - 1 -> 2047
all values finite:           yes
exact round trip:            no

The unit in the last place at 2048 is 2. The merge loses the increment, while the subsequent subtraction rounds to the adjacent representable value. A finiteness check accepts this result because neither NaN nor infinity appears. Quantized bases add dequantize, requantize, scale, zero-point, packing, and saturation decisions, so an exact arithmetic rollback claim is even weaker.

The operational rule is:

immutable clean base is the rollback source
merged checkpoint is a new base revision
arithmetic unmerge is a convenience operation, not artifact recovery

0x07D What Pinned PEFT Actually Guarantees

The PEFT v0.19.1 source establishes narrower contracts than a generic claim that “safe merge is transactional”:

  1. Linear.merge(safe_merge=True) clones one base-layer weight, adds that layer’s delta, checks that the result is finite, installs the clone, and only then records the adapter as merged.
  2. unmerge() pops merged adapters in reverse order and subtracts each delta. It therefore inherits finite-precision drift.
  3. get_delta_weight() can temporarily cast CPU FP16/BF16 factors to FP32 for the matrix multiplication and cast the delta back. Dtype scheduling is part of the result.
  4. merge_adapter retains wrappers and factors; merge_and_unload merges and replaces wrappers with base modules; unload removes wrappers without merging.
  5. Whole-model merge/unload iterates modules. A later module can fail after an earlier one changed, so layer-local safe_merge is not a whole-model atomic transaction or rollback mechanism.

For compiled hotswap, the pinned preparation path can tensorize scaling and pad factor storage to a configured maximum rank. It must run after the first adapter is loaded and before compilation, and differing target layers remain unsupported. The hotswap path dry-runs incoming keys, rejects unexpected keys, zeros stale old weights for missing incoming keys, updates scaling, and then uses tensor swap for the ordinary path or in-place copy for compiled tensors. Unused physical-rank tails are zero-filled.

Those are useful framework mechanics. They still do not provide one global all-module transaction, compensating rollback after a partial copy, request leases, stream/event fencing, or production multi-request concurrency safety. Loop 7 adds those as rewrite contracts, not as PEFT claims.

0x07E vLLM Registration Is Not Same-Alias Hotswap

The pinned vLLM v0.12.0 serving surface serializes adapter loading by LoRA name, rejects a duplicate name, allocates a new integer ID, asks the engine to add the adapter, and publishes the request in its serving registry. Unload removes the registered name. Worker-side mutation is explicitly not thread-safe and relies on the single-threaded core engine loop; activation copies LoRA tensors into a free GPU slot.

Its LoRARequest carries name, integer ID, and path, but no slot generation or pointer generation. Therefore the stricter same-alias, overlapping-generation protocol below is not a description of vLLM v0.12.0. It is the runtime contract required if an implementation chooses to offer that feature.

0x07F A Hotswap Is A Publication Transaction

A slot handle is valid only as one tuple:

The catalog maps an alias at generation to that immutable handle:

The exact fixture starts with

catalog generation 8
tenant-a -> slot 7 / slot generation 12 / pointer generation 31 / old digest

old request lease
request-old -> the same four-part old handle
refcount(slot 7) = 1
last-use event(slot 7) = incomplete

The replacement is staged in free slot 8. It is not visible merely because the copy began or the factor shapes fit. Publication requires

After one atomic catalog update:

catalog generation 9
tenant-a -> slot 8 / slot generation 21 / pointer generation 41 / new digest

request-old keeps the old handle and output [4, 19/2]
request-new binds the new handle and output [5, 3]
slot 7 becomes retiring; slot 8 becomes active
Lifecycle diagram separating exact live and merged LoRA outputs, finite-precision unmerge drift, shadow-slot publication, old and new request leases, and reference-plus-event reclamation.

0x07G Shadow-Copy Publication Algorithm

def publish_replacement(alias, artifact):
    old = catalog.resolve(alias)  # immutable generation handle
    validate_artifact(artifact, base_abi, target_signature)

    shadow = reserve_free_slot(next_generation=True)
    try:
        zero_physical_rank_tail(shadow, artifact.logical_rank)
        copy_all_module_tensors(shadow, artifact)
        validate_staged_digest_layout_and_finiteness(shadow, artifact)

        copy_done = record_event(copy_stream)
        publication_stream.wait_event(copy_done)

        new = shadow.freeze_handle(
            artifact_digest=artifact.digest,
            pointer_generation=shadow.pointer_generation + 1,
        )
        catalog.compare_and_publish(alias, expected=old, replacement=new)
        mark_active(new)
        mark_retiring(old)
        return new
    except Exception:
        # Catalog still points at old. No new request can bind shadow.
        discard_shadow_and_bump_generations(shadow)
        raise

The event semantics are deliberately modest. CUDA documents that a recorded event completes after preceding work in its stream and that a waiting stream’s subsequent work waits for that event. This article does not execute a CUDA event or prove a production control plane. The fixture checks the required state ordering only.

0x07H Request Leases Prevent Mixed Generations

A request resolves the alias once at admission and retains the resulting lease for its lifetime:

def bind_request(request, alias):
    handle = catalog.resolve(alias)
    reject_if_stale(handle)
    increment_refcount(handle)
    request.adapter_lease = handle

def build_launch(request):
    handle = request.adapter_lease  # do not re-resolve alias per iteration
    assert pointer_table.matches(handle)
    return launch_snapshot(handle)

Re-resolving tenant-a during every decode iteration can move one request from old factors to new factors after publication. That would also violate the KV provenance contract in 0x08 whenever the adapter changes K/V-producing projections. A stable request lease closes both the factor and cache identity.

The old slot may be reclaimed only when

The reference count protects submitted and queued logical users. The event protects asynchronous device work after host ownership was released. Neither substitutes for the other. Reclamation increments both slot and pointer generations, so a delayed stale handle cannot become valid again when slot 7 is reused: this is the ABA defense.

0x07I Failure, Rollback, And Post-Publish Recovery

The fixture injects failure while copying the new module tensors, before publication:

catalog remains generation 8 and still names old slot 7
old request output remains [4, 19/2]
no request can bind the shadow slot
partial new weights are never visible
shadow slot returns to free with bumped slot/pointer generations

This is rollback because the visible catalog never changed. Once generation 9 is published and requests bind it, silently mapping the alias back to generation 8 is not an in-place undo: it can strand new requests, violate refcounts, and reintroduce an already-retiring handle. Post-publication recovery must stage and publish another generation, with the old artifact bytes or another approved revision, under the same copy and retirement rules.

0x07J Cost Ledger And Design Alternatives

Shadow publication pays overlap memory:

It also pays copy and validation time before publication, plus old-generation retirement time afterward. Those costs are not adapter-kernel TPOT. They belong to control-plane availability and cold-transition ledgers.

DesignExtra resident capacityAvailability during changeRequired fenceAppropriate use
drain then overwrite in placeno extra slotblocks new work and waits old workold refcount zero and last-use event completememory-constrained, infrequent maintenance
shadow copy then publishone compatible slotold and new generations overlapcopy event before publish; retire event before reclaimsame alias with low interruption
load under a new aliasone slotcaller migrates explicitlynormal request binding and old-alias drainsimplest versioned API
immutable merged releasefull model artifact/deploymentseparate rolloutrelease validation and traffic cutoverstable single-adapter product

PEFT compiled hotswap optimizes replacement inside a prepared model; vLLM’s pinned API loads a distinct name/ID; the shadow protocol specifies a stronger serving feature. These contracts solve different problems and should not be presented as interchangeable implementations.

0x07K Lifecycle Failure Lab

FailureWhy shape checks miss itRequired response
arithmetic unmerge treated as exact artifact rollbackevery tensor remains finite and shape-correctreload immutable clean base
per-layer safe merge called whole-model atomican early layer can change before a later failurestage a new model artifact or implement compensating transaction
compiled slot tail not zeroed after rank decreaseallocated shapes are unchangedzero unused A rows and B columns before validation
missing incoming key leaves old factor bytesold tensor still has valid shapeexplicit zero or reject according to compatibility policy
alias published before copy eventcatalog and pointer shapes look validwait event, validate digest/layout, then publish once
request re-resolves alias each decode iterationalias is valid before and after updateretain admission-time generation lease
retiring slot reclaimed on refcount alonehost users are gone but GPU work can remainrequire refcount zero and completed last-use event
retiring slot reclaimed on event alonequeued/submitted logical owners can remainrequire event and reference conditions
reused slot keeps same generationstale pointer can pass identity comparisonbump slot and pointer generations
pre-publication failure exposes staged pointerfactor contents can be partial across moduleskeep shadow unreachable and discard it
post-publication rollback mutates catalog backwardnew-generation requests already existpublish another generation transaction
framework behavior presented as runtime prooflibrary code lacks request and event ownershiplabel source claim and rewrite contract separately

0x07L Executable Loop 7 Oracle

The local rational and integer oracle proves only the bounded contract:

old and new live outputs equal their merged outputs exactly
logical rank 1 equals zero-padded physical rank 2
binary16 arithmetic merge/unmerge drifts 2048 -> 2047
old and new requests remain bound to distinct immutable handles
shadow copy failure leaves the old catalog and output unchanged
retirement needs both refcount zero and last-use event completion
slot and pointer generations advance on aborted staging and reclaim
86 one-field failures reject source overclaims, malformed tensors,
identity drift, unsafe ordering, early reclamation, and claim inflation

It imports neither PEFT nor vLLM, copies no GPU tensor, records no CUDA event, compiles no graph, and measures no latency, throughput, or model quality.

0x08 Adapter And KV Compatibility

An adapter does not merely accompany a request. It may become an ancestor of the K/V rows already stored for that request. The owner question is therefore:

Given a fixed token interval, which adapter execution facts change the mathematical K/V rows, which facts change only later logits, and which physical runtime facts must stay outside the semantic prefix key?

The answer is not “check whether the adapter targets k_proj or v_proj.” Direct K/V targets are the simplest incompatibility, but a query, output, or MLP update in an earlier layer can change the hidden state projected into K/V by every downstream layer. Conversely, an output-head-only adapter can change prompt logits while leaving every K/V row unchanged. Exact reuse needs an architecture dependency closure and an interval-specific activation schedule, not a module-name shortcut.

This section owns the adapter projection supplied to M5’s cache contract. It does not reimplement M5.3’s block hash, radix tree, allocator, reference counts, copy-on-write, or immutable prefix-match receipt.

0x08A Derive K/V From Effective Per-Token Operators

Let say whether adapter is active at token position . For module in layer , define the effective operator

For the pre-normalized hidden row ,

A direct K update produces

That equation is necessary but not sufficient. The hidden row is itself a causal recurrence:

Even when , an adapted ancestor can make differ. Cache identity follows the full producer graph, not only the final projection names.

0x08B The Cache-Ancestor Closure

For a conventional serial decoder block, a conservative ancestor set for one cached row is

The same-layer Q, O, and MLP operators are not ancestors of K/V that were already projected at that layer. They are ancestors of downstream-layer K/V, and their effects can propagate to later tokens through causal attention. A parallel attention/MLP block, post-norm model, recurrent state-space layer, or other architecture needs its own graph. The graph revision is therefore part of the compatibility manifest.

Define an affected-row predicate

Two K/V rows are compatible only if their exact inputs, position contract, representation, and effective operators agree throughout the ancestor closure:

where is the immutable execution manifest. Equality of raw bytes or tensor shapes does not prove this condition. The implication is written in the safe direction: an implementation may conservatively reject equivalent rows if it lacks a proof, but it may not accept incompatible rows because a target-name allowlist looked harmless.

0x08C Exact Two-Layer Dependency Witness

The local Loop 8 fixture uses a two-token, two-layer scalar-head witness. It keeps the softmax arithmetic exact by selecting logits whose exponentials are integers. The input rows are

Choose

Layer 0 therefore stores

A Q-only adapter leaves those rows unchanged. For token 1, let the base query produce logits and the adapted query produce . Then

With values , the attention contexts are

Let the output direction be . After the residual update,

Now project the next layer with

The downstream cache rows differ:

The trace proves the missing implication:

layer-0 Q update
    -> layer-0 K/V rows unchanged
    -> layer-0 attention output changes
    -> layer-1 hidden input changes
    -> layer-1 K/V rows change

For comparison, a direct K delta changes layer-0 K from [0, 1] to [1, 3] immediately. Both paths invalidate ordinary raw-adapter cross-reuse, but for different graph reasons.

0x08D K/V Compatibility Is Not Prompt-Output Compatibility

Suppose an adapter changes only the final LM head. For fixed final hidden row , use

The logits change from

while every K/V row remains unchanged. This creates two independent questions:

Reused objectRequired equality
K/V prefix onlycache-producing ancestor closure
cached final hidden statehidden-state producer closure
cached prompt logitshidden-state closure plus LM-head operator
sampled continuationK/V and logits for the fixed prefix, then the actual token/RNG policy

A runtime may reuse the K/V payload for an LM-head-only adapter, but it may not reuse base prompt logits as adapter logits. Likewise, equal K/V does not mean future generated token IDs will remain equal. M5 keys exact past state; the sampler owns the future branch.

0x08E Activated LoRA Makes Activation A Position Function

Activated LoRA changes ordinary LoRA’s always-on schedule. Let be the first token of the chosen invocation occurrence:

The projected matrices become piecewise:

with corresponding equations for Q, V, and any adapted MLP/operator. The important boundary is strict:

[0, t_invoke)     base execution; eligible for base/aLoRA sharing
[t_invoke, T)     adapter execution; adapter-specific cache

For tokens=[11,12,99,100] and invocation tokens [99,100], pinned PEFT v0.19.1 derives

and applies the adapter to the last o rows:

position:       0      1      2      3
token:         11     12     99     100
adapter mask: false  false   true   true
reusable base frontier: [0,2)

PEFT searches for the last exact invocation-token occurrence. For [99,100,11,99,100,12], the last start is 3, the backward offset is 3, and rows 3 through 5 are adapted. Tokenization therefore belongs to the activation contract: a matching text substring is insufficient if its token IDs do not contain the exact invocation sequence.

Adapter and KV compatibility trace showing direct and downstream dependency paths, aLoRA's base-only prefix and adapter-specific suffix, interval execution identities, legal prefix forks, and rejected cache relabeling

0x08F Why The Pre-Invocation Prefix Is Equal

The aLoRA paper’s proposition is an induction over causal positions and layer depth, not an assertion that arbitrary LoRA caches happen to be close.

  1. For every , the adapter mask is zero for every adapted operator.
  2. Layer 0 therefore receives the same token/position input and uses the same effective Q/K/V/MLP operators as the base model.
  3. Causal attention at those positions cannot observe later activated rows.
  4. The layer output is equal, so the next layer receives equal hidden rows.
  5. Induction over layers proves all internal states, including K/V, equal on .

Formally,

After invocation, that equality no longer licenses cross-adapter reuse. The paper explicitly treats adapter-generated suffix cache as adapter-specific. For adapters sharing base rows and processing activated rows, its source-reported asymptotic ledger is

versus ordinary LoRA’s recomputed-prefix terms

These are paper-model asymptotics, not a local latency reproduction. Block granularity, batching, kernel support, cache-copy policy, and scheduling can change realized savings.

0x08G Training And Pinned PEFT Runtime Contract

aLoRA’s cache property is created during training. The paper’s SFT contract uses an input/context followed by an invocation and completion:

context tokens:
    adapter disabled
    normally excluded from completion loss

invocation tokens and completion:
    adapter enabled
    completion labels train the specialized behavior

The authors adapt attention projections and note that MLP adaptation can use the same position-gated construction. They also report that aLoRA can require higher rank than ordinary LoRA in some tasks. Those are training design choices; cache equivalence still comes from the zero adapter mask before the boundary.

At revision ba6a190..., PEFT implements a narrower concrete contract:

Pinned behaviorServing consequence
find last exact invocation-token subsequenceactivation depends on full tokenized input, not a text search
return offset T - start and mask the last offset rowsthe first invocation token is adapted
invocation absent -> None offset -> base patha product expecting specialization should reject rather than silently accept base behavior
inputs_embeds without token IDs -> aLoRA disabled with warningside-input-only requests need an explicit offset or fail-closed policy
post-activation cache documented as adapter-taintedpreserve a clean fork before activation if another branch needs base cache
merge/unmerge unsupportedselective per-token execution cannot be replaced by one static merged weight
beam search unsupported in the pinned pathserving admission must reject unsupported generation mode

PEFT’s DynamicCache examples show two useful patterns. Base-to-aLoRA can pass the clean base cache into the activated continuation. aLoRA-to-base or aLoRA-to-another-aLoRA preserves a deep copy/fork of the clean shared prefix before the first branch taints its suffix. Those examples demonstrate caller cache handling; they do not implement M5.3’s multi-tenant prefix index, generation receipt, or authorization boundary.

0x08H Project Adapter State Into An Interval Execution Digest

M5.1 defines the logical cache ABI. M5.3 defines the physical layout, candidate key, namespace, references, and exact-reuse receipt. M6.5 supplies one field that neither article can infer alone:

The interval-specific cache projection is:

covered token IDs and position IDs
base execution ABI
interval execution digest E_[s,e)
dependency-graph revision
cache schema, dtype, quantization, and local shard
position / RoPE / visibility contract
side-input identity
isolation namespace

The following are ownership or future-policy fields, not mathematical K/V compatibility fields:

request ID
adapter catalog alias
resident slot ID
slot generation
pointer generation
physical K/V block IDs
sampling policy

The raw requested adapter ID is retained in the immutable request manifest, but it is not blindly copied into every interval key. For ordinary always-on LoRA, includes the adapter revision from position 0. For aLoRA, an interval wholly before invocation normalizes to the base execution digest, allowing several adapters to share it. An interval touching or following the boundary includes the active adapter revision and activation schedule.

This avoids two opposite bugs:

raw adapter ID in every pre-invocation block:
    safe but destroys aLoRA's intended base-prefix sharing

adapter omitted after activation:
    unsafe cross-adapter hit over different K/V rows

If a prefix engine indexes only full token blocks and the activation boundary falls inside a block, the reusable indexed length may stop at the preceding full block even though individual rows before the boundary are equal. Partial tail publication and lookup remain M5.3 policies.

0x08I Prefix Lookup And Publication Protocol

def acquire_adapter_compatible_prefix(request, cache_index):
    manifest = freeze_request_model_adapter_activation_manifest(request)
    execution = derive_interval_execution_digests(
        tokens=manifest.token_ids,
        positions=manifest.position_ids,
        base_abi=manifest.base_execution_abi,
        adapter=manifest.adapter_artifact,
        activation=manifest.activation_schedule,
        dependency_graph=manifest.dependency_graph_revision,
    )

    namespace = authorize_cache_namespace(manifest.isolation)
    candidate = cache_index.lookup_longest(
        namespace=namespace,
        token_ids=manifest.token_ids,
        execution_digests=execution,
        cache_abi=manifest.cache_abi,
    )

    receipt = validate_and_acquire_m5_prefix_receipt(candidate, manifest)
    branch = fork_copy_on_write(receipt)

    first_incompatible = receipt.covered_end
    suffix = run_prefill_suffix(
        branch,
        manifest.token_ids[first_incompatible:],
        activation=manifest.activation_schedule,
    )
    return publish_complete_suffix_rows(branch, suffix)

The ordering is mandatory:

freeze semantics
    -> derive interval execution
    -> authorize namespace
    -> lookup and validate candidate
    -> acquire immutable M5 receipt
    -> fork shared prefix
    -> compute first incompatible suffix
    -> publish all-layer suffix rows

A cache mismatch rejects the candidate without mutating the producer. Failure before suffix publication discards unpublished rows and retains the old receipt. Failure after a successor publication is repaired by another generation transaction. Old adapter rows are never relabeled as new adapter or base rows.

0x08J Mid-Request Switch Cases

SwitchReusable K/V in the four-token fixtureRequired action
ordinary LoRA A -> ordinary LoRA B0reject switch or recompute the full prefix under B
base -> aLoRA A at position 22fork clean base prefix [0,2), compute invocation and suffix under A
aLoRA A -> base after position 22return to a saved clean fork or recompute the tainted suffix
aLoRA A -> aLoRA B, same boundary2share base prefix only; fork distinct adapter suffixes
same aLoRA artifact, different boundary1 in the exact fixtureactivation schedule changes the execution digest
LM-head-only adapter4 K/V rowsreuse K/V but recompute adapter-specific prompt logits
same semantic adapter relocated to another slot4reuse; physical slot identity is not semantic K/V identity

Ordinary LoRA’s conservative full-prefix recompute is deliberate. A more specialized engine could prove a longer layer- or row-specific compatible prefix, but then it must version the architecture graph, preserve the needed intermediate state, and still satisfy M5’s all-layer publication contract. Most engines gain little by turning this edge case into a second cache ABI.

0x08K Design Alternatives

DesignSafety proofReuseCost / limitation
raw adapter revision in every keysimple and conservativenone across adapter IDsmisses output-only and pre-invocation equivalence
dependency-closed interval digestarchitecture graph plus activation schedulemaximal under the proven graphcomplex versioning and negative-test surface
aLoRA boundary contractpaper-proven base equality before invocationclean prefix shared across base and aLoRAsmethod-specific training/runtime and tainted suffix handling
full prefix recompute on every switchno cross-adapter equality needednonehighest prefill latency and duplicate cache memory
layer-selective recomputeper-layer dependency and intermediate-state proofpotentially moreusually requires hidden-state materialization and a new publication ABI

The recommended default is conservative ordinary-LoRA identity plus the explicit aLoRA exception. General dependency-closed reuse should be added only when the runtime can validate the model graph and test every supported target pattern.

0x08L Adapter/KV Failure Lab

FailureWhy it looks plausibleRequired closure
check only k_proj/v_proj targetsQ/O/MLP factors are absent from direct projectioncompute architecture dependency closure or reject conservatively
reuse base cache for ordinary Q-only LoRAcurrent layer K/V shapes and bytes matchdownstream K/V can differ; recompute or use proven interval contract
require raw aLoRA ID before invocationadapter is attached to requestnormalize proven inactive interval to base execution digest
omit aLoRA ID after invocationprefix began under base executionfork at boundary; suffix is adapter-specific
use first invocation occurrencetoken sequence contains a valid markerpinned PEFT uses the last exact occurrence
activate after the invocation tokensphrase “after invocation” is ambiguouspinned implementation starts at the first invocation token
invocation absent silently runs product as basePEFT’s row-level fallback is shape-safereject when the product contract requires specialization
inputs_embeds request silently disables aLoRAPEFT cannot derive token offsetsrequire explicit verified offsets or reject
mutate one cache from base -> A -> basetensor allocation remains validkeep clean fork; never relabel tainted suffix
adapter revision omitted under same aliasname still matches runtime keycontent changed; advance execution digest and cache namespace
slot generation added to semantic prefix keyprotects pointer lifetime elsewheredestroys reuse after harmless relocation; keep it in ownership receipt
K/V match treated as cached-logit matchoutput-only adapter leaves K/V unchangedrecompute hidden/logit artifact under its own compatibility contract
boundary falls inside full block but whole block is reusedmost rows are base-equivalentstop at legal block/tail frontier owned by M5.3
cache candidate validated before authorizationbytes may never be returnedlookup itself can leak cross-tenant prefix existence; authorize first

0x08M Executable Loop 8 Oracle

The local exact oracle proves only the bounded teaching contract:

direct K adaptation changes layer-0 K from [0,1] to [1,3]
Q-only adaptation leaves layer-0 K/V unchanged but changes layer-1
    K from 6 to 7 and V from 4 to 9/2
LM-head-only adaptation changes logits [3,1] -> [6,0] with unchanged K/V
PEFT-style last-occurrence offsets produce masks [F,F,T,T]
    and [F,F,F,T,T,T]
base, ordinary LoRA, aLoRA, output-only, relocation, position,
    representation, layout, and token compatibility cases close exactly
pre-invocation execution normalizes to base; post-invocation does not
semantic execution fields remain separate from slot/block ownership fields
55 one-field malformed fixtures fail closed with 52 distinct error codes

It executes no Transformer, PEFT model, attention kernel, vLLM cache lookup, GPU allocation, paper benchmark, latency test, throughput test, or model-quality evaluation. The softmax witness proves one dependency path; the conservative graph projection is a rewrite contract for unsupported target combinations, not a claim that pinned PEFT or vLLM implements that general key.

0x09 Scheduler, Fairness, Observability, And Recovery

An adapter-aware scheduler does not replace the serving scheduler built in M5.2. It extends one already-legal iteration plan with new facts:

which immutable adapter artifact the request names
whether its exact generation is resident and published
whether the worker supports every target/rank/layout
how many adapter, basis, temporary, and K/V pages the request reserves
which phase-specific heterogeneous kernel can execute its rows
how much cold-load, rank-padding, run-fragmentation, and collective work it adds

That distinction is the owner contract for this loop.

M5.2 still ownsM6.5 Loop 9 adds
request state and legal row intervalsimmutable adapter execution identity
token, sequence, and future-state budgetsadapter/basis residency and published generation
TTFT/TBT clocks and SLO feasibilitycold-load time and adapter-specific readiness
generic continuous batching and chunked prefilladapter run, rank, target, and basis affinity
client/job/group fairness definitionsprojections by adapter class and load eligibility
preemption, resume, and completed-service publicationadapter load rollback and request-generation revalidation

Loop 9 therefore does not claim a new continuous-batching scheduler or a new fairness theorem. It asks a narrower systems question:

Once M5 has declared which work is legal and urgent, how should adapter residency, heterogeneous execution cost, fairness projections, telemetry, and load failure change the decision without weakening M5’s contracts?

0x09A State Added By An Adapter Request

For request on worker , freeze an adapter execution record:

where:

SymbolMeaning
immutable artifact/content digest
requested semantic adapter generation
module-specific logical-rank vector
target-module and factor-layout manifest
optional shared-basis/cluster identity from Loop 6
worker residency state: cold, loading, resident, retiring, failed
atomically published worker generation
worker kernel/TP/layout capability contract
adapter generation the catalog currently publishes for the request’s alias
the that bound at admission and keeps for its lifetime (0x07H); a later hotswap does not change it

This record is not the whole request. M5 still owns prompt length, decode frontier, K/V state, deadline clocks, cancellation state, and the candidate iteration budget. Adapter state is an additional execution prerequisite.

The scheduler must also retain separate clocks:

request arrival clock          never reset by adapter loading or retry
adapter-load attempt clock     new attempt ID for every reservation/copy
generation-publication clock   advances only after validated copy completion
iteration selection clock      planned work, not completed service
iteration result clock         authoritative completed-service publication

Resetting request age after a cold load makes loading delay disappear from TTFT and can manufacture apparent fairness. Reusing a failed load attempt ID can make stale copy events appear to complete the current generation.

0x09B Five Predicates, Not One Score

A single weighted score hides incompatible logical states. A large affinity bonus can accidentally make an unsupported or stale request look selectable. Use five predicates instead.

1. Adapter feasibility

This predicate consumes the exact artifact checks from Loop 2, joint adapter/K/V reservation from Loop 5, TP placement from Loop 6, and K/V compatibility from Loop 8. The generation test compares with the request’s lease, not with the catalog’s current generation: after a hotswap (0x07F) an in-flight request still holds the old generation, and 0x07H requires it to finish on that generation. A request admitted after the hotswap leases the new , so asking for a superseded generation still fails.

2. Adapter readiness

A cold request can be feasible without being ready. A resident slot with the wrong generation is neither ready nor a cache hit.

is true when already holds a refcounted lease (0x07H) on the slot that serves on worker ; , the copy event, and describe that slot. A retiring slot accepts no new binds, but the requests that leased it before a hotswap stay ready on it. After the publication in 0x07F, request-old keeps running on retiring slot 7 with its generation-8 lease while request-new binds generation 9 on slot 8, and the refcount and last-use event keep slot 7 from being reclaimed under it.

3. Execution eligibility

Only this intersection may enter an adapter kernel launch. A cold request may instead be load-eligible, which authorizes a prefetch transaction but not a model row.

4. Preference

Preference orders already-legal candidates. It may improve affinity, fairness, or expected cost. It cannot repair a failed predicate.

5. Selection and completion

Selected is a plan. Completed is a publication event. Adapter prefetch, failed copies, cancelled rows, speculative plans, and recomputation do not become completed tenant service merely because they consumed GPU time.

The distinction is easy to test in one snapshot:

RequestFeasible?Ready?Reason
r_hot, resident A generation 7yesyesexact generation and supported rank/targets
r_cold, cold B generation 3yesnoload may be scheduled; model row may not
r_peer, resident C generation 5yesyesshares basis 0 with A but retains distinct artifact
r_stale, requests A generation 6nonopublished generation is 7; holds no generation-6 lease
r_rank, rank 32 on max-rank-16 workernonobackend ABI unsupported

The Loop 9 fixture selects only from r_hot and r_peer; it cannot promote r_cold, r_stale, or r_rank by adding affinity weight.

0x09C The Adapter Cost Is A Vector

The original score sketch collapsed unlike units. Replace it with a cost vector that can be measured and constrained independently:

For an iteration plan :

R_true predicts useful low-rank row work. R_pad exposes a fixed-slot backend’s padding overhead. Delta N_runs predicts segmented launch and metadata fragmentation. Load bytes, joint pages, and collective bytes are not interchangeable with either rank ledger.

A conservative local ordering can therefore be lexicographic:

Lower keys run first. The ordering means:

  1. preserve M5’s urgency/deadline class;
  2. prefer the protected tenant with less completed weighted service;
  3. age requests so affinity cannot defer one forever;
  4. minimize adapter load, basis load, run, padding, page, and collective cost;
  5. break ties deterministically.

This is a Transformer System teaching policy, not Punica, S-LoRA, VTC, or vLLM. In particular, no VTC bound transfers after adding readiness, loading, prefetch, or this completion-reconciled ordering.

0x09D PetS: Two-Stage Coordinated Batching

PetS predates modern autoregressive multi-LoRA engines, but it exposes the first important scheduling decomposition: shared operators and task-specific operators need different grouping decisions.

For macro-batch , PetS models latency as:

alpha models the shared operator over total batch size and maximum length . beta models PET type , same-task mini-batch size , and length .

Why the Bellman recurrence appears

Within one task, sort requests by length. If the last mini-batch contains requests , every earlier request must already be optimally partitioned; otherwise replacing that prefix with a cheaper partition would improve the whole solution. This optimal-substructure argument gives:

After producing same-task mini-batches, sort those mini-batches by maximum length and repeat the argument for shared operators:

The exact Loop 9 toy table gives:

task A lengths [2,4,8]
    optimal PET groups = [a0,a1] + [a2]
    cost = 7 + 9 = 16

task B lengths [3,3]
    optimal PET group = [b0,b1]
    cost = 6

sorted mini-batches = [taskB.mb0(max=3), taskA.mb0(max=4), taskA.mb1(max=8)]
optimal shared groups = [taskB.mb0,taskA.mb0] + [taskA.mb1]
cost = 10 + 9 = 19

PetS then orders PET operators with an operational-intensity proxy and assigns different intensities across streams to reduce resource conflict. But its latency model treats PET operators sequentially while its stream schedule can overlap them; the paper explicitly leaves a more accurate model and online QoS scheduling as future work. PetS therefore motivates hierarchical grouping. It does not prove a decoder K/V scheduler, LoRA cold-load policy, or tenant fairness contract.

0x09E Punica: Consolidation, Async Loading, And Migration

Punica uses a different owner object: a global scheduler places requests among GPU working sets while each GPU invokes the shared base path and heterogeneous LoRA rows.

For a new request, the paper’s candidate workers satisfy:

It then chooses the feasible worker with the largest working set:

The UUID is a deterministic tie-break in the paper. This consolidation policy keeps busy GPUs busy, lets lightly loaded GPUs drain, and leaves idle GPUs releasable.

The exact toy placement is:

WorkerWorking setFree K/V pagesFeasible for 8 pages?
gpu-08100yes
gpu-1125no
gpu-2820yes

gpu-0 and gpu-2 tie at working-set size 8, so the fixture’s UUID ordering selects gpu-2. The result reconstructs the source rule; it does not establish that consolidation is optimal for another topology, K/V allocator, or SLO mix.

Punica also separates placement from readiness:

adapter absent
    -> issue asynchronous host-to-device copy
    -> continue running the existing working set
    -> join the request only after adapter load completion

Under K/V pressure, the paper migrates the newest request to preserve FCFS, cancels its source execution, discards the newly generated token, and recomputes the prompt plus prior output on the destination rather than copying K/V. That is a paper-specific recovery choice. M5.2 and M5.5 still own whether recompute, preserve, transfer, or reject is legal in another runtime.

0x09F S-LoRA: Clustering, Prefetch, And Early Abort

S-LoRA adopts iteration-level scheduling, keeps the large adapter population in host memory, and loads only adapters needed by the active batch. Three policy choices matter here.

Adapter clustering

Let be the number of distinct adapters in plan . Prioritizing same-adapter requests can reduce:

but a hot adapter can then dominate the running batch. S-LoRA explicitly frames clustering as a throughput/latency/fairness tradeoff and studies cluster size in an ablation. “Fewer adapters per batch” is therefore an optimization objective, not a fairness rule.

Queue-derived prefetch

While batch runs, S-LoRA predicts adapter demand for from the current waiting queue and uses available GPU memory to overlap transfer with compute:

subject to available memory. The exact selection and benefit depend on the queue and memory policy. The Loop 9 fixture uses an explicitly labelled teaching FCFS first-fit rule:

waiting adapters = [B, B, C, D]
pages            = {B:3, C:4, D:2}
available        = 6
teaching choice  = [B,D] using 5 pages

This reproduces neither S-LoRA’s scheduler code nor a canonical paper algorithm. It merely makes the queue-to-prefetch state transition executable.

Early abort under overload

S-LoRA rejects a request whose estimated prefill can no longer meet its maximum latency:

Its appendix estimates a serviceable count . When the moving arrival estimate exceeds the moving admission estimate , it selects the newest serviceable requests; otherwise it selects the earliest. In the exact fixture:

t_now=10, estimated prefill=2, l=2, R1=5, R2=2
q0 arrival=0 -> infeasible
q1 arrival=4 -> feasible
q2 arrival=6 -> feasible
q3 arrival=8 -> feasible
overload choice -> [q3,q2]

Newest-first under overload maximizes the paper’s defined reward under stated assumptions. It can sacrifice old requests. Calling it “fair” would change the protected identity and objective without proof.

0x09G A Local Adapter-Aware Selection Trace

The local policy composes the closed contracts in this order:

def plan_adapter_extension(m5_candidates, worker, completed_service, now):
    classified = []
    for req in m5_candidates:
        adapter = req.adapter_lease  # bound at admission (0x07H), not re-resolved
        feasible = adapter_feasible(req, adapter, worker)  # Loops 2, 5, 6, 8
        ready = feasible and adapter_ready(req, adapter, worker)  # Ready_A: resident, or retiring under this lease
        classified.append((req, adapter, feasible, ready))

    # Cold work may request a load transaction. It is not a model row yet.
    load_candidates = [x for x in classified if x.feasible and not x.ready]
    prefetch = choose_by_m5_urgency_then_age(load_candidates)
    if prefetch is not None:
        begin_loop5_reservation_copy_publish(prefetch)

    executable = [x for x in classified if x.ready]
    executable.sort(key=lambda x: (
        m5_urgency_class(x.req),
        completed_service[x.req.tenant_id] / tenant_weight(x.req.tenant_id),
        -request_age(x.req, now),
        adapter_cost_vector(x, worker),
        x.req.arrival_tick,
        x.req.request_id,
    ))

    extension = pack_without_breaking_m5_budgets(executable)
    return publish_generation_stamped_plan(extension, prefetch)

The first line of defense is still m5_candidates. Adapter logic cannot make an M5-illegal token row legal. The second is the immutable generation snapshot. The third is readiness. Only then does the policy compare completed service, age, and affinity.

The static fixture has two ready requests:

r_hot  tenant completed service = 3, resident adapter A
r_peer tenant completed service = 1, resident adapter C

They share the same M5 urgency class. With a one-sequence budget, the local key chooses r_peer. The cold request is separately eligible for a load decision; the stale-generation and unsupported-rank requests fail closed.

0x09H Completed Service And Adapter-Specific Fairness Projections

Consume M5.2’s completed-service definition. For tenant :

Loop 9 may project the same completion events by adapter class :

The class may be a bounded operational grouping such as:

resident vs cold-loaded
rank bucket
phase
target signature
shared-basis cluster

But this projection is not tenant fairness. One adapter may serve many tenants; one tenant may use many adapters. Publishing equal service per adapter can still starve a tenant, and equal tenant service can still leave one cold adapter unloaded.

The readiness pipeline needs two liveness predicates.

Adapter-load starvation:

Tenant-service starvation, inherited from M5.2:

A cold adapter that never becomes ready is a load-starvation case, not yet an execution-eligible tenant-service starvation case. Keeping those predicates separate reveals whether the failure belongs to prefetch/residency or to batch selection after readiness.

0x09I Six-Tick Starvation Witness

The exact trace contains one resident adapter A, one cold adapter B, one cold request c0, and a new A request at every tick.

TickResident-greedyDeficit + age + affinity
0run h0run h0
1run h1run h1
2run h2prefetch B; run h2
3run h3publish B; run c0
4run h4run h3
5run h5run h4

Resident greed completes six hot-service units and never publishes B. The exact fixture records LoadStarved(B)=true. It does not claim ServiceStarved(cold tenant)=true, because B never became execution-ready.

The local policy triggers prefetch at age 2, publishes B at tick 3, and then selects the cold tenant because its completed service is 0 versus the hot tenant’s 3. The final ledger is:

resident-greedy:
    completed service = {hot:6}
    load-starved adapters = [B]

deficit + age + affinity:
    completed service = {hot:5, cold:1}
    load-starved adapters = []
    service-starved tenants = []

This proves progress only for one six-tick synthetic trace. It is not a universal wait bound, a VTC theorem, an SLO proof, or a production comparison.

Adapter-aware scheduler proof separating M5 legality from adapter feasibility and readiness, comparing resident-greedy load starvation with age-triggered prefetch and completed-service selection, mapping metrics to publication events, and rolling back a failed adapter load without resetting queue age

0x09J Prefetch And Admission Compete For Real Pages

Prefetch is speculative memory work. Admission is a commitment to a request. They must not draw independently from the same free-page counter.

For worker :

A prefetch candidate is safe only if its provisional reservation preserves the already-admitted K/V growth horizon:

The load state machine is:

load-eligible request
  -> provisional joint-page reservation
  -> asynchronous copy under attempt_id
  -> digest/layout validation
  -> copy-complete event
  -> atomic pointer + generation publication
  -> request may become execution-ready

Eviction, cancellation, timeout, or prediction changes before publication must release provisional pages. A prefetched adapter that is never used records wasted load bytes and occupancy time, not completed request service.

0x09K Observability Begins At Publication Events

A metric is meaningful only after naming the state transition that publishes it. Loop 9 uses this event spine:

EventWhat becomes authoritativeExample metrics
queue_enqueuedoriginal request arrival and identityqueue age, cold-wait histogram
prefetch_reservedprovisional pages owned by one attemptreserved pages, prediction count
adapter_load_startedtransfer attempt beganin-flight copies, requested bytes
adapter_load_completedcopy finished, not yet necessarily publishedH2D latency/bytes
adapter_generation_publishedvalidated addresses and generation visibleresidency state, cache hit eligibility
iteration_selectedimmutable plan chosenplanned rows/runs/rank work; zero service debit
iteration_completedexecution result knownsuccess/failure/cancelled rows
completed_service_debitedM5 service counters advancetenant and adapter-class completed service
prefetch_releasedprovisional ownership closedwasted-prefetch pages/bytes/time

For event , a counter increment is valid only when the event is the declared publication point:

This prevents three common errors:

  1. count a planned row as completed service;
  2. count copy completion as resident before generation publication;
  3. count reserved pages as both free and resident.

Metrics also need denominator and identity contracts:

The denominator must include failed, cancelled, or wasted attempts where the metric’s meaning requires them. Reporting only successful load latency hides failure tail behavior.

Cardinality is an operational contract

Do not attach raw request, tenant, or adapter IDs to default time-series labels. A large adapter catalog can turn one useful metric into millions of series. Keep default labels bounded:

phase
rank_bucket
residency_state
result
stage

Use sampled traces, logs, exemplars, or a bounded top-k/debug endpoint for raw identity. Per-tenant fairness accounting may remain in a state store without becoming an unbounded metrics label.

The exact event fixture publishes two queue arrivals, one adapter load, two selected iterations, two completions, and two service debits. It derives:

load-B-1 latency = 1 tick
completed queue wait = {h0:0, c0:3}
tenant-class completed service = {resident:1, cold:1}
adapter-class completed service = {resident:1, cold-loaded:1}

0x09L Recovery Is A Transaction, Not A Retry Label

Consider a cold adapter D with eight free pages and a three-page load.

tick 0  queue d0; reserve 3 pages for load-D-1      free=5
tick 1  load-D-1 fails; publish zero service
tick 1  rollback load-D-1 reservation               free=8
tick 3  reserve 3 pages for load-D-2                free=5
tick 3  validate and publish generation 2
tick 4  select and complete request; debit service=1
tick 5  release request reservation                 free=8

The original queue arrival remains tick 0. The second attempt gets a new ID and new generation. Failure closes ownership before retry.

def recover_adapter_load(req, attempt, error):
    mark_attempt_failed(attempt, error)       # no completed-service debit
    unpublish_if_never_committed(attempt)
    rollback_joint_reservation(attempt)
    release_copy_events_and_provisional_pins(attempt)

    req.load_attempt += 1
    req.queue_arrival_tick = req.original_arrival_tick  # never reset
    req.required_generation = catalog.current_generation(req.adapter_id)
    return retry_with_backoff_or_reject(req)

Recovery must also handle:

FailureRequired closure
stale generation discovered after planninginvalidate plan; release provisional pins; rebuild metadata
copy fails before publicationrollback reservation; old generation remains authoritative
failure after generation publicationretire through a successor generation; never mutate published addresses in place
request cancels during loadrelease request pin; keep or cancel shared prefetch by policy; preserve accounting
prefetch prediction becomes obsoletecancel before publication or publish as ordinary cache state; record wasted prefetch
selected iteration failspublish zero completed service; preserve M5 semantic frontiers
K/V grows into prefetched pagesforbid independent allocation; joint reservation/conservation must fail closed

0x09M Policy Alternatives And Failure Boundaries

There is no single adapter scheduler independent of product objective.

PolicyOptimizesMain riskRequired protection
FIFO after readinessarrival ordercold load blocks may dominate TTFTasync load and capacity admission
resident greedyzero/low load costadapter-load starvationage or load-progress quota
adapter clusteringfewer active adapters/runsother adapters waitbounded cluster window or age override
basis-cluster affinityshared-basis reusecluster dominancetenant and raw-adapter projections
rank/target bucketingefficient kernelslong-tail shape classes waitbucket aging and fallback backend
Punica-style consolidationhigh working-set densityhotspot/SLO imbalanceK/V feasibility and scale-out policy
S-LoRA-style early abortsource reward under overloadsacrifices old requestsexplicit offered/rejected outcome ledger
completed-service deficit + affinitytenant service before local efficiencyno inherited theorem after compositionmeasure gaps/starvation; claim only observed policy

Failure symptoms identify which predicate was collapsed:

SymptomLikely mistake
stale adapter pointer executesreadiness used adapter alias, not published generation
hot resident adapter monopolizes every tickaffinity had no load-progress/age protection
“fair” adapter distribution but one tenant receives nothingadapter class was mislabeled tenant identity
load latency absent from TTFTqueue clock reset at load start or completion
success rate looks high during overloadrejected/offered denominator omitted
resident bytes exceed joint poolprefetch and K/V reservations used independent free counters
fairness counters increase on failed kernelsplanned work was debited as completed service
load failure leaks pagesattempt did not close reservation/pin/copy ownership
monitoring backend overloadsraw adapter/tenant/request IDs became metric labels

0x09N Executable Loop 9 Oracle

The local artifact closes a bounded, exact teaching contract:

PetS dynamic programs recover intra-task cost 16 / 6 and macro cost 19
Punica placement filters K/V-infeasible gpu-1 and selects gpu-2 by tie-break
S-LoRA teaching prefetch chooses B,D in 5 of 6 pages
S-LoRA overload example chooses newest feasible q3,q2 under source reward
local snapshot separates feasible [r_cold,r_hot,r_peer]
    from ready [r_hot,r_peer] and selected [r_peer]
resident greed leaves adapter B load-starved across six ticks
age-triggered prefetch publishes B and completes cold request c0 at tick 3
event-derived counters reconcile load latency, queue wait, and completed service
failed load-D-1 restores all pages; load-D-2 completes without resetting age
64 one-field malformed fixtures fail closed with 54 distinct error codes

Run it with:

python3 docs/numinens-evidence/m6-5-multi-adapter-serving-runtime/adapter_scheduler_oracle.py \
  docs/numinens-evidence/m6-5-multi-adapter-serving-runtime/adapter_scheduler_fixture.json \
  --write-report docs/numinens-evidence/m6-5-multi-adapter-serving-runtime/loop9_report.json

The oracle executes no PetS, Punica, S-LoRA, vLLM, GPU allocator, adapter kernel, production scheduler, or paper benchmark. It proves no latency, throughput, SLO-attainment, universal bounded-wait, or fairness theorem. Its exact evidence is limited to the fixture’s Bellman tables, placement snapshot, prefetch/abort examples, six-tick trace, event ledger, and recovery transaction.

0x0A Punica, S-LoRA, PEFT, And vLLM Source-To-Runtime Oracle

The previous sections derived the states a serving runtime needs. We can now ask a harder question:

When Punica, S-LoRA, PEFT, and vLLM all say that they execute LoRA adapters, what is actually the same, what is represented differently, and where does each pinned source stop providing evidence?

The answer cannot be a feature table alone. A library can expose a method named load_adapter, a server can expose a route named load_lora_adapter, and a kernel wrapper can accept several weight pointers, while the three operations still have different identity, residency, activation, publication, and retirement semantics.

Loop 10 therefore uses four evidence layers:

LayerQuestionEvidence type
algebradoes a row receive the intended low-rank delta?exact rational-arithmetic oracle
representationhow are row identity, rank, scale, and weight location encoded?revision-pinned source trace
lifecyclewhen is an artifact registered, resident, selectable, and retired?source-observed state transitions plus explicit unknowns
performancehow fast is the path on a concrete system?not measured by this loop

The pinned revisions are Punica v1.1.0, S-LoRA’s archived final commit, PEFT v0.19.1, and vLLM v0.12.0. The source observations below are not promises about later releases.

One normalized five-row LoRA transaction projected through Punica segments, S-LoRA indexed pages, PEFT named sub-batches, and vLLM request-to-slot metadata, with source evidence ceilings at retirement and in-flight safety.

Transformer System reconstruction. The four lanes share one normalized mathematical transaction. They do not share an artifact format, metadata ABI, lifecycle API, or demonstrated safety protocol.

Punica multi-tenant serving architecture

Source: Punica, Figure 2, reproduced from the official open-access paper. Each runner keeps a shared base model and K/V cache while the scheduler manages request and adapter placement. This is Punica’s paper architecture, not a generic PEFT, S-LoRA, or vLLM memory map.

0x0AA One Transaction, Four Non-Interchangeable Contracts

Consider one linear target module. The base path has five rows:

Rows use the adapter map:

row                  0    1    2       3       4
logical adapter      A    A    B    __base__    B

Both adapters have rank two, but they have different scales:

For row , define as its adapter identity. The common semantic contract is:

This formula does not specify a runtime representation. The same mapping is encoded four ways in the fixture:

Backend surfaceIdentity seen by executionFixture representation
Punicaadapter pointer position plus contiguous segmentpermutation [0,1,2,4,3], segments [0,2,4]
S-LoRAcompact adapter index plus indexed weight locationsslots [0,0,1,-1,1], rank/scale/start/length/location tables
PEFTadapter name for each item on the first input axis['A','A','B','__base__','B']
vLLMpositive request ID translated to active GPU slotIDs [11,11,22,-1,22], slots [1,1,0,-1,0]

The owner contract is deliberately narrow. Loop 10 proves that these four declared representations reconstruct the same five outputs after explicit normalization. It does not run any framework or prove that their APIs, schedulers, kernels, retirement paths, or performance are interchangeable.

0x0AB Punica: Pointer Vectors, Contiguous Segments, And A Fixed Rank

The pinned Punica source makes its kernel contract concrete.

Weight storage and pointer indirection

LoraWeight allocates:

PEFT-style is transposed during copy. BatchedLoraWeight then stores device vectors of integer addresses:

The kernel therefore receives no dense tensor with an adapter axis. It receives pointer vectors and a segment boundary vector.

Why the segment vector appears

Suppose requests are stably permuted so every row for adapter is contiguous. If adapter owns rows, define:

Then segment is the half-open interval . In the exact fixture:

permuted original rows = [0,1 | 2,4 | 3]
adapter segments       = [ A  |  B  | base]
kernel segment vector  = [0,2,4]

The base-only row is outside the two adapter segments. After the segmented kernel, output rows are scattered back through the inverse permutation.

BatchedLlamaLoraWeight constructs the cumulative segment vector, but it also sets:

self.rank = weights[0].q.lora_rank

The q/k/v calls pass that one scalar rank with every pointer vector. That is strong source evidence for a fixed-rank invocation in this pinned wrapper. It is not evidence that the Punica idea, paper, or all later implementations forbid variable-rank adapters.

The scale boundary is external

The pinned PEFT converter extracts and stacks only A/B tensors, enforces one rank, and does not visibly read adapter_config.json or carry (lora_alpha/r). The kernel wrapper likewise has no per-adapter scale argument on this path. Therefore the oracle does not pretend raw PEFT artifacts can be compared directly. It declares:

before constructing Punica’s stored B payload. This is a Transformer System normalization contract, not behavior attributed to the converter.

# Semantic reconstruction, not an import of Punica.
for j, adapter_id in enumerate(adapter_order):
    for packed_row in range(segment[j], segment[j + 1]):
        original_row = permutation[packed_row]
        Y[original_row] += X[original_row] @ A[adapter_id].T @ B_scaled[adapter_id].T

The source shows the low-rank invocation. Punica’s paper owns cluster scheduling, asynchronous loading, and migration claims discussed in 0x09. The pinned model/kernel tree does not, by itself, prove a production registration, lease, generation-publication, or retirement protocol.

0x0AC S-LoRA: Variable-Rank Indexed State And A Publication Gap

S-LoRA moves the adapter identity out of contiguous pointer segments and into indexed resident state. The archived InferAdapter stores:

adapter_dirs   compact index -> artifact directory
idx_map        artifact directory -> compact index
a_start[j]     start in the adapter-location vector
a_len[j]       number of occupied cells
a_loc[...]     physical allocator locations
a_scaling[j]   per-adapter alpha/r scale
prefetch_tag   protected membership for the current prefetch generation

For the attention-only archived path, one adapter consumes (4r) allocator cells: q, k, v, and o low-rank pieces. Thus:

This is why variable rank is a length-table problem rather than a single scalar rank argument. The exact fixture keeps both ranks equal to two so all four backends can share one numeric transaction, but S-LoRA’s representation still carries a rank and scale per adapter.

Loading mutates metadata and issues copies

The pinned load_adapters does the following:

scan missing adapters
-> first-fit against available allocator cells for prefetch
-> allocate all selected cells
-> append dirs/start/length/location/scale metadata
-> issue A/B copies, optionally on prefetch_stream

The ordering matters. A directory may already exist in idx_map while the prefetch stream is still performing its copies. The class exposes no explicit adapter-local completion event or READY(generation) bit. The router awaits load RPCs and uses global CUDA synchronization on selected non-prefetch batch transitions, but this is not the same as the event-scoped publication protocol derived in 0x07.

The correct reading is therefore:

That is not a claim that the archived system necessarily races in its intended execution path. It is an evidence ceiling: the inspected class does not prove a general adapter-local publication theorem.

Retirement compacts every dependent index

offload_adapters frees removed locations, compacts every surviving metadata tensor, and rebuilds idx_map. If a consumer retained an old compact index across this operation, it could name a different adapter after compaction. A legal runtime must either quiesce those consumers, version the mapping, or lease the old generation. The pinned source span does not prove which generalized protocol should be used.

Finally, the archived LoraTpPartAdapter constructor asserts world_size == 1. S-LoRA’s paper describes tensor-parallel designs, but this pinned constructor cannot be cited as executable TP evidence. Paper contract and archived-code contract remain separate.

0x0AD PEFT: Named Model Slots And First-Axis Mixed Batches

PEFT owns a different layer of the stack. Its primary object is an adapted model with named adapter modules, not a K/V-aware multi-tenant server.

Loaded is not active

In PEFT v0.19.1, load_adapter(name) adds a named adapter to the model, while set_adapter(name) changes the active adapter. The two calls encode two states:

This distinction is useful, but it is process-local model state. It does not provide admission, GPU-slot capacity, request generation, K/V compatibility, or in-flight retirement semantics.

Mixed batches group the first input axis

The pinned LoRA layer accepts adapter_names and requires:

It rejects this route when adapters are merged and rejects mixed adapter names when DoRA is enabled. __base__ identifies rows that receive no adapter delta.

The implementation computes the base layer once, groups row indices by name, and applies one low-rank branch per named sub-batch:

result = base_layer(x)
for adapter_name in unique(adapter_names):
    if adapter_name == "__base__":
        continue
    rows = [i for i, name in enumerate(adapter_names) if name == adapter_name]
    result[rows] += B[adapter_name](A[adapter_name](x[rows])) * scaling[adapter_name]

Let gather rows named , and let scatter them back. The grouped update is:

Because every row belongs to exactly one named group or __base__, gathering and scattering only reorders independent row computations. This proves the same row-wise algebra. It does not prove that Python sub-batching is a high-throughput token scheduler.

Hotswap has a model-compatibility contract, not a serving lease contract

PEFT’s compiled hotswap helper can pad ranks and tensorize scaling before compilation. Its state-dict path dry-runs key compatibility, zeroes missing old keys, updates scaling, and copies or pads new tensors. The pinned source still states important limits: target-module sets must remain compatible, the rough config check is LoRA-specific, and restoring the original model may require a reload.

None of these operations supplies the generation and lease protocol from 0x07. Mutating a model slot in place while requests use it is a separate serving problem.

0x0AE vLLM: Request Identity, Registered Cache, Active Slots, And Token Metadata

vLLM v0.12.0 connects a request-facing identity to bounded resident slots and kernel metadata. That path has several distinct state transitions.

Request identity is composite

The pinned LoRARequest carries:

lora_name
lora_int_id > 0
lora_path
optional base model and long-context metadata

The class explicitly notes that global integer-ID uniqueness is required but not enforced there. Equality and hashing use the name. Therefore a robust catalog must validate name, integer ID, path/content revision, base revision, and generation before a request reaches a worker.

Registered cache and active GPU slots are different

LoRAModelManager maintains:

_registered_adapters   CPU-side adapter objects, bounded by max_cpu_loras
_active_adapters       GPU-active identities, bounded by max_loras
lora_index_to_id       active GPU slot -> positive LoRA integer ID

The configuration enforces:

Activation finds a free slot, records the adapter ID in lora_index_to_id, resets each layer’s slot, and copies the adapter’s true rank extent. Registration success alone does not establish an active slot, and an active slot alone does not establish which token rows use it.

Scaling is absorbed before execution

The pinned LoRALayerWeights.optimize() path performs:

The layer then calls the indexed shrink/expand wrapper with scale one. This is mathematically equal because scalar multiplication commutes with the final linear expansion:

It is not artifact-byte parity with PEFT or S-LoRA; it is an execution-time normal form.

Max-rank slots preserve algebra through zero tails

For true rank and configured physical rank , vLLM allocates fixed slot extents. Define:

Then:

The zero tails preserve the intended output. They do not prove that padding is free in memory traffic, workspace, or kernel work. Loop 4 owns the true-rank versus padded-rank cost ledger.

Request IDs become stable kernel groups

The exact fixture intentionally places B in slot 0 and A in slot 1:

lora_index_to_id       = [22,11]
token request IDs      = [11,11,22,-1,22]
token slot mapping     = [ 1, 1, 0,-1, 0]
stable sorted row IDs  = [ 3, 2, 4, 0, 1]
active slot IDs        = [-1,0,1]
counts                 = [ 1,2,2]
starts                 = [ 0,1,3,5]

-1 is the no-adapter group. The stable ordering preserves original row order inside each slot group. These metadata are related to Punica’s segments, but they are not the same ABI: vLLM first resolves request identity to an active slot, then derives indexed kernel groups.

Dynamic API removal is not enough evidence for worker retirement

The inspected load endpoint locks by adapter name, allocates an integer ID, asks the engine to add/preload the adapter, and only then publishes the API name mapping. The inspected unload endpoint removes that name from the API registry under its lock. That source span does not itself call a worker-cache retirement path or establish that old in-flight requests hold leases.

Therefore the strongest justified statement is:

This is an evidence boundary, not a claim that every complete vLLM execution leaks adapters or is unsafe. The exact engine/control-plane path must be audited before asserting retirement semantics.

0x0AF Exact Algebraic Normalization

The oracle uses integer matrices and rational scales, so no floating-point tolerance can hide a metadata error. For each adapter:

The derived delta table is:

RowAdapter
0A[3, 3/2, 0, -3/2]
1A[-1/2, -5/2, 3, 1]
2B[9, 9/2, 0, -9/2]
3base[0, 0, 0, 0]
4B[6, 3/2, 3, -3/2]

Adding the fixture’s nonzero base output gives:

row 0  [13,   3/2, 1,  -5/2]
row 1  [-1/2, 5/2, 1,   2  ]
row 2  [12,  15/2, 3,  -3/2]
row 3  [-1,  -1,  -1,  -1  ]
row 4  [8,   11/2, 9,  13/2]

The four reconstruction proofs are now explicit:

  1. Punica: permute rows into contiguous adapter segments, evaluate each segment with externally pre-scaled B, and inverse-permute outputs.
  2. S-LoRA: use each row’s compact adapter index to recover its rank, scale, and indexed locations, then evaluate the true-rank factors.
  3. PEFT: gather rows by adapter name, evaluate one named sub-batch at a time, and scatter into the base result.
  4. vLLM: map request IDs to active slots, evaluate zero-padded A and scale-absorbed B, and restore rows through stable metadata.

Each produces the exact table above. Changing one segment, one scale, one slot, one rank tail, or one base-row sentinel changes the output or fails validation.

0x0AG Lifecycle State Is Not A Shared API

Place the systems on common coordinates without pretending their concrete states are identical:

CoordinatePunica v1.1.0 sourceS-LoRA archived sourcePEFT v0.19.1vLLM v0.12.0
validate artifactconverter checks tensor names/shapes and one rankrouter/config records rank and artifact directoryconfig/state loading into named adapterPEFT helper validates supported features, rank, bias, targets
registerconstruct LlamaLoraWeight and batched pointer vectorsdirectory enters router catalog/compact mapload_adapter(name) adds module stateadapter object enters registered CPU cache
make residentcaller supplies device-resident tensorsallocator pages and A/B copiesparameters reside in the model processactivation copies into bounded GPU slot
publish mappingcaller creates contiguous segmentsrouter batch transition; no adapter-local event in inspected classset_adapter or per-item adapter_namesrequest ID -> slot -> per-token kernel metadata
executesegmented shrink + expandindexed variable-rank prefill/decode pathbase once plus named sub-batch deltasindexed shrink/expand over active slots
retirenot proved in pinned model/kernel treefree pages, compact arrays, rebuild idx_mapmodel API, not a serving lease protocolAPI name removal does not itself show worker retirement

The lifecycle comparison exposes two general rules.

First, identity changes coordinate. A name, path, compact index, pointer-list position, positive request ID, active slot, and token slot are not synonyms. Every transition needs a checked map.

Second, publication changes authority. Allocation, metadata insertion, copy submission, copy completion, active-slot installation, row mapping, and request admission are separate events. Collapsing them into loaded=True recreates the races derived in 0x05 and 0x07.

0x0AH What Parity Does And Does Not Mean

Parity layerLoop 10 resultWhy
normalized LoRA outputexactrational oracle returns the same five rows
logical row-to-adapter assignmentexacteach representation reconstructs A,A,B,base,B
raw artifact bytesnot equallayout, transpose, padding, and scale placement differ
metadata ABInot equalsegments, compact page tables, names, and slot metadata differ
API surfacenot equalmodel library, archived server, kernel wrapper, and serving engine own different calls
lifecycle semanticsnot equalregistration, activation, publication, and retirement differ
in-flight hotswap safetynot provedno common lease/generation theorem is present in all pinned paths
latency or throughputnot measuredno framework, GPU, or benchmark is executed

This distinction prevents two opposite mistakes. We should not dismiss the systems as incomparable: they do share a low-rank row algebra that can be tested exactly. But we should not turn equal algebra into operational parity: serving correctness depends on all the surrounding state.

Compress then Serve remains a fifth design family rather than a fifth backend in this oracle. It changes the adapter collection representation through shared bases and adapter-specific cores. Loop 6 already derives that algebra and placement. Mixing it into the four-way runtime fixture would test a different question: approximation/reconstruction error as well as dispatch.

0x0AI Source-To-Runtime Failure Boundaries

FailureLocally observable symptomWhy shape checks may still passFail-closed action
Punica mixed ranks passed under first-adapter rankwrong pointer stride or ignored true rankevery pointer still has an addresssplit by rank or use a verified variable-rank ABI
Punica PEFT scale omittednumerically wrong adapter strengthA/B shapes and rank are validcarry config-derived scale or pre-scale under a recorded transform
Punica rows not contiguous by adaptersegment applies wrong weightstotal row count and segment endpoint matchvalidate every packed row against segment identity
S-LoRA idx_map treated as copy completionrow can observe incomplete payloadcompact index existsrequire an authoritative completion/publication event
S-LoRA compact index retained across offloadrow names a moved adapterindex remains in integer rangeversion or rebuild all consumers after compaction
archived S-LoRA code cited as TP executionunsupported world size enters constructorpaper describes TPkeep paper and code evidence separate
PEFT newly loaded slot assumed activerequest receives old/default adapternamed tensors are loadedactivate explicitly or provide per-item names
PEFT mixed names used on merged/DoRA layerunsupported semanticsinput and output shapes matchreject before forward as pinned source does
PEFT hotswap used as serving publicationin-flight rows can cross generationstarget tensor shape can be paddeddrain, lease, or generation-publish at runtime level
vLLM integer ID collisiontwo artifacts can alias a runtime identityboth IDs are positiveenforce catalog uniqueness with artifact generation
vLLM request ID mapped to stale slot tablevalid slot selects wrong adapterslot is in boundspublish mapping and active-slot generation atomically
nonzero max-rank tailpadded coordinates add an unintended deltaphysical shape is correctzero/reset slot before bounded copy
API unload treated as worker retirementstale residency or in-flight user remainsname disappears from list endpointaudit engine retirement and lease completion separately

The exact negative corpus mutates these and related boundaries one field at a time. It includes identity, rank, scale, segment, page, name, slot, padding, metadata, lifecycle, parity, and claim-ceiling failures.

0x0AJ Executable Loop 10 Oracle

The evidence bundle contains:

backend_runtime_fixture.json
    one 5x3 input, one 5x4 base result, two rank-2 adapters,
    four representations, lifecycle matrix, parity matrix, claim ceiling

backend_runtime_oracle.py
    exact Fraction-based LoRA evaluation
    Punica segment reconstruction
    S-LoRA compact-index reconstruction
    PEFT named gather/scatter reconstruction
    vLLM ID/slot/padded-rank reconstruction

invalid_backend_runtime_fixtures.json
    95 one-field malformed fixtures
    95 distinct fail-closed error codes

Run it with:

python3 docs/numinens-evidence/m6-5-multi-adapter-serving-runtime/backend_runtime_oracle.py \
  docs/numinens-evidence/m6-5-multi-adapter-serving-runtime/backend_runtime_fixture.json \
  --write-report docs/numinens-evidence/m6-5-multi-adapter-serving-runtime/loop10_report.json

The oracle imports no framework and executes no PyTorch, CUDA, GPU allocator, kernel, server, scheduler, dynamic API, or benchmark. It proves no latency, throughput, memory-footprint, distributed-execution, API-compatibility, production-lifecycle, or in-flight hotswap-safety claim. Its exact evidence is the normalized five-row algebra, declared representation transforms, pinned source observations, lifecycle non-equivalence, and fail-closed fixture set.

0x0B Operational Metric Registry

Section 0x09K defines when state becomes authoritative. This section lists the metric surface. Every implementation must attach each metric to one of those publication events, document its denominator, and keep default labels bounded.

Scheduler and liveness metrics:

adapter_requests_offered_total{phase,rank_bucket}
adapter_requests_admitted_total{phase,rank_bucket}
adapter_requests_rejected_total{reason,phase}
adapter_requests_unfinished{phase,residency_state}
adapter_load_eligible_wait_seconds{rank_bucket}
adapter_execution_ready_wait_seconds{phase,rank_bucket}
adapter_load_starvation_intervals_total{rank_bucket}
adapter_service_starvation_intervals_total{phase,rank_bucket}
adapter_prefetch_requests_total{result}
adapter_prefetch_precision_ratio
adapter_prefetch_wasted_bytes_total{reason}
adapter_completed_service_units{phase,rank_bucket}
adapter_completed_service_gap{phase,rank_bucket}
adapter_affinity_overrides_total{reason}
adapter_plan_invalidations_total{reason}
adapter_generation_replans_total{stage}

These counters do not establish fairness by themselves. A starvation metric needs a protected identity, eligibility predicate, interval, and completion event. adapter_load_starvation protects load-eligible adapter state; adapter_service_starvation protects execution-eligible tenant or client state. Keep them separate.

Required adapter lifecycle and kernel metrics:

adapter_load_requests_total
adapter_load_failures_total
adapter_load_latency_seconds
adapter_h2d_bytes_total
adapter_gpu_resident_bytes
adapter_host_resident_bytes
adapter_cache_hits_total
adapter_cache_misses_total
adapter_evictions_total
adapter_pinned_count
adapter_distinct_per_iteration
adapter_rows_per_iteration
adapter_prefill_rows_per_iteration
adapter_decode_rows_per_iteration
adapter_prefill_requests_per_iteration
adapter_decode_requests_per_iteration
adapter_rank_histogram
adapter_rank_histogram_by_phase
adapter_true_rank_row_values
adapter_padded_rank_row_values
adapter_rank_padding_ratio
adapter_contiguous_runs_before_reorder
adapter_contiguous_runs_after_reorder
adapter_kernel_seconds
adapter_kernel_seconds_by_phase
adapter_metadata_build_seconds
adapter_gather_scatter_seconds
adapter_batch_fragmentation_ratio
adapter_tp_collective_bytes_total
adapter_tp_collective_seconds
adapter_hotswap_seconds
adapter_slot_generation_mismatch_total
adapter_basis_gpu_resident_bytes
adapter_basis_cache_hits_total
adapter_basis_cache_misses_total
adapter_basis_load_latency_seconds
adapter_basis_version_mismatch_total
adapter_cluster_rows_per_iteration
adapter_joint_core_kernel_seconds
adapter_residency_state_count{state}
adapter_page_reservations
adapter_pages_reclaimable
adapter_retirement_wait_seconds
adapter_publication_generation
adapter_publication_failures_total{stage}
adapter_copy_events_inflight
adapter_compensating_rollbacks_total{result}
adapter_victim_restore_bytes_total

Joint adapter/KV metrics:

kv_bytes_by_adapter
joint_memory_reservation_failures_total
adapter_load_blocked_by_kv_total
kv_admission_blocked_by_adapter_total
prefix_cache_hits_by_adapter
prefix_cache_adapter_mismatch_total
joint_pool_pages{class,state}
joint_pool_conservation_failures_total
joint_admission_shortfall_pages
joint_growth_reserve_pages

Without joint metrics, adapter cache pressure and KV pressure can blame each other while the operator sees only generic OOMs.

Raw adapter, request, or tenant identifiers are not default Prometheus-style labels. Preserve them in sampled traces, structured logs, exemplars, or bounded top-k debugging views. The fairness/accounting state store may retain exact identity without exporting one time series per catalog entry.

0x0C Failure Injection

The cases below are the human-readable attack surface. They are intentionally more concrete than a release checklist: each line names one event that an operator, scheduler, loader, or kernel test can inject. The executable evidence bundle contains 553 one-field malformed fixtures across nine mechanism families. Section 0x0D does not replace either corpus. It gives those detailed cases a typed recovery index so a failed detector has one consequence, one repair owner, and one release gate.

Test cases:

load adapter with wrong base revision
load rank above kernel maximum
submit mixed ranks to a fixed-rank segmented kernel
leave nonzero values in a reused slot's padded A tail
leave nonzero values in a reused slot's padded B tail
count one adapter row per prefill request instead of per token
set doff before the final prefill row
reuse adapter segments as attention request boundaries
select the first rather than last prefill logit row
reorder prefills without rebuilding the scheduler-output inverse map
load adapter with missing target module
cancel request during adapter transfer
evict adapter while queued request holds reservation
evict adapter whose generation is still named by a live launch snapshot
publish adapter page table before the copy-complete event
publish adapter with one factor page or target-module entry missing
reuse retired victim pages, then fail copy before publication
rollback overwritten victim without a verified host source
release reservation bitmap but leave an adapter or KV owner attached
hotswap slot while kernel is in flight
mix two adapter revisions under one cache key
switch K/V-changing adapter mid-request
reuse base cache for a Q-only adapter without downstream dependency closure
reuse aLoRA suffix cache after switching back to base
select the first rather than last aLoRA invocation occurrence
omit invocation tokens and silently serve base behavior
reuse K/V-compatible LM-head cache as if prompt logits also matched
place physical slot generation in the semantic prefix key
force host-to-device transfer slowdown
fill GPU with adapters, then grow decode KV
fill GPU with KV, then request a cold adapter
inject malformed scaling metadata
load a compressed core with the wrong basis version
evict a shared basis while requests in its cluster are in flight
add an adapter to a frozen cluster without rebuilding decomposition metadata
let resident affinity override a failed M5 legality predicate
schedule a feasible cold request before its copy event and generation publish
keep selecting a hot resident adapter while never issuing a load for an aged cold adapter
call load-eligible cold wait execution-eligible tenant starvation
call adapter-class progress per-tenant fairness
debit completed service when an iteration is selected rather than committed
debit completed service for prefetch, recomputation, cancellation, or failed execution
reset request arrival time after adapter load or retry
reuse one load attempt ID across rollback and retry
reserve prefetch pages independently of admitted K/V growth pages
publish copy completion as residency before pointer-table generation publication
count only successful loads in the load-latency denominator
attach raw adapter, request, and tenant IDs to every time-series metric
apply S-LoRA newest-first overload abort and call it fair aging
transfer VTC's service bound to the local readiness/affinity composition

Expected behavior should be explicit:

reject
queue
recompute
preempt
evict
fallback
or fail closed

Silent use of a base model or a different adapter is not a safe fallback unless the product contract explicitly permits it.

0x0D Failure Lab

FailureMissing systems conceptSymptom
one kernel launch per adapter per layerheterogeneous batching absentdecode overhead rises with adapter cardinality
adapter alias, path, or integer ID treated as immutable contentartifact digest absentsame identifier resolves to different factor bytes or target map
one scalar rank stored for a rank-heterogeneous artifactmodule manifest collapsedshape-correct loading fails or silently pads/truncates a module
logical factor orientation used as physical kernel layoutconversion ABI absentvalid tensor dimensions feed the wrong kernel axes
physical slot generation inserted into semantic prefix keyownership and compatibility conflatedsafe cache reuse is destroyed after harmless adapter relocation
stale slot or pointer generation accepted because adapter name matcheslaunch snapshot absentold metadata dereferences republished factor storage
one global generation counter compared across state ownersgeneration namespaces collapsedunrelated updates appear ordered while stale owner state survives
prefill adapter ID repeated once per requestrequest identity not expanded to token rowstail prompt rows execute the wrong adapter or no adapter
adapter run reused as attention boundaryprojection and sequence metadata conflatedcross-request attention or invalid K/V writes
doff disagrees with final prefill pointerphase manifest stalerows enter the wrong attention/KV path
prefill request reorder omits inverse sample mappacked and scheduler coordinates conflatedcorrect logits are returned to the wrong request
runtime chooses first prefill row rather than lastsampling-row map absentnext token ignores most of the prompt
mixed rank sent to pinned fixed-rank Punica wrapperbackend rank ABI ignoredout-of-bounds factor reads or numerically wrong deltas
padded A or B tail retains prior slot bytesslot reset incompletelower-rank adapter inherits another adapter’s update
configured maximum rank treated as logical ranksemantic and physical rank conflatedcost, residency, and artifact validation are wrong
adapter cache fills all free HBMKV and adapter policies independentrequests fail during KV growth
entire adapter counted as rank pagesone [R,H] tensor confused with all factors/modules/layersadmission under-reserves device slots
registered adapter treated as GPU-residenthost catalog and active slot collapsedrequest launches through an absent pointer table
adapter published before copy event and digest validationpublication fence absentkernel reads partial or stale factor rows
LRU victim selected before ref/pin/event checksranking substituted for eligibilityactive adapter storage is overwritten
retired victim pages overwritten and bitmap merely released on copy failurecompensating rollback omittedcatalog claims the old adapter is resident over corrupted bytes
adapter and KV pages share allocator and ownership keyphysical pool confused with semantic ownershipcross-request KV reuse or adapter pages freed with one request
growth reserve omitted from joint admissionadmission horizon incompletedecode reaches a capacity cliff after successful prefill
pointer generation updated separately from page tablevisibility is not atomiclaunch combines new identity with old addresses
all ranks padded to maximumrank heterogeneity ignoredhigh wasted FLOPs and bandwidth
adapter factors sharded independently of the base projectiontensor-parallel placement contract missingwrong global update or extra collectives
low-rank all-gather launched separately when fusion was assumedcollective schedule not implementedsmall-message latency dominates adapter work
aggressive adapter bucketingSLO ignoredqueueing dominates kernel savings
adapter affinity implemented as one unbounded weighted bonusfeasibility/readiness and preference collapsedstale, cold, or unsupported request appears selectable
cold request called execution-eligible before generation publicationload eligibility and model-row eligibility collapsedfairness ledger blames selection for a residency failure
resident-only greed has no age/load-progress overrideload liveness absentcold adapter remains feasible but is never published
adapter-class service reported as tenant fairnessprotected identities conflatedone tenant can starve while every adapter bucket progresses
iteration selection debits completed serviceplan and result publication collapsedfailed/cancelled rows make fairness counters advance
adapter-load retry resets request arrivalload and request clocks conflatedTTFT and starvation wait are understated
failed load keeps provisional reservationrecovery ownership not closedfree-page ledger leaks and later admission fails
prefetch and K/V each read the same free-page countno joint reservation serializationboth plans succeed and overcommit one physical pool
raw adapter ID used as default metric labelobservability cardinality unboundedtelemetry memory and query cost scale with catalog size
S-LoRA early-abort reward called fairnessobjective and protected identity changednewest-first overload sacrifice is hidden by terminology
VTC theorem attached to local affinity policytheorem assumptions changeda synthetic trace is presented as a service bound
hotswap overwrites in-flight slotlifetime fence absentnondeterministic mixed-adapter output
adapter revision absent from KV keycache provenance incompleteexact-reuse corruption
adapter target names treated as the cache dependency graphindirect Q/O/MLP effects are omitteddownstream K/V rows are reused under the wrong hidden state
raw aLoRA ID included in every pre-invocation blockinactive execution normalized incorrectlysafe base-prefix sharing is lost
aLoRA ID omitted from post-invocation blocksone request began with a base prefixadapter-tainted suffix is reused by base or another adapter
output-head K/V equality treated as prompt-logit equalitycache object types collapsedbase logits are returned under adapter semantics
first invocation occurrence used instead of lastactivation implementation not pinnedwrong rows execute adapter factors and receive the wrong cache identity
missing invocation silently accepted as specialized resultframework fallback mistaken for product policyrequested adapter behavior is absent without an admission failure
arithmetic unmerge repeatedfinite-precision accumulation ignoredbase weight drifts
cold adapter load omitted from TTFTresidency not modeledtail latency surprises
engine documentation treated as timelessversion contract omittedunsupported API or kernel path
compressed core loaded with the wrong shared basiscollection artifact provenance omittedshape-correct but numerically unrelated adapter update
compression ratio treated as throughput gainthree-stage operator and shared rank omittedlower residency but unchanged or worse TPOT
scheduler groups only by adapter IDshared-basis affinity omittedrepeated basis loads and fragmented joint kernels
scheduler groups only by basis clusterqueueing/SLO tradeoff omittedhot clusters starve unrelated requests

0x0DA A Failure Record Needs Five Coordinates

A failure name alone is not an operational contract. stale adapter, for example, could mean stale catalog bytes, a stale physical slot, a stale pointer table, a stale cache key, or an old request lease. Those failures have different detectors and different repair owners. M6.5 therefore indexes every release failure by five semantic coordinates:

1. identity:     which state owner and generation became inconsistent?
2. invariant:    what relation had to remain true?
3. detector:     which authoritative observation proves the violation?
4. consequence: what can become wrong if execution continues?
5. recovery:     who repairs the state, and which test blocks release?

The machine record keeps category, mechanism loop, and test surface as explicit fields around those five coordinates:

where is the mechanism loop, the failure category, the invariant, the detector, the consequence, the recovery owner, the executable test surface, and the release gate. A record is not closed merely because its detector fired. It is closed only when the named owner restores the invariant and the associated test returns to green.

This distinction prevents two unsafe shortcuts:

  • a metric is not automatically a detector unless it is bound to an authoritative publication or completion event;
  • a fallback is not automatically recovery unless it restores the declared semantic state or the product contract explicitly permits degraded service.

0x0DB Failure Families And Alarm Ownership

The release index contains 36 typed failures: four for every mechanism loop from Loop 2 through Loop 10. The table is deliberately compact; Sections 0x01-0x0A and the executable fixtures retain the tensor values, state-machine steps, source spans, and one-field mutations.

LoopTyped failureRequired invariantDetectorConsequenceRecovery owner
2identity_alias_collisionalias resolves to one immutable artifact digest, base revision, and target manifestcatalog/manifest reconciliationrequest executes different factors under the same nameidentity registry
2module_rank_manifest_collapseevery target module preserves its own rank, axes, scale, dtype, and shardmodule-shape ledgervalid-looking tensor is interpreted under the wrong ABIartifact validator
2generation_namespace_collapsecatalog, slot, pointer, batch, cache, and RNG generations remain namespacedowner-generation snapshotunrelated updates hide stale owner statelaunch validator
2slot_semantic_identity_conflationphysical slot identity stays outside semantic adapter and prefix identityrelocation-invariance checkharmless movement invalidates reuse or stale slot aliases semanticscache identity owner
3row_permutation_not_bijectivegather and scatter maps are inverse over every packed rowpermutation oracleoutputs return to the wrong request rowbatch packer
3segment_identity_drifteach contiguous segment contains only rows for its declared adapterrow-to-segment reconciliationone adapter’s factors update another adapter’s rowssegmented-kernel planner
3scale_orientation_driftfactor orientation and scale encoding reconstruct the declared LoRA deltarational tensor oracleshape-correct branch computes another updateadapter operator owner
3combine_metadata_lossorigin row, local row, adapter, slot, and scale metadata survive executionscatter metadata auditbase and adapter outputs combine at wrong coordinatesbatch packer
4phase_row_count_driftprefill contributes prompt-token rows and ordinary decode one row per requestmixed-phase row ledgermetadata lengths disagree with execution rowsiteration planner
4rank_tail_nonzerocoordinates beyond true rank are zero in every padded slotslot-tail scana low-rank adapter inherits prior slot bytesslot loader
4sampling_inverse_missingpacked sample rows map bijectively back to scheduler request orderoutput inverse-map oraclecorrect logits are returned to the wrong requestscheduler/output bridge
4attention_boundary_aliasattention request boundaries remain independent of adapter runs and phase splitindptr/segment comparisoncross-request attention or invalid K/V writesattention batch owner
5registered_called_residentcatalog registration, page reservation, copy, validation, publication, and activity remain distinctresidency state-machine checklaunch dereferences absent or partial factorsresidency manager
5publication_before_copy_validationcopy completion, digest/layout validation, and pointer publication are orderedevent-and-generation receiptkernel reads partial or stale payloadpublication owner
5eviction_eligibility_bypassedvictim has zero refs, pins, reservations, and incomplete use events before reuseeligibility predicate auditlive storage is overwritteneviction manager
5rollback_owner_leakfailed admission restores victim bytes and releases every provisional adapter/K/V ownerpage conservation oracleallocator leaks or catalog names corrupted datatransaction coordinator
6tp_factor_placement_driftadapter factors follow the base projection’s declared tensor-parallel ownershipshard reconstruction oracleglobal update is numerically wrongTP adapter operator
6collective_schedule_omittedevery required low-rank collective has an owner, byte count, order, and completion eventcollective tracehidden communication or stale partial resultdistributed runtime
6compressed_basis_version_mismatchadapter core and shared basis carry one compatible immutable versioncollection-manifest checkshape-correct reconstruction denotes another adaptercollection loader
6compression_ratio_called_speedupstorage, transfer, reconstruction, collective, and kernel costs remain separate ledgersoperator/cost reconciliationlower bytes are advertised as unmeasured throughputrelease evaluator
7arithmetic_unmerge_called_rollbackexact rollback reloads immutable base plus tested adapter lineagedigest comparison after unmergefinite-precision base drift accumulateslifecycle manager
7hotswap_without_generation_leaseeach in-flight request retains one immutable adapter generationrequest/slot lease auditone sequence mixes old and new factorsrequest lifecycle owner
7retiring_slot_reclaimed_earlyrefcount is zero and last-use event is complete before slot reuseretirement fencenew payload overwrites in-flight storageresidency manager
7postpublication_recovery_called_rollbackpre-publication abort and post-publication replacement use different generation protocolstransaction-state auditconsumers retain receipts for state silently rewritten in placepublication owner
8kv_dependency_closure_omittedcache compatibility includes every direct and downstream path that can change stored K/Varchitecture dependency closureprefix cache reuses state from another model functionM5.3/M6.5 cache owner
8alora_interval_boundary_driftlast invocation occurrence, first active token, and post-activation taint are pinnedinterval mask oraclefactors execute on wrong rows or cache identity changes too early/lateaLoRA integration owner
8prefix_identity_incompletesemantic adapter digest and activation interval enter exact prefix identityprefix-key auditcross-adapter exact-reuse corruptionM5.3/M6.5 cache owner
8prompt_logit_equivalence_overclaimedK/V equality, hidden-state equality, prompt-logit equality, and future sampling stay distinctoutput-object compatibility matrixbase logits are returned under adapted semanticsAPI/cache owner
9feasibility_readiness_collapsedlegal, resident, copy-complete, generation-published, and preferred are separate predicatesscheduler predicate tracecold or unsupported work appears executableadapter scheduler
9load_starvation_hiddenload-eligible age and execution-eligible service use separate clocks and protected identitiesstarvation interval oraclea cold adapter can wait forever while hot work progressesliveness controller
9service_debited_before_commitfairness service advances only after successful result publicationcompletion-ledger auditcancelled or failed work receives phantom servicefairness accountant
9recovery_observability_incompleteattempt IDs, preserved request age, page restoration, and zero failed-service debit are observablerecovery traceretries hide latency and leak ownershiprecovery coordinator
10backend_representation_normalized_awayPunica, S-LoRA, PEFT, and vLLM metadata/lifecycle contracts remain non-interchangeablefour-backend source oracleone backend ABI is implemented as if universalbackend integration owner
10source_claim_ceiling_exceededsource observation, paper claim, local exact evidence, and unexecuted claim remain distinctsource-span/claim auditstatic reading is presented as runtime proofevidence owner
10lifecycle_parity_overclaimedequal normalized output does not imply equal publication, retirement, or in-flight safetylifecycle matrixunsafe unload/hotswap behavior inherits false confidencelifecycle/release gate
10numeric_parity_called_performance_parityalgebraic equality remains separate from latency, memory, throughput, and API compatibilitybenchmark firewallunmeasured deployment claim enters release notesrelease evaluator

The six alarm families are not interchangeable:

Failure categoryPrimary loopsAlarm surfaceRepair boundary
identity and state2immutable manifests and generation receiptsregistry, manifest, launch snapshot
tensor and kernel3, 4, 6exact tensor, permutation, rank-tail, shard, and collective oraclespacker, kernel, TP operator
residency and publication5, 7ownership conservation, copy events, leases, and retirement fencesresidency/lifecycle transaction
cache and lifecycle8dependency closure, activation interval, semantic prefix identityM5.3 plus M6.5 adapter provenance
scheduler and observability9readiness, starvation clocks, completed service, recovery receiptsscheduler and accounting state
evidence and release10, 11source ceilings, parity scope, link/figure/visual closureevidence and release gate
Nine mechanism fixture families containing 553 one-field failures are indexed by 36 typed recovery records, then reconciled with source, route, figure, and visual evidence into a static release candidate that still awaits Loop 12 browser and live-route acceptance

The malformed fixtures remain mechanism-local because they do not share one runtime ABI. Loop 11 reconciles their counts and test surfaces without pretending that a pointer mutation, a scheduler mutation, and a source-ceiling mutation can be executed by one validator:

Mechanism evidenceOne-field fixturesExecutable test surface
Loop 2 runtime identity30test_runtime_identity_manifest.py
Loop 3 segmented tensor execution46test_segmented_tensor_oracle.py
Loop 4 mixed phase and rank60test_mixed_phase_rank_oracle.py
Loop 5 residency and admission59test_residency_admission_oracle.py
Loop 6 TP and collection compression58test_tp_collection_oracle.py
Loop 7 lifecycle and hotswap86test_lifecycle_hotswap_oracle.py
Loop 8 adapter/KV/prefix compatibility55test_adapter_kv_prefix_oracle.py
Loop 9 scheduler and recovery64test_adapter_scheduler_oracle.py
Loop 10 backend runtime contracts95test_backend_runtime_oracle.py
Total553nine independent mechanism oracles

Publication closure has a different unit from technical correctness. A correct kernel section can still ship with a moving source alias, a broken local route, an orphaned image, a stale digest, or an unreviewed source figure. Loop 11 therefore performs set equality rather than spot checks:

article external URLs == publication source-registry URLs
article local post routes == existing Markdown owners
article image routes == cumulative visual-provenance routes
retained source figures == article routes with matching asset digests
all 53 A22 figures == explicit defer-to-owner decisions for M6.5

The static inventory after this loop is:

SurfaceClosed inventoryWhat closure proves
source families21every local, primary, and official family has a claim ceiling
exact external URLs45every published URL has an explicit family, revision policy, evidence file, and claim ceiling
local article routes8every M5/M6/A22 cross-reference resolves to source Markdown
cumulative source-trace records127every mechanism loop’s source and synthesis evidence remains addressable
A22 figure decisions53M6.5 reuses none of the figures owned by M6.3/M6.4/M6.9
M6.5 source-figure decisions13every candidate became retain, replace, or defer
retained M6.5 source figures6every retained paper figure has a route, asset, and digest
article image routes29every route has non-empty alternative text and provenance
responsive native pairs10each loop-owned mechanism visual has desktop and mobile geometry

The registry contains 45 exact external URLs. Static SVG validation checks a root viewBox, role="img", title, description, non-empty alternative text, asset existence, and digest equality. It does not prove font loading, MathJax placement, browser layout, theme contrast, or mobile overflow. Those are rendered observations and remain Loop 12.

0x0DD Static Release Candidate And Rollback Gate

Let each static closure bit be true only when its exact registry or oracle returns no mismatch:

Publication requires two additional evidence classes:

Loop 11 may set . It must keep , and therefore . The candidate state is awaiting_loop12, not published.

Release coordinateLoop 11 stateWhy
parent source digestknownthe Loop 10 article SHA is recorded
candidate source digestknownevery Loop 11 artifact binds the patched article
failure/source/figure/visual static closureexactlocal validators reconcile the complete declared sets
browser acceptancenot executedrequires normalized desktop/mobile, light/dark rendering
live external-route acceptancenot executedstatic URL provenance is not network availability
publication allowednotwo required acceptance bits are still false
rollback digestknownthe previous source identity is recorded
retrievable rollback artifactnot claimeda digest is not an artifact locator or executable rollback

This release state is intentionally conservative. It prevents a common audit error in which all files exist becomes the page renders, or a prior SHA becomes rollback is operational without a retrievable immutable bundle.

0x0DE Executable Loop 11 Oracle

The static closure bundle contains:

failure_closure_manifest.json
    36 typed failure records across Loops 2-10

publication_source_registry.json
    one record for every exact external URL published by the article

publication_surface_fixture.json
    expected source, route, figure, visual, fixture, and boundary sets

publication_surface_audit.py
    fail-closed set and digest reconciliation

invalid_publication_surface_fixtures.json
    one-field mutations of the publication contract itself

release_state_fixture.json
    static candidate state and explicit Loop 12 blockers

Run the bounded validator with:

python3 docs/numinens-evidence/m6-5-multi-adapter-serving-runtime/validate_loop11.py
python3 -m unittest \
  docs/numinens-evidence/m6-5-multi-adapter-serving-runtime/test_loop11_publication_surface.py

The oracle reads local Markdown, JSON, Python test surfaces, PNG/SVG assets, and source digests. It opens no browser, performs no live HTTP request, launches no framework or GPU kernel, and reproduces no paper benchmark. Loop 12 owns formula rendering, responsive geometry, theme evidence, console cleanliness, and live route acceptance.

0x0DF Final Formula, Rendering, Accessibility, Boundary, And Rollback Closure

The final audit keeps five publication surfaces separate because none can stand in for another:

SurfaceExact Loop 12 closureWhat remains outside the claim
source228 source-ordered display formulas, the complete fenced-code and table surface, 29 image routes, 45 exact external URLs, and eight local article routes retain their Loop 11 identitiesformal proof of every derivation, future availability of third-party hosts, or reproduction of a paper experiment
generated routeevery source math node is paired with one completed MathJax rendering and no MathJax error under each normalized profilecompatibility with every browser, font override, assistive technology, or zoom policy
responsive imagesten picture elements select their mobile source at the mobile viewport and their desktop fallback at the desktop viewport; all remaining figures keep their declared single sourceperceptual equivalence under every display, color-vision condition, or user stylesheet
browser and local routesdesktop/mobile and light/dark profiles load every article image and local owner route, preserve heading and anchor identity, contain article-owned overflow, and emit no article-owned browser errorlive external URL health, production adapter execution, GPU kernels, memory, latency, throughput, model quality, or tenant isolation
boundaries and releaseconcrete M5.1—M5.3, M6.3, M6.4, M6.7, M6.9, and M8 owners remain distinct; a deterministic rollback recipe reconstructs the Loop 11 source digest before the candidate is promotedcompletion of the still-dynamic M6.9 owner or a production deployment rollback

The Loop 11 state remains an immutable historical record: awaiting_loop12, browser acceptance false, and publication false. Loop 12 does not rewrite that earlier gate. It adds a final release record whose browser and local-route checks are true and whose verdict is publishable_with_declared_scope. Live external availability remains false because the browser audit does not turn third-party network health into a publication invariant.

Rollback is executable at the article-source boundary rather than inferred from a remembered digest. The release bundle names the start and end markers of this Loop 12-only span, removes that span from a temporary copy, and requires the reconstructed bytes to hash exactly to the Loop 11 candidate. It never mutates the working article during validation. This proves one narrow rollback: final M6.5 article source to the immediately preceding static candidate. It does not prove an application, model, adapter, cache, or infrastructure rollback.

The final closure therefore changes publication evidence, not the technical mechanism. It adds no formula, benchmark, source-reported result, serving-policy recommendation, or framework/GPU claim. The formula registry, source registry, mechanism oracles, typed failure records, and figure dispositions retain their earlier claim ceilings.

0x0E Boundary To M8

M6.5 defines the runtime state of live adapters. M8 decides whether a deployment should instead:

merge one adapter
quantize a merged artifact
keep a quantized base plus live adapters
distill adapter behavior into another model
compress a large adapter collection
choose a different serving engine or hardware target

Routed, shared-factor, post-hoc-composed, and continual adapter families add another layer above this runtime. M6.9 owns their routing granularity, training provenance, factor-sharing geometry, lifecycle order, and task-time growth. Those methods still inherit M6.5’s residency, batching, fencing, and K/V provenance contracts.

0x0F Publish Gate

CheckStatus
Single-adapter execution, heterogeneous batching, state lifetimes, residency, and KV prerequisites are explicitpass
Request and worker adapter state are explicitpass
Base, artifact, semantic-adapter, local-kernel, request, cache/prefix, and slot identities are separatepass
Module-specific rank, scale, logical axes, factor digests, and local TP shard are immutable manifest fieldspass
Prefix compatibility excludes request/slot/RNG ownership while inheriting semantic adapter identity through the M5 cache ABIpass
Catalog, request, slot, pointer-table, batch-plan, cache, and RNG generations remain namespacedpass
The synthetic manifest and 30 negative fixtures reconcile logical, local, and cluster adapter bytespass
Shared base GEMM and heterogeneous adapter branch are separatedpass
Naive grouping and segmented kernels are comparedpass
Scheduler, request, active, segment-local, and output row coordinates are separatedpass
The exact 8-row fixture reconciles gather, shrink, expand, scatter, base-only rows, and additive outputpass
Contiguous Punica intervals and indexed vLLM metadata are not conflatedpass
All 46 malformed Loop 3 tensor, pointer, scale, and generation fixtures fail closedpass
Prefill and decode adapter shapes are distinguishedpass
Mixed-iteration row count is derived from prefill token counts plus one row per ordinary decode requestpass
Prefill indptr, phase doff, adapter row mapping, and scheduler-output inverse mapping are distinctpass
The exact five-request fixture permits one adapter run to cross doff without granting cross-request attentionpass
Last-prefill-row and one-token-decode sampling coordinates are derived and restored to scheduler request orderpass
Exact-rank, phase-split, rank-bucketed, and zero-padded paths produce the same rational adapter deltapass
Logical rank, configured/physical rank, and active intermediate width are separate fieldspass
Padded A and B tails are proven zero and the true-versus-padded rank ledger is explicitpass
Pinned Punica fixed-rank, S-LoRA per-adapter-rank, and vLLM max-rank-slot contracts are not conflatedpass
All malformed Loop 4 phase, row, rank, padding, and sampling fixtures fail closedpass
Punica SGMV shrink/expand semantics and segment metadata are explicitpass
Loop, Gather-BMM, and segmented-kernel alternatives are comparedpass
Attention request boundaries and adapter row segments are kept separatepass
S-LoRA vector-page layout and object lifetime differences are explicitpass
Adapter residency and cold-load TTFT are quantifiedpass
Adapter and KV memory are governed jointlypass
Primitive vector-page bytes, pinned S-LoRA paired-slot bytes, and complete-adapter page demand are not conflatedpass
Registered, reserved, loading, validated, published, active, idle, and retiring residency states are distinctpass
Refcount, pin count, queued reservation, in-flight event, and live generation jointly determine eviction eligibilitypass
The exact 16-slot fixture reconciles 1,024 payload bytes and an 8-slot adapter-plus-KV admissionpass
Victim eligibility, victim ranking, and physical page reuse are separate contractspass
Copy completion and digest/layout validation happen before one generation-stamped publication pointpass
Pre-publication copy failure performs compensating victim reload rather than only releasing a bitmappass
Unified, separate-pool, fixed-slot, host-LRU, load-per-batch, and shadow-copy alternatives are comparedpass
All malformed Loop 5 geometry, ownership, identity, victim, reservation, publication, and rollback fixtures fail closedpass
Rank heterogeneity is treated as a kernel/scheduler concernpass
Tensor-parallel factor placement and low-rank communication are derivedpass
Collection-level joint decomposition includes parameter, operator, basis-version, and scheduler consequencespass
Merge, unmerge, and hotswap have different safety contractspass
In-flight slot generation and fencing are explicitpass
Live and merged LoRA equivalence is derived under explicit orientation, scale, target, arithmetic, and dtype assumptionspass
Binary16 arithmetic unmerge is proven finite but non-reversible, so immutable base reload owns exact rollbackpass
PEFT layer-local safe merge, whole-model merge/unload, compiled hotswap, and vLLM registration contracts are not conflatedpass
Shadow copy, copy-event completion, digest/layout validation, and atomic catalog publication are ordered explicitlypass
Old and new requests keep immutable generation leases rather than re-resolving an alias during decodepass
Retiring slot reclamation requires both refcount zero and last-use event completion, with generation bumps preventing ABA reusepass
Pre-publication rollback and post-publication recovery are different generation protocolspass
All 86 malformed Loop 7 source, tensor, identity, ordering, reclamation, rollback, and claim-ceiling fixtures fail closedpass
Direct K/V adaptation and indirect Q/O/MLP-to-downstream-K/V dependencies are separated by an architecture closurepass
The exact Q-only witness leaves layer-0 K/V unchanged while changing layer-1 K/Vpass
K/V compatibility, cached-hidden compatibility, prompt-logit compatibility, and future sampling are distinctpass
aLoRA’s last-invocation offset, first-token activation, pre-invocation proof, post-invocation taint, training mask, and pinned PEFT limits are explicitpass
The interval execution digest normalizes proven inactive aLoRA rows to base while binding active rows to adapter content and schedulepass
Semantic prefix fields exclude request, slot, pointer, block, and sampling ownership fieldspass
Mid-request ordinary LoRA, base/aLoRA, cross-aLoRA, output-only, and relocation cases have different legal closurepass
Prefix mismatch, pre-publication suffix failure, and post-publication recovery preserve immutable M5 receiptspass
All 55 malformed Loop 8 source, tensor, activation, dependency, prefix, runtime, and claim-ceiling fixtures fail closedpass
Generic legal iteration plans, deadline clocks, admission, fairness identities, and preemption remain M5.2 ownerspass
Adapter feasibility, readiness, preference, selection, and completed publication are distinct predicatespass
Adapter cost remains a vector of load, basis, run, true/padded rank, page, and collective work rather than one dimensionless scorepass
PetS’s two-stage Bellman partition and operator schedule are reconstructed with their sequential-model and QoS limitspass
Punica’s feasible-worker consolidation, asynchronous adapter load, and recompute migration retain paper-specific scopepass
S-LoRA’s clustering, queue-derived prefetch, and overload early-abort reward are not mislabeled fairnesspass
Completed tenant service and adapter-class projections remain different protected identitiespass
Adapter-load starvation and execution-eligible tenant-service starvation use different predicatespass
The exact six-tick trace compares resident greed with age-triggered prefetch and completed-service deficit without claiming a theorempass
Prefetch and K/V growth consume one joint reservation/conservation ledgerpass
Metrics bind to authoritative queue, load, generation, result, service, and release events with bounded default labelspass
Failed load recovery preserves request age, uses a new attempt/generation, debits zero failed service, and restores all pagespass
All 64 malformed Loop 9 source, policy, paper, liveness, telemetry, recovery, and claim-ceiling fixtures fail closedpass
One exact five-row transaction is reconstructed through Punica, S-LoRA, PEFT, and vLLM metadata without conflating their lifecycle contractspass
All 95 malformed Loop 10 representation, lifecycle, parity, and claim-ceiling fixtures fail closedpass
Thirty-six typed failures assign every mechanism loop four explicit invariants, detectors, consequences, recovery owners, and test surfacespass
All 553 one-field malformed fixtures reconcile across nine independent mechanism familiespass
All exact external URLs, local routes, source spans, A22 dispositions, M6.5 source figures, image routes, and visual digests close staticallypass
The Loop 11 release state remains recorded as awaiting_loop12; static closure does not retroactively claim browser rendering, live external availability, publication, or executable rollbackpass
Loop 12 reconciles formulas, four browser profiles, responsive selection, local routes, article accessibility, concrete owner boundaries, and a source-level rollback into publishable_with_declared_scopepass

0xFF References