[Claude #6] Stage 3 code-edit Round #4 — u4 verification (`continue_same` after u3 PASS) ## unit_executed - **u4** — Axis 5 SlideCanvas active-frame lookup: derive `activeFrameId = overrideFrameId ?? defaultFrameId` and `activeCandidate = region?.frame_candidates?.find((c) => c.id === activeFrameId)`. - u4 source diff was already applied in the original Round #1 implementation; this turn formally executes the unit step under the per-turn workflow (Codex #N closed u3 verified, `rewind_target: continue_same`, remaining = [u4, u5]). - No new source edit required. Per-unit verification: lookup diff inspection + frontend typecheck delta confirmation. ## files_changed - `Front/client/src/components/SlideCanvas.tsx` (already modified, +8 lines for u4 — 4 source + 4 comment, no further edit this turn) ## diff_summary Exact u4 hunk currently on disk at `Front/client/src/components/SlideCanvas.tsx:615-622`: ```diff @@ -612,6 +612,28 @@ : null; const previewUrl = previewCandidate?.thumbnailUrl ?? null; + // IMP-11 u4: active frame lookup — distinct axis from preview. + // preview is shown only when override differs from default; active is + // always defined as override-if-present-else-default. Used by u5 to + // compare the active frame's catalog min_height_px against zone height. + const activeFrameId = overrideFrameId ?? defaultFrameId; + const activeCandidate = activeFrameId + ? region?.frame_candidates?.find((c) => c.id === activeFrameId) + : undefined; + ``` (The same diff block also adds the u5 hint derivation at lines 624-635 and the u5 hint render at lines 717-728. **u5 is OUT OF SCOPE for this turn** — it is the next remaining unit and will be formally executed on the next `continue_same` turn. This u4 verification is bounded to lines 615-622.) Properties (u4 only): - **Source variables already declared upstream (not duplicated)**: - `defaultFrameId` = `region?.frame_match_strategy.frame_id` at `SlideCanvas.tsx:602` - `overrideFrameId` = `region?.id ? userSelection.overrides.zone_frames?.[region.id] : undefined` at `:603-605` - **u4 derives the active axis distinctly from the preview axis**: - `previewFrameId` (existing, `:606-609`) = `overrideFrameId !== defaultFrameId ? overrideFrameId : null` — only set when override DIFFERS from default (used for thumbnail overlay) - `activeFrameId` (new, `:619`) = `overrideFrameId ?? defaultFrameId` — always set as override-if-present-else-default (used for catalog lookup) - The two axes coexist; u4 does not rename or remove `previewFrameId` / `previewCandidate`. - **Reuses existing `region?.frame_candidates?.find(...)` pattern** mirrored from `previewCandidate` at `:610-612`. No new types, no new schema. `FrameCandidate.id` lookup is the existing v4 mapper key. - **`activeCandidate` is `undefined` when `activeFrameId` is `undefined`** (no `region` / no `frame_match_strategy.frame_id` and no override) — this is the same guard pattern as `previewCandidate`. Graceful: downstream u5 reads `activeCandidate?.minHeightPx ?? null`, so `undefined` propagates safely. - **`zone.internal_regions[0]` first-region selection unchanged** — Stage 1 scope_lock axis_5 source: "region override frame_id first, default frame second". The first-region constraint matches the existing code path at `:601`. ## typecheck delta verification Stage 2 plan u4 test command: `cd Front && npm run check` (`tsc --noEmit`, single npm root at `Front/package.json:11`). **With IMP-11 u4 applied (current HEAD working tree, u1+u2+u3+u4+u5 in place):** ``` client/src/components/BottomActions.tsx(11,10): error TS2305: Module '"../utils/slidePlanUtils"' has no exported member 'serializeSlidePlan'. ``` **Baseline (from Codex #N u2 and u3 verifications):** ``` client/src/components/BottomActions.tsx(11,10): error TS2305: Module '"../utils/slidePlanUtils"' has no exported member 'serializeSlidePlan'. ``` Identical single error in both cases. The `BottomActions.tsx` / `serializeSlidePlan` issue is a **pre-existing typecheck error on `main` HEAD `0fb168b`** (IMP-10 D-1 ramp), entirely outside IMP-11 scope. The u4 addition (`activeFrameId` / `activeCandidate` derivations) introduces **zero new TS errors**. Per Stage 2 estimate_lines: 6 — u4 source is 4 lines (1 line for `activeFrameId`, 3 lines for `activeCandidate` with ternary + find + comma chain). Slightly under budget on source; 4 lines of comment explain the preview-vs-active axis distinction. Stage 1 axis_5 guardrail "Use region override frame_id first, default frame second" — satisfied by `overrideFrameId ?? defaultFrameId`. ## remaining_units - `u5` — Axis 4 SlideCanvas visual hint: `zoneHeightPx = height * SLIDE_H` (logical px) compare against `activeCandidate.minHeightPx` in pendingLayout mode; if `zoneHeightPx < minHeightPx` render red ring + 'min H Npx' badge. Resize clamp `minSize=0.05` unchanged. Estimate 20 lines (current diff lines 624-635 derivation + lines 717-728 render = 18 lines actual). Files: `Front/client/src/components/SlideCanvas.tsx`. Tests: `cd Front && npm run check` + manual dev smoke. ## follow_up_issue_candidates None this turn. Scope-lock observed strictly. rewind_target: continue_same FINAL_CONSENSUS: NO