feat(#61): IMP-33 AI fallback scaffolding (u1~u11, flag default OFF)
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>
This commit is contained in:
1 parent
c412f1ea75
commit
c864fe0479
24 files changed
+2119
-5
No files matched your search
@@ -0,0 +1,111 @@
|
||||
"""IMP-33 u9 — Step 17 AI repair wiring (BLOCKED until IMP-34 + IMP-35 land).
|
||||
|
||||
Phase Z Step 17 = retry / salvage cascade (see ``src.phase_z2_pipeline``
|
||||
section 11.7 ``_attempt_salvage_chain`` and the existing IMP-12 u8/u9
|
||||
deterministic chain at ``src/phase_z2_pipeline.py:1994`` and
|
||||
``src/phase_z2_pipeline.py:4948``).
|
||||
|
||||
Per IMP-17 carve-out (``docs/architecture/IMP-17-CARVE-OUT.md`` lines 16,
|
||||
40-44), AI repair at Step 17 is permitted ONLY after the full deterministic
|
||||
chain is exhausted AND popup escalation is exhausted AND a user-approved
|
||||
fallback budget remains. IMP-34 (zone resize + compact retry) and IMP-35
|
||||
(``details_popup_escalation``) are explicit prerequisites under the IMP-33
|
||||
out-of-scope contract — neither has landed yet. Therefore Step 17 AI repair
|
||||
is STRUCTURALLY BLOCKED at u9.
|
||||
|
||||
This module:
|
||||
|
||||
1. **SPECIFIES** the canonical overflow cascade order via
|
||||
:data:`OVERFLOW_CASCADE_ORDER` — ``deterministic`` → ``popup`` →
|
||||
``ai_repair`` → ``user_override``. Downstream Step 17 consumers can rely
|
||||
on this single source of truth.
|
||||
2. **KEEPS** Step 17 AI repair structurally blocked. The entry point
|
||||
:func:`gather_step17_ai_repair_proposals` does NOT import
|
||||
``route_ai_fallback`` (u7), does NOT instantiate ``AiFallbackClient`` (u4),
|
||||
and does NOT call any Anthropic API. Every unit is recorded with
|
||||
``skip_reason="step17_ai_blocked_imp_34_35_prerequisites_missing"`` so
|
||||
the caller can distinguish "blocked by carve-out gate" from any other
|
||||
skip path (e.g., u8 ``not_provisional`` / ``design_reference_only_no_ai``).
|
||||
|
||||
Once IMP-34 + IMP-35 land AND a user-approved fallback budget is granted,
|
||||
this module will gain the actual ``route_ai_fallback`` wiring guarded by
|
||||
the cascade-stage conjunction. Today the gate is closed.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
from enum import Enum
|
||||
from typing import Any, Callable, Iterable
|
||||
|
||||
|
||||
class OverflowCascadeStage(str, Enum):
|
||||
"""Step 17 overflow cascade stages — canonical order (u9 single source of truth).
|
||||
|
||||
Members are ordered to match the AI isolation contract:
|
||||
|
||||
* ``DETERMINISTIC`` — IMP-12 u4/u5/u6 (``cross_zone_redistribute`` /
|
||||
``glue_compression`` / ``font_step_compression``) + IMP-12 terminal
|
||||
actions (``layout_adjust`` / ``frame_reselect``) + IMP-34
|
||||
(``zone resize + compact retry``, pending). No AI in any sub-stage.
|
||||
* ``POPUP`` — IMP-35 (``details_popup_escalation``, pending). Content
|
||||
popup escalation as the final deterministic resort before any AI.
|
||||
* ``AI_REPAIR`` — IMP-33 (this carve-out) + IMP-46 cache. Only reachable
|
||||
after DETERMINISTIC and POPUP are both exhausted AND user-approved
|
||||
fallback budget remains.
|
||||
* ``USER_OVERRIDE`` — explicit user override after all auto stages.
|
||||
"""
|
||||
|
||||
DETERMINISTIC = "deterministic"
|
||||
POPUP = "popup"
|
||||
AI_REPAIR = "ai_repair"
|
||||
USER_OVERRIDE = "user_override"
|
||||
|
||||
|
||||
OVERFLOW_CASCADE_ORDER: tuple[OverflowCascadeStage, ...] = (
|
||||
OverflowCascadeStage.DETERMINISTIC,
|
||||
OverflowCascadeStage.POPUP,
|
||||
OverflowCascadeStage.AI_REPAIR,
|
||||
OverflowCascadeStage.USER_OVERRIDE,
|
||||
)
|
||||
|
||||
|
||||
STEP17_AI_REPAIR_BLOCKED_REASON = (
|
||||
"step17_ai_blocked_imp_34_35_prerequisites_missing"
|
||||
)
|
||||
|
||||
|
||||
def gather_step17_ai_repair_proposals(
|
||||
units: Iterable[Any],
|
||||
*,
|
||||
route_for_label: Callable[[str | None], str | None],
|
||||
) -> list[dict]:
|
||||
"""Return one BLOCKED record per unit. No AI call is performed at u9.
|
||||
|
||||
The record schema mirrors :func:`src.phase_z2_ai_fallback.step12
|
||||
.gather_step12_ai_repair_proposals` so the Step 17 artifact consumer can
|
||||
reuse the same shape, with one addition: ``cascade_stage`` pins the
|
||||
stage this record belongs to (always ``ai_repair`` here).
|
||||
|
||||
Per Stage 2 contract (IMP-33 u9): Step 17 AI repair is blocked behind
|
||||
IMP-34 + IMP-35. Every unit returns with
|
||||
``skip_reason=STEP17_AI_REPAIR_BLOCKED_REASON`` and ``ai_called=False``.
|
||||
"""
|
||||
records: list[dict] = []
|
||||
for index, unit in enumerate(units):
|
||||
label = getattr(unit, "label", None)
|
||||
record: dict = {
|
||||
"unit_index": index,
|
||||
"source_section_ids": list(
|
||||
getattr(unit, "source_section_ids", []) or []
|
||||
),
|
||||
"frame_template_id": getattr(unit, "frame_template_id", None),
|
||||
"label": label,
|
||||
"route_hint": route_for_label(label),
|
||||
"provisional": bool(getattr(unit, "provisional", False)),
|
||||
"cascade_stage": OverflowCascadeStage.AI_REPAIR.value,
|
||||
"ai_called": False,
|
||||
"skip_reason": STEP17_AI_REPAIR_BLOCKED_REASON,
|
||||
"proposal": None,
|
||||
"error": None,
|
||||
}
|
||||
records.append(record)
|
||||
return records
|
||||
Reference in new issue
Block a user