74 lines
3.4 KiB
Markdown
74 lines
3.4 KiB
Markdown
# 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
|
|
|
|
- [x] The walk is iterative (worklist), never recursive — a deep provider
|
|
tree cannot overflow the stack.
|
|
- [x] 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).
|
|
- [x] 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.
|
|
- [x] Whole-bookmark writes are tmp-and-swap; overwriting an existing
|
|
bookmark never leaves a mix of old and new entries.
|
|
- [x] 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.
|
|
- [x] The capture runs on a spawned task; the orchestrator loop keeps
|
|
serving commands during a large walk.
|
|
- [x] No file contents in logs (paths, names, and counts only).
|
|
|
|
## Mutable top level (fsdy)
|
|
|
|
- [x] 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.
|
|
- [x] `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).
|
|
- [x] Rename validates the new title with the shared
|
|
`validate_folder_name` (reserved names rejected as targets) and never
|
|
merges onto an existing sibling (`InvalidInput`).
|
|
- [x] Delete is idempotent (already gone → success) and returns the
|
|
refreshed root listing; rename returns the renamed node at its new
|
|
path.
|
|
- [x] The `/queues` instance reserves `current`; `/bookmarks` reserves
|
|
nothing; `/fs` stays fully immutable.
|
|
- [x] Path traversal validation still happens only in `disk_path`; rename
|
|
and delete go through it for every path they touch.
|
|
|
|
## RPC and orchestrator
|
|
|
|
- [x] `capture_library_node` maps errors: invalid name/source →
|
|
`invalid_argument`, over-cap or disabled → `failed_precondition`,
|
|
walk/write failures → `internal`.
|
|
- [x] 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.
|
|
- [x] Bookmarks init is non-fatal: no config dir or an unopenable store
|
|
disables capture and the `/bookmarks` mount, never the server.
|
|
|
|
## TUI
|
|
|
|
- [x] `w` is bound in `Scope::Library` (queue's `w` untouched), has a help
|
|
description, and passes the bindings-table invariant tests unchanged.
|
|
- [x] The capture overlay opens only for a queueable bare selection,
|
|
prefilled with the selection's title; marks are ignored.
|
|
- [x] `MessageFromUi::CaptureNode` reaches the new rpc; a failed capture
|
|
is logged and never tears down the poll loop.
|
|
- [x] Renaming/deleting bookmark and saved-queue folders works through the
|
|
existing `e`/`d` flows with no TUI code changes.
|
|
|
|
## Hygiene
|
|
|
|
- [x] New public items are documented; docs state error/edge behavior.
|
|
- [x] `clippy -D warnings`, `fmt`, `taplo`, `markdownlint` clean on the
|
|
whole workspace; all tests green.
|
|
- [x] `architecture/queue-persistence.md` D8 reconciled (rename/delete of
|
|
saved queues is no longer out of scope).
|