From 9077c4035b99f56cf4d87bb8fb20c52d984e854d Mon Sep 17 00:00:00 2001 From: Luke Zehrung Date: Mon, 3 Aug 2026 12:44:26 -0400 Subject: [PATCH 1/2] docs: consolidate active plans --- ...26-05-12-graph-first-language-expansion.md | 590 ------------------ .../2026-05-12-source-language-expansion.md | 74 +++ .../2026-05-27-agent-test-plan-generation.md | 188 ------ ...-06-performance-and-cache-opportunities.md | 460 +------------- .../2026-07-03-08-framework-route-nodes.md | 104 --- .../2026-07-03-09-mobile-bridge-edges.md | 87 --- .../2026-07-03-10-dispatch-synthesizers.md | 90 --- ...2026-07-03-11-source-language-expansion.md | 90 --- .../2026-07-03-12-affected-tests-command.md | 97 --- .../2026-07-03-16-config-extension-mapping.md | 93 --- docs/plans/2026-07-03-plan-priority-index.md | 29 +- .../2026-07-03-semantic-graph-synthesizers.md | 63 ++ ...2026-07-21-warm-run-discovery-avoidance.md | 290 +-------- ...6-08-03-performance-measurement-backlog.md | 54 ++ 14 files changed, 231 insertions(+), 2078 deletions(-) delete mode 100644 docs/plans/2026-05-12-graph-first-language-expansion.md create mode 100644 docs/plans/2026-05-12-source-language-expansion.md delete mode 100644 docs/plans/2026-05-27-agent-test-plan-generation.md delete mode 100644 docs/plans/2026-07-03-08-framework-route-nodes.md delete mode 100644 docs/plans/2026-07-03-09-mobile-bridge-edges.md delete mode 100644 docs/plans/2026-07-03-10-dispatch-synthesizers.md delete mode 100644 docs/plans/2026-07-03-11-source-language-expansion.md delete mode 100644 docs/plans/2026-07-03-12-affected-tests-command.md delete mode 100644 docs/plans/2026-07-03-16-config-extension-mapping.md create mode 100644 docs/plans/2026-07-03-semantic-graph-synthesizers.md create mode 100644 docs/plans/2026-08-03-performance-measurement-backlog.md diff --git a/docs/plans/2026-05-12-graph-first-language-expansion.md b/docs/plans/2026-05-12-graph-first-language-expansion.md deleted file mode 100644 index db487d5d..00000000 --- a/docs/plans/2026-05-12-graph-first-language-expansion.md +++ /dev/null @@ -1,590 +0,0 @@ -# Graph-First Language Expansion Implementation Plan - -> **For:** Codegraph maintainers implementing Scala, Lua, PowerShell, Elixir, Objective-C, Julia, and Dart support -> **Goal:** Add useful graph/chunk/import coverage for seven source languages without claiming full semantic go-to/reference parity before it exists. - -## Context - -The repo has an established language-support workflow: define support surface, add a language definition, wire native grammars and reduced-mode behavior, add fixtures/tests, then update parity/scenario docs and the agent skill surface. Follow [docs/adding-language-support.md](../adding-language-support.md) exactly. - -This plan intentionally targets graph-first support. Each language should provide parsing, chunking, top-level symbol extraction, and static dependency edges. It should not claim full cross-file semantic navigation until shared `goto`, `references`, and native semantic parity tests prove that behavior. - -Graph-first source-language support still participates in the normal code dependency graph for explicit imports/includes from that language. That is different from SQL artifact support, where SQL object candidates must stay isolated unless a separate bridge rule proves the SQL fact is relevant to code review. Do not use this language-expansion plan as precedent for globally linking artifact symbols into source-language dependency resolution. - -## Target Languages - -| Language | Extensions | npm grammar | Rust grammar | -| ----------- | ------------------------ | -------------------------------------------------------------------------------- | --------------------------------------------------------------------------- | -| Scala | `.scala`, `.sc` | [`tree-sitter-scala`](https://www.npmjs.com/package/tree-sitter-scala) | [`tree-sitter-scala`](https://crates.io/crates/tree-sitter-scala) | -| Lua | `.lua` | [`tree-sitter-lua`](https://www.npmjs.com/package/tree-sitter-lua) | [`tree-sitter-lua`](https://crates.io/crates/tree-sitter-lua) | -| PowerShell | `.ps1`, `.psm1`, `.psd1` | [`tree-sitter-powershell`](https://www.npmjs.com/package/tree-sitter-powershell) | [`tree-sitter-powershell`](https://crates.io/crates/tree-sitter-powershell) | -| Elixir | `.ex`, `.exs` | [`tree-sitter-elixir`](https://www.npmjs.com/package/tree-sitter-elixir) | [`tree-sitter-elixir`](https://crates.io/crates/tree-sitter-elixir) | -| Objective-C | `.m` | [`tree-sitter-objc`](https://www.npmjs.com/package/tree-sitter-objc) | [`tree-sitter-objc`](https://crates.io/crates/tree-sitter-objc) | -| Julia | `.jl` | [`tree-sitter-julia`](https://www.npmjs.com/package/tree-sitter-julia) | [`tree-sitter-julia`](https://crates.io/crates/tree-sitter-julia) | -| Dart | `.dart` | [`tree-sitter-dart`](https://www.npmjs.com/package/tree-sitter-dart) | [`tree-sitter-dart`](https://crates.io/crates/tree-sitter-dart) | - -Deliberately defer Objective-C `.h` and `.mm` until header and Objective-C++ ownership can be resolved without breaking existing C/C++ `.h` heuristics. - -## Agentic Coding Value - -Graph-first support is valuable for agents even before full semantic navigation exists. It lets the standard Codegraph workflows answer first-pass questions in more polyglot repos: - -- orient a repo and identify language-owned areas -- include static dependencies in `graph`, `inspect`, `impact`, and `review` -- chunk unfamiliar source files for bounded model context -- detect hotspots, unresolved imports, and duplicate code units where supported - -The product boundary is important: graph-first languages may participate in dependency and chunking workflows, but docs and tests must continue to say when `goto` and `refs` are unsupported. - -## Support Contract - -For each language, v1 support should provide: - -- File discovery for listed extensions. -- Tree-sitter parsing through the native runtime when the Rust grammar exposes a compatible API. -- Reduced-mode graph and regex recovery that stays safe when native is unavailable. -- Chunking for top-level declarations and important nested declarations. -- Definition extraction for top-level names. -- Static import/include/dependency extraction. -- File-level and chunk-level graph impact. - -For each language, v1 support should not claim: - -- Cross-file go-to definition. -- Cross-file references. -- Type-aware resolution. -- Build-system-aware package resolution. - -Docs should mark these languages as graph-first source languages with "No" or "Partial" cells for source-navigation parity until the shared semantic suites prove more. - -Unlike SQL artifact nodes, these source-language nodes may appear in dependency graph output when the language extractor emits explicit import/include/module relationships. Keep that distinction visible in docs if both plans are implemented near each other. - -## Shared Implementation Shape - -Add one definition file per language: - -- `src/languages/definitions/scala.ts` -- `src/languages/definitions/lua.ts` -- `src/languages/definitions/powershell.ts` -- `src/languages/definitions/elixir.ts` -- `src/languages/definitions/objectiveC.ts` -- `src/languages/definitions/julia.ts` -- `src/languages/definitions/dart.ts` - -Register them in: - -- `src/languages/all.ts` -- `src/languages.ts` -- `src/util/projectFiles.ts` if discovery is not fully driven by definitions -- `packages/codegraph-native/Cargo.toml` -- `packages/codegraph-native/src/languages.rs` - -Add tests and fixtures: - -- `tests/languages/scala.test.ts` -- `tests/languages/lua.test.ts` -- `tests/languages/powershell.test.ts` -- `tests/languages/elixir.test.ts` -- `tests/languages/objective-c.test.ts` -- `tests/languages/julia.test.ts` -- `tests/languages/dart.test.ts` -- `tests/samples/scala/*` -- `tests/samples/lua/*` -- `tests/samples/powershell/*` -- `tests/samples/elixir/*` -- `tests/samples/objective-c/*` -- `tests/samples/julia/*` -- `tests/samples/dart/*` - -Add shared guard tests: - -- `tests/project-file-discovery.test.ts` -- `tests/native-tree-sitter.test.ts` -- `tests/native-parser-ownership.test.ts` -- `tests/native-semantic-parity.test.ts` -- `tests/goto.test.ts` -- `tests/references.test.ts` - -The semantic parity, go-to, and references tests should explicitly preserve honest unsupported behavior for these graph-first languages. - -## Language-Specific Extraction Targets - -### Scala - -Extract: - -- `package` declarations. -- `import` selectors. -- `class`, `case class`, `object`, `trait`, `enum`, `def`, and top-level `val`/`var`. -- Edges from imports to package/module strings. - -Fixtures: - -- Package plus imports. -- Companion object and class. -- Trait implemented by class. -- Scala script `.sc`. - -### Lua - -Extract: - -- `require` calls with literal module names. -- `function name(...)`, `local function name(...)`, table method definitions, and returned module tables. -- Top-level assignment exports such as `M.foo = function(...)`. - -Fixtures: - -- CommonJS-like module table. -- Nested table method. -- Local require alias. - -### PowerShell - -Extract: - -- `Import-Module`, `using module`, and dot-sourced script paths. -- `function` declarations. -- `class` declarations. -- exported functions from simple `Export-ModuleMember` calls. -- `.psd1` module manifest dependencies when parseable. - -Fixtures: - -- Script file `.ps1`. -- Module file `.psm1`. -- Manifest `.psd1` with required modules. -- Dot-sourced helper file. - -### Elixir - -Extract: - -- `defmodule`. -- `alias`, `import`, `require`, and `use`. -- `def`, `defp`, `defmacro`. -- Nested modules. - -Fixtures: - -- Module with aliases and imports. -- `use GenServer`. -- Nested module. -- `.exs` script. - -### Objective-C - -Extract: - -- `#import` and `#include`. -- `@interface`, `@implementation`, `@protocol`, `@class`. -- Method declarations and implementations. -- Category names such as `@interface Foo (Bar)`. - -Fixtures: - -- `.m` implementation with framework import. -- Interface and implementation in one file. -- Protocol and category. - -Do not claim `.h` support in v1 because `.h` is already shared with C/C++ detection. - -### Julia - -Extract: - -- `module`. -- `using` and `import`. -- `function`, compact assignment functions, `struct`, `mutable struct`, `abstract type`, and `macro`. -- `include("file.jl")` dependencies. - -Fixtures: - -- Module with `using`. -- Include graph. -- Struct and function. -- Macro. - -### Dart - -Extract: - -- `import`, `export`, and `part`/`part of`. -- `library` declarations. -- `class`, `mixin`, `extension`, `enum`, `typedef`, and top-level functions. - -Fixtures: - -- Library with imports. -- Part file. -- Class with mixin. -- Barrel export file. - -## Implementation Steps - -### Task 1: Document graph-first support tier - -Files: - -- `docs/language-parity.md` -- `docs/scenario-catalog.md` -- `README.md` -- `codegraph-skill/codegraph/SKILL.md` - -Changes: - -- Add a graph-first source-language support tier if the existing docs do not already name it. -- Add planned rows for the seven languages with honest v1 claims. -- Add scenario catalog entries for import graph, chunking, native parser smoke, and unsupported semantic navigation. -- Distinguish graph-first source languages from isolated artifact languages such as SQL. - -Verification: - -- Review rendered markdown. -- Confirm README table of contents remains accurate if sections change. - -Commit: - -```bash -git add docs/language-parity.md docs/scenario-catalog.md README.md codegraph-skill/codegraph/SKILL.md -git commit -m "docs: define graph-first language tier" -``` - -### Task 2: Add grammar dependencies and native IDs - -Files: - -- `packages/codegraph-native/Cargo.toml` -- `packages/codegraph-native/src/languages.rs` -- `tests/native-tree-sitter.test.ts` -- `tests/native-parser-ownership.test.ts` - -Changes: - -- Add Rust grammar dependencies for all seven languages. -- Keep reduced-mode behavior safe without adding a JavaScript grammar fallback. -- Register native IDs using stable lowercase language ids: - - `scala` - - `lua` - - `powershell` - - `elixir` - - `objective-c` - - `julia` - - `dart` -- Add parser load and ownership tests. -- If a Rust grammar uses a nonstandard API, adapt that one language explicitly and document the reason in code. - -Commands: - -```bash -npm install -cargo test --manifest-path packages/codegraph-native/Cargo.toml -npx vitest run tests/native-tree-sitter.test.ts tests/native-parser-ownership.test.ts -``` - -Commit: - -```bash -git add packages/codegraph-native/Cargo.toml packages/codegraph-native/src/languages.rs package-lock.json tests/native-tree-sitter.test.ts tests/native-parser-ownership.test.ts -git commit -m "feat: add graph-first language parsers" -``` - -### Task 3: Add Scala graph-first support - -Files: - -- `src/languages/definitions/scala.ts` -- `src/languages/all.ts` -- `src/languages.ts` -- `tests/languages/scala.test.ts` -- `tests/samples/scala/*` -- `tests/project-file-discovery.test.ts` - -Changes: - -- Add `.scala` and `.sc` support. -- Extract packages, imports, classes, case classes, objects, traits, enums, defs, and top-level vals/vars. -- Add tests for chunks, symbols, imports, and discovery. - -Command: - -```bash -npx vitest run tests/languages/scala.test.ts tests/project-file-discovery.test.ts -``` - -Commit: - -```bash -git add src/languages tests/languages/scala.test.ts tests/samples/scala tests/project-file-discovery.test.ts -git commit -m "feat: add Scala graph support" -``` - -### Task 4: Add Lua graph-first support - -Files: - -- `src/languages/definitions/lua.ts` -- `src/languages/all.ts` -- `src/languages.ts` -- `tests/languages/lua.test.ts` -- `tests/samples/lua/*` -- `tests/project-file-discovery.test.ts` - -Changes: - -- Add `.lua` support. -- Extract literal `require` dependencies, functions, local functions, table methods, and module-table exports. -- Add tests for chunks, symbols, requires, and discovery. - -Command: - -```bash -npx vitest run tests/languages/lua.test.ts tests/project-file-discovery.test.ts -``` - -Commit: - -```bash -git add src/languages tests/languages/lua.test.ts tests/samples/lua tests/project-file-discovery.test.ts -git commit -m "feat: add Lua graph support" -``` - -### Task 5: Add PowerShell graph-first support - -Files: - -- `src/languages/definitions/powershell.ts` -- `src/languages/all.ts` -- `src/languages.ts` -- `tests/languages/powershell.test.ts` -- `tests/samples/powershell/*` -- `tests/project-file-discovery.test.ts` - -Changes: - -- Add `.ps1`, `.psm1`, and `.psd1` support. -- Extract imports, dot-sourced script dependencies, functions, classes, and simple module exports. -- Add tests for script, module, manifest, and discovery fixtures. - -Command: - -```bash -npx vitest run tests/languages/powershell.test.ts tests/project-file-discovery.test.ts -``` - -Commit: - -```bash -git add src/languages tests/languages/powershell.test.ts tests/samples/powershell tests/project-file-discovery.test.ts -git commit -m "feat: add PowerShell graph support" -``` - -### Task 6: Add Elixir graph-first support - -Files: - -- `src/languages/definitions/elixir.ts` -- `src/languages/all.ts` -- `src/languages.ts` -- `tests/languages/elixir.test.ts` -- `tests/samples/elixir/*` -- `tests/project-file-discovery.test.ts` - -Changes: - -- Add `.ex` and `.exs` support. -- Extract modules, aliases, imports, requires, uses, functions, private functions, macros, and nested modules. -- Add tests for module graph, nested declarations, scripts, and discovery. - -Command: - -```bash -npx vitest run tests/languages/elixir.test.ts tests/project-file-discovery.test.ts -``` - -Commit: - -```bash -git add src/languages tests/languages/elixir.test.ts tests/samples/elixir tests/project-file-discovery.test.ts -git commit -m "feat: add Elixir graph support" -``` - -### Task 7: Add Objective-C graph-first support - -Files: - -- `src/languages/definitions/objectiveC.ts` -- `src/languages/all.ts` -- `src/languages.ts` -- `tests/languages/objective-c.test.ts` -- `tests/samples/objective-c/*` -- `tests/project-file-discovery.test.ts` - -Changes: - -- Add `.m` support only. -- Extract imports, includes, interfaces, implementations, protocols, categories, and methods. -- Add tests that `.m` is discovered and `.h` behavior remains governed by the existing C/C++ heuristic. - -Command: - -```bash -npx vitest run tests/languages/objective-c.test.ts tests/project-file-discovery.test.ts -``` - -Commit: - -```bash -git add src/languages tests/languages/objective-c.test.ts tests/samples/objective-c tests/project-file-discovery.test.ts -git commit -m "feat: add Objective-C graph support" -``` - -### Task 8: Add Julia graph-first support - -Files: - -- `src/languages/definitions/julia.ts` -- `src/languages/all.ts` -- `src/languages.ts` -- `tests/languages/julia.test.ts` -- `tests/samples/julia/*` -- `tests/project-file-discovery.test.ts` - -Changes: - -- Add `.jl` support. -- Extract modules, using/import dependencies, includes, functions, compact functions, structs, abstract types, and macros. -- Add tests for dependency graph, chunks, symbols, and discovery. - -Command: - -```bash -npx vitest run tests/languages/julia.test.ts tests/project-file-discovery.test.ts -``` - -Commit: - -```bash -git add src/languages tests/languages/julia.test.ts tests/samples/julia tests/project-file-discovery.test.ts -git commit -m "feat: add Julia graph support" -``` - -### Task 9: Add Dart graph-first support - -Files: - -- `src/languages/definitions/dart.ts` -- `src/languages/all.ts` -- `src/languages.ts` -- `tests/languages/dart.test.ts` -- `tests/samples/dart/*` -- `tests/project-file-discovery.test.ts` - -Changes: - -- Add `.dart` support. -- Extract library declarations, imports, exports, parts, classes, mixins, extensions, enums, typedefs, and top-level functions. -- Add tests for part files, exports, chunks, symbols, and discovery. - -Command: - -```bash -npx vitest run tests/languages/dart.test.ts tests/project-file-discovery.test.ts -``` - -Commit: - -```bash -git add src/languages tests/languages/dart.test.ts tests/samples/dart tests/project-file-discovery.test.ts -git commit -m "feat: add Dart graph support" -``` - -### Task 10: Add shared semantic boundary tests - -Files: - -- `tests/goto.test.ts` -- `tests/references.test.ts` -- `tests/native-semantic-parity.test.ts` -- `docs/language-parity.md` -- `docs/scenario-catalog.md` - -Changes: - -- Add negative or boundary tests proving graph-first languages do not falsely report full semantic navigation. -- If a language accidentally resolves something through a generic fallback, document and test the exact supported behavior. -- Finalize docs with the actual implemented support, not the planned support. - -Command: - -```bash -npx vitest run tests/goto.test.ts tests/references.test.ts tests/native-semantic-parity.test.ts -``` - -Commit: - -```bash -git add tests/goto.test.ts tests/references.test.ts tests/native-semantic-parity.test.ts docs/language-parity.md docs/scenario-catalog.md -git commit -m "test: lock graph-first navigation boundaries" -``` - -### Task 11: Full verification and docs sweep - -Files: - -- `README.md` -- `docs/language-parity.md` -- `docs/scenario-catalog.md` -- `docs/how-it-works.md` -- `codegraph-skill/codegraph/SKILL.md` - -Changes: - -- Ensure every new language appears consistently in docs, scenarios, skill instructions, and tests. -- Verify docs do not claim cross-file go-to/reference support. -- Verify all public supported-language tables match the implemented extension set. - -Commands: - -```bash -npm run build -npm run test:ci -npm run test:native -``` - -Commit: - -```bash -git add README.md docs/language-parity.md docs/scenario-catalog.md docs/how-it-works.md codegraph-skill/codegraph/SKILL.md -git commit -m "docs: finalize graph-first language support" -``` - -## Acceptance Criteria - -- All seven languages parse through native runtime, unless a documented grammar compatibility blocker is found and reflected in parity docs. -- All seven languages retain safe reduced-mode behavior when native is unavailable. -- File discovery includes the planned extensions. -- Each language has a focused `tests/languages/*.test.ts` suite and fixtures. -- Each language extracts top-level declarations and static dependency edges listed in this plan. -- Go-to and references tests preserve honest unsupported behavior. -- Docs, scenario catalog, README, and agent skill instructions all describe the same support surface. - -## Risks - -- Grammar node names may differ substantially from assumptions. Mitigation: start each language with a fixture-driven AST inspection and keep extraction tied to observed node kinds. -- Objective-C extension ownership can conflict with C/C++ headers. Mitigation: support `.m` first and defer `.h`/`.mm`. -- PowerShell `.psd1` manifests are data files, not ordinary script files. Mitigation: parse simple manifests for dependencies only and mark complex cases unsupported. -- Graph-first support may be mistaken for full semantic navigation. Mitigation: parity docs and negative tests make the boundary explicit. - -## References - -- [Language support checklist](../adding-language-support.md) -- [Language parity matrix](../language-parity.md) -- [Scenario catalog](../scenario-catalog.md) -- [`tree-sitter-scala` on npm](https://www.npmjs.com/package/tree-sitter-scala) -- [`tree-sitter-lua` on npm](https://www.npmjs.com/package/tree-sitter-lua) -- [`tree-sitter-powershell` on npm](https://www.npmjs.com/package/tree-sitter-powershell) -- [`tree-sitter-elixir` on npm](https://www.npmjs.com/package/tree-sitter-elixir) -- [`tree-sitter-objc` on npm](https://www.npmjs.com/package/tree-sitter-objc) -- [`tree-sitter-julia` on npm](https://www.npmjs.com/package/tree-sitter-julia) -- [`tree-sitter-dart` on npm](https://www.npmjs.com/package/tree-sitter-dart) diff --git a/docs/plans/2026-05-12-source-language-expansion.md b/docs/plans/2026-05-12-source-language-expansion.md new file mode 100644 index 00000000..945f0bff --- /dev/null +++ b/docs/plans/2026-05-12-source-language-expansion.md @@ -0,0 +1,74 @@ +# Source language expansion + +Status: Planned. Add one language per pull request; do not ship a language pack. + +## Goal + +Extend Codegraph to a new source language through the existing language-support workflow without claiming semantic behavior that the shared suites do not prove. + +## Candidate backlog + +| Language | Extensions | Initial static dependency shapes | +| ----------- | ------------------------ | --------------------------------------------- | +| Lua | `.lua` | Literal `require(...)` | +| Scala | `.scala`, `.sc` | Package and import declarations | +| PowerShell | `.ps1`, `.psm1`, `.psd1` | Module imports and literal dot-sourcing | +| Elixir | `.ex`, `.exs` | `alias`, `import`, `require`, and `use` | +| Objective-C | `.m` | Imports and includes | +| Julia | `.jl` | `using`, `import`, and literal `include(...)` | +| Dart | `.dart` | Imports, exports, and parts | + +Lua is the default first candidate because it offers a compact vertical slice with common plugin and configuration use cases. Product evidence may select another candidate. + +Objective-C `.h` and `.mm` remain out of the initial slice until ownership can be resolved without breaking the existing C/C++ header heuristic. + +## Per-language contract + +The first pull request for a language must provide: + +- discovery for the documented extensions +- native parsing when a compatible, license-acceptable Rust grammar exists +- safe reduced-mode graph and regex recovery when native parsing is unavailable +- block-aware chunking for important declarations +- top-level symbol extraction +- conservative static dependency edges +- file and symbol participation in search, graph, impact, and review + +Cross-file `goto`, references, call hierarchy, type hierarchy, and implementation lookup are supported only where the existing shared semantic suites prove them. Partial or unsupported behavior must remain explicit in parity docs and negative tests. + +## Slice workflow + +Follow [the language support checklist](../adding-language-support.md) rather than duplicating its file-by-file instructions here: + +1. Inspect the grammar against representative fixtures and record exact node kinds. +2. Add the language definition, registry entry, discovery extensions, and native grammar identity. +3. Implement declarations, imports, and chunks from observed syntax only. +4. Add the nearest `tests/languages/*.test.ts` suite and representative fixtures. +5. Add shared coverage in `tests/goto.test.ts`, `tests/references.test.ts`, and `tests/native-semantic-parity.test.ts` for every claimed cross-file capability. +6. Update `docs/language-parity.md` and `docs/scenario-catalog.md`; update public language tables and the agent skill when their claims change. +7. Run the focused language and parity suites, `npm run test:native`, and `npm run check`. + +## Candidate-specific boundaries + +- Lua: accept literal module names; skip dynamic `require`, metatable inference, and runtime path execution. +- Scala: cover packages, classes, objects, traits, enums, defs, and top-level values before advanced implicit or type resolution. +- PowerShell: treat `.psd1` as a data-oriented manifest and extract only conservative literal dependencies. +- Elixir: cover modules and explicit import-like forms; do not infer macro expansion or runtime module construction. +- Objective-C: cover interfaces, implementations, protocols, categories, and methods in `.m`; defer header and Objective-C++ ownership. +- Julia: cover modules, declarations, and literal includes; skip dynamic evaluation and generated names. +- Dart: cover libraries, parts, classes, mixins, extensions, enums, typedefs, and top-level functions without build-system inference. + +## Acceptance + +- The new language appears in doctor and native supported-language output when native support is available. +- Discovery, parsing, chunks, declarations, and static dependency edges match the documented fixtures. +- Unsupported dynamic forms fail conservatively. +- Public claims match the shared semantic tests and language parity matrix. +- Existing supported-language behavior and extension ownership remain unchanged. + +## Non-goals + +- No multiple-language pull request. +- No arbitrary grammar loading from project config. +- No type-aware or build-system-aware resolution without a separate proven design. +- No promotion from graph-first support to semantic parity based on generic fallback behavior alone. diff --git a/docs/plans/2026-05-27-agent-test-plan-generation.md b/docs/plans/2026-05-27-agent-test-plan-generation.md deleted file mode 100644 index 28d5efc6..00000000 --- a/docs/plans/2026-05-27-agent-test-plan-generation.md +++ /dev/null @@ -1,188 +0,0 @@ -# Agent Test Plan Generation Implementation Plan - -> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. - -**Goal:** Turn candidate test files from impact and review into bounded, copyable test plans for agents. - -**Architecture:** Reuse existing candidate-test detection, coverage-aware suggestions, review bundles, and impact reports. Add a small command-template expansion layer and expose the resulting commands consistently in CLI JSON, review summaries, MCP, and packet outputs. - -**Tech Stack:** TypeScript, Vitest, existing impact/review candidate-test modules, CLI review and impact renderers, MCP handlers, agent packet/explain helpers. - ---- - -## Context - -Codegraph already identifies likely tests through impact and review workflows: - -```bash -codegraph impact --base main --head feature --lcov coverage/lcov.info --coverage-report coverage/coverage-final.json -codegraph impact --base main --head feature --coverage-report coverage/coverage-final.json --test-command-template "pnpm vitest {files}" -codegraph review --base HEAD --head WORKTREE --summary -``` - -Agents still have to translate candidate files into exact commands in many paths. This plan makes test execution guidance a first-class structured output without inventing new test discovery logic. - -Relevant files: - -- `src/impact/context.ts`: candidate test detection. -- `src/impact/report-suggestions.ts`: coverage-aware suggestions. -- `src/impact/types.ts`: impact report contracts. -- `src/review.ts`, `src/review/summaries.ts`: review bundle and summaries. -- `src/cli/impact.ts`, `src/cli/review.ts`: CLI presentation. -- `src/agent/explain.ts`, `src/agent/packet.ts`: packet follow-up context. -- `src/mcp/server.ts`, `src/mcp/tools.ts`: MCP review and impact handlers. -- `docs/cli.md`, `docs/library-api.md`, `docs/agent-workflows.md`, `codegraph-skill/codegraph/SKILL.md`: public docs and skill guidance. - -## Deliverable - -Add a shared test-plan output shape: - -```ts -export interface AgentTestPlan { - schemaVersion: 1; - commands: AgentTestCommand[]; - candidateTests: CandidateTestFile[]; - omittedCounts: { - commands: number; - candidateTests: number; - }; -} - -export interface AgentTestCommand { - command: string; - files: string[]; - confidence: "high" | "medium" | "low"; - reason: string; -} -``` - -Integrate it into: - -- `impact` JSON when candidate tests exist and a command template is available. -- `review` JSON and `review --summary`. -- `packet get ` and changed-context explain packets. -- MCP `impact` and `review` responses through the same structured fields. - -## Command Template Rules - -Start with the existing `--test-command-template` behavior and make it reusable. - -Rules: - -- `{files}` expands to shell-quoted test files joined by spaces. -- `{file}` expands only when a command contains exactly one file; reject or omit otherwise. -- Preserve candidate-test confidence in each command. -- Bound emitted commands; do not emit one command per low-confidence candidate in large repos. -- Do not infer a test runner when no template is configured. -- Do not execute tests. Codegraph only suggests commands. - -## Task 1: Extract Test Command Planning Helper - -**Files:** - -- Create: `src/impact/testPlan.ts` -- Modify: `src/impact/index.ts` -- Test: `tests/impact-test-plan.test.ts` - -- [ ] Add tests for `{files}` expansion, shell quoting, confidence grouping, omitted counts, empty candidates, and missing template. -- [ ] Extract the helper without changing current `impact --test-command-template` behavior. -- [ ] Run: - -```bash -npx vitest run tests/impact-test-plan.test.ts tests/impact-analyzer.test.ts -``` - -## Task 2: Add Impact JSON Test Plans - -**Files:** - -- Modify: `src/impact/types.ts` -- Modify: nearest impact report builder modules -- Modify: `src/cli/impact.ts` if presentation needs wiring -- Test: `tests/impact-cli.test.ts` - -- [ ] Add optional `testPlan` to full and compact impact outputs when a template and candidate tests are available. -- [ ] Keep `schemaVersion` and `format` stable. -- [ ] Ensure pretty output remains compact and only lists high/medium confidence commands. -- [ ] Run: - -```bash -npx vitest run tests/impact-cli.test.ts tests/impact-analyzer.test.ts -``` - -## Task 3: Add Review Summary Test Plans - -**Files:** - -- Modify: `src/review.ts` -- Modify: `src/review/summaries.ts` -- Modify: `src/cli/review.ts` -- Test: `tests/review.test.ts` - -- [ ] Add optional `testPlan` to review JSON. -- [ ] Add a short `Suggested test commands` section to `review --summary` when commands exist. -- [ ] Preserve existing candidate-test fields for compatibility. -- [ ] Run: - -```bash -npx vitest run tests/review.test.ts tests/cli-regressions.test.ts -``` - -## Task 4: Surface Test Plans in Agent Packets and MCP - -**Files:** - -- Modify: `src/agent/explain.ts` -- Modify: `src/agent/packet.ts` -- Modify: `src/mcp/server.ts` -- Test: `tests/agent-packet.test.ts` -- Test: `tests/mcp-server.test.ts` - -- [ ] Include test plans in review packets. -- [ ] Include changed-context test plans in explain packets when the caller supplies a review range or changed context. -- [ ] Ensure MCP `review` and `impact` return the same structured fields as library calls. -- [ ] Run: - -```bash -npx vitest run tests/agent-packet.test.ts tests/mcp-server.test.ts -``` - -## Task 5: Update Docs and Skill - -**Files:** - -- Modify: `docs/cli.md` -- Modify: `docs/library-api.md` -- Modify: `docs/agent-workflows.md` -- Modify: `codegraph-skill/codegraph/SKILL.md` -- Test: `tests/package-metadata.test.ts` - -- [ ] Document that Codegraph suggests test commands but does not execute them. -- [ ] Show a review workflow that uses `--test-command-template` and then runs selected commands externally. -- [ ] Update the skill guidance so agents prefer structured `testPlan` fields over parsing summary prose. -- [ ] Run: - -```bash -npx vitest run tests/package-metadata.test.ts -git diff --check -``` - -## Acceptance Criteria - -- Test command suggestions are deterministic and bounded. -- Missing command templates produce candidate tests without invented commands. -- Review, impact, MCP, and packet outputs preserve candidate-test confidence and reasons. -- CLI summaries remain short and omit low-confidence command spam. -- Existing candidate-test output remains backward compatible. -- No tests are executed by Codegraph. - -## Final Verification - -- [ ] Run: - -```bash -npm run lint -npm run build -npm run test:ci -git diff --check -``` diff --git a/docs/plans/2026-06-06-performance-and-cache-opportunities.md b/docs/plans/2026-06-06-performance-and-cache-opportunities.md index 9662d525..bd9eee8e 100644 --- a/docs/plans/2026-06-06-performance-and-cache-opportunities.md +++ b/docs/plans/2026-06-06-performance-and-cache-opportunities.md @@ -1,458 +1,38 @@ -# Performance and Cache Opportunities Plan +# Remaining performance cleanup candidates -This plan captures remaining high-impact opportunities from a broad repo audit focused on MCP startup, cache behavior, search, references, impact/review, and duplicate detection performance. It is self-contained so another agent can implement items without the original conversation. +Status: Needs decision. The original audit is complete enough to retire; merged work is preserved in Git history. -Follow-up: `2026-07-21-warm-run-discovery-avoidance.md` continues Priority 7/8 below with a deeper finding that full recursive directory discovery, not just graph reconstruction, still runs on most warm/unchanged commands. Read that plan before picking up Priority 7's remaining validation items. +Measurement-only follow-ups moved to [the performance measurement backlog](2026-08-03-performance-measurement-backlog.md). The candidates below are the only unimplemented ideas not already owned by the active native-startup plan. -Existing unrelated worktree context when this plan was written: +## Candidate-test reuse -- `src/cli/help.ts`, `tests/cli-command-modules.test.ts`, `src/review.ts`, and `tests/review.test.ts` had small fixes for CLI help and review `head` metadata. -- `package-lock.json` was modified by `npm install` to restore a missing optional Rolldown native dependency needed by Vitest. +Impact, review, coverage suggestions, and `affected` share test-file classification and candidate selection but still create some run-local matchers and candidate maps independently. -Use focused tests while implementing each item. Run `npm run check` before concluding major work. +Possible outcome: introduce one prepared per-index or per-run test-candidate context reused by these consumers. -## Observed Baseline +Decision risk: no current measurement shows this work is material, and `affected` already provides the direct test-selection workflow. Do not implement without a profile showing repeated classification or traversal dominates a representative impact or review run. -Commands run from repo root: +## Navigation lookup caches -- `node ./dist/cli.js doctor` -- `node ./dist/cli.js orient --root . --budget small --json` -- `node ./dist/cli.js hotspots ./src --limit 25 --json` -- `node ./dist/cli.js inspect ./src --limit 20` +Repeated `goto` and reference verification may revisit receiver, member, and local-scope lookups. -Observed facts: +Possible outcome: add bounded snapshot-owned lookup caches for proven repeated resolver operations. -- Native backend is available. -- `inspect ./src` saw 287 TypeScript source files, zero unresolved imports, and zero cycles. -- Hotspots included `src/indexer/build-index.ts`, `src/indexer/navigation.ts`, `src/agent/search.ts` dependencies, `src/native/treeSitterNative.ts`, and project-file utilities. -- Duplicate health reported many high-confidence duplicate opportunities in `src`; this makes duplicate detection and duplicate-context paths important performance targets. +Decision risk: cache identity and invalidation complexity can exceed the saved work. The reference-candidate index and persisted Bloom filters already removed broader scans; measure the remaining semantic verification path first. -## MCP Server and Cache Behavior Today +## Narrower detailed graph work in impact -Starting `mcp serve` does **not** refresh the on-disk cache today. +Impact still requests detailed graph context for relevant changed files while some internal graph construction remains project-wide. -Evidence: +Possible outcome: construct only the detailed graph sections required by the changed-file context while preserving every reported edge, risk, candidate test, and omission count. -- `serveCodegraphMcp()` only creates handlers/server and connects transports in `src/mcp/server.ts`. -- `createCodegraphMcpHandlers()` creates an `AgentSession`, but does not call `loadProject()`. -- `createAgentSession()` defers all index work until `loadProject()`. -- The first actual tool request calls `buildProjectIndexIncremental()` with `cache: "disk"` and `keepParsed: true`, which can refresh `.codegraph-cache/index-v1`. +Decision risk: a narrower graph can silently change review output. Require full-output parity and a profile proving detailed graph construction remains a dominant impact phase. -Implication: +## Decision -- Lazy startup is fast, but the first MCP request pays indexing and cache-refresh cost. -- Long-running MCP sessions can serve stale in-memory snapshots until manually invalidated or restarted. +Review these three candidates as a group: -## Priority 1: Avoid Eager Symbol Graph Construction in MCP +- Keep this plan only if at least one candidate has enough expected value to justify a measurement scenario. +- Otherwise delete it. The measurement backlog can create a new implementation plan later if evidence establishes a bottleneck. -Several MCP tools only need the base `ProjectIndex` or file graph, but currently can force detailed symbol graph construction. - -Why this matters: - -- This is likely the highest ROI small change for MCP first-query latency. -- `createAgentSession.loadProject({ symbolGraph: "skip" })` already exists and shares the same cached base snapshot with later eager loads. -- Later symbol-heavy tools can still build the detailed graph once when needed. - -Implementation checklist: - -- [x] In `src/agent/orient.ts`, load with `session.loadProject({ symbolGraph: "skip" })` unless orientation starts using `snapshot.symbolGraph`. -- [x] In `src/mcp/server.ts`, use skipped symbol graph loads for `deps`, `rdeps`, `path`, `goto`, and position-based `refs`. -- [x] Keep handle-based `refs`, `get_symbol`, `packet_get`, and hybrid/symbol search eager where explain/search needs symbol graph context. -- [x] Add tests proving these MCP calls do not invoke `buildSymbolGraphDetailed()`. -- [x] Preserve current eager behavior for tools that need symbol graph neighbors or symbol handles. - -Likely files: - -- `src/mcp/server.ts` -- `src/agent/orient.ts` -- `src/agent/session.ts` -- `tests/mcp-server.test.ts` -- `tests/agent-session.test.ts` - -Validation: - -- [x] `npx vitest run tests/mcp-server.test.ts tests/agent-session.test.ts` -- [x] `node ./dist/cli.js orient --root . --budget small --json` - -## Priority 2: Add Explicit MCP Warmup - -Add an opt-in warmup mode so users can refresh the disk cache before the first agent request. - -Why this matters: - -- Lazy startup is good for stdio, but HTTP and long-lived agent processes often prefer paying setup cost once. -- Warmup can refresh the on-disk incremental cache while reusing the same in-memory session that handlers will use. - -Implementation checklist: - -- [x] Add `warmup?: "off" | "base" | "symbols"` to `CodegraphMcpServerOptions`. -- [x] Add CLI flags in `src/cli/mcp.ts`, for example `--warmup` and `--warmup-symbols`. -- [x] Implement base warmup with `session.loadProject({ symbolGraph: "skip" })`. -- [x] Implement symbol warmup with the default eager `session.loadProject()`. -- [x] Reuse the handler session so a concurrent first request joins the same promise rather than building twice. -- [x] Decide default behavior explicitly: keep stdio lazy; for HTTP either keep lazy or start background base warmup after listen. -- [x] Document that warmup refreshes `.codegraph-cache/index-v1` through the incremental disk cache. - -Risks: - -- Foreground warmup delays server readiness. -- Background warmup can race the first request unless it shares the same `AgentSession` promise. - -Likely files: - -- `src/cli/mcp.ts` -- `src/mcp/server.ts` -- `src/agent/session.ts` -- `src/cli/help.ts` -- `docs/cli.md` -- `docs/mcp.md` -- `docs/agent-workflows.md` -- `codegraph-skill/codegraph/SKILL.md` -- `tests/mcp-server.test.ts` -- `tests/cli-command-modules.test.ts` - -Validation: - -- [x] `npx vitest run tests/mcp-server.test.ts tests/cli-command-modules.test.ts` -- [x] `node ./dist/cli.js mcp serve --help` - -## Priority 3: Add MCP Session Invalidation - -Long-running MCP servers need a way to refresh stale snapshots when files, config, or cache inputs change. - -Why this matters: - -- Disk cache invalidation is handled when a build runs, but MCP may not trigger a new build because `AgentSession` holds resolved snapshots. -- Current behavior can omit files created after the first load from later artifact/search results. - -Implementation checklist: - -- [x] Add explicit refresh before handlers that depend on indexed repo state when a fresh snapshot is needed. -- [x] Prefer conservative triggers: config hash, manifest timestamp/version, file-list fingerprint, or explicit user refresh. -- [x] Avoid full discovery on every request; debounce any file-system check. -- [x] Add a read-only MCP tool or request option such as `refresh_index` if automatic invalidation is too expensive or risky. -- [x] Call `session.invalidate()` before the next `loadProject()` when stale. -- [x] Keep `get_file` independent because it reads directly from disk. - -Likely files: - -- `src/agent/session.ts` -- `src/mcp/server.ts` -- `src/mcp/tools.ts` -- `src/indexer/build-cache/manifest.ts` -- `src/indexer/build-index.ts` -- `tests/mcp-server.test.ts` -- `tests/cache-invalidation.test.ts` - -Validation: - -- [x] Add a test that loads a session, creates `late.ts`, refreshes/invalidates, then verifies search or artifact output includes `late.ts`. -- [x] `npx vitest run tests/mcp-server.test.ts tests/cache-invalidation.test.ts` - -## Priority 4: Skip Detailed Symbol Graph for SQL-Only Search - -`mode: "sql"` can use SQL locals already present in the base index instead of building the detailed symbol graph. - -Why this matters: - -- `searchNeedsSymbolGraph()` currently returns eager for every mode except `path` and `text`. -- SQL object symbols are produced by SQL indexing into `ProjectIndex.byFile`; detailed graph construction mostly wraps them for search. -- SQL-only search should be closer to path/text search cost. - -Implementation checklist: - -- [x] Add a SQL-specific result path in `src/agent/search.ts` that iterates `.sql` module locals from `snapshot.index.byFile`. -- [x] Reuse existing token scoring and SQL handle formatting. -- [x] Change `searchNeedsSymbolGraph()` so `mode === "sql"` loads with `symbolGraph: "skip"`. -- [x] Keep hybrid behavior unchanged initially to avoid ranking churn. -- [x] Avoid symbol-neighbor work for SQL-only mode unless it can be sourced from the base file graph. - -Likely files: - -- `src/agent/search.ts` -- `src/sql/sourceGraph.ts` -- `src/graphs/symbol-graph.ts` -- `tests/agent-search.test.ts` -- `tests/agent-session.test.ts` - -Validation: - -- [x] Extend SQL search tests to assert SQL object results still appear. -- [x] Add a spy assertion that SQL-only search does not call `buildSymbolGraphDetailed()`. -- [x] `npx vitest run tests/agent-search.test.ts tests/agent-session.test.ts` - -## Priority 5: Reuse Reference Scans Across Impact and Review - -Impact and review paths can scan references for the same changed symbol more than once. - -Why this matters: - -- `attachCallCompatibilityHints()` calls `findReferences()` per changed callable. -- `analyzeDirectReferences()` then calls `findReferences()` again for direct impact. -- `summarizeChangedFiles()` repeats a similar pattern for review callsites. -- Reference scans are among the most expensive semantic operations on larger repos. - -Implementation checklist: - -- [x] Add a per-run reference cache keyed by symbol id plus options that affect output. -- [x] Include at least max reference limit, context mode, context line/block settings, and filters in the cache key. -- [x] Let `attachCallCompatibilityHints()` accept a cache or callback for reference lookup. -- [x] Let direct impact consume cached uncontextualized references when options match. -- [x] In review, reuse compatibility references for callsites when the requested limit is compatible; otherwise top up with a larger scan instead of starting from zero. -- [x] Keep contextual reference snippets separate unless the cached result includes the same context options. - -Likely files: - -- `src/impact/analyzer.ts` -- `src/impact/direct.ts` -- `src/impact/callCompatibility.ts` -- `src/review/summaries.ts` -- `tests/impact-analyzer.test.ts` -- `tests/review.test.ts` -- `tests/impact-call-compatibility/fallback-budget.test.ts` - -Validation: - -- [ ] Add tests with a spy/count around `findReferences()` for one changed callable. -- [x] `npx vitest run tests/impact-analyzer.test.ts tests/review.test.ts tests/impact-call-compatibility/fallback-budget.test.ts` - -## Priority 6: Native Duplicate Candidate Generation - -Move the duplicate-detection hot path into `packages/codegraph-native` when the payoff justifies native expansion. - -Why this matters: - -- `src/duplicates.ts` tokenizes source, normalizes tokens, builds shingles, stores token sets/signatures, buckets units, and scores candidate pairs in JavaScript. -- The audit observed very large duplicate candidate counts even for `src`-only scans. -- Rust can reduce allocations, avoid JS `Set` overhead, and parallelize pair generation more predictably. - -Implementation checklist: - -- [x] Define a native API that accepts source text and returns compact duplicate-token preprocessing results. -- [x] Start with native tokenization and normalization while keeping shingle/winnow fingerprints and candidate-pair generation in TypeScript. -- [x] Keep final reporting, grouping, and CLI JSON schema in TypeScript initially. -- [x] Preserve reduced-mode behavior when native is unavailable or disabled. -- [x] Add parity fixtures comparing native and reduced-mode duplicate results for exact, renamed, near, and low-confidence cases. -- [ ] Add a benchmark fixture with many repeated units and a performance threshold or regression report. - -Likely files: - -- `src/duplicates.ts` -- `src/native/treeSitterNative.ts` -- `packages/codegraph-native/src/*` -- `packages/codegraph-native/Cargo.toml` -- `tests/duplicates.test.ts` -- `tests/native-semantic-parity.test.ts` or a new native duplicate parity test - -Validation: - -- [x] `npx vitest run tests/duplicates.test.ts` -- [x] `npm run test:native` -- [ ] A targeted duplicate benchmark before and after the native path. - -## Priority 7: Persist a Ready-to-Load Project Index Snapshot - -Warm disk cache still reconstructs a `ProjectIndex` from per-file entries. A ready snapshot could make MCP first requests much faster. - -Why this matters: - -- On large repos, reconstructing maps, exports, import graph, and derived metadata can dominate warm start even when per-file parsing is cached. -- MCP and agent commands repeatedly need the same immutable project snapshot. - -Implementation checklist: - -- [x] Design a manifest-backed serialized project-index snapshot, probably SQLite or compact binary JSON. -- [x] Include all invalidation inputs: codegraph version, native backend version, config hash, discovery options, graph options, file list, file signatures, and language definitions version. -- [x] Load the snapshot before reconstructing from per-file cache entries. -- [x] Fall back to current incremental path on any version or manifest mismatch. -- [x] Keep schema migrations explicit if SQLite is used. -- [x] Measure warm start for `orient`, `search`, `refs`, and MCP first request. - -Likely files: - -- `src/indexer/build-index.ts` -- `src/indexer/build-cache/*` -- `src/sqlite/*` -- `src/agent/session.ts` -- `tests/cache-invalidation.test.ts` -- New snapshot-cache regression tests - -Validation: - -- [x] Old-cache migration or fallback test. -- [ ] Warm-cache parity test comparing current incremental output and snapshot output. -- [ ] `node ./dist/cli.js orient --root . --budget small --json` before/after timing. -- Note: these two remaining items and the discovery-scan gap they did not cover are tracked together in `2026-07-21-warm-run-discovery-avoidance.md`. - -## Priority 8: Stop Hashing Every File on Warm Git-Backed Cache Runs - -When the repo is clean and tracked, git object ids or index metadata can avoid rereading every file to verify cache entries. - -Why this matters: - -- Warm cache performance can still suffer from file reads/hashes before doing useful work. -- WSL and network filesystems make repeated stat/read operations expensive. - -Implementation checklist: - -- [x] Identify where file signatures are computed for disk cache entries. -- [x] Add a git-backed signature provider when the project root is inside a git worktree. -- [x] Use git object id for tracked clean files when safe. -- [x] Use content hashing for `--cache-strict`; use mtime/size metadata only in non-strict modes where `--cache-verify` and existing cache contracts allow it. -- [x] Keep `--cache-strict` and `--cache-verify` semantics intact. - -Likely files: - -- `src/indexer/build-index.ts` -- `src/indexer/build-cache/*` -- `src/drift/git.ts` or a new git metadata helper -- `tests/cache-invalidation.test.ts` - -Validation: - -- [ ] Tests for clean tracked file, modified tracked file, untracked file, and `--cache-strict`. -- [ ] Warm-cache timing on this repo. - -## Priority 9: Add a Reference Candidate Index - -Create a ProjectIndex-level reverse lookup for reference candidates to reduce broad scans. - -Why this matters: - -- `findReferences()` is used by user commands, MCP, impact, and review. -- Current verified reference scans often find candidates by walking AST/text and then validating via navigation. -- A precomputed candidate index can drastically reduce files/ranges to inspect. - -Implementation checklist: - -- [x] Build a ProjectIndex-level reverse import/export candidate index during project finalization. -- [x] Index import targets and re-exporting files so common reference queries avoid full project candidate-file scans. -- [x] Use the index as a candidate filter before expensive go-to verification. -- [x] Preserve current correctness by keeping verification for ambiguous candidates. -- [ ] Consider native/Rust extraction for occurrence vectors to avoid JS AST walking. - -Likely files: - -- `src/indexer/navigation.ts` -- `src/indexer/navigation-local.ts` -- `src/indexer/reference-context.ts` -- `src/indexer/build-index.ts` -- `packages/codegraph-native/src/*` -- `tests/references.test.ts` -- `tests/native-semantic-parity.test.ts` - -Validation: - -- [x] Existing references test suite. -- [ ] A benchmark for reference lookup across a large fixture. - -## Priority 10: Make Review Duplicate-Sibling Detection Target-First - -Review duplicate tasks should not need broad duplicate detection for every review. - -Why this matters: - -- Review only needs duplicates overlapping changed symbols or changed lines. -- Broad duplicate detection is valuable for the dedicated `duplicates` command, but too expensive as a review side effect. - -Implementation checklist: - -- [x] In review, collect duplicate targets from changed symbols and uncovered changed lines. -- [x] Build candidate buckets only around those targets. -- [x] Reuse existing `findDuplicateContexts()` behavior where possible, but ensure it does target-first work internally. -- [x] Keep exhaustive duplicate detection unchanged for `codegraph duplicates`. -- [x] Report omitted/partial metadata when target-first budgets truncate results. - -Likely files: - -- `src/review.ts` -- `src/duplicates.ts` -- `src/review/types.ts` -- `tests/review.test.ts` -- `tests/duplicates.test.ts` - -Validation: - -- [x] Review duplicate-sibling tests still pass. -- [x] Add a test proving unchanged duplicate-heavy files do not dominate review runtime or pair count. - -## Priority 11: Search Hot-Loop and Ranking Optimizations - -Repeated agent/MCP searches can avoid repeated file reads, normalization, and full-result sorts. - -Why this matters: - -- Agent search is an interactive path. -- Path/text searches already skip detailed symbol graph, but still benefit from cached normalized text and bounded top-K ranking. - -Implementation checklist: - -- [x] Add session-level caches for file text, normalized text, text chunks, and chunk boundaries. -- [x] Replace full-result sort with bounded top-K where output limit is small. -- [x] Make path-only search a file-list fast path that avoids index load entirely when possible. -- [ ] Move token scoring and text prefilter loops to native/Rust only after cache boundaries are stable. Deferred until search cache boundaries have production timing evidence. - -Likely files: - -- `src/agent/search.ts` -- `src/agent/session.ts` -- `src/chunking/*` -- `packages/codegraph-native/src/*` -- `tests/agent-search.test.ts` - -Validation: - -- [x] Existing agent search tests. -- [ ] Repeated MCP search timing before/after. - -## Priority 12: Smaller Performance Cleanups - -These are useful after the larger wins or when touching nearby code. - -Checklist: - -- [x] Persist SQL navigation lookup/facts on `ProjectIndex` instead of rebuilding per SQL goto/refs request. -- [x] Auto-enable native workers for large MCP/agent cold builds, with explicit opt-out. -- [ ] Precompute candidate-test indexes once per impact/review run. -- [ ] Cache receiver/member/local-scope lookup primitives used by `goToDefinition()`. -- [ ] Scope detailed symbol graph construction to changed-file context for impact where full graph context is unnecessary. -- [ ] Persist or reuse Bloom filters instead of rereading every cached source file. - -Status note: - -- Priority 12 remains a tracking bucket, not one atomic feature. The bounded cache and worker items are implemented; the remaining items need separate design because they affect impact/review output shape, navigation resolver internals, detailed symbol-graph semantics, or persistent cache schema. - -## Correctness Opportunities Still Worth Tracking - -These are not primarily performance work, but they remained confirmed high-value gaps from the same audit stream. - -Checklist: - -- [x] TypeScript enum declarations should be indexed as real symbols for goto/refs. -- [x] Anonymous JS/TS default exports should resolve through default imports. -- [x] JS/TS shorthand binding nodes should navigate to the actual binding/import. -- [x] Breaking-change suggestions should handle multiline exported signatures. -- [x] Publishing/install docs should clarify that reduced mode has graph-only and regex recovery, not parser recovery. -- [x] Consider stable subpath exports before narrowing the broad root API. - -## Suggested Execution Order - -- [ ] Start with Priority 1 because it is small, low-risk, and directly improves MCP latency. -- [ ] Add MCP warmup and invalidation next so long-running server behavior is explicit and correct. -- [ ] Optimize SQL-only search and reference reuse before native expansion; both are medium effort with clear tests. -- [ ] Tackle duplicate native acceleration only after budgets and JS behavior are well covered by parity tests. -- [ ] Add project-index snapshots after cache invalidation semantics are settled. - -## Validation Checklist - -Use the narrowest tests during iteration, then run broader gates before finalizing major implementation work. - -- [ ] `npx vitest run tests/mcp-server.test.ts tests/agent-session.test.ts` -- [ ] `npx vitest run tests/agent-search.test.ts` -- [ ] `npx vitest run tests/impact-analyzer.test.ts tests/review.test.ts tests/impact-call-compatibility/fallback-budget.test.ts` -- [ ] `npx vitest run tests/duplicates.test.ts` -- [ ] `npm run test:native` when touching `packages/codegraph-native` -- [ ] `node ./dist/cli.js doctor` -- [ ] `node ./dist/cli.js orient --root . --budget small --json` -- [ ] `node ./dist/cli.js inspect --root . ./src --limit 20 --json` -- [ ] `npm run check` before concluding major work +Do not use unchecked items from the retired audit as an implementation queue. diff --git a/docs/plans/2026-07-03-08-framework-route-nodes.md b/docs/plans/2026-07-03-08-framework-route-nodes.md deleted file mode 100644 index 32fc1dd4..00000000 --- a/docs/plans/2026-07-03-08-framework-route-nodes.md +++ /dev/null @@ -1,104 +0,0 @@ -# Framework route nodes - -## Goal - -Represent common web route declarations as graph nodes linked to handler symbols so Codegraph can answer route-to-handler and handler-to-route questions. - -## Initial scope - -Implement one vertical slice first: - -- Express-style JavaScript/TypeScript routes: - - `app.get("/x", handler)` - - `router.post("/x", handler)` - - middleware chains ending in handler -- FastAPI-style Python routes: - - `@app.get("/x")` - - `@router.post("/x")` - -Do not implement every framework in one PR. - -## Design - -### Data model - -Add route nodes to the symbol graph: - -```ts -type RouteNode = { - id: string; - kind: "route"; - file: string; - name: string; // GET /users/:id - method?: string; - pathPattern: string; - range: SourceRange; - metadata: { - framework: "express" | "fastapi"; - confidence: "high" | "medium"; - }; -}; -``` - -Edges: - -- route -> handler with label `references` -- handler -> route only if existing reverse traversal derives it from incoming edges; do not duplicate reverse edges unless the graph model requires it. - -## Extraction - -Add route extraction after normal symbol extraction, using parser-backed captures where possible. - -Express: - -- identify member calls where property is an HTTP method. -- first argument must be a string literal route path. -- handler is the last function-like argument or identifier argument. -- middleware identifiers can be recorded as additional references with metadata. - -FastAPI: - -- identify decorated function definitions. -- decorator call property/name is HTTP method. -- first argument string literal is route path. -- decorated function is handler. - -## Output integration - -Route nodes should appear in: - -- `search` when querying route paths or handler names. -- `packet_get` for handler symbols as incoming references. -- `refs` for handlers. -- `graph --symbols-detailed`. -- `impact` and `review` when handler changes. - -## Files likely touched - -- `src/graphs/symbol-graph.ts` -- `src/indexer/types.ts` -- language-specific extraction under `src/languages/definitions/typescript.ts`, `javascript.ts`, `python.ts` -- `src/agent/search.ts` -- `src/agent/packet.ts` -- `docs/language-parity.md` -- `docs/scenario-catalog.md` -- tests in `tests/languages/*.test.ts`, `tests/goto.test.ts`, `tests/references.test.ts` where applicable - -## Tests - -- Express route creates route node and handler reference edge. -- Express middleware chain links final handler and records middleware metadata. -- FastAPI decorator creates route node and handler reference edge. -- handler `refs` includes route declaration. -- `search "GET /users"` returns route node. -- unsupported dynamic route path is skipped or marked low confidence; do not fabricate. - -## Acceptance - -- Route extraction is conservative and provenance-tagged. -- Existing graph output remains backward-compatible or schema-versioned if changed. -- Docs clearly state initial framework coverage and limitations. - -## Review pass - -Checked scope: this plan starts with two high-value framework shapes and avoids broad heuristic claims. It integrates routes into existing symbol/reference surfaces instead of creating a separate route subsystem. diff --git a/docs/plans/2026-07-03-09-mobile-bridge-edges.md b/docs/plans/2026-07-03-09-mobile-bridge-edges.md deleted file mode 100644 index e7334bfb..00000000 --- a/docs/plans/2026-07-03-09-mobile-bridge-edges.md +++ /dev/null @@ -1,87 +0,0 @@ -# Mobile bridge edges - -## Goal - -Add conservative cross-language graph edges for mobile/native bridge boundaries so Codegraph can trace flows that cross source-language files through explicit bridge declarations. - -## Initial scope - -Do not implement every bridge at once. Start with one high-value, parser-visible bridge shape: - -- Swift `@objc` exposed methods referenced from Objective-C message sends. - -Follow-up bridge families can be separate PRs: - -- React Native legacy modules -- React Native event emitters -- Expo modules -- Fabric/Paper view components - -## Design - -Introduce a bridge-synthesis pass after normal per-language symbol extraction and before final graph edge materialization. - -```ts -type SynthesizedEdge = { - from: string; - to: string; - label: "references" | "calls"; - provenance: "heuristic"; - synthesizedBy: string; - confidence: "high" | "medium" | "low"; - metadata?: Record; -}; -``` - -Edges must be tagged. Never make synthesized bridge edges indistinguishable from parser-direct edges. - -## Swift/ObjC vertical slice - -Extraction: - -- Index Swift methods with explicit `@objc` names. -- Index Swift methods with implicit ObjC selector candidates only when exposure is clear. -- Index Objective-C message sends and method declarations if Objective-C support exists in the same PR. If Objective-C is not yet supported, limit this PR to Swift-side metadata and tests that prove no false graph claims are emitted. - -Resolution: - -- Match explicit `@objc(name:)` first. -- Match class-qualified receivers when available. -- Skip ambiguous selector matches. -- Record `synthesizedBy: "swift-objc-bridge"`. - -## Non-goals - -- No dynamic runtime dispatch inference. -- No reflection/string selector inference. -- No broad React Native support in this PR. -- No low-confidence edges in default graph output unless explicitly requested. - -## Files likely touched - -- `src/indexer/types.ts` -- `src/graphs/symbol-graph.ts` -- `src/languages/definitions/swift.ts` -- new `src/graphs/synthesized-edges/mobileBridge.ts` -- `packages/codegraph-native/src/languages.rs` only if adding Objective-C grammar support -- `docs/language-parity.md` -- `docs/scenario-catalog.md` -- tests under `tests/languages/swift.test.ts` and new bridge-specific tests - -## Tests - -- explicit `@objc(foo:)` maps to matching selector. -- ambiguous selector candidates are skipped. -- synthesized edge has provenance and confidence metadata. -- graph consumers can distinguish synthesized edges. -- no bridge edges are emitted when only one side is present. - -## Acceptance - -- Bridge edges improve cross-file impact without hiding uncertainty. -- Every synthesized edge explains how it was created. -- Unsupported bridge families remain documented as non-goals. - -## Review pass - -Checked scope: this plan chooses one conservative bridge vertical slice and requires provenance on every synthetic edge. It avoids turning dynamic runtime behavior into unqualified graph facts. diff --git a/docs/plans/2026-07-03-10-dispatch-synthesizers.md b/docs/plans/2026-07-03-10-dispatch-synthesizers.md deleted file mode 100644 index d8988c70..00000000 --- a/docs/plans/2026-07-03-10-dispatch-synthesizers.md +++ /dev/null @@ -1,90 +0,0 @@ -# Dispatch synthesizers - -## Goal - -Model common explicit dispatch patterns that static import/call extraction misses, while keeping every inferred edge conservative and provenance-tagged. - -## Initial scope - -Start with one low-risk pattern already common in TypeScript projects: - -- Redux Toolkit Query endpoint declarations to generated hook/use-site references, or -- Redux thunk dispatch references. - -Pick one pattern for the PR. Do not add a generic heuristic engine that claims arbitrary dynamic dispatch. - -## Design - -Add a small synthesizer framework: - -```ts -type GraphSynthesizer = { - id: string; - languages: string[]; - collect(snapshot: ProjectIndex): SynthesizedEdge[]; -}; -``` - -Synthesizers run after symbol extraction and before graph finalization. They receive indexed symbols, imports, locals, and source snippets where already available. - -All edges emitted by synthesizers must include: - -- `provenance: "heuristic"` -- `synthesizedBy` -- `confidence` -- `reason` - -## Quality bar - -A synthesizer may emit an edge only when: - -- both endpoints are concrete symbols or files -- the pattern has a stable framework convention -- ambiguity is resolved or the edge is skipped -- tests cover negative cases - -Do not emit edges for string names unless the framework convention requires string keys and the key is locally declared. - -## Output integration - -Synthesized edges should participate in: - -- `path` -- `deps`/`rdeps` where file-level edges are affected -- `impact` -- `review` -- `packet_get` -- `explain` - -Pretty output should mark synthesized/heuristic edges where relevant. - -## Files likely touched - -- `src/graphs/symbol-graph.ts` -- `src/indexer/types.ts` -- new `src/graphs/synthesizers/index.ts` -- one concrete synthesizer file -- `src/agent/packet.ts` -- `src/impact/report*.ts` if provenance needs display -- `docs/language-parity.md` -- `docs/scenario-catalog.md` -- tests under new `tests/dispatch-synthesizers.test.ts` - -## Tests - -- positive fixture emits expected edge. -- renamed/ambiguous fixture emits no edge. -- generated edge has provenance metadata. -- path traversal can use synthesized edge. -- impact report includes synthesized dependency with clear reason. -- disabling synthesizers, if supported, removes the edge. - -## Acceptance - -- One concrete dispatch pattern is supported end to end. -- The framework is extensible without encouraging broad unproven heuristics. -- Every inferred edge remains auditable. - -## Review pass - -Checked scope: this plan keeps dynamic-dispatch support evidence-driven. It adds one proven synthesizer and a small framework rather than a broad inference engine. diff --git a/docs/plans/2026-07-03-11-source-language-expansion.md b/docs/plans/2026-07-03-11-source-language-expansion.md deleted file mode 100644 index ce2ba3f7..00000000 --- a/docs/plans/2026-07-03-11-source-language-expansion.md +++ /dev/null @@ -1,90 +0,0 @@ -# Source language expansion vertical slice - -## Goal - -Add one new source language end to end using the existing language-support conventions, including graph extraction, symbols, navigation where feasible, docs, and tests. - -## Recommended first candidate - -Use Lua as the first expansion candidate unless product priorities choose another language. - -Reasons: - -- compact syntax surface -- common in plugin/config ecosystems -- useful for repo understanding -- reasonable first target for functions, method-like calls, `require` imports, and local variables - -Do not add multiple languages in one PR. - -## Design - -### Capability target - -For the first PR, target: - -- dependency graph: yes -- symbol extraction: yes -- go-to-definition: basic local/imported symbols where supported by existing navigation machinery -- find references: basic same-name/call references where supported -- chunking: yes -- PR impact mapping: yes through file/symbol graph -- call compatibility: no unless parameter extraction is reliable - -## Implementation steps - -1. Add native parser dependency in `packages/codegraph-native/Cargo.toml` if available and license-compatible. -2. Register language id in `packages/codegraph-native/src/languages.rs`. -3. Add `src/languages/definitions/lua.ts`. -4. Register language in the source language registry. -5. Add queries for: - - function declarations - - local function declarations - - assignment-style function definitions - - method definitions using `:` - - `require(...)` imports with string literals - - call expressions -6. Add chunking support through existing language config generation. -7. Add docs and parity matrix entry. - -## Tests - -Add fixtures under `tests/languages/samples/` and tests in `tests/languages/lua.test.ts`: - -- file import via `require("mod")` -- local function extraction -- table method extraction -- method call references -- exported module table pattern if feasible -- unsupported dynamic require skipped cleanly - -Add shared tests where behavior is claimed: - -- `tests/goto.test.ts` -- `tests/references.test.ts` -- `tests/native-semantic-parity.test.ts` if native runtime supports it - -## Documentation - -Update: - -- `docs/language-parity.md` -- `docs/scenario-catalog.md` -- `README.md` supported language list if public-facing claim changes -- `codegraph-skill/codegraph/SKILL.md` only if agent-facing capabilities change - -## Non-goals - -- No runtime module path execution. -- No metatable/data-flow inference. -- No language family pack in one PR. - -## Acceptance - -- The new language appears in doctor/native supported language output when native is available. -- Graph, symbols, search, chunking, and impact work for the documented subset. -- Unsupported dynamic cases are documented and covered by negative tests. - -## Review pass - -Checked scope: this plan turns language expansion into one complete vertical slice. It follows this repo's parity and documentation rules instead of making a broad unsupported language claim. diff --git a/docs/plans/2026-07-03-12-affected-tests-command.md b/docs/plans/2026-07-03-12-affected-tests-command.md deleted file mode 100644 index 9a5634c6..00000000 --- a/docs/plans/2026-07-03-12-affected-tests-command.md +++ /dev/null @@ -1,97 +0,0 @@ -# Affected tests command - -## Goal - -Add a direct CLI command that maps changed source files to likely affected test files for local development and CI scripts. - -Command: - -```bash -codegraph affected src/auth.ts src/db.ts -codegraph affected --stdin --quiet -codegraph affected --base main --head HEAD --json -``` - -## Design - -Build on existing impact/candidate-test logic. Do not invent a second dependency graph. - -Inputs: - -- positional files -- `--stdin` for newline-delimited file paths -- `--base`/`--head` to derive changed files from git diff -- `--root` -- `--filter ` to restrict test files -- `--depth ` for reverse dependency traversal depth -- `--json` -- `--quiet` for paths only - -## Algorithm - -1. Normalize changed files relative to `--root`. -2. Build or load project graph/index with existing cache options. -3. For each changed file, traverse reverse dependencies up to depth. -4. Classify test files using existing test-file detection/candidate-test helpers. -5. Include directly changed test files even if no source file maps to them. -6. Sort deterministically by path. - -## JSON output - -```ts -type AffectedTestsReport = { - schemaVersion: 1; - root: string; - changedFiles: string[]; - affectedTests: Array<{ - file: string; - reasons: string[]; - depth: number; - }>; - omittedCounts: Record; -}; -``` - -## CLI output - -Default pretty output: - -```text -Affected tests -- tests/auth.test.ts (reverse dependency from src/auth.ts, depth 1) -``` - -`--quiet` prints only paths, one per line. - -## Files likely touched - -- `src/cli/help.ts` -- `src/cli/options.ts` -- `src/cli.ts` -- new `src/cli/affected.ts` -- `src/impact/report-suggestions.ts` or shared test-candidate helper extraction -- `docs/cli.md` -- `README.md` -- `codegraph-skill/codegraph/SKILL.md` -- tests under new `tests/affected.test.ts` - -## Tests - -- positional source file maps to direct test. -- transitive reverse dependency maps to test within depth. -- `--depth 0` only includes changed tests. -- `--stdin` reads paths. -- `--filter` limits results. -- `--base`/`--head` uses git provider safely. -- `--quiet` prints stable paths only. -- JSON schema is stable. - -## Acceptance - -- CI can run `codegraph affected --stdin --quiet` and pipe results into a test runner. -- Review/impact candidate-test behavior is reused, not forked. -- Output is deterministic and root-relative. - -## Review pass - -Checked scope: this plan exposes a simple command over existing graph and test-candidate logic. It avoids duplicating impact analysis while adding a useful scripting interface. diff --git a/docs/plans/2026-07-03-16-config-extension-mapping.md b/docs/plans/2026-07-03-16-config-extension-mapping.md deleted file mode 100644 index a0102b24..00000000 --- a/docs/plans/2026-07-03-16-config-extension-mapping.md +++ /dev/null @@ -1,93 +0,0 @@ -# Configurable extension mapping - -## Goal - -Allow projects to map nonstandard file extensions to already-supported languages through `codegraph.config.json`. - -Example: - -```json -{ - "languages": { - "extensions": { - ".tpl": "php", - ".inc.php": "php", - ".build.ts": "ts" - } - } -} -``` - -## Design - -Extend the existing config schema. Keep mappings limited to language ids already known to Codegraph. - -Config type: - -```ts -type CodegraphConfig = { - discovery?: ProjectFileDiscoveryOptions; - languages?: { - extensions?: Record; - }; -}; -``` - -Rules: - -- Extension keys must be literal suffixes starting with `.` and containing only letters, digits, `.`, `_`, `+`, or `-`. -- Values must be supported language ids. -- Longer extension keys win first, so `.inc.php` beats `.php`. -- Built-in extensions remain unless explicitly remapped; `.vue` and `.svelte` remain single-file components and cannot be remapped. -- Invalid mappings fail config validation with actionable errors. - -## Integration - -Thread extension mapping into language detection, not individual commands. - -Likely approach: - -- Add a `LanguageResolver` or extend existing language lookup helpers. -- Load config at the project boundary. -- Merge built-in extensions with config mapping. -- Include normalized mapping in cache keys/build options hash. -- Ensure CLI include/ignore glob semantics remain unchanged. - -## Non-goals - -- Do not load arbitrary grammars from config. -- Do not allow shell commands or parser package names in config. -- Do not claim new language support through extension mapping alone. - -## Files likely touched - -- `src/config.ts` -- `src/languages.ts` -- language detection utilities under `src/languages/` -- index/build cache key code -- CLI context/config loading -- `docs/cli.md` -- `docs/installation.md` or `docs/language-parity.md` -- `README.md` if public config surface changes -- `codegraph-skill/codegraph/SKILL.md` if config guidance changes -- tests under new `tests/config-extension-mapping.test.ts` - -## Tests - -- `.tpl` mapped to `php` is indexed as PHP. -- longest extension wins. -- invalid extension key fails validation. -- unknown language id fails validation. -- cache invalidates when mapping changes. -- built-in extension still works when unrelated mapping exists. -- remapping a built-in extension behaves deterministically and is documented. - -## Acceptance - -- Users can index supported-language files with project-specific extensions. -- Mapping behavior is deterministic across CLI, library sessions, MCP, and artifacts. -- Config docs distinguish durable project mappings from one-off include/ignore globs. - -## Review pass - -Checked scope: this plan adds flexibility without dynamic parser loading. It keeps language support bounded to known ids and makes mapping part of cache identity. diff --git a/docs/plans/2026-07-03-plan-priority-index.md b/docs/plans/2026-07-03-plan-priority-index.md index 6a0cc461..9d71398f 100644 --- a/docs/plans/2026-07-03-plan-priority-index.md +++ b/docs/plans/2026-07-03-plan-priority-index.md @@ -4,8 +4,6 @@ This is the live index for plans that still need a decision or implementation. C ## Next -These plans describe current, executable work: - 1. `2026-07-25-performance-program-index.md` - Keep the shared performance baseline and coordinate the remaining native-startup work. 2. `2026-07-25-native-runtime-startup.md` @@ -13,31 +11,18 @@ These plans describe current, executable work: ## Planned -These plans are unimplemented and remain distinct product outcomes: - -- `2026-05-27-agent-test-plan-generation.md` +- `2026-05-12-source-language-expansion.md` - `2026-07-03-03-shared-server-lifecycle.md` -- `2026-07-03-08-framework-route-nodes.md` -- `2026-07-03-09-mobile-bridge-edges.md` -- `2026-07-03-10-dispatch-synthesizers.md` -- `2026-07-03-12-affected-tests-command.md` +- `2026-07-03-semantic-graph-synthesizers.md` - `2026-07-03-14-privacy-preserving-diagnostics.md` -- `2026-07-03-16-config-extension-mapping.md` - -The affected-tests plan has an old open implementation in PR #146. Reconcile that branch against current `main` before treating it as executable work. - -## Needs reconciliation +- `2026-08-03-performance-measurement-backlog.md` -These plans mix completed work, overlapping scope, or measurement-gated follow-ups. Do not implement or delete them until the remaining outcome is restated: +## Needs decision -- `2026-05-12-graph-first-language-expansion.md` - - Consolidate with `2026-07-03-11-source-language-expansion.md` into one language-expansion owner. -- `2026-07-03-11-source-language-expansion.md` - - Preserve the narrow vertical-slice guidance when consolidating language work. - `2026-06-06-performance-and-cache-opportunities.md` - - Most ranked work shipped; move only still-validated gaps into the performance program. + - Three unmeasured cleanup candidates remain after completed and measurement-only work was removed. - `2026-07-21-warm-run-discovery-avoidance.md` - - Priorities 1-4 and audit ranks 1-3 shipped; decide whether the remaining stretch items still justify ownership. + - Only the non-Git directory-mtime fallback remains; its state and correctness cost may exceed its value. ## Deferred or rejected @@ -47,6 +32,6 @@ These plans mix completed work, overlapping scope, or measurement-gated follow-u ## Status rules -- Every new plan must appear here as `next`, `planned`, `blocked`, or `needs reconciliation`. +- Every new plan must appear here as `next`, `planned`, `blocked`, or `needs decision`. - A plan leaves this index when its outcome is merged, explicitly rejected, or superseded. - Completed and superseded plan files should be removed instead of retained as a second roadmap. diff --git a/docs/plans/2026-07-03-semantic-graph-synthesizers.md b/docs/plans/2026-07-03-semantic-graph-synthesizers.md new file mode 100644 index 00000000..589e9b47 --- /dev/null +++ b/docs/plans/2026-07-03-semantic-graph-synthesizers.md @@ -0,0 +1,63 @@ +# Semantic graph synthesizers + +Status: Planned. Build one shared provenance contract and one concrete vertical slice before adding another framework family. + +## Goal + +Model parser-visible framework semantics that ordinary imports and calls miss while keeping every inferred node and edge conservative, auditable, and optional. + +## Shared contract + +A synthesizer runs after normal symbol extraction and before graph finalization. It consumes indexed symbols, imports, locals, and already-available source context; it must not create a second parser pipeline. + +Every synthesized fact must include: + +- a stable synthesizer id +- `provenance: "heuristic"` +- confidence +- a human-readable reason +- concrete source ranges and endpoints + +Emit a fact only when the framework convention is stable and ambiguity can be resolved. Skip dynamic names, runtime dispatch, reflection, and ambiguous matches; low-confidence facts must not appear in default graph output. + +Synthesized facts may participate in search, path, references, dependencies, impact, review, packets, and explain only when those surfaces preserve provenance and omission counts. + +## Candidate vertical slices + +Pick one slice for the first pull request. + +### Framework routes + +- Express-style JavaScript/TypeScript routes with literal paths and a concrete final handler. +- FastAPI-style Python decorators with a literal path and the decorated function as handler. +- Create route nodes such as `GET /users/:id` plus references to handlers and explicit middleware. +- Skip dynamic paths and ambiguous handler expressions. + +### Mobile bridges + +- Start with explicit Swift `@objc` names matched to Objective-C selectors. +- Require Objective-C source support before emitting a cross-language edge; Swift-only indexing may retain metadata but must not claim a bridge. +- Match class-qualified receivers when available and skip ambiguous selectors. +- Defer React Native, Expo, Fabric, and Paper families. + +### Dispatch conventions + +- Start with either Redux Toolkit Query endpoint declarations mapped to generated hooks or Redux thunk dispatch references. +- Require both endpoints to be concrete symbols or locally declared framework keys. +- Do not infer generic event buses, dependency injection, or arbitrary string dispatch. + +## First-slice implementation + +1. Define the shared synthesized-fact and provenance schema without changing parser-direct facts. +2. Add one synthesizer and positive, negative, renamed, and ambiguous fixtures. +3. Integrate the fact into the smallest relevant query surfaces. +4. Prove disabling synthesis removes the facts without changing ordinary graph output. +5. Update `docs/language-parity.md` and `docs/scenario-catalog.md` with the exact framework and limitations. + +## Acceptance + +- One concrete framework pattern works end to end. +- Every emitted fact explains how and where it was derived. +- Ambiguous and dynamic cases produce no false graph claims. +- Existing graph output remains backward compatible or receives an explicit schema version. +- The shared contract can host a second slice without a parallel framework or provenance shape. diff --git a/docs/plans/2026-07-21-warm-run-discovery-avoidance.md b/docs/plans/2026-07-21-warm-run-discovery-avoidance.md index f0015a98..7cf7b4e2 100644 --- a/docs/plans/2026-07-21-warm-run-discovery-avoidance.md +++ b/docs/plans/2026-07-21-warm-run-discovery-avoidance.md @@ -1,285 +1,21 @@ -# Warm-Run Discovery Avoidance Plan +# Non-Git warm discovery fallback -**Status: Priorities 1-4 implemented.** Priority 5 remains an unstarted stretch item, as originally scoped. Follow-up audit ranks 1-3 are also implemented; the lower-priority candidates remain measurement-gated. +Status: Needs decision. Git-backed warm discovery, freshness reuse, symlink-walk avoidance, scoped inspect/review caching, and detailed-symbol-graph persistence are implemented and preserved in Git history. -This plan targets one specific, verified gap left by `2026-06-06-performance-and-cache-opportunities.md`: even on a fully warm, unchanged repo, most commands still pay for a full recursive directory scan before any cache or manifest logic gets a chance to short-circuit. Priority 7 of that plan ("Persist a Ready-to-Load Project Index Snapshot") made graph reconstruction skippable once files are known unchanged, but it did not remove the discovery scan that determines "unchanged" in the first place. This plan closes that gap and fixes a related default-cache inconsistency across CLI commands. +## Remaining outcome -It is self-contained so another agent can implement items without the original conversation. It complements, and in one place extends, `2026-06-06-performance-and-cache-opportunities.md`; see the cross-reference added there. +Non-Git projects and strict verification paths still require exhaustive discovery. A possible fallback would persist directory mtimes and skip globbing subtrees whose membership cannot have changed. -## Problem Statement +The design would need: -All findings below are evidence-backed against the current `main` tree. +- explicit manifest schema versioning and an older-schema migration regression +- a periodic exhaustive verification fallback +- documented behavior for network, cloud-sync, overlay, and bind-mounted filesystems whose directory mtimes may be unreliable +- `--cache-verify` as an unconditional exhaustive path +- proof that additions, removals, renames, symlink changes, and ignored-path changes cannot be missed -### F1: `AgentSession` always re-scans the full tree, warm or not +## Value gate -`createAgentSession()` in `src/agent/session.ts` backs `search`, `orient`, `explore`, `explain`, `packet get`, `refactor-plan`, `rename-preview`, `callers`/`callees`, `supertypes`/`subtypes`, `workspace-symbols`, `file --include-graph-context`, `artifact build`, `sync`, and every MCP tool. Its `loadFiles()` (session.ts:193-201) unconditionally calls `listAgentSessionFiles()` -> `listProjectFiles()` (session.ts:104-106) on every `loadProject()` call that does not already have a cached promise for this process. That scanned list is then passed into `buildProjectIndexIncremental()` as `opts.files` (session.ts:209-221). +Do not implement this from the historical warm-run measurements. Git reconciliation now covers the primary repository workflow, while the non-Git fallback adds persistent state and correctness risk. -This is not accidental: it is the only mechanism that reliably surfaces brand-new, uncommitted, untracked files (see F6). But it means every agent-facing command pays full-tree discovery cost regardless of whether anything changed. - -### F2: Discovery silently doubles as a second full tree walk - -`listProjectFiles()` (`src/util/projectFiles.ts:322-379`) does the expected pattern-matching `fg()` walk, then unconditionally calls `listEntriesFromSafeSymlinkDirectories()` (`projectFiles.ts:381-446`), which runs a **second** full recursive walk (`fg(["**/*"], { onlyFiles: false, ... })`) to find symlinked directories. This runs even for projects with zero symlinks. Every discovery call pays for two tree walks, not one. - -### F3: MCP freshness checks repeat the same full scan - -`checkFreshness()` (session.ts:275-315), used when `freshness.policy` is `"check"` or `"auto"` (the MCP server's default per `src/mcp/server.ts:282`), calls `listProjectFiles()` again (session.ts:282) to diff against the cached baseline. Long-running MCP sessions pay the full F1/F2 cost on every freshness check, on top of the one paid at session creation. - -### F4: `goto`, `refs`, `impact`, and default `graph`/`index` bypass the incremental path entirely - -`src/cli/navigation.ts` (`goto`, `refs`, `dumpmod`) and `src/cli/impact.ts` build via `buildProjectIndex()` / `buildProjectIndexFromFiles()`, not `buildProjectIndexIncremental()`. `buildProjectIndexWithManifestOptions()` (`src/indexer/build-index.ts:783-810`) always runs `listProjectFiles()` + `discoverProjectFiles()` in parallel (line 789-797) with no manifest short-circuit — there is no "unchanged, skip discovery" branch on this path at all, only on `buildProjectIndexIncremental()`. - -Worse, these commands never pass `--cache`, so `cache` defaults to `"off"` (`createIndexBuildRunState`, build-index.ts:420). `cacheEnabled` becomes `false`, disabling per-file parse-cache reuse (build-index.ts:427). Yet `buildProjectIndexWithManifestOptions()` still passes `manifestMode: "read-write"` unconditionally (build-index.ts:799), so a manifest is written on every run — and then never read back, because these commands do not call the one function (`buildProjectIndexIncremental`) that reads it. The manifest write cost is paid for no benefit on this code path. - -Net effect: `codegraph goto`, `codegraph refs`, and `codegraph impact` fully rediscover and fully reparse the project on every single invocation, by construction, independent of any cache flag the user might think to pass. - -### F5: The existing snapshot fast path is real but discovery-gated - -Inside `buildProjectIndexIncremental()`, the "0 changed files" branch correctly skips graph reconstruction via `tryLoadProjectIndexSnapshot()`. The warm Git-backed path now reaches that snapshot before worker setup, all-file content hashing, and manifest rewriting; `--cache-strict`, non-Git projects, untracked candidates, malformed snapshots, and manifests requiring path sanitization retain the exhaustive path. AgentSession also passes its manifest/Git reconciliation evidence into the indexer so one command does not run the same working-tree and untracked-file checks twice. - -### F6: No cheap way to detect new untracked files exists yet - -`src/util/git.ts` has `listChangedFiles()`, which shells out to `git diff --name-only`. `git diff` never reports untracked files, by design, regardless of `--diff-filter`. There is no `git status`/`git ls-files --others` helper anywhere in the codebase. This absence is _why_ F1's blanket full scan exists: it is currently the only reliable way to catch a file the user just created that is not yet committed or staged. - -## Priority 1: Route `goto`/`refs`/`impact`/default `graph`/`index` Through the Incremental Path - -Lowest risk, highest immediate value: reuse infrastructure that `search`/`orient`/`inspect`/`review`/`agent-tools` already exercise in production, instead of inventing anything new. - -Why this matters: - -- Fixes F4 directly. `buildProjectIndexIncremental()` already knows how to read the manifest these commands are currently writing and discarding. -- No new schema, no new git plumbing required for this step alone. - -Implementation checklist: - -- [x] Change `src/cli/navigation.ts` (`goto`, `refs`, `dumpmod`) to call `buildProjectIndexIncremental()` instead of `buildProjectIndex()`. -- [x] Change `src/cli/impact.ts`'s default (non-`--changed-since`) build to call `buildProjectIndexIncremental()`. -- [x] Default `cache` to `"disk"` for these commands unless the user passes `--cache off`/`--cache memory`, matching `inspect`'s existing default (`src/cli/inspect.ts:271`). -- [x] Audit `src/cli/graph.ts` and `src/cli/index.ts` non-incremental branches for the same fix; keep `--changed-since`/`--git-base` behavior unchanged since those already use the incremental path. Shipped narrower than originally scoped: `index.ts`'s whole-project branch (`shouldWriteManifest`) now uses `buildProjectIndexIncremental()`; its scoped-include-root branch and all of `graph.ts`'s `buildProjectIndexFromFiles()` call sites keep the explicit, already-resolved file list (multi-root scans are not safely reconcilable against a whole-project-scoped manifest) but now default `cache` to `"disk"` for per-file parse-cache reuse. `graph.ts`'s default (no `--symbols`/`--sqlite`) output path uses `collectGraph()` directly, a different function family outside this plan's scope; left unchanged. -- [x] Confirm `dumpmod` does not have a reason to want a forced full rebuild — it shares `indexOptions()` with `goto`/`refs`, no distinct requirement found; moved to `buildProjectIndexIncremental()` too. -- [x] Add a regression test proving a second `goto`/`refs`/`impact` invocation against an unchanged repo reuses the manifest: `tests/cli-command-modules.test.ts` spies on `listProjectFiles` and asserts zero calls on the second invocation of each command. -- [x] Update `docs/cli.md` (and `docs/agent-workflows.md`, which made the same narrower claim) to state that `goto`/`refs`/`impact` and a whole-project `graph`/`index` run now default to the incremental disk cache too, alongside agent commands. - -Likely files: - -- `src/cli/navigation.ts` -- `src/cli/impact.ts` -- `src/cli/graph.ts` -- `src/cli/index.ts` -- `docs/cli.md` -- `tests/cli-command-modules.test.ts` -- `tests/navigation.test.ts` or equivalent -- `tests/impact-analyzer.test.ts` - -Risks: - -- `buildProjectIndexIncremental()` on a stale/mismatched manifest falls back to a full rebuild automatically (build-index.ts:889-897), so behavior should degrade gracefully; verify this with a test that mutates `codegraph.config.json` between runs and confirms a full rebuild still happens. -- Confirm no caller relies on `goto`/`refs`/`impact` ignoring on-disk cache state for correctness (e.g., deliberately avoiding any manifest interaction). Search history/tests before changing; if found, document why and scope the change narrower. - -Validation: - -- [x] `npx vitest run tests/cli-command-modules.test.ts tests/impact-analyzer.test.ts` — passing. -- [x] `node ./dist/cli.js goto ` timed twice back-to-back; second run reuses the manifest instead of rebuilding. -- [x] `node ./dist/cli.js impact --base HEAD --head WORKTREE --json` timed twice back-to-back. - -## Priority 2: Cheap Git-Status Reconciliation for `AgentSession` Discovery - -Addresses F1 and F6 for the majority git-repo case, without regressing correctness for untracked files. - -Why this matters: - -- This is the actual fix for "expensive full recursive directory scan before every command" for the whole agent/MCP surface, not just the four commands in Priority 1. -- `git status`/`git ls-files --others` is native, typically far cheaper than a JS `fast-glob` + `picomatch` walk against every ignore/include pattern, and git already tracks its own working-tree state. - -Implementation checklist: - -- [x] Add a `listUntrackedFiles()` helper to `src/util/git.ts` (`git ls-files --others [--exclude-standard] -z`). Shipped narrower than the originally-scoped combined helper: modified/deleted tracked files since the manifest's `lastCommit` already have a correctness path via the existing `listChangedFiles()` commit-diff plus `buildProjectIndexIncremental()`'s existing per-file signature comparison (both pre-dating this plan); only new untracked files had no detection path at all, so only that primitive was net-new. -- [x] `src/indexer/incremental-plan.ts` gained `listUntrackedProjectFiles()` (Git-sourced candidates filtered through project discovery patterns), `canUseIncrementalDiscoveryFastPath()` (the shared disqualification predicate below), and `resolveIncrementalFileList()`, a manifest-plus-Git resolver used by `AgentSession.loadFiles()`/`discoverFiles()`/`checkFreshness()` that returns `null` to signal "fall back to a full scan" rather than reconciling inline in `session.ts`, so the same resolver is independently unit-testable and reusable. -- [x] `AgentSession.loadFiles()` (`listAgentSessionFiles()` in session.ts) tries `resolveIncrementalFileList()` first and falls back to `listProjectFiles()` when it returns `null`. -- [x] Untracked-candidate filtering reuses a new shared `createDiscoveredFileMatcher()` (`src/util/projectFiles.ts`) against the small candidate set only, then applies the same realpath-within-root confinement as `listProjectFiles()` so an untracked source-looking symlink cannot escape `--root`. The existing manifest-tracked baseline is not re-filtered (it was already filtered when it entered the manifest). -- [x] Fall back to a full scan when: no manifest yet, the manifest predates recorded `buildOptions`, discovery options changed since the manifest was written (via `diffBuildOptions(...).includes("discovery")`), no Git repo, `--cache-strict` is set, or any Git command in the resolution fails. `useGitignore: false` no longer forces a full-scan fallback: `listUntrackedProjectFiles()` drops Git's `--exclude-standard` in that mode instead of giving up, so gitignored-but-untracked files are still found correctly (fixed in review; the first version incorrectly disqualified the fast path here). -- [x] `discoverFiles()` intentionally now shares the same fast-path-aware `listAgentSessionFiles()` rather than staying full-scan-only: the fast path is a strictly-correct-or-null substitute (never returns a wrong answer, only `null` on any doubt), so there is no accuracy downside, and its one caller (`mcp/server.ts`'s SQLite-artifact freshness check) benefits from the same scan avoidance. -- [x] Tests added: new untracked file found without a scan; gitignored untracked file found when `useGitignore: false`; untracked symlink escaping the real project root excluded; older manifest without `buildOptions` falling back to a full scan; modified/deleted tracked files after a new commit found without a scan (`resolveIncrementalFileList` in `tests/incremental-plan.test.ts`); non-Git fallback, `--cache-strict` fallback, and discovery-option-change fallback (`tests/agent-session.test.ts`). Rename-as-delete+add is covered implicitly (Git reports a delete and an add for an unstaged rename with no `--find-renames` tracking at the porcelain level used here) rather than as a dedicated named case. - -Likely files: - -- `src/util/git.ts` -- `src/agent/session.ts` -- `tests/agent-session.test.ts` -- `tests/cache-invalidation.test.ts` -- New or extended `tests/util-git.test.ts` - -Risks: - -- Git worktrees, submodules, and sparse checkouts need explicit test coverage; do not assume `git status` behaves identically to a plain repo in these configurations. -- `git status`/`git ls-files` still walks the working tree internally in the worst case (no fsmonitor); benchmark before assuming a guaranteed win on very large repos, and keep the fallback path correct regardless of the performance delta. -- A file rewritten with git-invisible changes (e.g., content changed but `git diff` sees it as clean due to a race, or `.git` metadata corruption) must not silently go stale; keep `--cache-verify` as an explicit escape hatch that always forces the full path. - -Validation: - -- [x] `npx vitest run tests/agent-session.test.ts tests/cache-invalidation.test.ts tests/incremental-plan.test.ts tests/git-diff-semantics.test.ts` — passing. -- [x] Manual timing: representative AgentSession-backed commands (`orient`, `inspect`, `search`, and `symbols`) on an unchanged Git-backed repo no longer call `listProjectFiles`; direct CLI commands that use the incremental index path report cache validation first, then report build/update progress only when work is required. Unchanged snapshot hits also skip all-file signature generation and do not rewrite the manifest. -- [x] Manual correctness check: create an untracked file, run AgentSession-backed commands such as `search`/`orient`, confirm it is found without `--changed-since` — covered by the "finds a newly created untracked file" test in `tests/agent-session.test.ts`. - -## Priority 3: Skip the Symlink-Directory Walk When There Are No Symlinks - -Small, safe, and independent of Priority 1/2 — ship first if sequencing matters. - -Why this matters: - -- Fixes F2. Most projects have zero symlinked directories under the project root, yet pay for a second full `fg(["**/*"], { onlyFiles: false })` walk on every single `listProjectFiles()` call. - -Implementation checklist: - -- [x] Record `symlinkDirectories: string[]` in the manifest (shipped as the actual path list rather than a boolean flag: an empty array means "known, none," and a populated array lets the fast path re-verify each entry directly instead of re-deriving the set from a fresh probe) the next time a full scan runs and actually enumerates entries. -- [x] `listProjectFiles()` and `discoverProjectFiles()` both accept `knownSymlinkDirectories`/`onSymlinkDirectoriesDiscovered` (`ProjectFileDiscoveryOptions`, `src/util/projectFiles.ts`); when a known list is provided, `resolveSafeSymlinkDirectories()` re-verifies each entry directly (lexically inside `root`, `lstat().isSymbolicLink()`, directory `stat`, and realpath inside `realRoot`) instead of running the full `fg(["**/*"])` probe. `buildProjectIndexWithManifestOptions()` (`src/indexer/build-index.ts`) peeks the manifest for the hint before its full-scan `Promise.all`, passes it to both discovery calls, and writes the verified list back to the manifest so stale/invalid hints are pruned. -- [x] Missing field on an old-schema manifest is `undefined`, which both call sites treat identically to "unknown, probe once" — a JSON-optional-field default, not a code migration step. A regression test loads a manifest fixture built via `createManifest()` (pre-dating this field) and confirms a rebuild completes and backfills `symlinkDirectories`. -- [x] Tests proving a symlinked directory's files are still found via both the probing path and the fast (known-list) path, plus stale-known-entry, real-directory-hint, outside-root-hint, and no-symlinks cases, added to `tests/project-file-discovery.test.ts`; manifest persistence, stale-hint pruning, populated/empty lists, and old-schema migration added to `tests/cache-invalidation.test.ts`. - -Likely files: - -- `src/util/projectFiles.ts` -- `src/indexer/build-cache/manifest.ts` -- `tests/project-files.test.ts` or equivalent -- `tests/cache-invalidation.test.ts` (schema migration case) - -Validation: - -- [x] `npx vitest run tests/cache-invalidation.test.ts tests/project-file-discovery.test.ts` — passing (symlink tests skip gracefully via `isSymlinkUnavailable()` on platforms/permission levels that cannot create symlinks). -- [x] Confirmed a project with an intentional symlinked source directory still indexes those files correctly, both cold (probing) and warm (known-list fast path). - -## Priority 4: Make Freshness Checks Reuse the Cheap Path - -Why this matters: - -- Fixes F3. Once Priority 2 exists, `checkFreshness()` should use the same git-status reconciliation instead of an independent `listProjectFiles()` call, so long-running MCP servers do not pay full-scan cost on every freshness check. - -Implementation checklist: - -- [x] `checkFreshness()` now calls `listAgentSessionFiles(options)` (the same fast-path-aware resolver `loadFiles()`/`discoverFiles()` use) instead of calling `listProjectFiles()` directly. -- [x] `collectAgentFileSignatures`/`diffAgentFileSignatures` are unchanged and still run over the resolved file list. Shipped narrower than originally scoped: the resolved list itself is the full current file set (from the fast path or the full-scan fallback), not a pre-narrowed delta; stat-collection over that full list is unchanged from before this plan, and the discovery-scan cost specifically (the actual target of this plan) is what's eliminated. Narrowing `collectAgentFileSignatures` itself to stat only a Git-reported delta is a separate, smaller optimization not required to fix the discovery-scan problem and is left as a follow-up. -- [x] `policy: "manual"` and the `maxAutoRefreshFiles`/`maxAutoRefreshBytes` auto-refresh gates are untouched. - -Likely files: - -- `src/agent/session.ts` -- `tests/mcp-server.test.ts` -- `tests/agent-session.test.ts` - -Validation: - -- [x] `npx vitest run tests/mcp-server.test.ts tests/agent-session.test.ts` — passing. -- [x] `tests/agent-session.test.ts` adds a direct spy-count assertion: `checkFreshness()` on an unchanged Git-backed project calls `listProjectFiles` zero times. - -## Priority 5 (Stretch): Directory-Mtime Fallback Discovery for Non-Git Projects - -Not scoped for immediate implementation; recorded so it is not lost. - -Why this matters: - -- Priority 2 only helps git repos. Non-git projects (or git repos with `--cache-strict` forced) still pay full discovery every time. -- Most filesystems update a directory's mtime when an entry is added, removed, or renamed directly inside it (not on content changes to existing files). A manifest that records each directory's mtime can skip re-globbing subtrees whose mtime has not moved, without needing git at all. - -Notes for whoever picks this up: - -- Known caveats to design around explicitly: some network/cloud-sync filesystems and certain overlay/bind mounts do not reliably update directory mtimes; this must have a documented, tested fallback (periodic full-rescan interval, or `--cache-verify` forcing it). -- This is a larger manifest-schema change than Priority 3's single boolean; plan explicit schema versioning per `AGENTS.md`, with a migration test starting from the current schema. -- Do not start this until Priority 2 ships and its real-world hit rate is known; git-status reconciliation may cover enough of the practical caseload that this stretch item stops being worth the complexity. - -## Correctness and Schema Notes - -- Priorities 3 and 5 both touch persistent manifest state. Per `AGENTS.md`, any schema change needs an explicit migration/backfill path and a regression test that starts from the older schema, not just `CREATE TABLE IF NOT EXISTS` or an added-but-unvalidated JSON field. -- Priority 2's git-status fast path must never silently under-report changes. Keep `--cache-verify` as an unconditional trapdoor back to the full scan, and keep the existing manifest-mismatch / config-hash / graph-options-mismatch full-rebuild triggers untouched. -- `docs/cli.md` and `docs/agent-workflows.md` previously scoped the disk-cache-by-default claim to "agent commands" only. Priority 1 makes that statement true for `goto`/`refs`/`impact`/whole-project `graph`/`index` too; both docs are updated in this change to state that broader scope precisely. `codegraph-skill/codegraph/SKILL.md` did not make this claim in the first place (checked; no correction needed there). -- The manifest schema change for `symlinkDirectories` (Priority 3) did not need an explicit migration function: it is a plain optional JSON field, and a missing field on an older manifest is indistinguishable in code from "not yet known," which is exactly the fallback both call sites already needed to handle. A regression test still proves an old-schema manifest loads and rebuilds correctly, per the spirit of `AGENTS.md`'s schema-migration rule even though the SQLite `ALTER TABLE` mechanism it describes does not apply to a JSON manifest file. - -## Follow-up Whole-Repository Performance Audit - -**Status: Ranks 1-3 implemented.** The lower-priority items below remain measurement-gated. - -Measured on this repository after the warm-run fixes above, using the built CLI on Windows. Exact wall time varies with cache state, but the phase reports and repeated-process comparisons identify the same dominant work. - -### Rank 1: Stop Review Ranges from Re-invalidating the Current Index - -Evidence: - -- Repeating `review --base HEAD~1 --head HEAD --summary --json` took 43.6s with the current default. Its report attributed 15.2s to indexing and showed all 662 project files parsed again. -- Adding `--cache disk` reduced the repeat to 19.8s, but indexing still took 11.6s and reparsed 349 files. The reviewed range touched central files, so transitive dependent expansion made the explicit range much larger than the actual diff. -- The remaining reported review work was dominated by targeted duplicate-context collection. A second CLI-only duplicate summary added about 1.8s after `buildReviewReport()` returned. - -Recommended change: - -- Default the CLI `review` command to disk cache, matching the other index-backed agent commands. -- Keep review diff selection separate from current-index freshness. `gitBase`, `gitHead`, `changedSince`, and review-selected `files` choose report contents; they should not be forwarded as incremental index invalidation inputs after `collectReviewChanges()` has already consumed them. -- Reuse one collected duplicate-unit/bucket set for review tasks and the human duplicate summary instead of preparing duplicate candidates twice. - -Risk and proof: - -- Implemented with Git-backed cold/warm parity coverage, prepared duplicate-analysis reuse, and transient explicit-file provenance. A repeated no-change review now completes in about 0.39s on this repository; review ranges still scale with their actual changed-symbol work. - -### Rank 2: Mark Inspect and Hotspot File Lists as Scope, Not Changes - -Evidence: - -- Warm `inspect --root . ./src --limit 20 --json` without `--duplicates` took 11-13s. -- `buildScopedReportGraph()` passes the resolved 345-file scope through `files`, so the incremental builder treats those files as caller-selected changes. A direct run against the same warm manifest reported 988 changed and parsed files and took 16.3s. -- Passing the same list as `filesAreProjectScope: true` reused the snapshot in 0.29s in the direct index measurement. - -Recommended change: - -- Set `filesAreProjectScope: true` in the disk-cache branch of `buildScopedReportGraph()`. Keep `restrictGraphToIncludeRoots()` as the output boundary. -- Cover both `inspect` and `hotspots`, including child include roots, deleted tracked files, untracked additions, and cache/report mode. - -Risk and proof: - -- Implemented with option-shape, child-root, stale-file, native-mode, and progress regressions. Repeated scoped inspect fell from 11-13s to about 0.59s on this repository. - -### Rank 3: Persist the Detailed Symbol Graph for One-Shot Navigation - -Evidence: - -- A warm base-index load completed in roughly 0.4-0.5s inside one process, but adding eager detailed-symbol loading cost about 7.4s. -- One-shot `search --mode symbol` and hybrid search took about 7-8s, while text-only search was much cheaper. `buildSymbolGraphDetailed()` rereads and reparses supported source files because the project-index snapshot stores module indexes and the file graph, not detailed body/member edges. - -Recommended change: - -- Add a versioned detailed-symbol-graph sidecar keyed by the same project snapshot identity and graph/native options. Write atomically and load only for commands that require detailed edges. -- Prefer immutable snapshot replacement over serializing syntax trees. Invalidate the sidecar whenever the project snapshot signature changes. - -Risk and proof: - -- Implemented as an atomic, versioned, identity-bound sidecar with malformed/stale cache fallback and semantic graph validation. Repeated one-shot symbol search fell from about 7-8s to about 1.1s on this repository, with navigation and member/inheritance parity covered. - -### Lower-Priority Opportunities - -- `checkFreshness()` still stats the resolved file list under automatic freshness policies. The measured full-list signature pass was tens of milliseconds, so narrowing it to Git deltas is not currently worth extra state complexity. -- `getGitBlobHashes()` remains O(files) on exhaustive rebuild/verification paths, but the clean Git fast path now returns before it. Optimize this only with a benchmark dominated by hash time. -- Non-Git directory-mtime discovery remains Priority 5. It needs a periodic verification fallback and a manifest migration; do not trade correctness for a speculative warm-run win. -- Add report fields naming the path used: snapshot hit, Git reconciliation, exhaustive scan, module-cache hits, and detailed-graph cache hit. This is low runtime risk and would make future regressions self-diagnosing. -- `buildProjectIndexWithManifestOptions()` still starts project-file and metadata discovery separately on cold/full builds. Measure those walks independently before combining them. - -### Explicitly Deprioritized After Measurement - -- Manifest JSON parsing: about 3-7ms on the current multi-megabyte manifest. -- Manifest/snapshot writing: about 45-120ms when a write is actually required; clean warm runs now skip it. -- Bloom-filter creation in synthetic 300- and 500-file builds: no repeatable material wall-time difference. Persistence remains useful only if a source-reread profile proves otherwise. -- CLI import dispatch: a minimal Node child process and `codegraph --version` both measured around 0.37-0.40s on this workstation, so the observed floor is process launch rather than Codegraph command-module loading. - -## Suggested Execution Order - -- [x] Priority 3 first: smallest, safest, no cross-cutting risk, immediately reduces every discovery call's cost by roughly half. -- [x] Priority 2's `buildProjectIndexIncremental()`-side untracked-file detection shipped before Priority 1's CLI migration, not after: routing `goto`/`refs`/`impact` onto `buildProjectIndexIncremental()` (Priority 1) only became safe once that function could discover new untracked files on its own (previously guaranteed only by callers like `AgentSession` pre-scanning and passing an explicit `files` list, which `goto`/`refs`/`impact` never did). This reordering was discovered during implementation, not anticipated in the original plan text above. -- [x] Priority 1 next: reuses existing, already-tested incremental infrastructure; fixes the most visibly broken commands (`goto`, `refs`, `impact` never benefiting from their own manifest writes). -- [x] Priority 2's `AgentSession`-side fast path (`resolveIncrementalFileList()` wired into `listAgentSessionFiles()`) followed, now benefiting all commands including the ones just fixed in Priority 1. -- [x] Priority 4 immediately followed, reusing the same resolver. -- [ ] Priority 5 not started: Priority 2's real-world git-repo coverage should be observed before deciding whether the non-git gap is worth the added manifest-schema complexity. - -## Validation Checklist - -- [x] `npx vitest run tests/agent-session.test.ts tests/mcp-server.test.ts tests/cache-invalidation.test.ts` -- [x] `npx vitest run tests/cli-command-modules.test.ts tests/impact-analyzer.test.ts` -- [x] `npx vitest run tests/incremental-plan.test.ts tests/git-diff-semantics.test.ts tests/project-file-discovery.test.ts` -- [x] `node ./dist/cli.js doctor` -- [x] `node ./dist/cli.js orient --root . --budget small --json` (timed, warm, before/after) -- [x] `node ./dist/cli.js goto ` (timed, warm, before/after) -- [x] `node ./dist/cli.js impact --base HEAD --head WORKTREE --json` (timed, warm, before/after) -- [x] `npm run check` before concluding major work +Keep this plan only if [the performance measurement backlog](2026-08-03-performance-measurement-backlog.md) demonstrates that representative non-Git projects spend material time in discovery and identifies a reliable target filesystem contract. Otherwise delete it. diff --git a/docs/plans/2026-08-03-performance-measurement-backlog.md b/docs/plans/2026-08-03-performance-measurement-backlog.md new file mode 100644 index 00000000..85789a4f --- /dev/null +++ b/docs/plans/2026-08-03-performance-measurement-backlog.md @@ -0,0 +1,54 @@ +# Performance measurement backlog + +Status: Planned. This file owns measurement and instrumentation work only. It does not authorize an optimization by itself. + +## Goal + +Collect reproducible evidence for the remaining speculative performance ideas before they become implementation plans. Use the existing benchmark corpus and command timing reports instead of one-off stopwatch claims. + +## Measurements + +### Duplicate preprocessing + +- Add a checked-in benchmark scenario with enough repeated units to exercise native and reduced duplicate preprocessing. +- Record elapsed time, units, fingerprints, candidate pairs, omitted counts, and native mode. +- Use parity as a hard contract. Establish a stable baseline before choosing a regression threshold. + +Decision unlocked: whether more duplicate candidate generation should move to Rust. + +### Reference lookup + +- Add a realistic multi-file reference scenario with imports, re-exports, ambiguous names, and negative candidates. +- Record candidate files, files parsed, references verified, cache path, and elapsed time for cold and warm runs. +- Separate candidate selection cost from semantic verification cost. + +Decision unlocked: whether occurrence vectors or additional navigation caches have measurable value. + +### Repeated search + +- Measure repeated MCP symbol, hybrid, text, and path searches in one session and across one-shot processes. +- Record base-index, detailed-graph, content-cache, ranking, and total time separately. +- Compare JavaScript scoring with any native experiment only after the current cache paths are warm and visible. + +Decision unlocked: whether token scoring or text prefilters justify native implementation. + +### Discovery and cache-path observability + +- Add report fields for snapshot hit, Git reconciliation, exhaustive discovery, module-cache hits, and detailed-graph cache hit. +- Measure project-file and metadata discovery separately on cold and exhaustive builds. +- Revisit Git hash enumeration, freshness stat narrowing, and non-Git discovery only when their measured phase dominates a representative scenario. + +Decision unlocked: whether another discovery or manifest change is worth its correctness and migration cost. + +## Output contract + +- Put reusable scenarios and expected fields under `docs/benchmarks/` and the existing benchmark scripts. +- Record environment, revision, native mode, cache state, corpus size, and command arguments with every result. +- Prefer relative comparisons across the same environment. Do not turn workstation-specific timings into universal product promises. +- Any follow-up implementation plan must cite the scenario and measured bottleneck it addresses. + +## Acceptance + +- Each scenario is deterministic, bounded, and runnable from a source checkout. +- Results distinguish cold, warm, one-shot, and long-lived-session behavior. +- Measurement output is sufficient to accept or reject the corresponding optimization without reopening the original audit documents. From c73247410e3f2be512d43903309aa4998d66d143 Mon Sep 17 00:00:00 2001 From: Luke Zehrung Date: Mon, 3 Aug 2026 12:46:58 -0400 Subject: [PATCH 2/2] docs: drop rejected performance plans --- ...-06-performance-and-cache-opportunities.md | 38 ------------------- docs/plans/2026-07-03-plan-priority-index.md | 7 ---- ...2026-07-21-warm-run-discovery-avoidance.md | 21 ---------- 3 files changed, 66 deletions(-) delete mode 100644 docs/plans/2026-06-06-performance-and-cache-opportunities.md delete mode 100644 docs/plans/2026-07-21-warm-run-discovery-avoidance.md diff --git a/docs/plans/2026-06-06-performance-and-cache-opportunities.md b/docs/plans/2026-06-06-performance-and-cache-opportunities.md deleted file mode 100644 index bd9eee8e..00000000 --- a/docs/plans/2026-06-06-performance-and-cache-opportunities.md +++ /dev/null @@ -1,38 +0,0 @@ -# Remaining performance cleanup candidates - -Status: Needs decision. The original audit is complete enough to retire; merged work is preserved in Git history. - -Measurement-only follow-ups moved to [the performance measurement backlog](2026-08-03-performance-measurement-backlog.md). The candidates below are the only unimplemented ideas not already owned by the active native-startup plan. - -## Candidate-test reuse - -Impact, review, coverage suggestions, and `affected` share test-file classification and candidate selection but still create some run-local matchers and candidate maps independently. - -Possible outcome: introduce one prepared per-index or per-run test-candidate context reused by these consumers. - -Decision risk: no current measurement shows this work is material, and `affected` already provides the direct test-selection workflow. Do not implement without a profile showing repeated classification or traversal dominates a representative impact or review run. - -## Navigation lookup caches - -Repeated `goto` and reference verification may revisit receiver, member, and local-scope lookups. - -Possible outcome: add bounded snapshot-owned lookup caches for proven repeated resolver operations. - -Decision risk: cache identity and invalidation complexity can exceed the saved work. The reference-candidate index and persisted Bloom filters already removed broader scans; measure the remaining semantic verification path first. - -## Narrower detailed graph work in impact - -Impact still requests detailed graph context for relevant changed files while some internal graph construction remains project-wide. - -Possible outcome: construct only the detailed graph sections required by the changed-file context while preserving every reported edge, risk, candidate test, and omission count. - -Decision risk: a narrower graph can silently change review output. Require full-output parity and a profile proving detailed graph construction remains a dominant impact phase. - -## Decision - -Review these three candidates as a group: - -- Keep this plan only if at least one candidate has enough expected value to justify a measurement scenario. -- Otherwise delete it. The measurement backlog can create a new implementation plan later if evidence establishes a bottleneck. - -Do not use unchecked items from the retired audit as an implementation queue. diff --git a/docs/plans/2026-07-03-plan-priority-index.md b/docs/plans/2026-07-03-plan-priority-index.md index 9d71398f..4d1f6e0a 100644 --- a/docs/plans/2026-07-03-plan-priority-index.md +++ b/docs/plans/2026-07-03-plan-priority-index.md @@ -17,13 +17,6 @@ This is the live index for plans that still need a decision or implementation. C - `2026-07-03-14-privacy-preserving-diagnostics.md` - `2026-08-03-performance-measurement-backlog.md` -## Needs decision - -- `2026-06-06-performance-and-cache-opportunities.md` - - Three unmeasured cleanup candidates remain after completed and measurement-only work was removed. -- `2026-07-21-warm-run-discovery-avoidance.md` - - Only the non-Git directory-mtime fallback remains; its state and correctness cost may exceed its value. - ## Deferred or rejected - A check-only `upgrade` command is rejected because the name implies an update that it would not perform. diff --git a/docs/plans/2026-07-21-warm-run-discovery-avoidance.md b/docs/plans/2026-07-21-warm-run-discovery-avoidance.md deleted file mode 100644 index 7cf7b4e2..00000000 --- a/docs/plans/2026-07-21-warm-run-discovery-avoidance.md +++ /dev/null @@ -1,21 +0,0 @@ -# Non-Git warm discovery fallback - -Status: Needs decision. Git-backed warm discovery, freshness reuse, symlink-walk avoidance, scoped inspect/review caching, and detailed-symbol-graph persistence are implemented and preserved in Git history. - -## Remaining outcome - -Non-Git projects and strict verification paths still require exhaustive discovery. A possible fallback would persist directory mtimes and skip globbing subtrees whose membership cannot have changed. - -The design would need: - -- explicit manifest schema versioning and an older-schema migration regression -- a periodic exhaustive verification fallback -- documented behavior for network, cloud-sync, overlay, and bind-mounted filesystems whose directory mtimes may be unreliable -- `--cache-verify` as an unconditional exhaustive path -- proof that additions, removals, renames, symlink changes, and ignored-path changes cannot be missed - -## Value gate - -Do not implement this from the historical warm-run measurements. Git reconciliation now covers the primary repository workflow, while the non-Git fallback adds persistent state and correctness risk. - -Keep this plan only if [the performance measurement backlog](2026-08-03-performance-measurement-backlog.md) demonstrates that representative non-Git projects spend material time in discovery and identifies a reliable target filesystem contract. Otherwise delete it.