Skip to content

refactor: Consume /v1/analysis/dead-code API endpoint instead of local graph analysis #8

@jonathanpopham

Description

@jonathanpopham

Summary

The Supermodel public API now exposes a dedicated dead code analysis endpoint at POST /v1/analysis/dead-code (operationId: generateDeadCodeAnalysis). This action should be refactored from performing local graph analysis to being a thin consumer of that endpoint.

Currently, the action:

  1. Zips the repo
  2. Calls generateSupermodelGraph to get the full Supermodel IR (nodes + relationships)
  3. Locally filters Function nodes, checks for callers via calls relationships
  4. Applies heuristic entry-point/export/test filtering in dead-code.ts
  5. Formats results into a PR comment

After this refactor, the action should:

  1. Zip the repo (unchanged)
  2. Call generateDeadCodeAnalysis — the API handles all analysis server-side
  3. Map the API response directly to PR comment / action outputs
  4. No local graph processing needed

Why

  • The API endpoint is smarter — it combines parse graph + call graph, detects transitive dead code, does symbol-level import analysis, and provides confidence levels + reasons
  • Removes ~200 lines of local analysis logic that the API now handles better
  • The API detects entry points server-side (exports, route handlers, main functions) — no need for local heuristics
  • Response includes confidence (high/medium/low) and reason fields for richer reporting
  • Detects more than just functions: classes, methods, interfaces, types, variables, constants

Current Architecture (to be replaced)

src/index.ts

  • Entry point for the GitHub Action
  • Creates zip via git archive
  • Generates idempotency key from commit hash + UUID
  • Calls api.generateSupermodelGraph() via @supermodeltools/sdk
  • Passes raw graph nodes/relationships to findDeadCode()
  • Posts PR comment, sets action outputs
  • Comprehensive error handling with status-code-specific messages

src/dead-code.ts

  • findDeadCode(nodes, relationships, ignorePatterns) — the core local analysis:
    • Filters for Function label nodes
    • Builds set of called function IDs from calls relationships
    • Skips: ignored files, entry point files, entry point function names, exported functions
  • formatPrComment(deadCode) — markdown table formatter
  • Helper functions: isEntryPointFile, isEntryPointFunction, shouldIgnoreFile
  • Constants: DEFAULT_EXCLUDE_PATTERNS, ENTRY_POINT_PATTERNS, ENTRY_POINT_FUNCTION_NAMES

action.yml

  • Inputs: supermodel-api-key, github-token, comment-on-pr, fail-on-dead-code, ignore-patterns
  • Outputs: dead-code-count, dead-code-json
  • Runs on node20, main: dist/index.js

Tests

  • src/__tests__/dead-code.test.ts — unit tests for all local analysis functions
  • src/__tests__/integration.test.ts — end-to-end test calling actual API (skipped without key)

Dependencies

  • @supermodeltools/sdk@^0.4.1 — needs upgrade for new endpoint
  • @actions/core, @actions/exec, @actions/github — standard GH Action libs
  • minimatch@^9.0.0 — for glob pattern matching (may no longer be needed)

New API Endpoint Details

POST /v1/analysis/dead-code
Header: Idempotency-Key, X-Api-Key
Body: multipart/form-data with `file` (zip archive)

Response Schema (DeadCodeAnalysisResponse)

{
  metadata: {
    totalDeclarations: number;
    deadCodeCandidates: number;
    aliveCode: number;
    analysisMethod: string; // e.g. "parse_graph + call_graph"
    rootFilesCount?: number;
    transitiveDeadCount?: number;
    symbolLevelDeadCount?: number;
    analysisStartTime?: string;
    analysisEndTime?: string;
  };
  deadCodeCandidates: Array<{
    file: string;
    name: string;
    line: number;
    type: 'function' | 'class' | 'method' | 'interface' | 'type' | 'variable' | 'constant';
    confidence: 'high' | 'medium' | 'low';
    reason: string;
  }>;
  aliveCode: Array<{
    file: string;
    name: string;
    line: number;
    type: string;
    callerCount: number;
  }>;
  entryPoints: Array<{
    file: string;
    name: string;
    line: number;
    type: string;
    reason: string;
  }>;
}

Async envelope: Returns 202 with { status: "processing", jobId, retryAfter } while processing, then 200 with { status: "completed", jobId, result: DeadCodeAnalysisResponse } when done. The SDK handles polling automatically.

Implementation Plan

1. Update SDK dependency

2. Refactor src/index.ts

  • Replace api.generateSupermodelGraph()api.generateDeadCodeAnalysis()
  • Remove graph node/relationship processing
  • Map response.result.deadCodeCandidates directly to output format
  • Update idempotency key prefix from deadcode to analysis:deadcode
  • Expose richer metadata in action outputs (confidence, reason, type, metadata stats)

3. Simplify src/dead-code.ts

  • Remove findDeadCode() — no longer needed
  • Remove all entry point detection helpers — API handles this
  • Remove DEFAULT_EXCLUDE_PATTERNS, ENTRY_POINT_PATTERNS, ENTRY_POINT_FUNCTION_NAMES
  • Keep formatPrComment() but update to use new response fields:
    • Add Type and Confidence columns to the table
    • Include reason in expandable details
    • Add metadata summary (totalDeclarations, analysis method, etc.)
  • ignore-patterns input can remain for client-side post-filtering (filter by file path)
  • minimatch dependency can stay if we keep ignore-patterns, otherwise remove

4. Update action.yml

  • Consider adding new outputs: metadata-json, alive-code-count, entry-points-json
  • Existing outputs (dead-code-count, dead-code-json) should map cleanly

5. Rewrite tests

  • Unit tests: rewrite to test new response mapping and comment formatting
  • Integration test: update to call generateDeadCodeAnalysis instead of generateCallGraph

6. Update README

  • Update "What it does" section to reflect API-driven analysis
  • Note new capabilities (confidence levels, types beyond functions, transitive detection)

7. Version bump for GH Actions marketplace

  • Bump package.json version
  • Rebuild dist/index.js via npm run build
  • Create new release / update v1 tag

Related

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions