From 42f4e648d7b057213e4356615069270aee534b64 Mon Sep 17 00:00:00 2001 From: clawbot <35+clawbot@noreply.example.org> Date: Tue, 22 Sep 2026 09:05:36 +0200 Subject: [PATCH] Reconcile docs with code across the accuracy-sweep items (closes #74) Docs-only sweep of the accuracy items. Corrected ARCHITECTURE.md chunk sizes and the fx config type; documented the ls/rm aliases, the CPU/MEM profile env vars, the age_secret_key threat-model caveat, the four zstd presets, and a new locking section for the process-wide PID lock. Narrowed the internal/ui output claim to what holds today (refactor deferred to https://git.eeqj.de/sneak/vaultik/issues/149); lock-scoping deferred to https://git.eeqj.de/sneak/vaultik/issues/150. Added the missing ARCHITECTURE.md and config.example.yml README links. Every claim re-verified against the tree. Disclosure: a pre-existing gomodguard linter deprecation surfaced during the gate; unrelated. Model: opus-4-8 --- ARCHITECTURE.md | 6 +++--- README.md | 50 +++++++++++++++++++++++++++++++++++++++++-------- 2 files changed, 45 insertions(+), 11 deletions(-) diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md index a93fe6a..17d7cf4 100644 --- a/ARCHITECTURE.md +++ b/ARCHITECTURE.md @@ -63,7 +63,7 @@ A content-addressed unit of data. Files are split into variable-size chunks usin - `ChunkHash`: SHA256 hash of chunk content (primary key) - `Size`: Chunk size in bytes -Chunk sizes vary between `avgChunkSize/4` and `avgChunkSize*4` (typically 16KB-256KB for 64KB average). +Chunk sizes vary between `avgChunkSize/4` and `avgChunkSize*4` (2.5MB-40MB for the 10MB default average). #### FileChunk (`database.FileChunk`) Maps files to their constituent chunks: @@ -120,7 +120,7 @@ The CLI uses fx for dependency injection. Here's the instantiation order: ```go // cli/app.go: NewApp() fx.New( - fx.Supply(config.ConfigPath(opts.ConfigPath)), // 1. Config path + fx.Supply(config.Path(opts.ConfigPath)), // 1. Config path fx.Supply(opts.LogOptions), // 2. Log options fx.Provide(globals.New), // 3. Globals fx.Provide(log.New), // 4. Logger config @@ -193,7 +193,7 @@ scanner := v.ScannerFactory(snapshot.ScannerParams{ - **Created by**: `chunker.NewChunker(avgChunkSize)` - **When**: Inside `snapshot.NewScanner()` - **Configuration**: - - `avgChunkSize`: From config (typically 64KB) + - `avgChunkSize`: From config (default 10MB) - `minChunkSize`: avgChunkSize / 4 - `maxChunkSize`: avgChunkSize * 4 diff --git a/README.md b/README.md index dc1e541..64e8f1e 100644 --- a/README.md +++ b/README.md @@ -147,10 +147,10 @@ vaultik [--config ] config edit vaultik [--config ] config get vaultik [--config ] config set vaultik [--config ] snapshot create [snapshot-names...] [--cron] [--prune] [--keep-newer-than ] -vaultik [--config ] snapshot list [--json] +vaultik [--config ] snapshot list [--json] # alias: ls vaultik [--config ] snapshot verify [--deep] [--json] vaultik [--config ] snapshot purge [--keep-latest | --older-than ] [--snapshot ...] [--force] -vaultik [--config ] snapshot remove [--dry-run] [--force] [--local-only] [--json] +vaultik [--config ] snapshot remove [--dry-run] [--force] [--local-only] [--json] # alias: rm vaultik [--config ] snapshot restore [paths...] [--verify] vaultik [--config ] prune [--force] [--json] vaultik [--config ] info @@ -169,6 +169,21 @@ vaultik version * `--quiet`, `-q`: Suppress non-error output (also suppresses startup banner) * `--skip-errors`: Continue past per-file errors instead of aborting (applies to `snapshot create` and `restore`) +### locking + +Every command that opens the local index — `snapshot create`, `snapshot +list`, `snapshot verify`, `snapshot purge`, `snapshot remove`, `snapshot +restore`, `prune`, `info`, and `remote info`/`remote nuke` — takes a +process-wide lock at `$XDG_DATA_HOME/vaultik/vaultik.pid` +(`~/.local/share/vaultik/vaultik.pid` on Linux) for the whole run. Only +one such command runs at a time: a second one exits immediately with an +"already running" error rather than waiting. The lock is not scoped to +mutating commands, so read-only commands are affected too — `vaultik +snapshot list` fails while a backup is in progress; scoping it so +read-only commands run during a backup is tracked in +[issue #150](https://git.eeqj.de/sneak/vaultik/issues/150). `config`, +`database delete`, `completion`, and `version` do not take the lock. + ### stdout and stderr Log output — everything from `--verbose` and `--debug`, and every @@ -203,6 +218,8 @@ and `vaultik prune --json | jq .` both work as written. * `VAULTIK_AGE_SECRET_KEY`: Age private key for decryption (required for `snapshot restore` and `snapshot verify --deep`) * `VAULTIK_CONFIG`: Path to config file (overridden by `--config`) * `VAULTIK_INDEX_PATH`: Override local SQLite index path +* `VAULTIK_CPUPROFILE`: Write a CPU profile to this path for the duration of the run (development/debugging) +* `VAULTIK_MEMPROFILE`: Write a heap profile to this path when the run exits (development/debugging) ### shell completion @@ -395,6 +412,10 @@ both are set. ## architecture +For an implementation-level view of the internals — the data model, the +`fx` dependency-injection wiring, and the scanner — see +[`ARCHITECTURE.md`](ARCHITECTURE.md). + ### remote storage layout ``` @@ -472,19 +493,24 @@ derivation. ### compression -* zstd compression at configurable level (1-19, default 3) +* zstd compression at configurable level (1-19, default 3). The level is + accepted as 1-19 but maps onto zstd's four internal speed presets: + 1-2 fastest, 3-5 default, 6-9 better, 10-19 best. Levels within the + same band compress identically. * Applied before encryption at the blob level --- ## configuration reference -Run `vaultik config init` to generate a fully commented config file. -Key fields: +Run `vaultik config init` to generate a fully commented config file; a +complete annotated example also lives in +[`config.example.yml`](config.example.yml). Key fields: | Field | Default | Description | |-------|---------|-------------| | `age_recipients` | (required) | Age public keys for encryption | +| `age_secret_key` | (unset) | Age private key for decryption (`snapshot restore`, `snapshot verify --deep`). Setting it in the config file places the private key on the backed-up host, defeating the public-key-only design (see "why" above). Prefer the `VAULTIK_AGE_SECRET_KEY` environment variable, supplied only on the machine you restore from. | | `snapshots` | (required) | Named snapshot definitions with paths and excludes | | `storage_url` | | Storage backend URL (`s3://`, `file://`, `rclone://`) | | `s3.*` | | Legacy S3 configuration (endpoint, bucket, credentials) | @@ -600,9 +626,17 @@ priority. ## output style -All user-facing output goes through helpers in `internal/ui` and conforms -to a uniform style. Color is enabled when stdout is a TTY and the -`NO_COLOR` environment variable is unset (https://no-color.org/). +The operational narration of the long-running commands — the Begin, +Complete, Progress, and status lines of `snapshot create`, `prune`, +`snapshot restore`, and the like — goes through helpers in `internal/ui` +and conforms to the uniform style below. Some commands instead write +plain text straight to stdout (`version`, `info`, `config`, the +`database delete` prompt, and the `snapshot list` table); that output is +unstyled and does not honor `--quiet`. Routing it through `internal/ui` +is tracked in +[issue #149](https://git.eeqj.de/sneak/vaultik/issues/149). Color is +enabled when stdout is a TTY and the `NO_COLOR` environment variable is +unset (https://no-color.org/). `internal/ui` writes to stdout; it is the output the user asked for. Structured log records are a different thing and go through