diff --git a/crates/ff-engine/src/edit.rs b/crates/ff-engine/src/edit.rs index 417cb50..3ce65af 100644 --- a/crates/ff-engine/src/edit.rs +++ b/crates/ff-engine/src/edit.rs @@ -1200,9 +1200,22 @@ pub fn apply_edits( .map(|&i| &entries[i as usize].path) .collect(); nested_paths.sort_by(|a, b| b.len().cmp(&a.len()).then(b.cmp(a))); + let mut touched_roots: Vec = nested_paths.iter().map(|p| p[0]).collect(); for path in nested_paths { remove_form_child(&page, path)?; } + // ĐÁNH THỨC trang: GenerateContent chỉ ghi lại stream trang khi có + // object CẤP TRANG dirty; rút con mới làm FORM dirty thôi — op thuần + // trong form (Delete...) không đụng cấp trang → trang không regenerate + // → ProcessForm (nơi ghi lại form) không bao giờ chạy. Nhân identity + // vào form tổ tiên cấp trang: Transform luôn SetDirty, giá trị không + // đổi → trang được ghi lại → form được ghi lại theo. + touched_roots.sort_unstable(); + touched_roots.dedup(); + for r in touched_roots { + let mut root = object_at_path(&page, &[r])?; + root.apply_matrix(PdfMatrix::IDENTITY).map_err(err)?; + } // Cấp trang: xoá thật theo index trang GIẢM DẦN. let mut page_idxs: Vec = to_remove .iter() diff --git a/docs/12-phase4-summary.md b/docs/12-phase4-summary.md index 6b9fe5d..94a27d1 100644 --- a/docs/12-phase4-summary.md +++ b/docs/12-phase4-summary.md @@ -39,9 +39,17 @@ Type0/CID nhúng), trong khi `list_objects` chỉ duyệt object cấp trang. ff-engine lẫn app): wrapper 0.8.37 gate `remove_object` của form chỉ mở cho 7350/future dù binding có đủ cho 7543 (sót gate upstream); API 7350 là subset của DLL bblanchon mới → không mất gì (đã quét: 0 hàm 7543-only). +- **Bài học CI vòng 2 — "đánh thức" trang**: `GenerateContent` chỉ ghi lại + stream trang khi có object CẤP TRANG dirty; rút con chỉ làm FORM dirty → + op thuần trong form (Delete) không kích hoạt gì → `ProcessForm` không chạy. + Fix: sau khi rút con, nhân identity matrix vào form tổ tiên cấp trang + (Transform luôn SetDirty, giá trị không đổi) → trang regenerate → form + regenerate theo. - CI test chạy `--test-threads=1`: PDFium serialize qua 1 mutex toàn cục — - 1 test panic khi giữ lock sẽ poison mutex, 17 test song song chết oan - (đã dính ở CI vòng 1). + 1 test panic (kể cả panic Ở ASSERT khi instance Pdfium còn sống — unwind + drop guard giữa panic) sẽ poison mutex, mọi test SAU đó trong cùng process + chết oan tại thread_safe.rs:76. Khi đọc log CI: chỉ failure ĐẦU TIÊN là + lỗi thật. - Vá kèm: đọc source crate pdfium-render tải từ crates.io để chốt API vì máy dev không compile được Rust (xem mục CI bên dưới).