crabidy/quality/bookmarks.md

3.4 KiB

Quality gates: bookmarks

Criteria the implementation must satisfy beyond the automatic tests (fsdy/src/lib.rs, crabidy-server/src/bookmark_store.rs, plus the TUI tests added during implementation). Each gate is pass/fail by reading the code.

Capture

  • The walk is iterative (worklist), never recursive — a deep provider tree cannot overflow the stack.
  • The caps bound total directories and tracks and abort with a typed error; the temp folder is removed on every failure path (cap, walk error, write error).
  • Captures write through the same primitives as queues (TrackFile::from_track, track_file_name, and dir_name sharing one sanitizer) — no second serialization or naming scheme.
  • Whole-bookmark writes are tmp-and-swap; overwriting an existing bookmark never leaves a mix of old and new entries.
  • A source path that is a track captures as a folder with one file; an unreadable source is BadSource, not a panic or an empty bookmark.
  • The capture runs on a spawned task; the orchestrator loop keeps serving commands during a large walk.
  • No file contents in logs (paths, names, and counts only).

Mutable top level (fsdy)

  • The is_editable/is_deletable flags appear only on direct child folders of an editable instance's root, never on reserved names, nested nodes, tracks, or immutable instances.
  • rename_lib_node/delete_lib_node enforce the same gate they advertise: option on + direct child + not reserved; everything else is NotSupported (matching the flags a client saw).
  • Rename validates the new title with the shared validate_folder_name (reserved names rejected as targets) and never merges onto an existing sibling (InvalidInput).
  • Delete is idempotent (already gone → success) and returns the refreshed root listing; rename returns the renamed node at its new path.
  • The /queues instance reserves current; /bookmarks reserves nothing; /fs stays fully immutable.
  • Path traversal validation still happens only in disk_path; rename and delete go through it for every path they touch.

RPC and orchestrator

  • capture_library_node maps errors: invalid name/source → invalid_argument, over-cap or disabled → failed_precondition, walk/write failures → internal.
  • The orchestrator routes /bookmarks in every ProviderClient method (same completeness as /queues), and get_lib_root lists the bookmarks child only when the instance exists.
  • Bookmarks init is non-fatal: no config dir or an unopenable store disables capture and the /bookmarks mount, never the server.

TUI

  • w is bound in Scope::Library (queue's w untouched), has a help description, and passes the bindings-table invariant tests unchanged.
  • The capture overlay opens only for a queueable bare selection, prefilled with the selection's title; marks are ignored.
  • MessageFromUi::CaptureNode reaches the new rpc; a failed capture is logged and never tears down the poll loop.
  • Renaming/deleting bookmark and saved-queue folders works through the existing e/d flows with no TUI code changes.

Hygiene

  • New public items are documented; docs state error/edge behavior.
  • clippy -D warnings, fmt, taplo, markdownlint clean on the whole workspace; all tests green.
  • architecture/queue-persistence.md D8 reconciled (rename/delete of saved queues is no longer out of scope).