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
//! What a row's `protocol` column says about a yog turn (DESIGN §9.4) — the
//! two reads keyed on brazen's own `ProtocolId`, split off [`super`] at §12's
//! line budget along the seam the module already had: the parent is the table's
//! *projection* (three columns, the credential model, the rendered row), and
//! this is the dialect judgement over one of those columns.
//!
//! **`protocol` is the TOOL capability** (bl-3d22). The column carries brazen's
//! own `ProtocolId` spelling, and `ProtocolId` is a public, closed enum on
//! brazen's library surface — so [`ProviderRow::tools_blocked`] parses the
//! column back into that enum through brazen's own serde rename and answers
//! over a **total match**, which a new upstream dialect fails to compile until
//! its arm is added. That is the whole reason the judgement is here rather than
//! a table of row NAMES: `claude-code` is a name, `claude_code` is a protocol,
//! and only the second is a fact about request shape.
//!
//! It exists because row EXISTENCE never established request-shape
//! compatibility, which §9.4 used to claim it did: `/model worker claude-code
//! <id>` passed the row gate, advanced both config halves, and the next worker
//! start died at brazen's encoder before any network call — *"claude_code
//! carries no tool declarations; use the `anthropic` row for tools"*. Every yog
//! turn declares at least the `clients` tool
//! ([`crate::tool_host::Injection::tools`] returns it unconditionally, and
//! litany splices the injection into every canonical request), so a
//! tool-less dialect can serve no litany ROLE at all.
//!
//! **The same judgement answers the failure that already happened** (bl-5252).
//! Gating the picker never reached a config written BEFORE the gate, or written
//! by hand through the §9.1 editor, which is the operator's own authority: that
//! step still dies at encode, and the §7.3 banner offered it Dismiss and nothing
//! else, because [`crate::config_edit::fault`] keyed on litany's `Config`-kind
//! wrapper and brazen stamps every dialect decline `ErrorKind::ParseInput`. So
//! [`dialect_decline`] reads the dead step's own words into the same match a row
//! is read into — the route, not a second table.
//!
//! **The upstream ask is already filed, and is brazen bl-5053** ("publish
//! per-row capability declines (tools, multi-turn) on the read surface"): brazen
//! projects no capability column — `--list-providers` serves `name`/`protocol`/
//! `auth`/`credential`, and the `Protocol` trait that owns the rejection is
//! crate-private, so the authoritative answer cannot be asked for. That ball was
//! filed off THIS defect seen once before, and its own words name the cost:
//! *"yog's model picker validated provider=claude-code for a tool-bearing worker
//! role (it only checks the row exists in `bz --list-providers`), and every
//! session call then died at encode"*. It was never gated on yog's side, so it
//! recurred. When brazen serves the column, the match below is deleted and the
//! column read in its place — that is the whole migration.
//!
//! **The refusal is per-ROLE, and removes nothing from the catalog.** The VISION
//! §4.9 alignment monitor's check is structurally tool-less
//! ([`crate::monitor::check`]: *"`bz` takes no tool flag, so tool-lessness here
//! is structural rather than a promise"*) and pins a MODEL rather than a provider
//! row, so a tool-less dialect is a legitimate target for it. What cannot be a
//! litany role's row is not thereby useless.
//!
//! **The second read is a CAVEAT, not a refusal** (bl-671d, §9.4). A dialect
//! whose request declares no context size hands that number to the server, and
//! yog cannot see what the server chose — so the honest answer is the fact and
//! the remedy, at the seat where the row is picked, and never a gate. It is the
//! same discipline [`is_unknown_row`](crate::model_pick::grammar::is_unknown_row)
//! applies to a table that did not answer: no surface may refuse on the strength
//! of a question that went unanswered. `ollama_chat` is the dialect
//! ([`ProviderRow::context_caveat`]), and it is the *whole* of what the wire
//! carries: the pin's own encoder maps the output cap to `options.num_predict`
//! and emits no `options.num_ctx` at all — `tests/brazen_ollama_context.rs`
//! drives the linked brazen and asserts that body, so the sentence below is
//! true because a test says so and fails the day brazen changes it. **The
//! upstream ask was brazen bl-f19d and it landed in 0.0.10**: a row's
//! `body_defaults` `extra` folds one namespace deep, so [`CONTEXT_REMEDY`] is
//! one line rather than three. The dialect arm itself is what bl-b6c9 rewrites
//! — since brazen 0.0.13 a ROW can state the window and brazen stamps it on the
//! `Usage` event, so the honest caveat is a row-statement read, not a dialect
//! judgement.
use ProviderRow;
/// The operator's way to give an `ollama_chat` row an explicit context, in the
/// one file that authors a row (§9.1's editor) — the hover beside
/// [`ProviderRow::context_caveat`], because the fact fits a line and the recipe
/// does not.
///
/// **One line since brazen 0.0.10** (upstream bl-f19d), and it was three before.
/// The recipe used to clear the typed cap and restate it inside the object,
/// because `encode` inserted the typed `options` FIRST and folded config
/// passthrough with `or_insert`, dropping a `body_defaults` `options` beside a
/// typed `max_tokens` **whole and silently**. The `extra` fold now goes one
/// namespace deep, so the two keys compose per key and the operator writes the
/// context alone. Measured against the linked brazen either way —
/// `tests/brazen_ollama_context.rs` leg two asserted the drop and now asserts
/// the composition, so this sentence fails the day the fold changes again.
pub const CONTEXT_REMEDY: &str = "give the row an explicit context in this workspace's brazen \
config.toml: `body_defaults = { options = { num_ctx = <your context> } }`. It composes with \
the output cap the request already carries — the two are distinct fields, `num_ctx` sizing \
the input window and `num_predict` capping the output.";
/// Why a dialect can carry no litany role, keyed on the `protocol` **spelling**
/// rather than on a row — the one match, which [`ProviderRow::tools_blocked`]
/// reads a column into and [`dialect_decline`] reads a dead step's own words
/// into. Two callers, one arm per dialect: a second table would be the thing
/// bl-3d22 refused to build.
/// Why the dialect a **failed step's own words** name can serve no role, or
/// `None` when they name none (bl-5252) — the route from a dead step back to
/// [`dialect_blocked`], which [`crate::config_edit::fault`] pairs with the §9.1
/// route.
///
/// **The signal is the dialect naming ITSELF, and that is brazen's own habit.**
/// Every decline the `claude_code` encoder writes leads with its `ProtocolId`
/// spelling — *"`claude_code` carries no tool declarations…"*, *"…cannot express
/// a tool_choice"*, *"…is single-turn"*, *"…accepts only text content in
/// {slot}"* — one family from one `reject` helper, all four stamped
/// `ErrorKind::ParseInput`, so no error KIND separates them from a malformed
/// image block. So the scan is over whole `[a-z0-9_]` tokens, judged by the
/// match above, which makes it narrow in the only way that matters: it is
/// **exact and case-sensitive on brazen's spelling**, so the row NAME
/// `claude-code` — hyphen, the thing an operator's config and every other
/// failure line carry — answers nothing, and a tool-capable dialect that names
/// itself (*"anthropic_messages requires max_tokens"*) answers nothing either.
/// A dialect this build cannot name is an unanswered question, as everywhere
/// else here.
/// A `protocol` spelling parsed back into brazen's own registry key, through
/// brazen's own serde rename — never a second table of spellings beside it.
/// `None` for a spelling this build cannot name, which is a *newer* brazen
/// or a degraded column, and in both cases an unanswered question.