Skip to content

fix(types): create TriageNodeRow type for triage query results#576

Merged
carlos-alm merged 3 commits intomainfrom
fix/573-triage-node-row-type
Mar 23, 2026
Merged

fix(types): create TriageNodeRow type for triage query results#576
carlos-alm merged 3 commits intomainfrom
fix/573-triage-node-row-type

Conversation

@carlos-alm
Copy link
Copy Markdown
Contributor

Summary

  • Adds TriageNodeRow interface to src/types.ts, extending NodeRow with the computed columns returned by the triage SQL query: fan_in, cognitive, mi, cyclomatic, max_nesting, churn
  • Updates findNodesForTriage return type from NodeRow[] to TriageNodeRow[] across Repository, SqliteRepository, InMemoryRepository, and the standalone query function
  • Replaces the as NodeRow cast in InMemoryRepository with as TriageNodeRow

Closes #573

Test plan

  • All 171 existing unit tests pass (repository, in-memory-repository, repository-parity)
  • Biome lint passes on all changed files

…#573)

findNodesForTriage returns computed columns (fan_in, cognitive, mi,
cyclomatic, max_nesting, churn) that don't exist on the base NodeRow.
Add a dedicated TriageNodeRow interface extending NodeRow and plumb it
through Repository, SqliteRepository, InMemoryRepository, and the
standalone findNodesForTriage function.
@claude
Copy link
Copy Markdown

claude bot commented Mar 23, 2026

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


PR Review Complete ✅

Todo List


Root Cause Analysis

Problem Being Solved: Type safety issue where findNodesForTriage returns SQL query results with computed columns (fan_in, cognitive, mi, cyclomatic, max_nesting, churn) that don't exist on the base NodeRow interface. This creates a type mismatch where callers expect these properties but TypeScript doesn't know they exist.

Why This Approach: The PR properly extends the existing type hierarchy by creating TriageNodeRow extends NodeRow with the additional computed properties, then updates all relevant interfaces and implementations consistently. This maintains backward compatibility while providing proper type safety.

Risk Assessment: Very low risk - purely additive type changes with no runtime behavior modifications.

Phase 2: Configuration Changes

No configuration changes detected - this PR only adds types and updates method signatures.

Phase 3: Test Integrity

All tests still pass - PR description confirms 171 existing unit tests pass, and Biome lint passes. No test modifications were needed since this is purely a type-level change.

Phase 4: Code Quality Assessment

Strengths:

  • Consistent implementation: The change is applied uniformly across all repository implementations (base abstract class, SQLite implementation, in-memory implementation, and standalone function)
  • Proper type hierarchy: TriageNodeRow extends NodeRow maintains the is-a relationship correctly
  • Complete interface coverage: All relevant interfaces (Repository, SqliteRepository, InMemoryRepository) are updated consistently
  • Clear naming: TriageNodeRow clearly indicates its purpose and relationship to triage functionality

Technical Review:

  • src/types.ts:120-127: Clean interface definition with all 6 computed columns from the triage SQL query
  • src/db/repository/base.ts:90: Proper abstract method signature update
  • src/db/repository/sqlite-repository.ts:143: Wrapper method correctly delegates with updated return type
  • src/db/repository/in-memory-repository.ts:289,338: Both method signature and cast updated consistently
  • src/db/repository/nodes.ts:49: Standalone function signature matches the interface

No Issues Found:

  • No security concerns
  • No performance impacts
  • No potential runtime bugs
  • Follows existing code conventions perfectly

Phase 5: Backlog Compliance

Zero-dep: ✅ No new runtime dependencies added - purely type-level changes to existing interfaces

Foundation-aligned: ✅ Fully aligned - this improves type safety for the existing graph query API without violating any principles

Problem-fit: 4/5 - While not directly addressing AI context navigation, this enables more precise tooling by ensuring triage result properties are properly typed. This prevents runtime errors when AI tools or other consumers access these computed metrics.

Breaking: No - This is purely additive. Existing code using findNodesForTriage will continue to work unchanged, but now TypeScript will properly recognize the additional properties.

Tier: 1 (zero-dep ✅ + foundation-aligned ✅)

Critical Concerns

None - This is an exemplary type safety improvement that follows all best practices.

Final Recommendation

  • Rating: ⭐⭐⭐⭐⭐ (5/5)
  • Action: APPROVE
  • Reasoning: This is a textbook example of proper TypeScript migration work. The PR addresses a real type safety issue with a clean, consistent solution that maintains backward compatibility while improving developer experience. The implementation is thorough, touching all relevant files consistently, and the testing confirms no regressions. Changes like this are exactly what should be prioritized during TypeScript migration efforts.

--- | Branch: fix/573-triage-node-row-type

@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps bot commented Mar 23, 2026

Greptile Summary

This PR introduces TriageNodeRow, a dedicated TypeScript interface for the results of findNodesForTriage, replacing the previously inaccurate NodeRow[] return type. Alongside the new type, the SQLite query is updated to SELECT all NodeRow columns (parent_id, exported, qualified_name, scope, visibility) so the runtime shape genuinely satisfies the extends NodeRow contract — addressing the structural gap flagged in the prior review round.

Key changes:

  • src/types.ts: Adds TriageNodeRow extends NodeRow with the six triage-signal fields (fan_in, cognitive, mi, cyclomatic, max_nesting, churn), and updates the Repository interface accordingly.
  • src/db/repository/nodes.ts: Expands the triage SQL SELECT to include all NodeRow columns; return type tightened to TriageNodeRow[].
  • src/db/repository/in-memory-repository.ts: Return type updated; as NodeRow cast replaced with the correct as TriageNodeRow.
  • base.ts / sqlite-repository.ts: Mechanical propagation of the new return type.

