Skip to content

feat: add core TypeScript type definitions (src/types.ts)#516

Merged
carlos-alm merged 4 commits intomainfrom
feat/core-type-definitions
Mar 19, 2026
Merged

feat: add core TypeScript type definitions (src/types.ts)#516
carlos-alm merged 4 commits intomainfrom
feat/core-type-definitions

Conversation

@carlos-alm
Copy link
Contributor

Summary

  • Adds src/types.ts with 153 exported types and interfaces covering the entire codegraph domain model
  • Serves as the migration contract for future TypeScript adoption — each module will be migrated to satisfy its interface
  • Covers all 20 sections: kind enumerations, database row shapes, Repository contract, extractor output types, parser/language registry, import resolution, AST visitor system, analysis engine, CodeGraph model, build pipeline context, configuration, pagination, error codes, feature result shapes (audit, complexity, diff-impact, triage, communities, check, batch, flow, manifesto, exports, path, stats, module-map, roles), registry, MCP server, CLI command interface, risk scoring, sequence diagrams, and graph export formats

Test plan

  • Compiles cleanly with tsc --noEmit --strict --target ES2022
  • Passes Biome lint and format checks
  • Verify types align with runtime shapes via spot-checking key modules

…odel

New file src/types.ts defines 153 exported types and interfaces covering
the entire codegraph domain: symbol/edge kind enumerations, database row
shapes, Repository contract, extractor output types, parser/language
registry, import resolution, AST visitor system, analysis engine,
CodeGraph model, build pipeline context, configuration, pagination,
error codes, all feature result shapes (audit, complexity, diff-impact,
triage, communities, check, batch, flow, manifesto, exports, path,
stats, module-map, roles), registry, MCP server, CLI command interface,
risk scoring, sequence diagrams, and graph export formats.
@claude
Copy link

claude bot commented Mar 19, 2026

Claude finished @carlos-alm's task —— View job


PR Review: Core TypeScript Type Definitions

Conducting comprehensive review of the TypeScript type definitions PR following the 5-phase framework.

Review Progress

  • Phase 1: Root Cause Analysis
  • Phase 2: Configuration Change Detection
  • Phase 3: Test Integrity
  • Phase 4: Code Quality Review
  • Phase 5: Backlog Compliance Assessment
  • Final Assessment and Recommendation

Root Cause Analysis

Problem Being Solved: This PR creates comprehensive TypeScript type definitions (src/types.ts) as a "migration contract" for future TypeScript adoption. The 153 exported types cover the entire codegraph domain model across 20 sections.

Why This Approach: The approach is sensible — creating types upfront establishes the contract before migrating individual modules. This prevents type drift and provides a clear target for each module migration.

Risk Assessment: Low risk. This is purely additive type definitions with no runtime impact.

Configuration Change Detection ✅

No high-risk configuration changes detected:

  • No linting rules disabled or relaxed
  • No test timeouts or coverage thresholds modified
  • No build configuration changes
  • No TypeScript strict mode flags disabled
  • Single file addition only

Test Integrity ✅

No test integrity concerns:

  • No test files modified
  • No assertions removed or weakened
  • PR description indicates clean TypeScript compilation (tsc --noEmit --strict)
  • Biome lint/format checks pass

Code Quality Review

Strengths

  1. Comprehensive coverage: 153 types across all major subsystems
  2. Well-organized: Clear sectional structure with descriptive comments
  3. Consistent naming: Follows established patterns (NodeRow, EdgeRow, etc.)
  4. Backward compatibility: Types align with existing runtime shapes
  5. Documentation: Each section has clear purpose documentation

Specific Analysis

§1 Kind Enumerations: Types match runtime constants in src/shared/kinds.js. Verified CoreSymbolKind matches CORE_SYMBOL_KINDS array.

§2 Database Row Shapes: Field types appear accurate based on SQLite schema and repository queries. Boolean flags correctly typed as 0 | 1 for SQLite.

§3 Repository Interface: Comprehensive interface covering all database operations. Method signatures align with actual SqliteRepository implementation.

§4-20 Additional Sections: Extensive coverage of extractors, parser registry, import resolution, AST analysis, graph model, build pipeline, configuration, and all feature result shapes.

