Summary
Core.Create does not check whether a generated (or explicitly provided) bean ID already exists in the store. At the default id_length: 4 (36-char alphabet, ~1.7M space) collisions are near-certain at realistic store sizes, and each collision silently writes a second file that shadows the first: beans check stays green, while beans list/GraphQL collapse the two records into one.
Reproduction (CLI, v0.4.2)
mkdir -p store && cat > .beans.yml <<'YAML'
beans:
path: store
prefix: scroll-
id_length: 4
YAML
python3 -c "
aliases = ' '.join(f'b{i}: createBean(input: {{title: \"Vol {i}\"}}) {{ id }}' for i in range(6000))
print('mutation { ' + aliases + ' }')" > bulk.graphql
beans query --json "$(cat bulk.graphql)" > /dev/null
ls store | sed 's/--.*//' | sort | uniq -d # -> 13 duplicate IDs
beans check; echo "exit=$?" # -> exit=0
6000 creations produced 5987 unique IDs (13 duplicate groups). beans check exits 0 over the duplicated store.
Failing test (Go, against internal/beancore)
func TestCreateRejectsDuplicateID(t *testing.T) {
dir := t.TempDir()
core := newTestCore(t, dir) // existing test helper pattern
a := &bean.Bean{ID: "scroll-dupe", Title: "First"}
if err := core.Create(a); err != nil {
t.Fatalf("first create failed: %v", err)
}
b := &bean.Bean{ID: "scroll-dupe", Title: "Second"}
if err := core.Create(b); err == nil {
t.Fatal("second create with the same ID succeeded; want duplicate-ID rejection")
}
}
The second Create succeeds today: Create only generates an ID when b.ID == "" and then writes unconditionally (internal/beancore/core.go, c.beans[b.ID] = b + saveToDisk).
Suggested fix
Two parts, either independently valuable:
- Collision guard: in
Create, if b.ID already exists (explicit or generated), either regenerate with a bounded retry loop or return an error. The explicit-ID case should always error.
- Check detection:
beans check should fail when two files resolve to the same bean ID, so already-duplicated stores are discoverable.
Environment
- beans 0.4.2 (670ecf3) built 2026-03-10, darwin/arm64, Homebrew cask
- reproduced with ~3.2k real beans (33 duplicate groups found in the wild) and the synthetic run above
Summary
Core.Createdoes not check whether a generated (or explicitly provided) bean ID already exists in the store. At the defaultid_length: 4(36-char alphabet, ~1.7M space) collisions are near-certain at realistic store sizes, and each collision silently writes a second file that shadows the first:beans checkstays green, whilebeans list/GraphQL collapse the two records into one.Reproduction (CLI, v0.4.2)
6000 creations produced 5987 unique IDs (13 duplicate groups).
beans checkexits 0 over the duplicated store.Failing test (Go, against
internal/beancore)The second
Createsucceeds today:Createonly generates an ID whenb.ID == ""and then writes unconditionally (internal/beancore/core.go,c.beans[b.ID] = b+saveToDisk).Suggested fix
Two parts, either independently valuable:
Create, ifb.IDalready exists (explicit or generated), either regenerate with a bounded retry loop or return an error. The explicit-ID case should always error.beans checkshould fail when two files resolve to the same bean ID, so already-duplicated stores are discoverable.Environment