Rule.matcher was lazily compiled and cached in matchPattern with no synchronisation. applyCoverageDomains matches files across goroutines against one shared []Rule (MatchFile takes &rules[i]), so concurrent first calls raced on r.matcher and on the half-published GitIgnore — go test -race flagged it at parser.go:35/36.
Parse now precompiles rule.matcher in its single goroutine; matchPattern is read-only (returns the cached matcher, or a throwaway compile for a Rule built outside Parse) and never writes the field, so the concurrent MatchFile hot path only reads. No lock is added — Rule is a value type copied by append, which would trip copylocks. Cost is negligible: a CODEOWNERS file is small and compiled once per file, not per source file.
parser_race_test.go drives 64 goroutines x MatchFile over a shared rule list; pre-fix it tripped the race detector, clean after.
Code-intelligence questions like "list TODOs older than 90 days assigned
to me", "what's the license of this file", and "who owns this path" had
no graph answer — agents fell back to grep. This commit lands the schema
scaffolding for a broader coverage push and ships three contained
Phase 1 domains end-to-end.
- graph: 17 new NodeKinds (param, closure, constant, enum_member,
generic_param, module, table, column, config_key, flag, event,
migration, fixture, todo, team, release, license) and 22 new EdgeKinds
(param_of, returns, typed_as, captures, spawns, sends/recvs, queries,
reads_col/writes_col, reads_config/writes_config, toggles_flag, emits,
generated_by, depends_on_module, owns, authored, covered_by, aliases,
composes, licensed_as). Structural ones default to ast_resolved
through DefaultOriginFor; the rest fall through to confidence-based
ranking. Most are empty placeholders today, ready for downstream
extractors.
- todos: comment-context scanner that emits per-line markers
(TODO/FIXME/HACK/XXX/NOTE) with assignee, due-date, ticket, and
truncated text. Restricted to lines opening with whitespace + a known
comment delimiter so string literals containing "TODO" don't
false-match. Covers C-family, shell/Python, SQL/Lua, and block
continuations.
- licenses: scans the first ten lines for SPDX-License-Identifier and
emits a shared license node per distinct expression, linked to each
file via EdgeLicensedAs. Expression-form (MIT OR Apache-2.0) is
preserved verbatim.
- codeowners: parses .github/CODEOWNERS / CODEOWNERS / docs/CODEOWNERS
using the existing go-gitignore matcher, applies last-match-wins per
file, and emits team or person nodes (classified by '/' presence)
with EdgeOwns. Loaded once per indexer via sync.Once.
- indexer: applyCoverageDomains is shared between the bulk IndexCtx
worker pool and the incremental indexFile path so both routes pick
up coverage extraction. Each domain is gated by an
IndexConfig.Coverage block with documented per-domain defaults —
cheap structural domains on, expensive ones (SQL, runtime
enrichment) off.
- analysis: edgeWeight extends to the new structural edges
(spawns/param_of/returns/typed_as/aliases/composes/depends_on_module)
so community detection sees them at appropriate weights, while
domain-hub edges (queries, owns, licensed_as, …) deliberately stay
at 0 to avoid pulling symbols toward per-domain hubs.
- tests: 17 unit tests across the three new packages covering marker
variants, comment-context exclusion, multi-line block continuation,
SPDX expression parsing, last-match CODEOWNERS semantics, owner
classification, and graph-artifact construction.