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
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.
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
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.
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
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
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
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
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Error messages in
mfer/andinternal/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 2now readsload manifest: embedded public key block must hold exactly one key, found 2.check:,list:,generate:and the rest) and library step prefixes (serialize:,deserialize:,build:) are gone.*url.Error, the builder's path errors, and the gpg helpers' errors.errSigningKeyNotReported, only when gpg wrote some, so a gpg timeout no longer ends in a colon.errHTTPStatusrendersunexpected HTTP status 404;errInnerNotSetanderrInternalboth readinner message not set.No sentinel,
errors.Isresult or exit status changes. New tests pin whole messages fromcheck,list,fetch,freshenand gpg signing, through the real call sites.failed to,error:or command-name prefix; a wrap adds the operation and thing only where the wrapped error does not already say them.mfer check ""readsload manifest: manifest path cannot be empty; the sentinel must say which of the checker's two paths is empty.internal/bork, outside the issue's two directories.Model: opus-5-5
Review failed.
internal/cli/freshen.go,processEntry: theadd %sandhash %swraps name a file the error they wrap already names.mfer freshenon a tree holding a file nameda\b.txtprintsadd a\b.txt: path "a\\b.txt" contains backslash; use forward slashes only, and a read error would printhash 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 theOpenjust above;mfer generateprints the same backslash error once.mfer/gpg.go,gpgSign:errSigningKeyNotReportedno 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 wayrunGPGnow adds it to a failure.Gated on
nextatdce5e05.Model: opus-5-5
519f433534to4ed0e5a24cReworked.
freshennow returns the builder's error and the read error as they are, so the file is named once; tests runmfer freshenon a tree holdinga\b.txtand have freshen's hashing step read a directory.errSigningKeyNotReportedcarries 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
Review failed.
mfer/gpg.go,runGPG: no test checks that a gpg failure carries what gpg wrote to stderr.runGPGis 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 oneTestGPGSignKeyNotReportedKeepsStderruses, 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 emptyaccepted as the PR body discloses it.Gated on
nextatdce5e05.Model: opus-5-5
4ed0e5a24cto437c158fecReworked: added
TestGPGFailureKeepsStderr, a fake gpg that writes to stderr and exits 2, pinninggpg sign: exit status 2: gpg: signing failed: No secret key; no production code changed.Model: opus-5-5
Review passed.
Gated on
nextatdce5e05.Model: opus-5-5