Rewrite README.md and the other prose documents sentence by sentence (closes #397, closes #398) #399

Open
clawbot wants to merge 14 commits from docs/397-rewrite-prose-documents into next
pull from: docs/397-rewrite-prose-documents
Collaborator

Rewrites the four prose documents from scratch under the rules on #397. Also says what each command needs in its --help text and in config.example.yml, for #398.

Rewritten: README.md, ARCHITECTURE.md, docs/DATAMODEL.md, docs/REPOSTRUCTURE.md. None passed as it was. Left alone as out of scope: REPO_POLICIES.md and AGENTS.md. TODO.md changes only under "Future Steps".

Where the old text disagreed with the code on next:

  • snapshot verify --deep needs the private key; no document or help text said so.
  • The key is also read from age_secret_key; restore named only the environment variable.
  • age-keygen | grep in config.example.yml discards the private key.
  • config init does not explain every setting; five are absent from its file.
  • snapshot remove refuses a remote key.
  • A restore reads only db.zst.age, never the manifest.
  • blobs.blob_hash holds a placeholder, not NULL, until the blob is closed.
  • blob_chunks rows are written when the blob is closed, not at once.
  • Queries are parameterised, not prepared.
  • files.source_path, local_meta, schema_migrations and five indexes were undocumented.
  • No command creates a snapshot ID without a name.
  • A blob is uploaded again when its look-up is refused.
  • ARCHITECTURE.md named BlobWithReader, PurgeSnapshots, an S3 client and repository interfaces that do not exist.

Not settled here: the README's roadmap is unbuilt work, so it moved to TODO.md; the README's branch rule now follows REPO_POLICIES.md, not "merge to main".

Code bugs seen, not fixed: two error messages name only VAULTIK_AGE_SECRET_KEY; snapshot remove cannot remove a remote-only snapshot.

The first comment has the detail for the reviewer.

Model: fable-5-1

Rewrites the four prose documents from scratch under the rules on https://git.eeqj.de/sneak/vaultik/issues/397. Also says what each command needs in its `--help` text and in `config.example.yml`, for https://git.eeqj.de/sneak/vaultik/issues/398. **Rewritten:** `README.md`, `ARCHITECTURE.md`, `docs/DATAMODEL.md`, `docs/REPOSTRUCTURE.md`. None passed as it was. Left alone as out of scope: `REPO_POLICIES.md` and `AGENTS.md`. `TODO.md` changes only under "Future Steps". **Where the old text disagreed with the code on `next`:** - `snapshot verify --deep` needs the private key; no document or help text said so. - The key is also read from `age_secret_key`; restore named only the environment variable. - `age-keygen | grep` in `config.example.yml` discards the private key. - `config init` does not explain every setting; five are absent from its file. - `snapshot remove` refuses a remote key. - A restore reads only `db.zst.age`, never the manifest. - `blobs.blob_hash` holds a placeholder, not `NULL`, until the blob is closed. - `blob_chunks` rows are written when the blob is closed, not at once. - Queries are parameterised, not prepared. - `files.source_path`, `local_meta`, `schema_migrations` and five indexes were undocumented. - No command creates a snapshot ID without a name. - A blob is uploaded again when its look-up is refused. - `ARCHITECTURE.md` named `BlobWithReader`, `PurgeSnapshots`, an S3 client and repository interfaces that do not exist. **Not settled here:** the README's roadmap is unbuilt work, so it moved to `TODO.md`; the README's branch rule now follows `REPO_POLICIES.md`, not "merge to `main`". **Code bugs seen, not fixed:** two error messages name only `VAULTIK_AGE_SECRET_KEY`; `snapshot remove` cannot remove a remote-only snapshot. The first comment has the detail for the reviewer. Model: fable-5-1
clawbot added the needs-review label 2026-11-06 19:37:19 +01:00
clawbot added 8 commits 2026-11-06 19:37:19 +01:00
Rewrite README.md sentence by sentence
check / check (push) Successful in 10m57s
de9ef62073
Rewritten from scratch against the code on next: what the program is,
how to use it, a command reference that says what each command needs,
the configuration reference as nested bullets, then development and
releasing.

snapshot verify --deep now says it needs the private key, from
VAULTIK_AGE_SECRET_KEY or age_secret_key, as snapshot restore does.

The roadmap section is removed: it described features that are not
built.

Model: fable-5-1
Rewrite ARCHITECTURE.md sentence by sentence
check / check (push) Successful in 9m24s
43c9b2c39b
Rewritten from scratch against the code on next: the packages, the fx
wiring, and the steps of a backup, a restore, a verify and a prune.

Names that no longer exist in the code are gone: the S3 client as the
upload step, blob.BlobWithReader, PurgeSnapshots and the repository
interfaces. The storage layer is described through storage.Storer.

Model: fable-5-1
Rewritten from scratch against internal/database on next. Every table
and column in schema/001.sql is listed, with the indexes.

Added what the old text lacked: files.source_path, the local_meta and
schema_migrations tables, and five indexes. Corrected what it had
wrong: blobs.blob_hash holds a placeholder, not NULL, until the blob is
closed; blob_chunks rows are written when the blob is closed; queries
are parameterised, not prepared.

Model: fable-5-1
Turn two comma chains in ARCHITECTURE.md into lists
check / check (push) Successful in 9m47s
63f8d4df59
Model: fable-5-1
Rewrite docs/REPOSTRUCTURE.md sentence by sentence
check / check (push) Failing after 16m10s
8654d9b7f5
Rewritten from scratch against the code on next: the layout of the
destination, what it protects, the accepted risks, the order of writes
and the rules that keep prune from deleting data in use.

Corrected: a restore needs only db.zst.age and the blobs it reads, not
the manifest. The snapshot ID form without a name is gone, since no
command creates one.

Model: fable-5-1
Model: fable-5-1
snapshot verify --help now says --deep needs the age private key, from
VAULTIK_AGE_SECRET_KEY or age_secret_key, as snapshot restore does.
Both now name the config key as well as the environment variable.

The help of snapshot create, list, purge, remove, prune, remote info
and remote nuke says which access to the destination it needs.
config.example.yml gains age_secret_key, and no longer tells the reader
to pipe age-keygen into grep, which discards the private key.

Only help strings and comments change.

Model: fable-5-1
Split sentences that carried two or three ideas, turned the cases in
which a backup does not find a mount point into a list, and named the
figures that remote info reports as unknown.

Model: fable-5-1
clawbot self-assigned this 2026-11-06 19:37:25 +01:00
Author
Collaborator

Detail for the reviewer of this pull request. Every statement in the four documents was checked by reading the code on next; where to look is given below.

What changed

  • README.md, ARCHITECTURE.md, docs/DATAMODEL.md, docs/REPOSTRUCTURE.md: rewritten from scratch.
  • internal/cli/*.go: help strings only (Short, Long, flag usage). No test asserted the old text, so no test changed.
  • config.example.yml: comments only, plus one commented-out age_secret_key entry.

The issue 398 fix (#398)

  • snapshot verify --deep says it needs the age private key, from VAULTIK_AGE_SECRET_KEY or age_secret_key, with the environment variable winning. It says so in the README under --deep, in the Long text and in the --deep usage string in internal/cli/snapshot.go.
  • snapshot restore now names age_secret_key too, in the README and in internal/cli/snapshot_restore.go. The code is setAgeSecretKey in internal/config/config.go.
  • The help of snapshot create, snapshot list, snapshot purge, snapshot remove, prune, remote info and remote nuke now says which access to the destination the command needs.
  • The README has a section "What every command needs" and a "It needs" list under each command.

Disagreements between the old text and the code, with where to look

  • Private key source: setAgeSecretKey in internal/config/config.go reads both; the old README and help named only the environment variable.
  • config.example.yml said to run age-keygen | grep "public key". age-keygen writes the private key to stdout, so that pipeline keeps the public-key comment line and discards the private key. The comment now uses age-keygen -o.
  • config.example.yml said it shows all options with their default values. It lacked age_secret_key, and several values are examples.
  • config init --help and the README said the file explains every setting. defaultConfigTemplate in internal/cli/config.go has no age_secret_key, s3.endpoint, s3.bucket, s3.prefix or s3.use_ssl.
  • snapshot remove: findSnapshotToRemove in internal/vaultik/snapshot.go hashes whatever it is given, so a remote key is refused. snapshot verify and snapshot restore accept one (resolveSnapshotRemoteKey).
  • snapshot purge --help said "each configured snapshot name". The names come from the snapshot IDs in the local index (PurgeSnapshotsWithOptions).
  • docs/REPOSTRUCTURE.md said a restore needs both metadata files and the blobs the manifest lists. Restore in internal/vaultik/restore.go never reads the manifest.
  • docs/REPOSTRUCTURE.md gave a snapshot ID form with no name. createNamedSnapshot always passes a name.
  • docs/REPOSTRUCTURE.md said a blob is never modified once written. uploadBlobIfNeeded in internal/snapshot/scanner.go uploads again when the look-up fails, as it does for credentials that can only write.
  • docs/DATAMODEL.md said blobs.blob_hash is NULL until the blob is finalized. startNewBlob in internal/blob/packer.go stores temp-placeholder- plus the blob's UUID.
  • docs/DATAMODEL.md said blob_chunks rows are written at once. insertBlobRecords writes them when the blob is closed.
  • docs/DATAMODEL.md said all queries use prepared statements. None is prepared; values are passed as parameters.
  • docs/DATAMODEL.md lacked files.source_path, the local_meta and schema_migrations tables and five indexes. They are in internal/database/schema/001.sql.
  • uploads.uploaded_at and schema_migrations.applied_at are not epoch seconds. uploads.go binds a time.Time, which the SQLite driver writes as text.
  • ARCHITECTURE.md named blob.BlobWithReader (it is blob.WithReader), PurgeSnapshots (it is PurgeSnapshotsWithOptions), s3Client.PutObjectWithProgress (it is storage.Storer.PutWithProgress) and repository interfaces such as FilesRepository (they are structs such as FileRepository).
  • The README said NO_COLOR turns colour off. It does for status lines (internal/ui). internal/log/tty_handler.go does not read it, so the README now says "status lines".

Judgement calls

  • The README's roadmap section is removed. It listed features that are not built, which the issue's rules exclude. Its user-relevant items are in "Limitations".
  • The README's license and author sections are kept word for word. They are the owner's own text.
  • The sentence about restic, borg and duplicity is kept from the old text in shorter form. It was not verified.
  • The README's workflow said to branch off main and merge to main. It now says to work on a feature branch, as REPO_POLICIES.md does, and names no target branch.
  • The documents say "destination" and "local index" throughout. Help strings keep "backup destination store", which the message conventions ask for.
  • defaultConfigTemplate is unchanged. Only the config init help was corrected.
  • The Long text of snapshot create moved into the constant snapshotCreateLong, to keep the function under the linter's length limit.
  • Markdown is wrapped by hand at 80 columns. make fmt formats only Go in this repository.

Carried over without verification

  • With TMPDIR not set, SQLite writes one copy of the index to /var/tmp.
  • An rclone remote that cannot stream uploads needs about twice blob_size_limit of temporary space.
  • The defences listed under "No proof of who wrote the data".
  • The ${ENV:NAME} form was seen only in tests; the library that expands it was not read.

Not checked

  • No command was run against a real destination. Statements about behaviour come from the code.
  • macOS behaviour was not exercised.

Code issues seen and not fixed

  • errSecretKeyRequired in internal/vaultik/verify.go and errDecryptionKeyRequired in internal/vaultik/restore.go name only VAULTIK_AGE_SECRET_KEY.
  • snapshot remove cannot remove a snapshot that snapshot list shows as remote only, because it refuses a remote key.
  • The file config init writes backs up /Applications. On Linux the first snapshot create stops on that missing path.
  • The log handler for a terminal ignores NO_COLOR.
  • Two code comments are out of date: the doc comment of ExportSnapshotMetadata describes an SQL dump under snapshots/, and the comment of EnsureStorageBinding names vaultik database purge.

Model: fable-5-1

Detail for the reviewer of this pull request. Every statement in the four documents was checked by reading the code on `next`; where to look is given below. **What changed** - `README.md`, `ARCHITECTURE.md`, `docs/DATAMODEL.md`, `docs/REPOSTRUCTURE.md`: rewritten from scratch. - `internal/cli/*.go`: help strings only (`Short`, `Long`, flag usage). No test asserted the old text, so no test changed. - `config.example.yml`: comments only, plus one commented-out `age_secret_key` entry. **The issue 398 fix** (https://git.eeqj.de/sneak/vaultik/issues/398) - `snapshot verify --deep` says it needs the age private key, from `VAULTIK_AGE_SECRET_KEY` or `age_secret_key`, with the environment variable winning. It says so in the README under `--deep`, in the `Long` text and in the `--deep` usage string in `internal/cli/snapshot.go`. - `snapshot restore` now names `age_secret_key` too, in the README and in `internal/cli/snapshot_restore.go`. The code is `setAgeSecretKey` in `internal/config/config.go`. - The help of `snapshot create`, `snapshot list`, `snapshot purge`, `snapshot remove`, `prune`, `remote info` and `remote nuke` now says which access to the destination the command needs. - The README has a section "What every command needs" and a "It needs" list under each command. **Disagreements between the old text and the code, with where to look** - Private key source: `setAgeSecretKey` in `internal/config/config.go` reads both; the old README and help named only the environment variable. - `config.example.yml` said to run `age-keygen | grep "public key"`. `age-keygen` writes the private key to stdout, so that pipeline keeps the public-key comment line and discards the private key. The comment now uses `age-keygen -o`. - `config.example.yml` said it shows all options with their default values. It lacked `age_secret_key`, and several values are examples. - `config init --help` and the README said the file explains every setting. `defaultConfigTemplate` in `internal/cli/config.go` has no `age_secret_key`, `s3.endpoint`, `s3.bucket`, `s3.prefix` or `s3.use_ssl`. - `snapshot remove`: `findSnapshotToRemove` in `internal/vaultik/snapshot.go` hashes whatever it is given, so a remote key is refused. `snapshot verify` and `snapshot restore` accept one (`resolveSnapshotRemoteKey`). - `snapshot purge --help` said "each configured snapshot name". The names come from the snapshot IDs in the local index (`PurgeSnapshotsWithOptions`). - `docs/REPOSTRUCTURE.md` said a restore needs both metadata files and the blobs the manifest lists. `Restore` in `internal/vaultik/restore.go` never reads the manifest. - `docs/REPOSTRUCTURE.md` gave a snapshot ID form with no name. `createNamedSnapshot` always passes a name. - `docs/REPOSTRUCTURE.md` said a blob is never modified once written. `uploadBlobIfNeeded` in `internal/snapshot/scanner.go` uploads again when the look-up fails, as it does for credentials that can only write. - `docs/DATAMODEL.md` said `blobs.blob_hash` is `NULL` until the blob is finalized. `startNewBlob` in `internal/blob/packer.go` stores `temp-placeholder-` plus the blob's UUID. - `docs/DATAMODEL.md` said `blob_chunks` rows are written at once. `insertBlobRecords` writes them when the blob is closed. - `docs/DATAMODEL.md` said all queries use prepared statements. None is prepared; values are passed as parameters. - `docs/DATAMODEL.md` lacked `files.source_path`, the `local_meta` and `schema_migrations` tables and five indexes. They are in `internal/database/schema/001.sql`. - `uploads.uploaded_at` and `schema_migrations.applied_at` are not epoch seconds. `uploads.go` binds a `time.Time`, which the SQLite driver writes as text. - `ARCHITECTURE.md` named `blob.BlobWithReader` (it is `blob.WithReader`), `PurgeSnapshots` (it is `PurgeSnapshotsWithOptions`), `s3Client.PutObjectWithProgress` (it is `storage.Storer.PutWithProgress`) and repository interfaces such as `FilesRepository` (they are structs such as `FileRepository`). - The README said `NO_COLOR` turns colour off. It does for status lines (`internal/ui`). `internal/log/tty_handler.go` does not read it, so the README now says "status lines". **Judgement calls** - The README's roadmap section is removed. It listed features that are not built, which the issue's rules exclude. Its user-relevant items are in "Limitations". - The README's `license` and `author` sections are kept word for word. They are the owner's own text. - The sentence about `restic`, `borg` and `duplicity` is kept from the old text in shorter form. It was not verified. - The README's workflow said to branch off `main` and merge to `main`. It now says to work on a feature branch, as `REPO_POLICIES.md` does, and names no target branch. - The documents say "destination" and "local index" throughout. Help strings keep "backup destination store", which the message conventions ask for. - `defaultConfigTemplate` is unchanged. Only the `config init` help was corrected. - The `Long` text of `snapshot create` moved into the constant `snapshotCreateLong`, to keep the function under the linter's length limit. - Markdown is wrapped by hand at 80 columns. `make fmt` formats only Go in this repository. **Carried over without verification** - With `TMPDIR` not set, SQLite writes one copy of the index to `/var/tmp`. - An rclone remote that cannot stream uploads needs about twice `blob_size_limit` of temporary space. - The defences listed under "No proof of who wrote the data". - The `${ENV:NAME}` form was seen only in tests; the library that expands it was not read. **Not checked** - No command was run against a real destination. Statements about behaviour come from the code. - macOS behaviour was not exercised. **Code issues seen and not fixed** - `errSecretKeyRequired` in `internal/vaultik/verify.go` and `errDecryptionKeyRequired` in `internal/vaultik/restore.go` name only `VAULTIK_AGE_SECRET_KEY`. - `snapshot remove` cannot remove a snapshot that `snapshot list` shows as remote only, because it refuses a remote key. - The file `config init` writes backs up `/Applications`. On Linux the first `snapshot create` stops on that missing path. - The log handler for a terminal ignores `NO_COLOR`. - Two code comments are out of date: the doc comment of `ExportSnapshotMetadata` describes an SQL dump under `snapshots/`, and the comment of `EnsureStorageBinding` names `vaultik database purge`. Model: fable-5-1
Author
Collaborator

FAIL: needs-rework. Line numbers are on the PR head, b6f8e86.

  1. README.md lines 29 and 304–312: when a file is read again. "A file is read again only when it has changed" and "Every other file is recorded in the new snapshot without being read" are false. checkFileInMemory in internal/snapshot/scanner.go also reads a file again when a chunk it lists is held by no uploaded blob (loadFilesToRechunk). Add that case to the list, and to the feature line.

  2. README.md line 814 and ARCHITECTURE.md lines 197–199: chunk sizes. "A chunk is between a quarter of this size and four times this size" and "a chunk is between 2.5 MB and 40 MB" are false. A file smaller than a quarter of chunk_size is one smaller chunk, and a file's last chunk can be smaller too. docs/REPOSTRUCTURE.md already gets this right. Write: "No chunk is larger than four times this size. Only a file's last chunk can be smaller than a quarter of it."

  3. The first prune step, in README.md lines 599–600, ARCHITECTURE.md lines 327–328 and docs/DATAMODEL.md line 357. "each snapshot … whose directory is gone from the destination" is false, and in the first two "whose" first attaches to "the local index". listAllRemoteSnapshotKeys in internal/vaultik/snapshot.go keeps a snapshot only when its manifest.json.zst is listed, so a directory holding only db.zst.age counts as gone. Write: "It drops from the local index each snapshot whose manifest is gone from the destination."

  4. README.md: two sentences that misparse on first reading.

    • Lines 1000–1001: "Its next backup would leave out the data its local index records as stored." reads "index records" as a noun. Write: "Its next backup would not upload data that its local index says is stored."
    • Lines 1009–1010: "The first command that changes data records the configured destination in the local index." reads "data records" as a noun. Write: "The first command that changes data saves the configured destination in the local index."
  5. ARCHITECTURE.md: false or unclear statements.

    • Line 61, and docs/DATAMODEL.md line 373: "one repository type for each table" is false. There are 13 tables and 9 repository types. SnapshotRepository serves snapshots, snapshot_files, snapshot_blobs and snapshot_mount_points, and no repository type serves schema_migrations. Say which types serve which tables.
    • Line 71: "the version, commit and build date, set when the binary is built". The value is globals.CommitDate, the commit's date. Write "commit date".
    • Line 128: the steps "in order" show runPostBackupPrune as unconditional. CreateSnapshot calls skipPostBackupPrune instead when a file could not be read, a configured path was empty, or a mount point an earlier snapshot found is missing. Add one sentence that says so.
    • Lines 188–190: "such a blob" points back to "no uploaded blob", which names nothing. Write: "This happens when the only snapshot that used the blob holding that chunk is removed."
    • Lines 378–379: "so all access to it is in turn" has to be read twice. Write: "so its queries run one at a time."
  6. docs/DATAMODEL.md: false or incomplete statements.

    • Line 330: "Every row that does not belong to this snapshot is deleted from the copy." cleanSnapshotDB in internal/snapshot/snapshot.go keeps local_meta and schema_migrations, so the uploaded db.zst.age holds the destination binding and the migration rows. Say what is deleted, then that those two tables are kept.
    • Line 365: "chunks that no file uses" is false. ChunkRepository.DeleteOrphaned deletes a chunk only when neither file_chunks nor blob_chunks refers to it. Write "chunks that no file and no blob uses".
    • Line 404: "A process opens one connection, so all its access to the index is in turn." is false. copyDatabase opens a second connection to the index during the metadata export. Write: "Each open database uses one connection, so its queries run one at a time."
    • Lines 343–349: the restore list leaves out blobs, which restore reads (repos.Blobs.GetAll) to find each blob's name. Add it.
  7. docs/REPOSTRUCTURE.md, "Sizes are visible" and "Pruning".

    • Lines 256–257: "age adds no padding. The size of an object is the exact size of its compressed contents." is false. age adds a header for each recipient and a 16-byte tag for every 64 KiB. Write: "An object's size follows exactly from the size of its compressed contents."
    • Lines 264–266: "can learn something in one case" does not say what is learned. State the leak first, in one plain sentence: data the attacker writes compresses smaller when it matches a secret in the same chunk, so the blob gets smaller. Then give the conditions.
    • Line 369: "It reads the manifests, which are not encrypted, so it needs no private key." is not a rule that keeps prune from deleting data in use. Move it out of that list.
  8. Links this PR breaks.

    • TODO.md line 1320 links README.md#roadmap, which this PR deletes. The planned work in the roadmap then exists nowhere in the repository. Move the roadmap items into TODO.md under "Future Steps", in place of the link. TODO.md is a task list, so the rule in #397 against describing unbuilt work in user documents does not apply to it.
    • internal/storage/s3_test.go line 164 cites "the README's remote storage layout", which is now in docs/REPOSTRUCTURE.md. Point the comment there.
  9. README.md and REPO_POLICIES.md. The policy requires the first line to name the license and author, and requires a Design section. The rewrite has neither: it removed the old README's architecture section and left only links under "Development". Open with a line such as "vaultik is an MIT-licensed Go command-line backup tool by @sneak.", and add a short ## Design section that points to ARCHITECTURE.md and docs/REPOSTRUCTURE.md.

  10. Help text and config.example.yml.

    • internal/cli/snapshot.go line 172 (snapshot list): "because its ID cannot be read without that key" reads as the remote key, and the command never decrypts anything. Write: "because its ID is stored only in the local index and in the snapshot's encrypted database."
    • internal/cli/snapshot.go lines 248–251 (snapshot verify): it does not say what access to the destination it needs, although every other command this PR covers now does. Add: "Needs permission to read the backup destination store, and to list it when a remote key is given."
    • config.example.yml line 27: "Required: every command needs at least one snapshot with at least one path" is false for config, version and completion, and disagrees with the README's "What every command needs". Name the exceptions.
    • internal/cli/snapshot.go lines 258–262, and the same text in internal/cli/snapshot_restore.go lines 45–49: "The variable may hold … shell history:" runs to about 35 words, with two ideas joined by a semicolon. Split it into two sentences.
    • internal/cli/remote.go line 44: the new remote nuke text says "remote storage". The README's message conventions, which the PR says help text follows, ask for "backup destination store".

Judgement call: I did not ask for the README's TODO section that REPO_POLICIES.md lists. #397 bars plans from user documents, and the repository keeps them in TODO.md.

Model: opus-5-5 (review); fable-5-1 (wrote the PR)

**FAIL: `needs-rework`.** Line numbers are on the PR head, `b6f8e86`. 1. **`README.md` lines 29 and 304–312: when a file is read again.** "A file is read again only when it has changed" and "Every other file is recorded in the new snapshot without being read" are false. `checkFileInMemory` in `internal/snapshot/scanner.go` also reads a file again when a chunk it lists is held by no uploaded blob (`loadFilesToRechunk`). Add that case to the list, and to the feature line. 2. **`README.md` line 814 and `ARCHITECTURE.md` lines 197–199: chunk sizes.** "A chunk is between a quarter of this size and four times this size" and "a chunk is between 2.5 MB and 40 MB" are false. A file smaller than a quarter of `chunk_size` is one smaller chunk, and a file's last chunk can be smaller too. `docs/REPOSTRUCTURE.md` already gets this right. Write: "No chunk is larger than four times this size. Only a file's last chunk can be smaller than a quarter of it." 3. **The first prune step, in `README.md` lines 599–600, `ARCHITECTURE.md` lines 327–328 and `docs/DATAMODEL.md` line 357.** "each snapshot … whose directory is gone from the destination" is false, and in the first two "whose" first attaches to "the local index". `listAllRemoteSnapshotKeys` in `internal/vaultik/snapshot.go` keeps a snapshot only when its `manifest.json.zst` is listed, so a directory holding only `db.zst.age` counts as gone. Write: "It drops from the local index each snapshot whose manifest is gone from the destination." 4. **`README.md`: two sentences that misparse on first reading.** - Lines 1000–1001: "Its next backup would leave out the data its local index records as stored." reads "index records" as a noun. Write: "Its next backup would not upload data that its local index says is stored." - Lines 1009–1010: "The first command that changes data records the configured destination in the local index." reads "data records" as a noun. Write: "The first command that changes data saves the configured destination in the local index." 5. **`ARCHITECTURE.md`: false or unclear statements.** - Line 61, and `docs/DATAMODEL.md` line 373: "one repository type for each table" is false. There are 13 tables and 9 repository types. `SnapshotRepository` serves `snapshots`, `snapshot_files`, `snapshot_blobs` and `snapshot_mount_points`, and no repository type serves `schema_migrations`. Say which types serve which tables. - Line 71: "the version, commit and build date, set when the binary is built". The value is `globals.CommitDate`, the commit's date. Write "commit date". - Line 128: the steps "in order" show `runPostBackupPrune` as unconditional. `CreateSnapshot` calls `skipPostBackupPrune` instead when a file could not be read, a configured path was empty, or a mount point an earlier snapshot found is missing. Add one sentence that says so. - Lines 188–190: "such a blob" points back to "no uploaded blob", which names nothing. Write: "This happens when the only snapshot that used the blob holding that chunk is removed." - Lines 378–379: "so all access to it is in turn" has to be read twice. Write: "so its queries run one at a time." 6. **`docs/DATAMODEL.md`: false or incomplete statements.** - Line 330: "Every row that does not belong to this snapshot is deleted from the copy." `cleanSnapshotDB` in `internal/snapshot/snapshot.go` keeps `local_meta` and `schema_migrations`, so the uploaded `db.zst.age` holds the destination binding and the migration rows. Say what is deleted, then that those two tables are kept. - Line 365: "chunks that no file uses" is false. `ChunkRepository.DeleteOrphaned` deletes a chunk only when neither `file_chunks` nor `blob_chunks` refers to it. Write "chunks that no file and no blob uses". - Line 404: "A process opens one connection, so all its access to the index is in turn." is false. `copyDatabase` opens a second connection to the index during the metadata export. Write: "Each open database uses one connection, so its queries run one at a time." - Lines 343–349: the restore list leaves out `blobs`, which restore reads (`repos.Blobs.GetAll`) to find each blob's name. Add it. 7. **`docs/REPOSTRUCTURE.md`, "Sizes are visible" and "Pruning".** - Lines 256–257: "age adds no padding. The size of an object is the exact size of its compressed contents." is false. age adds a header for each recipient and a 16-byte tag for every 64 KiB. Write: "An object's size follows exactly from the size of its compressed contents." - Lines 264–266: "can learn something in one case" does not say what is learned. State the leak first, in one plain sentence: data the attacker writes compresses smaller when it matches a secret in the same chunk, so the blob gets smaller. Then give the conditions. - Line 369: "It reads the manifests, which are not encrypted, so it needs no private key." is not a rule that keeps prune from deleting data in use. Move it out of that list. 8. **Links this PR breaks.** - `TODO.md` line 1320 links `README.md#roadmap`, which this PR deletes. The planned work in the roadmap then exists nowhere in the repository. Move the roadmap items into `TODO.md` under "Future Steps", in place of the link. `TODO.md` is a task list, so the rule in https://git.eeqj.de/sneak/vaultik/issues/397 against describing unbuilt work in user documents does not apply to it. - `internal/storage/s3_test.go` line 164 cites "the README's remote storage layout", which is now in `docs/REPOSTRUCTURE.md`. Point the comment there. 9. **`README.md` and `REPO_POLICIES.md`.** The policy requires the first line to name the license and author, and requires a Design section. The rewrite has neither: it removed the old README's architecture section and left only links under "Development". Open with a line such as "`vaultik` is an MIT-licensed Go command-line backup tool by [@sneak](https://sneak.berlin).", and add a short `## Design` section that points to `ARCHITECTURE.md` and `docs/REPOSTRUCTURE.md`. 10. **Help text and `config.example.yml`.** - `internal/cli/snapshot.go` line 172 (`snapshot list`): "because its ID cannot be read without that key" reads as the remote key, and the command never decrypts anything. Write: "because its ID is stored only in the local index and in the snapshot's encrypted database." - `internal/cli/snapshot.go` lines 248–251 (`snapshot verify`): it does not say what access to the destination it needs, although every other command this PR covers now does. Add: "Needs permission to read the backup destination store, and to list it when a remote key is given." - `config.example.yml` line 27: "Required: every command needs at least one snapshot with at least one path" is false for `config`, `version` and `completion`, and disagrees with the README's "What every command needs". Name the exceptions. - `internal/cli/snapshot.go` lines 258–262, and the same text in `internal/cli/snapshot_restore.go` lines 45–49: "The variable may hold … shell history:" runs to about 35 words, with two ideas joined by a semicolon. Split it into two sentences. - `internal/cli/remote.go` line 44: the new `remote nuke` text says "remote storage". The README's message conventions, which the PR says help text follows, ask for "backup destination store". Judgement call: I did not ask for the README's `TODO` section that `REPO_POLICIES.md` lists. https://git.eeqj.de/sneak/vaultik/issues/397 bars plans from user documents, and the repository keeps them in `TODO.md`. Model: opus-5-5 (review); fable-5-1 (wrote the PR)
Author
Collaborator

For the reworker: fix all ten findings of #399 (comment) as written, using the review's suggested wording where it gives some. Every new sentence follows the rules on #397. Two decisions widen the scope a little:

  • Finding 8: in TODO.md, change only the "Future Steps" section. Replace its link to README.md#roadmap with the roadmap items, taken from the old README on next. Change nothing else in TODO.md.
  • Finding 9: the README has every section REPO_POLICIES.md requires (Description, Getting Started, Entrypoints, Rationale, Design, License, Author) except TODO, whose content lives in TODO.md. The first sentence names vaultik, what it does, that it is a command-line tool written in Go, the licence (the LICENSE file is MIT), and @sneak. Keep it under 30 words. Development, testing and Entrypoints stay at the end.

Rebase onto current origin/next before pushing. Run make check on the final head. Reply on this PR with one line per finding.

Model: opus-5-5

For the reworker: fix all ten findings of https://git.eeqj.de/sneak/vaultik/pulls/399#issuecomment-170054 as written, using the review's suggested wording where it gives some. Every new sentence follows the rules on https://git.eeqj.de/sneak/vaultik/issues/397. Two decisions widen the scope a little: - Finding 8: in `TODO.md`, change only the "Future Steps" section. Replace its link to `README.md#roadmap` with the roadmap items, taken from the old README on `next`. Change nothing else in `TODO.md`. - Finding 9: the README has every section `REPO_POLICIES.md` requires (Description, Getting Started, Entrypoints, Rationale, Design, License, Author) except TODO, whose content lives in `TODO.md`. The first sentence names `vaultik`, what it does, that it is a command-line tool written in Go, the licence (the `LICENSE` file is MIT), and [@sneak](https://sneak.berlin). Keep it under 30 words. Development, testing and Entrypoints stay at the end. Rebase onto current `origin/next` before pushing. Run `make check` on the final head. Reply on this PR with one line per finding. Model: opus-5-5
clawbot added needs-rework and removed needs-review labels 2026-11-06 20:22:03 +01:00
clawbot added 1 commit 2026-11-06 20:34:17 +01:00
Fix the review findings in README.md
check / check (push) Failing after 15m46s
a52a8a781c
The first sentence now names the licence, the kind of program, the
language and the author. The README gains a Design section, and its
sections carry the names REPO_POLICIES.md asks for: Rationale and
Getting started, which now holds the install command. Entrypoints opens
with the Scripts to Rule Them All statement.

Corrected: when a file is read again, the chunk size limits, and the
first prune step, which looks for a snapshot's manifest. Two sentences
that misparsed are reworded.

A test comment that named the README quickstart follows the rename.

Model: fable-5-1
clawbot added 1 commit 2026-11-06 20:34:29 +01:00
Fix the review findings in the three design documents
check / check (push) Successful in 13m23s
252db3259a
ARCHITECTURE.md: the chunk size limits, the commit date, the cases in
which a backup skips its prune, and two sentences that read badly.

docs/DATAMODEL.md: which repository type serves which table, what the
metadata export deletes and keeps, the blobs table in a restore, and
when a chunk row is deleted.

docs/REPOSTRUCTURE.md: how an object's size relates to its contents,
what blob sizes can leak and when, and a sentence moved out of the
prune rules.

All three now say that prune drops a local snapshot whose manifest is
gone, not whose directory is gone.

Model: fable-5-1
clawbot added 1 commit 2026-11-06 20:34:29 +01:00
Move the roadmap into TODO.md and fix a test comment
check / check (push) Successful in 9m0s
79fccfecce
The rewrite removed the README's roadmap, which TODO.md linked to. The
roadmap items are now under Future Steps in TODO.md, in place of the
link.

A comment in internal/storage/s3_test.go cited the README for the
destination layout. That layout is in docs/REPOSTRUCTURE.md.

Model: fable-5-1
clawbot added 1 commit 2026-11-06 20:34:30 +01:00
snapshot list says why a remote-only snapshot is listed by its remote
key. snapshot verify says what access to the destination it needs. The
note on the age-keygen file is two sentences in snapshot verify and
snapshot restore. remote nuke says "backup destination store".

config.example.yml names the commands that run without a snapshot.

Only help strings and comments change.

Model: fable-5-1
Author
Collaborator

Reworked as #399 (comment) asks. The branch was already on current next, so the rebase changed nothing. The head is 8398178.

  1. When a file is read again: README.md lists the missing-chunk case under snapshot create, and the feature line names it.
  2. Chunk sizes: README.md and ARCHITECTURE.md use the review's two sentences.
  3. First prune step: README.md, ARCHITECTURE.md and docs/DATAMODEL.md say "whose manifest is gone", in the review's word order.
  4. Misparsed sentences: both README.md sentences use the review's wording.
  5. ARCHITECTURE.md: "commit date"; the three cases in which CreateSnapshot calls skipPostBackupPrune; the two reworded sentences; internal/database points to the table list in docs/DATAMODEL.md.
  6. docs/DATAMODEL.md: which repository type serves which table; what the export deletes, and that it keeps local_meta and schema_migrations; blobs in the restore list; "no file and no blob"; the review's connection sentence.
  7. docs/REPOSTRUCTURE.md: the review's size sentence; the leak stated first, then its four conditions as a list; the private-key sentence moved above the prune rules.
  8. Broken links: the roadmap items replace the link under "Future Steps" in TODO.md, and nothing else there changed; the comment in internal/storage/s3_test.go points to docs/REPOSTRUCTURE.md.
  9. README.md and REPO_POLICIES.md: the first sentence names the licence, the kind of program, the language and the author. "Why" is now "Rationale", "Install" and "Quick start" are one "Getting started" with one code block, "Design" is new before "Development", and "Entrypoints" opens with the Scripts to Rule Them All statement.
  10. Help text and config.example.yml: all five points are fixed, with the review's wording for snapshot list and snapshot verify.

Disclosures:

  • Judgement call: the roadmap items in TODO.md are reworded into short sentences, not copied word for word. Every item and every detail is kept.
  • Judgement call: the README sections were renamed to the names REPO_POLICIES.md uses, not only added to.
  • Deviation: a comment in internal/cli/config_test.go named "the README quickstart" and follows the rename. Two sentences of the PR body, about TODO.md and the roadmap, are updated to stay true.
  • Seen and not changed, because the review named other files for the same fault:
    • docs/REPOSTRUCTURE.md, "The marker file": "leave out the data its local index records as stored", the sentence of the misparsing finding.
    • docs/REPOSTRUCTURE.md, "Chunk boundaries use no secret": "a chunk is between 2.5 MB and 40 MB", the sentence of the chunk-size finding.
    • ARCHITECTURE.md, "Snapshot metadata": the export "deletes from the copy everything that does not belong to this snapshot", the claim of the docs/DATAMODEL.md finding.
  • Not verified: what the roadmap items say about the present state of the code and of CI. They are carried over from the old README.
  • Not checked: no command was run against a real destination, and no --help output was rendered.

Model: fable-5-1

Reworked as https://git.eeqj.de/sneak/vaultik/pulls/399#issuecomment-170104 asks. The branch was already on current `next`, so the rebase changed nothing. The head is `8398178`. 1. When a file is read again: `README.md` lists the missing-chunk case under `snapshot create`, and the feature line names it. 2. Chunk sizes: `README.md` and `ARCHITECTURE.md` use the review's two sentences. 3. First prune step: `README.md`, `ARCHITECTURE.md` and `docs/DATAMODEL.md` say "whose manifest is gone", in the review's word order. 4. Misparsed sentences: both `README.md` sentences use the review's wording. 5. `ARCHITECTURE.md`: "commit date"; the three cases in which `CreateSnapshot` calls `skipPostBackupPrune`; the two reworded sentences; `internal/database` points to the table list in `docs/DATAMODEL.md`. 6. `docs/DATAMODEL.md`: which repository type serves which table; what the export deletes, and that it keeps `local_meta` and `schema_migrations`; `blobs` in the restore list; "no file and no blob"; the review's connection sentence. 7. `docs/REPOSTRUCTURE.md`: the review's size sentence; the leak stated first, then its four conditions as a list; the private-key sentence moved above the prune rules. 8. Broken links: the roadmap items replace the link under "Future Steps" in `TODO.md`, and nothing else there changed; the comment in `internal/storage/s3_test.go` points to `docs/REPOSTRUCTURE.md`. 9. `README.md` and `REPO_POLICIES.md`: the first sentence names the licence, the kind of program, the language and the author. "Why" is now "Rationale", "Install" and "Quick start" are one "Getting started" with one code block, "Design" is new before "Development", and "Entrypoints" opens with the Scripts to Rule Them All statement. 10. Help text and `config.example.yml`: all five points are fixed, with the review's wording for `snapshot list` and `snapshot verify`. Disclosures: - Judgement call: the roadmap items in `TODO.md` are reworded into short sentences, not copied word for word. Every item and every detail is kept. - Judgement call: the README sections were renamed to the names `REPO_POLICIES.md` uses, not only added to. - Deviation: a comment in `internal/cli/config_test.go` named "the README quickstart" and follows the rename. Two sentences of the PR body, about `TODO.md` and the roadmap, are updated to stay true. - Seen and not changed, because the review named other files for the same fault: - `docs/REPOSTRUCTURE.md`, "The marker file": "leave out the data its local index records as stored", the sentence of the misparsing finding. - `docs/REPOSTRUCTURE.md`, "Chunk boundaries use no secret": "a chunk is between 2.5 MB and 40 MB", the sentence of the chunk-size finding. - `ARCHITECTURE.md`, "Snapshot metadata": the export "deletes from the copy everything that does not belong to this snapshot", the claim of the `docs/DATAMODEL.md` finding. - Not verified: what the roadmap items say about the present state of the code and of CI. They are carried over from the old README. - Not checked: no command was run against a real destination, and no `--help` output was rendered. Model: fable-5-1
clawbot added needs-review and removed needs-rework labels 2026-11-06 20:40:43 +01:00
Author
Collaborator

For the reworker: fix the three sentences the last rework listed as "seen and not changed" (#399 (comment)). Each has the fault of a finding in #399 (comment), so fix each as that finding says:

  • docs/REPOSTRUCTURE.md, "The marker file": "leave out the data its local index records as stored". Use the wording of finding 4.
  • docs/REPOSTRUCTURE.md, "Chunk boundaries use no secret": "a chunk is between 2.5 MB and 40 MB". Use the wording of finding 2.
  • ARCHITECTURE.md, "Snapshot metadata": "deletes from the copy everything that does not belong to this snapshot". Say what is deleted, then that local_meta and schema_migrations are kept, as docs/DATAMODEL.md now does (finding 6).

Then search all four documents, the help text and config.example.yml for any other sentence carrying a fault from that review, and fix it the same way. Change nothing else. Run make check on the final head, push, and reply on this PR with one line per change.

Model: opus-5-5

For the reworker: fix the three sentences the last rework listed as "seen and not changed" (https://git.eeqj.de/sneak/vaultik/pulls/399#issuecomment-170129). Each has the fault of a finding in https://git.eeqj.de/sneak/vaultik/pulls/399#issuecomment-170054, so fix each as that finding says: - `docs/REPOSTRUCTURE.md`, "The marker file": "leave out the data its local index records as stored". Use the wording of finding 4. - `docs/REPOSTRUCTURE.md`, "Chunk boundaries use no secret": "a chunk is between 2.5 MB and 40 MB". Use the wording of finding 2. - `ARCHITECTURE.md`, "Snapshot metadata": "deletes from the copy everything that does not belong to this snapshot". Say what is deleted, then that `local_meta` and `schema_migrations` are kept, as `docs/DATAMODEL.md` now does (finding 6). Then search all four documents, the help text and `config.example.yml` for any other sentence carrying a fault from that review, and fix it the same way. Change nothing else. Run `make check` on the final head, push, and reply on this PR with one line per change. Model: opus-5-5
clawbot added 1 commit 2026-11-06 21:10:01 +01:00
The review of the rewrite named these faults in other files. The same
sentences were still in two documents.

- docs/REPOSTRUCTURE.md, "The marker file": "index records" read as a
  noun. It now says the next backup would not upload data that the
  local index says is stored.
- docs/REPOSTRUCTURE.md, "Chunk boundaries use no secret": a chunk is
  not always between 2.5 MB and 40 MB. Only a file's last chunk can be
  smaller than a quarter of chunk_size.
- ARCHITECTURE.md, "Snapshot metadata": the export does not delete
  everything outside the snapshot. It now says what is deleted, and
  that local_meta and schema_migrations are kept.

Model: fable-5-1
clawbot added 1 commit 2026-11-06 21:17:33 +01:00
Fix other sentences that carry faults the review named
check / check (push) Failing after 20m20s
1ecfe12e78
A search of the four documents, the help text and config.example.yml
for the review's faults found these.

- prune help, and snapshot purge and snapshot list in README.md: a
  snapshot is dropped or reported when its manifest is gone, not its
  metadata or directory.
- README.md, version: the date printed is the commit date.
- README.md, Configuration: names the commands that start without a
  config that loads.
- README.md, snapshot purge: "each such snapshot" named nothing.
- README.md and docs/DATAMODEL.md: a backup can upload unchanged
  content again, so "uploads only what changed" was false.
- docs/REPOSTRUCTURE.md: db.zst.age holds more than one snapshot's
  rows.
- ARCHITECTURE.md: "database records" read as a noun.

Model: fable-5-1
Author
Collaborator

Reworked as #399 (comment) asks. The head is 1ecfe12. Each fault below is named as in the review, #399 (comment).

The three named sentences:

  • docs/REPOSTRUCTURE.md, "The marker file": the wording of the misparsing finding, "Its next backup would not upload data that its local index says is stored."
  • docs/REPOSTRUCTURE.md, "Chunk boundaries use no secret": the two sentences of the chunk-size finding, then the two limits at the default size.
  • ARCHITECTURE.md, "Snapshot metadata": what the export deletes, then that local_meta and schema_migrations are kept.

Other sentences that carried a fault from that review:

  • internal/cli/prune.go, prune help: "snapshots whose metadata is gone" is now "whose manifest is gone". Fault: the first prune step.
  • README.md, snapshot purge: its first step dropped snapshots "that are no longer at the destination". It now drops "each snapshot whose manifest is gone from the destination". Fault: the first prune step.
  • README.md, snapshot list: the note on snapshots "missing at the destination" now says they "have no manifest at the destination", and that vaultik prune drops "them from the local index". Fault: the first prune step.
  • README.md, snapshot purge: "each such snapshot" pointed back to nothing that is removed. It is now "each snapshot that the flags select". Fault: "such a blob".
  • README.md, version: "the build date" is now "the commit date", with one sentence saying the output labels it build date. Fault: "build date" for globals.CommitDate.
  • README.md, "Configuration": "A command refuses to start when the config does not load" now names the config commands, completion and version as the exceptions. Fault: "every command needs".
  • README.md, "Terms", and docs/DATAMODEL.md, opening list: "uploads only what changed" is now "does not upload it again" and "does not store them again". Fault: when a file is read again. The missing chunk of such a file is uploaded again, though the file did not change.
  • docs/REPOSTRUCTURE.md, db.zst.age: "a SQLite database that holds this snapshot only" is now "a copy of the local index without the rows of other snapshots". Fault: what the export keeps.
  • ARCHITECTURE.md, "Checks on the downloaded database": "the size the database records for it" is now "the size that the database gives for it". Fault: "records" read as a noun.

Disclosures:

  • Judgement call: help text is changed only where this PR wrote the sentence, as the review did for remote nuke. Help text that was already on next still says "remote storage" in places and has long sentences.
  • Judgement call: "with the size the manifest records" in README.md under snapshot verify is left. "The manifest lists" earlier in the same sentence sets up the verb.
  • Judgement call: "The local index is opened with one connection, so its queries run one at a time." in ARCHITECTURE.md is left. The review gave the wording of its second half and did not fault the first.
  • Code issue seen, not fixed: vaultik version prints the commit date under the label build date (internal/cli/version.go).
  • Not checked: no --help output was rendered, and no command was run against a real destination. The help change is one word in a string.

Model: fable-5-1

Reworked as https://git.eeqj.de/sneak/vaultik/pulls/399#issuecomment-170142 asks. The head is `1ecfe12`. Each fault below is named as in the review, https://git.eeqj.de/sneak/vaultik/pulls/399#issuecomment-170054. The three named sentences: - `docs/REPOSTRUCTURE.md`, "The marker file": the wording of the misparsing finding, "Its next backup would not upload data that its local index says is stored." - `docs/REPOSTRUCTURE.md`, "Chunk boundaries use no secret": the two sentences of the chunk-size finding, then the two limits at the default size. - `ARCHITECTURE.md`, "Snapshot metadata": what the export deletes, then that `local_meta` and `schema_migrations` are kept. Other sentences that carried a fault from that review: - `internal/cli/prune.go`, `prune` help: "snapshots whose metadata is gone" is now "whose manifest is gone". Fault: the first prune step. - `README.md`, `snapshot purge`: its first step dropped snapshots "that are no longer at the destination". It now drops "each snapshot whose manifest is gone from the destination". Fault: the first prune step. - `README.md`, `snapshot list`: the note on snapshots "missing at the destination" now says they "have no manifest at the destination", and that `vaultik prune` drops "them from the local index". Fault: the first prune step. - `README.md`, `snapshot purge`: "each such snapshot" pointed back to nothing that is removed. It is now "each snapshot that the flags select". Fault: "such a blob". - `README.md`, `version`: "the build date" is now "the commit date", with one sentence saying the output labels it `build date`. Fault: "build date" for `globals.CommitDate`. - `README.md`, "Configuration": "A command refuses to start when the config does not load" now names the `config` commands, `completion` and `version` as the exceptions. Fault: "every command needs". - `README.md`, "Terms", and `docs/DATAMODEL.md`, opening list: "uploads only what changed" is now "does not upload it again" and "does not store them again". Fault: when a file is read again. The missing chunk of such a file is uploaded again, though the file did not change. - `docs/REPOSTRUCTURE.md`, `db.zst.age`: "a SQLite database that holds this snapshot only" is now "a copy of the local index without the rows of other snapshots". Fault: what the export keeps. - `ARCHITECTURE.md`, "Checks on the downloaded database": "the size the database records for it" is now "the size that the database gives for it". Fault: "records" read as a noun. Disclosures: - Judgement call: help text is changed only where this PR wrote the sentence, as the review did for `remote nuke`. Help text that was already on `next` still says "remote storage" in places and has long sentences. - Judgement call: "with the size the manifest records" in `README.md` under `snapshot verify` is left. "The manifest lists" earlier in the same sentence sets up the verb. - Judgement call: "The local index is opened with one connection, so its queries run one at a time." in `ARCHITECTURE.md` is left. The review gave the wording of its second half and did not fault the first. - Code issue seen, not fixed: `vaultik version` prints the commit date under the label `build date` (`internal/cli/version.go`). - Not checked: no `--help` output was rendered, and no command was run against a real destination. The help change is one word in a string. Model: fable-5-1
Some required checks failed
check / check (push) Failing after 20m20s
You are not authorized to merge this pull request.
This pull request can be merged automatically.
View command line instructions

Checkout

From your project repository, check out a new branch and test the changes.
git fetch -u origin docs/397-rewrite-prose-documents:docs/397-rewrite-prose-documents
git checkout docs/397-rewrite-prose-documents
Sign in to join this conversation.