Skip to content

test(mcp): the globstar-gate test cannot fail — its fixture is refused by the size bound first #686

Description

@zzet

TestMatchFidelityGlob_NonGlobstarPatternDoesNotEnterTheWalk (internal/mcp/fidelity_globs_test.go:486) exists to pin the patternHasGlobstarSegment gate in compileGlob — the check that keeps a pattern with no whole-segment ** out of the segment walk. It does not pin it. The gate can be deleted outright and the test stays green.

Cause

Its fixture is refused earlier by a different check:

pattern := strings.Repeat("segment/", 999) + "*"   // 7,993 bytes

compileGlob (internal/mcp/fidelity_globs.go:158) bounds before it gates:

g := compiledGlob{pattern: filepath.ToSlash(pattern)}
if g.tooComplex() {          // 7,993 > maxGlobBytes (1024) — returns here
    return g
}
if patternHasGlobstarSegment(g.pattern) {   // never reached for this fixture
    g.segments = globPatternSegments(g.pattern)
}

segments stays nil because the pattern is over-budget, not because it has no globstar. The test's own require.False(t, patternHasGlobstarSegment(pattern), ...) guard-the-guard assertion is true but irrelevant — it checks a condition that never gets consulted.

BenchmarkMatchFidelityGlob_LongTerminalStarWithoutGlobstar (:381) uses the same fixture and has the same problem. Its doc-comment's "99,009 B/op before the gate" figure is no longer reachable: with the admission bounds in place that pattern is refused by find_files and parseFidelityGlobs before it reaches the matcher at all.

Repro

Remove the gate, keeping everything else:

 	if g.tooComplex() {
 		return g
 	}
-	if patternHasGlobstarSegment(g.pattern) {
-		g.segments = globPatternSegments(g.pattern)
-	}
+	g.segments = globPatternSegments(g.pattern)
go test -count=1 -run 'FidelityGlob|FindFiles_Glob' ./internal/mcp/
ok  github.com/zzet/gortex/internal/mcp  2.026s

The entire glob suite passes with the mechanism gone.

The gate is load-bearing

Measured with an in-bounds fixture — strings.Repeat("segment/", 63) + "*" (505 bytes, 64 segments, admitted) against a 40-segment path, darwin/arm64:

ns/op B/op allocs/op
gate present 4,259 1,032 2
gate removed 921,190 4,099 6

216x per candidate. find_files runs the matcher against every candidate file ahead of limit, so on a 10k-file scope that is ~9 s of CPU for one request with no ** in the glob at all.

Fix

Two changes are needed, not one. Swapping in an in-bounds fixture alone still will not fail: the ungated cost there is 4,099 B/op, comfortably under the test's own 40,000 B ceiling. That ceiling was calibrated against the out-of-bounds fixture (99,009 vs 16,384) and does not survive the move.

  • Use a fixture inside the admission bounds, and assert that it is: require.False(t, compileGlob(pattern).tooComplex(), ...).
  • Assert the gate structurally rather than through an allocation proxy: require.Nil(t, compileGlob(pattern).segments, "a pattern with no whole-segment globstar must not compile a segment walk"). That cannot drift with allocator behaviour and fails the moment the gate is removed.
  • Give the benchmark the same in-bounds fixture and correct its doc-comment figure, or drop the stale number.

Context

Introduced in #647. The other two performance guards in that change do bite under mutation and need no work — restoring the strings.Join suffix rebuild fails at 17,024,844 B against the 1 MB ceiling, and replacing the memo with naive recursion blows the 5 s timeout.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions