0110: Remove the reask assistant-prefill continuation branch¶
- Status: Accepted
- Author: Chris Colinsky
- Created: 2026-07-27
- Accepted: 2026-07-27
- Ships as: v0.104.1
- Targets: spec/llm-provider/spec.md §7.1 (remove the reask working-transcript's
assistant-prefill continuation clause — the branch that fires "when the working transcript's last
message is already an
assistantmessage (e.g. a caller prefill)"); spec/conformance-adapter/spec.md §5.11 (remove the full-listwire_requests[*].messagessub-form, whose sole documented purpose is asserting that continuation); conformance: remove llm-provider fixture067-call-level-reask-assistant-prefill-continuation(.md+.yaml), the branch's only fixture. - Related: 0095 (introduced the reask feature, the continuation clause, fixture 067, and the §5.11
messagessub-form — this retracts that one branch and leaves the rest of 0095 in force), 0082 (structured_output_invalidis the failure reask makes retryable — unchanged) - Supersedes:
Summary¶
0095's structured-output reask specifies a working transcript that starts from the caller's messages
and, on each structured_output_invalid retry, appends the model's raw output as an assistant message
plus the caller's correction as a user message. One sub-clause handles a special case: when the
transcript's last message is already an assistant message (a caller prefill), the model's output
continues that message rather than starting a new one. Fixture 067 exercises exactly that, and the
conformance-adapter §5.11 full-list messages directive exists only to assert it.
That branch is unreachable. llm-provider §3 already requires — as a hard MUST, with mandatory
pre-send validation — that the last message handed to complete() be user or tool; a caller cannot
supply a trailing assistant prefill without the call raising provider_invalid_request first. So the
one input that would put an assistant message last in the transcript is rejected before reask runs.
The continuation branch, its fixture, and its bespoke assertion directive are dead code that contradicts
§3, and fixture 067 is unsatisfiable against a conforming implementation (one that validates §3 as
required raises provider_invalid_request on 067's input and can never reach the asserted success).
This proposal removes the branch, the fixture, and the directive. No reachable behavior changes.
Motivation¶
The contradiction is a governance-level defect: two sections of the same spec prescribe incompatible things for the same input, and a shipped conformance fixture cannot be satisfied by a conforming implementation. A reference implementation surfaced it directly — an implementation that correctly enforces the §3 MUST rejects fixture 067's input, so 067 fails not because the implementation is wrong but because the fixture asks it to violate §3.
The deeper cause is that 0095 introduced first-class prefill support (a caller starting the
assistant turn, e.g. {role: assistant, content: "Sure: "}) as a side effect of reask, in a spec that
does not support prefill as an input anywhere. §3 forbids a trailing assistant message; no §8.x wire
mapping handles prefill continuation; nothing outside the 0095 reask clause mentions it. Prefill is a
real and useful technique, but it is provider-specific (Anthropic continues a trailing assistant
message; OpenAI-compatible and Gemini treat it differently), so blessing it belongs in a deliberate,
cross-provider proposal that amends §3 and every mapping — not in a reask footnote that one mapping's
fixture silently assumes. Removing the branch now settles the contradiction; a future proposal MAY add
prefill as a proper first-class input if cross-provider demand warrants.
Reachability proof (why removal is non-behavioral)¶
The continuation branch fires only when the reask working transcript's last message is assistant
at the moment reask appends. Trace every way the transcript can end:
- It starts as a copy of the caller's
messages. Per §3 those end inuserortool(MUST, validated pre-send) — neverassistant. - A reask retry appends
[assistant output, user correction]— ending inuser. - A transient retry appends nothing — the ending is unchanged.
So the transcript ends in user/tool in every case, and the "last message is already assistant"
condition is only ever true if the caller supplied a trailing-assistant prefill — which §3 rejects
before the retry loop runs. The branch is therefore unreachable for any implementation that enforces §3,
which every conforming implementation MUST. Removing it changes no reachable behavior; appending the
model's output as a fresh assistant message (the general rule that remains) is always valid because the
transcript never ends in assistant, so it never produces the consecutive-assistant sequence §8.2
forbids.
Proposal¶
1. llm-provider §7.1 — remove the assistant-prefill continuation clause¶
In the reask extension text, the sentence currently reads (verbatim):
The
assistantmessage carries the attempt's output as the text the error surfaces onoutput_content(§7 / 0082); when the working transcript's last message is already anassistantmessage (e.g. a caller prefill), the output continues that message — concatenated onto its content verbatim, with no OA-added separator — rather than starting a new one, so alternation still holds.
The continuation clause (everything from the semicolon onward) is removed, leaving:
The
assistantmessage carries the attempt's output as the text the error surfaces onoutput_content(§7 / 0082).
The surviving rule is unchanged and unambiguous: the model's raw output is appended as an assistant
message and the builder's correction as a user message, keeping the sequence role-alternating. The
reachability proof above guarantees this never yields consecutive assistant messages. Every other reask
obligation (transcript accumulation, the single max_attempts budget, the builder invoked only when a
further attempt remains, transient retries appending nothing, OA authoring no text of its own) is
untouched.
2. conformance-adapter §5.11 — remove the full-list wire_requests[*].messages sub-form¶
§5.11's per-attempt wire_requests directive documents two message-assertion sub-forms:
appended_messages (the ordered pairs a reask retry appends after the caller's messages) and the
full-list messages (the whole outbound list). The full-list form earns its keep only when a retry
modifies a caller message rather than only appending after it — a case appended_messages cannot
express — and the assistant-prefill continuation was the sole modifying case the retry loop defined
(fixture 067 is its only user; every other reask fixture asserts via appended_messages). With the
continuation branch gone, every reachable retry-loop attempt is append-only, so appended_messages
covers all of them and the full-list messages form is not merely unused but uncoverable: no
reachable fixture, present or future, could exercise it that appended_messages could not. It is removed.
appended_messages (and the sampling and attributes_absent directives) are unchanged, as is the
single-request expected_wire_request.messages whole-list assertion the provider wire-mapping fixtures
use (a separate directive, untouched). This keeps the conformance-adapter directive vocabulary matched to
what fixtures actually use, per the 0107 principle that documented directives track real fixture usage.
3. Conformance — remove fixture 067¶
spec/llm-provider/conformance/067-call-level-reask-assistant-prefill-continuation.{md,yaml} is removed.
It is the continuation branch's only fixture and is unsatisfiable against a §3-conforming implementation.
The reachable reask behavior stays fully covered by fixtures 062–066 (success, budget exhausted,
off-by-default, override compose, transient interleave). No fixture is renumbered — conformance fixtures
are addressed by filename, and the corpus tolerates a gap at 067.
Conformance¶
- Removed: llm-provider fixture
067-call-level-reask-assistant-prefill-continuation. No fixture is added — this proposal removes an unsatisfiable fixture for an unreachable branch and adds no new behavior to cover. The reachable reask surface remains covered by 062–066.
Versioning¶
PATCH (whole-spec SemVer) — v0.104.1. Non-behavioral: the removed §7.1 clause, §5.11 sub-form,
and fixture 067 all describe a branch unreachable under the §3 message-ordering MUST, so no conforming
implementation's behavior changes and none can newly fail (the removal deletes an expectation, and one
that no conforming implementation could satisfy). This is the clarification/erratum class
(governance §"Spec versioning": clarification … or non-behavioral change). Two capabilities' Latest
advance to the shipped version (llm-provider and conformance-adapter both change), as their spec text is
edited; neither gains or loses behavior.
Open questions¶
- First-class prefill support is deliberately out of scope. If a caller-supplied trailing-
assistantprefill is worth supporting as an input, it earns its own proposal that amends §3's message-ordering MUST and specifies the continuation semantics across every §8.x wire mapping (Anthropic, OpenAI- compatible, Gemini), whose native trailing-assistantbehavior differs. That is a MINOR feature addition, not this erratum.