Conversation
…s case ckb impact prepare reported unexported Go methods (e.g. Engine#buildProvenance) as "public" with a "Public API change" risk factor. This was going on the homepage as real evidence, so the wrong call here is user-facing, not cosmetic. Root cause: SCIPIdentifier.GetSimpleName() (internal/backends/scip/ids.go) only split a method descriptor on the last '/', so for `pkg`/Engine#build Provenance(). it returned "Engine#buildProvenance" instead of "buildProvenance" — the capitalized receiver type leaked into the "simple name". inferVisibility (internal/backends/scip/symbols.go) then tested Go export-by-case on that mangled name, saw the uppercase 'E' from "Engine", and called every method on an exported type "public" regardless of the method's own case. Fix: after stripping the trailing "()", also split on the last '#' so the receiver type is discarded and only the method name is returned. Verified end-to-end: inferVisibility(buildProvenance) now returns "private" as it should. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
… "unknown"
ckb impact prepare showed every directDependents entry with
symbolId: "" and name: "unknown" — only file/line were populated.
The caller-resolution data actually exists: SCIP's processOccurrence
(internal/backends/scip/references.go:75) already resolves the
enclosing symbol per reference via findContainingSymbolFast and
stores it on SCIPReference.FromSymbol. It just never made it past
the backend boundary.
Root cause: backends.Reference (internal/backends/backend.go:146) had
no field for the enclosing symbol, so SCIPAdapter.convertToReference
(internal/backends/scip/adapter.go:359) silently dropped
scipRef.FromSymbol on every conversion. Downstream,
internal/query/impact.go:294 built impact.Reference without ever
setting FromSymbol/FromModule (both of which the impact.Reference type
already had fields for), so internal/impact/analyzer.go:130's
`StableId: ref.FromSymbol` was always "" and
`extractNameFromStableId("")` (analyzer.go:208) hard-coded "unknown".
Fix: added FromSymbol/FromSymbolName to backends.Reference, populated
from SCIPReference.FromSymbol in convertToReference (short name derived
via the SCIPIdentifier.GetSimpleName fix from the previous commit), and
wired FromSymbol/FromName through internal/query/impact.go into
impact.Reference. Where the backend genuinely can't resolve an
enclosing symbol (e.g. a package-level reference outside any
function), StableId/Name now come back "" rather than "unknown" —
extractNameFromStableId/extractModuleNameFromId no longer fabricate a
placeholder, and PrepareDependent/ImpactItem's symbolId, name, and
moduleId JSON fields are now `omitempty` so the response omits them
instead of showing a lie.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
… form Follow-up to the directDependents fix: while validating it against the full golden suite, ckb impact prepare's typescript fixtures showed "name": "scip-typescript npm fixture 1.0.0 src/`main.ts`/" — the entire raw, space-and-backtick-laden SCIP ID dumped as a caller name. Worse than the "unknown" placeholder it replaced. Root cause: some scip-ts "enclosing symbols" are module/namespace-level (descriptor ends in a bare "/" with nothing after it — a whole-file scope, not a named function), and GetSimpleName legitimately returns "" for those. convertToReference (internal/backends/scip/adapter.go) still set FromSymbol to the raw ID in that case, so internal/impact's extractNameFromStableId fallback echoed the full ID as "name" once FromName came back empty. Fix: when GetSimpleName can't derive a short name, leave both FromSymbol and FromSymbolName empty — same as "no enclosing symbol resolved" — so the field is omitted rather than filled with a wall of text. Confirmed against testdata/fixtures/typescript/expected/impact_* .json, which previously couldn't have caught this because FromSymbol was never populated at all before the directDependents fix. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…leName fix
Downstream fallout from the Go-method-visibility fix (SCIPIdentifier.
GetSimpleName, internal/backends/scip/ids.go): that function backs the
symbol "Name" the SCIP indexer stores when a symbol has no DisplayName,
which turns out to feed searchSymbols relevance, getSymbol exact-name
resolution, and listEntrypoints' naming-based classification — not just
impact visibility. These golden fixtures were snapshotting the old
mangled names ("Handler#service" for a field literally named "service",
etc.), so once the name is correct they mismatch.
Verified each diff by hand before updating:
- search_*.json: fields/methods whose old mangled name coincidentally
substring-matched the query (e.g. "Handler#service" matching a search
for "handler") no longer do, and now-clean names both remove that
false-positive relevance boost and let previously-invisible symbols
surface — this is a relevance improvement, not a regression. Go's
search_handler total drops 10->9 by legitimately excluding one field
that only ever matched "handler" through the type prefix, not the
field itself.
- symbol_Model.json: exact-name lookup for "Model" was resolving to
the *method* "Model#Clone" (because its old mangled name started with
"Model"); it now correctly resolves to the "Model" type itself.
- trace_FormatOutput.json (typescript): the entrypoint list's
deterministic tie-breaker sorts by Name (internal/query/navigation.go
~1418); with the old mangled names, the TypeScript "handle" method's
entrypoint entry (real name "handle", camelCase) happened to also
carry the receiver's PascalCase "Handler" prefix, which is what let
it match the entrypoint-detection pattern list (naming.go ~1305:
strings.HasPrefix(sym.Name, "Handle")). With the name fixed to bare
"handle", it legitimately no longer matches a PascalCase-only
pattern list, so it's no longer classified "api". That's a real,
separate, pre-existing gap in ListEntrypoints' TypeScript coverage
(naming patterns are Go-convention-only) that this fix incidentally
un-masked — not something introduced here, and out of scope for the
three reported evidence-output bugs, so left as-is and called out for
a follow-up.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…t names
Two independent bugs in `ckb callgraph <sym> --direction=callers`:
1. Human-format header said "Callees (what this calls)" for a
callers-only query, even though every node's JSON role was
"caller". cmd/ckb/format.go's formatCallgraphHuman grouped nodes by
`n.Depth < 0` (callers) / `n.Depth > 0` (callees), but no code path
in internal/query/navigation.go's GetCallGraph ever emits a negative
Depth — caller nodes get Depth: 1 same as callees (navigation.go:512
vs :534), Depth is always a non-negative distance from the root
regardless of direction. Every non-root node fell into the ">0"
bucket, so real callers always printed under "Callees". Fixed by
grouping on the Role field instead, which the engine already sets
correctly to "caller"/"callee"/"transitive"/"root" — and gave
"transitive" (depth>1 BFS nodes, which also have no direction info)
its own section instead of silently lumping it into "Callees" too.
2. Node short names were mangled, e.g.
"com/SimplyLiz/CodeMCP/internal/query`/Engine#buildModuleLevelResponse"
— missing the "github." prefix. Root cause:
internal/backends/scip/callgraph.go's extractSymbolName looked for
the *last* "." anywhere in the descriptor to find a name separator.
scip-go descriptors quote the full module path in backticks right
inside the descriptor (`` `github.com/org/repo/pkg`/Type#Method(). ``),
and "github.com" has a dot of its own — extractSymbolName found that
dot instead of a real separator and sliced after it, dropping
"github." and everything before. Existing tests didn't catch this
because their fixture package paths ("ckb/internal/query") don't
contain dots.
Fixed with a shared stripQuotedPackagePrefix helper that strips a
backtick-quoted package-path prefix when present, and only falls
back to last-dot splitting when there isn't one. Deliberately keeps
the existing "Type#Method" / "Type#field" convention (extractSymbolName's
own tests already lock that in, e.g. "Engine#Close" — unlike
SCIPIdentifier.GetSimpleName, which intentionally strips the receiver
for the separate Go-visibility fix) — the task's own suggested output
is "Engine#buildModuleLevelResponse".
Golden fixtures updated: the Go fixtures previously encoded the exact
bug (`` `fixture/pkg`/NewServer `` with literal backticks in the name),
and the TypeScript fixture was worse ("ts`/runServer" — a completely
different off-by-N slice against the "src/`main.ts`/runServer()."
descriptor shape). Both now show clean names.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
ckb impact prepare reported "kind": "function" for Engine#buildProvenance,
a method, not a bare function.
Root cause: SCIPIdentifier.ExtractSymbolKind (internal/backends/scip/
ids.go) checked descriptor for '(' before checking for '#', and returned
KindFunction as soon as it saw '(' — so a method descriptor like
`pkg`/Engine#buildProvenance(). (which contains both markers) was always
classified as a bare function; the '#' check a few lines further down
was unreachable for any symbol with parens at all.
This isn't just an edge case: ExtractSymbolKind is the fallback used
when SymbolInformation.Kind isn't reliably set, and multiple comments
elsewhere in this package (e.g. callgraph.go's isFunctionSymbol) note
that scip-go frequently doesn't set it — so this fallback is the live
path for a lot of real Go methods, not a rare corner case.
Fix: classify as KindMethod when both '#' and '(' are present, before
falling through to the parens-only (function) and hash-only (class)
checks.
Golden fixtures updated: SearchSymbols results include Kind and are
sorted, so this ripples into search_*.json the same way the earlier
GetSimpleName fix did (verified by hand: only receiver methods and
constructors flip from "function" to "method"; plain package-level
functions like NewModel/newDefaultService correctly stay "function").
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…oundary ckb impact prepare reported "score": 0.7000000000000001 instead of 0.7. Root cause: calculatePrepareRisk (internal/query/compound.go) accumulates score via repeated float64 addition of factor weights (0.25, 0.2, 0.15, 0.1, ...). None of these are exactly representable in binary floating point, so the sum carries rounding noise — e.g. 0.15+0.2+0.15+0.2 is 0.7000000000000001 in Go, not 0.7. Nothing downstream ever rounded it before it hit the JSON/human output. Fix: round to 2 decimals (math.Round(score*100)/100) at the output boundary, in the PrepareRisk struct literal — the individual factor weights don't carry more precision than that anyway. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…t checks ckb impact prepare's "No tests found" risk factor fired for Engine#buildProvenance even though internal/query has abundant *_test.go files right next to engine.go. Two things, found while investigating: 1. Real bug: getPrepareTests (internal/query/compound.go) globs for *_test.go/*.test.ts/*.spec.ts files in the target's own module directory, gated on `target.ModuleId != ""`. resolvePrepareTarget set ModuleId straight from the SCIP backend's symbol lookup, which never resolves it (backends/scip/adapter.go's convertToSymbolResult hardcodes ModuleID: "" with the comment "resolved later by the query engine" — nothing downstream ever did that). So target.ModuleId was "" for every symbol target, the glob never ran, and the factor fired unconditionally regardless of whether tests existed. Fixed by deriving ModuleId from the symbol's file path when the backend doesn't supply one, same as the file/directory target branches in the same function already do. 2. Wording: even with (1) fixed, this check only proves test *files* exist in the same directory — it doesn't check whether the target symbol is itself referenced by any test. Renamed the factor to "No test files found in target module" so it says what it actually verifies instead of implying broader coverage knowledge the check doesn't have. Not touching the check's logic to claim more than that — per the request, wording only, no faked coverage. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…ated ckb impact prepare suggested "Ensure backward compatibility or bump major version" for Engine#buildProvenance, an unexported method. Certainty: this was already fixed as a side effect of the earlier Go-method-visibility commit (SCIPIdentifier.GetSimpleName) — not a separate bug. calculatePrepareRisk (internal/query/compound.go) was already correctly gated on `target.Visibility == "public"` before that commit; the suggestion only ever fired for buildProvenance because visibility itself came back "public" for it, which is what the GetSimpleName fix addressed. Verified by reading calculatePrepareRisk: no change needed here. Adds a regression test locking in the gate itself (internal visibility -> neither the "Public API change" factor nor the suggestion; public visibility -> both), so a future visibility regression would be caught at this call site too, independent of the SCIP-parsing layer. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…arser
ParseSCIPIdentifier hand-rolled its own symbol-ID splitter, which only
handled scip-go's backtick-quoted package paths and Go-shaped method
descriptors. A prior fix on this branch (GetSimpleName stripping "Type#"
unconditionally to fix Go method visibility) broke every other language:
TypeScript member names collapsed the same way search relies on to keep
members findable by container, TS parameter descriptors like
"Handler#handle().(input)" got misclassified as "method" because
ExtractSymbolKind just checked for '#' and '(' anywhere in the descriptor,
Java's two-token maven package coordinate was mis-split by
SplitN(id, " ", 5) treating the artifact as the version, and constructor
descriptors with backtick-escaped names ("`<constructor>`") produced empty
or garbled names.
Fix: delegate to github.com/sourcegraph/scip/bindings/go/scip's
ParseSymbol, which splits a symbol into scheme, package
(manager/name/version, each correctly unescaping a doubled-space-escaped
internal space per the SCIP spec), and a chain of descriptors each
carrying its own suffix (namespace '/', type '#', term '.', method "().",
type-parameter '[..]', parameter '(..)', meta ':', macro '!'), with
backtick-escaped names unescaped. GetSimpleName is then just "the last
descriptor's name" (no receiver leakage regardless of language);
ExtractSymbolKind checks the last descriptor's suffix, distinguishing
method vs. function by whether the second-to-last descriptor is a type;
GetContainerName walks back for the nearest enclosing type descriptor;
GetPackageInfo now returns the already-correctly-parsed manager/name/
version instead of re-splitting the package string on whitespace.
Identifiers that don't conform to the strict SCIP grammar (e.g. "local
..." symbols, or malformed 4-field test fixtures missing a package
version) fall back to the original heuristic parser, so ad-hoc test
identifiers keep working.
Replaced ids_test.go's struct-literal tests (which bypassed the real
parser and only exercised the legacy fallback) with end-to-end
ParseSCIPIdentifier tests across Go, TypeScript, Java, Python, and Rust,
covering methods, free functions, constructors, parameter descriptors,
and the Java package-coordinate escaping.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
extractSymbolName built call graph node labels ("Type#Member") by hand:
find the last space-delimited "part" of the ID, strip a trailing "()." or
".", then strip a backtick-quoted package prefix. Two bugs: (1)
stripQuotedPackagePrefix found the *last* backtick in the string, which
for a symbol like `pkg`/Handler#`<constructor>`() is the constructor's own
closing backtick, not the package path's — the "name" after it is empty,
so the constructor node got named "". (2) The same helper (and the
splitter feeding it) only understood Go-shaped "()." method descriptors
and receiver-name splitting; it wasn't documented as Go-specific but broke
on other languages' descriptor shapes the same way ids.go did.
Fix: parse with the official scip bindings and rebuild the label from the
parsed descriptor chain, dropping namespace (package-path) descriptors
and adding back just enough suffix punctuation per descriptor kind to
stay unambiguous — "().” between a method and what follows it, "(...)"
around a parameter — while omitting that trailing punctuation on the
terminal descriptor. This reproduces the existing (already-reviewed)
call graph name format exactly (e.g. "Engine#buildModuleLevelResponse",
bare "Engine#", "NewServer") and additionally gives non-empty names for
constructors and other backtick-escaped descriptors. Falls back to the
original heuristic splitter for identifiers that don't conform to the
strict SCIP grammar.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…espace convertToReference resolves FromSymbol/FromSymbolName (the enclosing function/type containing a reference) by parsing the enclosing symbol ID and taking GetSimpleName(). Some scip-go/scip-typescript "enclosing symbols" are whole-file, namespace-level SymbolInformation entries whose EnclosingRange spans the entire document (scip-typescript emits one per file) — a top-level reference with no enclosing function/type resolves its "container" to that file-scope symbol. Previously GetSimpleName legitimately returned "" for that case (its old implementation only found a name after a trailing "`/" package-path split, which a bare namespace descriptor doesn't have), so the existing check `name != ""` correctly filtered it out. Now that GetSimpleName always returns the last descriptor's name — correct in general, see the prior commit — a namespace descriptor's name (e.g. "handler.ts", the file itself) is no longer empty, so it started leaking through as if a file were a "caller". Fix: also check that the resolved symbol's kind isn't KindNamespace before treating it as a real enclosing symbol, restoring the original intent (skip file/namespace-only containers) without special-casing GetSimpleName itself, which other callers rely on to return a namespace's own name for real namespace symbols. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…detection Two related regressions from the GetSimpleName fix, both stemming from symbol names becoming correctly bare (e.g. "handle" instead of "Handler#handle" or "Handler.handle"): 1. FTS indexing built the container-qualified "signature" field (e.g. "Handler.handle", so searching "Handler" still finds its members) from SymbolInformation.EnclosingSymbol via GetSimpleName. But scip-go/scip-typescript frequently leave EnclosingSymbol unset (empty in both fixtures used by the golden tests), so that branch never ran and signature silently fell back to the bare name — container-qualified search was never actually populated, just coincidentally still working before because GetSimpleName used to leak the receiver into the "name" itself. Fix: derive the container from the symbol's own descriptor chain via GetContainerName (which doesn't depend on EnclosingSymbol being set) as the primary path, keeping the EnclosingSymbol-based lookup as a fallback. 2. listEntrypoints' handler-pattern detection used strings.HasPrefix(sym.Name, "Handle") — case-sensitive. This accidentally matched TS's "handle" method before, only because the mangled name "Handler#handle" happened to start with "Handle" (the capitalized *receiver type*, not the method itself). With names now correctly bare, "handle" no longer matches a case-sensitive "Handle" prefix. Go's exported convention capitalizes names Go programmers would call "Handle*"; TS/JS methods are conventionally lowercase for the same naming pattern. Made the check case-insensitive so the naming-convention detection isn't accidentally Go-specific. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…dule ids, and make risk level agree with the displayed score
Three related evidence-output bugs in prepareChange/analyzeImpact:
1. A prior commit added `,omitempty` to PrepareDependent.SymbolId/Name/
ModuleId and ImpactItem.StableId/ModuleId so an unresolved enclosing
symbol wouldn't display the literal string "unknown". That's the right
call for the *value* (empty string, not a fake placeholder) but wrong
for the *JSON shape*: these responses are schemaVersion 1, which
documents these as always-present string fields. Dropping the key
entirely when the value happens to be empty is a breaking contract
change for any strict consumer, without a version bump to announce it.
Reverted the omitempty tags; the fields still serialize as "" rather
than "unknown".
2. Neither PrepareDependent nor ImpactItem's construction ever derived a
moduleId for a reference's enclosing symbol — analyzeImpact's
reference-building loop set Kind/Location/FromSymbol/FromName but never
FromModule, so every direct dependent's moduleId stayed "". That fed
straight through to prepareChange's module-spread count
(moduleId->bool set) and blastRadius.moduleCount, both of which
silently under-reported (0 modules affected regardless of the actual
spread). Derived FromModule from the reference's own file path
(filepath.Dir), the same way resolvePrepareTarget already derives a
symbol target's moduleId from its file path. Also guarded the
module-spread set against inserting an empty "" key for any reference
that still has no location.
3. calculatePrepareRisk derived `level` ("low"/"medium"/"high"/"critical")
from the raw, unrounded score, but returned a Score field rounded to 2
decimals for display. Binary-float accumulation (0.15+0.2+0.15+0.2,
etc.) can land just under a threshold (e.g. 0.6999999999999998), which
rounds to a displayed "0.70" while classifying as "high" — display and
level visibly disagree at the boundary. Round once, and derive level
from that same rounded value.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…parsing, disambiguate symbol_Model by kind
Regenerated after the ids.go/callgraph.go/adapter.go/fts.go/navigation.go
fixes in this branch. Every diff falls into one of:
- search_handler (go, ts): member search restored — "handle"/"Handle" and
other members are findable again via the container-qualified FTS
signature; parameter/property descriptors that were misclassified as
"method" now show their real kind; constructor names are no longer
garbled ("Handler#`<constructor>`" -> "<constructor>").
- search_service, search_model (go, ts): same kind-classification fix —
fields previously mislabeled "class" (any descriptor containing '#' was
called a class) now show as "property"/"method" correctly, and
previously-invisible field members (empty name, filtered out) are now
found.
- search_main (go): a previously-invisible whole-file namespace symbol
(empty name before this fix) now surfaces with its real name; harmless,
the file's own name is now a legitimate low-rank match.
- impact_FormatOutput, impact_Handler (go, ts): moduleCount/modulesAffected
now populated (see the FromModule-derivation fix) and riskScore.score
changed accordingly; a constructor name resolved correctly instead of
showing the raw escaped descriptor; a field wrongly classified "class"
now shows "property".
golden_test.go: TestGolden_GetSymbol's "Model" case searched by name only
and took the top (Limit: 1) result. Fixing the kind-classification bug
above means the TS fixture's "model" field is now also a valid unfiltered
match for the query "Model", and it happened to rank above the "Model"
class in the TypeScript fixture (bm25 tie-break, not something this
branch controls) — the test started resolving a different symbol than
the "Data structure" case comment says it's meant to exercise. Filtered
that case by Kind: "class" to restore deterministic intent; with the
filter applied the resolved symbol is byte-identical to the pre-existing
develop baseline, so no golden file was needed for it.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The FTS5 unicode61 tokenizer folds case, so a query for "Model" can't be
told apart from a field named "model" by bm25() alone — ties broke on
SQLite's internal row order, which put the field ahead of the class in the
TypeScript fixture (and, by luck of insertion order, not in Go). A previous
commit on this branch papered over the symptom by adding a Kind: "class"
filter to the golden test instead of fixing the ranking, which hid a real
user-facing regression: searching "Model" could return the lowercase field
instead of the type.
Two changes close the gap:
- internal/storage/fts.go (searchExact): sort a case-sensitive exact name
match first, then a type-like kind (class/interface/struct/type) among
case-fold-only matches, before bm25 — and before the caller's LIMIT is
applied. Without this, opts.Limit*ftsMultiplier (2, for a Limit:1 caller
like GetSymbol's search-then-fetch) could truncate the FTS candidate pool
before the correct symbol ever reached Go-side ranking, no matter how
good that ranking was.
- internal/query/symbols.go (rankSearchResults): split the "exact" match
tier into a case-sensitive exact match (score +100) and a case-fold-only
match (+80, plus a further tie-break for type-like kinds over
properties/parameters). This keeps the SCIP/tree-sitter fallback paths
(which don't go through FTS) consistent with the FTS ordering.
Removed the Kind: "class" filter from TestGolden_GetSymbol's symbol_Model
case; it now passes on ranking alone for both fixtures.
Regenerated testdata/fixtures/{go,typescript}/expected/impact_Handler.json:
both fixtures deliberately contain a second "Handler" — a free function in
Go's main.go (explicitly commented as a disambiguation decoy) and a private
`handler` field in the TS Server class — that collided with the exported
Handler type under the old ranking. AnalyzeImpact's "Handler" lookup now
resolves to the actual Handler type (which has real callers/blast radius)
instead of the zero-impact decoy function / the field. impact_FormatOutput
was also touched by -update but is byte-identical (no name collision there).
Added unit tests: TestRankSearchResults_CaseExactOutranksFold and
TestIsTypeLikeKind in internal/query/symbols_test.go, and
TestFTSManagerSearchExactCasePriority in internal/storage/fts_test.go.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
FTS-backed search already indexes a "Container.member" alias (convertSymbolToFTSRecord in internal/query/fts.go) so a query for "Handler" finds "Handler#handle" even though the member's own display name is just "handle". The SCIP-native SearchSymbols path never got the same fix: all three of its code paths (the NameIndex fast path, the ConvertedSymbols map fallback, and the on-the-fly last-resort conversion) matched only the bare display name via matchesQuery. Any installation with FTS disabled, unavailable, or returning no results silently lost member findability by container name. Add an Alias field to NameEntry (container-qualified name, built from the already-computed SCIPSymbol.ContainerName) and check it in the NameIndex pre-filter; matchesQuery now falls back to the same container-qualified check for the two paths that don't use NameIndex. Old on-disk derived caches decode fine (Alias defaults to "") and self-heal on the next reindex, since the cache is keyed by the .scip file's mtime+size. Add a no-FTS regression test covering all three SearchSymbols paths. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
isTypeLikeKind decides which kind wins a case-fold-only search tie (e.g. class Model vs. field model). It listed class/interface/ struct/type but omitted enum, even though enum is a real kind this codebase emits (SCIP kind 3, see inferKindString in internal/query/fts.go and KindEnum in internal/backends/scip/ types.go). A case-fold-only query like "STATUS" ranked an enum `Status` no higher than a property `status`, contradicting the type-like ranking policy's intent. Checked the full SymbolKind set this codebase defines (internal/backends/scip/types.go) for other type-like kinds worth adding: there is no separate trait/protocol/typealias kind here — Rust traits and meta descriptors both collapse to the existing "type" kind via kindFromDescriptors in internal/backends/scip/ids.go — so enum was the only gap. Extends TestIsTypeLikeKind and adds a case-fold ranking regression test (STATUS -> enum Status over property status). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
getPrepareTests only implements test-file discovery for Go
(*_test.go) and TypeScript/JavaScript (*.test.ts/js, *.spec.ts/js).
calculatePrepareRisk fired "No test files found in target module"
(and its 0.2 score contribution) whenever the glob came back empty —
which for Python, Rust, Java/Kotlin, and every other language was
every single time, since discovery never runs for them. That's a
false claim ("no tests exist"), not a finding ("we didn't check").
Rather than implementing multi-language discovery now, make the
factor honest: add languageSupportsTestDiscovery, which checks the
target's file extension (or, for directory/module targets, globs the
module dir for .go/.ts/.js files) and only lets the factor fire when
discovery is actually implemented for that language. Every other
language just omits the factor instead of asserting something we
don't know.
Updates the two existing calculatePrepareRisk tests that relied on
the factor firing unconditionally to use a .go target path, and adds
a Python-target regression test confirming the factor (and its score)
is omitted.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…names Round-2 evidence review flagged that recent fixes (see TestConvertToReference_ModuleLevelEnclosingSymbol in internal/backends/scip/adapter_test.go, and the FromSymbol/ FromSymbolName comments in internal/query/compound.go) changed the fallback for an unresolved dependent name/symbolId from the string "unknown" to "" — a genuine semantic change for any consumer that checked for the literal "unknown" sentinel, even though the JSON key itself is unaffected (schemaVersion 1 fields aren't omitempty). Add an Unreleased entry so downstream consumers see it before the next release, following this changelog's existing dated-section format. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
gofmt rewrites a doubled backtick in doc comments to a typographic quote, which would have changed what the comment says about SCIP escaping. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
🟢 Change Impact Analysis
Blast Radius: 0 modules, 0 files, 0 unique callers 📝 Changed Symbols (16)
Recommendations
Generated by CKB |
CKB Analysis
Risk factors: Large PR with 46 files • High churn: 2454 lines changed • Touches 22 hotspot(s) 👥 Suggested: @lisa.welsch1985@gmail.com (22%), @talantyyr@gmail.com (9%), @lisa@tastehub.io (4%)
🎯 Change Impact Analysis · 🟢 LOW · 16 changed → 0 affected
Symbols changed in this PR:
Recommendations:
💣 Blast radius · 0 symbols · 10 tests · 0 consumersTests that may break:
🔥 Hotspots · 22 volatile files
📦 Modules · 3 at risk
📊 Complexity · 12 violations
💡 Quick wins · 10 suggestions
📚 Stale docs · 202 broken references
Generated by CKB · Run details |
🔐 Security Audit Results❌ Security gate FAILED - 4 HIGH severity gosec finding(s)
🛡️ SAST AnalysisFound 28 issue(s) across 1 scanner(s) DetailsGosec (28 findings)
📦 Dependency VulnerabilitiesFound 21 vulnerability(ies) across 2 scanner(s) DetailsTrivy (14 findings)
OSV-Scanner (7 findings)
📜 License IssuesFound 142 non-permissive license(s) Details
Generated by CKB Security Audit | View Details | Security Tab |
CKB Review: 🟡 WARN — 42/10046 files (+2454 changes) · 7 modules ·
Top Risks
Findings (17 actionable, 24 informational)
... and 7 more Code Health — 3 degradedDegraded:
^1 File could not be parsed by tree-sitter New files: 3 (avg health: 86) 3 degraded · 0 improved · avg -1.4 Estimated review: not feasible as a single PR (46 files, 2454 lines) Reviewers: lisa.welsch1985 (22%) · talantyyr (9%) · lisa (4%) |
Fixes the output of prepareChange/analyzeImpact, getCallGraph and searchSymbols wherever it showed wrong or unusable evidence.
SCIP IDs
SearchSymbolspath.Impact / prepareChange
methodinstead offunction.directDependentsresolves the enclosing symbol instead of returning"unknown". A raw SCIP ID no longer shows up as the name.Search / callgraph
enumcounts as type-like in the tie-break.Compatibility-relevant (in the CHANGELOG): unresolved
directDependents[].name/.symbolIdnow serialize as""instead of"unknown". The new code from #245 doesn't check for that string (verified).Rebased onto develop after #245. The only conflict was CHANGELOG
[Unreleased]; both sides are kept. Golden fixtures regenerated.go build,go vet, gofmt, golangci-lint (0 issues),sync-version --checkandgo test -race ./...pass. One extra commit rewords a doc comment inscip/ids.go: gofmt would have turned a doubled backtick into a typographic quote.🤖 Generated with Claude Code