Why do I need explicit breakpoints after both D and E in ABCDE to reuse cached ABCD?

Why do I need explicit breakpoints after both D and E in ABCDE to reuse cached ABCD?

Hi,

I am trying to understand why an explicit cache breakpoint after D must remain in the next request when I append E.

Using the same prompt_cache_key:

Request 1: ABCD/       -> writes ABCD
Request 2: ABCDE/      -> cached_tokens = 0, rewrites full ABCDE

However, if Request 2 keeps the old D breakpoint and adds E:

Request 1: ABCD/
Request 2: ABCD/E/     -> reads ABCD, writes only E

Here / means prompt_cache_breakpoint: {"mode":"explicit"}.

The A-D message text, roles, ordering, model, cache key, cache mode, and TTL are unchanged. Request 2 only appends E and moves the sole breakpoint from D to E.

One representative run returned:

ABCD/  seed:           cached_tokens=0,    cache_write_tokens=2233
ABCDE/ move probe:     cached_tokens=0,    cache_write_tokens=2497
ABCD/E/ retain probe:  cached_tokens=2233, cache_write_tokens=264

Minimal reproduction

#!/usr/bin/env bash
set -euo pipefail

: "${OPENAI_API_KEY:?OPENAI_API_KEY is required}"

MODEL="${OPENAI_MODEL:-gpt-5.6-luna}"
ENDPOINT='https://api.openai.com/v1/responses'
NONCE=$(uuidgen | tr '[:upper:]' '[:lower:]' | tr -d '-')
CACHE_KEY="explicit-breakpoint-repro:${NONCE}"

A_FILLER=$(printf 'foundation %.0s' {1..1400})
ECHO_FILLER=$(printf 'echo %.0s' {1..256})

A=$(printf 'RUN_NONCE=%s\nSEGMENT_A\n%s' "$NONCE" "$A_FILLER")
B=$(printf 'SEGMENT_B\n%s' "$ECHO_FILLER")
C=$(printf 'SEGMENT_C\n%s' "$ECHO_FILLER")
D=$(printf 'SEGMENT_D\n%s' "$ECHO_FILLER")
E=$(printf 'SEGMENT_E\n%s' "$ECHO_FILLER")

jq -n \
  --arg model "$MODEL" \
  --arg key "$CACHE_KEY" \
  --arg a "$A" --arg b "$B" --arg c "$C" --arg d "$D" \
  '{
    model: $model,
    instructions: "Reply with exactly OK.",
    input: [$a, $b, $c, $d]
      | map({type:"message", role:"user", content:[{type:"input_text", text:.}]}),
    stream: true,
    max_output_tokens: 64,
    prompt_cache_key: $key,
    prompt_cache_options: {mode:"explicit", ttl:"30m"}
  }
  | .input[3].content[0].prompt_cache_breakpoint = {mode:"explicit"}' \
  > /tmp/oai-breakpoint-request-1.json

jq -n \
  --arg model "$MODEL" \
  --arg key "$CACHE_KEY" \
  --arg a "$A" --arg b "$B" --arg c "$C" --arg d "$D" --arg e "$E" \
  '{
    model: $model,
    instructions: "Reply with exactly OK.",
    input: [$a, $b, $c, $d, $e]
      | map({type:"message", role:"user", content:[{type:"input_text", text:.}]}),
    stream: true,
    max_output_tokens: 64,
    prompt_cache_key: $key,
    prompt_cache_options: {mode:"explicit", ttl:"30m"}
  }
  | .input[4].content[0].prompt_cache_breakpoint = {mode:"explicit"}' \
  > /tmp/oai-breakpoint-request-2.json

curl --fail-with-body --silent --show-error --no-buffer \
  "$ENDPOINT" \
  -H "Authorization: Bearer ${OPENAI_API_KEY}" \
  -H 'Content-Type: application/json' \
  --data-binary @/tmp/oai-breakpoint-request-1.json \
  --output /tmp/oai-breakpoint-response-1.sse

sleep 2

curl --fail-with-body --silent --show-error --no-buffer \
  "$ENDPOINT" \
  -H "Authorization: Bearer ${OPENAI_API_KEY}" \
  -H 'Content-Type: application/json' \
  --data-binary @/tmp/oai-breakpoint-request-2.json \
  --output /tmp/oai-breakpoint-response-2.sse

for response in /tmp/oai-breakpoint-response-1.sse \
                /tmp/oai-breakpoint-response-2.sse; do
  sed -n 's/^data: \({.*\)$/\1/p' "$response" \
    | jq 'select(.type == "response.completed")
          | .response.usage.input_tokens_details'
done

My question is:

Is this the intended explicit-mode behavior? Does the service only attempt cache lookup at breakpoint positions that are still present in the current request, even when an earlier exact prefix was already cached under the same prompt_cache_key?

If so, does a client that resends full conversation history need to retain every earlier breakpoint it may want to reuse, producing ABCD/E/ rather than moving the breakpoint forward to ABCDE/