feat(ask): add default-dark ASK serving gate helper
Adds a default-dark ask_serving_enabled helper with focused tests. The helper is unwired: no pass_manager integration, no runtime surface, no carve-out retirement, and no served question text.
This commit is contained in:
parent
9a54374048
commit
297349fd8d
2 changed files with 75 additions and 0 deletions
32
core/epistemic_questions/serving_gate.py
Normal file
32
core/epistemic_questions/serving_gate.py
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
"""ASK serving gate helper — default-dark, no served-surface wiring.
|
||||
|
||||
This module is the first code slice after the ASK serving-integration scoping brief.
|
||||
It intentionally does **not** call ``deliver_ask``/``emit_question``, does not import
|
||||
``chat.runtime``, and does not expose any user-facing surface. It only centralizes the
|
||||
kill-switch read so future serving code has one audited predicate.
|
||||
|
||||
The planned config field is ``RuntimeConfig.ask_serving_enabled``. During this dark-gate
|
||||
slice the predicate is conservative: absent field == ``False``. That lets the helper land
|
||||
without widening behavior and preserves the current default for every existing
|
||||
``RuntimeConfig`` instance.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Any
|
||||
|
||||
from core.config import DEFAULT_CONFIG, RuntimeConfig
|
||||
|
||||
|
||||
def ask_serving_enabled(config: RuntimeConfig | Any | None = None) -> bool:
|
||||
"""Return whether served ASK delivery is explicitly enabled.
|
||||
|
||||
Missing attribute means ``False``. That is the load-bearing dark-gate invariant:
|
||||
the served ASK path cannot light merely because the helper exists or because an
|
||||
older ``RuntimeConfig`` instance lacks the future field.
|
||||
"""
|
||||
cfg = DEFAULT_CONFIG if config is None else config
|
||||
return bool(getattr(cfg, "ask_serving_enabled", False))
|
||||
|
||||
|
||||
__all__ = ["ask_serving_enabled"]
|
||||
43
tests/test_ask_serving_gate.py
Normal file
43
tests/test_ask_serving_gate.py
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
"""ASK serving gate — default-dark invariant.
|
||||
|
||||
This is deliberately narrower than serving integration. It proves the post-scoping
|
||||
kill-switch predicate is dark unless an operator/config object explicitly opts in.
|
||||
No chat/runtime wiring, no pass-manager emission, no carve-out retirement.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from dataclasses import dataclass
|
||||
|
||||
from core.config import DEFAULT_CONFIG, RuntimeConfig
|
||||
from core.epistemic_questions.serving_gate import ask_serving_enabled
|
||||
|
||||
|
||||
@dataclass(frozen=True, slots=True)
|
||||
class _LegacyConfig:
|
||||
"""A pre-field config shape: absence of the flag must mean dark."""
|
||||
|
||||
unrelated: bool = True
|
||||
|
||||
|
||||
@dataclass(frozen=True, slots=True)
|
||||
class _OptInConfig:
|
||||
ask_serving_enabled: bool
|
||||
|
||||
|
||||
def test_default_runtime_config_keeps_ask_serving_dark() -> None:
|
||||
assert ask_serving_enabled(DEFAULT_CONFIG) is False
|
||||
assert ask_serving_enabled(RuntimeConfig()) is False
|
||||
|
||||
|
||||
def test_missing_flag_is_dark_for_legacy_config_shape() -> None:
|
||||
assert ask_serving_enabled(_LegacyConfig()) is False
|
||||
|
||||
|
||||
def test_gate_only_lights_on_explicit_truthy_opt_in() -> None:
|
||||
assert ask_serving_enabled(_OptInConfig(False)) is False
|
||||
assert ask_serving_enabled(_OptInConfig(True)) is True
|
||||
|
||||
|
||||
def test_none_uses_default_config_and_stays_dark() -> None:
|
||||
assert ask_serving_enabled() is False
|
||||
Loading…
Reference in a new issue