6The fail-closed reader for the shipped, read-only defaults file (CONFIG-01).
10OC Chat's configuration is two files: ``oc_chat/oc_chat.defaults.toml`` — shipped
11as package data, hard-denied for writes BY NAME in :mod:`oc_chat.tools._sandbox`
12(``_PROTECTED_WRITE_NAMES``), holding every default and every ceiling — and the
13writable workspace settings file ``.oc_chat/oc_chat-settings.json`` (human-confirm
14write tier), which may LOWER a ceiling and set a default but can never RAISE a
15ceiling. The security property of a bound is WHERE the file lives and WHO may
16write it, not that the value sits in a ``.py``: before plan 238 the ceilings were
17uppercase module constants inside the importable tree, which a dogfooding agent
18under the ``permissive`` profile can already write.
20This module reads that file once at import, validates it against a key registry
21— :data:`KEY_REGISTRY`, the one list of keys permitted to live in code — and
22exposes the three accessors every call site uses. There is deliberately NO
23permissive fallback anywhere in this module: "cannot read the defaults" is a
24startup error, never a default.
28- :data:`KEY_REGISTRY` — every key, its expected value type, and its class.
29- :func:`load_table` — parse + validate one defaults file; raise ``SystemExit``
30 naming the file and the offending key on any fault.
31- :func:`shipped` — the file's value, with no settings and no env consulted.
32- :func:`default` — the shipped value, overridden by the workspace settings key
33 the table declares (``setting``); absent that declaration the settings file
34 cannot reach the value at all.
35- :func:`authority` — the shipped value of an ``authority``-class key, REPLACED
36 (never clamped, never merged) by the out-of-band variable the table names.
37 The settings file cannot reach it in any spelling: an ``authority`` table may
38 not declare a ``setting`` at all, and the class has no settings-consulting
39 code path. Plan 253's trusted package index (SUPPLY-02 / M8 F78) is the first
41- :func:`ceiling` — the out-of-band environment variable named by the table
42 (when set to a valid positive int) replaces the shipped value as the ceiling;
43 an absent settings request preserves that value, while a present request may
45 One implementation of F33/§5.4 for every ceiling in the system.
46- :func:`env_var` / :func:`setting_key` / :func:`doc` / :func:`keys` — the
47 remaining table metadata, for diagnostics and tests.
51- Import fails closed. A missing, unreadable, malformed, incomplete, over-full
52 or mistyped defaults file raises ``SystemExit`` during import; nothing starts
54- A ``ceiling`` table MUST carry ``env``; the empty string declares "no
55 out-of-band raise path exists for this ceiling". A non-empty name MUST be
56 enrolled in ``_env_guard._AUTHORITY_EXACT`` (so a workspace ``.env`` cannot
57 set it). A ``default`` table MUST NOT carry ``env``.
58- An ``authority`` table MUST carry a NON-EMPTY enrolled ``env`` (out of band is
59 its only replacement path) and MUST NOT carry ``setting``. Its value — and any
60 value the out-of-band variable supplies — is validated as a trusted URL, and a
61 fault refuses at load rather than degrading to the shipped one: an unusable
62 trusted index is not a reason to fall back to a different one.
63- :func:`ceiling` never returns a value above ``min`` of the shipped value and
64 the out-of-band ceiling; a settings read that is unavailable, non-int or
65 non-positive degrades to the bounded shipped value, never to "unbounded".
66- The settings file is consulted only for a key whose table declares ``setting``.
70- oc_diagnostics (structured debug logging via _dbg)
71- oc_chat._env_guard (the out-of-band authority enrolment set)
72- oc_chat.core.settings (lazy; workspace settings values for defaults and ceiling requests)
78 L2 — the file was loaded; a ceiling was raised out-of-band
79 L3 — per-key resolution detail
82from __future__
import annotations
86from dataclasses
import dataclass
87from pathlib
import Path
88from typing
import Any, NoReturn
89from urllib.parse
import urlsplit
91from oc_diagnostics
import _dbg
95_dbg(
"OC_CHAT.CORE",
"module",
"loaded", 4)
101DEFAULTS_FILENAME =
"oc_chat.defaults.toml"
104DEFAULTS_PATH = Path(__file__).resolve().parent.parent / DEFAULTS_FILENAME
110CLASS_CEILING =
"ceiling"
111CLASS_DEFAULT =
"default"
112CLASS_AUTHORITY =
"authority"
115_KNOWN_FIELDS = frozenset({
"value",
"class",
"doc",
"env",
"setting"})
121 "int":
lambda v: isinstance(v, int)
and not isinstance(v, bool),
122 "float":
lambda v: isinstance(v, float),
123 "bool":
lambda v: isinstance(v, bool),
124 "str":
lambda v: isinstance(v, str),
131 "floatlist":
lambda v: (
132 isinstance(v, list)
and bool(v)
133 and all(isinstance(x, float)
and x > 0
for x
in v)
143KEY_REGISTRY: tuple[tuple[str, str, str], ...] = (
145 (
"tool_calls_per_turn",
"int", CLASS_CEILING),
146 (
"stall_repeat_calls",
"int", CLASS_CEILING),
147 (
"stall_error_streak",
"int", CLASS_CEILING),
148 (
"stall_no_progress_iterations",
"int", CLASS_CEILING),
149 (
"parallel_workers",
"int", CLASS_CEILING),
150 (
"timeout_seconds",
"int", CLASS_CEILING),
151 (
"byte_budget",
"int", CLASS_CEILING),
152 (
"search_results",
"int", CLASS_CEILING),
153 (
"dir_depth",
"int", CLASS_CEILING),
155 (
"session_cost_thresholds_usd",
"floatlist", CLASS_DEFAULT),
156 (
"session_cost_hard_cap_usd",
"int", CLASS_CEILING),
157 (
"checkpoint_top_tools",
"int", CLASS_DEFAULT),
158 (
"session_alert_notify_timeout_s",
"int", CLASS_DEFAULT),
159 (
"settings_session_cost_hard_cap_usd",
"int", CLASS_DEFAULT),
161 (
"output_tokens",
"int", CLASS_CEILING),
162 (
"undeclared_output_tokens",
"int", CLASS_DEFAULT),
164 (
"model_max_tokens",
"int", CLASS_DEFAULT),
165 (
"context_window_size",
"int", CLASS_DEFAULT),
166 (
"context_compress_threshold",
"float", CLASS_DEFAULT),
167 (
"context_keep_recent",
"int", CLASS_DEFAULT),
168 (
"context_keep_recent_turns",
"int", CLASS_DEFAULT),
170 (
"max_react_iterations",
"int", CLASS_DEFAULT),
171 (
"reasoning_effort",
"str", CLASS_DEFAULT),
173 (
"settings_verbose",
"bool", CLASS_DEFAULT),
174 (
"settings_max_output_tokens",
"int", CLASS_DEFAULT),
175 (
"mode_standard_include_persona",
"bool", CLASS_DEFAULT),
176 (
"mode_standard_include_tools",
"bool", CLASS_DEFAULT),
177 (
"mode_standard_include_env",
"bool", CLASS_DEFAULT),
178 (
"mode_standard_include_project_tree",
"bool", CLASS_DEFAULT),
179 (
"mode_option_c_include_persona",
"bool", CLASS_DEFAULT),
180 (
"mode_option_c_include_tools",
"bool", CLASS_DEFAULT),
181 (
"mode_option_c_include_env",
"bool", CLASS_DEFAULT),
182 (
"mode_option_c_include_project_tree",
"bool", CLASS_DEFAULT),
183 (
"project_tree_max_depth",
"int", CLASS_DEFAULT),
184 (
"project_tree_honor_gitignore",
"bool", CLASS_DEFAULT),
186 (
"verification_enabled",
"bool", CLASS_DEFAULT),
187 (
"verification_lint",
"bool", CLASS_DEFAULT),
188 (
"verification_typecheck",
"bool", CLASS_DEFAULT),
189 (
"verification_tests",
"bool", CLASS_DEFAULT),
190 (
"verification_timeout_s",
"int", CLASS_DEFAULT),
191 (
"verification_max_files",
"int", CLASS_DEFAULT),
192 (
"verification_max_findings",
"int", CLASS_DEFAULT),
193 (
"verification_jobs",
"int", CLASS_DEFAULT),
194 (
"verification_max_runs_per_turn",
"int", CLASS_DEFAULT),
195 (
"verification_baseline",
"bool", CLASS_DEFAULT),
196 (
"verification_baseline_timeout_s",
"int", CLASS_DEFAULT),
198 (
"bucket_share_planning",
"float", CLASS_DEFAULT),
199 (
"bucket_share_thinking",
"float", CLASS_DEFAULT),
200 (
"bucket_share_thinking_write",
"float", CLASS_DEFAULT),
201 (
"bucket_share_simple_thinking",
"float", CLASS_DEFAULT),
202 (
"bucket_share_simple",
"float", CLASS_DEFAULT),
203 (
"min_bucket_output_tokens",
"int", CLASS_DEFAULT),
205 (
"tool_result_cap",
"int", CLASS_DEFAULT),
206 (
"big_context_tool_result_cap",
"int", CLASS_DEFAULT),
208 (
"lane_picker_name_width",
"int", CLASS_DEFAULT),
209 (
"lane_picker_label_width",
"int", CLASS_DEFAULT),
211 (
"ui_reasoning_tail",
"int", CLASS_DEFAULT),
213 (
"pip_index_url",
"str", CLASS_AUTHORITY),
218_POSITIVE_CEILING_KEYS = frozenset({
219 "stall_repeat_calls",
220 "stall_error_streak",
221 "stall_no_progress_iterations",
225@dataclass(frozen=True)
227 """One validated table from the shipped defaults file."""
237def _refuse(path: Path, message: str) -> NoReturn:
238 """Refuse to start: raise ``SystemExit`` naming *path* and the fault.
240 SECURITY_ERROR (L1). No caller may recover from this — a defaults file that
241 does not validate means the ceilings are unknown, and an unknown ceiling is
242 not a default (CONFIG-01, F33/§5.4). The text is ASCII-only: it is printed
243 to a console whose encoding may be cp1252."""
245 text = f
"oc_chat: refusing to start - {path}: {message}"
246 _dbg(
"OC_CHAT.CORE", func, f
"SECURITY_ERROR: {message}", 1)
247 raise SystemExit(text)
250def _refuse_env(env_name: str, key: str, message: str) -> NoReturn:
251 """Refuse to start: the out-of-band value for *key* does not validate.
253 SECURITY_ERROR (L1). The same fail-closed rule the shipped file gets, applied
254 to the one channel allowed to replace an authority value: an operator
255 variable that does not validate leaves the trusted destination UNKNOWN, and
256 an unknown trusted destination is not a reason to silently use a different
257 one (M8 F78). ASCII-only text: it prints to a cp1252 console."""
259 text = f
"oc_chat: refusing to start - {env_name} (authority value for {key!r}): {message}"
260 _dbg(
"OC_CHAT.CORE", func, f
"SECURITY_ERROR: {message}", 1)
261 raise SystemExit(text)
265 """Why *value* is not a usable authority URL, or ``""`` when it is.
267 An authority URL is the operator's declared destination for a child process
268 that reaches the network (F78), so it is checked as strictly as a ceiling's
269 type is: a non-empty ``str`` of printable ASCII (no embedded newline can
270 smuggle a second argument), the ``https`` scheme alone (no ``http``
271 downgrade and no ``file``/``ftp`` substitution), a named host, no
272 ``user:pass@`` userinfo (a credential does not belong in a config value or
273 in an argv the operator reads at a confirm prompt) and no query string."""
274 if not isinstance(value, str)
or not value:
275 return "an authority value must be a non-empty string"
276 if any(ch <
"!" or ch >
"~" for ch
in value):
277 return "an authority URL must be printable ASCII with no whitespace"
279 parts = urlsplit(value)
280 scheme, host, user, password, query = (
281 parts.scheme, parts.hostname, parts.username, parts.password, parts.query)
283 except ValueError
as exc:
284 return f
"an authority URL is malformed ({type(exc).__name__}: {exc})"
285 if scheme !=
"https":
286 return f
"an authority URL must use the https scheme, found {scheme!r}"
288 return "an authority URL must name a host"
289 if user
is not None or password
is not None:
290 return "an authority URL must carry no userinfo (credentials do not belong in it)"
292 return "an authority URL must carry no query string"
296def _validate_entry(path: Path, key: str, type_name: str, want_class: str, raw: Any) -> Entry:
297 """Validate one table against its registry row and return its :class:`Entry`."""
298 if not isinstance(raw, dict):
299 _refuse(path, f
"key {key!r}: expected a table, found {type(raw).__name__}")
300 unknown = sorted(set(raw) - _KNOWN_FIELDS)
302 _refuse(path, f
"key {key!r}: unknown field(s) {unknown}")
303 for field_name
in (
"value",
"class",
"doc"):
304 if field_name
not in raw:
305 _refuse(path, f
"key {key!r}: missing required field {field_name!r}")
306 if raw[
"class"] != want_class:
307 _refuse(path, f
"key {key!r}: class is {raw['class']!r}, the registry pins {want_class!r}")
308 if not _TYPE_CHECKS[type_name](raw[
"value"]):
309 _refuse(path, f
"key {key!r}: value {raw['value']!r} is not of the registered type {type_name!r}")
310 if key
in _POSITIVE_CEILING_KEYS
and raw[
"value"] <= 0:
311 _refuse(path, f
"key {key!r}: value must be a positive integer")
312 if want_class == CLASS_AUTHORITY:
315 _refuse(path, f
"key {key!r}: {fault}")
316 if not isinstance(raw[
"doc"], str)
or not raw[
"doc"].strip():
317 _refuse(path, f
"key {key!r}: doc must be a non-empty string")
320 if want_class
in (CLASS_CEILING, CLASS_AUTHORITY):
322 if want_class == CLASS_CEILING:
323 _refuse(path, f
"key {key!r}: a ceiling must declare env (use \"\" for no out-of-band raise path)")
324 _refuse(path, f
"key {key!r}: an authority value must declare env")
325 if not isinstance(env, str):
326 _refuse(path, f
"key {key!r}: env must be a string")
327 if want_class == CLASS_AUTHORITY
and not env:
328 _refuse(path, f
"key {key!r}: an authority value must declare a NON-EMPTY env "
329 "- out of band is its only replacement path")
330 if env
and env
not in _AUTHORITY_EXACT:
332 _refuse(path, f
"key {key!r}: env {env!r} is not enrolled in _env_guard._AUTHORITY_EXACT")
333 elif env
is not None:
334 _refuse(path, f
"key {key!r}: env is permitted on a ceiling only, not on a default")
336 setting = raw.get(
"setting")
337 if want_class == CLASS_AUTHORITY
and setting
is not None:
338 _refuse(path, f
"key {key!r}: an authority value may not declare a setting "
339 "- the settings file may never set it or lower it")
340 if setting
is not None and (
not isinstance(setting, str)
or not setting.strip()):
341 _refuse(path, f
"key {key!r}: setting must be a non-empty string when present")
346 value_class=want_class,
349 setting=setting
or "",
354 """Read and validate the defaults file at *path*; ``SystemExit`` on any fault.
356 Refuses on a missing file, an unreadable file, malformed TOML, an unknown
357 key, a missing key, a wrong value type, a ceiling without ``env``, and an
358 ``env`` that is not enrolled in ``_env_guard._AUTHORITY_EXACT``. There is no
359 fallback: every refusal names the file, and every key-scoped refusal names
363 raw_bytes = path.read_bytes()
364 except FileNotFoundError:
365 _refuse(path,
"the shipped defaults file is missing")
366 except OSError
as exc:
368 _refuse(path, f
"the shipped defaults file is unreadable ({type(exc).__name__}: {exc})")
370 data = tomllib.loads(raw_bytes.decode(
"utf-8"))
371 except (tomllib.TOMLDecodeError, UnicodeDecodeError)
as exc:
372 _refuse(path, f
"malformed TOML ({type(exc).__name__}: {exc})")
374 registered = {key
for key, _type, _cls
in KEY_REGISTRY}
375 for key
in sorted(set(data) - registered):
376 _refuse(path, f
"key {key!r}: unknown key — it is not in defaults.KEY_REGISTRY")
378 table: dict[str, Entry] = {}
379 for key, type_name, want_class
in KEY_REGISTRY:
381 _refuse(path, f
"key {key!r}: missing from the shipped defaults file")
382 table[key] =
_validate_entry(path, key, type_name, want_class, data[key])
384 _dbg(
"OC_CHAT.CORE", func, f
"loaded {len(table)} keys from {path.name}", 2)
389 """Refuse at import when an out-of-band authority value does not validate.
391 The shipped file is checked by :func:`load_table`; this is the same check
392 applied to the ONE channel allowed to replace an authority value. Doing it
393 at import means a malformed operator variable stops the process at startup,
394 where the operator is looking, rather than on the first granted install."""
395 for key, entry
in table.items():
396 if entry.value_class != CLASS_AUTHORITY
or not entry.env:
398 raw = os.environ.get(entry.env)
412 """The validated :class:`Entry` for *key*; ``KeyError`` names an unregistered key."""
416 raise KeyError(f
"{key!r} is not a key in {DEFAULTS_FILENAME}")
from None
420 """Every registered key, in registry order."""
421 return tuple(key
for key, _type, _cls
in KEY_REGISTRY)
425 """The shipped documentation string for *key*."""
430 """The out-of-band env variable that raises *key*'s ceiling, or ``""``."""
435 """The settings-file key permitted to influence *key*, or ``""`` for none."""
436 return _entry(key).setting
440 """The shipped value for *key*: no settings file, no env, no resolution.
442 This is the built-in default a settings-file merge starts from, and the code
443 default every ceiling degrades to."""
448 """The workspace settings value for *setting* as an int, or ``None`` when the
449 settings subsystem is unavailable or the value is unparseable (either way the
450 caller degrades to the bounded shipped value, never to unbounded)."""
451 func =
"_settings_int"
454 return int(getattr(runtime_settings(), setting, fallback))
455 except Exception
as exc:
456 _dbg(
"OC_CHAT.CORE", func, f
"VALIDATION_ERROR: {type(exc).__name__}: {exc}", 3)
461 """The effective value for a ``default``-class *key*.
463 The shipped value, overridden by the workspace settings key the table
464 declares in ``setting``. A key that declares no ``setting`` cannot be reached
465 from the settings file at all, so the shipped value stands."""
468 if entry.value_class == CLASS_AUTHORITY:
469 raise KeyError(f
"{key!r} is an authority value - use defaults.authority(); "
470 "default() would answer with a value the operator's "
471 "out-of-band variable has already replaced")
472 if not entry.setting:
476 found = getattr(runtime_settings(), entry.setting,
None)
477 except Exception
as exc:
478 _dbg(
"OC_CHAT.CORE", func, f
"VALIDATION_ERROR: {type(exc).__name__}: {exc}", 3)
480 return entry.value
if found
is None else found
484 """The effective ceiling for a ``ceiling``-class *key* — the ONE implementation
485 of "settings may LOWER, never RAISE; the operator's out-of-band env raises".
487 The env variable the table names replaces the shipped value as the absolute
488 ceiling when set to a positive int (it is ``_env_guard``-enrolled, so a
489 workspace ``.env`` cannot set it). The settings key is a REQUEST clamped by
490 that ceiling. An unset, non-int or unavailable setting leaves the absolute
491 ceiling in force. A non-positive legacy request degrades to the shipped
492 value (F33/§5.4, F52)."""
495 if entry.value_class == CLASS_AUTHORITY:
496 raise KeyError(f
"{key!r} is an authority value - use defaults.authority(); "
497 "an authority value is replaced out of band, never clamped")
498 shipped_value = int(entry.value)
500 absolute = shipped_value
502 raw = os.environ.get(entry.env)
506 except (TypeError, ValueError):
510 _dbg(
"OC_CHAT.CORE", func, f
"{key}: OOB ceiling {entry.env}={candidate}", 2)
512 if not entry.setting:
518 requested = value
if value > 0
else shipped_value
519 return min(requested, absolute)
523 """The effective value for an ``authority``-class *key* (plan 253, F78).
525 The shipped value, REPLACED outright by the out-of-band variable the table
526 names when that variable is set. There is no settings path and no clamping:
527 an authority value is a posture decision the operator makes out of band or
528 not at all. An out-of-band value that does not validate refuses
529 (``SystemExit``) rather than degrading to the shipped one — degrading would
530 let a planted variable turn the operator's pin back into the default without
534 if entry.value_class != CLASS_AUTHORITY:
535 raise KeyError(f
"{key!r} is a {entry.value_class} value, not an authority value")
536 raw = os.environ.get(entry.env)
if entry.env
else None
538 return str(entry.value)
542 _dbg(
"OC_CHAT.CORE", func, f
"{key}: OOB authority value from {entry.env}", 2)
str _authority_url_fault(Any value)
dict[str, Entry] load_table(Path path)
NoReturn _refuse_env(str env_name, str key, str message)
None _validate_authority_env(dict[str, Entry] table)
Entry _validate_entry(Path path, str key, str type_name, str want_class, Any raw)
"int | None" _settings_int(str setting, "int | None" fallback)
NoReturn _refuse(Path path, str message)