aliehsaeedii commented on code in PR #22882:
URL: https://github.com/apache/kafka/pull/22882#discussion_r3778759561


##########
docs/streams/developer-guide/interactive-queries.md:
##########
@@ -257,6 +257,237 @@ After the application has started, you can get access to 
"CountsWindowStore" and
       System.out.println("Count of 'world' @ time " + windowTimestamp + " is " 
+ next.value);
     }
 
+## Header-aware stores and interactive queries 
{#header-aware-stores-interactive-queries}
+
+A [header-aware 
store](/{version}/streams/developer-guide/processor-api/#headers-in-state-stores)
 — built with a `*WithHeaders` supplier and its matching builder 
([KIP-1271](../../upgrade-guide/#kip-1271-headers-aware-stores)) — persists 
each record's 
[headers](</{version}/javadoc/org/apache/kafka/streams/processor/api/Record.html#headers()>)
 alongside its value (and, for key-value and window stores, its timestamp). 
This section shows how to read those headers back interactively, through both 
the `store()` API and the IQv2 `query()` API.
+
+### Reading headers with the `store()` API
+
+Look up the store with the `*WithHeaders()` entry from `QueryableStoreTypes` 
that matches your store type. The returned `ReadOnly*Store` surfaces the 
headers as part of its value type: 
[ValueTimestampHeaders](/{version}/javadoc/org/apache/kafka/streams/state/ValueTimestampHeaders.html)
 for key-value and window stores, and 
[AggregationWithHeaders](/{version}/javadoc/org/apache/kafka/streams/state/AggregationWithHeaders.html)
 for session stores. These examples assume a header-aware store built with a 
`*WithHeaders` supplier, as shown in [Headers in State 
Stores](/{version}/streams/developer-guide/processor-api/#headers-in-state-stores).
 There are only three such helpers — `timestampedKeyValueStoreWithHeaders()`, 
`timestampedWindowStoreWithHeaders()`, and `sessionStoreWithHeaders()`; there 
is no `*WithHeaders()` helper for a plain (non-timestamped) key-value or window 
store. What the store returns also depends on the supplier the `*WithHeaders` 
builder wraps (see the store-build tabl
 e below): on the adapter paths the `store()` API degrades silently — empty 
headers, or a `-1` timestamp — rather than failing the way the IQv2 `query()` 
API does.

Review Comment:
   [content] "rather than failing the way the IQv2 `query()` API does" is too 
broad. IQv2 only fails on the *plain* adapter; on the timestamped adapter it 
succeeds and just returns empty headers — which is what your own table row says 
("All succeed", line 458). Narrow this to the plain path.



##########
docs/streams/developer-guide/interactive-queries.md:
##########
@@ -257,6 +257,237 @@ After the application has started, you can get access to 
"CountsWindowStore" and
       System.out.println("Count of 'world' @ time " + windowTimestamp + " is " 
+ next.value);
     }
 
+## Header-aware stores and interactive queries 
{#header-aware-stores-interactive-queries}
+
+A [header-aware 
store](/{version}/streams/developer-guide/processor-api/#headers-in-state-stores)
 — built with a `*WithHeaders` supplier and its matching builder 
([KIP-1271](../../upgrade-guide/#kip-1271-headers-aware-stores)) — persists 
each record's 
[headers](</{version}/javadoc/org/apache/kafka/streams/processor/api/Record.html#headers()>)
 alongside its value (and, for key-value and window stores, its timestamp). 
This section shows how to read those headers back interactively, through both 
the `store()` API and the IQv2 `query()` API.
+
+### Reading headers with the `store()` API
+
+Look up the store with the `*WithHeaders()` entry from `QueryableStoreTypes` 
that matches your store type. The returned `ReadOnly*Store` surfaces the 
headers as part of its value type: 
[ValueTimestampHeaders](/{version}/javadoc/org/apache/kafka/streams/state/ValueTimestampHeaders.html)
 for key-value and window stores, and 
[AggregationWithHeaders](/{version}/javadoc/org/apache/kafka/streams/state/AggregationWithHeaders.html)
 for session stores. These examples assume a header-aware store built with a 
`*WithHeaders` supplier, as shown in [Headers in State 
Stores](/{version}/streams/developer-guide/processor-api/#headers-in-state-stores).
 There are only three such helpers — `timestampedKeyValueStoreWithHeaders()`, 
`timestampedWindowStoreWithHeaders()`, and `sessionStoreWithHeaders()`; there 
is no `*WithHeaders()` helper for a plain (non-timestamped) key-value or window 
store. What the store returns also depends on the supplier the `*WithHeaders` 
builder wraps (see the store-build tabl
 e below): on the adapter paths the `store()` API degrades silently — empty 
headers, or a `-1` timestamp — rather than failing the way the IQv2 `query()` 
API does.
+    
+    
+    // Key-value store built with a *WithHeaders supplier
+    ReadOnlyKeyValueStore<String, ValueTimestampHeaders<Long>> keyValueStore =
+        streams.store(StoreQueryParameters.fromNameAndType(
+            "counts-store", 
QueryableStoreTypes.timestampedKeyValueStoreWithHeaders()));
+    
+    ValueTimestampHeaders<Long> vth = keyValueStore.get("hello");
+    if (vth != null) {
+      System.out.println("value:     " + vth.value());
+      System.out.println("timestamp: " + vth.timestamp());
+      System.out.println("headers:   " + vth.headers());
+    }
+    
+    // Window store built with a *WithHeaders supplier
+    ReadOnlyWindowStore<String, ValueTimestampHeaders<Long>> windowStore =
+        streams.store(StoreQueryParameters.fromNameAndType(
+            "counts-window-store", 
QueryableStoreTypes.timestampedWindowStoreWithHeaders()));
+    
+    // fetch returns a WindowStoreIterator whose values carry headers
+    try (WindowStoreIterator<ValueTimestampHeaders<Long>> it =
+             windowStore.fetch("hello", Instant.ofEpochMilli(0), 
Instant.now())) {
+      while (it.hasNext()) {
+        ValueTimestampHeaders<Long> wv = it.next().value;
+        System.out.println("value: " + wv.value() + " headers: " + 
wv.headers());
+      }
+    }
+
+Session stores return `AggregationWithHeaders<V>`, which exposes the 
aggregated value via `aggregation()` (not `value()`) and the headers via 
`headers()`.
+    
+    
+    // Session store built with a *WithHeaders supplier
+    ReadOnlySessionStore<String, AggregationWithHeaders<Long>> sessionStore =
+        streams.store(StoreQueryParameters.fromNameAndType(
+            "counts-session-store", 
QueryableStoreTypes.sessionStoreWithHeaders()));
+    
+    try (KeyValueIterator<Windowed<String>, AggregationWithHeaders<Long>> it =
+             sessionStore.fetch("hello")) {
+      while (it.hasNext()) {
+        AggregationWithHeaders<Long> awh = it.next().value;
+        System.out.println("aggregation: " + awh.aggregation());
+        System.out.println("headers:     " + awh.headers());
+      }
+    }
+
+### Reading headers with the IQv2 `query()` API
+
+Interactive Queries v2 (IQv2) is the query-based interactive-queries API: 
instead of accessing a store object directly, you build a `Query`, wrap it in a 
[StateQueryRequest](/{version}/javadoc/org/apache/kafka/streams/query/StateQueryRequest.html),
 and run it with `KafkaStreams#query(...)`. The call returns a 
[StateQueryResult](/{version}/javadoc/org/apache/kafka/streams/query/StateQueryResult.html)
 that holds a per-partition 
[QueryResult](/{version}/javadoc/org/apache/kafka/streams/query/QueryResult.html):
 use `getOnlyPartitionResult()` for a single-key lookup, or 
`getPartitionResults()` for the full `Map<Integer, QueryResult<R>>`. Each 
`QueryResult` exposes the query result via `getResult()` and its data-freshness 
`Position` via `getPosition()`. To require a minimum freshness on the request 
side, bound it with `StateQueryRequest#withPositionBound(...)`; a 
not-up-to-bound failure (described in the behavior notes below) means the store 
had not yet reached that bound.
+
+Before [KIP-1356](../../upgrade-guide/#kip-1356-iqv2-header-queries), no IQv2 
query type exposed record headers. 
[KIP-1356](../../upgrade-guide/#kip-1356-iqv2-header-queries) adds four 
`@Evolving` query types whose results carry headers. Each returns a 
[ReadOnlyRecord](/{version}/javadoc/org/apache/kafka/streams/processor/api/ReadOnlyRecord.html)
 — a read-only view exposing `key()`, `value()`, `timestamp()`, and `headers()` 
— or, for the range and window queries, a closeable 
[ReadOnlyRecordIterator](/{version}/javadoc/org/apache/kafka/streams/state/ReadOnlyRecordIterator.html)
 of such records. `headers()` is never null (an empty `Headers` when the record 
had none) and must be treated as read-only: records served as IQv2 results have 
their headers frozen, so adding or removing a header (for example `add(...)`) 
throws `IllegalStateException`. The freeze is shallow, though — the byte array 
behind an individual header value can still be mutated in place, so treat 
header values as 
 read-only too.
+
+`TimestampedKeyWithHeadersQuery` is a single-key lookup against a header-aware 
key-value store, parallel to `TimestampedKeyQuery`:
+    
+    
+    TimestampedKeyWithHeadersQuery<String, Long> query =
+        TimestampedKeyWithHeadersQuery.withKey("hello");
+    
+    StateQueryRequest<ReadOnlyRecord<String, Long>> request =
+        StateQueryRequest.inStore("counts-store").withQuery(query);
+    
+    StateQueryResult<ReadOnlyRecord<String, Long>> result = 
streams.query(request);
+    QueryResult<ReadOnlyRecord<String, Long>> partitionResult = 
result.getOnlyPartitionResult();
+    if (partitionResult != null && partitionResult.isSuccess()) {
+      ReadOnlyRecord<String, Long> record = partitionResult.getResult();
+      if (record != null) {
+        System.out.println("value:   " + record.value());
+        System.out.println("headers: " + record.headers());
+      }
+    }
+
+Chain `skipCache()` when building the query — 
`TimestampedKeyWithHeadersQuery.withKey("hello").skipCache()` — to bypass the 
record cache and read directly from the underlying store. The query types are 
immutable, so `skipCache()` returns a new query rather than mutating the one 
you already built (of the four header-aware queries, only this single-key one 
offers `skipCache()`).

Review Comment:
   [content] This chained form doesn't compile. `withKey("hello")` sits in 
receiver position, so it isn't target-typed and `V` infers to `Object` — 
`TimestampedKeyWithHeadersQuery<String,Object>` won't assign to `<String, 
Long>`. It needs an explicit type witness: 
`TimestampedKeyWithHeadersQuery.<String, Long>withKey("hello").skipCache()`, 
which is exactly what Kafka's own test writes 
(`TimestampedKeyValueStoreBuilderWithHeadersTest.java:402`). The unchained form 
at line 321 is fine because the assignment target-types it. This one's on me — 
the chained wording was my suggestion last round.



##########
docs/streams/developer-guide/interactive-queries.md:
##########
@@ -257,6 +257,237 @@ After the application has started, you can get access to 
"CountsWindowStore" and
       System.out.println("Count of 'world' @ time " + windowTimestamp + " is " 
+ next.value);
     }
 
+## Header-aware stores and interactive queries 
{#header-aware-stores-interactive-queries}
+
+A [header-aware 
store](/{version}/streams/developer-guide/processor-api/#headers-in-state-stores)
 — built with a `*WithHeaders` supplier and its matching builder 
([KIP-1271](../../upgrade-guide/#kip-1271-headers-aware-stores)) — persists 
each record's 
[headers](</{version}/javadoc/org/apache/kafka/streams/processor/api/Record.html#headers()>)
 alongside its value (and, for key-value and window stores, its timestamp). 
This section shows how to read those headers back interactively, through both 
the `store()` API and the IQv2 `query()` API.
+
+### Reading headers with the `store()` API
+
+Look up the store with the `*WithHeaders()` entry from `QueryableStoreTypes` 
that matches your store type. The returned `ReadOnly*Store` surfaces the 
headers as part of its value type: 
[ValueTimestampHeaders](/{version}/javadoc/org/apache/kafka/streams/state/ValueTimestampHeaders.html)
 for key-value and window stores, and 
[AggregationWithHeaders](/{version}/javadoc/org/apache/kafka/streams/state/AggregationWithHeaders.html)
 for session stores. These examples assume a header-aware store built with a 
`*WithHeaders` supplier, as shown in [Headers in State 
Stores](/{version}/streams/developer-guide/processor-api/#headers-in-state-stores).
 There are only three such helpers — `timestampedKeyValueStoreWithHeaders()`, 
`timestampedWindowStoreWithHeaders()`, and `sessionStoreWithHeaders()`; there 
is no `*WithHeaders()` helper for a plain (non-timestamped) key-value or window 
store. What the store returns also depends on the supplier the `*WithHeaders` 
builder wraps (see the store-build tabl
 e below): on the adapter paths the `store()` API degrades silently — empty 
headers, or a `-1` timestamp — rather than failing the way the IQv2 `query()` 
API does.
+    
+    
+    // Key-value store built with a *WithHeaders supplier
+    ReadOnlyKeyValueStore<String, ValueTimestampHeaders<Long>> keyValueStore =
+        streams.store(StoreQueryParameters.fromNameAndType(
+            "counts-store", 
QueryableStoreTypes.timestampedKeyValueStoreWithHeaders()));
+    
+    ValueTimestampHeaders<Long> vth = keyValueStore.get("hello");
+    if (vth != null) {
+      System.out.println("value:     " + vth.value());
+      System.out.println("timestamp: " + vth.timestamp());
+      System.out.println("headers:   " + vth.headers());
+    }
+    
+    // Window store built with a *WithHeaders supplier
+    ReadOnlyWindowStore<String, ValueTimestampHeaders<Long>> windowStore =
+        streams.store(StoreQueryParameters.fromNameAndType(
+            "counts-window-store", 
QueryableStoreTypes.timestampedWindowStoreWithHeaders()));
+    
+    // fetch returns a WindowStoreIterator whose values carry headers
+    try (WindowStoreIterator<ValueTimestampHeaders<Long>> it =
+             windowStore.fetch("hello", Instant.ofEpochMilli(0), 
Instant.now())) {
+      while (it.hasNext()) {
+        ValueTimestampHeaders<Long> wv = it.next().value;
+        System.out.println("value: " + wv.value() + " headers: " + 
wv.headers());
+      }
+    }
+
+Session stores return `AggregationWithHeaders<V>`, which exposes the 
aggregated value via `aggregation()` (not `value()`) and the headers via 
`headers()`.
+    
+    
+    // Session store built with a *WithHeaders supplier
+    ReadOnlySessionStore<String, AggregationWithHeaders<Long>> sessionStore =
+        streams.store(StoreQueryParameters.fromNameAndType(
+            "counts-session-store", 
QueryableStoreTypes.sessionStoreWithHeaders()));
+    
+    try (KeyValueIterator<Windowed<String>, AggregationWithHeaders<Long>> it =
+             sessionStore.fetch("hello")) {
+      while (it.hasNext()) {
+        AggregationWithHeaders<Long> awh = it.next().value;
+        System.out.println("aggregation: " + awh.aggregation());
+        System.out.println("headers:     " + awh.headers());
+      }
+    }
+
+### Reading headers with the IQv2 `query()` API
+
+Interactive Queries v2 (IQv2) is the query-based interactive-queries API: 
instead of accessing a store object directly, you build a `Query`, wrap it in a 
[StateQueryRequest](/{version}/javadoc/org/apache/kafka/streams/query/StateQueryRequest.html),
 and run it with `KafkaStreams#query(...)`. The call returns a 
[StateQueryResult](/{version}/javadoc/org/apache/kafka/streams/query/StateQueryResult.html)
 that holds a per-partition 
[QueryResult](/{version}/javadoc/org/apache/kafka/streams/query/QueryResult.html):
 use `getOnlyPartitionResult()` for a single-key lookup, or 
`getPartitionResults()` for the full `Map<Integer, QueryResult<R>>`. Each 
`QueryResult` exposes the query result via `getResult()` and its data-freshness 
`Position` via `getPosition()`. To require a minimum freshness on the request 
side, bound it with `StateQueryRequest#withPositionBound(...)`; a 
not-up-to-bound failure (described in the behavior notes below) means the store 
had not yet reached that bound.
+
+Before [KIP-1356](../../upgrade-guide/#kip-1356-iqv2-header-queries), no IQv2 
query type exposed record headers. 
[KIP-1356](../../upgrade-guide/#kip-1356-iqv2-header-queries) adds four 
`@Evolving` query types whose results carry headers. Each returns a 
[ReadOnlyRecord](/{version}/javadoc/org/apache/kafka/streams/processor/api/ReadOnlyRecord.html)
 — a read-only view exposing `key()`, `value()`, `timestamp()`, and `headers()` 
— or, for the range and window queries, a closeable 
[ReadOnlyRecordIterator](/{version}/javadoc/org/apache/kafka/streams/state/ReadOnlyRecordIterator.html)
 of such records. `headers()` is never null (an empty `Headers` when the record 
had none) and must be treated as read-only: records served as IQv2 results have 
their headers frozen, so adding or removing a header (for example `add(...)`) 
throws `IllegalStateException`. The freeze is shallow, though — the byte array 
behind an individual header value can still be mutated in place, so treat 
header values as 
 read-only too.
+
+`TimestampedKeyWithHeadersQuery` is a single-key lookup against a header-aware 
key-value store, parallel to `TimestampedKeyQuery`:
+    
+    
+    TimestampedKeyWithHeadersQuery<String, Long> query =
+        TimestampedKeyWithHeadersQuery.withKey("hello");
+    
+    StateQueryRequest<ReadOnlyRecord<String, Long>> request =
+        StateQueryRequest.inStore("counts-store").withQuery(query);
+    
+    StateQueryResult<ReadOnlyRecord<String, Long>> result = 
streams.query(request);
+    QueryResult<ReadOnlyRecord<String, Long>> partitionResult = 
result.getOnlyPartitionResult();
+    if (partitionResult != null && partitionResult.isSuccess()) {
+      ReadOnlyRecord<String, Long> record = partitionResult.getResult();
+      if (record != null) {
+        System.out.println("value:   " + record.value());
+        System.out.println("headers: " + record.headers());
+      }
+    }
+
+Chain `skipCache()` when building the query — 
`TimestampedKeyWithHeadersQuery.withKey("hello").skipCache()` — to bypass the 
record cache and read directly from the underlying store. The query types are 
immutable, so `skipCache()` returns a new query rather than mutating the one 
you already built (of the four header-aware queries, only this single-key one 
offers `skipCache()`).
+
+`TimestampedRangeWithHeadersQuery` is a key-range scan, parallel to 
`TimestampedRangeQuery`. It returns a `ReadOnlyRecordIterator`, so close it 
when done (for example, with try-with-resources). A range can span several 
local partitions, so iterate `getPartitionResults()`:
+    
+    
+    TimestampedRangeWithHeadersQuery<String, Long> query =
+        TimestampedRangeWithHeadersQuery.withRange("a", "n");
+    
+    StateQueryRequest<ReadOnlyRecordIterator<String, Long>> request =
+        StateQueryRequest.inStore("counts-store").withQuery(query);
+    
+    StateQueryResult<ReadOnlyRecordIterator<String, Long>> result = 
streams.query(request);
+    for (QueryResult<ReadOnlyRecordIterator<String, Long>> partition : 
result.getPartitionResults().values()) {
+      if (partition.isFailure()) {
+        System.out.println("failed: " + partition.getFailureReason() + " - " + 
partition.getFailureMessage());
+        continue;
+      }
+      try (ReadOnlyRecordIterator<String, Long> iterator = 
partition.getResult()) {
+        while (iterator.hasNext()) {
+          ReadOnlyRecord<String, Long> record = iterator.next();
+          System.out.println(record.key() + " -> " + record.value() + " " + 
record.headers());
+        }
+      }
+    }
+
+Use `withLowerBound`, `withUpperBound`, or `withNoBounds` for open-ended or 
full scans. Results are unordered by default; call `withAscendingKeys()` or 
`withDescendingKeys()` to fix the order, which is defined over the serialized 
`byte[]` of the keys rather than their logical order.
+
+`TimestampedWindowKeyWithHeadersQuery` fetches all windows for a single key 
within a window-start range from a header-aware window store. It parallels 
`WindowKeyQuery`, but with a different result shape: `WindowKeyQuery` returns a 
`WindowStoreIterator<V>` keyed by the window-start `long`, whereas this query 
returns a `ReadOnlyRecordIterator<Windowed<K>, V>` whose records are keyed by 
`Windowed<K>` (the window lives in the key; `timestamp()` is the stored record 
event-time). Build and consume it as for the range query above, but note the 
`Windowed<String>` in the request and result types:
+    
+    
+    TimestampedWindowKeyWithHeadersQuery<String, Long> query =
+        TimestampedWindowKeyWithHeadersQuery.withKeyAndWindowStartRange(
+            "hello", Instant.ofEpochMilli(0), Instant.now());
+    
+    StateQueryRequest<ReadOnlyRecordIterator<Windowed<String>, Long>> request =
+        StateQueryRequest.inStore("counts-window-store").withQuery(query);
+    
+    StateQueryResult<ReadOnlyRecordIterator<Windowed<String>, Long>> result = 
streams.query(request);
+    // Iterate result.getPartitionResults() and close each 
ReadOnlyRecordIterator, as in the range example.
+
+`TimestampedWindowRangeWithHeadersQuery` is parallel to `WindowRangeQuery` and 
has two forms. Use `withWindowStartRange(timeFrom, timeTo)` against a 
header-aware window store to fetch every key across a window-start range, or 
`withKey(key)` against a header-aware session store to fetch all sessions for a 
key (for session results, `timestamp()` is the session-window end). As with 
`WindowRangeQuery`, each store accepts only its corresponding form; submitting 
the wrong form fails with an unknown-query-type error. Both forms are 
`Query<ReadOnlyRecordIterator<Windowed<K>, V>>` — including the session 
`withKey` form, whose records are keyed by the session's `Windowed<K>`.
+    
+    
+    // Window store: every key across a window-start range
+    TimestampedWindowRangeWithHeadersQuery<String, Long> byWindow =
+        TimestampedWindowRangeWithHeadersQuery.withWindowStartRange(
+            Instant.ofEpochMilli(0), Instant.now());
+    
+    // Session store: all sessions for one key
+    TimestampedWindowRangeWithHeadersQuery<String, Long> byKey =
+        TimestampedWindowRangeWithHeadersQuery.withKey("hello");
+    
+    // Both forms have the same result type (element type 
ReadOnlyRecord<Windowed<String>, Long>),
+    // but each must target its own store type — submitting the wrong form 
fails with an unknown-query-type error:
+    StateQueryRequest<ReadOnlyRecordIterator<Windowed<String>, Long>> 
windowRequest =
+        StateQueryRequest.inStore("counts-window-store").withQuery(byWindow);
+    StateQueryRequest<ReadOnlyRecordIterator<Windowed<String>, Long>> 
sessionRequest =
+        StateQueryRequest.inStore("counts-session-store").withQuery(byKey);
+    
+    StateQueryResult<ReadOnlyRecordIterator<Windowed<String>, Long>> result = 
streams.query(windowRequest);
+    // Iterate result.getPartitionResults() and close each 
ReadOnlyRecordIterator, as in the range example.
+
+**Behavior notes**
+
+  * **Window start range is required.** As with the existing window queries, 
`TimestampedWindowKeyWithHeadersQuery` and the `withWindowStartRange` form of 
`TimestampedWindowRangeWithHeadersQuery` require a closed window-start range — 
both `timeFrom` and `timeTo` must be present, and both bounds are inclusive.
+  * **Close iterators exactly once.** The range and window queries return a 
`ReadOnlyRecordIterator`; close it when you are done — always, even if a 
`next()` call throws partway through — or the underlying store iterator (and 
the store's `num-open-iterators` metric) leaks. A try-with-resources block does 
this correctly. The iterator does not support `remove()`.
+  * **Read-your-writes applies only to the single-key query.** Only 
`TimestampedKeyWithHeadersQuery` reads through the record cache, so it sees a 
write that has not yet been flushed to the store — unless you call 
`skipCache()`, or the entry has already been flushed. The range, window, and 
session queries bypass the cache entirely, so a not-yet-flushed write is 
invisible to them and, with a position bound, fails with a not-up-to-bound 
error.
+
+**How the store was built determines what the queries return.** For key-value 
and window stores, the outcome depends on the supplier the `*WithHeaders` 
builder wraps:
+
+<table>
+<tr>
+<th>
+
+`*WithHeaders` store built over…
+</th>
+<th>
+
+Headers
+</th>
+<th>
+
+Query outcome
+</th> </tr>
+<tr>
+<td>
+
+Native (RocksDB) header supplier
+</td>
+<td>
+
+Returned
+</td>
+<td>
+
+All succeed
+</td> </tr>
+<tr>
+<td>
+
+In-memory non-header supplier
+</td>
+<td>
+
+Returned (a marker keeps the header-format bytes verbatim)
+</td>
+<td>
+
+All succeed
+</td> </tr>
+<tr>
+<td>
+
+Persistent *timestamped* non-header supplier
+</td>
+<td>
+
+Empty

Review Comment:
   [content] "Empty" needs the same cache-served caveat you gave the plain row. 
On a timestamped-adapter build a warm `TimestampedKeyWithHeadersQuery` returns 
the written headers — the record cache holds the full serialized bytes and sits 
above the adapter — and they only go empty once flushed or with `skipCache()`. 
`TimestampedKeyValueStoreBuilderWithHeadersTest.java:393` asserts exactly that: 
`expectedHeaders = cachingEnabled ? headers : new RecordHeaders()`.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to