Skip to content

Commit e475d20

Browse files
fix(heritage): PR #142 review fixes (6 cycles) (#143)
* fix(heritage): address PR #142 review findings (cycle 1) Class superClass generics, type-alias resolve, incremental scope expansion, module-level symbol preference, complex extends fallback, recipe dedupe; heritage-resolver tests + new recipe goldens; doc/glossary updates. * fix(heritage): address review cycle 2 (expression bases, SQL dedupe) Skip resolve for (expression) heritage markers; align type-descendants homonym dedupe with ancestors via scope_local_id ordering; add scoped re-resolve test. * docs: close type-heritage-substrate plan (review cycle 3) Delete shipped plan per docs-governance; prune roadmap and agent-surface cross-refs; document (expression) heritage rows in recipe help. * fix(heritage): review cycle 4 (default import, re-export, SQL) Resolve default-import bases; expand incremental scope for re-export barrel importers; homonym dedupe on ancestor start symbols; align type kind filters; doc/changeset parity updates. * test(heritage): review cycle 5 (persist + incremental e2e) Add persistTypeHeritageResolution unit test and run-index incremental test proving scoped heritage re-resolve updates DB rows. * docs(recipes): note type kind filter on type-descendants (cycle 6)
1 parent a085ec6 commit e475d20

37 files changed

Lines changed: 1241 additions & 283 deletions
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@stainless-code/codemap": patch
3+
---
4+
5+
Fix type heritage resolve edge cases: default-import bases, re-export barrel incremental scope, homonym dedupe in ancestor walks, and `(expression)` complex extends handling.

.changeset/type-hierarchy-recipes.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,4 @@
22
"@stainless-code/codemap": patch
33
---
44

