§6.2
Chapter 06 · QPACK Behavior and Header Compression Optimization

§6.2Acknowledgments and Insert with Acknowledgment Mechanics

RFC 9204

Learning objective. Understand the three decoder-stream instructions (Section Acknowledgment, Insert Count Increment, and Stream Cancellation) and the single number they maintain, the Known Received Count, which is what tells the encoder which dynamic-table entries are safe to reference.

The number that matters: Known Received Count #

The encoder faces one central uncertainty. It can insert an entry on the encoder stream and reference it from a HEADERS section on a request stream, but because those are different QUIC streams, the reference can overtake the insert on the wire. Reference an entry the decoder has not yet received and you have created a blocked stream (§6.3). To reason about this, the encoder tracks the Known Received Count (KRC): the number of dynamic-table insertions the decoder has confirmed it received ([RFC 9204 §2.1.4]). Any entry with absolute index below the KRC is safe — the decoder demonstrably has it, so referencing it can never block. The decoder's whole job on its feedback stream is to advance that number.

Three decoder-stream instructions #

The decoder sends three instruction types on its decoder stream (type 0x03), distinguished by leading bits (constants.md §14):

DecoderEncoderKnown ReceivedCount = 0Insert Count = 2KRC = 2 · entries0,1 safe to referencedecode ok, thenfinished with thesectionKRC stays 2 ·section-4 refsreleasedstream 8 resetbefore decodeoutstanding refs onstream 8 droppedencoder stream — Insert A (abs 0),Insert B (abs 1)decoder stream — Insert CountIncrement (+2)request stream 4 — HEADERS refabs 1, RIC=2decoder stream — Section Ack(stream 4)request stream 8 — HEADERS refabs 1decoder stream — StreamCancellation (stream 8)
Fig. 6.2-1Insert Count Increment advances the encoder's Known Received Count directly; a Section Acknowledgment both confirms a request stream's decode and can raise the KRC to that section's Required Insert Count; Stream Cancellation releases a reset stream's outstanding references without implying any table state was received.RFC 9204 §4.4.1, §4.4.2, §4.4.3
  • Insert Count Increment (leading 00). "I have now processed N more insertions." It raises the KRC by its Increment ([RFC 9204 §4.4.3]). This is the decoder's way of acknowledging table growth directly, independent of any request stream. An Increment of 0, or one that pushes the KRC past what the encoder actually sent, is a QPACK_DECODER_STREAM_ERROR (0x0202).
  • Section Acknowledgment (leading 1). Sent after the decoder finishes decoding a field section that used dynamic references, carrying the section's stream ID ([RFC 9204 §4.4.1]). It does double duty: it releases the encoder's bookkeeping for that section's references, and if the section's Required Insert Count exceeds the current KRC, it raises the KRC to that value ([RFC 9204 §2.1.4]). So a stream of ordinary requests keeps the KRC current for free, without separate Increment instructions.
  • Stream Cancellation (leading 01). Sent when a request stream is reset or abandoned before its headers are decoded, carrying the stream ID ([RFC 9204 §4.4.2]). It tells the encoder that this stream's outstanding dynamic references are gone, so entries they pinned can become evictable. Crucially, it does not imply the decoder received any table updates: it only retracts references ([RFC 9204 §2.2.2.2]).

Why acknowledgment gates eviction, too #

The KRC does more than green-light references; it also governs eviction. An entry cannot be evicted while it is still referenced by a field section the decoder has not acknowledged — the decoder might still need it to decode that section ([RFC 9204 §2.1.1]). An entry becomes evictable only once its insertion is acknowledged (absolute index below the KRC) and it has no outstanding references in unacknowledged sections ([RFC 9204 §2.2.2.2]). This is why a fresh insert cannot be evicted immediately even if never referenced: the decoder has not yet confirmed it. Acknowledgment, then, is the hinge for both halves of the encoder's freedom: what it may reference and what it may evict.

Worked example: two inserts, one ack, one cancel #

Follow Figure 6.2-1 with the KRC in hand. The encoder inserts A (abs 0) and B (abs 1); its KRC is still 0 — it has sent two entries but heard nothing back. The decoder, having applied both, sends Insert Count Increment (+2); now KRC = 2 and the encoder knows both entries are safe. It sends a request on stream 4 referencing B with RIC = 2; the decoder decodes it and returns a Section Acknowledgment (stream 4), which here does not raise the KRC (already 2) but releases stream 4's references, letting A and B become evictable. Then a request on stream 8 that also referenced B is reset before decoding; the decoder sends Stream Cancellation (stream 8), retracting those references without touching the KRC. On the wire, that entire conversation of feedback is three bytes: 0x02, 0x84, 0x48, exactly as laid out in Figure 6.2-2.

Note

Section Acknowledgment and Insert Count Increment can be redundant. A request that references the latest insert acknowledges it implicitly, so the decoder need not also send an Increment. RFC 9204 §2.2.2.3 leaves the decoder free to delay Increments and coalesce them, or skip them when Section Acknowledgments already carry the news. Delay too long, though, and the encoder, waiting for acknowledgment before referencing new entries, falls back to literals and loses compression.

In practice

editorial If compression ratio looks worse than expected on a healthy connection, check the acknowledgment latency, not the encoder. An encoder that only references acknowledged entries is at the mercy of how promptly the peer's decoder emits Section Acknowledgments and Insert Count Increments. A decoder that batches its feedback to save packets can starve the encoder of the confirmations it needs to reuse dynamic entries, so headers quietly fall back to literals. When you diff two implementations' compression, look at when each one acks. Table capacity is rarely the whole story.

Takeaways #

The decoder keeps the encoder honest with three instructions on the decoder stream: Insert Count Increment advances the Known Received Count directly, Section Acknowledgment advances it per decoded section and releases that section's references, and Stream Cancellation retracts a reset stream's references without acknowledging any table state. The KRC that results gates both what the encoder may safely reference and what it may evict. When the encoder chooses to reference entries below the KRC it never blocks; when it reaches for entries the decoder may not have yet, it courts the blocked streams of §6.3.