From e10ec3661786b8510d5e4ab16291c11fc36f9648 Mon Sep 17 00:00:00 2001 From: kyeongmin Date: Tue, 19 May 2026 08:12:43 +0900 Subject: [PATCH] =?UTF-8?q?feat(IMP-17):=20AI=20repair=20fallback=20infra?= =?UTF-8?q?=20carve-out=20=E2=80=94=20design-only=20boundary=20+=203-cond?= =?UTF-8?q?=20AND=20gate?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit u1 — src/phase_z2_pipeline.py:564 route hint comment corrected from non-existent IMP-31 to IMP-17 (carve-out, AI fallback only, normal path 밖). Line 565 IMP-29 frontend override reference untouched. u2 — docs/architecture/IMP-17-CARVE-OUT.md (new) defines: - allowed scope (Step 12 restructure proposal, Step 16/17 retry fallback) - forbidden scope (normal-path AI calls, MDX compression, HTML structure) - 3-condition AND activation gate (User GO ∧ B4 frame_selection evidence ∧ IMP-04 catalog + IMP-05 V4 fallback live) - pattern shape reference (link-only): content_editor.py:21,318 + sse_utils.py:16-50 (Phase Q Archive Candidate, no port) - AI 격리 contract + Kei persona 단절 (permanent) u3 — PHASE-Z-IMPLEMENTATION-ISSUE-BACKLOG.md:68 IMP-17 row gains carve-out doc link + 3-cond AND gate pointer. u4 — PHASE-Q-INSIGHT-TO-22STEP-MAP.md AI repair fallback infra registry row prefixed with IMP-17 + carve-out link; normal_path=no preserved. Anchor test: tests/orchestrator_unit/test_imp17_comment_anchor.py asserts line 564 IMP-17 wording AND line 565 IMP-29 preservation (2 tests pass). Runtime behavior change: 0. Only delta in executable file is one comment line. Normal-path AI invocation count remains 0. Refs: gitea #17 Co-Authored-By: Claude Opus 4.7 (1M context) --- docs/architecture/IMP-17-CARVE-OUT.md | 44 +++++++++++++++++++ .../PHASE-Q-INSIGHT-TO-22STEP-MAP.md | 2 +- .../PHASE-Z-IMPLEMENTATION-ISSUE-BACKLOG.md | 2 +- src/phase_z2_pipeline.py | 2 +- .../test_imp17_comment_anchor.py | 29 ++++++++++++ 5 files changed, 76 insertions(+), 3 deletions(-) create mode 100644 docs/architecture/IMP-17-CARVE-OUT.md create mode 100644 tests/orchestrator_unit/test_imp17_comment_anchor.py diff --git a/docs/architecture/IMP-17-CARVE-OUT.md b/docs/architecture/IMP-17-CARVE-OUT.md new file mode 100644 index 0000000..3805376 --- /dev/null +++ b/docs/architecture/IMP-17-CARVE-OUT.md @@ -0,0 +1,44 @@ +# IMP-17 — AI repair fallback infrastructure (carve-out) + +**Status**: carve-out, **design-only**. Normal-path AI calls = 0. No runtime fallback code lands until the activation gate clears. + +**Source anchors** +- IMP-17 backlog row — [`PHASE-Z-IMPLEMENTATION-ISSUE-BACKLOG.md`](PHASE-Z-IMPLEMENTATION-ISSUE-BACKLOG.md):68 (carve-out — normal path 밖, soft link IMP-04 + IMP-05). +- INSIGHT-MAP §3 — [`PHASE-Q-INSIGHT-TO-22STEP-MAP.md`](PHASE-Q-INSIGHT-TO-22STEP-MAP.md) (G3 AI repair fallback infra registry row, normal path = no). +- 22-step pipeline — [`PHASE-Z-PIPELINE-OVERVIEW.md`](PHASE-Z-PIPELINE-OVERVIEW.md) Step 12 (lines 280-287), Step 16 (lines 318-325), Step 17 (lines 326-333). +- Pattern shape reference (Phase Q Archive — link-only, do not port) — `src/content_editor.py:21,318` (httpx + retry shape, imports `sse_utils`) + `src/sse_utils.py:16-50` (SSE token parser). +- Route hint emission site — `src/phase_z2_pipeline.py:564` (`restructure` → `ai_adaptation_required` route hint; deterministic emission today, AI consumer deferred to IMP-17). + +## Carve-out boundary + +### Allowed (fallback path only) +- **Step 12**: when V4 emits `restructure` (route hint `ai_adaptation_required`) AND deterministic mapping cannot satisfy the frame contract, an AI proposal MAY be invoked to map `content_object` → `Internal Region` / `Frame Slot`. Output = placement proposal at content-object granularity. Frame selection, layout selection, zone topology remain deterministic. +- **Step 16 / 17**: when retry router exhausts deterministic actions (zone_ratio_retry / layout_adjust / frame_reselect / details_popup_escalation / image_fit_candidate / frame_internal_fit_candidate) AND user-approved fallback budget remains, an AI proposal MAY be invoked. Output scope identical to Step 12 — content-object placement only. + +### Forbidden (any path) +- Normal-path AI calls (Step 12 deterministic mapper, all other steps). +- MDX 원문 요약·삭제·재작성 (Phase Z spacing direction guardrail: never compress text). +- HTML / CSS 직접 생성, frame contract 신설, layout / zone topology 결정 (Layer-A / Layer-B planning은 코드 영역). +- 공통 padding / spacing / tolerance 축소 (PZ-4 — no silent shrink). +- 신규 IMP ID 발급 (이 carve-out 은 IMP-17 슬롯에 영구 귀속). + +## Activation gate (3-condition AND — all three required) + +1. **User GO** — 명시적 axis activation 요청. carve-out 자체로는 코드 작성 트리거 안 됨. +2. **B4 frame_selection evidence integration complete** — Step 9 frame_selection 의 evidence trace 가 안정화되어야 fallback proposal 이 어떤 frame contract 안에서 동작해야 하는지 식별 가능. +3. **IMP-04 (catalog 확장) + IMP-05 (V4 fallback) live** — 카탈로그가 32 frame 으로 확장되고 V4 rank-2/3 fallback 이 활성화돼야 `ai_adaptation_required` 라우트가 실제 의미를 가짐 (현재는 dead-end route hint). + +세 조건 중 하나라도 미충족이면 본 carve-out 은 design-only 상태로 잠겨 있다. + +## Pattern shape reference (link-only, do not import) + +Phase Q `content_editor.py` 는 **Archive Candidate** ([`PHASE-Q-AUDIT.md`](PHASE-Q-AUDIT.md):660-673) — 포팅 대상 아님. 모양만 참조한다: +- httpx async streaming + retry 구조 — `src/content_editor.py:21,318` 라인 부근 (import + `stream_sse_tokens` 호출 site). +- SSE token 파서 분리 모듈 — `src/sse_utils.py:16-50` (`stream_sse_tokens` 본체). +- `EDITOR_PROMPT` (Kei persona) 및 Kei-API endpoint 는 **영구 단절**. 재사용 금지. + +## AI 격리 + Kei persona 단절 contract + +- AI 호출은 normal path 에 없다 (Phase Z 원칙, [memory `feedback_ai_isolation_contract`](../../README.md)). +- 출력 단위는 항상 content_object / Internal Region / Frame Slot 또는 restructuring proposal — HTML 구조 / 레이아웃 / 프리셋 결정 X. +- Phase Q 자산 (Kei persona prompts, Kei-API endpoint, persona retry semantics) 과 단절. Phase Z 의 fallback runtime 은 별도 prompt / endpoint 설계로 출발한다 (본 carve-out 활성 시). diff --git a/docs/architecture/PHASE-Q-INSIGHT-TO-22STEP-MAP.md b/docs/architecture/PHASE-Q-INSIGHT-TO-22STEP-MAP.md index 29ff8a8..3be3525 100644 --- a/docs/architecture/PHASE-Q-INSIGHT-TO-22STEP-MAP.md +++ b/docs/architecture/PHASE-Q-INSIGHT-TO-22STEP-MAP.md @@ -120,7 +120,7 @@ | A-4 slide-base iframe mode | Step 13 | §2.8 I2 (renderer.py slide-base 사용 호출 지점) | pending | yes (UI/backend) | | Step 14 visual_check 보강 | Step 14, 21 | §2.7 H1 (`content_verifier` utilities Reference Only) | pending | yes (deterministic) | | B-2 verification 보조 | Step 1, 2, 14, 21, 22 | §2.7 H3 (text 추출 / 정규화 / 비교 utility) | pending | yes (UI/backend) | -| AI repair fallback infra | Step 12, 16, 17 | §2.6 G3 (`httpx` + SSE streaming + retry + JSON parse pattern) | pending | no (AI fallback only) | +| IMP-17 AI repair fallback infra (carve-out — see [`IMP-17-CARVE-OUT.md`](IMP-17-CARVE-OUT.md)) | Step 12, 16, 17 | §2.6 G3 (`httpx` + SSE streaming + retry + JSON parse pattern) | pending | no (AI fallback only) | | I3 SVG 좌표 보강 | Step 0, 9 | §2.8 I3 (`renderer._preprocess_svg_data`) | pending | yes (deterministic) | | I4 zone 비중 분배 | Step 8 | §2.8 I4 (`renderer._group_blocks_by_area`) | pending | yes (deterministic) | | H2 frame contract validation | Step 10 | §2.7 H2 (`content_verifier.verify_structure` pattern) | pending | yes (deterministic) | diff --git a/docs/architecture/PHASE-Z-IMPLEMENTATION-ISSUE-BACKLOG.md b/docs/architecture/PHASE-Z-IMPLEMENTATION-ISSUE-BACKLOG.md index b65140b..a3e043c 100644 --- a/docs/architecture/PHASE-Z-IMPLEMENTATION-ISSUE-BACKLOG.md +++ b/docs/architecture/PHASE-Z-IMPLEMENTATION-ISSUE-BACKLOG.md @@ -65,7 +65,7 @@ | IMP-14 | A-4 slide-base iframe mode | Step 13 | §3 새로 만들기 | ↓ low | `slide-base.html` conditional CSS (embedded vs standalone) | Claude / Phase R' HTML generation 회귀 X / Jinja2 deterministic | none | pending | | IMP-15 | Step 14 visual_check 보강 | Step 14, 21 | §3 H1 Reference Only | medium | image_aspect_mismatch / tabular_overflow 검사 추가 | AI/Kei classification 회귀 X / deterministic 검사 + trace | soft link: IMP-01 (Step 14 측정/trace layer 공유) | pending | | IMP-16 | B-2 verification 보조 axis | Step 1, 2, 14, 21, 22 | §3 H3 Reference Only | ↓ low | B-2 reverse path 의 verification 보조. main reverse path 는 IMP-07, 본 issue 는 text/visual/trace 검증 layer | AI/Kei verification 회귀 X / utility deterministic | hard link: IMP-07 (B-2 main 활성 시점 의미) | pending | -| **IMP-17** | **AI repair fallback infra** (**carve-out — normal path 밖**) | Step 12, 16, 17 | §3 G3 | (별 axis priority — pending) | `httpx` + SSE streaming + retry + JSON parse pattern reference — light_edit / restructure proposal | **normal path AI 호출 0 — 본 axis = fallback only, normal path 와 분리 설계** / Kei persona 단절 (Phase Q 자산과 단절) | soft link: IMP-04 + IMP-05 (catalog 확장 + V4 fallback 활성 시 의미) | pending | +| **IMP-17** | **AI repair fallback infra** (**carve-out — normal path 밖**) | Step 12, 16, 17 | §3 G3 | (별 axis priority — pending) | [carve-out boundary + activation gate](IMP-17-CARVE-OUT.md) (3-cond AND: User GO ∧ B4 frame_selection evidence ∧ IMP-04/05 live — full def in u2 doc) — `httpx` + SSE streaming + retry + JSON parse pattern reference — light_edit / restructure proposal | **normal path AI 호출 0 — 본 axis = fallback only, normal path 와 분리 설계** / Kei persona 단절 (Phase Q 자산과 단절) | soft link: IMP-04 + IMP-05 (catalog 확장 + V4 fallback 활성 시 의미) | pending | | IMP-18 | I3 SVG 좌표 보강 | Step 0, 9 | §3 Reference Only | ↓ low | `renderer._preprocess_svg_data` 패턴 reference — frame_partials SVG 좌표 사전 박힘 | Phase R' (renderer.py) 회귀 X | soft link: IMP-04 (frame_partials 등록 후 의미 ↑) | pending | | IMP-19 | I4 zone 비중 분배 | Step 8 | §3 Reference Only | ↓ low | `renderer._group_blocks_by_area` 패턴 reference — zone-level ratio 분배 | Phase O 컨테이너 회귀 X / 직접 통합 X | soft link: IMP-09 (zone 비중 분배 영역 공유) | pending | | IMP-20 | H2 frame contract validation | Step 10 | §3 Reference Only | ↓ low | `content_verifier.verify_structure` pattern reference — Phase Z frame contract 검증 pattern | Phase Q `REQUIRED_PATTERNS` 값 회귀 X / Phase Z 자체 pattern dict 설계 | soft link: IMP-04 (확장 catalog 적용 시 검증 범위 확대) | pending | diff --git a/src/phase_z2_pipeline.py b/src/phase_z2_pipeline.py index a5c0d08..8e450be 100644 --- a/src/phase_z2_pipeline.py +++ b/src/phase_z2_pipeline.py @@ -561,7 +561,7 @@ def lookup_v4_match( # (frontend zone-level override / AI-assisted adaptation). Codex #2 conceptual model : # use_as_is → Phase Z direct render # light_edit → deterministic minor adjustment -# restructure → AI-assisted frame-aware adaptation (deferred to IMP-31) +# restructure → AI-assisted frame-aware adaptation (deferred to IMP-17 — carve-out, AI fallback only, normal path 밖) # reject → design reference only (deferred to IMP-29 frontend override) _IMP05_ROUTE_HINTS: dict[str, str] = { "use_as_is": "direct_render", diff --git a/tests/orchestrator_unit/test_imp17_comment_anchor.py b/tests/orchestrator_unit/test_imp17_comment_anchor.py new file mode 100644 index 0000000..015dabc --- /dev/null +++ b/tests/orchestrator_unit/test_imp17_comment_anchor.py @@ -0,0 +1,29 @@ +"""IMP-17 u1 (2026-05-19) — comment anchor for src/phase_z2_pipeline.py route hint table. + +Stage 1 finding: line 564 previously referenced a non-existent ID ("IMP-31"). +The legitimate slot is IMP-17 (Gitea #17, carve-out — AI fallback only, normal path 밖). +Line 565 (IMP-29 frontend zone-level override) must remain untouched. + +Run: pytest -q tests/orchestrator_unit/test_imp17_comment_anchor.py +""" +from pathlib import Path + +ROOT = Path(__file__).parent.parent.parent +PIPELINE = ROOT / "src" / "phase_z2_pipeline.py" + + +def _lines() -> list[str]: + return PIPELINE.read_text(encoding="utf-8").splitlines() + + +def test_line_564_references_imp17_not_imp31(): + line = _lines()[563] # 1-indexed line 564 + assert "restructure" in line, f"line 564 anchor drifted: {line!r}" + assert "IMP-17" in line, f"line 564 must reference IMP-17 (carve-out): {line!r}" + assert "IMP-31" not in line, f"line 564 must not reference non-existent IMP-31: {line!r}" + + +def test_line_565_still_references_imp29(): + line = _lines()[564] # 1-indexed line 565 + assert "reject" in line, f"line 565 anchor drifted: {line!r}" + assert "IMP-29" in line, f"line 565 must still reference IMP-29 frontend override: {line!r}"