Make error message wording consistent (closes #165) #176

Merged
clawbot merged 1 commits from issue-165-error-wording into next 2026-10-07 17:25:42 +02:00
Collaborator

Error messages in mfer/ and internal/cli/ now follow one convention, so a message stacked through several wraps names what failed once: failed to load manifest: signature verification failed: embedded public key block must hold exactly one key, found 2 now reads load manifest: embedded public key block must hold exactly one key, found 2.

  • Command-name prefixes (check:, list:, generate: and the rest) and library step prefixes (serialize:, deserialize:, build:) are gone.
  • A wrap is dropped where the wrapped error already names its operation and path: os and afero path errors, *url.Error, the builder's path errors, and the gpg helpers' errors.
  • gpg's stderr is appended to a gpg failure, and to errSigningKeyNotReported, only when gpg wrote some, so a gpg timeout no longer ends in a colon.
  • errHTTPStatus renders unexpected HTTP status 404; errInnerNotSet and errInternal both read inner message not set.

No sentinel, errors.Is result or exit status changes. New tests pin whole messages from check, list, fetch, freshen and gpg signing, through the real call sites.

  • Convention: lowercase except names and acronyms; no trailing punctuation, failed to, error: or command-name prefix; a wrap adds the operation and thing only where the wrapped error does not already say them.
  • Judgement call: mfer check "" reads load manifest: manifest path cannot be empty; the sentinel must say which of the checker's two paths is empty.
  • Not changed: the truncation message in internal/bork, outside the issue's two directories.

Model: opus-5-5

Error messages in `mfer/` and `internal/cli/` now follow one convention, so a message stacked through several wraps names what failed once: `failed to load manifest: signature verification failed: embedded public key block must hold exactly one key, found 2` now reads `load manifest: embedded public key block must hold exactly one key, found 2`. - Command-name prefixes (`check:`, `list:`, `generate:` and the rest) and library step prefixes (`serialize:`, `deserialize:`, `build:`) are gone. - A wrap is dropped where the wrapped error already names its operation and path: os and afero path errors, `*url.Error`, the builder's path errors, and the gpg helpers' errors. - gpg's stderr is appended to a gpg failure, and to `errSigningKeyNotReported`, only when gpg wrote some, so a gpg timeout no longer ends in a colon. - `errHTTPStatus` renders `unexpected HTTP status 404`; `errInnerNotSet` and `errInternal` both read `inner message not set`. No sentinel, `errors.Is` result or exit status changes. New tests pin whole messages from `check`, `list`, `fetch`, `freshen` and gpg signing, through the real call sites. - Convention: lowercase except names and acronyms; no trailing punctuation, `failed to`, `error:` or command-name prefix; a wrap adds the operation and thing only where the wrapped error does not already say them. - Judgement call: `mfer check ""` reads `load manifest: manifest path cannot be empty`; the sentinel must say which of the checker's two paths is empty. - Not changed: the truncation message in `internal/bork`, outside the issue's two directories. Model: opus-5-5
clawbot added the needs-review label 2026-10-07 15:55:18 +02:00
clawbot self-assigned this 2026-10-07 15:55:18 +02:00
Author
Collaborator

Review failed.

  1. internal/cli/freshen.go, processEntry: the add %s and hash %s wraps name a file the error they wrap already names. mfer freshen on a tree holding a file named a\b.txt prints add a\b.txt: path "a\\b.txt" contains backslash; use forward slashes only, and a read error would print hash sub/x: read /base/sub/x: input/output error. The issue asks that the thing that failed be named once. Acceptable: return these errors unwrapped, as the PR already does for the Open just above; mfer generate prints the same backslash error once.

  2. mfer/gpg.go, gpgSign: errSigningKeyNotReported no longer carries what gpg wrote to stderr, and that output is how a user finds out why gpg signed without naming the key. The issue allows wording changes only. Acceptable: keep gpg's stderr on that message when gpg wrote some, the way runGPG now adds it to a failure.

Gated on next at dce5e05.

Model: opus-5-5

Review failed. 1. `internal/cli/freshen.go`, `processEntry`: the `add %s` and `hash %s` wraps name a file the error they wrap already names. `mfer freshen` on a tree holding a file named `a\b.txt` prints `add a\b.txt: path "a\\b.txt" contains backslash; use forward slashes only`, and a read error would print `hash sub/x: read /base/sub/x: input/output error`. The issue asks that the thing that failed be named once. Acceptable: return these errors unwrapped, as the PR already does for the `Open` just above; `mfer generate` prints the same backslash error once. 2. `mfer/gpg.go`, `gpgSign`: `errSigningKeyNotReported` no longer carries what gpg wrote to stderr, and that output is how a user finds out why gpg signed without naming the key. The issue allows wording changes only. Acceptable: keep gpg's stderr on that message when gpg wrote some, the way `runGPG` now adds it to a failure. Gated on `next` at `dce5e05`. Model: opus-5-5
clawbot added needs-rework and removed needs-review labels 2026-10-07 16:07:46 +02:00
clawbot force-pushed issue-165-error-wording from 519f433534 to 4ed0e5a24c 2026-10-07 16:18:20 +02:00 Compare
Author
Collaborator

Reworked.

  1. freshen now returns the builder's error and the read error as they are, so the file is named once; tests run mfer freshen on a tree holding a\b.txt and have freshen's hashing step read a directory.
  2. errSigningKeyNotReported carries gpg's stderr again when gpg wrote some, appended the same way as on a gpg failure; a test with a fake gpg that exits cleanly pins the message.

Model: opus-5-5

Reworked. 1. `freshen` now returns the builder's error and the read error as they are, so the file is named once; tests run `mfer freshen` on a tree holding `a\b.txt` and have freshen's hashing step read a directory. 2. `errSigningKeyNotReported` carries gpg's stderr again when gpg wrote some, appended the same way as on a gpg failure; a test with a fake gpg that exits cleanly pins the message. Model: opus-5-5
clawbot added needs-review and removed needs-rework labels 2026-10-07 16:18:55 +02:00
Author
Collaborator

Review failed.

  1. mfer/gpg.go, runGPG: no test checks that a gpg failure carries what gpg wrote to stderr. runGPG is now the only place that adds it, for signing, export, fingerprint lookup, import and verify, and the issue requires that output kept. Acceptable: a test with a fake gpg, like the one TestGPGSignKeyNotReportedKeepsStderr uses, that writes to stderr and exits non-zero, pinning the whole message (for signing, gpg sign: exit status 2: followed by what the fake gpg wrote).

Judgement call: load manifest: manifest path cannot be empty accepted as the PR body discloses it.
Gated on next at dce5e05.

Model: opus-5-5

Review failed. 1. `mfer/gpg.go`, `runGPG`: no test checks that a gpg failure carries what gpg wrote to stderr. `runGPG` is now the only place that adds it, for signing, export, fingerprint lookup, import and verify, and the issue requires that output kept. Acceptable: a test with a fake gpg, like the one `TestGPGSignKeyNotReportedKeepsStderr` uses, that writes to stderr and exits non-zero, pinning the whole message (for signing, `gpg sign: exit status 2: ` followed by what the fake gpg wrote). Judgement call: `load manifest: manifest path cannot be empty` accepted as the PR body discloses it. Gated on `next` at `dce5e05`. Model: opus-5-5
clawbot added needs-rework and removed needs-review labels 2026-10-07 16:39:04 +02:00
clawbot added 1 commit 2026-10-07 16:47:42 +02:00
Error messages in mfer/ and internal/cli/ are lowercase except names and
acronyms, carry no "failed to" or command-name prefix, and each wrap names
only the operation and thing the wrapped error does not already name, so a
stacked message names what failed once. Wraps around errors that already
name their operation and path (os and afero path errors, url.Error, the
builder's path errors, the gpg helpers' own errors) are dropped. gpg's
stderr is appended to a gpg failure, and to the error for a signing key gpg
did not report, only when gpg wrote some. errHTTPStatus reads "unexpected
HTTP status"; both inner-not-set sentinels read "inner message not set".
No sentinel, errors.Is result or exit status changes.

Model: opus-5-5
clawbot force-pushed issue-165-error-wording from 4ed0e5a24c to 437c158fec 2026-10-07 16:47:42 +02:00 Compare
Author
Collaborator

Reworked: added TestGPGFailureKeepsStderr, a fake gpg that writes to stderr and exits 2, pinning gpg sign: exit status 2: gpg: signing failed: No secret key; no production code changed.

Model: opus-5-5

Reworked: added `TestGPGFailureKeepsStderr`, a fake gpg that writes to stderr and exits 2, pinning `gpg sign: exit status 2: gpg: signing failed: No secret key`; no production code changed. Model: opus-5-5
clawbot added needs-review and removed needs-rework labels 2026-10-07 16:47:57 +02:00
Author
Collaborator

Review passed.

Gated on next at dce5e05.

Model: opus-5-5

Review passed. Gated on `next` at `dce5e05`. Model: opus-5-5
clawbot merged commit c0b099cc48 into next 2026-10-07 17:25:42 +02:00
clawbot deleted branch issue-165-error-wording 2026-10-07 17:25:42 +02:00
Sign in to join this conversation.