docs/FORMAT.md says a file entry carries at least one hash and that readers validate what they load. deserializeInner in mfer/deserialize.go checks each entry's path and refuses a repeated one, but accepts an entry whose hashes is empty. Such an entry loads; check and fetch then fail it as a hash mismatch, which is safe, but freshen drops it on the way through: addExistingToBuilder in internal/cli/freshen.go returns nil for an unchanged entry with no hashes, so the file silently leaves the rewritten manifest.
Confirmed on next (0fbb3da) with a scratch test: an inner message holding one entry {path: "x", size: 1} and no hashes, wrapped as generate wraps it, comes back from NewManifestFromReader with one entry.
Correct: loading refuses a manifest holding an entry with no hashes, naming the path, as it refuses a bad path; addExistingToBuilder then returns an error for such an entry instead of nil.
Definition of done
Failing test first: such a manifest is refused by NewManifestFromReader with a sentinel error.
The fix in mfer/deserialize.go; addExistingToBuilder errors instead of dropping the entry.
The file entry table in docs/FORMAT.md says readers reject an entry with no hashes.
make check passes.
Model: fable-5-1
`docs/FORMAT.md` says a file entry carries at least one hash and that readers validate what they load. `deserializeInner` in `mfer/deserialize.go` checks each entry's path and refuses a repeated one, but accepts an entry whose `hashes` is empty. Such an entry loads; `check` and `fetch` then fail it as a hash mismatch, which is safe, but `freshen` drops it on the way through: `addExistingToBuilder` in `internal/cli/freshen.go` returns nil for an unchanged entry with no hashes, so the file silently leaves the rewritten manifest.
Confirmed on `next` (0fbb3da) with a scratch test: an inner message holding one entry `{path: "x", size: 1}` and no hashes, wrapped as `generate` wraps it, comes back from `NewManifestFromReader` with one entry.
Correct: loading refuses a manifest holding an entry with no hashes, naming the path, as it refuses a bad path; `addExistingToBuilder` then returns an error for such an entry instead of nil.
## Definition of done
- Failing test first: such a manifest is refused by `NewManifestFromReader` with a sentinel error.
- The fix in `mfer/deserialize.go`; `addExistingToBuilder` errors instead of dropping the entry.
- The file entry table in `docs/FORMAT.md` says readers reject an entry with no hashes.
- `make check` passes.
Model: fable-5-1
clawbot
self-assigned this 2026-10-12 11:17:37 +02:00
Implemented in #202: loading refuses a file entry with no hash, naming its path; freshen errors on one instead of leaving it out; docs/FORMAT.md says readers reject it.
Model: opus-5-5
Implemented in https://git.eeqj.de/sneak/mfer/pulls/202: loading refuses a file entry with no hash, naming its path; `freshen` errors on one instead of leaving it out; `docs/FORMAT.md` says readers reject it.
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.
docs/FORMAT.mdsays a file entry carries at least one hash and that readers validate what they load.deserializeInnerinmfer/deserialize.gochecks each entry's path and refuses a repeated one, but accepts an entry whosehashesis empty. Such an entry loads;checkandfetchthen fail it as a hash mismatch, which is safe, butfreshendrops it on the way through:addExistingToBuilderininternal/cli/freshen.goreturns nil for an unchanged entry with no hashes, so the file silently leaves the rewritten manifest.Confirmed on
next(0fbb3da) with a scratch test: an inner message holding one entry{path: "x", size: 1}and no hashes, wrapped asgeneratewraps it, comes back fromNewManifestFromReaderwith one entry.Correct: loading refuses a manifest holding an entry with no hashes, naming the path, as it refuses a bad path;
addExistingToBuilderthen returns an error for such an entry instead of nil.Definition of done
NewManifestFromReaderwith a sentinel error.mfer/deserialize.go;addExistingToBuildererrors instead of dropping the entry.docs/FORMAT.mdsays readers reject an entry with no hashes.make checkpasses.Model: fable-5-1
Implemented in #202: loading refuses a file entry with no hash, naming its path;
freshenerrors on one instead of leaving it out;docs/FORMAT.mdsays readers reject it.Model: opus-5-5