5-
Add `type-ancestors` and `type-descendants` query recipes for extends/implements hierarchy walks parsed from indexed symbol signatures.
5+
Add `type-ancestors` and `type-descendants` query recipes for extends/implements hierarchy walks (backed by the `type_heritage` substrate after #142).

docs/architecture.md

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -151,7 +151,7 @@ A local SQLite database (`.codemap/index.db`) indexes the project tree and store
151151

152152
**Watch wiring:** **`src/cli/cmd-watch.ts`** (argv — `--debounce <ms>` / `--quiet`; bootstrap absorbs `--root`/`--config`) + **`src/application/watcher.ts`** (engine — pure debouncer + glob filter + injectable backend; production wires [chokidar v5](https://github.com/paulmillr/chokidar) selected via the 6-watcher audit in PR #46 — pure JS, runs identically on Bun + Node, ~30M repos use it). On every change/add/unlink event chokidar emits, the engine filters via `shouldIndexPath` (same indexed extensions as the indexer + project-local recipes; skips `node_modules` / `.git` / `dist`), debounces with a sliding window (default 250 ms), then calls `createReindexOnChange` which opens a DB, runs `runCodemapIndex({mode: 'files', files: [...changed]})`, closes the DB, and logs `reindex N file(s) in Mms` to stderr unless `--quiet`. SIGINT / SIGTERM drains pending edits via `flushNow()` before the watcher closes. **Default-ON for `mcp` / `serve` since 2026-05:** both transports boot the watcher in-process so every tool reads a live index — eliminates the per-request reindex prelude. Opt out with `--no-watch`, `CODEMAP_WATCH=0`, or `CODEMAP_NO_WATCH=1`. **`src/application/watch-policy.ts`** disables the watcher on WSL2 Windows drive mounts (`/mnt/*`) unless `CODEMAP_FORCE_WATCH=1`; stderr points at `codemap agents init --git-hooks` for git-triggered freshness. Standalone `codemap watch` runs the watcher decoupled from a transport for users wiring it next to a separate MCP / HTTP process. **Audit prelude optimization:** module-level `watchActive` flag; `handleAudit` skips its incremental-index prelude when active (and marks the close as readonly to avoid a wasted checkpoint). Explicit `no_index: false` still forces the prelude.
153153

154-
**Performance wiring:** **`--performance`** plumbs through **`RunIndexOptions.performance`****`indexFiles({ performance, collectMs })`**. `parse-worker-core.ts` records per-file **`parseMs`** on each `ParsedFile`; main thread times the seven phases (`collect`, `parse`, `insert`, `index_create`, `bindings`, `module_cycles`, `re_export_chains`) and assembles **`IndexPerformanceReport`** under `IndexRunStats.performance`. Note: `total_ms` is `indexFiles` wall-clock (parse + insert + DDL + bindings + cycles + re_exports), **not** end-to-end run wall — `collect_ms` happens before `indexFiles` and is reported separately. Env var **`CODEMAP_PERFORMANCE_JSON=<path>`** dumps the report as JSON post-run (consumed by [`bun run check:perf-baseline`](./benchmark.md#perf-baseline-regression-guardrail) for CI regression-gating).
154+
**Performance wiring:** **`--performance`** plumbs through **`RunIndexOptions.performance`****`indexFiles({ performance, collectMs })`**. `parse-worker-core.ts` records per-file **`parseMs`** on each `ParsedFile`; main thread times the eight phases (`collect`, `parse`, `insert`, `index_create`, `bindings`, `module_cycles`, `re_export_chains`, `heritage`) and assembles **`IndexPerformanceReport`** under `IndexRunStats.performance`. Note: `total_ms` is `indexFiles` wall-clock (parse + insert + DDL + bindings + cycles + re_exports + heritage), **not** end-to-end run wall — `collect_ms` happens before `indexFiles` and is reported separately. Env var **`CODEMAP_PERFORMANCE_JSON=<path>`** dumps the report as JSON post-run (consumed by [`bun run check:perf-baseline`](./benchmark.md#perf-baseline-regression-guardrail) for CI regression-gating).
155155

156156
**Agent templates:** `codemap agents init` writes thin pointer files (~16-line SKILL + ~22-line rule) to consumer disk; full content is served live by `codemap skill` / `codemap rule` (CLI) and `codemap://skill` / `codemap://rule` (MCP / HTTP) from `templates/agent-content/<kind>/*.md`. Section files concatenate in lexical order; `*.gen.md` sections dispatch to renderers in `application/agent-content.ts` so recipe catalog + schema DDL auto-register. Pointer-version stamp (`<!-- codemap-pointer-version: N -->`) + once-per-process stderr nag (`maybeWarnStalePointers`) flag stale consumer templates; cure is `codemap agents init --force`. Full matrix: [agents.md](./agents.md).
157157

@@ -271,22 +271,22 @@ Edges are deduped per (caller_scope, callee, call vs constructor) per file: if `
271271

272272
### `type_heritage` — Class/interface extends and implements edges (`STRICT`)
273273

274-
| Column | Type | Description |
275-
| ------------------- | ---------- | -------------------------------------------------------------------------------------- |
276-
| id | INTEGER PK | Auto-increment row id |
277-
| child_file_path | TEXT FK | File defining the child type |
278-
| child_name | TEXT | Child class or interface name |
279-
| child_kind | TEXT | `class` or `interface` |
280-
| child_line_start | INTEGER | Child definition line |
281-
| relation | TEXT | `extends` or `implements` |
282-
| base_simple_name | TEXT | Unqualified base name used for graph walks |
283-
| base_qualified_name | TEXT | Qualified base when present (e.g. `pkg.Type`); nullable |
284-
| base_file_path | TEXT | Resolved definition file (null until resolve pass) |
285-
| base_symbol_id | INTEGER FK | Resolved `symbols.id` (null when unresolved) |
286-
| resolution_kind | TEXT | `same-file`, `imported`, `qualified-unresolved`, or `unresolved` |
287-
| type_args | TEXT | Comma-separated generic args when present (display only; walks use `base_simple_name`) |
288-
289-
Populated at parse time from oxc AST; `heritage-resolver` fills `base_file_path` / `base_symbol_id` after bindings on full rebuild (scoped on incremental). Powers `type-ancestors` and `type-descendants` recipes.
274+
| Column | Type | Description |
275+
| ------------------- | ---------- | ----------------------------------------------------------------------------------------------------------------------------------- |
276+
| id | INTEGER PK | Auto-increment row id |
277+
| child_file_path | TEXT FK | File defining the child type |
278+
| child_name | TEXT | Child class or interface name |
279+
| child_kind | TEXT | `class` or `interface` |
280+
| child_line_start | INTEGER | Child definition line |
281+
| relation | TEXT | `extends` or `implements` |
282+
| base_simple_name | TEXT | Unqualified base name used for graph walks |
283+
| base_qualified_name | TEXT | Qualified base when present (e.g. `pkg.Type`); `(expression)` marks non-simple extends/implements expressions excluded from resolve |
284+
| base_file_path | TEXT | Resolved definition file (null until resolve pass) |
285+
| base_symbol_id | INTEGER FK | Resolved `symbols.id` (null when unresolved) |
286+
| resolution_kind | TEXT | `same-file`, `imported`, `qualified-unresolved`, or `unresolved` |
287+
| type_args | TEXT | Comma-separated generic args when present (display only; walks use `base_simple_name`) |
288+
289+
Populated at parse time from oxc AST; `heritage-resolver` fills `base_file_path` / `base_symbol_id` after bindings on full rebuild. Incremental `--files` re-resolves rows in changed files plus importers and consumers pointing at changed base files. Powers `type-ancestors` and `type-descendants` recipes.
290290

291291
### `imports` — Import statements (`STRICT`)
292292

docs/benchmark.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -207,7 +207,7 @@ Independent of the consumer-facing scenarios above, the repo carries a **per-pha
207207

208208
### Mechanism
209209

210-
1. `bun src/index.ts --full --performance` populates [`IndexPerformanceReport`](../src/application/types.ts) with `collect_ms` / `parse_ms` / `insert_ms` / `index_create_ms` / `bindings_ms` / `module_cycles_ms` / `re_export_chains_ms` / `total_ms`.
210+
1. `bun src/index.ts --full --performance` populates [`IndexPerformanceReport`](../src/application/types.ts) with `collect_ms` / `parse_ms` / `insert_ms` / `index_create_ms` / `bindings_ms` / `module_cycles_ms` / `re_export_chains_ms` / `heritage_ms` / `total_ms`.
211211
2. Setting `CODEMAP_PERFORMANCE_JSON=<path>` dumps that report as JSON to `<path>` after the run (no CLI flag added; env-var only).
212212
3. [`scripts/check-perf-baseline.ts`](../scripts/check-perf-baseline.ts) (alias `bun run check:perf-baseline`) runs the indexer 3× on this repo, takes per-phase **medians**, and compares to `fixtures/benchmark/perf-baseline.json`.
213213
4. **Local / scheduled only** — run before perf-sensitive PRs; [`.github/workflows/perf-baseline.yml`](../.github/workflows/perf-baseline.yml) fires weekly + `workflow_dispatch` for drift visibility. **Not** on the PR CI path (6 min × 3 runs + bimodal GHA runners → flaky merge gate).

docs/glossary.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -309,7 +309,7 @@ TS shape for one row of the `imports` table.
309309

310310
### `IndexPerformanceReport`
311311

312-
TS shape emitted under `IndexRunStats.performance` when `--performance` is set. Seven per-phase timings (`collect_ms`, `parse_ms`, `insert_ms`, `index_create_ms`, `bindings_ms`, `module_cycles_ms`, `re_export_chains_ms`) + `total_ms` + top-10 slowest files. Note: `total_ms` is `indexFiles` wall-clock (parse + insert + DDL + bindings + cycles + re_exports) and excludes `collect_ms`; end-to-end run wall is `collect_ms + total_ms`. Setting `CODEMAP_PERFORMANCE_JSON=<path>` dumps the report as JSON post-run.
312+
TS shape emitted under `IndexRunStats.performance` when `--performance` is set. Eight per-phase timings (`collect_ms`, `parse_ms`, `insert_ms`, `index_create_ms`, `bindings_ms`, `module_cycles_ms`, `re_export_chains_ms`, `heritage_ms`) + `total_ms` + top-10 slowest files. Note: `total_ms` is `indexFiles` wall-clock (parse + insert + DDL + bindings + cycles + re_exports + heritage) and excludes `collect_ms`; end-to-end run wall is `collect_ms + total_ms`. Setting `CODEMAP_PERFORMANCE_JSON=<path>` dumps the report as JSON post-run.
313313

314314
### `IndexResult`
315315

@@ -582,6 +582,10 @@ The glob implementation used on both Bun and Node (since the `collectFiles` refa
582582

583583
A small end-to-end vertical slice (see [`.cursor/rules/tracer-bullets.mdc`](../.cursor/rules/tracer-bullets.mdc)). Used in PRs to validate the critical path before expanding.
584584

585+
### `type_heritage` (table)
586+
587+
One row per `extends` / `implements` edge on a class or interface. Populated at parse from oxc AST; `heritage-resolver` (pass 2, after bindings) fills `base_file_path` / `base_symbol_id` and sets `resolution_kind` (`same-file`, `imported`, `qualified-unresolved`, `unresolved`). Non-simple expression bases use `base_qualified_name = '(expression)'` and stay out of recipe walks. Incremental `--files` re-resolves rows in changed files plus importers and consumers pointing at changed base files (including one-hop type re-export barrels). Powers `type-ancestors` and `type-descendants` recipes. **`file_path` param:** on `type-ancestors` it disambiguates the start symbol only; on `type-descendants` it also filters output to descendants in that file.
588+
585589
### `type_members` (table)
586590

587591
Properties and method signatures on interfaces and object-literal types. `symbol_name` references the parent `symbols.name`. `type` is null when the parser can't reconstruct the annotation. See `TypeMemberRow`.

docs/plans/agent-surface-and-ops.md

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -40,12 +40,11 @@ Details: [agents.md](../agents.md). Merge history: [agent-surface-delivery.md](.
4040

4141
## Related existing plans
4242

43-
| Plan | Relationship |
44-
| ------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------ |
45-
| [c9-plugin-layer](./c9-plugin-layer.md) | Prerequisite for [framework-route-extraction](./framework-route-extraction.md) |
46-
| [github-marketplace-action](./github-marketplace-action.md) | May add `affected` mode (shipped CLI/MCP `affected` + `affected-tests` recipe) |
47-
| [perf-triangulation-rollout](./perf-triangulation-rollout.md) | Parse-worker hardening shipped #130; Phase 3 deferrals remain in rollout plan |
48-
| [type-heritage-substrate](./type-heritage-substrate.md) | Lifts [#141](https://github.com/stainless-code/codemap/pull/141) recipe limits via `type_heritage` substrate |
43+
| Plan | Relationship |
44+
| ------------------------------------------------------------- | ------------------------------------------------------------------------------ |
45+
| [c9-plugin-layer](./c9-plugin-layer.md) | Prerequisite for [framework-route-extraction](./framework-route-extraction.md) |
46+
| [github-marketplace-action](./github-marketplace-action.md) | May add `affected` mode (shipped CLI/MCP `affected` + `affected-tests` recipe) |
47+
| [perf-triangulation-rollout](./perf-triangulation-rollout.md) | Parse-worker hardening shipped #130; Phase 3 deferrals remain in rollout plan |
4948

5049
---
5150

0 commit comments

Comments
 (0)