Minor Concerns

  1. Some interfaces may be over-specified: The AST visitor system types are quite detailed for a migration contract
  2. Language ID completeness: Need to verify all supported languages are included in LanguageId union
  3. Version coupling: Types tightly coupled to current implementation — may need updates as features evolve

Backlog Compliance Assessment

Zero-dep: ✓ — No new runtime dependencies. Pure TypeScript definitions.

Foundation-aligned: ✓ — Fully aligned with core principles:

  • No cloud API calls
  • No external infrastructure requirements
  • No code generation or editing
  • Embeddable-first design (provides programmatic API types)
  • Optimizes for development planning (clear migration contract)

Problem-fit: 3/5 — Useful for developers and future TypeScript migration but doesn't directly address the core "AI agents wasting tokens" problem. This is foundation work that enables better tooling but isn't immediately visible to agents.

Breaking: No — Purely additive. No existing behavior changes.

Tier: Tier 1 — Zero-dep ✓ + Foundation-aligned ✓


Critical Concerns

No critical concerns identified. This is a well-executed foundation piece.


Final Recommendation

  • Rating: ⭐⭐⭐⭐☆ (4/5)
  • Action: APPROVE
  • Reasoning: High-quality foundational work that establishes a clear migration contract for TypeScript adoption. Well-organized, comprehensive coverage, and no runtime risks. While not directly addressing the core AI agent problem, it's essential infrastructure for future improvements. The only reason it's not 5 stars is that it's foundation work rather than direct user/agent value.

Recommended Next Steps

  1. Begin migrating core modules (starting with src/shared/kinds.js) to satisfy their type contracts
  2. Set up TypeScript strict checking in CI to prevent type drift
  3. Consider gradual adoption starting with the most stable interfaces

@greptile-apps
Copy link
Contributor

greptile-apps bot commented Mar 19, 2026

Greptile Summary

This PR introduces src/types.ts, a 1609-line TypeScript type contract covering all 20 domain sections of codegraph — kind enumerations, database row shapes, the Repository interface, extractor output, the AST visitor system, the build pipeline context, configuration, pagination, feature result shapes, and graph export formats. It is intended as the migration contract that future modules will satisfy as they are converted to TypeScript.

The file is comprehensive and well-organized. Several issues from the previous review round have been addressed (edge kind narrowing on EdgeRow/AdjacentEdgeRow, ExtendedSymbolKind completeness, mergeCandidates shape, GraphNodeAttrs/GraphEdgeAttrs named fields). Three new issues remain:

  • 'method' type overlap (CoreSymbolKind and ExtendedSymbolKind both include 'method'), making the two unions non-disjoint and preventing reliable type narrowing between top-level and sub-declaration method nodes.
  • SubDeclaration.kind not referencing ExtendedSymbolKind — the inline literal union is an exact copy and will silently drift if ExtendedSymbolKind changes.
  • ComplexityEntry nullability mismatchmaintainabilityIndex and halstead are non-nullable in ComplexityEntry but the underlying ComplexityMetrics row and DefinitionComplexity shape both allow null/absent for these fields, which will require non-null assertions during migration.

Confidence Score: 3/5

  • Safe to merge with minor fixes — the type-only nature of the file means no runtime regression, but three type correctness issues should be resolved before downstream modules are migrated against this contract.
  • The file compiles cleanly and covers the domain comprehensively. However, two P1 logic issues (non-disjoint 'method' in kind unions; non-nullable ComplexityEntry fields that contradict the DB row shape) and one P2 style issue (inline literal vs ExtendedSymbolKind reference in SubDeclaration) reduce confidence. These are best corrected now while the contract is still purely additive, before modules begin depending on these exact shapes.
  • src/types.ts — specifically the kind enumeration section (§1, lines 17–34), SubDeclaration (line 354–360), and ComplexityEntry (lines 1150–1164).

Important Files Changed

Filename Overview
src/types.ts New file adding 153 exported types covering the full codegraph domain; three issues found: 'method' appears in both CoreSymbolKind and ExtendedSymbolKind making them non-disjoint; SubDeclaration.kind duplicates ExtendedSymbolKind as an inline literal instead of referencing it; and ComplexityEntry.maintainabilityIndex/halstead are non-nullable despite the underlying DB/DefinitionComplexity shapes allowing null/absent values.

Class Diagram

%%{init: {'theme': 'neutral'}}%%
classDiagram
    class CoreSymbolKind {
        <<type union>>
        'function' | 'method' | 'class'
        'interface' | 'type' | 'struct'
        'enum' | 'trait' | 'record' | 'module'
    }
    class ExtendedSymbolKind {
        <<type union>>
        'parameter' | 'property'
        'constant' | 'method' ⚠️ overlap
    }
    class SymbolKind {
        <<type union>>
        CoreSymbolKind | ExtendedSymbolKind
    }
    class AnyNodeKind {
        <<type union>>
        SymbolKind | FileNodeKind
    }
    class SubDeclaration {
        name: string
        kind: 'parameter'|'property'|'constant'|'method'
        line: number
    }
    class Definition {
        name: string
        kind: SymbolKind
        line: number
        children?: SubDeclaration[]
    }
    class NodeRow {
        id: number
        kind: AnyNodeKind
        file: string
        role: Role | null
    }
    class EdgeRow {
        id: number
        kind: EdgeKind
        confidence: number | null
    }
    class ComplexityMetrics {
        cognitive: number
        cyclomatic: number
        maintainability_index: number | null
    }
    class ComplexityEntry {
        cognitive: number
        cyclomatic: number
        maintainabilityIndex: number ⚠️ non-nullable
        halstead: HalsteadMetrics ⚠️ non-nullable
    }
    class Repository {
        <<interface>>
        findNodeById()
        findCallees()
        getComplexityForNode()
    }
    CoreSymbolKind --> SymbolKind
    ExtendedSymbolKind --> SymbolKind
    SymbolKind --> AnyNodeKind
    AnyNodeKind --> NodeRow
    Definition --> SubDeclaration
    ExtendedSymbolKind ..> SubDeclaration : should reference
    ComplexityMetrics ..> ComplexityEntry : maps to (nullability mismatch)
    NodeRow --> Repository
    EdgeRow --> Repository
Loading

Last reviewed commit: "fix: narrow edge kin..."

src/types.ts Outdated
Comment on lines +143 to +146
kind: AnyEdgeKind;
confidence: number | null;
dynamic: 0 | 1;
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 EdgeRow.kind is too wide — includes dataflow edge kinds that never appear in the edges table

DataflowEdgeKind values (flows_to, returns, mutates) are stored in a separate dataflow table, not in the main edges table. The runtime code in src/features/dataflow.js inserts these using a separate table alias (d vs e) and the edges table only ever holds EdgeKind values (CoreEdgeKind | StructuralEdgeKind).

Using AnyEdgeKind here makes the type wider than what the database actually produces, allowing downstream code to unsoundly pattern-match on flows_to | returns | mutates for an EdgeRow that will never carry those values.

Suggested change
kind: AnyEdgeKind;
confidence: number | null;
dynamic: 0 | 1;
}
kind: EdgeKind;

The same applies to AdjacentEdgeRow.edge_kind at line 164 — that field is populated via e.kind AS edge_kind from the edges table and should also be narrowed to EdgeKind.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed — EdgeRow.kind now uses EdgeKind instead of AnyEdgeKind. Dataflow edge kinds live in a separate table and never appear in the edges table.

src/types.ts Outdated
| 'module';

/** Sub-declaration kinds (Phase 1). */
export type ExtendedSymbolKind = 'parameter' | 'property' | 'constant';
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 ExtendedSymbolKind and SubDeclaration.kind are misaligned

ExtendedSymbolKind is documented as "Sub-declaration kinds" and only covers 'parameter' | 'property' | 'constant', but SubDeclaration.kind at line 356 also allows 'method'. The actual runtime behaviour confirms this gap: findNodeChildren (in src/db/repository/nodes.js) performs an unfiltered SELECT … FROM nodes WHERE parent_id = ?, meaning nodes with kind = 'method' can and do appear as children of class nodes.

Because SubDeclaration is the TypeScript mirror of "things that appear in a definition's children array", ExtendedSymbolKind is incomplete as currently defined. Any code that accepts ExtendedSymbolKind where a SubDeclaration.kind value is expected will silently reject valid 'method' children.

Consider either:

  • Adding 'method' to ExtendedSymbolKind (and updating its doc comment), or
  • Explicitly expressing SubDeclaration.kind as ExtendedSymbolKind | 'method' so the relationship is clear
Suggested change
export type ExtendedSymbolKind = 'parameter' | 'property' | 'constant';
export type ExtendedSymbolKind = 'parameter' | 'property' | 'constant' | 'method';

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed — added 'method' to ExtendedSymbolKind to match SubDeclaration.kind. findNodeChildren returns method nodes as class children.

Comment on lines +1243 to +1247
modularity: number;
drift: {
splitCandidates: Array<{ directory: string; communityCount: number }>;
mergeCandidates: unknown[];
};
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 mergeCandidates is typed as unknown[] while splitCandidates has a concrete shape

Both fields are members of the same drift sub-object, but splitCandidates has a well-defined element type { directory: string; communityCount: number } while mergeCandidates provides no type information at all. This asymmetry likely means either the merge candidate shape hasn't been settled yet or it was an oversight.

If merge candidates share the same structure as split candidates, align the types:

Suggested change
modularity: number;
drift: {
splitCandidates: Array<{ directory: string; communityCount: number }>;
mergeCandidates: unknown[];
};
drift: {
splitCandidates: Array<{ directory: string; communityCount: number }>;
mergeCandidates: Array<{ directory: string; communityCount: number }>;
};

If the merge candidate shape is genuinely different or still evolving, at minimum add a comment and narrow it to Array<Record<string, unknown>> to signal the intent.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed — mergeCandidates now has the concrete shape from the runtime: { communityId: number; size: number; directoryCount: number; directories: string[] }.

src/types.ts Outdated
Comment on lines +164 to +165
edge_kind: AnyEdgeKind;
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 AdjacentEdgeRow.edge_kind should also be EdgeKind, not AnyEdgeKind

As described in the EdgeRow.kind comment above, edge_kind here is sourced from e.kind AS edge_kind in SQL queries against the main edges table (confirmed in src/db/repository/edges.js). The edges table never stores DataflowEdgeKind values — those live in a separate dataflow table.

Suggested change
edge_kind: AnyEdgeKind;
}
edge_kind: EdgeKind;

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed — AdjacentEdgeRow.edge_kind and ImportEdgeRow.edge_kind both narrowed to EdgeKind.

Comment on lines +709 to +716
export interface GraphNodeAttrs {
[key: string]: unknown;
}

/** Edge attributes stored in the in-memory graph. */
export interface GraphEdgeAttrs {
[key: string]: unknown;
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 GraphNodeAttrs and GraphEdgeAttrs provide no structural type safety

Both are defined as bare index signatures identical to Record<string, unknown>, meaning the CodeGraph model's node and edge attributes carry zero compile-time shape information. Common attribute keys (e.g. kind, file, name, line for nodes; kind, confidence for edges) could be promoted as optional named fields alongside the catch-all index signature. This would give callers useful intellisense and catch obvious attribute typos without over-constraining the flexible graph model.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed — GraphNodeAttrs now has optional named fields (label, kind, file, name, line, dbId) and GraphEdgeAttrs has (kind, confidence, weight), both alongside the catch-all index signature. Derived from actual usage in graph/builders/.

- EdgeRow.kind, AdjacentEdgeRow.edge_kind, ImportEdgeRow.edge_kind now
  use EdgeKind instead of AnyEdgeKind since the edges table never stores
  dataflow edge kinds (those live in a separate table)
- ExtendedSymbolKind now includes 'method' to match SubDeclaration.kind
  which allows methods as class children
- mergeCandidates typed with actual runtime shape instead of unknown[]
- GraphNodeAttrs/GraphEdgeAttrs now have common optional named fields
  alongside the catch-all index signature for better intellisense

Impact: 13 functions changed, 0 affected
@carlos-alm
Copy link
Contributor Author

@greptileai

@carlos-alm carlos-alm merged commit e0ac4df into main Mar 19, 2026
5 checks passed
@carlos-alm carlos-alm deleted the feat/core-type-definitions branch March 19, 2026 06:29
@github-actions github-actions bot locked and limited conversation to collaborators Mar 19, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant