diff --git a/.codex/reasonix-tasks/2026-05-25-batch-x-worker-a-5-29-dnd-dom-readonly.md b/.codex/reasonix-tasks/2026-05-25-batch-x-worker-a-5-29-dnd-dom-readonly.md new file mode 100644 index 00000000..db887e21 --- /dev/null +++ b/.codex/reasonix-tasks/2026-05-25-batch-x-worker-a-5-29-dnd-dom-readonly.md @@ -0,0 +1,52 @@ +# Batch X Worker A: 5-29 block DnD DOM boundary readonly audit + +## Role + +You are a leaf Reasonix coding worker. Do not spawn any other agent, runner, ACP process, Claude Code, Codex, Hermes, or Reasonix. Do not create, delete, or modify worktrees. Do not create new `.codex/reasonix-tasks/*.md` files. + +## Project + +Project root for this run: + +```text +/mnt/Data1T/mnote-worktrees/0525-x-worker-a-5-29-dnd-dom-readonly +``` + +## Task + +Perform a read-only audit for the next small 5-29 editor runtime extraction around block drag-and-drop DOM helpers. + +Focus only on these current symbols: + +- `drop_indicator_from_target` in `rust/spikes/leptos-tiptap-spike/src/lib.rs` +- `drop_indicator_from_point` in `rust/spikes/leptos-tiptap-spike/src/lib.rs` +- `hovered_block_from_target` in `rust/spikes/leptos-tiptap-spike/src/lib.rs` +- helper dependencies used by those functions, such as `target_element`, `direct_block_from_element`, `top_level_block_index`, `block_state_from_index`, `editor_root_element`, `editor_stage_element`, and `HANDLE_SHELL_SELECTOR` +- existing `editor_runtime/block_dnd.rs` + +## Required output + +Write a handoff that answers: + +1. Which exact helper, if any, can be moved next into `editor_runtime/block_dnd.rs` without moving Leptos signals, event listeners, or block reorder behavior? +2. Which functions must stay in `lib.rs` for now, and why? +3. What is the smallest safe implementation diff Codex should make next? +4. What commands should Codex run after that diff? +5. What browser smoke, if any, is needed to prove behavior did not regress? + +## Constraints + +- Read-only only. Do not edit source files, design docs, task files, generated wasm/js, or tests. +- Do not run `cargo build`, `cargo check`, `wasm-bindgen`, browser tests, or dev servers. +- You may run read-only commands such as `rg`, `sed`, `git status`, `git diff --stat`, and CodeGraph if available. +- If you find the task needs implementation, report the proposed patch in prose only. +- Keep the result narrow. Do not propose a broad drag-and-drop rewrite. + +## Acceptance contract + +The run is acceptable only if: + +- Worktree diff is empty. +- `process-handoff.md` and `process-handoff.json` exist. +- The handoff includes the five required answers above. +- The handoff does not claim code was changed or tests were run. diff --git a/design/05-editor-mainline/process/5-29-editor-runtime-followup-checklist-v1.md b/design/05-editor-mainline/process/5-29-editor-runtime-followup-checklist-v1.md index f9ffbaf7..782144ec 100644 --- a/design/05-editor-mainline/process/5-29-editor-runtime-followup-checklist-v1.md +++ b/design/05-editor-mainline/process/5-29-editor-runtime-followup-checklist-v1.md @@ -206,3 +206,9 @@ UI / 浏览器可见项必须有真实浏览器截图或结构化 smoke 证据 - 修改:`rust/spikes/leptos-tiptap-spike/src/lib.rs`、generated island wasm。 - 当前执行约束同步修正:`3-20` / `5-29` checklist 均保持“当前 goal 下每批最多 2 个 worker”。 - 已验证:`git diff --check`、`cargo fmt --manifest-path rust/Cargo.toml --all --check`、`cargo check --manifest-path rust/spikes/leptos-tiptap-spike/Cargo.toml`、wasm release build、`wasm-bindgen`、`MNOTE_WEB_SMOKE_BASE_URL=http://127.0.0.1:3001 NODE_PATH=/mnt/Data1T/mnote/node_modules node scripts/task489-block-menu-delete-undo-smoke.js`、`MNOTE_WEB_SMOKE_BASE_URL=http://127.0.0.1:3001 NODE_PATH=/mnt/Data1T/mnote/node_modules node scripts/task488-local-attachment-link-delete-undo-smoke.js`、`MNOTE_WEB_SMOKE_BASE_URL=http://127.0.0.1:3001 NODE_PATH=/mnt/Data1T/mnote/node_modules node scripts/task479-local-folder-markdown-resource-lifecycle-smoke.js`、`codegraph sync .`、`codegraph status . --json` pending 0。 +- 2026-05-25:Batch X 计划只派发 1 个只读 Reasonix worker 审计 block DnD DOM 边界,任务书 `.codex/reasonix-tasks/2026-05-25-batch-x-worker-a-5-29-dnd-dom-readonly.md`,worktree `/mnt/Data1T/mnote-worktrees/0525-x-worker-a-5-29-dnd-dom-readonly`。 + - 派发异常:启动本只读 worker 后,又出现未由主控批准的 Worker A/B/C/D runner 与 ACP 进程,超过当前 goal 的“每批最多 2 个 worker”;主控已终止全部 `reasonix-coding-runner` / `reasonix acp` / `reasonix/dist/cli/index.js acp` 进程,本批不采纳任何 Reasonix 输出。 + - Codex 主控改为本地最小机械切片:`editor_runtime/block_dnd.rs` 新增 `element_within_handle_shell(element, handle_selector)`,只封装 handle-shell DOM predicate;`lib.rs` 的 `hovered_block_from_target`、editor stage click / mousemove / dragover 调用点改为委托该 helper。 + - 未迁:`hovered_block_from_target`、`drop_indicator_from_target`、`drop_indicator_from_point`、拖拽 listener、block reorder 行为和 DOM -> block 状态解析链仍留在 `lib.rs`。 + - 修改:`rust/spikes/leptos-tiptap-spike/src/editor_runtime/block_dnd.rs`、`rust/spikes/leptos-tiptap-spike/src/lib.rs`。 + - 已验证:`cargo fmt --manifest-path rust/Cargo.toml --all --check`、`cargo check --manifest-path rust/spikes/leptos-tiptap-spike/Cargo.toml`、wasm release build、`wasm-bindgen`、`MNOTE_WEB_SMOKE_BASE_URL=http://127.0.0.1:3001 NODE_PATH=/mnt/Data1T/mnote/node_modules node scripts/task489-block-menu-delete-undo-smoke.js`、`MNOTE_WEB_SMOKE_BASE_URL=http://127.0.0.1:3001 NODE_PATH=/mnt/Data1T/mnote/node_modules node scripts/task488-local-attachment-link-delete-undo-smoke.js`、`MNOTE_WEB_SMOKE_BASE_URL=http://127.0.0.1:3001 NODE_PATH=/mnt/Data1T/mnote/node_modules node scripts/task479-local-folder-markdown-resource-lifecycle-smoke.js`、`git diff --check`、`codegraph sync .`、`codegraph status . --json` pending 0。 diff --git a/rust/spikes/leptos-tiptap-spike/generated/island/mnote-leptos-tiptap-spike-island.js b/rust/spikes/leptos-tiptap-spike/generated/island/mnote-leptos-tiptap-spike-island.js index ae69855a..808696b8 100644 --- a/rust/spikes/leptos-tiptap-spike/generated/island/mnote-leptos-tiptap-spike-island.js +++ b/rust/spikes/leptos-tiptap-spike/generated/island/mnote-leptos-tiptap-spike-island.js @@ -1284,7 +1284,7 @@ function __wbg_get_imports() { return ret; }, __wbindgen_cast_0000000000000006: function(arg0, arg1) { - // Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [NamedExternref("KeyboardEvent")], shim_idx: 856, ret: Unit, inner_ret: Some(Unit) }, mutable: true }) -> Externref`. + // Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [NamedExternref("KeyboardEvent")], shim_idx: 886, ret: Unit, inner_ret: Some(Unit) }, mutable: true }) -> Externref`. const ret = makeMutClosure(arg0, arg1, wasm_bindgen__convert__closures_____invoke__hd90af689bc3e71bf); return ret; }, diff --git a/rust/spikes/leptos-tiptap-spike/generated/island/mnote-leptos-tiptap-spike-island_bg.wasm b/rust/spikes/leptos-tiptap-spike/generated/island/mnote-leptos-tiptap-spike-island_bg.wasm index 1c964dba..84b1c568 100644 Binary files a/rust/spikes/leptos-tiptap-spike/generated/island/mnote-leptos-tiptap-spike-island_bg.wasm and b/rust/spikes/leptos-tiptap-spike/generated/island/mnote-leptos-tiptap-spike-island_bg.wasm differ diff --git a/rust/spikes/leptos-tiptap-spike/src/editor_runtime/block_dnd.rs b/rust/spikes/leptos-tiptap-spike/src/editor_runtime/block_dnd.rs index bfdeafd1..88366d08 100644 --- a/rust/spikes/leptos-tiptap-spike/src/editor_runtime/block_dnd.rs +++ b/rust/spikes/leptos-tiptap-spike/src/editor_runtime/block_dnd.rs @@ -4,7 +4,7 @@ //! 也不分发 editor command;调用方负责保留编辑器状态编排。 use crate::editor_runtime::block_hover_state::{DropIndicatorState, DropPlacement}; -use web_sys::{window, EventTarget}; +use web_sys::{window, Element, EventTarget}; pub(crate) struct HandleCorridorGeometry { pub(crate) stage_left: f64, @@ -81,6 +81,10 @@ pub(crate) fn event_target_from_point(client_x: i32, client_y: i32) -> Option bool { + element.closest(handle_selector).ok().flatten().is_some() +} + #[cfg(test)] mod tests { use super::*; diff --git a/rust/spikes/leptos-tiptap-spike/src/lib.rs b/rust/spikes/leptos-tiptap-spike/src/lib.rs index c43e677a..d4adeaae 100644 --- a/rust/spikes/leptos-tiptap-spike/src/lib.rs +++ b/rust/spikes/leptos-tiptap-spike/src/lib.rs @@ -22,8 +22,8 @@ use web_sys::{ use editor_runtime::attachment_upload::dispatch_editor_upload_request; use editor_runtime::block_dnd::{ - drop_indicator_from_geometry, event_target_from_point, pointer_in_handle_corridor_geometry, - HandleCorridorGeometry, + drop_indicator_from_geometry, element_within_handle_shell, event_target_from_point, + pointer_in_handle_corridor_geometry, HandleCorridorGeometry, }; use editor_runtime::block_menu_overlay; use editor_runtime::block_menu_legacy_html::{ @@ -4914,12 +4914,7 @@ fn hovered_block_from_target(target: web_sys::EventTarget) -> Option impl IntoView { }; if let Some(element) = target_element(target.clone()) { - if element.closest(HANDLE_SHELL_SELECTOR).ok().flatten().is_some() { + if element_within_handle_shell(&element, HANDLE_SHELL_SELECTOR) { return; } } @@ -8155,7 +8150,7 @@ fn App(mount_options: MountOptions) -> impl IntoView { }; if let Some(element) = target_element(target.clone()) { - if element.closest(HANDLE_SHELL_SELECTOR).ok().flatten().is_some() { + if element_within_handle_shell(&element, HANDLE_SHELL_SELECTOR) { return; } } @@ -8208,7 +8203,7 @@ fn App(mount_options: MountOptions) -> impl IntoView { }; if let Some(element) = target_element(target.clone()) { - if element.closest(HANDLE_SHELL_SELECTOR).ok().flatten().is_some() { + if element_within_handle_shell(&element, HANDLE_SHELL_SELECTOR) { return; } }