- session.rs: drop save_manifest_raw — its only caller was
after_manifest_change itself; the pub(crate) advertised the exact
bypass-the-cache-refresh footgun the wrapper exists to eliminate.
Inline the encrypt + atomic_write pair.
- session.rs: into_kdf_params(self) → to_kdf_params(&self). Body just
copies three u32s; the consume-self had no ownership benefit and
forced the round-trip test to rebuild a ParamsFile field-by-field.
- helpers.rs: add git_rm(repo, paths, context) wrapper around git_run
+ the load-bearing --ignore-unmatch flag. Replaces two near-identical
three-line "build rm_args, extend, git_run" blocks in trash.rs.
- trash.rs: purge_item_filesystem drops the if x.exists() pre-checks
(TOCTOU + redundant stat per item per trash-empty iteration). Uses
ErrorKind::NotFound swallow on remove_file/remove_dir_all instead.
- basic_flows.rs: trim trash_empty_batches_into_one_commit's sleep
comment to just the WHY.
Renames purge_item to purge_item_filesystem — body becomes filesystem-only
(remove item.enc, remove attachments/<id>/, manifest.remove). Returns the
relative paths it removed. cmd_purge and cmd_trash_empty accumulate the
paths and fire ONE git rm + ONE git add + ONE git commit per invocation.
A 50-item trash empty now produces 3 git subprocesses regardless of N
(was N+2). New regression test trash_empty_batches_into_one_commit asserts
the one-commit invariant via git rev-list --count.
Uses assert_cmd + tempfile to spin up a fresh vault per test.
Covers init layout, add/list/get mask semantics, rm/restore/purge cycle,
and generate smoke. Adds RELICARIO_TEST_PASSPHRASE env-var hatch in
unlock_interactive and cmd_init so tests don't need a TTY.
Also fixes read_params in session.rs to correctly parse the nested
params.json format (kdf sub-object) rather than trying to deserialize
the whole file as KdfParams.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>