Skip to content

the ambiguous-prefix test asserts nothing in ~17% of runs, and its commit loop produced a git object failure in CI #649

Description

@MongLong0214

test/sha256-repo.test.ts > resolveRevision turns user input into one full id, or refuses (R0-03) > refuses an ambiguous prefix rather than picking one has two separate problems. The first is measurable and certain; the second is observed once and I cannot explain its mechanism.

1. It passes without asserting, about one run in six

The test commits up to 120 times looking for two commit ids that share a 3-hex prefix, then returns early if it finds none:

for (let i = 0; i < 120 && ambiguous === null; i += 1) {  }
if (ambiguous === null) return;   // reported as a pass

120 draws into 4096 buckets leaves a 17.2% chance of no collision. In those runs the test reports green having exercised nothing — neither git's ambiguity detection nor resolveRevision's refusal.

The comment above the loop shows this was a deliberate choice — skipping rather than faking is the right instinct when a search fails. But the skip is invisible: vitest counts it as a pass, so a green suite does not distinguish the refusal works from we never looked. That is the same shape as the ENOENT assertion fixed in #641 — a check that cannot report the thing it appears to check.

A cheaper and more reliable construction is available: git reports an ambiguous short name when the prefix matches multiple objects of any type, so writing blobs with git hash-object -w --stdin until one collides with the HEAD commit's prefix costs no commits, no trees, and no index writes, and can search far enough that failing to find a collision is negligible rather than routine.

2. A staged object vanished mid-loop, once, on CI

Run 31771047613, job check (22.23.2), on PR #644:

FAIL test/sha256-repo.test.ts > … > refuses an ambiguous prefix rather than picking one
Error: git commit --quiet --no-verify -m c105 failed (exit 1):
  error: invalid object 100644 1da3827fbab6786665dbd0a1df4272cb81b0b8fe for 'c102.txt'
  error: Error building trees
Tests  1 failed | 3064 passed | 2 skipped (3067)

c102.txt was staged three iterations earlier by stageChange, which uses git add and throws on a non-zero exit — so the blob existed when it was staged. By the time c105 built its tree, the object was gone from the database.

What I checked and ruled out:

  • Not a shared temp directory. temp() uses mkdtempSync, so every repo is unique; there is no glob-based sweep of tmpdir() anywhere in test/, src/, or scripts/.
  • Not the product calling gc. The only git gc in the tree is test/deterministic-bench.test.ts, scoped to its own fixture.
  • Not automatic gc, as far as I can tell. gc.auto defaults to 6700 loose objects; this loop creates roughly 360.

What the measurements say about scope:

I cannot explain how the object disappeared. Recording it rather than closing it, because a git object database losing a just-written object inside a test is worth knowing about even at one occurrence, and the honest state is unexplained rather than benign.

The two problems are plausibly connected — 120 commits with a growing index is the heaviest thing this file does, and replacing it with blob hashing would remove the stressor as well as the silent pass — but I have not shown that the loop caused the failure, and fixing the loop should not be recorded as fixing the object loss.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions