0105: Extras-key vs mapping-managed wire-field collision rule¶
- Status: Draft
- Author: Chris Colinsky
- Created: 2026-07-18
- Targets: spec/llm-provider/spec.md §6 (a general rule for what happens when an undeclared extras key
collides with a wire field the mapping manages — an explicit, bounded carve-out to the untouched
pass-through), inherited by retrieval-provider §10. Applied to the known managed keys: §8.4
embedding_types(the merge arm, ratifying 0099's mapping-local exception as the general rule) and the fail-loud truncation flag in §8.1 / §8.2 / §8.4 (truncate/truncation, the reject arm). Conformance: a reject-arm fixture. - Related: 0099 (pinned the §8.4
embedding_typescollision as a mapping-local exception and explicitly left the general rule open — this closes it), and §6's Extras pass-through contract, which this proposal amends with a bounded carve-out - Supersedes:
Summary¶
llm-provider §6 says an undeclared extras field is forwarded to the wire body untouched and MUST NOT be
translated, renamed, or transformed. It says nothing about an extras key that collides with a wire field the
mapping itself manages — a field the mapping sets for its own correctness (e.g. Cohere's
embedding_types: ["float"], which its response consumer reads; truncate: "NONE", which enforces the
fail-loud posture). Under untouched pass-through, a caller's colliding extras value silently overrides the
managed field and breaks the mapping — the exact failure 0099 prevented for one key and explicitly declined
to generalize. Two conforming implementations can diverge: forward-untouched, let-the-mapping-win, or
silently-drop.
This proposal states the general rule, bounded to keys a mapping declares it manages:
A managed wire field governs a colliding extras key. If the field is additive / list-shaped, the caller's value(s) are merged with the mapping's (de-duplicated, so a matching entry collapses). If it is a scalar whose override would break the mapping's contract, a value equal to the managed value is a redundant no-op and a conflicting value is rejected pre-send (
provider_invalid_request). A mapping MUST NOT silently drop a conflicting value or silently let it override the managed one. Keys the mapping does not manage keep untouched pass-through unchanged.
Motivation¶
The gap 0099 left open¶
0099 pinned the §8.4 embedding_types collision as an explicit mapping-local exception: the mapping must
request "float" for its own response consumer, so an extras-supplied embedding_types is merged with
"float" rather than replacing it. 0099 closed with: "The general question — what happens when any extras key
collides with any mapping-managed wire field — is not specified." This is that specification.
The failure mode is concrete. A managed field is one the mapping sets because its own logic depends on it. If an
undeclared extras key of the same name reaches the wire untouched (as §6 currently requires), it overrides the
managed value and defeats the mapping: an extras embedding_types: ["int8"] strips the embeddings.float key
the response consumer reads (0099's case); an extras truncate: "END" overrides the mapping's "NONE" and
silently truncates an over-length input the mapping meant to fail loud on. Untouched pass-through is correct for
a field the mapping doesn't touch; it is wrong for a field the mapping owns.
Why merge for some, reject for others¶
The resolution depends on the shape of the managed field:
- Additive / list-shaped (
embedding_types): the managed value and the caller's can coexist — the wire accepts a set, and the response is keyed by member, so the mapping requests"float"and the caller's precisions. Merge (deterministic order, de-duplicated) preserves both without breaking the consumer. - Scalar mode-switch (
truncate, and — when it lands — an outputencoding_format): the field selects one behavior; the managed value and the caller's are mutually exclusive. There is nothing to merge, and honoring the caller's value breaks the mapping's contract (its fail-loud posture, its response format). The only safe resolution is to reject pre-send withprovider_invalid_request— fail-loud, not a silent drop (which would hide the caller's intent) and not a silent override (which would break the mapping).
Rejecting is not hostile to the extras mechanism: it applies only to a key the mapping manages, which the mapping declares. Every other undeclared key still passes through untouched. The rule narrows, it does not close, the extras bag.
Proposal¶
1. §6 — the general rule (bounded carve-out)¶
Add to §6's Extras pass-through a managed-field collision clause:
- Define a managed wire field: a wire-body field the wire-format mapping (§8) sets for its own correctness — because its response consumer reads a value keyed to it, or because it enforces a mapping-level contract. Each §8.x mapping MUST enumerate the keys it manages.
- When an undeclared extras key names a managed field, untouched pass-through does not apply. Instead:
- Merge if the managed field is additive / list-shaped: the mapping's mandatory value(s) and the caller's are combined, in a deterministic order (mapping value(s) first), de-duplicated first-occurrence-wins.
- Reject pre-send with
provider_invalid_request(§7) if the managed field is a scalar whose override would break the mapping's contract or its response consumer — unless the extras value equals the managed value, which is a redundant no-op (the scalar analogue of the merge arm's de-duplication). - A mapping MUST NOT silently drop a conflicting extras value, and MUST NOT silently let it override the managed value.
- A key the mapping does not manage is unaffected: it keeps the untouched pass-through of §6 verbatim. The managed set is opt-in per mapping; the default for any other key is unchanged.
2. §8.4 embedding_types — the merge arm (ratify 0099)¶
Re-anchor 0099's embedding_types exception as an instance of §6's merge arm rather than a standalone
mapping-local exception: embedding_types is a managed list-shaped field; an extras-supplied value merges with
"float" (float-first, de-duplicated), per §1 above. The behavior is unchanged; only its framing generalizes.
3. truncate / truncation — the reject arm (§8.1 / §8.2 / §8.4)¶
The TEI (§8.1), Jina (§8.2), and Cohere (§8.4) embed mappings each send a managed fail-loud truncation flag
so an over-length input errors rather than being silently truncated — truncate: false (TEI; Jina
/v1/embeddings), truncation: false (Jina /v1/rerank), truncate: "NONE" (Cohere). The value type differs
by vendor, but in each case the mapping sets the flag to enforce its fail-loud contract. Declare each mapping's
truncation flag a managed scalar: an extras-supplied value that conflicts with the managed flag is
rejected pre-send with provider_invalid_request (honoring it would defeat the fail-loud posture; the
mapping MUST NOT silently drop it either); a value equal to the managed flag is a redundant no-op.
4. Conformance¶
A reject-arm fixture: an extras truncate colliding with a mapping's managed value raises
provider_invalid_request pre-send (no wire request issued). The existing retrieval-provider merge-arm
fixture (039, the embedding_types merge) already exercises §1's merge arm.
Versioning¶
MINOR (whole-spec SemVer), expected as a batch accept. Behavioral for a managed-key collision only: a
conflicting extras value on a managed scalar (truncate) that a mapping previously forwarded untouched now
rejects pre-send. That prior behavior was undefined and harmful (it silently defeated the mapping), so this is a
correction, not a removal of working behavior. A matching value is a no-op; every unmanaged extras key is
unaffected; the embedding_types merge is unchanged from 0099.
Open questions¶
- Full per-mapping managed-key audit. §1 requires each §8.x mapping to enumerate its managed keys; this
proposal enumerates the currently-known ones (
embedding_types,truncate). A future §8.x mapping MUST declare its own; the enumeration is per-mapping, not a global list. An outputencoding_formatwill be the first new reject-arm managed key when output-encoding support lands (a separate proposal).