Skip to main content
Three labels are worth choosing between today: np-2026-08-r4, the newest and the default, np-2026-08-r3, and np-2026-07-r2, which a caller had to pin explicitly starting from when the default moved to r4; see release notes. np-2026-07-r1 stays resolvable for work that cites it and is not a label to start on. This page describes what each label does, in terms you can see in a response. It does not rank them by quality.
We do not publish an accuracy comparison between operating points. We have not measured one at a scale that would justify a public claim, and a comparison made on our workloads would not transfer to yours in any case. Anyone telling you that one label is “better for retrieval” is describing an impression, not a published result.Choose by the behaviour described below, then validate on your own traffic before you switch. That is the only comparison that answers your question.

What differs, on the wire

Everything in this table is observable in a response you can produce yourself. Row two is the one that decides most migrations for a workload that leans toward standing down: see the stand-down case, where r2 returns nothing and r3 and r4 return your whole context instead, neither charged for it. It is not the only outcome on this page, though: the canonical request below is a case where all three labels find something worth selecting, and select different amounts of it. Whether either pattern holds across your traffic, and what it costs there, is a question only your traffic can answer, which is what the evaluation step is for.
selection_recall and records_admitted are additive response fields that np-2026-08-r3 and np-2026-08-r4 emit and np-2026-07-r2 does not; np-2026-08-r4 adds four more top-level fields. A client that follows the rule about ignoring unrecognised fields needs no change to accept them.

The same request under all three labels

This is the canonical billing-dispute request, unchanged except for budget.operating_point. It is a 30-record request now: the same billing dispute, plus support-desk distractors, enlarged specifically so a reader could see all three labels engage on it rather than only r2. Run it yourself and you will get these numbers.
All three engage on this request; none of them stands down or passes through. r2 selects the tightest set, the customer’s message and the credit policy (r-008, r-009); r3 and r4 select the same five records as each other, in the same order, for the same token arithmetic: those two plus the refund policy and its exceptions (r-004, r-005) and a prior agent turn (r-021). All three are charged at the full rate, because all three engaged.
r3 and r4 agree here down to the byte count, unlike on the stand-down example below, where they also agree with each other but differ from r2 in kind, not just in count. Do not read “r3 and r4 selected the same records” as a general rule: it is a property of this request, not a guarantee. Evaluate on your own traffic rather than assuming it transfers.
r3 and r4 both selected on the first recall pass; neither had to widen its search, so format_metrics.attempted_recall_rungs holds one entry on both. Their selection_recall blocks otherwise carry the shape the wire-differences table above describes, at version: "npsr-2026-08-r1" on r3 and "npsr-2026-08-r2" on r4:
Read the observable difference plainly, without a story about why: on this request r2 selected two records; r3 and r4 each selected the same wider set of five. None of the three needed to widen its search to reach its conclusion, which is itself informative: a request this well-supported does not exercise the multi-rung recall path at all. The stand-down example below is where r3 and r4’s behaviour actually diverges from r2’s.

And a request where all three agree

Forty filler records and one that answers the question, at a 600-token budget. Build it yourself:
All three labels select n-001 and nothing else. All three report records_selected: 1, tokens_before: 2418, tokens_saved: 2360 and reduction_ratio: 0.9760132340777502, and all three engage rather than fall back, at charge_multiplier: "1.0". The selected set and the token arithmetic are identical across the three. The responses also differ in the additive fields r3 and r4 add, in selected[].reason, selected[].score and gate.reason, and r4 inserts a newline in both selected[].excerpt and rendered_context. The reason strings are open-ended, and none of these differences changes the selected record. We include this deliberately. It is the case a “the newer label is stronger at long sparse retrieval” story would predict a difference on, and there is none. Do not pick a label on a story; pick it on your own traffic.

A stand-down is a correct outcome

The most common surprise on a first integration is a response that saved nothing. Usually nothing is wrong. Needlepath selects when there is a selection worth making. Two ordinary situations produce no savings:
If everything you sent fits comfortably inside max_context_tokens, there is no pressure to relieve, and cutting would only lose you information for no gain. You get your context back. The three-record example does exactly this.
If no record scores meaningfully above the others against your task, there is no defensible subset to choose. Returning an arbitrary one would be worse than returning all of them.

What that looks like under each label

Three small records, a 4000-token budget, and nothing under pressure. This is the three-record example, sent unchanged to all three labels. One of the three is sent with importance: 0.0, the lowest priority the signal has; it comes back on r3 and r4 exactly like the other two.
Same request, same conclusion that there is nothing worth selecting, and one difference in what comes back: r2 returns nothing, r3 and r4 return all three records unchanged, including the one sent with importance: 0.0. A full-context fallback does not filter by importance; nothing is dropped for any reason on that path. None of the three is charged: stood_down on r2 and pass_through on r3 and r4 both carry charge_multiplier: "0". All three hand you a context you can send. It is still worth measuring on your own traffic before switching: a fallback that changes the token total is charged, and how often that happens is a property of your workload. Both are 200 responses. Neither is an error, and neither means the integration is broken. Read them like this:
If most of your traffic stands down, that is a signal about the workload rather than a fault: you are probably calling on contexts that already fit. The homepage has the fit criteria. Measure it with shadow mode before you tune anything.

Evaluating a newer label on your own traffic

Nothing below requires a code change beyond the value of one string.
1

Mirror real traffic, do not switch it

Keep production pinned to the label it runs today. Send a copy of the same requests with budget.operating_point set to the label you are evaluating, and discard the result. This is exactly the shadow mode pattern, with the label as the only variable. Wrap it so a failure cannot touch the real call.Both calls are metered, and each is billed according to its own receipt’s charge_multiplier. Sample if that matters: a fixed fraction of requests, chosen by a stable uniform hash of request_id rather than by content, keeps the comparison representative and reduces the cost in proportion.
2

Compare the pairs, not the aggregates

Log both responses against the same request_id and compare per request:An aggregate savings figure will not tell you whether an answer degraded. The per request dropped-record list will.
3

Spot-check the disagreements

Pull the requests where the two labels selected different records and read them. That set is normally small, and it is the entire evidence base for the decision.
4

Switch one string

When you are satisfied, change budget.operating_point to the label you evaluated in production. Nothing else in the request or the response handling changes.

Rolling back

Set budget.operating_point back to the label production ran before the switch: whatever label you pinned production to before you started evaluating a new one. The warning below covers the case where there was nothing pinned to go back to; the default itself has moved once already (np-2026-07-r2 to np-2026-08-r4), which is exactly the scenario it describes. That is the whole procedure, and it works because labels are immutable: the label you left applies today the same configuration it applied when you left it, so going back is not a migration, it is a one-word revert. There is no deprecation to race and no deadline attached to any published label. Every published label stays resolvable. What rollback restores is the configuration, which is the thing that changed when you switched labels. It does not rewind the engine build, and it does not need to: see what a label pins.
Rollback only works if you pinned in the first place. A caller that omits budget.operating_point inherits the server default, has nothing to revert to, and cannot tell from its own code which configuration produced last week’s results. Pin the label even when you are pinning the one that is already the default.

Next

Operating points

What a label pins, what it cannot, and why it is opaque.

Shadow mode

The measurement pattern this page’s evaluation step is built on.

How billing works

What each usage.outcome costs.

Errors

Reading a stand-down in full.