diff --git a/.gitignore b/.gitignore index 7d7a50f..5fcaeff 100644 --- a/.gitignore +++ b/.gitignore @@ -8,7 +8,11 @@ dist/ build/ .venv/ node_modules/ -data/ +data/* +# IMP-46 u6 — track only the frame_cache directory marker; cached payloads stay ignored. +!data/frame_cache/ +data/frame_cache/* +!data/frame_cache/.gitkeep # session workspace (push X — 작업 흐름 trace, 사용자 결정 2026-05-08) forex/ diff --git a/Front/client/src/components/FramePanel.tsx b/Front/client/src/components/FramePanel.tsx index c7f383a..050540e 100644 --- a/Front/client/src/components/FramePanel.tsx +++ b/Front/client/src/components/FramePanel.tsx @@ -19,6 +19,20 @@ interface FramePanelProps { onNoDesignToggle: () => void; } +// ─── IMP-41 u3 — application_mode consequence tooltip map (issue #70) ──────── +// Keyed by application_mode VALUE (backend authoritative), NOT V4 label. +// Source = src/phase_z2_pipeline.py APPLICATION_MODE_BY_V4_LABEL (:107-112) +// emitted via Step 9 unit.application_candidates[] and forwarded by +// designAgentApi.ts (IMP-41 u2). When applicationMode is absent (legacy +// fixtures pre-IMP-32, or candidate filtered out at Step 9) the tooltip +// falls back to the raw V4 label string per Stage 2 contract. +const APPLICATION_MODE_TOOLTIP_KR: Record = { + direct_insert: "코드 직접 적용", + same_frame_with_adjustment: "AI 보강 필요", + layout_or_region_change: "AI restructure 필요", + exclude: "render path 제외", +}; + export default function FramePanel({ slidePlan, selectedZone, @@ -46,6 +60,26 @@ export default function FramePanel({ return userSelection.overrides.zone_frames[targetRegion.id] || targetRegion.frame_match_strategy.frame_id; }, [selectedZone, selectedRegion, userSelection.overrides.zone_frames]); + // IMP-47B u11 — reject-click confirm guard. Per #76 policy: 사용자가 reject + // 카드 명시 클릭 → backend `--override-frame` 전달 + reject frame 유지 + AI 재구성. + // The window.confirm makes the AI-rebuild intent explicit (deselecting an + // already-applied reject frame does not prompt). Pure UX gate — no state + // mutation here; the parent `onFrameSelect` still owns the override apply. + const handleFrameSelect = React.useCallback( + (candidate: FrameCandidate) => { + const isReject = candidate.label === "reject"; + const alreadyApplied = currentFrameId === candidate.id; + if (isReject && !alreadyApplied) { + const ok = window.confirm( + `"${candidate.name}" 은 V4 reject 라벨입니다.\n선택 시 frame 은 유지되고 AI 가 콘텐츠를 frame 구조에 맞게 재구성합니다.\n계속하시겠습니까?`, + ); + if (!ok) return; + } + onFrameSelect(candidate.id); + }, + [currentFrameId, onFrameSelect], + ); + if (!selectedZone) { return (
@@ -151,7 +185,7 @@ export default function FramePanel({ className="w-full" >