# Plan — editable and deletable nodes Ordered tasks for the `implement` stage. Inputs: `architecture/node-editing.md`, stubs across the workspace, gates in `quality/node-editing.md`. Tests: `devenv shell -- cargo test --workspace` (10 failing at plan time = the target: 5 in tidaldy, 5 in cbd-tui). Use the session-local `CARGO_TARGET_DIR` if `target/` contains artifacts owned by the repo owner. ## 1. Term-list mutations (tidaldy) - [x] Implement `rename_search_term(old, new)`: under one write lock, if `new` already exists remove the `old` slot (merge); else if `old` exists replace it in place; else push `new` (stale-client forgiveness). Implement `remove_search_term(term)`: `retain` everything but `term`. Both poison-tolerant like `register_search_term`, no await under the lock. **Verify**: `rename_replaces_in_place_and_merges_duplicates` passes; gate "lock discipline". ## 2. Provider rename/delete (tidaldy) - [x] `rename_lib_node`: trim new title → `InvalidInput` if empty; `parse_path(path)?` must be `TidalPath::SearchTerm(old)` else `NotSupported`; decode old term, `rename_search_term`, return `get_lib_node(join_path(parent, encode_segment(new)))`. **Verify**: `rename_rejects_empty_titles_and_foreign_paths` passes (validation before any network call). - [x] `delete_lib_node`: `parse_path(path)?` must be `SearchTerm` else `NotSupported`; decode + `remove_search_term` (idempotent); return `get_lib_node(/tidal/search)`. **Verify**: `delete_rejects_foreign_paths` and `delete_removes_terms_idempotently_and_returns_the_parent` pass. - [x] Flag term children in the `Search` arm of `get_lib_node`: `is_editable: true, is_deletable: true` via struct update. **Verify**: `search_node_lists_created_terms` passes (extended assertion). ## 3. Server handlers (crabidy-server) - [x] Replace the `todo!()` bodies of `rpc.rs rename_library_node`/`delete_library_node`: record span fields, bounded(1) rendezvous with the matching `ProviderCommand`, map errors exactly like `create_library_node` (`NotSupported` → `failed_precondition` with an operation-specific message, `InvalidInput` → `invalid_argument`, rest → `internal`). **Verify**: gates "error mapping" + "bounded rendezvous"; `cargo check`. (Orchestrator routing and the command-loop arms were finalized at stub time — re-read them against the gate rather than re-doing them.) ## 4. TUI library accessors + marker (cbd-tui) - [x] Implement `Library::selected_editable` / `selected_deletable` from `list_state.selected()` + the `UiItem` flags. **Verify**: `edit_opens_the_overlay_prefilled_only_on_editable_selections`, `delete_sends_only_for_deletable_selections`, `rename_submit_sends_the_trimmed_new_title`, `rename_cancels_and_emptied_buffers_send_nothing` pass (dispatch and overlay logic already landed with the stubs). - [x] Render the `[e]`/`[d]`/`[ed]` suffix for modifiable items in `Library::render`, `COLOR_SECONDARY` like `[%]`. **Verify**: `modifiable_items_are_marked_and_the_rename_overlay_is_labelled` passes; gate "marked in UI". ## 5. TUI ↔ server wiring (cbd-tui) - [x] `RpcClient::rename_library_node`: send the rpc, evict the old path and the parent (`crabidy_core::parent_path`), insert + return the renamed node. `delete_library_node`: send the rpc, evict the deleted path and the parent, insert + return the returned parent node. **Verify**: gate "cache eviction" (read; the cache is private, as with create). - [x] `main.rs poll`: replace the `todo!()` arms — `RenameNode` calls `rename_library_node`, `DeleteNode` calls `delete_library_node`; on success `ReplaceLibraryNode(node)`, on failure `error!` and leave the UI unchanged. **Verify**: gate "failures never panic". ## 6. End-to-end + gates sweep - [x] Exercise the full path against the live API if the local tidal config is available (create a term, rename it, delete it, confirm the parent listing and that a queued search track still resolves a URL); note the outcome in the summary. If unavailable, rely on the offline tests and say so. - [x] Sweep: no `todo!()` left (workspace grep), fmt + clippy + tests green, every `quality/node-editing.md` box checked, docs updated where behavior shifted. Append the outcome + deviations to `plan/summary.md`.