1 line
4.4 KiB
JSON
1 line
4.4 KiB
JSON
{"body":"[Claude #7]\n\n**unit_executed**: u4 — stale-detect short-circuit (compare `index.html` mtime+sha256 against last manifest entry; mark `skipped_unchanged` when both match)\n\n**files_changed**:\n- MOD `D:\\ad-hoc\\kei\\design_agent\\scripts\\generate_frame_previews.py` (88 → 110 lines per `Measure-Object -Line`; u4 net add = 22 lines, ≤ Stage 2 u4 estimate of 45)\n\n**diff_summary**:\n- Added `_sha256_file(path: Path) -\u003e str` (private, leading underscore) — buffered `hashlib.sha256()` digest of `index.html` content, 65 KiB chunked read. Stdlib only.\n- Added `is_unchanged(row: FrameRow, last_entry: Optional[Dict[str, Any]]) -\u003e bool` — the Stage 2 u4 short-circuit predicate. Returns `True` iff:\n 1. `last_entry` is not `None`, AND\n 2. `row.has_index` and `row.has_preview` are both `True`, AND\n 3. `preview.png` mtime `\u003e=` `index.html` mtime (per Stage 2 guardrail: \"skip if preview.png mtime \u003e= index.html mtime AND content hash unchanged\"), AND\n 4. `last_entry[\"index_sha256\"]` is non-empty, AND\n 5. recomputed `_sha256_file(index.html)` equals `last_entry[\"index_sha256\"]`.\n Otherwise returns `False` — the caller (u6) MUST re-render. `OSError` on `stat()` is caught and treated as \"must re-render\" (defensive against transient FS races).\n- **No wiring into `main()`** — predicate is provided in isolation per Stage 2 unit boundary. u6 will load the manifest, call `is_unchanged()` per row, and write back the `skipped_unchanged` / `rendered` status. This keeps u4 ≤ 45-line guardrail and lets u5 (orphan/missing categorization) and u6 (manifest writer + coverage report) layer on top without re-touching u4 surface.\n- Module-level imports: added `hashlib` (stdlib) and `Dict`, `Optional` to existing `typing` import. No new third-party deps. Selenium remains lazy (u2/u3 contract preserved).\n- Module docstring updated: `(u1-u3; stale/orphan/manifest added in u4-u6)` → `(u1-u4; orphan/manifest added in u5-u6)`.\n- `FrameRow` / `discover` / `_build_driver` / `render_one` / `main` / CLI **untouched**. u1/u2/u3 contracts preserved.\n\n**verification**:\n- `(Get-Content scripts/generate_frame_previews.py | Measure-Object -Line).Lines` → **110** (u4 add = 22 lines, ≤ 45 guardrail).\n- `python scripts/generate_frame_previews.py --dry-run` → `discovered: total=33 with_index_html=20 with_preview_png=4` (unchanged from u1/u2/u3 baseline at commit `56619a0` — u4 does not alter discovery output and does not wire into main).\n- `$env:PYTHONPATH = \u0027...\\scripts\u0027; python -c \"import generate_frame_previews as m; print(\u0027import_ok\u0027, hasattr(m,\u0027is_unchanged\u0027), hasattr(m,\u0027_sha256_file\u0027), hasattr(m,\u0027render_one\u0027), hasattr(m,\u0027_build_driver\u0027), hasattr(m,\u0027discover\u0027), hasattr(m,\u0027main\u0027))\"` → `import_ok True True True True True True` (lazy-selenium import preserved — module imports without selenium installed).\n- Forbidden-pattern audit `rg -n \"^(import|from) |anthropic|openai|jinja|phase_z2|slide_measurer|1280|720|1400|900\"` → only stdlib imports (`argparse`, `hashlib`, `sys`, `dataclasses`, `pathlib`, `typing`). **No** AI/Jinja/`phase_z2`/`slide_measurer` substring; **no** `1280`/`720`/`1400`/`900` literal. RULE 7 (no hardcoding) holds.\n- **Predicate behavioral smoke** (`.orchestrator/tmp/u4_smoke.py`, gitignored temp): 6 cases — (1) `None` last_entry → False, (2) matching sha + png-newer-than-idx → True, (3) matching sha but stale png (older than idx) → False, (4) mismatched sha → False, (5) empty/missing `index_sha256` key → False, (6) missing index.html (post-unlink rediscover) → False. All assertions pass; final line `u4_predicate_ok` printed.\n- Scope guard: `git diff --name-only -- src/slide_measurer.py src/phase_z2_pipeline.py Front/vite.config.ts templates/phase_z2/frames tests figma_to_html_agent/blocks/_preview_manifest.json` → **empty output** (no tracked-file change outside `scripts/generate_frame_previews.py`).\n- Tracked status: `scripts/generate_frame_previews.py` is the only IMP-13 working-tree change; `figma_to_html_agent/blocks/_preview_manifest.json` is **not** created in u4 (correctly deferred to u6).\n\n**remaining_units**: [u5, u6, u7]\n\n**follow_up_issue_candidates**: none from this unit. Stage 2 already flagged IMP-04 (`missing_index_html=13`) and `data/figma_previews/index.json` parse failure as separate axes. u4 introduces no new out-of-scope dependency.\n\nrewind_target: continue_same\n"} |