DocsDemoGitHub
§4.3

Symbol identity

Every symbol is named by a SCIP-style structured descriptor. Identity is one human-readable string, and resolution is a string match rather than an opaque id lookup.

A descriptor is five parts —scheme manager package version descriptor-path — of which the first four are the package coordinate and the last is the structural path to the symbol inside it.

A descriptor from the seeded corpusscip-go gomod github.com/gaarutyunov/codiq v0.1.0 internal/graph/Store#Put(). └──┬───┘ └─┬─┘ └──────────────┬──────────────┘ └──┬──┘ └───────────┬─────────┘ scheme manager package version descriptor path ─────────────┬──────────────── ────────┬──────── supplied by the batch, per ecosystem emitted by the stanza, (go.mod, package.json, …) from the CST

The suffix grammar is SCIP's: # closes a type,() a method or function, . a term such as a field or a variable. So internal/graph/Store# is the type,internal/graph/Store#db. its field, andinternal/graph/Store#Put(). its method — three descriptors that sort next to each other and read without a lookup table.

Why the split matters

The whole point of the split is to keep extraction file-local. A stanza runs against one CST and knows nothing about the project it is in, so it can only honestly produce the structural suffix. The package coordinate is a property of the project, so a per-ecosystem manifest resolver readsgo.mod (then package.json, and so on) once per batch and maps each file path to its coordinate. The extractor stays dumb; the descriptor still comes out complete.

That coordinate is exactly what the four pkg_ columns onfile hold — see the core model.

Same-file versus cross-file

A reference whose target definition is in the same CST is resolved at extraction time and gets a references_local edge on the spot. A reference whose target is in another file cannot be resolved by a file-local extractor, so the row is written with the target's descriptorunresolved — the descriptor column is meaningful on both roles — and the link pass matches it later:

What the link pass does, in one linereference.descriptor == definition.descriptor

The "symbol index" that makes this fast is not a separate structure. It is the btree on occurrence.descriptor that the SDL declares, and nothing else.

Worked example, from the seed

cmd/codiq/main.go writes graph.Store{…} and then calls store.Put(…). Both are cross-file, so extraction emits two reference occurrences carrying the descriptors of definitions it has never seen:

-- cmd/codiq/main.go, role = reference, target in another file 'scip-go gomod github.com/gaarutyunov/codiq v0.1.0 internal/graph/Store#' 'scip-go gomod github.com/gaarutyunov/codiq v0.1.0 internal/graph/Store#Put().' -- internal/graph/store.go, role = definition — same strings 'scip-go gomod github.com/gaarutyunov/codiq v0.1.0 internal/graph/Store#' 'scip-go gomod github.com/gaarutyunov/codiq v0.1.0 internal/graph/Store#Put().'

The link pass joins those pairs and writes two resolves_toedges. Nothing about main.go's rows had to know thatstore.go exists, which is precisely what makes re-indexing one file independent of the other.

Because the coordinate is part of the identity, the same type name in two modules — or in two versions of one module — is two different descriptors. No extra scoping machinery is needed to keep them apart, and a corpus spanning several repositories resolves with the same string match.