The change is purely additive at the type level — TriageNodeRow extends NodeRow, so all existing callers that accepted NodeRow[] continue to work without modification.

Confidence Score: 5/5

  • Safe to merge — type-only improvement with no behavioural changes and all 171 tests passing.
  • The change is additive and backward-compatible: TriageNodeRow extends NodeRow, so no existing consumer breaks. The SQL fix is correct and complete — all five missing NodeRow columns are now included in the SELECT. The in-memory path correctly spreads a full NodeRow before the cast. No logic changes, no new error paths.
  • No files require special attention.

Important Files Changed

Filename Overview
src/types.ts Adds TriageNodeRow interface extending NodeRow with the six triage-signal fields; also updates the Repository interface's findNodesForTriage return type.
src/db/repository/nodes.ts Updates findNodesForTriage return type to TriageNodeRow[] and expands the SQL SELECT to include all NodeRow columns (parent_id, exported, qualified_name, scope, visibility), fulfilling the structural contract implied by extends NodeRow.
src/db/repository/in-memory-repository.ts Updates return type to TriageNodeRow[] and changes the cast from as NodeRow to as TriageNodeRow; the spread of the full NodeRow object plus the computed triage fields satisfies the new interface at runtime.
src/db/repository/base.ts Imports TriageNodeRow and updates the abstract stub findNodesForTriage return type — straightforward propagation of the new type.
src/db/repository/sqlite-repository.ts Imports TriageNodeRow and updates findNodesForTriage return type — delegates to nodes.ts, minimal change.

Class Diagram

%%{init: {'theme': 'neutral'}}%%
classDiagram
    class NodeRow {
        +number id
        +string name
        +AnyNodeKind kind
        +string file
        +number line
        +number|null end_line
        +number|null parent_id
        +0|1|null exported
        +string|null qualified_name
        +string|null scope
        +string|null visibility
        +Role|null role
    }

    class NodeRowWithFanIn {
        +number fan_in
    }

    class TriageNodeRow {
        +number fan_in
        +number cognitive
        +number mi
        +number cyclomatic
        +number max_nesting
        +number churn
    }

    class Repository {
        +findNodesForTriage(opts?) TriageNodeRow[]
    }

    class SqliteRepository {
        +findNodesForTriage(opts?) TriageNodeRow[]
    }

    class InMemoryRepository {
        +findNodesForTriage(opts?) TriageNodeRow[]
    }

    NodeRow <|-- NodeRowWithFanIn
    NodeRow <|-- TriageNodeRow
    Repository <|-- SqliteRepository
    Repository <|-- InMemoryRepository
    Repository ..> TriageNodeRow : returns
Loading

Reviews (2): Last reviewed commit: "fix(types): include all NodeRow columns ..." | Re-trigger Greptile

Comment on lines +120 to +127
export interface TriageNodeRow extends NodeRow {
fan_in: number;
cognitive: number;
mi: number;
cyclomatic: number;
max_nesting: number;
churn: number;
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P2 TriageNodeRow extends NodeRow over-promises available fields

TriageNodeRow extends NodeRow, which tells TypeScript consumers that all NodeRow fields (parent_id, exported, qualified_name, scope, visibility) are present. However, the SQLite-side findNodesForTriage query only selects n.id, n.name, n.kind, n.file, n.line, n.end_line, n.role plus the triage signals — those other NodeRow fields will be undefined at runtime for any SQLite-backed call.

The in-memory path avoids this because it uses { ...n, ... } (spreading a full NodeRow), so that path is fine. But the SQLite path silently violates the structural contract implied by extends NodeRow.

Two ways to fix this:

Option A – extend only the fields the query actually returns, so the type is structurally honest:

/** A node row augmented with triage signals (from findNodesForTriage). */
export interface TriageNodeRow extends NodeRowWithFanIn {
  cognitive: number;
  mi: number;
  cyclomatic: number;
  max_nesting: number;
  churn: number;
}

Then update the SQL SELECT in nodes.ts to also select the remaining NodeRow fields (parent_id, exported, qualified_name, scope, visibility), or alternatively, define a narrower base type with only the fields the query actually returns.

Option B – keep extends NodeRow but update the SQL SELECT to include all NodeRow columns, so the runtime data actually matches the declared type:

n.id, n.name, n.kind, n.file, n.line, n.end_line, n.parent_id,
n.exported, n.qualified_name, n.scope, n.visibility, n.role,
COALESCE(fi.cnt, 0) AS fan_in, ...

Right now no consumer of findNodesForTriage accesses the missing fields, so there is no active bug — but the type contract is misleading and could cause a hard-to-trace undefined if anyone adds such access in the future.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Fixed — updated the SQL SELECT in findNodesForTriage to include all NodeRow columns (parent_id, exported, qualified_name, scope, visibility) so the runtime shape matches the TriageNodeRow extends NodeRow type contract (Option B from your suggestion).

The SQL SELECT only returned id, name, kind, file, line, end_line, role
but TriageNodeRow extends NodeRow which includes parent_id, exported,
qualified_name, scope, and visibility. Add the missing columns so the
runtime shape matches the declared type contract.
@carlos-alm
Copy link
Copy Markdown
Contributor Author

@greptileai

@carlos-alm carlos-alm merged commit 83357e5 into main Mar 23, 2026
15 checks passed
@carlos-alm carlos-alm deleted the fix/573-triage-node-row-type branch March 23, 2026 10:40
@github-actions github-actions bot locked and limited conversation to collaborators Mar 23, 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.

follow-up: create TriageNodeRow type and plumb through Repository hierarchy

1 participant