> ## Documentation Index
> Fetch the complete documentation index at: https://docs.nextmoca.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Release notes

> What changed at /v1: the default moving to np-2026-08-r4, the np-2026-08-r4 label's publication (2026-09-03), and the 2026-08-07 changes, including the one behavior change worth checking against your own traffic.

**Every field below is additive within `/v1`**; see [Versioning](/versioning)
for what that guarantees, and it is a real guarantee: nothing was removed,
renamed, or made required. It is not the same claim as "nothing about your
traffic changes." If you pin `budget.operating_point` on every request, as
[Operating points](/concepts/operating-points#always-pin-it) has always
recommended, the entry directly below does not apply to you at all. If you do
not, read it: an unpinned caller can see a genuinely different status code on
some requests, not only additive fields. The `importance` default change
further down is the one item worth five minutes of your attention regardless
of pinning.

## The default moves to `np-2026-08-r4`

**A request that omits `budget.operating_point` now runs `np-2026-08-r4`
instead of `np-2026-07-r2`.** Nothing else changed to cause this: the label
itself is unchanged, immutable, and still resolvable by name exactly as
before. Only the server's resolution of an *absent* label moved.

**If you pin `budget.operating_point` on every request, this entry does not
apply to you.** A pinned label runs exactly the configuration it always has;
see [what a label pins](/concepts/operating-points#what-a-label-pins-and-what-it-cannot).
`np-2026-07-r2` and `np-2026-08-r3` both stay in the registry and stay
pinnable; nothing about them changed.

**If you do not pin it**, here is what moves, stated from live captures, not
from the general description of `r4` elsewhere on this site:

* **New, additive response fields start appearing**: `selection_recall`,
  `records_admitted`, and four top-level fields (`task_kind`,
  `selection_strategy_used`, `support_contract_used`,
  `adapter_attempt_count`). A client that already
  [ignores fields it does not recognise](/versioning#two-rules-that-keep-your-client-working)
  needs no change.
* **`safety` is populated far more often.** It reads `null` on
  `np-2026-07-r2`'s plain fixed-budget path; `np-2026-08-r4` was observed
  computing a real verdict on the same kind of request. See
  [the two cases that are not errors](/errors#the-two-cases-that-are-not-errors).
* **A request that used to stand down with an empty selection may come back as
  a full-context pass-through instead.** Where `np-2026-07-r2` returns
  `records_selected: 0` and nothing in `selected[]`, `np-2026-08-r4` can return
  every record you sent, unchanged, including one sent with `importance: 0.0`.
  Both are `200`, neither is charged, and the shape of `selected[]` is
  genuinely different. See [reading a stand-down](/errors#reading-a-stand-down).
* **`gate.reason` strings change.** Different standdown and engage reasons are
  in play under `r4` than under `r2`. This was already true of every label
  change; keep logging `gate.reason` rather than branching on it, and branch on
  `outcome` as [Errors](/errors#reading-a-stand-down) has always said.
* **A `text` request whose paragraphs normalize to more than 1,000 units is
  now rejected with `400`, `reason: "semantic_normalization_limit"`, instead
  of being silently capped at 1,000 units and served as a `200`.** See
  [the normalization ceiling](/limits#the-text-normalization-ceiling-and-why-it-differs-by-operating-point).

None of this is a wire-contract change: every field above is additive, and a
client following
[the two rules that keep it working](/versioning#two-rules-that-keep-your-client-working)
handles all of them without a code change. **The `text`-normalization item is
the one exception worth naming plainly**: it is a new failure mode, not just a
new field, and a client that does not already handle `400` gracefully can
break on a request that previously returned `200`. Everything else here is
listed because *behaviour* moved for any caller that never chose a label,
which is exactly the caller
[Operating points](/concepts/operating-points#always-pin-it) has always warned
about; the fix in every case, including the `text`-normalization one, is the
same one-line pin.

## 2026-09-03: `np-2026-08-r4` is published

The [registry](/concepts/operating-points#the-registry) now lists
`np-2026-08-r4`. At the time of this entry, the default was unchanged: a
request that omitted `budget.operating_point` still ran `np-2026-07-r2`. See
the entry above for when the default itself moved.

Across the three example requests on
[Choosing an operating point](/concepts/choosing-an-operating-point),
`np-2026-08-r4` returned the `np-2026-07-r2` fields, the `selection_recall`
block and `records_admitted` that `np-2026-08-r3` added, four additive
top-level fields (`task_kind`, `selection_strategy_used`,
`support_contract_used`, `adapter_attempt_count`), a `selection_recall.version`
of `npsr-2026-08-r2`, and further `format_metrics` entries. Optional
`format_metrics` entries vary by label: on those three requests r4 did not emit
`capacity_cap_tokens`, which r3 does. Treat any `format_metrics` entry as
optional, as [Versioning](/versioning#two-rules-that-keep-your-client-working)
already asks. [Choosing an operating point](/concepts/choosing-an-operating-point)
shows the same three requests under all three labels.

The rest of this page describes the 2026-08-07 changes.

## Behavior change: the default for a missing `importance`

<Warning>
  **Records that omit `importance` no longer default to `0.0`.**

  Previously, a record sent without an `importance` field was scored as if it
  had explicitly set `importance: 0.0`, the lowest possible value on the
  signal's own scale. That biased selection *against* those records, toward
  stand-down, purely because the field was absent rather than because it was
  genuinely low-priority. Records now receive a neutral default instead, so
  omitting the field no longer counts against them.

  **This changes selection output for requests whose records omit
  `importance`.** As a historical example, at the time this note was written the
  site's canonical billing-dispute fixture (a smaller, 12-record version of the
  one now on the [quickstart](/quickstart#5-make-a-selection); the fixture has
  since been enlarged for other reasons and no longer produces these exact
  numbers) previously returned `records_selected: 1` and `tokens_saved: 785`.
  Under the same 12-record request it then returned `records_selected: 2` and
  `tokens_saved: 733`: the neutral default let a second record clear the bar
  that the old zero-default held it under.

  **Requests that set `importance` explicitly are unchanged.** This only
  affects the default applied when the field is absent; a record that sends
  its own value, including `0.0`, scores exactly as it did before.

  Stand-downs remain billed at `charge_multiplier: "0"` regardless of which
  default applied; see [How billing works](/billing/how-billing-works).
</Warning>

Nothing about this is a wire-contract change: no field was added, removed,
renamed, or made required, and the response shape is identical. It is listed
here because it can move selection output for a request that was, and
remains, perfectly valid. If your integration pins exact record sets or
byte-compares responses for requests that omit `importance`, re-run them
against current behavior. If you always set `importance` explicitly, or don't
compare responses byte-for-byte, there is nothing to do.

<Note>
  **This is what "a label pins the configuration, not the engine build" looks
  like in practice.** The change above landed in the engine, not in any operating
  point's settings, so it moved output under labels that were pinned the whole
  time. Pinning did its job: no threshold behind `np-2026-07-r2` was retuned. It
  simply does not extend to the code reading those thresholds. See
  [what a label pins](/concepts/operating-points#what-a-label-pins-and-what-it-cannot),
  and record `build_id` from `/v1/health` next to `policy_version` if you keep
  results to compare.
</Note>

## Added: the simple request shape

You can now send raw material instead of pre-split records. See
[The simple shape](/quickstart#start-here-the-smallest-call-that-works) in the quickstart for the
full walkthrough; the short version:

* Send `text` in place of `records[]`. Needlepath splits it on blank lines,
  and each resulting chunk becomes one record of kind `external_data`.
* Each derived record gets a stable id of the form `sha256:<16 hex
  characters>`, the hash of that record's own text, so you can recompute it
  yourself from the chunk content. The same paragraph always produces the
  same id.
* `budget.operating_point` is optional on this shape, same as with
  `records[]`. Whichever operating point resolves is always echoed back in
  `policy_version`.
* `budget.max_context_tokens` is still required: there is no operating-point
  default to fall back to when the request carries no `records[]`-based
  budget elsewhere.
* Sending both `text` and `records` in the same request is a `400`, with
  `error: "text_and_records_both_set"`.

This is purely additive: `records[]` continues to work exactly as before, and
nothing about it changed.

## Added: optional fields

* **`request_id` is now optional everywhere.** It remains a caller-side
  correlation id, echoed back on the response and useful for tying a request
  to your own logs; omit it and nothing about selection, metering, or the
  response shape changes.
* **`records[].kind` is now optional**, defaulting to `external_data` when
  omitted. Setting it explicitly is still worth doing; see
  [Records and tasks](/concepts/records-and-tasks), since `kind` carries
  selection priors that a default cannot infer for you.

## Also in this release: console

* The self-serve dashboard now shows value metrics on the account overview:
  tokens saved, an estimated savings figure at a labelled reference price,
  and a lifetime savings percentage.
* Usage analytics gained selectable time windows (all-time, 30 days, 7 days,
  and 24 hours) with both a chart and a table view, and a per-key breakdown.
* A signed-in demo is now available that runs live requests against your own
  API key, rather than a shared or sample credential.

## Not a version bump

Every item on this page ships at the existing `/v1` URL version. Nothing here
removes a field, renames a field, makes an optional field required, or
narrows an accepted range; see [What counts as breaking](/versioning#what-counts-as-breaking)
for the exact test. The `importance`-default change is a behavior change, not
a contract change: the request and response shapes are byte-identical to
before, and a client written against the documented schema keeps working
without modification.
