# Workflow * branch (from `main`) * do the work in Next Step * move Next Step to the top of Completed Steps * move the top item of Future Steps into Next Step * commit (`TODO.md` changes in the same commit as the work) * merge to `main` if the branch is not protected, otherwise open a PR * push # Status pre-1.0 # Next Step Triage the stale remote branches (issue #71): for each, merge the work or delete the branch. # Completed Steps - 2026-08-09: Stopped `script/cibuild` from reporting a green it did not earn (issue #85). A bare `docker build .` let Docker serve the check layers from the layer cache whenever the tree had not changed: the checks never executed and the build still exited 0. The fix is an `ARG CHECK_EPOCH` declared immediately above the check `RUN`s in both the lint stage and the builder stage (`ARG` scope is per-stage, so each declares its own), with `script/cibuild` assigning `epoch="$(date +%s)"` and passing `--build-arg CHECK_EPOCH="$epoch"`. The assignment is separate on purpose: under `set -eu` a command substitution that fails inside an argument does not abort the script, which would leave an empty constant `CHECK_EPOCH` and restore the very false green being fixed. Placement is the rest of the point — the `ARG` sits below the `apk add`, `COPY go.mod go.sum`, and `go mod download` layers, so only the checks are invalidated and the dependency layers still cache. The guarantee is conditional on a fresh value rather than absolute: a bare `docker build .` gets an empty `CHECK_EPOCH` and can still serve the check layers from cache, which `README.md` and the `Dockerfile` now say plainly, with issue #91 tracking the upstream hardening (expanded `ARG` form, unset guard, per-invocation epoch, `script/docker`) that would close it. Verified by re-running the reproduction plus the withheld-`--build-arg` counterfactual; the measurements are recorded once, in the PR #89 verification comment, rather than restated here. `.golangci.yml`, the lint-stage `FROM` line and its digest, `script/lint`, and `.gitea/workflows/check.yml` are all untouched. - 2026-08-09: Corrected the `Vaultik.UI` doc comment (issue #84). It claimed the cli layer replaces the writer with a discarding one in `--cron` mode; the actual mechanism is `UI.SetQuiet(true)` in `setupGlobals`, which drops Begin/Complete/Info/Notice/Detail/ Progress/Banner but still emits Warning and Error. The `--cron` line in `README.md` said "Silent unless error", which understated what survives, and now names warnings too. The other `--cron` comments (`internal/log/log.go`, `internal/cli/snapshot.go`, `internal/vaultik/snapshot.go`) were audited and already accurate. Comments and docs only, no behavior change. - 2026-08-09: Made `snapshot list` list the destination store without the private key (issue #64). The listing is now the union of the local index and a single streamed listing of the `metadata/` prefix, with no `age_secret_key` gate — the manifest is unencrypted, so a host holding only the public key can enumerate its own backups and a host that lost its local index can still see them. A remote-only snapshot's hostname and name are deliberately not recovered (they are not recoverable without the private key, and making them so would undo the privacy property tracked in issue #81); such rows are labelled by an abbreviation of their remote key and carry the real timestamp and compressed size from the manifest, with `` in the two columns that require the local index. Local-only snapshots are reported as drift, and the hint now names `vaultik prune`, which exists, instead of `vaultik snapshot cleanup`, which does not. `reportRemoteDrift` collapsed into the merged view. Every remote manifest read in the codebase now goes through `downloadManifestByKey`, so issue #81 has one call site to change. Review rework: snapshot timestamps now normalize to UTC in `scanSnapshotRows`, the one place they enter the domain, so the merged TIMESTAMP column cannot show local time for a locally tracked row and UTC for a remote-only row on a non-UTC host; `GetIncompleteByHostname` was folded onto that same scanner. `--json` now reports the unreadable-manifest count and the 1000-row truncation on stderr instead of returning a silently short document (the document's shape is unchanged). The two per-snapshot `log.Warn` calls on the listing path now route through the same JSON-aware writer as the existing workaround, so one corrupt manifest can no longer put a log line on stdout ahead of the document and break `| jq` — still a local workaround pending issue #82. Verified with `script/cibuild` and with an uncached `make check` (`0 issues.`, no cached test packages), plus end to end against a `file://` destination with no secret key present. - 2026-08-09: Closed the gap between `make lint` and CI (issue #78). `script/lint` now runs the digest-pinned `golangci-lint` image taken from the `Dockerfile` lint stage, which is the single source of truth for the linter version; the duplicate pin in the `Makefile` `deps` target and the unpinned `golangci-lint` install in `script/bootstrap` are gone. A `golangci-lint` on `PATH` is used only when its version is exactly the pinned one (which is how the lint stage runs it inside the container); anything else goes through Docker, and a missing or unreachable Docker daemon is a hard error rather than a silent fallback. `make check` is therefore now as trustworthy as `script/cibuild`. - 2026-08-09: Finished the lint remediation under the canonical `.golangci.yml` (issue #61, which also unblocks issue #59). The remaining findings were fixed behavior-preservingly: `wsl_v5` whitespace, `sqlclosecheck`, and `prealloc`. The `sqlclosecheck` sites now close `sql.Rows` in a deferred closure instead of via the `CloseRows` helper, which the linter could not see through. Only the `revive` package-name findings remain suppressed, with per-site `//nolint` directives; the package-rename question behind them is tracked in issue #76. Verified with `script/cibuild`, which exits 0 — that is the only trustworthy gate, because `script/lint` runs whatever `golangci-lint` happens to be on `PATH` rather than the pinned v2.12.2 that CI and the `Dockerfile` use, so `make check` can report green on findings CI still fails. That tooling gap is tracked in issue #78. - 2026-08-09: The earlier next step "reconcile the uncommitted `ARCHITECTURE.md` edits on `main`" needed no work: the working tree is clean and `ARCHITECTURE.md` is committed on `main`. - 2026-08-07: Updated golangci-lint to v2.12.2 everywhere it is pinned (`Dockerfile` lint stage, `Makefile` deps target), replaced `.golangci.yml` with the canonical config (v2 schema, `default: all`), and remediated the bulk of the lint findings it surfaced (issue #61): behavior-preserving fixes across every package, 2,990 findings down to 80. `make test` and `make fmt-check` were green at that point but `make lint` was still red; the commit message claiming `make check` was green was wrong. - 2026-08-07: Added the standard `.golangci.yml` and `.editorconfig` (issue #59); lint findings under the new config are tracked in issue #61. `script/bootstrap` now installs sqlite3 (needed by tests). - 2026-07-07 Adopted scripts-to-rule-them-all: `script/` entrypoints, Makefile shims, README Entrypoints section - 2026-07-02: Consolidated CLI verbs, retired overlapping commands; bound the local index to its backup destination URL. - 2026-06-28: snapshot rm now removes metadata only and prints the prune command; restore skips chown when running as non-root. - 2026-06-26: Snapshot IDs hashed at the storage boundary; snapshot list made resilient to bad remote entries. - 2026-06-24: Collapsed snapshot prune into vaultik prune; restore streams blobs to disk and restores files in blob-locality order; cron output fixes. - 2026-06-17: Restore overhaul: ReadAt chunk reads from cached blobs, reference-counted blob sweeper, integration tests; new internal/ui output layer, banner, and progress lines. - 2025-12-18: Added ARCHITECTURE.md and godoc coverage for exported API. - 2025-07-26: End-to-end integration tests; manifest format refactor; renamed backup to snapshot; afero filesystem abstraction. - 2025-07-20: Initial design and implementation: cobra + fx CLI skeleton, SQLite index database, UUID blob storage with streaming chunking. # Future Steps - Define remaining scope for a first tagged release and cut v0.1.0.