Files
C.E.L_Slide_test2/tests/test_phase_z2_ai_fallback_config.py
kyeongmin 1186ad8ae2 feat(#76): IMP-47B reject-as-AI-adaptation activation (u1~u13 backend + tests)
- u1~u9: AI fallback infrastructure (router/prompts/schema/validator) + Step 12 hook
- u10: e2e reject chain (writes final.html with AI-repaired slot, full coverage)
- u11: frontend wiring deferred to follow-up commit (split from IMP-41 hunks)
- u12: coverage_invariant guard
- u13: cache save gate (visual_check PASS + user_approved/auto_cache) — Codex #22 verified

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-22 00:19:10 +09:00

87 lines
3.4 KiB
Python

"""IMP-33 u1 — AI fallback Settings defaults (locked).
These defaults are the binding contract from Stage 2 plan (per-unit u1):
- ai_fallback_enabled = False (master flag OFF; fallback path only)
- ai_fallback_model = "claude-opus-4-6-20250415"
- ai_fallback_timeout_s = 60.0
- ai_fallback_max_retries = 3
- ai_fallback_backoff_base_s = 1.0
- ai_fallback_backoff_cap_s = 8.0
- ai_fallback_backoff_jitter = 0.3
- ai_fallback_budget_per_run = 10
- ai_fallback_circuit_breaker_threshold = 5
Downstream u4 (client) MUST source timeout/retry/backoff/budget/circuit from
Settings; inline literals are forbidden by Stage 2 plan.
"""
from __future__ import annotations
from src.config import Settings
def test_ai_fallback_master_flag_default_off() -> None:
s = Settings()
assert s.ai_fallback_enabled is False, (
"AI fallback master flag MUST default OFF (normal path AI=0 contract)."
)
def test_ai_fallback_model_default_locked() -> None:
s = Settings()
assert s.ai_fallback_model == "claude-opus-4-6-20250415"
def test_ai_fallback_retry_timeout_backoff_defaults_locked() -> None:
s = Settings()
assert s.ai_fallback_timeout_s == 60.0
assert s.ai_fallback_max_retries == 3
assert s.ai_fallback_backoff_base_s == 1.0
assert s.ai_fallback_backoff_cap_s == 8.0
assert s.ai_fallback_backoff_jitter == 0.3
def test_ai_fallback_budget_and_circuit_defaults_locked() -> None:
s = Settings()
assert s.ai_fallback_budget_per_run == 10
assert s.ai_fallback_circuit_breaker_threshold == 5
# IMP-46 u5 — auto-cache opt-in setting default lock.
# The CLI flag ``--auto-cache`` in src/phase_z2_pipeline.py mutates this
# setting at parse time. The default MUST stay OFF so the dual-gate
# contract (visual_check_passed AND user_approved) survives without an
# explicit operator opt-in.
def test_ai_fallback_auto_cache_default_off() -> None:
s = Settings()
assert s.ai_fallback_auto_cache is False, (
"IMP-46 u5 auto-cache MUST default OFF; the dual-gate contract "
"(visual_check_passed AND user_approved) survives without an "
"explicit --auto-cache opt-in."
)
# IMP-47B u1 — reject route hint policy correction.
# Prior to 2026-05-21 the reject V4 label routed to ``design_reference_only``
# (no AI). The user policy correction (issue #76) reroutes reject to
# ``ai_adaptation_required`` so the rank-1 reject frame is kept and the AI
# re-maps MDX content into its declared slots. Activation remains gated by
# ``ai_fallback_enabled`` (default OFF preserves the normal-path AI=0
# contract — see test_ai_fallback_master_flag_default_off above).
def test_reject_route_hint_routes_to_ai_adaptation() -> None:
from src.phase_z2_pipeline import _IMP05_ROUTE_HINTS, _imp05_route_hint
assert _IMP05_ROUTE_HINTS["reject"] == "ai_adaptation_required", (
"IMP-47B u1: reject must route to ai_adaptation_required so the "
"rank-1 reject frame is retained and AI re-maps MDX content into "
"its slots (frame auto-swap forbidden)."
)
assert _imp05_route_hint("reject") == "ai_adaptation_required"
# Sibling routes unchanged — guardrail against accidental drift.
assert _imp05_route_hint("use_as_is") == "direct_render"
assert _imp05_route_hint("light_edit") == "deterministic_minor_adjustment"
assert _imp05_route_hint("restructure") == "ai_adaptation_required"