Skip to content

Commit 75febb9

Browse files
committed
docs: clarify SDLBench cache contract
1 parent 9960b5e commit 75febb9

1 file changed

Lines changed: 34 additions & 10 deletions

File tree

devdocs/superpowers/specs/2026-08-30-sdlbench-prompt-cache-design.md

Lines changed: 34 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -71,12 +71,13 @@ interface BenchmarkSession {
7171
interface BenchmarkTurn {
7272
turnIndex: number;
7373
request: unknown;
74+
canonicalModelInput: string;
7475
toolCalls: unknown[];
7576
toolResults: unknown[];
7677
}
7778
```
7879

79-
The persisted representation uses deterministic JSON serialization. Tool order, object key order, and result bytes are part of the measured cache surface. Operational timestamps, durations, request IDs, absolute paths, and other non-actionable noise remain outside the model-facing transcript.
80+
The persisted transcript stores every canonical model-input string, not only a digest. It also records the assembly version, serialization version, UTF-8 encoding, and tokenizer identity needed to replay the cache calculation losslessly. Tool order, object key order, and result bytes are part of the measured cache surface. Operational timestamps, durations, request IDs, absolute paths, and other non-actionable noise remain outside the model-facing transcript. Benchmark transcripts contain controlled fixture data only, not user sessions.
8081

8182
The same task fixture defines the user request, turn limit, context budget, quality oracle, and completion criteria for every product. Product-specific instructions are allowed only when they arrive through that product's normal public installation or MCP loading path.
8283

@@ -85,11 +86,22 @@ The same task fixture defines the user request, turn limit, context budget, qual
8586
Each benchmark result contains deterministic simulated metrics and optional provider metrics:
8687

8788
```ts
89+
type ProviderCacheResult =
90+
| {
91+
status: "available";
92+
provider: string;
93+
model: string;
94+
pricingProfile: string;
95+
ranking:
96+
| { status: "ranked" }
97+
| { status: "unranked"; reason: string };
98+
metrics: CacheMetrics;
99+
}
100+
| { status: "unavailable"; reason: string };
101+
88102
interface CacheResult {
89103
simulated: CacheMetrics;
90-
provider:
91-
| CacheMetrics
92-
| { status: "unavailable"; reason: string };
104+
provider: ProviderCacheResult;
93105
}
94106

95107
interface CacheMetrics {
@@ -117,6 +129,8 @@ effectiveSavingsPct = effectiveSavingsTokens / totalInputTokens
117129

118130
Zero-input runs report zero percentages rather than `NaN`.
119131

132+
Each run starts a fresh product and model session. Turn `0` is the cold phase; turns `1..` are the warm phase. A one-turn run has an all-zero warm phase. Repeated executions use new run IDs and begin new cold phases. Whole-session values are the sum of the cold and warm phase values.
133+
120134
### Deterministic simulation
121135

122136
The simulator compares consecutive serialized model-input prefixes. A byte is reusable only while every preceding byte is unchanged. Content moved earlier, reordered keys, changing tool definitions, and injected runtime metadata invalidate the prefix from the first differing byte.
@@ -130,7 +144,16 @@ Token counts use SDLBench's existing tokenizer. The simulator records:
130144
- invalidated-prefix tokens
131145
- reusable-prefix percentage
132146

133-
For simulation, reusable-prefix tokens are cache reads and all remaining input tokens are uncached. Cache writes are reported separately but use a neutral weight of `1.0`, so the simulated gate measures deterministic reuse rather than provider pricing.
147+
For each turn, the simulator partitions input tokens into two mutually exclusive categories. A token is a cache read only when all of its serialized UTF-8 bytes occur before the first differing byte from the prior turn. Every other token is a cache write. Simulated uncached input is zero, so `totalInputTokens = cacheReadTokens + cacheWriteTokens`.
148+
149+
The first turn has zero reads and writes its complete input. Later turns read the unchanged prefix and write the changed suffix. Simulation assigns read weight `0.0` and write weight `1.0`:
150+
151+
```text
152+
simulatedEffectiveInputTokens = cacheWriteTokens
153+
simulatedEffectiveSavingsTokens = cacheReadTokens
154+
```
155+
156+
This is an ideal deterministic reuse measure, not a prediction of provider cache thresholds, expiration, or pricing.
134157

135158
### Provider normalization
136159

@@ -151,7 +174,7 @@ effectiveInputTokens =
151174

152175
Weights are the provider's read and write prices divided by its normal input price for the recorded model. This expresses cache cost in full-price input-token equivalents. Cold writes can therefore produce negative savings when a provider charges a write premium. Dollar savings use the same profile but remain informational.
153176

154-
Provider comparisons are valid only when product results use the same provider, model, and pricing-profile version.
177+
Provider comparisons are valid only when product results use the same provider, model, and pricing-profile version. Aggregation assigns `ranking.status`: compatible records are `ranked`; valid but incompatible records are retained as `unranked` with the mismatch reason.
155178

156179
## Provider Usage Import
157180

@@ -168,7 +191,8 @@ Provider usage is imported after a benchmark session. SDLBench never stores cred
168191
"turns": [
169192
{
170193
"turnIndex": 0,
171-
"inputTokens": 12000,
194+
"totalInputTokens": 12000,
195+
"uncachedInputTokens": 3000,
172196
"cacheReadTokens": 0,
173197
"cacheWriteTokens": 9000,
174198
"outputTokens": 800
@@ -177,7 +201,7 @@ Provider usage is imported after a benchmark session. SDLBench never stores cred
177201
}
178202
```
179203

180-
The importer joins records by `productId`, `taskId`, `runId`, and `turnIndex`. It rejects duplicate turns, negative or non-finite values, unknown runs, mismatched product identities, and incompatible provider/model/profile combinations.
204+
The importer joins records by `productId`, `taskId`, `runId`, and `turnIndex`. It rejects duplicate turns, negative or non-finite values, unknown runs, mismatched product identities, and provider metadata that conflicts with the recorded run. A provider, model, or profile mismatch between otherwise valid product runs does not discard either run; aggregation retains both and marks that comparison unranked.
181205

182206
Imported files must not contain raw prompts, tool results, API keys, provider request IDs, or user data.
183207

@@ -221,7 +245,7 @@ interface ProductBenchmarkResult {
221245
}
222246
```
223247

224-
Saved results include the benchmark schema version, tokenizer identity, fixture revision, pricing-profile identity, and transcript digest. Comparisons reject incompatible schema, tokenizer, or fixture revisions instead of silently combining them.
248+
Saved results include the losslessly replayable transcript artifact, transcript digest, benchmark schema version, assembly version, serialization version, tokenizer identity, fixture revision, and pricing-profile identity. The result summary references that artifact. Comparisons reject incompatible schema, assembly, serialization, tokenizer, or fixture revisions instead of silently combining them.
225249

226250
Synthetic traces are regenerated from the same session/result contract. Existing stale traces remain historical artifacts and must not be presented as current SDLBench evidence.
227251

@@ -263,6 +287,6 @@ The rollout does not require provider credentials in CI. The first four steps ca
263287
- SDL-MCP, the traditional baseline, and every tested competitor produce the same session/result shape.
264288
- Every run saves simulated cache metrics; imported provider metrics are optional and explicitly ranked or unranked.
265289
- Whole-session, cold, warm, and per-turn cache values are reproducible from saved inputs.
266-
- Existing raw token, uncapped token, coverage, precision, and recall metrics remain available.
290+
- Existing raw token, capped token, uncapped token, coverage, precision, and recall metrics remain available.
267291
- Synthetic traces are regenerated and no stale-trace warning remains.
268292
- SDLBench documentation explains cache formulas, fairness rules, ranking eligibility, and provider-profile compatibility.

0 commit comments

Comments
 (0)