Frame-aware AI fallback module scaffolded under src/phase_z2_ai_fallback/ with master flag ai_fallback_enabled=False; normal-path AI call count remains 0. AI output constrained to builder_options_patch / partial_overrides / slot_mapping_proposal; MDX / frame_id / raw HTML / raw CSS mutations rejected at schema layer. IMP-46 cache gate (cache.py) raises AiFallbackCacheGateError unless visual_check_passed AND user_approved. Step 12 wires AI repair after IMP-30 provisional payload only; Step 17 stays blocked behind IMP-34 / IMP-35 prerequisites. AST isolation guard forbids fallback package from importing Phase Q / Kei / pipeline runtime symbols. Docs IMP-17 / IMP-31 bound to runtime module surface via 11-row structural test pin (test_docs_sync.py) so drift fails CI. Tests: 116 fallback / 161 phase_z2 regression / 526 scoped full sweep all passing. Existing pre-IMP-33 fixture issue in scripts/test_phase_t_* remains untouched (out of scope). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
83 lines
3.0 KiB
Python
83 lines
3.0 KiB
Python
"""IMP-33 u6 — AI fallback proposal cache (IMP-46 gate, no persistent storage).
|
|
|
|
This module defines the cache contract that IMP-33 callers use to remember
|
|
AI fallback proposals across runs. The persistent storage layer itself is
|
|
out-of-scope for IMP-33 and is owned by IMP-46 (frame transformation cache).
|
|
|
|
Behaviour locked by Stage 2 plan (u6):
|
|
|
|
* ``read_proposal(key)`` always returns ``None`` until IMP-46 lands a
|
|
persistent backend. Callers MUST handle the cache-miss path.
|
|
* ``save_proposal(key, proposal, *, visual_check_passed, user_approved)``
|
|
enforces the IMP-46 gate before any storage write is attempted:
|
|
|
|
- ``visual_check_passed=False`` -> ``AiFallbackCacheGateError``
|
|
- ``user_approved=False`` -> ``AiFallbackCacheGateError``
|
|
|
|
Only when BOTH gates are True does control reach the storage layer,
|
|
which currently raises ``NotImplementedError`` (the IMP-46 marker).
|
|
|
|
Guardrails:
|
|
|
|
* No Anthropic import; cache is pure proposal bookkeeping.
|
|
* No MDX read/write; proposals are u2 ``AiFallbackProposal`` instances.
|
|
* No silent persistence: gate violations are loud, not skipped writes
|
|
(`feedback_artifact_status_naming`).
|
|
"""
|
|
from __future__ import annotations
|
|
|
|
from src.phase_z2_ai_fallback.schema import AiFallbackProposal
|
|
|
|
|
|
class AiFallbackCacheGateError(RuntimeError):
|
|
"""Raised when ``save_proposal`` is called without both IMP-46 gates True."""
|
|
|
|
|
|
def read_proposal(key: str) -> AiFallbackProposal | None:
|
|
"""Look up a previously cached proposal by ``key``.
|
|
|
|
IMP-33 ships without a persistent backend; this stub always returns
|
|
``None`` so callers exercise the cache-miss path. The persistent
|
|
backend will be wired by IMP-46.
|
|
"""
|
|
if not isinstance(key, str) or not key:
|
|
raise ValueError("cache key must be a non-empty string")
|
|
return None
|
|
|
|
|
|
def save_proposal(
|
|
key: str,
|
|
proposal: AiFallbackProposal,
|
|
*,
|
|
visual_check_passed: bool,
|
|
user_approved: bool,
|
|
) -> None:
|
|
"""Persist ``proposal`` under ``key`` once both IMP-46 gates are True.
|
|
|
|
Raises ``AiFallbackCacheGateError`` if either gate is False — the
|
|
proposal is NOT written. When both gates are True, storage raises
|
|
``NotImplementedError`` (the IMP-46 persistent backend has not landed
|
|
yet).
|
|
"""
|
|
if not isinstance(key, str) or not key:
|
|
raise ValueError("cache key must be a non-empty string")
|
|
if not isinstance(proposal, AiFallbackProposal):
|
|
raise TypeError(
|
|
"proposal must be an AiFallbackProposal instance "
|
|
f"(got {type(proposal).__name__})"
|
|
)
|
|
if not visual_check_passed:
|
|
raise AiFallbackCacheGateError(
|
|
"IMP-46 gate: visual_check_passed=False; refusing to cache an "
|
|
"unverified proposal."
|
|
)
|
|
if not user_approved:
|
|
raise AiFallbackCacheGateError(
|
|
"IMP-46 gate: user_approved=False; refusing to cache without "
|
|
"explicit user approval."
|
|
)
|
|
raise NotImplementedError(
|
|
"IMP-46 persistent cache storage is not implemented yet; "
|
|
"this is the IMP-33 u6 stub marker."
|
|
)
|