Go tree-sitter fallback (ingester) Plan¶
REQUIRED SUB-SKILL: superpowers:subagent-driven-development.
Goal: Index non-buildable Go packages via tree-sitter when go/packages reports errors, instead of skipping them.
Spec: docs/superpowers/specs/2026-06-06-code-graph-full-scope-design.md (Go tree-sitter fallback).
CGo required. Read internal/analyze/golang.go (esp. the len(pkg.Errors) > 0 skip), internal/analyze/python.go (tree-sitter walk pattern with github.com/smacker/go-tree-sitter + a grammar subpackage), and internal/contract constants first.
Task 1: Fallback analyzer for broken Go packages¶
Files: - Create: internal/analyze/golang_fallback.go - Modify: internal/analyze/golang.go (call fallback at the package-error point) - Test: internal/analyze/golang_fallback_test.go, fixture internal/analyze/testdata/go_broken/
- Step 1: Broken-package fixture. Create
internal/analyze/testdata/go_broken/pkg/broken.gothat is syntactically parseable but does NOT type-check (e.g. references an undefined symbol):
package pkg
func H() int { return G() }
func G() int { return undefinedThing() } // undefinedThing is not declared -> type error
and internal/analyze/testdata/go_broken/go.mod:
-
Step 2: Failing test. In
golang_fallback_test.go, assert that running the Go analyzer over the broken package still emits ago_funcentity forHandG(repo-relativeFilePathpkg/broken.go), and acallsedgeH->Gwithproperties[degraded_by]containingno_typecheckandconfidence<= 0.45. Run -> RED (currently the package is skipped, so zero entities). -
Step 3: Implement
golang_fallback.go. A functionfallbackAnalyzeGoPackage(modulePath, absRepoRoot string, files []string, scope map[string]bool) analyze.Result(or method on the go analyzer): - Compute
pkgPathstructurally:modulePath+ "/" + (dir of the file relative to module root), ormodulePathif the file is at module root. (Module path read from go.mod via the existing analyzer; pass it in.) - Parse each in-scope
.gofile withgithub.com/smacker/go-tree-sitter+ thegolanggrammar (golang.GetLanguage()), mirroring python.go'ssitter.ParseCtxusage. - Walk for
function_declarationandmethod_declaration->go_func/go_methodentities (go:func:<pkgPath>.<name>,go:method:<pkgPath>.(<recv>).<name>);type_declaration/type_spec->go_type. Emitdefines/containsas the type-resolved analyzer does where cheap. - Walk
call_expression-> name-basedcallsedges using the same M3 ladder as python/js (scoped/global/ambiguous/unresolved over the package's own def set), but ALWAYS addno_typechecktodegraded_byand cap confidence at 0.45 (contract.ConfidenceForthen min with 0.45, i.e. set "0.45" when the raw value exceeds it). - Emit a Chunk per func/type.
-
Respect the scope set (only in-
filesemissions). -
Step 4: Hook into golang.go. Where the analyzer currently does
if len(pkg.Errors) > 0 { log.Warn(...); continue }, instead: log WARN (keep the signal) and call the fallback for that package's in-scope files, appending its Result. Type-resolved packages are unchanged. The module path is available (read it once from go.mod at analyze start, or derive from the first ok package's path - prefer reading go.mod). - Step 5: Run until the test passes. Confirm the existing
TestGoAnalyzer(type-resolved path) is unaffected. - Step 6:
golangci-lint run ./internal/analyze/...clean. Commitfeat(analyze): tree-sitter fallback for non-buildable Go packages.
Task 2: Verify¶
- Full
CGO_ENABLED=1 go test ./... -count=1green; lint clean. Note in MEMORY.md: fallback packages emit provides (names visible) but NOT requires (no type resolution to attribute external refs) - per spec.