File size: 26,788 Bytes
bb74494
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
# DS41-DSML function map

One row per function and per named constant of the DeepSeek-V4.1 encoding
oracle, then one row per DSML function of ours that the oracle does not
define.  This is the review list: what the oracle decides, where this repo
implements it, which case proves it, and what is still open.

The oracle is the official V4.1 text/vision encoding implementation,
operator-supplied 2026-10-18.  It is the authority for the carriage this
project serves; the DSML line serves no other markup for the V4.1 family.
It is vendored byte-identical at `tests/ds41_ref/oracle/encoding.py`
(sha256 `13231c592e958fb39e2af6001dae69d90e7a36b265702b9b390236fb387599e2`,
provenance in `tests/ds41_ref/oracle/README.md`) and pinned by that hash in
`tests/ds41_ref/ref_drive.py:46`, so a later edit of it fails the run loudly.
Line numbers below are into that vendored file.

## How to read a row

- Oracle: the function or constant, with its line in the oracle file.
- Decides: the one thing it fixes about the bytes.
- Ours: the counterpart in this repo, `file:line`.  "not located in this
  pass" means this session did not find a counterpart; it is a gap, not a
  claim that none exists.
- Case: the reference case that exercises it, under `tests/ds41_ref/`, with
  its fixture under `crates/ds4-server/tests/fixtures/ds41-ref/`.
- Verdict: `pass` (measured byte-identical to the oracle's fixture today),
  `OPEN` (a case exists or is owed and the bytes differ), `no case` (no case
  yet; nothing measured), `harness` (test-side only, not a served rule),
  `out of surface` (defined by the oracle but outside the OpenAI chat wire).

Verdicts are measured, not assumed: `pass` for the encode side means our
prompt bytes equal the oracle's prompt bytes for that case
(`crates/ds4-server/tests/ref_encoding.rs`), and for the decode side that our
parse yields the oracle's call names and argument values
(`crates/ds4-server/tests/ref_decode.rs`).

Every `file:line` in this document was re-verified against the working tree on
2026-10-20 (each symbol grepped in its file); the earlier revision of this map
had been written against older files and carried a uniform 40-line offset on
`render.rs` and a varying one on `parse.rs`.

## 1. Encode side — request to prompt

| Oracle | Decides | Ours | Case | Verdict |
| --- | --- | --- | --- | --- |
| `to_json` (76) | the JSON literal shape for non-string values: `ensure_ascii=False`, python separators | `crates/ds4-server/src/render.rs:336` `pyjson_write`, `:329` `pyjson_raw_value`, `crates/ds4-server/src/json.rs:379` `json_minify_raw_value` | `enc-argtypes-chat`, `dec-unicode` | pass |
| `tools_from_openai_format` (84) | the schema string handed to the model, in the client's declared order | `crates/ds4-server/src/parse.rs:2405` `parse_tools_value`, `:2011` `openai_function_schema_from_tool`, `:2221` `tool_schema_orders_add_json_wire` | `enc-tools-chat` | pass |
| `_split_tool_name` (101) | the `namespace::name` split, and the two asserts around it | not implemented on the chat surface: a tool-level `namespace` key is not read there and a `::`-qualified name is taken as given (`crates/ds4-server/src/parse.rs:2405`); the Responses surface keeps a namespace for `type:"namespace"` items (`:2282` `responses_namespace_function_schema`, `:2336` `append_responses_namespace_tool_schemas`) | `tests/parse.rs` `chat_tool_names_pass_through_verbatim`, `responses_namespace_tools_keep_both_spellings` | out of surface on the chat wire the oracle decides: the client's model-facing tool spec is name/description/parameters only (`conversation.rs:861-869`, `From<ToolDefinition> for ToolSpec` `:1039-1045`), and its `namespace` rides the editor-facing ToolCall meta instead (`acp_session.rs:1741` asserts the meta, not the wire), so no chat request can carry the field; the oracle's `namespace::name` qualification belongs to the message dicts it is handed |
| `_tool_name_for_encoding` (116) | the name printed in the invoke tag, namespace-qualified | `crates/ds4-server/src/render.rs:576` `append_dsml_tool_calls_text` | `enc-argtypes-chat` (bare name) | pass for the bare name; the qualified form is out of surface with the row above |
| `tool_calls_from_openai_format` (124) | a replayed assistant's `tool_calls` array into the internal call shape | `crates/ds4-server/src/parse.rs:1079` `parse_tool_calls_value`, `:1023` `add_tool_call_id` | `enc-argtypes-chat`, `enc-args-double` | pass |
| `decode_dsml_to_arguments` (156) | the arguments JSON string: `string="true"` wraps the body as a JSON string, `string="false"` takes the body as the value | `crates/ds4-server/src/tools.rs:376` `parse_dsml_generated`, `:1262` `json_value_is_complete`, `crates/ds4-server/src/json.rs:379` | `dec-one-call`, `dec-complex-args` | pass on names and values; our bytes are minified where the oracle keeps the body verbatim (matrix O-04) |
| `merge_tool_messages` (184) | a `tool` role becomes a `tool_result` block inside a user message, merging into an adjacent merged user | `crates/ds4-server/src/parse.rs:1330` `parse_messages`, `:1411` `append_tool_result_text`; `crates/ds4-server/src/render.rs:1484` | `enc-argtypes-chat` | pass |
| `sort_tool_results_by_call_order` (233) | tool_result blocks inside one user message are ordered by the preceding assistant's call order | `crates/ds4-server/src/render.rs:1442` `tool_run_in_call_order` with `:1421` `preceding_call_order` | `enc-toolresults-order` | pass (closed 2026-10-18) |
| `parse_tagged_text` (273) | the `<image>path</image>` text form expands to image blocks, and a malformed tag raises | not implemented, by contract: pixels arrive base64-only (AGENTS.md), so the tag is never markup | `tests/parse.rs` `the_image_path_tag_form_is_text_and_not_markup` | out of surface, measured 2026-10-20: no image is registered, the content keeps the tag, and the rendered prompt carries it verbatim |
| `_is_image_block` (300) | which content blocks count as images (`image`, `image_url`) | `crates/ds4-server/src/parse.rs:1134` `parse_chat_image_url`, `:456` `add_image_data_uri` | `enc-image-chat` | case added 2026-10-20: the placeholder and its position agree with the oracle, the block separator does not (O-06) |
| `_extract_image` (305) | the url/data/source normalization, and the refusal when none is present | `crates/ds4-server/src/parse.rs:415` `add_image_base64`, `:456` | `enc-image-chat` (the oracle's own record), `tests/parse.rs` `image_refusals_cover_the_oracle_path_and_url_forms` | the oracle's path and URL forms are refused by name; the data-URI form is measured by `enc-image-chat` |
| `_process_image_blocks` (323) | images are replaced by `<|deepseek_image|>` in place, nested tool-result images included, and the records keep prompt order | `crates/ds4-server/src/render.rs:1388` `append_dsml_user_content`, `crates/ds4-server/src/parse.rs:638` `write_tool_image_placeholders` | `enc-image-chat`; `tests/parse.rs` `openai_tool_message_carries_the_image_placeholder`; `tests/render.rs` `dsml_v41_places_tool_result_images_inside_the_envelope` | placeholder and order agree; the separator does not (O-06) |
| `_validate_no_image_sp_tokens` (355) | a user-supplied image placeholder in `content` or `reasoning_content` is refused | `crates/ds4-server/src/parse.rs:567` `reject_stray_image_in_content`, `:578` `reject_stray_image_in_reasoning`, called from every place the client's own text is read (message content, text blocks, a tool result's text, `reasoning_content`, the Responses text blocks) | `stray_image_token.rs` (9) and the served probes `…/probe-placeholder-04a0ab1f-20261019` | CLOSED at R7 (04a0ab1f): the oracle's two sentences on the wire; the engine does not implement the rule (`core_v41_vision.c:189-193`, `server_parse_tools.c:290`), so the port mirrors the oracle, CTR 8.9 |
| `process_image_messages` (370) | the per-message image pass, and `content` rebuilt from text blocks with `\n\n` | `crates/ds4-server/src/parse.rs:1167` `parse_openai_message_content`, `:587` `append_text_part` | `enc-blocks-chat`, `enc-image-chat` | O-06 (measured 2026-10-20): the pieces and their order agree, the rebuild's `\n\n` does not |
| `_read_until_stop` (399) | the earliest-of-stops scan the whole parser is built on | `crates/ds4-server/src/tools.rs:169` `split_reasoning_content` | every `dec-*` case | pass |
| `find_last_user_index` (562) | the last user-like index; a mid-conversation system message counts as one; a tool-result-only user message does not start a turn | `crates/ds4-server/src/render.rs:1545` (the loop) with `:263` `role_is_user_like`, `:1050` (the drop rule's copy) | `enc-plain-chat`, `enc-midsystem-chat`, `enc-toolresult-only` | pass, both halves: mid-system closed 2026-10-18, the tool-result-only tail added 2026-10-19 |
| `render_reasoning_effort` (456) | the effort header: thinking mode, index 0 only, `low/high/max` mapped to 50/75/100, an integer in [1,100] taken as itself, `None` to high | `crates/ds4-server/src/render.rs:98` `head_effort_prefix` / `:105` `v41_effort_prefix` with `crates/ds4-server/src/route/mod.rs:383` `RequestedEffort` | `enc-think-low`, `enc-think-max`, `enc-think-budget` | pass (closed 2026-10-18) |
| `render_tools` (509) | the tools preamble verbatim, with the schema list appended | `crates/ds4-server/src/render.rs:453` `append_dsml_tools_prompt_text` | `enc-tools-chat` | pass |
| `encode_arguments_to_dsml` (524) | one parameter element per argument key, in the call's key order, `string="true"` for a string child and its raw form otherwise; a non-dict `arguments` falls back to a single `arguments` key, a JSON string is decoded twice | `crates/ds4-server/src/render.rs:390` `append_dsml_arg`, `:416` `append_dsml_arguments_from_json`, and the retry at `:629` with `crates/ds4-server/src/json.rs:476` `json_string_contents` | `enc-argtypes-chat`, `enc-args-double`, `enc-args-nondict`, `enc-args-plain` | pass on all four, measured 2026-10-20; the stringified-arguments pass was added to the render that day and the C engine has no such pass (`ds4_server.c:3443-3463`), which `enc-args-double` pins |
| `render_message` (585) | one message's bytes, the role branches, the transition tokens, and the assistant header rule | `crates/ds4-server/src/render.rs:1484` `render_dsml_chat_choice_ex` | 19 encode cases | pass on every case measured; O-01 and O-02/O-03 closed 2026-10-18, the consecutive-assistant half of the header rule was found open and closed 2026-10-19 (`enc-think-two-assistants`, below) |
| `_drop_thinking_messages` (749) | before the last user, an assistant's `reasoning_content` is dropped, the message kept | `crates/ds4-server/src/render.rs:1634` `keep_reasoning` (the rule inline in the assistant branch rather than as a message pass) | `enc-think-drop-thinking`, `enc-drop-thinking`, `enc-think-tail-reasoning` | pass (closed 2026-10-19): the drop fires only in thinking mode with no tools anywhere, and the chat-mode case pins that the reasoning cannot leak |
| `_encode_messages_text` (770) | BOS, the loop over messages, and the drop rule forced false when any message carries tools | `crates/ds4-server/src/render.rs:1484` (the entry) with its message loop at `:1543` | all encode cases | pass |
| `encode_messages` (810) | the public entry: merge, sort, image pass, then the text render | `crates/ds4-server/src/render.rs:1484` behind the chat route | all encode cases | pass on the cases measured |
| `load_cases` (847) | the harness entry: a case-level `tools` key moves into `messages[0]`, a bare message list is wrapped | `tests/ds41_ref/ref_drive.py:68` | every encode case | harness |
| `encode_case` (872) | the harness entry: encode one case and return its images, case `thinking_mode` winning over the command line | `tests/ds41_ref/ref_drive.py:70` | every encode case; `:83` for the media driver | harness |

## 2. Decode side — completion to assistant message

| Oracle | Decides | Ours | Case | Verdict |
| --- | --- | --- | --- | --- |
| `parse_tool_calls` (890) | the invoke/parameter grammar: `>\n` after every open tag, one `name` per invoke, the type attribute, duplicate parameters refused | `crates/ds4-server/src/tools.rs:376` `parse_dsml_generated` | `dec-one-call`, `dec-two-calls`, `dec-complex-args`, `dec-unicode`, `dec-marker-in-value` | pass |
| `parse_message_from_completion_text` (946) | the thinking split at `</think>`, content up to EOS or the block start, no content after the block, no special token left in content or reasoning | `crates/ds4-server/src/tools.rs:376`, `:169` `split_reasoning_content` | every `dec-*` case, incl. `dec-thinking` | pass |
| `tool_calls_to_openai_format` (139) | the wire shape: `type: "function"`, `function.name`, `function.arguments`, `namespace` when present | `crates/ds4-server/src/stream.rs:173` `append_tool_calls_json` | every `dec-*` case (the fixture is the oracle's parse) | pass on names and values |

## 3. Constants and templates

Every literal the two sides must agree on, pinned against the oracle's own
source by `crates/ds4-server/tests/ref_constants.rs` (added 2026-10-20): the
test extracts the value the oracle assigns and compares it with ours, so a
row below is measured even when no case happens to carry the literal.  Where
a row says "other families", the constant sits beside ours in the same table
but belongs to a model family outside this line.

| Oracle | Ours | Verdict |
| --- | --- | --- |
| `bos_token` (29) | `crates/ds4-server/src/render.rs:118` `DSML_BOS` | pass |
| `eos_token` (30) | `:121` `DSML_EOS` | pass |
| `thinking_start_token` (31) | `:126` `DSML_THINK_START` | pass |
| `thinking_end_token` (32) | `:127` `DSML_THINK_END` | pass |
| `dsml_token` (33) `|DSML|` | folded into the tags below | pass |
| `USER_SP_TOKEN` (35) | `:119` `DSML_USER` | pass |
| `ASSISTANT_SP_TOKEN` (36) | `:120` `DSML_ASSISTANT` | pass |
| `SYSTEM_SP_TOKEN` (426) | `:78` `DSML_SYSTEM_TOKEN` | pass |
| `LATEST_REMINDER_SP_TOKEN` (37) | not located | out of surface: the role is not on the OpenAI wire |
| `IMAGE_PLACEHOLDER` (39) | `:132` `DSML_IMAGE` | pass (pinned by the constants leg and carried by `enc-image-chat`); the refusal beside it is measured by `stray_image_token.rs` |
| `IMAGE_TAG_PATTERN` (40) | not located | out of surface with the `parse_tagged_text` row above |
| `DS_TASK_SP_TOKENS` / `VALID_TASKS` (43, 51) | not located | out of surface: internal classification tasks, not on the OpenAI wire |
| `assistant_msg_template` / `wo_eos` (60, 61) | `crates/ds4-server/src/render.rs:1655` (EOS always written) | the template body is pinned by the constants leg; out of surface for `wo_eos`: no OpenAI request field reaches it (`wo_eos` appears nowhere under `crates/`), while the oracle reads it from the message dict for its own continuation flow (`encoding.py:607`, `:697-703`) |
| `response_format_template` (64) | `crates/ds4-server/src/format.rs:19` `parse_output_format_value`, called from `crates/ds4-server/src/parse.rs:3345`, `:3515`, `:3678`; no render-side counterpart | measured refusal, kept by decision: nothing is served that is not supported (see section 5) |
| `tool_output_template` (68) | `crates/ds4-server/src/render.rs:1368` `append_tool_result_text`, written at `:1619`/`:1621` | pass via `enc-argtypes-chat` |
| `tool_calls_block_name` (428) `" calls"` | `crates/ds4-server/src/tools.rs:44` `DSML_TOOL_CALLS_START_SPACED` | pass |
| `tool_call_tag_name` (429) `" invoke"` | `:46` `DSML_INVOKE_START_SPACED`, `:47` end | pass |
| `tool_parameter_tag_name` (430) `" parameter"` | `:48` `DSML_PARAM_START_SPACED`, `:49` end | pass |
| `tool_call_template` / `tool_calls_template` (432, 435) | `crates/ds4-server/src/render.rs:576`-`:652` | pass |
| `REASONING_EFFORT_TEMPLATE` (443) | the line shape | `crates/ds4-server/src/render.rs:44` `V41_EFFORT_TEMPLATE` with the 75/100 constants at `:36`/`:38` | `enc-think-low`, `enc-think-max`, `enc-think-budget` | pass |
| `REASONING_EFFORT_MAPPINGS` / `DEFAULT_REASONING_EFFORT` (448, 453) | low 50, high 75, max 100, `None` to high | `crates/ds4-server/src/route/mod.rs:368` `mode_budget` / `:395` `RequestedEffort::head_budget` | `enc-think-low`, `enc-think-budget` | pass (closed 2026-10-18) |

## 4. Ours with no oracle counterpart

Functions of this repo's DSML line that the oracle does not define.  They are
kept because a served turn needs them, not because the oracle asks for them.

| Ours | Why it exists | Covered by |
| --- | --- | --- |
| `crates/ds4-server/src/tools.rs:2157` `find_tool_start` (with `crates/ds4-server/src/dsml.rs:389` `dsml_find_tool_start`) | the streaming tracker: the artifact's root spelling (quoted, unquoted, short) is not the oracle's canonical one, so the scan is tolerant where the oracle's grammar refuses | `tests/dsml.rs` `syntax_greedy_spaced_dsml`; `dsml.rs` `override_tests::auto_tool_start_forces_function_prefix`, `::required_prefix_finishes_after_tool_start` |
| `crates/ds4-server/src/dsml.rs:550` `dsml_decode_state_for_text` | the incremental decode state machine that decides when markup is withheld from the stream | `tests/dsml.rs` `syntax_greedy_spaced_dsml`; `generate.rs` `disk_sync_tests::continued_decode_gate_stops_after_tool_syntax_begins` |
| `crates/ds4-server/src/tools.rs` `DSML_*_SHORT`, `DSML_*` (25-36) | the two older root spellings the artifact still emits; the oracle knows only the spaced one | `tests/dsml.rs` `syntax_greedy_spaced_dsml` plus the `dec-*` cases through `ref_decode` |
| `crates/ds4-server/src/parse.rs:2282` `responses_namespace_function_schema`, `:2336` `append_responses_namespace_tool_schemas` | the Responses `type:"namespace"` item: the prompt advertises `namespace + function` and the order keeps both spellings so the answer can be emitted under the client's own name (`crates/ds4-server/src/stream.rs:234` `responses_tool_wire_name`, `:287` the `namespace` field) | `tests/parse.rs` `responses_namespace_tools_keep_both_spellings` |
| `crates/ds4-server/src/retry.rs:144` `try_repair_dsml` | truncated-call repair; the oracle has no repair path (matrix G8, P3) | `tests/retry.rs` `dsml_repair_matches_the_reference_balance_contract`, `repair_and_decide_match_c` |
| `crates/ds4-server/src/render.rs:1681` `responses_visible_assistant_suffix` | the visible assistant tail a Responses client can replay (ds4_server.c:12821); the store that consumes it (`responses_live_remember` :14559) is the reserved checkpoint unit | `tests/render.rs` `responses_visible_suffix_matches_client_replay` |
| `crates/ds4-server/src/trace.rs` | C `--trace FILE` (ds4_help.c:323): one section per request with the prompt, its token ids and the parsed message (unit 3.2, TP-12/TP-15) | `trace.rs` `tests::a_section_carries_the_prompt_tokens_and_parsed_message` |
| `crates/ds4-server/src/retry.rs:260` `find_any_tool_start`, `:277` `find_last_structural` | the repair path's style choice and think scope (ds4_server.c:5842, :5890), ported with G8 | `tests/retry.rs` `repair_and_decide_match_c` |
| `crates/ds4-server/src/render.rs:133`-`:179`, other-family markers | Motif, EXAONE, Solar, Qwen, GLM, K2 tag sets: other families, outside this line | `tests/render.rs` `glm53_chat_and_image_protocol_match_official_template`, `ling31_uses_bailing_syntax`; `tests/parse.rs` `qwen_image_inputs_normalize_across_all_three_surfaces` |
| `crates/ds4-server/src/render.rs:202` `syntax_for_model_id` | family dispatch; the oracle covers V4.1 only | `tests/render.rs` `syntax_for_model_id_matches_c` |

## 5. The open rows

Measured on 2026-10-20, in order of what decides them.  Every row above now
carries a verdict; these are the ones that needed a judgement rather than a
fixture.

1. O-06, the block separator (rows `process_image_messages`,
   `_process_image_blocks`, `_is_image_block`, `process_image_messages`): the
   oracle joins the pieces a client sent as separate content blocks with a
   blank line -- `_process_image_blocks` turns an image into a
   `<|deepseek_image|>` text block and the user branch writes
   `"\n\n".join(parts)` (encoding.py:323-353, :631-656, and the `content`
   rebuild at :386-393) -- while this port concatenates them: at parse time for
   text pieces (`append_text_part`, parse.rs:587) and at render time for the
   placeholder (`append_dsml_user_content`, render.rs:1388).  The C lineage
   concatenates too (ds4_server.c:5865), so the port inherited it.  Measured
   the same day on `enc-image-chat` and `enc-blocks-chat`: the two prompts
   carry the same pieces in the same order and differ by that one separator,
   which is exactly what those two cases pin (`check_block_join`).  A third
   place shares the rule and has no case yet: a tool-result message's mixed
   blocks (`write_tool_image_placeholders`, parse.rs:638), asserted today as
   `"shot:<placeholder>done"` by `tests/parse.rs`
   `openai_tool_message_carries_the_image_placeholder`.  The fix is one join,
   gated to the V4.1 head, in the render's parts loop plus the parse's text
   pieces; it is the operator's call because it moves every image-bearing
   prompt and every multi-block message on that head.
2. The image surface's oracle leg (rows `parse_tagged_text`,
   `_is_image_block`, `_extract_image`, `_process_image_blocks`,
   `_validate_no_image_sp_tokens`, `process_image_messages`): `ref_drive.py`
   refused image cases by construction (`assert not images`, kept for the
   text-only legs), so the leg was rebuilt on 2026-10-20 as `encode-media`
   (`ref_drive.py:75`), which prints the prompt and reports the oracle's own
   image records on stderr.  `_validate_no_image_sp_tokens` is CLOSED at R7;
   the other five now have the oracle's bytes, with O-06 the only difference.
3. The namespace surface (rows `_split_tool_name`, `_tool_name_for_encoding`):
   out of surface.  The client's model-facing tool spec is
   name/description/parameters only (`conversation.rs:861-869`, the conversion
   at `:1039-1045`) and its `namespace` rides the editor-facing ToolCall meta
   (`acp_session.rs:1741`), so no chat request can carry the field and a
   `::`-qualified name is never sent.  Both halves are pinned by
   `tests/parse.rs` (`chat_tool_names_pass_through_verbatim`,
   `responses_namespace_tools_keep_both_spellings`).
4. `wo_eos` (`assistant_msg_template` / `wo_eos`): out of surface.  `wo_eos`
   appears nowhere under `crates/`; the oracle reads it from the message dict
   for its own continuation flow (`encoding.py:607`, `:697-703`).
5. `IMAGE_TAG_PATTERN`, the `<image>path</image>` text form, and
   `LATEST_REMINDER_SP_TOKEN` / `DS_TASK_SP_TOKENS` / `VALID_TASKS`: out of
   surface.  The carriage is base64-only by design (AGENTS.md) and the rest are
   internal classification roles, not on the OpenAI wire.  The tag form is
   measured rather than assumed (`tests/parse.rs`
   `the_image_path_tag_form_is_text_and_not_markup`).
6. `response_format` rendering (row `response_format_template`): the one row
   whose verdict is a decision and not a measurement.  Ours refuses
   `json_object` and `json_schema` with 400 "structured output is unsupported"
   (`format.rs:6-15`, the v0.6.3 refusal of ds4-on-spark#10), measured on the
   served binary today; the oracle renders the schema into the prompt instead
   (`encoding.py:628-629` with the template at `:64`).  The client of record can
   put `response_format: json_schema` on the chat wire, from
   `ConversationRequest.json_schema` (`conversation.rs:4107`), at two production
   sites -- the auto-mode permission classifier (`sampler_turn.rs:862`) and the
   goal evaluator (`goal_evaluator.rs:172`) -- while its main turns hardcode
   None (`request_builder.rs:148`, sampler `client.rs:4071`), and no capability
   gate guards those two sites.  The operator decided 2026-10-20 that the
   refusal stands: the field carries `strict: true`, i.e. a guarantee that the
   served text conforms to the schema, and only a decode-time constraint can
   give that guarantee.  A prompt-side instruction would be an invented
   approximation of a guarantee, so nothing is served for this field, and the
   client's own error branch records the side query as failed
   (`session_summary.rs:131-137` for the neighbouring title query).  Serving it
   for real means a JSON-schema-constrained decoder, a unit of its own.
7. O-04 arguments bytes: ours minify, the oracle keeps the parameter body
   verbatim.  Values agree; the strings differ.  Recorded, not a defect against
   the wire, since the client echoes our string.

Closed since the map was written: O-01 (the effort budget, both halves), O-02
(a mid-conversation system message renders in place), O-03 (tool results
ordered by call order), the repair rows of G8/G9, the image-placeholder
refusal (R7), the drop-thinking rule together with its chat-mode counterpart,
the stringified-arguments fallback (2026-10-20, `enc-args-double`), and the
`find_last_user_index` tool-result-only half (`enc-toolresult-only`).

One divergence was found by the 2026-10-19 pass and closed in code.  Two
assistant messages in a row share one `<Assistant>` header, so the second has
no header to open its thinking, and the oracle still writes that message's
reasoning and its closer as part of the body (`encoding.py:678-712`).
Measured before the fix: ours rendered 275 bytes against the oracle's 304,
dropping `SECOND-THOUGHT-MARKER` whole (`enc-think-two-assistants`).  The
assistant branch now writes the thinking body when it has no header, gated to
the V4.1 head so the port's own head keeps its bytes.

One divergence was found by the 2026-10-20 pass and closed in code.  A
replayed call whose `arguments` is itself a JSON string still renders that
object's parameters, because the oracle decodes the field twice before it
gives up (`encoding.py:528-537`).  Measured before the fix: ours wrote one
`arguments` parameter carrying the quoted text (1534 bytes against the
oracle's 1511, `enc-args-double`).  `append_dsml_tool_calls_text` now retries
the parse on the unwrapped string (`json_string_contents`, json.rs:476), and
the C engine's lack of that pass is pinned by the same case.

## 6. Reproducing

```bash
# the oracle's own bytes for a case, and its parse of a completion
python3 tests/ds41_ref/ref_drive.py encode       tests/ds41_ref/cases/enc-plain-chat.json chat
python3 tests/ds41_ref/ref_drive.py encode-media tests/ds41_ref/cases/enc-image-chat.json chat
python3 tests/ds41_ref/ref_drive.py parse        tests/ds41_ref/decode/dec-one-call.txt chat

# the three reference legs against the pinned fixtures
cargo test -p ds4-server --test ref_encoding
cargo test -p ds4-server --test ref_decode
cargo test -p ds4-server --test ref_constants
```

Regenerate the fixtures only when the oracle or a case changes:
`bash tests/ds41_ref/regen_fixtures.sh`.