Refuse a path listed twice in a manifest (closes #170) #174

Merged
clawbot merged 1 commits from issue-170-path-listed-once into next 2026-10-07 15:28:57 +02:00
Collaborator

Closes #170.

A manifest could list one path twice. Three places now refuse it, each naming the path:

  • gen given arguments whose files share a path (gen a b with a.txt in both, or gen . .) fails while the scanner lists the files, before any is hashed. The message names both files: duplicate path "a.txt": /x/a/a.txt and /x/b/a.txt.
  • Builder.AddFile and Builder.AddFileWithHash refuse a path already added.
  • Loading refuses a manifest that lists a path twice, compared byte for byte. The letter-case check in fetch is unchanged; an exact repeat now stops at load, before that check runs.

The Path Rules in docs/FORMAT.md gain the rule and say a reader rejects such a manifest.

What the diff does not show:

  • TestDeserializeRefusesEntriesThatDecodeTooLarge gave all 1000 entries one path, which loading now refuses. Each entry now has its own path of the same length, so the size figures in its comment still hold.
  • The builder checks for a repeat where it adds the entry, under its lock, so two concurrent adds of one path cannot both succeed. AddFile therefore reads the file before refusing; gen never gets that far.

Judgement call: loading keeps a map of the paths while it checks them, dropped when loading ends. checkDecodedSize does not count it, so peak memory while loading grows by a few dozen bytes per entry.

Model: opus-5-5

Closes https://git.eeqj.de/sneak/mfer/issues/170. A manifest could list one path twice. Three places now refuse it, each naming the path: - `gen` given arguments whose files share a path (`gen a b` with `a.txt` in both, or `gen . .`) fails while the scanner lists the files, before any is hashed. The message names both files: `duplicate path "a.txt": /x/a/a.txt and /x/b/a.txt`. - `Builder.AddFile` and `Builder.AddFileWithHash` refuse a path already added. - Loading refuses a manifest that lists a path twice, compared byte for byte. The letter-case check in `fetch` is unchanged; an exact repeat now stops at load, before that check runs. The Path Rules in `docs/FORMAT.md` gain the rule and say a reader rejects such a manifest. What the diff does not show: - `TestDeserializeRefusesEntriesThatDecodeTooLarge` gave all 1000 entries one path, which loading now refuses. Each entry now has its own path of the same length, so the size figures in its comment still hold. - The builder checks for a repeat where it adds the entry, under its lock, so two concurrent adds of one path cannot both succeed. `AddFile` therefore reads the file before refusing; `gen` never gets that far. Judgement call: loading keeps a map of the paths while it checks them, dropped when loading ends. `checkDecodedSize` does not count it, so peak memory while loading grows by a few dozen bytes per entry. Model: opus-5-5
clawbot added the needs-review label 2026-10-07 14:45:21 +02:00
clawbot self-assigned this 2026-10-07 14:45:21 +02:00
clawbot added 1 commit 2026-10-07 14:45:22 +02:00
gen given arguments whose files share a path, such as gen a b with a.txt
in both, or gen . ., now fails while listing the files, before hashing
any, naming the path and both files. Builder.AddFile and
Builder.AddFileWithHash refuse a path already added. Loading refuses a
manifest that lists a path twice, compared byte for byte; fetch keeps
its own letter-case check. The Path Rules in docs/FORMAT.md say each
path appears at most once. The decode-size test listed one path 1000
times; each entry now has its own path of the same length.

Model: opus-5-5
Author
Collaborator

Review passed, gated on next at f663f42.

  • Judgement call: loading builds a map of paths that checkDecodedSize does not count. The map costs a fixed amount per entry, and that limit already caps the number of entries by the inner message's size, so loading memory stays within a fixed multiple of that size. Accepted.
  • Judgement call: a Builder made without NewBuilder now panics on its first add, because its map of paths is never made. Nothing in the tree builds one that way. Accepted.

Model: opus-5-5

Review passed, gated on `next` at `f663f42`. - Judgement call: loading builds a map of paths that `checkDecodedSize` does not count. The map costs a fixed amount per entry, and that limit already caps the number of entries by the inner message's size, so loading memory stays within a fixed multiple of that size. Accepted. - Judgement call: a `Builder` made without `NewBuilder` now panics on its first add, because its map of paths is never made. Nothing in the tree builds one that way. Accepted. Model: opus-5-5
clawbot merged commit 4fe1ff2fe1 into next 2026-10-07 15:28:57 +02:00
clawbot deleted branch issue-170-path-listed-once 2026-10-07 15:28:58 +02:00
Sign in to join this conversation.