oc_chat
Loading...
Searching...
No Matches
defaults.py
Go to the documentation of this file.
1#!/usr/bin/env python3
2# -*- coding: utf-8 -*-
3# oc_chat/core/defaults.py
4
5"""
6The fail-closed reader for the shipped, read-only defaults file (CONFIG-01).
7
8Purpose
9-------
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.
19
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.
25
26Responsibilities
27----------------
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
40 such value.
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
44 only LOWER it.
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.
48
49Contracts
50---------
51- Import fails closed. A missing, unreadable, malformed, incomplete, over-full
52 or mistyped defaults file raises ``SystemExit`` during import; nothing starts
53 with a guessed value.
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``.
67
68Dependencies
69------------
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)
73
74Diagnostics
75-----------
76Domain: OC_CHAT.CORE
77Levels:
78 L2 — the file was loaded; a ceiling was raised out-of-band
79 L3 — per-key resolution detail
80 L4 — deep tracing
81"""
82from __future__ import annotations
83
84import os
85import tomllib
86from dataclasses import dataclass
87from pathlib import Path
88from typing import Any, NoReturn
89from urllib.parse import urlsplit
90
91from oc_diagnostics import _dbg
92
93from oc_chat._env_guard import _AUTHORITY_EXACT
94
95_dbg("OC_CHAT.CORE", "module", "loaded", 4)
96
97
98#: The shipped file's basename. Distinctive on purpose: it is hard-denied by
99#: NAME everywhere, and a generic ``defaults.toml`` would over-block unrelated
100#: files. Keep this in step with ``_sandbox._PROTECTED_WRITE_NAMES``.
101DEFAULTS_FILENAME = "oc_chat.defaults.toml"
102
103#: The shipped file's location: the package directory, one level above ``core/``.
104DEFAULTS_PATH = Path(__file__).resolve().parent.parent / DEFAULTS_FILENAME
105
106#: Value classes. A ceiling may only be LOWERED by the settings file; a default
107#: may be replaced by it (when the table declares a ``setting``); an authority
108#: value is out of the settings file's reach entirely — only the operator's
109#: out-of-band variable replaces it (plan 253, SUPPLY-02 / M8 F78).
110CLASS_CEILING = "ceiling"
111CLASS_DEFAULT = "default"
112CLASS_AUTHORITY = "authority"
113
114#: Fields a table may carry. Anything else is a fault (fail-closed).
115_KNOWN_FIELDS = frozenset({"value", "class", "doc", "env", "setting"})
116
117#: Value-type names the registry may pin, and their strict predicates. ``bool``
118#: is NOT accepted for ``int`` (Python's ``isinstance(True, int)`` would let a
119#: boolean masquerade as a ceiling).
120_TYPE_CHECKS = {
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),
125 # Plan 237 (CAPS-01): a non-empty list of positive floats — the cost
126 # checkpoint ladder. Deliberately as strict as the scalar ``float`` row:
127 # ``[2, 5]`` (TOML integers) REFUSES, exactly as ``0.70`` written as ``0``
128 # would, so the shipped ladder cannot silently change type. Emptiness is a
129 # fault too — "no checkpoints at all" must be written as a deliberate change
130 # to the resolver, never as an easily-overlooked empty list in the file.
131 "floatlist": lambda v: (
132 isinstance(v, list) and bool(v)
133 and all(isinstance(x, float) and x > 0 for x in v)
134 ),
135}
136
137
138#: The ONE list of keys permitted to live in code: key name, expected value
139#: type, class. Everything else about a value — the value itself, its doc, its
140#: out-of-band env knob, the settings key allowed to influence it — lives in the
141#: shipped file. A key here but not in the file, or in the file but not here,
142#: refuses to start.
143KEY_REGISTRY: tuple[tuple[str, str, str], ...] = (
144 # Appendix B resource ceilings.
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),
154 # Session cost bounds (CAPS-01, plan 237).
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),
160 # Completion (output) token budget.
161 ("output_tokens", "int", CLASS_CEILING),
162 ("undeclared_output_tokens", "int", CLASS_DEFAULT),
163 # Context window and compression.
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),
169 # ReAct loop.
170 ("max_react_iterations", "int", CLASS_DEFAULT),
171 ("reasoning_effort", "str", CLASS_DEFAULT),
172 # Settings-file schema defaults.
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),
185 # Verification backpressure.
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),
197 # Per-step output-budget shares.
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),
204 # API-context tool-result caps.
205 ("tool_result_cap", "int", CLASS_DEFAULT),
206 ("big_context_tool_result_cap", "int", CLASS_DEFAULT),
207 # Lane-picker table widths.
208 ("lane_picker_name_width", "int", CLASS_DEFAULT),
209 ("lane_picker_label_width", "int", CLASS_DEFAULT),
210 # Terminal UI.
211 ("ui_reasoning_tail", "int", CLASS_DEFAULT),
212 # The operator-trusted package index (SUPPLY-02, plan 253; M8 F78).
213 ("pip_index_url", "str", CLASS_AUTHORITY),
214)
215
216#: Plan 246 adds positive-only semantics for its three new thresholds without
217#: changing the validation contract of pre-existing ceiling entries.
218_POSITIVE_CEILING_KEYS = frozenset({
219 "stall_repeat_calls",
220 "stall_error_streak",
221 "stall_no_progress_iterations",
222})
223
224
225@dataclass(frozen=True)
226class Entry:
227 """One validated table from the shipped defaults file."""
228
229 key: str
230 value: Any
231 value_class: str
232 doc: str
233 env: str = ""
234 setting: str = ""
235
236
237def _refuse(path: Path, message: str) -> NoReturn:
238 """Refuse to start: raise ``SystemExit`` naming *path* and the fault.
239
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."""
244 func = "_refuse"
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)
248
249
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.
252
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."""
258 func = "_refuse_env"
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)
262
263
264def _authority_url_fault(value: Any) -> str:
265 """Why *value* is not a usable authority URL, or ``""`` when it is.
266
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"
278 try:
279 parts = urlsplit(value)
280 scheme, host, user, password, query = (
281 parts.scheme, parts.hostname, parts.username, parts.password, parts.query)
282 _ = parts.port # a malformed port raises here, not at the point of use
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}"
287 if not host:
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)"
291 if query:
292 return "an authority URL must carry no query string"
293 return ""
294
295
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)
301 if unknown:
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:
313 fault = _authority_url_fault(raw["value"])
314 if fault:
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")
318
319 env = raw.get("env")
320 if want_class in (CLASS_CEILING, CLASS_AUTHORITY):
321 if env is None:
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:
331 # OCT-LINT: disable=no_hardcoded_secrets reason="Refusal message naming _env_guard._AUTHORITY_EXACT trips Shannon entropy (4.51 bits/char); prose, no secret (operator ruling 2026-09-05)"
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")
335
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")
342
343 return Entry(
344 key=key,
345 value=raw["value"],
346 value_class=want_class,
347 doc=raw["doc"],
348 env=env or "",
349 setting=setting or "",
350 )
351
352
353def load_table(path: Path) -> dict[str, Entry]:
354 """Read and validate the defaults file at *path*; ``SystemExit`` on any fault.
355
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
360 the key."""
361 func = "load_table"
362 try:
363 raw_bytes = path.read_bytes()
364 except FileNotFoundError:
365 _refuse(path, "the shipped defaults file is missing")
366 except OSError as exc:
367 # EXTERNAL_ERROR (L2) at the seam; fail closed regardless.
368 _refuse(path, f"the shipped defaults file is unreadable ({type(exc).__name__}: {exc})")
369 try:
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})")
373
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")
377
378 table: dict[str, Entry] = {}
379 for key, type_name, want_class in KEY_REGISTRY:
380 if key not in data:
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])
383
384 _dbg("OC_CHAT.CORE", func, f"loaded {len(table)} keys from {path.name}", 2)
385 return table
386
387
388def _validate_authority_env(table: dict[str, Entry]) -> None:
389 """Refuse at import when an out-of-band authority value does not validate.
390
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:
397 continue
398 raw = os.environ.get(entry.env)
399 if raw is None:
400 continue
401 fault = _authority_url_fault(raw)
402 if fault:
403 _refuse_env(entry.env, key, fault)
404
405
406#: The validated table, read once at import. Import fails closed (SystemExit).
407_TABLE: dict[str, Entry] = load_table(DEFAULTS_PATH)
409
410
411def _entry(key: str) -> Entry:
412 """The validated :class:`Entry` for *key*; ``KeyError`` names an unregistered key."""
413 try:
414 return _TABLE[key]
415 except KeyError:
416 raise KeyError(f"{key!r} is not a key in {DEFAULTS_FILENAME}") from None
417
418
419def keys() -> tuple[str, ...]:
420 """Every registered key, in registry order."""
421 return tuple(key for key, _type, _cls in KEY_REGISTRY)
422
423
424def doc(key: str) -> str:
425 """The shipped documentation string for *key*."""
426 return _entry(key).doc
427
428
429def env_var(key: str) -> str:
430 """The out-of-band env variable that raises *key*'s ceiling, or ``""``."""
431 return _entry(key).env
432
433
434def setting_key(key: str) -> str:
435 """The settings-file key permitted to influence *key*, or ``""`` for none."""
436 return _entry(key).setting
437
438
439def shipped(key: str) -> Any:
440 """The shipped value for *key*: no settings file, no env, no resolution.
441
442 This is the built-in default a settings-file merge starts from, and the code
443 default every ceiling degrades to."""
444 return _entry(key).value
445
446
447def _settings_int(setting: str, fallback: "int | None") -> "int | None":
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"
452 try:
453 from oc_chat.core.settings import runtime_settings
454 return int(getattr(runtime_settings(), setting, fallback))
455 except Exception as exc: # noqa: BLE001 — settings unavailable ⇒ bounded default
456 _dbg("OC_CHAT.CORE", func, f"VALIDATION_ERROR: {type(exc).__name__}: {exc}", 3)
457 return None
458
459
460def default(key: str) -> Any:
461 """The effective value for a ``default``-class *key*.
462
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."""
466 func = "default"
467 entry = _entry(key)
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:
473 return entry.value
474 try:
475 from oc_chat.core.settings import runtime_settings
476 found = getattr(runtime_settings(), entry.setting, None)
477 except Exception as exc: # noqa: BLE001 — settings unavailable ⇒ shipped value
478 _dbg("OC_CHAT.CORE", func, f"VALIDATION_ERROR: {type(exc).__name__}: {exc}", 3)
479 return entry.value
480 return entry.value if found is None else found
481
482
483def ceiling(key: str) -> int:
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".
486
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)."""
493 func = "ceiling"
494 entry = _entry(key)
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)
499
500 absolute = shipped_value
501 if entry.env:
502 raw = os.environ.get(entry.env)
503 if raw is not None:
504 try:
505 candidate = int(raw)
506 except (TypeError, ValueError):
507 candidate = 0
508 if candidate > 0:
509 absolute = candidate
510 _dbg("OC_CHAT.CORE", func, f"{key}: OOB ceiling {entry.env}={candidate}", 2)
511
512 if not entry.setting:
513 return absolute
514
515 value = _settings_int(entry.setting, None)
516 if value is None:
517 return absolute
518 requested = value if value > 0 else shipped_value
519 return min(requested, absolute)
520
521
522def authority(key: str) -> str:
523 """The effective value for an ``authority``-class *key* (plan 253, F78).
524
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
531 anybody noticing."""
532 func = "authority"
533 entry = _entry(key)
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
537 if raw is None:
538 return str(entry.value)
539 fault = _authority_url_fault(raw)
540 if fault:
541 _refuse_env(entry.env, key, fault)
542 _dbg("OC_CHAT.CORE", func, f"{key}: OOB authority value from {entry.env}", 2)
543 return raw
544
545
546__all__ = [
547 "CLASS_AUTHORITY",
548 "CLASS_CEILING",
549 "CLASS_DEFAULT",
550 "DEFAULTS_FILENAME",
551 "DEFAULTS_PATH",
552 "Entry",
553 "KEY_REGISTRY",
554 "authority",
555 "ceiling",
556 "default",
557 "doc",
558 "env_var",
559 "keys",
560 "load_table",
561 "setting_key",
562 "shipped",
563]
Definition defaults.py:226
Entry _entry(str key)
Definition defaults.py:411
str _authority_url_fault(Any value)
Definition defaults.py:264
dict[str, Entry] load_table(Path path)
Definition defaults.py:353
str setting_key(str key)
Definition defaults.py:434
Any shipped(str key)
Definition defaults.py:439
str authority(str key)
Definition defaults.py:522
NoReturn _refuse_env(str env_name, str key, str message)
Definition defaults.py:250
None _validate_authority_env(dict[str, Entry] table)
Definition defaults.py:388
Any default(str key)
Definition defaults.py:460
str doc(str key)
Definition defaults.py:424
Entry _validate_entry(Path path, str key, str type_name, str want_class, Any raw)
Definition defaults.py:296
tuple[str,...] keys()
Definition defaults.py:419
"int | None" _settings_int(str setting, "int | None" fallback)
Definition defaults.py:447
str env_var(str key)
Definition defaults.py:429
NoReturn _refuse(Path path, str message)
Definition defaults.py:237
int ceiling(str key)
Definition defaults.py:483