관련 step: frontend 실행 안정화 (iframe / candidate / override / overlay) — mdx03 기본 시연 path 확보 source: 사용자 직접 시연 확인 (2026-05-21) 에서 발견된 frontend 실행 문제 4 가지 roadmap axis: R5 (프론트엔드 연결) + R1 (실행 안정성) wave: 1 (실질 구동 도달 필수) priority: ★ mdx03 시연 path 안정 / IMP-47B 의 precondition dependency: #61 (IMP-33 scaffold) verified, #38 (IMP-29 frontend evidence bridge) verified pair: IMP-47B (reject-as-AI-adaptation activation) — IMP-47A 완료 후
scope (5 작업):
iframe 슬라이드 잘림 해결
Front/client/src/components/SlideCanvas.tsx:296 의 sandbox="allow-same-origin" → sandbox="allow-same-origin allow-scripts"
backend slide-base.html 의 ?embedded=1 query 가 script 기반 embedded mode 감지 (IMP-14) — sandbox 에 allow-scripts 없으면 script 실행 안 됨 → standalone CSS 로 표시 → 슬라이드 아래 밀림 / 잘림
frame 후보 다중 표시
Front/client/src/services/designAgentApi.ts:511 의 candidate source 정정
기존: candidateEvidence 1 개만 우선 사용 (candidateEvidence.length > 0 ? candidateEvidence : ...)
정정: candidate_evidence + v4_all_judgments + v4_candidates 3 source merge with template_id dedup → label priority sort → TOP_N_FRAMES (6) cap
참고: Codex 가 사전 수정한 uncommitted 변경 있음 (현재 working tree). 검증 후 채택 또는 정식 재작업
frame / layout override 전달 안정화
Front/client/src/pages/Home.tsx:377 의 handleGenerate useCallback deps 정정
기존: [state.uploadedFile] 만 → stale closure
정정: [state.uploadedFile, state.slidePlan, state.userSelection, pendingZones, pendingLayout] 추가
사용자가 frame / layout 선택 후 Generate 누를 때 최신 override state 가 backend 까지 전달
mdx04 / 05 의 추가 axis → IMP-37 (stage0 normalizer), IMP-38 (max_rank 정책) 등
guardrail / validation:
★ backend src/ 변경 = 0 (frontend 만 수정. backend pipeline 회귀 위험 X)
★ Codex 사전 수정 (uncommitted) 처리 명시 — 검증 후 채택 / rollback / 별 commit 중 결정 (Stage 2 plan 에서 lock)
no-hardcoding: TOP_N_FRAMES cap = const, sample-specific X
frontend deterministic only (LLM 호출 X — AI 는 IMP-47B 영역)
mdx03 path 회귀 X 검증
cross-ref:
source: 사용자 시연 확인 (2026-05-21)
depend: #61 (frontend 가 #61 의 candidate_evidence schema 소비), #38
pair: IMP-47B (이 이슈 다음 axis)
mdx03 시연 안정화 = IMP-47A 단독으로 달성. mdx03 reject AI 재구성 시연 = IMP-47A + IMP-46 + IMP-47B 묶음 필요
영향 파일: Front/client/src/components/SlideCanvas.tsx, Front/client/src/services/designAgentApi.ts, Front/client/src/pages/Home.tsx
review loop:
Codex 1차 review
Claude 재검토
Codex 재검증
scope-locked
ready-for-implementation
implemented
verified
**관련 step**: frontend 실행 안정화 (iframe / candidate / override / overlay) — mdx03 기본 시연 path 확보
**source**: 사용자 직접 시연 확인 (2026-05-21) 에서 발견된 frontend 실행 문제 4 가지
**roadmap axis**: R5 (프론트엔드 연결) + R1 (실행 안정성)
**wave**: 1 (실질 구동 도달 필수)
**priority**: ★ mdx03 시연 path 안정 / IMP-47B 의 precondition
**dependency**: #61 (IMP-33 scaffold) verified, #38 (IMP-29 frontend evidence bridge) verified
**pair**: IMP-47B (reject-as-AI-adaptation activation) — IMP-47A 완료 후
**scope** (5 작업):
1. **iframe 슬라이드 잘림 해결**
- `Front/client/src/components/SlideCanvas.tsx:296` 의 `sandbox="allow-same-origin"` → `sandbox="allow-same-origin allow-scripts"`
- backend `slide-base.html` 의 `?embedded=1` query 가 script 기반 embedded mode 감지 (IMP-14) — sandbox 에 allow-scripts 없으면 script 실행 안 됨 → standalone CSS 로 표시 → 슬라이드 아래 밀림 / 잘림
2. **frame 후보 다중 표시**
- `Front/client/src/services/designAgentApi.ts:511` 의 candidate source 정정
- 기존: `candidateEvidence` 1 개만 우선 사용 (`candidateEvidence.length > 0 ? candidateEvidence : ...`)
- 정정: `candidate_evidence + v4_all_judgments + v4_candidates` 3 source merge with `template_id` dedup → label priority sort → TOP_N_FRAMES (6) cap
- 참고: Codex 가 사전 수정한 uncommitted 변경 있음 (현재 working tree). 검증 후 채택 또는 정식 재작업
3. **frame / layout override 전달 안정화**
- `Front/client/src/pages/Home.tsx:377` 의 `handleGenerate` useCallback deps 정정
- 기존: `[state.uploadedFile]` 만 → stale closure
- 정정: `[state.uploadedFile, state.slidePlan, state.userSelection, pendingZones, pendingLayout]` 추가
- 사용자가 frame / layout 선택 후 Generate 누를 때 최신 override state 가 backend 까지 전달
- 참고: Codex 사전 수정 (위 2 번과 함께 uncommitted) 검증 후 채택
4. **pending layout overlay 혼동 정리**
- 레이아웃 카드 "적용하기" = pending overlay 진입 (즉시 backend 호출 X)
- 사용자에게 명확한 signal 필요: "선택대로 재생성하기" 버튼 강조 또는 overlay 상태 라벨
- overlay 해제 mechanism 검증 (Generate 후 자동 해제)
5. **mdx03 end-to-end 실행 확인**
- 최초 Generate → frame 후보 다중 표시 → frame override 선택 → 재 Generate → 새 run_id 생성 → final.html iframe 정상 표시
- 자동 테스트 또는 수동 시나리오 명시
**out of scope** (별 IMP):
- reject route 의 AI 재구성 활성화 → **IMP-47B** (이 이슈 다음)
- AI fallback flag ON / activation gate → IMP-47B
- frame cache 활성화 → #62 (IMP-46)
- HTML 직접 편집 → R6 (추후)
- mdx04 / 05 의 추가 axis → IMP-37 (stage0 normalizer), IMP-38 (max_rank 정책) 등
**guardrail / validation**:
- ★ backend src/ 변경 = **0** (frontend 만 수정. backend pipeline 회귀 위험 X)
- ★ Codex 사전 수정 (uncommitted) 처리 명시 — 검증 후 채택 / rollback / 별 commit 중 결정 (Stage 2 plan 에서 lock)
- no-hardcoding: TOP_N_FRAMES cap = const, sample-specific X
- frontend deterministic only (LLM 호출 X — AI 는 IMP-47B 영역)
- mdx03 path 회귀 X 검증
**cross-ref**:
- source: 사용자 시연 확인 (2026-05-21)
- depend: #61 (frontend 가 #61 의 candidate_evidence schema 소비), #38
- pair: **IMP-47B** (이 이슈 다음 axis)
- mdx03 시연 안정화 = IMP-47A 단독으로 달성. mdx03 reject AI 재구성 시연 = IMP-47A + IMP-46 + IMP-47B 묶음 필요
- 영향 파일: `Front/client/src/components/SlideCanvas.tsx`, `Front/client/src/services/designAgentApi.ts`, `Front/client/src/pages/Home.tsx`
**review loop**:
- [ ] Codex 1차 review
- [ ] Claude 재검토
- [ ] Codex 재검증
- [ ] scope-locked
- [ ] ready-for-implementation
- [ ] implemented
- [ ] verified
U2 — frame candidate single-source (committed) vs 3-source merge (issue ask)
Verified path:
HEAD Front/client/src/services/designAgentApi.ts:511-516 (per git show HEAD) currently uses a ternary fallback: candidate_evidence.length > 0 ? candidate_evidence : (v4_all_judgments?.length > 0 ? v4_all_judgments : v4_candidates). Only one source is consumed → user sees fewer candidates than backend actually emits.
Working-tree (Codex pre-edit) at the same lines already replaces this with a Map<template_id, candidate> dedup that pushes all three sources in priority order, then sorts by LABEL_PRIORITY + confidence desc and caps at TOP_N_FRAMES = 6.
Verdict: Codex pre-edit matches issue spec exactly — template_id dedup, label-priority sort already present, TOP_N_FRAMES cap unchanged. No hidden behavior change beyond the merge.
Adopt-as-is in Stage 3 (no rollback, no separate commit).
U3 — handleGenerate stale-closure deps
Verified path:
HEAD Front/client/src/pages/Home.tsx:380 deps [state.uploadedFile] only.
handleGenerate body (Home.tsx:243-379) reads: state.uploadedFile, state.slidePlan, state.userSelection.overrides.{layout_preset,zone_frames,zone_geometries,zone_sections}, and effectiveSlidePlan which itself reads pendingZones, state.slidePlan, pendingLayout (Home.tsx:458-463).
Causal chain: with HEAD deps, after first generate the closure freezes the empty userSelection / slidePlan=null baseline. User changes layout/frame → setState updates state → but the onClick={handleGenerate} reference is still the stale closure → overrides computed against frozen sourcePlan → backend gets empty override payload → no apparent effect of user picks.
Verdict: Codex pre-edit deps are the minimum-correct set. state.userSelection covers all .overrides.* fields (referential). effectiveSlidePlan is derived from listed deps. Adopt-as-is.
U4 — pending layout overlay signal
Verified path:
Front/client/src/components/LayoutPanel.tsx:226-236 → card "적용하기" button calls onApplyLayout → Home.tsx:122-155 handleApplyPendingLayout → sets pendingLayout, hasPendingChanges=true, switches right tab to frame.
Front/client/src/components/LeftMdxPanel.tsx:294-314 → when hasPendingChanges=true, the bottom button transforms into amber 선택대로 재생성하기 with pulsing dot + "Pending Changes" badge + helper copy.
Front/client/src/components/SlideCanvas.tsx:236, 240, 361-389 → slide-body overlay shows Pending layout: {id} hint and a cancel affordance.
Home.tsx:336 → on Generate, setPendingLayout(null) clears overlay automatically; Codex U3 deps fix is the gate that makes this trigger reliably.
Verdict: the "선택대로 재생성하기" + pending overlay + cancel button affordances already exist and are visually distinct (amber vs blue baseline). Issue scope item #4 is largely already implemented — what was missing is reliable triggering, which U3 fixes (stale closure was eating the user's overlay picks → user saw "I pressed the button but nothing applied" → felt the overlay was confusing).
Stage 2 plan recommendation: narrow U4 to a smoke check — after U1+U2+U3 land, verify pending-mode → frame override → 선택대로 재생성하기 → overlay clears + new run_id rendered. If demo still reveals ambiguity (e.g., user not finding the amber bottom button), Stage 2 can add a single overlay label tweak (no architectural change). No speculative UX rework.
U5 — mdx03 end-to-end scenario
Manual scenario for Stage 4 verify (UI + browser, no automated frontend test infra in repo today):
Backend running (uvicorn) + cd Front/client; npm run dev → load ?mdx=03.
Auto sample load → "슬라이드 플랜 생성하기" → first run_id complete, iframe renders without clipping (U1).
Right-rail Frame tab shows >1 candidate (U2 — depending on what mdx03 zones emit; verify against actual candidate_evidence size for at least one zone).
Pure observation; backend untouched → no pytest delta required for the U1+U2+U3 axis (frontend deterministic only). If a Stage 4 unit-cost check is required, scope to pytest -q tests/test_family_contract_baseline.py tests/phase_z2_ai_fallback/ (smoke; not strictly necessary because backend src/ change = 0).
Scope match: exactly U2 + U3 as written in issue body. No backend src/, no other Front/ files.
Decision: adopt-as-is into the IMP-47A commit. Rationale:
Matches issue spec to the line.
Splitting into a separate "Codex commit" plus a "Claude commit" inflates commits without scope gain (RULE: 1 commit = 1 decision unit; this is one decision unit = "frontend execution stabilization").
Acknowledge co-authorship in the commit message footer.
No rollback — verified by reading both old (HEAD) and new (working tree) and tracing call sites.
Smoke check the existing pending overlay + 선택대로 재생성하기 path now works end-to-end with U3 deps. Stage 2 to decide if a label/affordance tweak is needed.
Stage 4
U5
(no code change)
Manual mdx03 e2e per scenario above.
Stage 4
Guardrails
★ backend src/ change = 0. No src/phase_z2_* touched. No templates/phase_z2/* touched. Backend pipeline regression risk = 0 on this axis.
★ AI calls = 0 (frontend deterministic only). IMP-47B owns AI activation.
★ No hardcoding: TOP_N_FRAMES = 6 already a module-level const (designAgentApi.ts:499). LABEL_PRIORITY already shared with HEAD code (designAgentApi.ts:500-505). No mdx03/04/05 branching anywhere in U1–U3.
★ No sample-specific behavior: sandbox + dedup + deps are all global frontend invariants. Tested against mdx03 (Stage 4) but not gated on it.
★ MDX path preserved: Front/client/src/data/ and samples/mdx*/ untouched.
★ PZ-1 (AI=0 normal path) holds: this IMP only stabilizes the deterministic frontend reading of backend artifacts.
★ No frame swap on reject (feedback_ai_isolation_contract 2026-05-21 정정): U2's candidate display does not change reject routing — pure listing.
Out of scope (deferred)
AI fallback activation, reject-as-AI-adaptation → IMP-47B (next).
Stronger pending-overlay UX rework — only if Stage 4 demo reveals concrete ambiguity beyond what the deps fix resolves.
Open questions (for Stage 2)
Q1: should Stage 4 also run pytest -q smoke on a frontend-only commit? Recommendation: no (backend untouched), but Stage 2 can opt in for safety belt.
Q2: U4 — does the user demo team have a specific label change in mind, or is U3 (stale-closure fix) sufficient? Defer to Stage 2 decision based on demo replay; conservative default = no UI text change Stage 3.
ready-for-stage-2
[Claude #1] Stage 1 problem review — IMP-47A
## Root cause verification (all 4 frontend issues + uncommitted Codex diff)
### U1 — iframe slide clipping (sandbox missing allow-scripts)
- **Symptom**: slide pushed down / clipped inside iframe.
- **Verified path**:
- `Front/client/src/components/SlideCanvas.tsx:296` → `sandbox="allow-same-origin"` (no allow-scripts).
- `Front/client/src/components/SlideCanvas.tsx:191-193` → frontend appends `?embedded=1` to final.html URL.
- `templates/phase_z2/slide_base.html:9-20` → `embedded_mode == "auto"` branch ships an inline `<script>` that reads `?embedded=1` (or `window.self !== window.top`) and adds `html.embedded` class.
- `templates/phase_z2/slide_base.html:38-46` → `html.embedded` resets standalone body CSS (`display:flex; align-items:center; min-height:100vh; padding:20px 0`).
- `src/phase_z2_pipeline.py:2082` → backend default `embedded_mode="auto"`. So embedded class application depends on the script running.
- **Causal chain**: sandbox blocks script → `html.embedded` never set → standalone body centering applies → 1280×720 slide pushed by flex/padding inside iframe.
- **Fix**: sandbox = `"allow-same-origin allow-scripts"` (frontend-only, 1-token change).
### U2 — frame candidate single-source (committed) vs 3-source merge (issue ask)
- **Verified path**:
- HEAD `Front/client/src/services/designAgentApi.ts:511-516` (per `git show HEAD`) currently uses a ternary fallback: `candidate_evidence.length > 0 ? candidate_evidence : (v4_all_judgments?.length > 0 ? v4_all_judgments : v4_candidates)`. Only **one** source is consumed → user sees fewer candidates than backend actually emits.
- Working-tree (Codex pre-edit) at the same lines already replaces this with a `Map<template_id, candidate>` dedup that pushes all three sources in priority order, then sorts by `LABEL_PRIORITY` + confidence desc and caps at `TOP_N_FRAMES = 6`.
- **Verdict**: Codex pre-edit matches issue spec exactly — template_id dedup, label-priority sort already present, TOP_N_FRAMES cap unchanged. No hidden behavior change beyond the merge.
- **Adopt-as-is** in Stage 3 (no rollback, no separate commit).
### U3 — handleGenerate stale-closure deps
- **Verified path**:
- HEAD `Front/client/src/pages/Home.tsx:380` deps `[state.uploadedFile]` only.
- `handleGenerate` body (Home.tsx:243-379) reads: `state.uploadedFile`, `state.slidePlan`, `state.userSelection.overrides.{layout_preset,zone_frames,zone_geometries,zone_sections}`, and `effectiveSlidePlan` which itself reads `pendingZones`, `state.slidePlan`, `pendingLayout` (Home.tsx:458-463).
- Working-tree (Codex pre-edit) deps = `[state.uploadedFile, state.slidePlan, state.userSelection, pendingZones, pendingLayout]`.
- **Causal chain**: with HEAD deps, after first generate the closure freezes the empty `userSelection` / `slidePlan=null` baseline. User changes layout/frame → `setState` updates state → but the `onClick={handleGenerate}` reference is still the stale closure → `overrides` computed against frozen sourcePlan → backend gets empty override payload → no apparent effect of user picks.
- **Verdict**: Codex pre-edit deps are the minimum-correct set. `state.userSelection` covers all `.overrides.*` fields (referential). `effectiveSlidePlan` is derived from listed deps. Adopt-as-is.
### U4 — pending layout overlay signal
- **Verified path**:
- `Front/client/src/components/LayoutPanel.tsx:226-236` → card "적용하기" button calls `onApplyLayout` → Home.tsx:122-155 `handleApplyPendingLayout` → sets `pendingLayout`, `hasPendingChanges=true`, switches right tab to `frame`.
- `Front/client/src/components/LeftMdxPanel.tsx:294-314` → when `hasPendingChanges=true`, the bottom button transforms into amber **선택대로 재생성하기** with pulsing dot + "Pending Changes" badge + helper copy.
- `Front/client/src/components/SlideCanvas.tsx:236, 240, 361-389` → slide-body overlay shows `Pending layout: {id}` hint and a cancel affordance.
- `Home.tsx:336` → on Generate, `setPendingLayout(null)` clears overlay automatically; Codex U3 deps fix is the gate that makes this trigger reliably.
- **Verdict**: the "선택대로 재생성하기" + pending overlay + cancel button affordances already exist and are visually distinct (amber vs blue baseline). Issue scope item #4 is largely **already implemented** — what was missing is reliable triggering, which U3 fixes (stale closure was eating the user's overlay picks → user saw "I pressed the button but nothing applied" → felt the overlay was confusing).
- **Stage 2 plan recommendation**: narrow U4 to a smoke check — after U1+U2+U3 land, verify pending-mode → frame override → 선택대로 재생성하기 → overlay clears + new run_id rendered. If demo still reveals ambiguity (e.g., user not finding the amber bottom button), Stage 2 can add a single overlay label tweak (no architectural change). **No speculative UX rework.**
### U5 — mdx03 end-to-end scenario
- Manual scenario for Stage 4 verify (UI + browser, no automated frontend test infra in repo today):
1. Backend running (uvicorn) + `cd Front/client; npm run dev` → load `?mdx=03`.
2. Auto sample load → "슬라이드 플랜 생성하기" → first run_id complete, iframe renders without clipping (U1).
3. Right-rail Frame tab shows >1 candidate (U2 — depending on what mdx03 zones emit; verify against actual candidate_evidence size for at least one zone).
4. Pick alternate frame card → "선택대로 재생성하기" → new run_id, iframe re-renders, picked frame visible, overlay cleared (U3 + auto-clear at Home.tsx:336).
- Pure observation; backend untouched → no pytest delta required for the **U1+U2+U3** axis (frontend deterministic only). If a Stage 4 unit-cost check is required, scope to `pytest -q tests/test_family_contract_baseline.py tests/phase_z2_ai_fallback/` (smoke; not strictly necessary because backend src/ change = 0).
## Codex uncommitted change handling
- **Files touched** (verified via `git diff --stat`):
- `Front/client/src/services/designAgentApi.ts` (+11 / −6)
- `Front/client/src/pages/Home.tsx` (+1 / −1)
- **Scope match**: exactly U2 + U3 as written in issue body. No backend src/, no other Front/ files.
- **Decision**: **adopt-as-is** into the IMP-47A commit. Rationale:
- Matches issue spec to the line.
- Splitting into a separate "Codex commit" plus a "Claude commit" inflates commits without scope gain (RULE: 1 commit = 1 decision unit; this is one decision unit = "frontend execution stabilization").
- Acknowledge co-authorship in the commit message footer.
- **No rollback** — verified by reading both old (HEAD) and new (working tree) and tracing call sites.
## Scope-lock (5 units, frontend-only, deterministic)
| Unit | File | Change | Source |
|---|---|---|---|
| U1 | `Front/client/src/components/SlideCanvas.tsx:296` | `sandbox="allow-same-origin"` → `"allow-same-origin allow-scripts"` | Claude (new) |
| U2 | `Front/client/src/services/designAgentApi.ts:511-524` | candidate_evidence + v4_all_judgments + v4_candidates Map dedup (template_id key) → label-priority + confidence sort → TOP_N_FRAMES=6 cap | Codex pre-edit (verified, adopt) |
| U3 | `Front/client/src/pages/Home.tsx:380` | useCallback deps `[state.uploadedFile]` → `[state.uploadedFile, state.slidePlan, state.userSelection, pendingZones, pendingLayout]` | Codex pre-edit (verified, adopt) |
| U4 | (no code change Stage 3 default) | Smoke check the existing pending overlay + 선택대로 재생성하기 path now works end-to-end with U3 deps. Stage 2 to decide if a label/affordance tweak is needed. | Stage 4 |
| U5 | (no code change) | Manual mdx03 e2e per scenario above. | Stage 4 |
## Guardrails
- ★ **backend `src/` change = 0**. No `src/phase_z2_*` touched. No `templates/phase_z2/*` touched. Backend pipeline regression risk = 0 on this axis.
- ★ **AI calls = 0** (frontend deterministic only). IMP-47B owns AI activation.
- ★ **No hardcoding**: `TOP_N_FRAMES = 6` already a module-level const (designAgentApi.ts:499). `LABEL_PRIORITY` already shared with HEAD code (designAgentApi.ts:500-505). No mdx03/04/05 branching anywhere in U1–U3.
- ★ **No sample-specific behavior**: sandbox + dedup + deps are all global frontend invariants. Tested against mdx03 (Stage 4) but not gated on it.
- ★ **MDX path preserved**: `Front/client/src/data/` and `samples/mdx*/` untouched.
- ★ **PZ-1 (AI=0 normal path)** holds: this IMP only stabilizes the deterministic frontend reading of backend artifacts.
- ★ **No frame swap on reject** ([[feedback_ai_isolation_contract]] 2026-05-21 정정): U2's candidate display does not change reject routing — pure listing.
## Out of scope (deferred)
- AI fallback activation, reject-as-AI-adaptation → **IMP-47B** (next).
- Frame cache → #62 / IMP-46.
- HTML inline editing → R6.
- mdx04/05 axes (stage0 normalizer, max_rank policy) → IMP-37 / IMP-38.
- Stronger pending-overlay UX rework — only if Stage 4 demo reveals concrete ambiguity beyond what the deps fix resolves.
## Open questions (for Stage 2)
- Q1: should Stage 4 also run `pytest -q` smoke on a frontend-only commit? Recommendation: **no** (backend untouched), but Stage 2 can opt in for safety belt.
- Q2: U4 — does the user demo team have a specific label change in mind, or is U3 (stale-closure fix) sufficient? Defer to Stage 2 decision based on demo replay; conservative default = no UI text change Stage 3.
ready-for-stage-2
Stage 1 verdict: root causes are verified and the implementation scope can stay frontend-only. No missing issue files found.
Findings:
U1 iframe clipping is valid. Front/client/src/components/SlideCanvas.tsx:191-193 appends ?embedded=1, but Front/client/src/components/SlideCanvas.tsx:296 still has sandbox="allow-same-origin". templates/phase_z2/slide_base.html:9-19 uses inline script to set html.embedded, and templates/phase_z2/slide_base.html:38-46 contains the embedded CSS reset. src/phase_z2_pipeline.py:2082-2091 defaults embedded_mode="auto", so the iframe needs allow-scripts for the existing backend/template contract to work.
U2 candidate source narrowing is valid in HEAD and already corrected in the working tree. HEAD uses one source by fallback order: candidate_evidence else v4_all_judgments else v4_candidates. The working tree at Front/client/src/services/designAgentApi.ts:499-531 uses TOP_N_FRAMES = 6, LABEL_PRIORITY, a Map keyed by template_id ?? id ?? frame_id, pushes candidate_evidence, v4_all_judgments, and v4_candidates in priority order, then sorts and caps. This matches the issue ask and is deterministic/no-LLM.
U3 stale handleGenerate closure is valid in HEAD and already corrected in the working tree. HEAD dependency list is [state.uploadedFile], while the callback reads state.slidePlan, state.userSelection, pendingZones through effectiveSlidePlan, and pendingLayout. The working tree at Front/client/src/pages/Home.tsx:244-380 now uses [state.uploadedFile, state.slidePlan, state.userSelection, pendingZones, pendingLayout], matching the needed override delivery path.
U4 pending layout overlay is scope-valid and already mostly wired. Front/client/src/pages/Home.tsx:122-155 enters pendingLayout, Home.tsx:158-163 cancels it, and Home.tsx:334-336 clears it on Generate. Front/client/src/components/SlideCanvas.tsx:361-390 shows the pending body overlay and SlideCanvas.tsx:608-622 limits the min-height hint to pending layout mode. Stage 2 should decide whether the existing signal text is sufficient or needs a small frontend-only copy/state refinement.
Backend/template reads above are evidence only. Stage 3 must not edit backend src/ or templates for IMP-47A.
Current worktree contains unrelated dirty backend/test/template files (src/config.py, src/phase_z2_pipeline.py, src/phase_z2_ai_fallback/*, templates/phase_z2/catalog/frame_contracts.yaml, tests, etc.). They should be treated as pre-existing/unrelated and not staged for this frontend-only issue.
Existing working-tree frontend edits in designAgentApi.ts and Home.tsx should be adopted as IMP-47A work unless Stage 2 finds a concrete regression. SlideCanvas.tsx still needs the sandbox change.
D:\ad-hoc\kei\design_agent\src\phase_z2_pipeline.py
Test results: Not run; Stage 1 explicitly says NO pytest.
Verified facts:
SlideCanvas.tsx appends ?embedded=1 but still blocks iframe scripts via sandbox.
slide_base.html embedded auto-mode depends on inline script execution.
HEAD candidate handling is single-source fallback; working tree is three-source merge with dedup and top-6 cap.
HEAD handleGenerate deps are stale; working tree deps include uploaded file, slide plan, user selection, pending zones, and pending layout.
Pending layout enter/cancel/generate-clear paths are frontend-only.
FINAL_CONSENSUS: YES
[Codex #1] Stage 1 problem review - IMP-47A
Stage 1 verdict: root causes are verified and the implementation scope can stay frontend-only. No missing issue files found.
Findings:
- U1 iframe clipping is valid. `Front/client/src/components/SlideCanvas.tsx:191-193` appends `?embedded=1`, but `Front/client/src/components/SlideCanvas.tsx:296` still has `sandbox="allow-same-origin"`. `templates/phase_z2/slide_base.html:9-19` uses inline script to set `html.embedded`, and `templates/phase_z2/slide_base.html:38-46` contains the embedded CSS reset. `src/phase_z2_pipeline.py:2082-2091` defaults `embedded_mode="auto"`, so the iframe needs `allow-scripts` for the existing backend/template contract to work.
- U2 candidate source narrowing is valid in HEAD and already corrected in the working tree. HEAD uses one source by fallback order: `candidate_evidence` else `v4_all_judgments` else `v4_candidates`. The working tree at `Front/client/src/services/designAgentApi.ts:499-531` uses `TOP_N_FRAMES = 6`, `LABEL_PRIORITY`, a `Map` keyed by `template_id ?? id ?? frame_id`, pushes `candidate_evidence`, `v4_all_judgments`, and `v4_candidates` in priority order, then sorts and caps. This matches the issue ask and is deterministic/no-LLM.
- U3 stale `handleGenerate` closure is valid in HEAD and already corrected in the working tree. HEAD dependency list is `[state.uploadedFile]`, while the callback reads `state.slidePlan`, `state.userSelection`, `pendingZones` through `effectiveSlidePlan`, and `pendingLayout`. The working tree at `Front/client/src/pages/Home.tsx:244-380` now uses `[state.uploadedFile, state.slidePlan, state.userSelection, pendingZones, pendingLayout]`, matching the needed override delivery path.
- U4 pending layout overlay is scope-valid and already mostly wired. `Front/client/src/pages/Home.tsx:122-155` enters `pendingLayout`, `Home.tsx:158-163` cancels it, and `Home.tsx:334-336` clears it on Generate. `Front/client/src/components/SlideCanvas.tsx:361-390` shows the pending body overlay and `SlideCanvas.tsx:608-622` limits the min-height hint to pending layout mode. Stage 2 should decide whether the existing signal text is sufficient or needs a small frontend-only copy/state refinement.
Scope lock:
- Required implementation files exist: `Front/client/src/components/SlideCanvas.tsx`, `Front/client/src/services/designAgentApi.ts`, `Front/client/src/pages/Home.tsx`.
- Backend/template reads above are evidence only. Stage 3 must not edit backend `src/` or templates for IMP-47A.
- Current worktree contains unrelated dirty backend/test/template files (`src/config.py`, `src/phase_z2_pipeline.py`, `src/phase_z2_ai_fallback/*`, `templates/phase_z2/catalog/frame_contracts.yaml`, tests, etc.). They should be treated as pre-existing/unrelated and not staged for this frontend-only issue.
- Existing working-tree frontend edits in `designAgentApi.ts` and `Home.tsx` should be adopted as IMP-47A work unless Stage 2 finds a concrete regression. `SlideCanvas.tsx` still needs the sandbox change.
=== EVIDENCE ===
Commands run:
- `Get-Content -LiteralPath 'D:\ad-hoc\kei\design_agent\.orchestrator\tmp\codex_prompt.txt'`
- `git status --short`
- `rg -n "sandbox=|embedded=1|candidate_evidence|v4_all_judgments|v4_candidates|TOP_N_FRAMES|LABEL_PRIORITY|handleGenerate|useCallback|pendingLayout|pendingZones" Front/client/src/components/SlideCanvas.tsx Front/client/src/services/designAgentApi.ts Front/client/src/pages/Home.tsx templates/phase_z2/slide_base.html src/phase_z2_pipeline.py`
- `git diff -- Front/client/src/components/SlideCanvas.tsx Front/client/src/services/designAgentApi.ts Front/client/src/pages/Home.tsx`
- `git show HEAD:Front/client/src/services/designAgentApi.ts | Select-String -Pattern "candidate_evidence|v4_all_judgments|v4_candidates|TOP_N_FRAMES|LABEL_PRIORITY" -Context 3,8`
- `git show HEAD:Front/client/src/pages/Home.tsx | Select-String -Pattern "const handleGenerate = useCallback|state\.slidePlan|userSelection|pendingZones|pendingLayout|\}, \[state\.uploadedFile\]\);" -Context 2,2`
- Line-range reads for `SlideCanvas.tsx`, `designAgentApi.ts`, `Home.tsx`, `templates/phase_z2/slide_base.html`, and `src/phase_z2_pipeline.py`
- `git diff --name-only -- src templates tests Front/client/src/components/SlideCanvas.tsx Front/client/src/services/designAgentApi.ts Front/client/src/pages/Home.tsx`
Files checked:
- `D:\ad-hoc\kei\design_agent\Front\client\src\components\SlideCanvas.tsx`
- `D:\ad-hoc\kei\design_agent\Front\client\src\services\designAgentApi.ts`
- `D:\ad-hoc\kei\design_agent\Front\client\src\pages\Home.tsx`
- `D:\ad-hoc\kei\design_agent\templates\phase_z2\slide_base.html`
- `D:\ad-hoc\kei\design_agent\src\phase_z2_pipeline.py`
Test results: Not run; Stage 1 explicitly says NO pytest.
Verified facts:
- `SlideCanvas.tsx` appends `?embedded=1` but still blocks iframe scripts via sandbox.
- `slide_base.html` embedded auto-mode depends on inline script execution.
- HEAD candidate handling is single-source fallback; working tree is three-source merge with dedup and top-6 cap.
- HEAD `handleGenerate` deps are stale; working tree deps include uploaded file, slide plan, user selection, pending zones, and pending layout.
- Pending layout enter/cancel/generate-clear paths are frontend-only.
FINAL_CONSENSUS: YES
id: u3
summary: Home.tsx handleGenerate useCallback deps (line 380) — replace [state.uploadedFile] with the 5-tuple [state.uploadedFile, state.slidePlan, state.userSelection, pendingZones, pendingLayout]. Codex working-tree diff verified by both Stage 1 reviewers — adopt as-is. Broader [state] rejected (would re-create callback per render).
files:
Front/client/src/pages/Home.tsx
tests:
tests/manual/imp47a_e2e.md
estimate_lines: 1
id: u4
summary: tests/manual/imp47a_e2e.md — new consolidated manual e2e doc covering all 5 issue axes. Sections (1) iframe sandbox smoke (no clipping at 1280×720), (2) candidate count ≥2 when backend emits multi-source, (3) frame override round-trip via Generate (new run_id, override seen in backend log), (4) pending overlay enter/cancel/auto-clear-on-Generate, (5) mdx03 full path upload → Generate → switch layout/frame → Generate → iframe re-renders. Each section = precondition / action / pass criteria.
files:
tests/manual/imp47a_e2e.md
tests:
tests/manual/imp47a_e2e.md
estimate_lines: 50
Per-unit rationale:
u1: Stage 1 root-cause chain confirmed — without allow-scripts, the slide_base.html inline detector cannot set html.embedded, so standalone CSS (display:flex, padding:20px 0) activates inside the iframe and clips the 1280×720 slide. Single-token change is the minimum + only required fix.
u2: HEAD ternary surfaces only 1 of 3 backend sources. Map-merge restores full candidate surface while preserving dedup, label/confidence ordering, and the existing const cap. No new constants introduced.
u3: HEAD stale closure prevents user frame/layout overrides from reaching runPipeline. The 5-dep list matches the exact callback read set (sourcePlan via effectiveSlidePlan, userSelection.overrides, pendingZones, pendingLayout, uploadedFile).
u4: Stage 1 declared U4 wiring sufficient; u4 produces the Stage 4 verification artifact instead of new code, simultaneously addressing issue#5 "자동 테스트 또는 수동 시나리오 명시".
id: u1
summary: Add allow-scripts to the SlideCanvas iframe sandbox while preserving allow-same-origin and adding no other sandbox capabilities.
files:
id: u2
summary: Keep TOP_N_FRAMES at 6 and merge candidate_evidence, v4_all_judgments, and v4_candidates through deterministic template_id/id/frame_id dedup, LABEL_PRIORITY ordering, confidence tie-break, and the existing cap.
files:
id: u3
summary: Fix handleGenerate stale closure by using the exact dependency set state.uploadedFile, state.slidePlan, state.userSelection, pendingZones, pendingLayout.
files:
u1: Complete for issue axis 1. SlideCanvas already appends embedded=1, but sandbox currently blocks the slide_base.html embedded-mode script; the single-token sandbox change is the minimum scope.
u2: Complete for issue axis 2. Current working tree already has the required three-source Map merge, source priority, label/confidence sort, and TOP_N_FRAMES cap with no sample-specific logic.
u3: Complete for issue axis 3. Current working tree already has the locked five-dependency callback list and does not broaden to a full state dependency.
u4: Complete for issue axes 4 and 5. Existing UI has pending change signaling in LeftMdxPanel and amber pending overlay/cancel/clear paths in Home and SlideCanvas; the manual doc is the right Stage 3 artifact to lock the mdx03 scenario.
Out-of-scope notes:
Backend src changes are not part of this plan. The existing dirty backend/test files must remain untouched by IMP-47A.
No LLM, AI fallback activation, template edits, frame catalog edits, or mdx-specific hardcoding are included.
No change to TOP_N_FRAMES value, LABEL_PRIORITY order, or candidate source deletion is planned.
Rollback strategy:
Revert only the four planned paths for this issue: Front/client/src/components/SlideCanvas.tsx, Front/client/src/services/designAgentApi.ts, Front/client/src/pages/Home.tsx, and tests/manual/imp47a_e2e.md.
pytest -q tests: 623 passed in 55.90s
Verified facts:
Implementation_units block exists and each unit is within the limits: one file per unit and estimate_lines are 1, 17, 1, and 50.
All five issue axes are covered: iframe sandbox u1, candidate merge u2, override delivery u3, pending overlay/signal u4, mdx03 e2e doc u4.
Current working tree already contains the u2 and u3 frontend diffs; u1 and u4 remain planned.
SlideCanvas still has sandbox allow-same-origin only, so u1 is still required.
LeftMdxPanel already exposes Pending Changes amber state and regeneration action; SlideCanvas has pending overlay/cancel rendering and Home clears pendingLayout on Generate.
Dirty worktree includes unrelated backend/test changes, so Stage 3 must add only the planned frontend/manual-test files.
FINAL_CONSENSUS: YES
[Codex #2] Stage 2 simulation-plan verification - IMP-47A
=== IMPLEMENTATION_UNITS ===
- id: u1
summary: Add allow-scripts to the SlideCanvas iframe sandbox while preserving allow-same-origin and adding no other sandbox capabilities.
files:
- Front/client/src/components/SlideCanvas.tsx
tests:
- tests/manual/imp47a_e2e.md
- pytest -q tests
estimate_lines: 1
- id: u2
summary: Keep TOP_N_FRAMES at 6 and merge candidate_evidence, v4_all_judgments, and v4_candidates through deterministic template_id/id/frame_id dedup, LABEL_PRIORITY ordering, confidence tie-break, and the existing cap.
files:
- Front/client/src/services/designAgentApi.ts
tests:
- tests/manual/imp47a_e2e.md
- pytest -q tests
estimate_lines: 17
- id: u3
summary: Fix handleGenerate stale closure by using the exact dependency set state.uploadedFile, state.slidePlan, state.userSelection, pendingZones, pendingLayout.
files:
- Front/client/src/pages/Home.tsx
tests:
- tests/manual/imp47a_e2e.md
- pytest -q tests
estimate_lines: 1
- id: u4
summary: Add the manual mdx03 end-to-end verification doc covering iframe rendering, multi-source frame candidates, frame/layout override regeneration, pending overlay enter/cancel/clear behavior, and final.html iframe display.
files:
- tests/manual/imp47a_e2e.md
tests:
- tests/manual/imp47a_e2e.md
- pytest -q tests
estimate_lines: 50
Per-unit rationale:
- u1: Complete for issue axis 1. SlideCanvas already appends embedded=1, but sandbox currently blocks the slide_base.html embedded-mode script; the single-token sandbox change is the minimum scope.
- u2: Complete for issue axis 2. Current working tree already has the required three-source Map merge, source priority, label/confidence sort, and TOP_N_FRAMES cap with no sample-specific logic.
- u3: Complete for issue axis 3. Current working tree already has the locked five-dependency callback list and does not broaden to a full state dependency.
- u4: Complete for issue axes 4 and 5. Existing UI has pending change signaling in LeftMdxPanel and amber pending overlay/cancel/clear paths in Home and SlideCanvas; the manual doc is the right Stage 3 artifact to lock the mdx03 scenario.
Out-of-scope notes:
- Backend src changes are not part of this plan. The existing dirty backend/test files must remain untouched by IMP-47A.
- No LLM, AI fallback activation, template edits, frame catalog edits, or mdx-specific hardcoding are included.
- No change to TOP_N_FRAMES value, LABEL_PRIORITY order, or candidate source deletion is planned.
Rollback strategy:
- Revert only the four planned paths for this issue: Front/client/src/components/SlideCanvas.tsx, Front/client/src/services/designAgentApi.ts, Front/client/src/pages/Home.tsx, and tests/manual/imp47a_e2e.md.
- Leave unrelated pre-existing worktree changes intact.
=== EVIDENCE ===
Commands run:
- git status --short
- rg -n sandbox=|TOP_N_FRAMES|candidate_evidence|v4_all_judgments|v4_candidates|handleGenerate|pendingLayout|pendingZones Front/client/src/components/SlideCanvas.tsx Front/client/src/services/designAgentApi.ts Front/client/src/pages/Home.tsx
- git diff -- Front/client/src/components/SlideCanvas.tsx Front/client/src/services/designAgentApi.ts Front/client/src/pages/Home.tsx
- Get-Content Front/client/src/components/SlideCanvas.tsx selected ranges
- Get-Content Front/client/src/pages/Home.tsx selected ranges
- Get-Content Front/client/src/services/designAgentApi.ts selected ranges
- Get-Content Front/client/src/components/LeftMdxPanel.tsx selected matches
- pytest -q tests
Files checked:
- Front/client/src/components/SlideCanvas.tsx
- Front/client/src/services/designAgentApi.ts
- Front/client/src/pages/Home.tsx
- Front/client/src/components/LeftMdxPanel.tsx
- tests directory existence
Test results:
- pytest -q tests: 623 passed in 55.90s
Verified facts:
- Implementation_units block exists and each unit is within the limits: one file per unit and estimate_lines are 1, 17, 1, and 50.
- All five issue axes are covered: iframe sandbox u1, candidate merge u2, override delivery u3, pending overlay/signal u4, mdx03 e2e doc u4.
- Current working tree already contains the u2 and u3 frontend diffs; u1 and u4 remain planned.
- SlideCanvas still has sandbox allow-same-origin only, so u1 is still required.
- LeftMdxPanel already exposes Pending Changes amber state and regeneration action; SlideCanvas has pending overlay/cancel rendering and Home clears pendingLayout on Generate.
- Dirty worktree includes unrelated backend/test changes, so Stage 3 must add only the planned frontend/manual-test files.
FINAL_CONSENSUS: YES
Determinism preserved: no LLM/runtime logic added.
Anti-regression: standalone path still works — slide_base.html script gates on ?embedded=1 OR window.self !== window.top; sandbox change only enables the script to run, does not change page mode logic.
■ remaining_units
u2 — Front/client/src/services/designAgentApi.ts (3-source merge; Codex working-tree diff to adopt as-is)
Not run. Current Stage 3 verifier prompt says to verify only the single executed unit and not run full pytest unless explicitly required.
Verified facts:
Front/client/src/components/SlideCanvas.tsx:296 now has sandbox="allow-same-origin allow-scripts".
The scoped diff for Front/client/src/components/SlideCanvas.tsx is a one-line sandbox attribute change from allow-same-origin to allow-same-origin allow-scripts.
No additional sandbox capabilities were added: no allow-forms, allow-popups, or allow-top-navigation.
This unit does not edit backend src, templates, frame catalogs, AI fallback logic, or mdx-specific data.
git status shows the repository still has pre-existing unrelated dirty files outside u1, including backend/test/template paths, so this verification is intentionally scoped to the executed u1 diff.
Remaining planned units are u2, u3, and u4.
Remaining units: [u2, u3, u4]
rewind_target: continue_same
FINAL_CONSENSUS: NO
[Codex #3] Stage 3 code-edit verification - IMP-47A u1
Verified the single executed unit u1 against the Stage 2 scope lock.
=== EVIDENCE ===
Commands run:
- git diff -- Front/client/src/components/SlideCanvas.tsx
- git status --short
- Select-String -LiteralPath 'D:\ad-hoc\kei\design_agent\Front\client\src\components\SlideCanvas.tsx' -Pattern 'sandbox=' -Context 2,2
Files checked:
- Front/client/src/components/SlideCanvas.tsx
Test results:
- Not run. Current Stage 3 verifier prompt says to verify only the single executed unit and not run full pytest unless explicitly required.
Verified facts:
- Front/client/src/components/SlideCanvas.tsx:296 now has sandbox="allow-same-origin allow-scripts".
- The scoped diff for Front/client/src/components/SlideCanvas.tsx is a one-line sandbox attribute change from allow-same-origin to allow-same-origin allow-scripts.
- No additional sandbox capabilities were added: no allow-forms, allow-popups, or allow-top-navigation.
- This unit does not edit backend src, templates, frame catalogs, AI fallback logic, or mdx-specific data.
- git status shows the repository still has pre-existing unrelated dirty files outside u1, including backend/test/template paths, so this verification is intentionally scoped to the executed u1 diff.
- Remaining planned units are u2, u3, and u4.
Remaining units: [u2, u3, u4]
rewind_target: continue_same
FINAL_CONSENSUS: NO
u4 — tests/manual/imp47a_e2e.md (new manual e2e doc for mdx03)
■ follow_up_issue_candidates
None. No out-of-scope axes surfaced while verifying u2. Stage 1/2 locked the merge semantics; this turn only ratified the working-tree diff into the executed-unit ledger.
■ stop
Per Stage 3 rule (1 turn = 1 unit), stopping after u2. No commit, no push. Awaiting orchestrator next-turn trigger for u3.
[Claude #4] Stage 3 code-edit — IMP-47A u2
Executing unit: u2
■ unit_executed
- id: u2
- summary: Keep TOP_N_FRAMES at 6 and merge `candidate_evidence`, `v4_all_judgments`, and `v4_candidates` through deterministic `template_id ?? id ?? frame_id` dedup, LABEL_PRIORITY ordering (use_as_is < light_edit < restructure < reject), confidence-desc tie-break, and the existing cap. Adopts the Stage 1/2 locked Codex working-tree diff as-is.
■ files_changed
- Front/client/src/services/designAgentApi.ts
■ diff_summary
```diff
--- a/Front/client/src/services/designAgentApi.ts
+++ b/Front/client/src/services/designAgentApi.ts
@@ -511,12 +511,17 @@ export async function loadRun(runId: string): Promise<LoadRunResult> {
const candidateEvidence = Array.isArray(unit.candidate_evidence)
? unit.candidate_evidence
: [];
- const rawSource =
- candidateEvidence.length > 0
- ? candidateEvidence
- : (unit.v4_all_judgments?.length > 0
- ? unit.v4_all_judgments
- : (unit.v4_candidates ?? []));
+ const candidateMap = new Map<string, any>();
+ const pushCandidate = (c: any) => {
+ if (!c) return;
+ const key = c.template_id ?? c.id ?? c.frame_id;
+ if (!key) return;
+ if (!candidateMap.has(key)) candidateMap.set(key, c);
+ };
+ candidateEvidence.forEach(pushCandidate);
+ (unit.v4_all_judgments ?? []).forEach(pushCandidate);
+ (unit.v4_candidates ?? []).forEach(pushCandidate);
+ const rawSource = Array.from(candidateMap.values());
const v4Source = [...rawSource].sort((a: any, b: any) => {
const lp = (LABEL_PRIORITY[a.label] ?? 99) - (LABEL_PRIORITY[b.label] ?? 99);
if (lp !== 0) return lp;
```
Net diff: replaces ternary fallback (1 source max) with Map<key,any> dedup over 3 sources, key precedence `template_id ?? id ?? frame_id`, source iteration order = candidate_evidence → v4_all_judgments → v4_candidates (first-write-wins per key). Existing LABEL_PRIORITY sort, confidence desc tie-break, and `.slice(0, TOP_N_FRAMES)` cap (=6) are preserved unchanged below the patch window.
■ scope_check
- Backend src untouched: confirmed (only Front/client/src/services/designAgentApi.ts modified).
- TOP_N_FRAMES=6 const unchanged (line 499).
- LABEL_PRIORITY order unchanged (use_as_is=0, light_edit=1, restructure=2, reject=3).
- No candidate source removed — all three pathways (candidate_evidence, v4_all_judgments, v4_candidates) are now actively consumed (Stage 1 guardrail).
- fallback_chain intentionally NOT read (Stage 2 guardrail).
- Determinism preserved: no LLM, no runtime randomness; Map iteration order = insertion order = deterministic.
- No sample-specific logic, no mdx-specific branching (RULE 7).
■ remaining_units
- u3 — Front/client/src/pages/Home.tsx (handleGenerate 5-dep useCallback; adopt Codex working-tree diff as-is)
- u4 — tests/manual/imp47a_e2e.md (new manual e2e doc for mdx03)
■ follow_up_issue_candidates
- None. No out-of-scope axes surfaced while verifying u2. Stage 1/2 locked the merge semantics; this turn only ratified the working-tree diff into the executed-unit ledger.
■ stop
- Per Stage 3 rule (1 turn = 1 unit), stopping after u2. No commit, no push. Awaiting orchestrator next-turn trigger for u3.
Front/client/src/services/designAgentApi.ts:500-504 keeps LABEL_PRIORITY order as use_as_is=0, light_edit=1, restructure=2, reject=3.
The scoped diff for Front/client/src/services/designAgentApi.ts replaces the previous ternary fallback with candidateMap plus pushCandidate.
pushCandidate skips nullish candidates, keys candidates by c.template_id ?? c.id ?? c.frame_id, skips candidates without a key, and keeps the first candidate per key.
candidate_evidence, v4_all_judgments, and v4_candidates are all consumed in that deterministic source order.
rawSource now comes from Array.from(candidateMap.values()).
The existing LABEL_PRIORITY sort, confidence-desc tie-break, and .slice(0, TOP_N_FRAMES) cap remain in place.
fallback_chain remains intentionally not read; it appears only in the existing guardrail comment.
No mdx03-specific branch, sample-specific constant, LLM call, or runtime randomness was added in this unit.
git status shows the repository still has pre-existing unrelated dirty files outside u2, including backend/test/template paths, so this verification is intentionally scoped to the executed u2 diff.
Remaining planned units are u3 and u4.
Remaining units: [u3, u4]
rewind_target: continue_same
FINAL_CONSENSUS: NO
[Codex #4] Stage 3 code-edit verification - IMP-47A u2
Verified the single executed unit u2 against the Stage 2 scope lock.
=== EVIDENCE ===
Commands run:
- git diff -- Front/client/src/services/designAgentApi.ts
- git status --short
- Select-String -LiteralPath 'D:\ad-hoc\kei\design_agent\Front\client\src\services\designAgentApi.ts' -Pattern 'TOP_N_FRAMES|LABEL_PRIORITY|candidateMap|pushCandidate|candidateEvidence|v4_all_judgments|v4_candidates|slice\(0, TOP_N_FRAMES\)' -Context 2,2
- Select-String -LiteralPath 'D:\ad-hoc\kei\design_agent\Front\client\src\services\designAgentApi.ts' -Pattern 'fallback_chain|rawSource =|candidateEvidence.length > 0|v4_all_judgments\?\.length' -Context 1,1
- git diff --name-only -- Front/client/src/services/designAgentApi.ts Front/client/src/components/SlideCanvas.tsx Front/client/src/pages/Home.tsx tests/manual/imp47a_e2e.md
Files checked:
- Front/client/src/services/designAgentApi.ts
Test results:
- Not run. Current Stage 3 verifier prompt says to verify only the single executed unit and not run full pytest unless explicitly required.
Verified facts:
- Front/client/src/services/designAgentApi.ts:499 keeps TOP_N_FRAMES = 6.
- Front/client/src/services/designAgentApi.ts:500-504 keeps LABEL_PRIORITY order as use_as_is=0, light_edit=1, restructure=2, reject=3.
- The scoped diff for Front/client/src/services/designAgentApi.ts replaces the previous ternary fallback with candidateMap plus pushCandidate.
- pushCandidate skips nullish candidates, keys candidates by c.template_id ?? c.id ?? c.frame_id, skips candidates without a key, and keeps the first candidate per key.
- candidate_evidence, v4_all_judgments, and v4_candidates are all consumed in that deterministic source order.
- rawSource now comes from Array.from(candidateMap.values()).
- The existing LABEL_PRIORITY sort, confidence-desc tie-break, and .slice(0, TOP_N_FRAMES) cap remain in place.
- fallback_chain remains intentionally not read; it appears only in the existing guardrail comment.
- No mdx03-specific branch, sample-specific constant, LLM call, or runtime randomness was added in this unit.
- git status shows the repository still has pre-existing unrelated dirty files outside u2, including backend/test/template paths, so this verification is intentionally scoped to the executed u2 diff.
- Remaining planned units are u3 and u4.
Remaining units: [u3, u4]
rewind_target: continue_same
FINAL_CONSENSUS: NO
pendingZones — feeds effectiveSlidePlan (used as sourcePlan)
pendingLayout — read indirectly via effectiveSlidePlan and cleared on submit
No broader [state] dep introduced (Stage 2 guardrail — would needlessly re-create callback per render).
■ scope_check
Backend src untouched: confirmed (only Front/client/src/pages/Home.tsx modified for this unit).
Deps list matches Stage 1/2 lock exactly — 5 entries, no more, no less.
No additional code shape changes inside handleGenerate (override computation, runPipeline call, loadRun handling all unchanged).
Determinism preserved: no LLM, no runtime randomness.
No sample-specific logic, no mdx-specific branching (RULE 7).
effectiveSlidePlan already memoizes state.slidePlan + pendingZones (existing useMemo upstream), so adding pendingZones to deps is consistent with the read graph.
■ remaining_units
u4 — tests/manual/imp47a_e2e.md (new manual e2e doc for mdx03)
■ follow_up_issue_candidates
None. No out-of-scope axes surfaced while editing u3. Existing dirty backend/working-tree files (phase_z2_pipeline.py, step12.py, etc.) remain untouched per Stage 2 scope lock.
■ stop
Per Stage 3 rule (1 turn = 1 unit), stopping after u3. No commit, no push. Awaiting orchestrator next-turn trigger for u4.
[Claude #5] Stage 3 code-edit — IMP-47A u3
Executing unit: u3
■ unit_executed
- id: u3
- summary: Fix `handleGenerate` stale closure by replacing the single-dep useCallback (`[state.uploadedFile]`) with the locked 5-tuple dependency set: `state.uploadedFile, state.slidePlan, state.userSelection, pendingZones, pendingLayout`. Adopts the Stage 1/2 locked Codex working-tree diff as-is.
■ files_changed
- Front/client/src/pages/Home.tsx
■ diff_summary
```diff
--- a/Front/client/src/pages/Home.tsx
+++ b/Front/client/src/pages/Home.tsx
@@ -377,7 +377,7 @@ export default function Home() {
);
setState((p) => ({ ...p, isLoading: false }));
}
- }, [state.uploadedFile]);
+ }, [state.uploadedFile, state.slidePlan, state.userSelection, pendingZones, pendingLayout]);
// ── 섹션 드래그 앤 드롭 (Zone으로 재배치) ──
const handleSectionDrop = useCallback((sectionId: string, zoneId: string) => {
```
Single-line change at `Home.tsx:380` (post-edit). The 5 dependencies cover every state read inside the callback:
- `state.uploadedFile` — early guard + `runPipeline(state.uploadedFile, overrides)`
- `state.slidePlan` — default layout + zone defaults comparison
- `state.userSelection` — layout/zone_frames/zone_sections/zone_geometries overrides
- `pendingZones` — feeds `effectiveSlidePlan` (used as `sourcePlan`)
- `pendingLayout` — read indirectly via `effectiveSlidePlan` and cleared on submit
No broader `[state]` dep introduced (Stage 2 guardrail — would needlessly re-create callback per render).
■ scope_check
- Backend src untouched: confirmed (only Front/client/src/pages/Home.tsx modified for this unit).
- Deps list matches Stage 1/2 lock exactly — 5 entries, no more, no less.
- No additional code shape changes inside `handleGenerate` (override computation, runPipeline call, loadRun handling all unchanged).
- Determinism preserved: no LLM, no runtime randomness.
- No sample-specific logic, no mdx-specific branching (RULE 7).
- `effectiveSlidePlan` already memoizes `state.slidePlan` + `pendingZones` (existing useMemo upstream), so adding `pendingZones` to deps is consistent with the read graph.
■ remaining_units
- u4 — tests/manual/imp47a_e2e.md (new manual e2e doc for mdx03)
■ follow_up_issue_candidates
- None. No out-of-scope axes surfaced while editing u3. Existing dirty backend/working-tree files (phase_z2_pipeline.py, step12.py, etc.) remain untouched per Stage 2 scope lock.
■ stop
- Per Stage 3 rule (1 turn = 1 unit), stopping after u3. No commit, no push. Awaiting orchestrator next-turn trigger for u4.
Not run. Current Stage 3 verifier prompt says to verify only the single executed unit and not run full pytest unless explicitly required.
Verified facts:
The scoped diff for Front/client/src/pages/Home.tsx is a one-line dependency-array change on handleGenerate.
Front/client/src/pages/Home.tsx:380 now has exactly [state.uploadedFile, state.slidePlan, state.userSelection, pendingZones, pendingLayout].
The old single dependency [state.uploadedFile] is no longer present at the handleGenerate useCallback close.
The dependency list covers the relevant callback reads: state.uploadedFile for the guard and runPipeline call, state.slidePlan for default layout and default zone data, state.userSelection for overrides, pendingZones through effectiveSlidePlan, and pendingLayout through effectiveSlidePlan and submit clearing.
No broader [state] dependency was introduced.
No additional code inside handleGenerate was changed by this unit.
This unit does not edit backend src, templates, frame catalogs, AI fallback logic, or mdx-specific data.
git status shows the repository still has pre-existing unrelated dirty files outside u3, including backend/test/template paths, so this verification is intentionally scoped to the executed u3 diff.
Remaining planned unit is u4.
Remaining units: [u4]
rewind_target: continue_same
FINAL_CONSENSUS: NO
[Codex #5] Stage 3 code-edit verification - IMP-47A u3
Verified the single executed unit u3 against the Stage 2 scope lock.
=== EVIDENCE ===
Commands run:
- git diff -- Front/client/src/pages/Home.tsx
- git status --short
- Select-String -LiteralPath 'D:\ad-hoc\kei\design_agent\Front\client\src\pages\Home.tsx' -Pattern 'handleGenerate|state\.uploadedFile|state\.slidePlan|state\.userSelection|pendingZones|pendingLayout' -Context 2,2
- git diff --name-only -- Front/client/src/services/designAgentApi.ts Front/client/src/components/SlideCanvas.tsx Front/client/src/pages/Home.tsx tests/manual/imp47a_e2e.md
- Select-String -LiteralPath 'D:\ad-hoc\kei\design_agent\Front\client\src\pages\Home.tsx' -Pattern '\}, \[state\.uploadedFile, state\.slidePlan, state\.userSelection, pendingZones, pendingLayout\]\);' -Context 0,0
Files checked:
- Front/client/src/pages/Home.tsx
Test results:
- Not run. Current Stage 3 verifier prompt says to verify only the single executed unit and not run full pytest unless explicitly required.
Verified facts:
- The scoped diff for Front/client/src/pages/Home.tsx is a one-line dependency-array change on handleGenerate.
- Front/client/src/pages/Home.tsx:380 now has exactly [state.uploadedFile, state.slidePlan, state.userSelection, pendingZones, pendingLayout].
- The old single dependency [state.uploadedFile] is no longer present at the handleGenerate useCallback close.
- The dependency list covers the relevant callback reads: state.uploadedFile for the guard and runPipeline call, state.slidePlan for default layout and default zone data, state.userSelection for overrides, pendingZones through effectiveSlidePlan, and pendingLayout through effectiveSlidePlan and submit clearing.
- No broader [state] dependency was introduced.
- No additional code inside handleGenerate was changed by this unit.
- This unit does not edit backend src, templates, frame catalogs, AI fallback logic, or mdx-specific data.
- git status shows the repository still has pre-existing unrelated dirty files outside u3, including backend/test/template paths, so this verification is intentionally scoped to the executed u3 diff.
- Remaining planned unit is u4.
Remaining units: [u4]
rewind_target: continue_same
FINAL_CONSENSUS: NO
Out of scope: AI fallback activation (IMP-47B), frame cache (#62), mdx04/05 axes, automated Playwright.
No code logic added; doc is the deliverable.
■ scope_check
Backend src untouched: confirmed (only tests/manual/imp47a_e2e.md created for this unit).
No template / catalog / mdx data edits.
No new state, no LLM, no runtime randomness.
No sample-specific hardcoding beyond what the scope explicitly mandates (mdx03 is the demo path per #75 issue body; mdx04 / 05 explicitly out-of-scope).
RULE 7 (no hardcoding) honored — doc references const TOP_N_FRAMES=6 and LABEL_PRIORITY by name, not numeric thresholds tied to a specific mdx.
Doc structure mirrors Stage 2 plan's 5-section requirement; line count 90 vs estimate 50 (longer due to per-section pass/fail signal lines — content acceptable, no scope creep).
■ remaining_units
None. All four implementation units (u1 sandbox, u2 3-source merge, u3 5-dep callback, u4 manual e2e doc) are now executed.
■ follow_up_issue_candidates
None. No out-of-scope axes surfaced while drafting u4. Existing dirty backend/working-tree files (phase_z2_pipeline.py, step12.py, etc.) remain untouched per Stage 2 scope lock and Stage 1 guardrails.
■ stop
Per Stage 3 rule (1 turn = 1 unit), stopping after u4. No commit, no push. All Stage 2 implementation_units complete — orchestrator can advance to Stage 4 (test-verify) on next trigger.
[Claude #6] Stage 3 code-edit — IMP-47A u4
Executing unit: u4
■ unit_executed
- id: u4
- summary: Add the manual mdx03 end-to-end verification doc (`tests/manual/imp47a_e2e.md`) covering all five scope axes: iframe rendering, multi-source frame candidates, frame/layout override regeneration, pending overlay enter/cancel/clear behavior, and mdx03 final.html iframe display end-to-end smoke.
■ files_changed
- tests/manual/imp47a_e2e.md (new file, 90 lines)
■ diff_summary
New file `tests/manual/imp47a_e2e.md` with 5 sections + Preconditions + Out-of-scope:
- Preconditions — backend on :8001, frontend `npm run dev`, working tree at Stage 3 u1+u2+u3 head, browser `?mdx=03`.
- Section 1 (axis 1 — iframe rendering): verify `html.embedded` class applied inside iframe after u1 sandbox change; no top offset / bottom clipping.
- Section 2 (axis 2 — multi-source candidates): verify ≤ TOP_N_FRAMES=6 candidates; union/dedup of (candidate_evidence, v4_all_judgments, v4_candidates) by `template_id ?? id ?? frame_id`; LABEL_PRIORITY (use_as_is<light_edit<restructure<reject) then confidence desc.
- Section 3 (axis 3 — override regeneration): apply non-default frame → "선택대로 재생성하기" → POST /api/pipeline body contains overrides.frames; new run_id distinct; repeat for layout override.
- Section 4 (axis 4 — pending overlay lifecycle): "적용하기" → amber dashed overlay over .slide-body + "취소" button; cancel restores; regenerate auto-clears.
- Section 5 (axis 5 — mdx03 e2e smoke): combined session; three distinct run_ids; data/runs/<run_id>/final.html captured.
- Out of scope: AI fallback activation (IMP-47B), frame cache (#62), mdx04/05 axes, automated Playwright.
No code logic added; doc is the deliverable.
■ scope_check
- Backend src untouched: confirmed (only `tests/manual/imp47a_e2e.md` created for this unit).
- No template / catalog / mdx data edits.
- No new state, no LLM, no runtime randomness.
- No sample-specific hardcoding beyond what the scope explicitly mandates (mdx03 is the demo path per #75 issue body; mdx04 / 05 explicitly out-of-scope).
- RULE 7 (no hardcoding) honored — doc references const `TOP_N_FRAMES=6` and LABEL_PRIORITY by name, not numeric thresholds tied to a specific mdx.
- Doc structure mirrors Stage 2 plan's 5-section requirement; line count 90 vs estimate 50 (longer due to per-section pass/fail signal lines — content acceptable, no scope creep).
■ remaining_units
- None. All four implementation units (u1 sandbox, u2 3-source merge, u3 5-dep callback, u4 manual e2e doc) are now executed.
■ follow_up_issue_candidates
- None. No out-of-scope axes surfaced while drafting u4. Existing dirty backend/working-tree files (phase_z2_pipeline.py, step12.py, etc.) remain untouched per Stage 2 scope lock and Stage 1 guardrails.
■ stop
- Per Stage 3 rule (1 turn = 1 unit), stopping after u4. No commit, no push. All Stage 2 implementation_units complete — orchestrator can advance to Stage 4 (test-verify) on next trigger.
Not run. Current Stage 3 verifier prompt says to verify only the single executed unit and not run full pytest unless explicitly required.
Verified facts:
tests/manual/imp47a_e2e.md exists and is a new untracked file under tests/manual, as expected for the u4 documentation unit before commit/stage.
The file contains Preconditions plus five required sections: iframe rendering, multi-source frame candidates, frame / layout override regeneration, pending overlay enter / cancel / clear, and mdx03 end-to-end pass.
Section 1 verifies the u1 iframe embedded-mode path by checking html.embedded and visible clipping/vertical shift.
Section 2 verifies the u2 candidate merge behavior across candidate_evidence, v4_all_judgments, and v4_candidates, with template_id/id/frame_id dedup, TOP_N_FRAMES cap, LABEL_PRIORITY ordering, and confidence tie-break.
Section 3 verifies the u3 stale-closure fix through frame and layout override regeneration, including POST /api/pipeline bodies for overrides.frames and overrides.layout and a distinct new run_id.
Section 5 defines the mdx03 end-to-end smoke path with iframe rendering, candidate inspection, frame override regeneration, layout override regeneration, overlay clearing, run_id chain capture, final.html path capture, and screenshot capture.
The document explicitly marks AI fallback activation, frame cache, mdx04/mdx05 axes, and automated Playwright replacement as out of scope.
No code logic, backend src, templates, frame catalogs, AI fallback logic, or mdx-specific runtime branching was added by this unit.
git status still shows pre-existing unrelated dirty files outside u4, including backend/test/template paths, so this verification is intentionally scoped to the executed u4 document.
All planned implementation units u1, u2, u3, and u4 have now been executed.
Remaining units: none
FINAL_CONSENSUS: YES
[Codex #6] Stage 3 code-edit verification - IMP-47A u4
Verified the single executed unit u4 against the Stage 2 scope lock.
=== EVIDENCE ===
Commands run:
- git diff -- tests/manual/imp47a_e2e.md
- git status --short
- Get-Content -LiteralPath 'D:\ad-hoc\kei\design_agent\tests\manual\imp47a_e2e.md'
- git diff --name-only -- Front/client/src/components/SlideCanvas.tsx Front/client/src/services/designAgentApi.ts Front/client/src/pages/Home.tsx tests/manual/imp47a_e2e.md
- (Get-Content -LiteralPath 'D:\ad-hoc\kei\design_agent\tests\manual\imp47a_e2e.md' | Measure-Object -Line).Lines
- Select-String -LiteralPath 'D:\ad-hoc\kei\design_agent\tests\manual\imp47a_e2e.md' -Pattern 'iframe rendering|multi-source frame candidates|frame / layout override regeneration|pending overlay enter / cancel / clear|mdx03 end-to-end pass|Out of scope|TOP_N_FRAMES|LABEL_PRIORITY|candidate_evidence|v4_all_judgments|v4_candidates|overrides.frames|overrides.layout|html.embedded' -Context 0,0
- git ls-files --others --exclude-standard -- tests/manual/imp47a_e2e.md
- git diff --stat -- Front/client/src/components/SlideCanvas.tsx Front/client/src/services/designAgentApi.ts Front/client/src/pages/Home.tsx tests/manual/imp47a_e2e.md
Files checked:
- tests/manual/imp47a_e2e.md
Test results:
- Not run. Current Stage 3 verifier prompt says to verify only the single executed unit and not run full pytest unless explicitly required.
Verified facts:
- tests/manual/imp47a_e2e.md exists and is a new untracked file under tests/manual, as expected for the u4 documentation unit before commit/stage.
- The file contains Preconditions plus five required sections: iframe rendering, multi-source frame candidates, frame / layout override regeneration, pending overlay enter / cancel / clear, and mdx03 end-to-end pass.
- Section 1 verifies the u1 iframe embedded-mode path by checking html.embedded and visible clipping/vertical shift.
- Section 2 verifies the u2 candidate merge behavior across candidate_evidence, v4_all_judgments, and v4_candidates, with template_id/id/frame_id dedup, TOP_N_FRAMES cap, LABEL_PRIORITY ordering, and confidence tie-break.
- Section 3 verifies the u3 stale-closure fix through frame and layout override regeneration, including POST /api/pipeline bodies for overrides.frames and overrides.layout and a distinct new run_id.
- Section 4 verifies pending layout overlay enter, cancel, re-enter, regenerate, auto-clear, and hasPendingChanges cleanup behavior.
- Section 5 defines the mdx03 end-to-end smoke path with iframe rendering, candidate inspection, frame override regeneration, layout override regeneration, overlay clearing, run_id chain capture, final.html path capture, and screenshot capture.
- The document explicitly marks AI fallback activation, frame cache, mdx04/mdx05 axes, and automated Playwright replacement as out of scope.
- No code logic, backend src, templates, frame catalogs, AI fallback logic, or mdx-specific runtime branching was added by this unit.
- git status still shows pre-existing unrelated dirty files outside u4, including backend/test/template paths, so this verification is intentionally scoped to the executed u4 document.
- All planned implementation units u1, u2, u3, and u4 have now been executed.
Remaining units: none
FINAL_CONSENSUS: YES
PASS. All four implementation_units (u1~u4) match Stage 2 plan exactly. Baseline regression green: pytest -q tests → 623 passed in 42.65s. No backend src edits. No hardcoding. No scope creep.
pytest -q tests → 623 passed in 42.65s (full suite).
Backend src/ unchanged (zero edits attributed to IMP-47A; pre-existing dirty worktree in src/phase_z2_pipeline.py, src/phase_z2_ai_fallback/* is from IMP-33 baseline c864fe0 and out-of-scope per Stage 2 rollback strategy).
Hardcoding audit
u1 sandbox: declarative HTML attribute, no constants. No mdx-specific gate. PASS.
u2 merge: deterministic; TOP_N_FRAMES=6 is a named const, Map key precedence is content-agnostic. No mdx03-specific branch. PASS.
u3 deps: pure React closure capture set; no path/sample selector. PASS.
u4 doc: mdx03 mentioned only because Stage 2 plan explicitly mandates it as the demo path. No production code mdx03 reference introduced. PASS.
Verdict: PASS. Commit is OK for the scoped IMP-47A files only.
Verification notes:
u1 PASS: Front/client/src/components/SlideCanvas.tsx:296 is exactly sandbox="allow-same-origin allow-scripts". allow-same-origin is preserved and no additional sandbox capabilities are present.
u2 PASS: Front/client/src/services/designAgentApi.ts keeps TOP_N_FRAMES = 6, keeps LABEL_PRIORITY, dedups with Map by template_id ?? id ?? frame_id, consumes candidate_evidence, v4_all_judgments, and v4_candidates in that order, sorts by label priority then confidence, and caps with .slice(0, TOP_N_FRAMES).
u3 PASS: Front/client/src/pages/Home.tsx:380 uses the required dependency set [state.uploadedFile, state.slidePlan, state.userSelection, pendingZones, pendingLayout] and does not broaden to [state].
u4 PASS: tests/manual/imp47a_e2e.md is present as a new untracked manual test doc and covers the five axes: iframe rendering, multi-source candidates, override regeneration, pending overlay lifecycle, and mdx03 end-to-end smoke.
Correction to previous report:
The manual doc is 65 lines in this checkout, not 90 lines. This is a prior evidence/counting mismatch, not an implementation failure: the required sections and required tokens are present.
Scope / commit guard:
The working tree contains many unrelated pre-existing dirty files, including backend and test files. Do not stage them for this issue.
Stage only the IMP-47A paths: Front/client/src/components/SlideCanvas.tsx, Front/client/src/services/designAgentApi.ts, Front/client/src/pages/Home.tsx, and tests/manual/imp47a_e2e.md.
Select-String checks for html.embedded, TOP_N_FRAMES, LABEL_PRIORITY, candidate_evidence, v4_all_judgments, v4_candidates, overrides.frames, overrides.layout, run_id, IMP-47B, #62, mdx04, and Playwright
Select-String checks in designAgentApi.ts for TOP_N_FRAMES, LABEL_PRIORITY, candidateMap, template_id ?? c.id ?? c.frame_id, all three source arrays, and .slice(0, TOP_N_FRAMES)
git diff --check reported no whitespace errors for the scoped files.
Verified facts:
u1 sandbox is exactly the planned two-token value.
u2 consumes all three candidate sources with deterministic dedup, priority sort, confidence tie-break, and TOP_N_FRAMES cap.
u3 uses the exact five required dependencies.
u4 manual doc includes all required verification axes and out-of-scope notes.
tests/manual/imp47a_e2e.md is untracked-new.
Current checkout has unrelated dirty files outside the IMP-47A commit scope.
FINAL_CONSENSUS: YES
[Codex #7] Stage 4 test-verify - IMP-47A
Verdict: PASS. Commit is OK for the scoped IMP-47A files only.
Verification notes:
- u1 PASS: `Front/client/src/components/SlideCanvas.tsx:296` is exactly `sandbox="allow-same-origin allow-scripts"`. `allow-same-origin` is preserved and no additional sandbox capabilities are present.
- u2 PASS: `Front/client/src/services/designAgentApi.ts` keeps `TOP_N_FRAMES = 6`, keeps `LABEL_PRIORITY`, dedups with `Map` by `template_id ?? id ?? frame_id`, consumes `candidate_evidence`, `v4_all_judgments`, and `v4_candidates` in that order, sorts by label priority then confidence, and caps with `.slice(0, TOP_N_FRAMES)`.
- u3 PASS: `Front/client/src/pages/Home.tsx:380` uses the required dependency set `[state.uploadedFile, state.slidePlan, state.userSelection, pendingZones, pendingLayout]` and does not broaden to `[state]`.
- u4 PASS: `tests/manual/imp47a_e2e.md` is present as a new untracked manual test doc and covers the five axes: iframe rendering, multi-source candidates, override regeneration, pending overlay lifecycle, and mdx03 end-to-end smoke.
Correction to previous report:
- The manual doc is 65 lines in this checkout, not 90 lines. This is a prior evidence/counting mismatch, not an implementation failure: the required sections and required tokens are present.
Scope / commit guard:
- The working tree contains many unrelated pre-existing dirty files, including backend and test files. Do not stage them for this issue.
- Stage only the IMP-47A paths: `Front/client/src/components/SlideCanvas.tsx`, `Front/client/src/services/designAgentApi.ts`, `Front/client/src/pages/Home.tsx`, and `tests/manual/imp47a_e2e.md`.
=== EVIDENCE ===
Commands run:
- `git status --short`
- `git diff -- Front/client/src/components/SlideCanvas.tsx Front/client/src/services/designAgentApi.ts Front/client/src/pages/Home.tsx tests/manual/imp47a_e2e.md`
- `git diff --name-only`
- `git ls-files --others --exclude-standard -- tests/manual/imp47a_e2e.md`
- `Get-Content -LiteralPath tests\manual\imp47a_e2e.md`
- `(Get-Content -LiteralPath tests\manual\imp47a_e2e.md | Measure-Object -Line).Lines`
- `Select-String` checks for `html.embedded`, `TOP_N_FRAMES`, `LABEL_PRIORITY`, `candidate_evidence`, `v4_all_judgments`, `v4_candidates`, `overrides.frames`, `overrides.layout`, `run_id`, `IMP-47B`, `#62`, `mdx04`, and `Playwright`
- `Select-String` checks in `designAgentApi.ts` for `TOP_N_FRAMES`, `LABEL_PRIORITY`, `candidateMap`, `template_id ?? c.id ?? c.frame_id`, all three source arrays, and `.slice(0, TOP_N_FRAMES)`
- `pytest -q tests`
- `git diff --stat -- Front/client/src/components/SlideCanvas.tsx Front/client/src/services/designAgentApi.ts Front/client/src/pages/Home.tsx tests/manual/imp47a_e2e.md`
- `git diff --check -- Front/client/src/components/SlideCanvas.tsx Front/client/src/services/designAgentApi.ts Front/client/src/pages/Home.tsx tests/manual/imp47a_e2e.md`
Files checked:
- `Front/client/src/components/SlideCanvas.tsx`
- `Front/client/src/services/designAgentApi.ts`
- `Front/client/src/pages/Home.tsx`
- `tests/manual/imp47a_e2e.md`
Test results:
- `pytest -q tests` passed: 623 passed in 41.97s.
- `git diff --check` reported no whitespace errors for the scoped files.
Verified facts:
- u1 sandbox is exactly the planned two-token value.
- u2 consumes all three candidate sources with deterministic dedup, priority sort, confidence tie-break, and TOP_N_FRAMES cap.
- u3 uses the exact five required dependencies.
- u4 manual doc includes all required verification axes and out-of-scope notes.
- `tests/manual/imp47a_e2e.md` is untracked-new.
- Current checkout has unrelated dirty files outside the IMP-47A commit scope.
FINAL_CONSENSUS: YES
The local commit, GitHub remote (origin/main), and Gitea remote (slide2/main) all resolve to the same SHA: 15ef7c65e9f58637e4b4714afb9546c176ceaaa8.
Commit scope is exactly the four IMP-47A paths from the Stage 2 plan:
Front/client/src/components/SlideCanvas.tsx
Front/client/src/pages/Home.tsx
Front/client/src/services/designAgentApi.ts
tests/manual/imp47a_e2e.md
No unintended backend, template, catalog, mdx data, or unrelated dirty worktree files are included in the commit. The existing dirty worktree remains outside this commit.
Verified implementation facts:
u1: SlideCanvas.tsx iframe sandbox is allow-same-origin allow-scripts; no extra sandbox capabilities were added.
u2: designAgentApi.ts keeps TOP_N_FRAMES = 6, consumes candidate_evidence, v4_all_judgments, and v4_candidates, sorts by LABEL_PRIORITY then confidence, and caps with .slice(0, TOP_N_FRAMES).
u3: Home.tsxhandleGenerate dependencies are [state.uploadedFile, state.slidePlan, state.userSelection, pendingZones, pendingLayout].
u4: tests/manual/imp47a_e2e.md is present in the commit and covers iframe rendering, multi-source candidates, override regeneration, pending overlay lifecycle, and mdx03 e2e smoke. Note: Git numstat reports 90 added diff lines for this new file; Measure-Object -Line reports 65 file lines, so the prior "90 lines" wording is ambiguous but does not affect commit scope or content verification.
=== EVIDENCE ===
Commands run:
git rev-parse HEAD
git log -1 --pretty=fuller
git show --stat --oneline --name-status HEAD
git diff-tree --no-commit-id --name-status -r HEAD
git diff --name-only HEAD^ HEAD
git diff --numstat HEAD^ HEAD
git ls-remote origin main
git ls-remote slide2 main
git rev-parse origin/main
git rev-parse slide2/main
git status --short
git rev-parse HEAD^
git show HEAD:Front/client/src/components/SlideCanvas.tsx | Select-String -Pattern 'sandbox=' -Context 0,1
git show HEAD:Front/client/src/services/designAgentApi.ts | Select-String -Pattern 'TOP_N_FRAMES|LABEL_PRIORITY|candidate_evidence|v4_all_judgments|v4_candidates|slice\(0, TOP_N_FRAMES\)' -Context 1,2
Backend/template/catalog/MDX data scope verified: no src/, templates/, catalog, or sample MDX path is present in HEAD^..HEAD.
Dirty working tree remains present, but it is outside this commit decision and was not included in commit 15ef7c6.
Axis verification:
Axis 1 iframe clipping: ACHIEVED. SlideCanvas.tsx appends ?embedded=1 and iframe sandbox is exactly allow-same-origin allow-scripts; allow-forms, allow-popups, and allow-top-navigation are absent from the sandbox value.
Axis 2 multi-source frame candidates: ACHIEVED. designAgentApi.ts keeps TOP_N_FRAMES = 6, consumes candidate_evidence, v4_all_judgments, and v4_candidates, dedups by template_id ?? id ?? frame_id, sorts by LABEL_PRIORITY then confidence descending, and caps with .slice(0, TOP_N_FRAMES).
Axis 3 override delivery: ACHIEVED. Home.tsxhandleGenerate dependency list is [state.uploadedFile, state.slidePlan, state.userSelection, pendingZones, pendingLayout]; it is not broadened to [state].
Axis 4 pending overlay lifecycle: ACHIEVED. Home.tsx enters pending layout on apply, cancels via handleCancelPendingLayout, clears pendingLayout and hasPendingChanges on generate, and passes pending state/cancel props into SlideCanvas; SlideCanvas.tsx renders the pending body layout overlay and cancel path.
Out of scope remains correctly excluded: IMP-47B AI fallback activation, frame cache #62, mdx04/mdx05 axes, automated Playwright replacement for the manual doc, and separate dirty-worktree cleanup.
=== EVIDENCE ===
Commands run:
git rev-parse HEAD; git rev-parse HEAD^; git status --short
git show --stat --oneline --name-status HEAD
git diff --name-only HEAD^ HEAD
git diff-tree --no-commit-id --name-status -r HEAD
git diff --numstat HEAD^ HEAD
git ls-remote origin main; git ls-remote slide2 main
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
관련 step: frontend 실행 안정화 (iframe / candidate / override / overlay) — mdx03 기본 시연 path 확보
source: 사용자 직접 시연 확인 (2026-05-21) 에서 발견된 frontend 실행 문제 4 가지
roadmap axis: R5 (프론트엔드 연결) + R1 (실행 안정성)
wave: 1 (실질 구동 도달 필수)
priority: ★ mdx03 시연 path 안정 / IMP-47B 의 precondition
dependency: #61 (IMP-33 scaffold) verified, #38 (IMP-29 frontend evidence bridge) verified
pair: IMP-47B (reject-as-AI-adaptation activation) — IMP-47A 완료 후
scope (5 작업):
iframe 슬라이드 잘림 해결
Front/client/src/components/SlideCanvas.tsx:296의sandbox="allow-same-origin"→sandbox="allow-same-origin allow-scripts"slide-base.html의?embedded=1query 가 script 기반 embedded mode 감지 (IMP-14) — sandbox 에 allow-scripts 없으면 script 실행 안 됨 → standalone CSS 로 표시 → 슬라이드 아래 밀림 / 잘림frame 후보 다중 표시
Front/client/src/services/designAgentApi.ts:511의 candidate source 정정candidateEvidence1 개만 우선 사용 (candidateEvidence.length > 0 ? candidateEvidence : ...)candidate_evidence + v4_all_judgments + v4_candidates3 source merge withtemplate_iddedup → label priority sort → TOP_N_FRAMES (6) capframe / layout override 전달 안정화
Front/client/src/pages/Home.tsx:377의handleGenerateuseCallback deps 정정[state.uploadedFile]만 → stale closure[state.uploadedFile, state.slidePlan, state.userSelection, pendingZones, pendingLayout]추가pending layout overlay 혼동 정리
mdx03 end-to-end 실행 확인
out of scope (별 IMP):
guardrail / validation:
cross-ref:
Front/client/src/components/SlideCanvas.tsx,Front/client/src/services/designAgentApi.ts,Front/client/src/pages/Home.tsxreview loop:
[Claude #1] Stage 1 problem review — IMP-47A
Root cause verification (all 4 frontend issues + uncommitted Codex diff)
U1 — iframe slide clipping (sandbox missing allow-scripts)
Front/client/src/components/SlideCanvas.tsx:296→sandbox="allow-same-origin"(no allow-scripts).Front/client/src/components/SlideCanvas.tsx:191-193→ frontend appends?embedded=1to final.html URL.templates/phase_z2/slide_base.html:9-20→embedded_mode == "auto"branch ships an inline<script>that reads?embedded=1(orwindow.self !== window.top) and addshtml.embeddedclass.templates/phase_z2/slide_base.html:38-46→html.embeddedresets standalone body CSS (display:flex; align-items:center; min-height:100vh; padding:20px 0).src/phase_z2_pipeline.py:2082→ backend defaultembedded_mode="auto". So embedded class application depends on the script running.html.embeddednever set → standalone body centering applies → 1280×720 slide pushed by flex/padding inside iframe."allow-same-origin allow-scripts"(frontend-only, 1-token change).U2 — frame candidate single-source (committed) vs 3-source merge (issue ask)
Front/client/src/services/designAgentApi.ts:511-516(pergit show HEAD) currently uses a ternary fallback:candidate_evidence.length > 0 ? candidate_evidence : (v4_all_judgments?.length > 0 ? v4_all_judgments : v4_candidates). Only one source is consumed → user sees fewer candidates than backend actually emits.Map<template_id, candidate>dedup that pushes all three sources in priority order, then sorts byLABEL_PRIORITY+ confidence desc and caps atTOP_N_FRAMES = 6.U3 — handleGenerate stale-closure deps
Front/client/src/pages/Home.tsx:380deps[state.uploadedFile]only.handleGeneratebody (Home.tsx:243-379) reads:state.uploadedFile,state.slidePlan,state.userSelection.overrides.{layout_preset,zone_frames,zone_geometries,zone_sections}, andeffectiveSlidePlanwhich itself readspendingZones,state.slidePlan,pendingLayout(Home.tsx:458-463).[state.uploadedFile, state.slidePlan, state.userSelection, pendingZones, pendingLayout].userSelection/slidePlan=nullbaseline. User changes layout/frame →setStateupdates state → but theonClick={handleGenerate}reference is still the stale closure →overridescomputed against frozen sourcePlan → backend gets empty override payload → no apparent effect of user picks.state.userSelectioncovers all.overrides.*fields (referential).effectiveSlidePlanis derived from listed deps. Adopt-as-is.U4 — pending layout overlay signal
Front/client/src/components/LayoutPanel.tsx:226-236→ card "적용하기" button callsonApplyLayout→ Home.tsx:122-155handleApplyPendingLayout→ setspendingLayout,hasPendingChanges=true, switches right tab toframe.Front/client/src/components/LeftMdxPanel.tsx:294-314→ whenhasPendingChanges=true, the bottom button transforms into amber 선택대로 재생성하기 with pulsing dot + "Pending Changes" badge + helper copy.Front/client/src/components/SlideCanvas.tsx:236, 240, 361-389→ slide-body overlay showsPending layout: {id}hint and a cancel affordance.Home.tsx:336→ on Generate,setPendingLayout(null)clears overlay automatically; Codex U3 deps fix is the gate that makes this trigger reliably.U5 — mdx03 end-to-end scenario
cd Front/client; npm run dev→ load?mdx=03.pytest -q tests/test_family_contract_baseline.py tests/phase_z2_ai_fallback/(smoke; not strictly necessary because backend src/ change = 0).Codex uncommitted change handling
git diff --stat):Front/client/src/services/designAgentApi.ts(+11 / −6)Front/client/src/pages/Home.tsx(+1 / −1)Scope-lock (5 units, frontend-only, deterministic)
Front/client/src/components/SlideCanvas.tsx:296sandbox="allow-same-origin"→"allow-same-origin allow-scripts"Front/client/src/services/designAgentApi.ts:511-524Front/client/src/pages/Home.tsx:380[state.uploadedFile]→[state.uploadedFile, state.slidePlan, state.userSelection, pendingZones, pendingLayout]Guardrails
src/change = 0. Nosrc/phase_z2_*touched. Notemplates/phase_z2/*touched. Backend pipeline regression risk = 0 on this axis.TOP_N_FRAMES = 6already a module-level const (designAgentApi.ts:499).LABEL_PRIORITYalready shared with HEAD code (designAgentApi.ts:500-505). No mdx03/04/05 branching anywhere in U1–U3.Front/client/src/data/andsamples/mdx*/untouched.Out of scope (deferred)
Open questions (for Stage 2)
pytest -qsmoke on a frontend-only commit? Recommendation: no (backend untouched), but Stage 2 can opt in for safety belt.ready-for-stage-2
[Codex #1] Stage 1 problem review - IMP-47A
Stage 1 verdict: root causes are verified and the implementation scope can stay frontend-only. No missing issue files found.
Findings:
Front/client/src/components/SlideCanvas.tsx:191-193appends?embedded=1, butFront/client/src/components/SlideCanvas.tsx:296still hassandbox="allow-same-origin".templates/phase_z2/slide_base.html:9-19uses inline script to sethtml.embedded, andtemplates/phase_z2/slide_base.html:38-46contains the embedded CSS reset.src/phase_z2_pipeline.py:2082-2091defaultsembedded_mode="auto", so the iframe needsallow-scriptsfor the existing backend/template contract to work.candidate_evidenceelsev4_all_judgmentselsev4_candidates. The working tree atFront/client/src/services/designAgentApi.ts:499-531usesTOP_N_FRAMES = 6,LABEL_PRIORITY, aMapkeyed bytemplate_id ?? id ?? frame_id, pushescandidate_evidence,v4_all_judgments, andv4_candidatesin priority order, then sorts and caps. This matches the issue ask and is deterministic/no-LLM.handleGenerateclosure is valid in HEAD and already corrected in the working tree. HEAD dependency list is[state.uploadedFile], while the callback readsstate.slidePlan,state.userSelection,pendingZonesthrougheffectiveSlidePlan, andpendingLayout. The working tree atFront/client/src/pages/Home.tsx:244-380now uses[state.uploadedFile, state.slidePlan, state.userSelection, pendingZones, pendingLayout], matching the needed override delivery path.Front/client/src/pages/Home.tsx:122-155enterspendingLayout,Home.tsx:158-163cancels it, andHome.tsx:334-336clears it on Generate.Front/client/src/components/SlideCanvas.tsx:361-390shows the pending body overlay andSlideCanvas.tsx:608-622limits the min-height hint to pending layout mode. Stage 2 should decide whether the existing signal text is sufficient or needs a small frontend-only copy/state refinement.Scope lock:
Front/client/src/components/SlideCanvas.tsx,Front/client/src/services/designAgentApi.ts,Front/client/src/pages/Home.tsx.src/or templates for IMP-47A.src/config.py,src/phase_z2_pipeline.py,src/phase_z2_ai_fallback/*,templates/phase_z2/catalog/frame_contracts.yaml, tests, etc.). They should be treated as pre-existing/unrelated and not staged for this frontend-only issue.designAgentApi.tsandHome.tsxshould be adopted as IMP-47A work unless Stage 2 finds a concrete regression.SlideCanvas.tsxstill needs the sandbox change.=== EVIDENCE ===
Commands run:
Get-Content -LiteralPath 'D:\ad-hoc\kei\design_agent\.orchestrator\tmp\codex_prompt.txt'git status --shortrg -n "sandbox=|embedded=1|candidate_evidence|v4_all_judgments|v4_candidates|TOP_N_FRAMES|LABEL_PRIORITY|handleGenerate|useCallback|pendingLayout|pendingZones" Front/client/src/components/SlideCanvas.tsx Front/client/src/services/designAgentApi.ts Front/client/src/pages/Home.tsx templates/phase_z2/slide_base.html src/phase_z2_pipeline.pygit diff -- Front/client/src/components/SlideCanvas.tsx Front/client/src/services/designAgentApi.ts Front/client/src/pages/Home.tsxgit show HEAD:Front/client/src/services/designAgentApi.ts | Select-String -Pattern "candidate_evidence|v4_all_judgments|v4_candidates|TOP_N_FRAMES|LABEL_PRIORITY" -Context 3,8git show HEAD:Front/client/src/pages/Home.tsx | Select-String -Pattern "const handleGenerate = useCallback|state\.slidePlan|userSelection|pendingZones|pendingLayout|\}, \[state\.uploadedFile\]\);" -Context 2,2SlideCanvas.tsx,designAgentApi.ts,Home.tsx,templates/phase_z2/slide_base.html, andsrc/phase_z2_pipeline.pygit diff --name-only -- src templates tests Front/client/src/components/SlideCanvas.tsx Front/client/src/services/designAgentApi.ts Front/client/src/pages/Home.tsxFiles checked:
D:\ad-hoc\kei\design_agent\Front\client\src\components\SlideCanvas.tsxD:\ad-hoc\kei\design_agent\Front\client\src\services\designAgentApi.tsD:\ad-hoc\kei\design_agent\Front\client\src\pages\Home.tsxD:\ad-hoc\kei\design_agent\templates\phase_z2\slide_base.htmlD:\ad-hoc\kei\design_agent\src\phase_z2_pipeline.pyTest results: Not run; Stage 1 explicitly says NO pytest.
Verified facts:
SlideCanvas.tsxappends?embedded=1but still blocks iframe scripts via sandbox.slide_base.htmlembedded auto-mode depends on inline script execution.handleGeneratedeps are stale; working tree deps include uploaded file, slide plan, user selection, pending zones, and pending layout.FINAL_CONSENSUS: YES
[Claude #2] Stage 2 simulation-plan IMP-47A r1 — mdx03 frontend 시연 안정화
Axis→unit map: issue#1 iframe sandbox → u1 / #2 3-source merge → u2 / #3 handleGenerate deps → u3 / #4 pending overlay (wiring done) + #5 mdx03 e2e → u4 (manual doc).
=== IMPLEMENTATION_UNITS ===
summary: SlideCanvas.tsx:296 sandbox — add
allow-scriptstoken only;allow-same-originpreserved; no allow-forms/popups/top-navigation (Stage 1 guardrail). Unblocks slide_base.html:9-20 inline script that detects?embedded=1and applieshtml.embeddedCSS reset → resolves iframe clipping.files:
tests:
estimate_lines: 1
summary: designAgentApi.ts loadRun frame-candidate merge (lines 511-524) — replace ternary fallback with Map<key,c> dedup over 3 sources (candidate_evidence, v4_all_judgments, v4_candidates); key precedence template_id|id|frame_id; sort by LABEL_PRIORITY (use_as_is<light_edit<restructure<reject) then confidence desc; cap TOP_N_FRAMES=6 (const at line 499, unchanged). Codex working-tree diff verified by both Stage 1 reviewers — adopt as-is.
files:
tests:
estimate_lines: 14
summary: Home.tsx handleGenerate useCallback deps (line 380) — replace
[state.uploadedFile]with the 5-tuple[state.uploadedFile, state.slidePlan, state.userSelection, pendingZones, pendingLayout]. Codex working-tree diff verified by both Stage 1 reviewers — adopt as-is. Broader[state]rejected (would re-create callback per render).files:
tests:
estimate_lines: 1
summary: tests/manual/imp47a_e2e.md — new consolidated manual e2e doc covering all 5 issue axes. Sections (1) iframe sandbox smoke (no clipping at 1280×720), (2) candidate count ≥2 when backend emits multi-source, (3) frame override round-trip via Generate (new run_id, override seen in backend log), (4) pending overlay enter/cancel/auto-clear-on-Generate, (5) mdx03 full path upload → Generate → switch layout/frame → Generate → iframe re-renders. Each section = precondition / action / pass criteria.
files:
tests:
estimate_lines: 50
Per-unit rationale:
allow-scripts, the slide_base.html inline detector cannot sethtml.embedded, so standalone CSS (display:flex, padding:20px 0) activates inside the iframe and clips the 1280×720 slide. Single-token change is the minimum + only required fix.Out of scope:
embedded_mode='auto'contract intact.Rollback: per-unit independent. u1=1-token toggle, u2=restore ternary block, u3=single-element deps, u4=delete doc.
=== EVIDENCE ===
Working-tree state verified now (
git diff+ Read):sandbox="allow-same-origin"(u1 not yet applied).Test infra: Front/package.json scripts={dev,build,start,preview,check,format} — no
test, no app-level*.test.*.pnpm check(tsc --noEmit) remains for type-level regression.Comments reviewed: Claude #1 + Codex #1 (Stage 1, FINAL_CONSENSUS: YES) + Stage 1 exit report (binding contract above) — root_cause / scope_lock / guardrails honored.
FINAL_CONSENSUS: YES
[Codex #2] Stage 2 simulation-plan verification - IMP-47A
=== IMPLEMENTATION_UNITS ===
summary: Add allow-scripts to the SlideCanvas iframe sandbox while preserving allow-same-origin and adding no other sandbox capabilities.
files:
tests:
estimate_lines: 1
summary: Keep TOP_N_FRAMES at 6 and merge candidate_evidence, v4_all_judgments, and v4_candidates through deterministic template_id/id/frame_id dedup, LABEL_PRIORITY ordering, confidence tie-break, and the existing cap.
files:
tests:
estimate_lines: 17
summary: Fix handleGenerate stale closure by using the exact dependency set state.uploadedFile, state.slidePlan, state.userSelection, pendingZones, pendingLayout.
files:
tests:
estimate_lines: 1
summary: Add the manual mdx03 end-to-end verification doc covering iframe rendering, multi-source frame candidates, frame/layout override regeneration, pending overlay enter/cancel/clear behavior, and final.html iframe display.
files:
tests:
estimate_lines: 50
Per-unit rationale:
Out-of-scope notes:
Rollback strategy:
=== EVIDENCE ===
Commands run:
Files checked:
Test results:
Verified facts:
FINAL_CONSENSUS: YES
[Claude #3] Stage 3 code-edit — IMP-47A u1
Executing unit: u1
■ unit_executed
allow-scriptsto the SlideCanvas iframe sandbox while preservingallow-same-originand adding no other sandbox capabilities.■ files_changed
■ diff_summary
Single-token addition.
allow-forms,allow-popups,allow-top-navigationNOT added (Stage 1/2 guardrail).■ scope_check
allow-same-originpreserved +allow-scriptsonly.slide_base.htmlscript gates on?embedded=1ORwindow.self !== window.top; sandbox change only enables the script to run, does not change page mode logic.■ remaining_units
■ follow_up_issue_candidates
■ stop
[Codex #3] Stage 3 code-edit verification - IMP-47A u1
Verified the single executed unit u1 against the Stage 2 scope lock.
=== EVIDENCE ===
Commands run:
Files checked:
Test results:
Verified facts:
Remaining units: [u2, u3, u4]
rewind_target: continue_same
FINAL_CONSENSUS: NO
[Claude #4] Stage 3 code-edit — IMP-47A u2
Executing unit: u2
■ unit_executed
candidate_evidence,v4_all_judgments, andv4_candidatesthrough deterministictemplate_id ?? id ?? frame_iddedup, LABEL_PRIORITY ordering (use_as_is < light_edit < restructure < reject), confidence-desc tie-break, and the existing cap. Adopts the Stage 1/2 locked Codex working-tree diff as-is.■ files_changed
■ diff_summary
Net diff: replaces ternary fallback (1 source max) with Map<key,any> dedup over 3 sources, key precedence
template_id ?? id ?? frame_id, source iteration order = candidate_evidence → v4_all_judgments → v4_candidates (first-write-wins per key). Existing LABEL_PRIORITY sort, confidence desc tie-break, and.slice(0, TOP_N_FRAMES)cap (=6) are preserved unchanged below the patch window.■ scope_check
■ remaining_units
■ follow_up_issue_candidates
■ stop
[Codex #4] Stage 3 code-edit verification - IMP-47A u2
Verified the single executed unit u2 against the Stage 2 scope lock.
=== EVIDENCE ===
Commands run:
Files checked:
Test results:
Verified facts:
Remaining units: [u3, u4]
rewind_target: continue_same
FINAL_CONSENSUS: NO
[Claude #5] Stage 3 code-edit — IMP-47A u3
Executing unit: u3
■ unit_executed
handleGeneratestale closure by replacing the single-dep useCallback ([state.uploadedFile]) with the locked 5-tuple dependency set:state.uploadedFile, state.slidePlan, state.userSelection, pendingZones, pendingLayout. Adopts the Stage 1/2 locked Codex working-tree diff as-is.■ files_changed
■ diff_summary
Single-line change at
Home.tsx:380(post-edit). The 5 dependencies cover every state read inside the callback:state.uploadedFile— early guard +runPipeline(state.uploadedFile, overrides)state.slidePlan— default layout + zone defaults comparisonstate.userSelection— layout/zone_frames/zone_sections/zone_geometries overridespendingZones— feedseffectiveSlidePlan(used assourcePlan)pendingLayout— read indirectly viaeffectiveSlidePlanand cleared on submitNo broader
[state]dep introduced (Stage 2 guardrail — would needlessly re-create callback per render).■ scope_check
handleGenerate(override computation, runPipeline call, loadRun handling all unchanged).effectiveSlidePlanalready memoizesstate.slidePlan+pendingZones(existing useMemo upstream), so addingpendingZonesto deps is consistent with the read graph.■ remaining_units
■ follow_up_issue_candidates
■ stop
[Codex #5] Stage 3 code-edit verification - IMP-47A u3
Verified the single executed unit u3 against the Stage 2 scope lock.
=== EVIDENCE ===
Commands run:
Files checked:
Test results:
Verified facts:
Remaining units: [u4]
rewind_target: continue_same
FINAL_CONSENSUS: NO
[Claude #6] Stage 3 code-edit — IMP-47A u4
Executing unit: u4
■ unit_executed
tests/manual/imp47a_e2e.md) covering all five scope axes: iframe rendering, multi-source frame candidates, frame/layout override regeneration, pending overlay enter/cancel/clear behavior, and mdx03 final.html iframe display end-to-end smoke.■ files_changed
■ diff_summary
New file
tests/manual/imp47a_e2e.mdwith 5 sections + Preconditions + Out-of-scope:npm run dev, working tree at Stage 3 u1+u2+u3 head, browser?mdx=03.html.embeddedclass applied inside iframe after u1 sandbox change; no top offset / bottom clipping.template_id ?? id ?? frame_id; LABEL_PRIORITY (use_as_is<light_edit<restructure<reject) then confidence desc.No code logic added; doc is the deliverable.
■ scope_check
tests/manual/imp47a_e2e.mdcreated for this unit).TOP_N_FRAMES=6and LABEL_PRIORITY by name, not numeric thresholds tied to a specific mdx.■ remaining_units
■ follow_up_issue_candidates
■ stop
[Codex #6] Stage 3 code-edit verification - IMP-47A u4
Verified the single executed unit u4 against the Stage 2 scope lock.
=== EVIDENCE ===
Commands run:
Files checked:
Test results:
Verified facts:
Remaining units: none
FINAL_CONSENSUS: YES
[Claude #7] Stage 4 test-verify — IMP-47A
Verdict
PASS. All four implementation_units (u1~u4) match Stage 2 plan exactly. Baseline regression green:
pytest -q tests→ 623 passed in 42.65s. No backend src edits. No hardcoding. No scope creep.Scope verification
u1 — SlideCanvas sandbox (axis 1)
Front/client/src/components/SlideCanvas.tsx:296sandbox="allow-same-origin"→sandbox="allow-same-origin allow-scripts"allow-same-originpreserved, NOallow-forms/allow-popups/allow-top-navigation. PASS.u2 — designAgentApi 3-source candidate merge (axis 2)
Front/client/src/services/designAgentApi.ts:511-524TOP_N_FRAMES = 6unchanged (line 499).LABEL_PRIORITYorder unchanged (use_as_is=0 < light_edit=1 < restructure=2 < reject=3, lines 500-505).c.template_id ?? c.id ?? c.frame_id(line 517) — matches plan.candidateEvidence→v4_all_judgments→v4_candidates(lines 521-523) — matches plan..slice(0, TOP_N_FRAMES)(line 531). PASS.u3 — Home.tsx handleGenerate deps (axis 3)
Front/client/src/pages/Home.tsx:380[state.uploadedFile]→[state.uploadedFile, state.slidePlan, state.userSelection, pendingZones, pendingLayout][state]dep. PASS.u4 — Manual e2e doc (axes 4 + 5)
tests/manual/imp47a_e2e.md(new, 90 lines)html.embeddedtokenTOP_N_FRAMES,LABEL_PRIORITY,candidate_evidence,v4_all_judgments,v4_candidatesoverrides.frames,overrides.layoutrun_idcaptureRegression check
pytest -q tests→ 623 passed in 42.65s (full suite).src/phase_z2_pipeline.py,src/phase_z2_ai_fallback/*is from IMP-33 baselinec864fe0and out-of-scope per Stage 2 rollback strategy).Hardcoding audit
TOP_N_FRAMES=6is a named const, Map key precedence is content-agnostic. No mdx03-specific branch. PASS.Guardrail attestation
Cross-axis trace
=== EVIDENCE ===
commands_run:
git status --shortgit diff Front/client/src/components/SlideCanvas.tsxgit diff Front/client/src/services/designAgentApi.tsgit diff Front/client/src/pages/Home.tsxgit ls-files --others --exclude-standard tests/manual/git diff --stat HEAD -- Front/client/src/components/SlideCanvas.tsx Front/client/src/services/designAgentApi.ts Front/client/src/pages/Home.tsxwc -l tests/manual/imp47a_e2e.mdpython -m pytest -q testsfiles_checked:
facts:
c864fe0(baseline as locked in Stage 2)scope_locked_paths_verified:
out_of_scope_paths_untouched_by_imp47a:
FINAL_CONSENSUS: YES
[Codex #7] Stage 4 test-verify - IMP-47A
Verdict: PASS. Commit is OK for the scoped IMP-47A files only.
Verification notes:
Front/client/src/components/SlideCanvas.tsx:296is exactlysandbox="allow-same-origin allow-scripts".allow-same-originis preserved and no additional sandbox capabilities are present.Front/client/src/services/designAgentApi.tskeepsTOP_N_FRAMES = 6, keepsLABEL_PRIORITY, dedups withMapbytemplate_id ?? id ?? frame_id, consumescandidate_evidence,v4_all_judgments, andv4_candidatesin that order, sorts by label priority then confidence, and caps with.slice(0, TOP_N_FRAMES).Front/client/src/pages/Home.tsx:380uses the required dependency set[state.uploadedFile, state.slidePlan, state.userSelection, pendingZones, pendingLayout]and does not broaden to[state].tests/manual/imp47a_e2e.mdis present as a new untracked manual test doc and covers the five axes: iframe rendering, multi-source candidates, override regeneration, pending overlay lifecycle, and mdx03 end-to-end smoke.Correction to previous report:
Scope / commit guard:
Front/client/src/components/SlideCanvas.tsx,Front/client/src/services/designAgentApi.ts,Front/client/src/pages/Home.tsx, andtests/manual/imp47a_e2e.md.=== EVIDENCE ===
Commands run:
git status --shortgit diff -- Front/client/src/components/SlideCanvas.tsx Front/client/src/services/designAgentApi.ts Front/client/src/pages/Home.tsx tests/manual/imp47a_e2e.mdgit diff --name-onlygit ls-files --others --exclude-standard -- tests/manual/imp47a_e2e.mdGet-Content -LiteralPath tests\manual\imp47a_e2e.md(Get-Content -LiteralPath tests\manual\imp47a_e2e.md | Measure-Object -Line).LinesSelect-Stringchecks forhtml.embedded,TOP_N_FRAMES,LABEL_PRIORITY,candidate_evidence,v4_all_judgments,v4_candidates,overrides.frames,overrides.layout,run_id,IMP-47B,#62,mdx04, andPlaywrightSelect-Stringchecks indesignAgentApi.tsforTOP_N_FRAMES,LABEL_PRIORITY,candidateMap,template_id ?? c.id ?? c.frame_id, all three source arrays, and.slice(0, TOP_N_FRAMES)pytest -q testsgit diff --stat -- Front/client/src/components/SlideCanvas.tsx Front/client/src/services/designAgentApi.ts Front/client/src/pages/Home.tsx tests/manual/imp47a_e2e.mdgit diff --check -- Front/client/src/components/SlideCanvas.tsx Front/client/src/services/designAgentApi.ts Front/client/src/pages/Home.tsx tests/manual/imp47a_e2e.mdFiles checked:
Front/client/src/components/SlideCanvas.tsxFront/client/src/services/designAgentApi.tsFront/client/src/pages/Home.tsxtests/manual/imp47a_e2e.mdTest results:
pytest -q testspassed: 623 passed in 41.97s.git diff --checkreported no whitespace errors for the scoped files.Verified facts:
tests/manual/imp47a_e2e.mdis untracked-new.FINAL_CONSENSUS: YES
[Claude #8] Stage 5 commit-push — IMP-47A
📌 Stage 5: 커밋 및 푸쉬 완료
■ 핵심 결정
■ 범위 제외
■ 다음 단계
=== EVIDENCE ===
commit
15ef7c65e9f58637e4b4714afb9546c176ceaaa815ef7c6c864fe0(Stage 2 baseline)fix(#75): IMP-47A mdx03 frontend execution stabilization (u1~u4)staged_scope (4 paths, exact)
Front/client/src/components/SlideCanvas.tsx— u1 (sandbox: +allow-scripts), +1/-1Front/client/src/pages/Home.tsx— u3 (handleGenerate deps 5-tuple), +1/-1Front/client/src/services/designAgentApi.ts— u2 (3-source Map merge), +13/-6tests/manual/imp47a_e2e.md— u4 (new, 90 lines, 5 axes)4 files changed, 103 insertions(+), 8 deletions(-)out-of-commit dirty paths (intentionally NOT staged — pre-existing, unrelated)
push verification
git push origin main→c864fe0..15ef7c6 main -> main(GitHub)git push slide2 main→c864fe0..15ef7c6 main -> main(Gitea C.E.L_Slide_test2)git ls-remote origin main→15ef7c65e9f58637e4b4714afb9546c176ceaaa8 refs/heads/maingit ls-remote slide2 main→15ef7c65e9f58637e4b4714afb9546c176ceaaa8 refs/heads/main15ef7c6✅unit ↔ commit traceability (per Stage 2 plan)
allow-same-origin allow-scripts(no allow-forms/popups/top-navigation) ✅.slice(0, TOP_N_FRAMES)cap (TOP_N_FRAMES=6 unchanged) ✅[state.uploadedFile, state.slidePlan, state.userSelection, pendingZones, pendingLayout](5-tuple, no broadened[state]) ✅guardrail audit
notes
line_count: 65from Codex (counting discrepancy); Stage 3 reported 90, and Stage 5 diff stat confirms 90 lines. Implementation status unaffected — file content verified present and complete.Home.tsx,designAgentApi.ts,imp47a_e2e.mdare environment-normal on Windows checkout; no behavior impact.commit_sha:
15ef7c65e9[Codex #8] Stage 5 commit-push verification - IMP-47A
Stage 5 verification result: PASS.
The local commit, GitHub remote (
origin/main), and Gitea remote (slide2/main) all resolve to the same SHA:15ef7c65e9f58637e4b4714afb9546c176ceaaa8.Commit scope is exactly the four IMP-47A paths from the Stage 2 plan:
Front/client/src/components/SlideCanvas.tsxFront/client/src/pages/Home.tsxFront/client/src/services/designAgentApi.tstests/manual/imp47a_e2e.mdNo unintended backend, template, catalog, mdx data, or unrelated dirty worktree files are included in the commit. The existing dirty worktree remains outside this commit.
Verified implementation facts:
SlideCanvas.tsxiframe sandbox isallow-same-origin allow-scripts; no extra sandbox capabilities were added.designAgentApi.tskeepsTOP_N_FRAMES = 6, consumescandidate_evidence,v4_all_judgments, andv4_candidates, sorts byLABEL_PRIORITYthen confidence, and caps with.slice(0, TOP_N_FRAMES).Home.tsxhandleGeneratedependencies are[state.uploadedFile, state.slidePlan, state.userSelection, pendingZones, pendingLayout].tests/manual/imp47a_e2e.mdis present in the commit and covers iframe rendering, multi-source candidates, override regeneration, pending overlay lifecycle, and mdx03 e2e smoke. Note: Git numstat reports 90 added diff lines for this new file;Measure-Object -Linereports 65 file lines, so the prior "90 lines" wording is ambiguous but does not affect commit scope or content verification.=== EVIDENCE ===
Commands run:
git rev-parse HEADgit log -1 --pretty=fullergit show --stat --oneline --name-status HEADgit diff-tree --no-commit-id --name-status -r HEADgit diff --name-only HEAD^ HEADgit diff --numstat HEAD^ HEADgit ls-remote origin maingit ls-remote slide2 maingit rev-parse origin/maingit rev-parse slide2/maingit status --shortgit rev-parse HEAD^git show HEAD:Front/client/src/components/SlideCanvas.tsx | Select-String -Pattern 'sandbox=' -Context 0,1git show HEAD:Front/client/src/services/designAgentApi.ts | Select-String -Pattern 'TOP_N_FRAMES|LABEL_PRIORITY|candidate_evidence|v4_all_judgments|v4_candidates|slice\(0, TOP_N_FRAMES\)' -Context 1,2git show HEAD:Front/client/src/pages/Home.tsx | Select-String -Pattern 'state\.uploadedFile, state\.slidePlan, state\.userSelection, pendingZones, pendingLayout' -Context 0,0git show HEAD:tests/manual/imp47a_e2e.md | Measure-Object -Linegit show HEAD:tests/manual/imp47a_e2e.mdFiles checked:
Front/client/src/components/SlideCanvas.tsxFront/client/src/pages/Home.tsxFront/client/src/services/designAgentApi.tstests/manual/imp47a_e2e.mdCommit SHA:
15ef7c65e9f58637e4b4714afb9546c176ceaaa8c864fe0479c1513afb4eb29c6b96342af5b50178origin/main:15ef7c65e9f58637e4b4714afb9546c176ceaaa8slide2/main:15ef7c65e9f58637e4b4714afb9546c176ceaaa8Verified facts:
fix(#75): IMP-47A mdx03 frontend execution stabilization (u1~u4).1/1,1/1,11/6, and90/0, totaling103 insertions(+), 8 deletions(-).src/,templates/, catalog, sample, or unrelated dirty paths are present ingit diff-tree HEAD.git ls-remotefor bothorigin mainandslide2 main.FINAL_CONSENSUS: YES
[Claude #9] Stage 6 final-close — IMP-47A
📌 [오케스트레이터] Stage 6: 최종 확인 / close 결정
■ 핵심 결정
15ef7c6에 반영 확인. origin + slide2 양 remote SHA equality 검증 PASS.■ 범위 제외
■ 다음 단계
=== EXIT REPORT (English, binding contract) ===
[Codex #9] Stage 6 final-close verification - IMP-47A
Final independent verification result: PASS. Issue #75 is close-ready.
Scope-qualified findings:
15ef7c65e9f58637e4b4714afb9546c176ceaaa8, parentc864fe0479c1513afb4eb29c6b96342af5b50178, messagefix(#75): IMP-47A mdx03 frontend execution stabilization (u1~u4).origin/mainandslide2/mainboth resolve to15ef7c65e9f58637e4b4714afb9546c176ceaaa8.Front/client/src/components/SlideCanvas.tsx,Front/client/src/pages/Home.tsx,Front/client/src/services/designAgentApi.ts,tests/manual/imp47a_e2e.md.src/,templates/, catalog, or sample MDX path is present inHEAD^..HEAD.15ef7c6.Axis verification:
SlideCanvas.tsxappends?embedded=1and iframe sandbox is exactlyallow-same-origin allow-scripts;allow-forms,allow-popups, andallow-top-navigationare absent from the sandbox value.designAgentApi.tskeepsTOP_N_FRAMES = 6, consumescandidate_evidence,v4_all_judgments, andv4_candidates, dedups bytemplate_id ?? id ?? frame_id, sorts byLABEL_PRIORITYthen confidence descending, and caps with.slice(0, TOP_N_FRAMES).Home.tsxhandleGeneratedependency list is[state.uploadedFile, state.slidePlan, state.userSelection, pendingZones, pendingLayout]; it is not broadened to[state].Home.tsxenters pending layout on apply, cancels viahandleCancelPendingLayout, clearspendingLayoutandhasPendingChangeson generate, and passes pending state/cancel props intoSlideCanvas;SlideCanvas.tsxrenders the pending body layout overlay and cancel path.tests/manual/imp47a_e2e.mdcovers iframe rendering, multi-source candidates, frame/layout override regeneration, pending overlay lifecycle, and mdx03 final.html smoke capture.Out of scope remains correctly excluded: IMP-47B AI fallback activation, frame cache #62, mdx04/mdx05 axes, automated Playwright replacement for the manual doc, and separate dirty-worktree cleanup.
=== EVIDENCE ===
Commands run:
git rev-parse HEAD; git rev-parse HEAD^; git status --shortgit show --stat --oneline --name-status HEADgit diff --name-only HEAD^ HEADgit diff-tree --no-commit-id --name-status -r HEADgit diff --numstat HEAD^ HEADgit ls-remote origin main; git ls-remote slide2 maingit rev-parse origin/main; git rev-parse slide2/maingit show --format='%H%n%P%n%s' --no-patch HEADSelect-Stringchecks for sandbox, embedded query, candidate merge tokens, handleGenerate deps, pending overlay lifecycle, overrides, and manual e2e tokensFiles checked:
Front/client/src/components/SlideCanvas.tsxFront/client/src/services/designAgentApi.tsFront/client/src/pages/Home.tsxtests/manual/imp47a_e2e.mdTest results:
pytest -q testsas623 passed in 42.65s.Commit SHA:
15ef7c65e9f58637e4b4714afb9546c176ceaaa8Verified facts:
HEAD,origin/main, andslide2/mainall equal15ef7c65e9f58637e4b4714afb9546c176ceaaa8.HEAD^equalsc864fe0479c1513afb4eb29c6b96342af5b50178.HEAD^..HEADcontains exactly the four IMP-47A paths and no backend/template/catalog/MDX data paths.allow-same-origin allow-scripts.handleGenerateuses the locked five-entry dependency list.FINAL_CONSENSUS: YES