Skip to content

refactor: consume /v1/analysis/dead-code API endpoint#9

Merged
jonathanpopham merged 4 commits intomainfrom
issue-8/consume-dead-code-api
Feb 11, 2026
Merged

refactor: consume /v1/analysis/dead-code API endpoint#9
jonathanpopham merged 4 commits intomainfrom
issue-8/consume-dead-code-api

Conversation

@jonathanpopham
Copy link
Collaborator

@jonathanpopham jonathanpopham commented Feb 11, 2026

Summary

  • Replaces local graph analysis with the dedicated POST /v1/analysis/dead-code API endpoint
  • The API now handles all analysis server-side: parse graph + call graph combination, transitive dead code propagation, symbol-level import analysis, entry point detection, and confidence scoring
  • Removes ~200 lines of local heuristic code (findDeadCode, entry point patterns, etc.)
  • Enriches PR comments with Type, Confidence columns and collapsible metadata summary
  • Bumps @supermodeltools/sdk to ^0.9.3 and version to 0.2.0

Test plan

  • Unit tests pass (13 passing, 2 integration skipped without key)
  • ncc build compiles cleanly
  • Dogfood CI job runs the action on this repo via uses: ./
  • Verify PR comment output includes new columns (Type, Confidence, metadata)

Closes #8

Summary by CodeRabbit

  • Chores

    • Version bumped to 0.2.0 and package description updated.
    • Supermodel SDK dependency upgraded to ^0.9.3.
  • New Features

    • Polling-based dead-code analysis workflow for async results.
    • PR comments enhanced with confidence badges, richer analysis summary and per-item details.
    • Result filtering via ignore-patterns supported.
    • Improved Markdown escaping for safe table rendering.
  • Documentation

    • README and action metadata updated; new input to enable posting PR comments.

Replace local graph analysis with the dedicated dead code analysis
endpoint. The API now handles parse graph + call graph combination,
transitive dead code propagation, symbol-level import analysis, entry
point detection, and confidence scoring server-side.

- Switch from generateSupermodelGraph to generateDeadCodeAnalysis
- Add async polling for job completion (202 → poll → 200)
- Remove local findDeadCode, entry point heuristics, pattern constants
- Keep filterByIgnorePatterns for client-side post-filtering
- Enrich PR comment with Type, Confidence columns and metadata summary
- Bump @supermodeltools/sdk ^0.4.1 → ^0.9.3
- Bump version 0.1.0 → 0.2.0

Closes #8
@github-actions
Copy link

Dead Code Hunter

No dead code found! Your codebase is clean.

@coderabbitai
Copy link

coderabbitai bot commented Feb 11, 2026

Walkthrough

This PR refactors the action to consume Supermodel's /v1/analysis/dead-code API with async polling, removes local graph heuristics in favor of client-side filtering/formatting of API results, updates PR comment formatting and metadata, adds a Markdown escape helper, updates tests, and bumps package/sdk version.

Changes

Cohort / File(s) Summary
Package Configuration
package.json
Bump version 0.1.00.2.0, update description to reference Supermodel dead code API, upgrade @supermodeltools/sdk ^0.4.1^0.9.3.
Core Dead Code Utilities
src/dead-code.ts
Remove local graph analysis and entry-point heuristics. Add/export filterByIgnorePatterns and formatPrComment. Rework PR comment table to include Type, Confidence, metadata summary, and escape table cells.
Action Entrypoint / API Flow
src/index.ts
Switch to async polling flow (pollForResult + retry constants) for generateDeadCodeAnalysis, change idempotency key prefix to analysis:deadcode, apply filterByIgnorePatterns, and call formatPrComment with metadata; use result.deadCodeCandidates for outputs and fail-on-dead-code logic.
Markdown helpers
src/markdown.ts
Add escapeTableCell(text: string) for safe Markdown table rendering (escapes pipes, removes newlines).
Tests
src/__tests__/dead-code.test.ts, src/__tests__/integration.test.ts
Replace unit tests for removed heuristics with tests for filterByIgnorePatterns and formatPrComment. Integration tests now poll generateDeadCodeAnalysis, validate DeadCodeAnalysisResponse, and assert ignore-pattern filtering and candidate properties.
Docs & Action Manifest
README.md, action.yml
Update wording to reflect unused/dead-code analysis API, add github-token input description, update outputs descriptions and example table to include Confidence and types.

Sequence Diagram

sequenceDiagram
    rect rgba(200,200,255,0.5)
    participant Action as GitHub Action
    end
    rect rgba(200,255,200,0.5)
    participant API as Supermodel API
    end
    rect rgba(255,200,200,0.5)
    participant Result as DeadCodeAnalysisResponse
    end

    Action->>Action: Prepare repo zip + idempotency key (analysis:deadcode:...)
    Action->>API: POST /v1/analysis/dead-code (zip, Idempotency-Key)
    API-->>Action: 202 Accepted {status: processing, jobId, retryAfter}

    loop Poll until completion or timeout
        Action->>Action: sleep(DEFAULT_RETRY_INTERVAL_MS)
        Action->>API: GET/POST with same idempotency key
        API-->>Action: 202 or 200 {status, (result)}
    end

    API-->>Result: 200 {status: completed, result: DeadCodeAnalysisResponse}
    Action->>Action: filterByIgnorePatterns(result.deadCodeCandidates, ignorePatterns)
    Action->>Action: formatPrComment(filteredCandidates, result.metadata)
    Action->>Action: set outputs (dead-code-count, dead-code-json, metadata) + post PR comment
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

Possibly related PRs

From local graphs to API's bright glow,
We poll the cloud and let insights flow,
Candidates listed with confidence and line,
Metadata, badges, and comments refined.
🚀 Dead Code Hunter sails the new pipeline.

🚥 Pre-merge checks | ✅ 4 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 45.45% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'refactor: consume /v1/analysis/dead-code API endpoint' directly captures the main change—moving from local graph analysis to consuming the dedicated API endpoint.
Linked Issues check ✅ Passed All core objectives from issue #8 are implemented: API endpoint migration [#8], SDK dependency bump [#8], response mapping to outputs [#8], removed local analysis logic [#8], enriched PR comments with Type/Confidence [#8], and tests updated [#8].
Out of Scope Changes check ✅ Passed All changes directly align with the refactor objectives; no unrelated modifications detected. Package version bump and description updates support the API migration.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch issue-8/consume-dead-code-api

No actionable comments were generated in the recent review. 🎉

🧹 Recent nitpick comments
src/dead-code.ts (1)

33-42: Consider escaping dc.type and dc.file as well for table safety.

Right now only dc.name goes through escapeTableCell. While it's unlikely, if dc.type or dc.file ever contained a pipe character (|) or newline, the Markdown table would break. Since these values come from an external API, a bit of defensive escaping wouldn't hurt.

For example, imagine the API returns a file path like src/weird|file.ts—the table row would get messed up.

🛡️ Optional defensive fix
       const badge = dc.confidence === 'high' ? ':red_circle:' :
                     dc.confidence === 'medium' ? ':orange_circle:' : ':yellow_circle:';
-      return `| \`${escapeTableCell(dc.name)}\` | ${dc.type} | ${fileLink} | ${lineInfo} | ${badge} ${dc.confidence} |`;
+      return `| \`${escapeTableCell(dc.name)}\` | ${escapeTableCell(dc.type)} | ${escapeTableCell(fileLink)} | ${lineInfo} | ${badge} ${dc.confidence} |`;
src/__tests__/integration.test.ts (1)

120-129: This test always passes—consider removing or documenting intent.

Line 128 has expect(true).toBe(true) which will never fail. This test seems to exist just to print a message about the API key status. That's fine for developer ergonomics, but it might be clearer to either:

  1. Remove the assertion entirely (tests can just log without asserting), or
  2. Add a comment explaining this is intentionally a no-op for messaging purposes

Not a big deal, just a small clarity thing.


Comment @coderabbitai help to get the list of available commands and usage tips.

…ection

Add uncalled functions in dead-code.ts (truncateString, groupByDirectory,
fileSeverity) and a new markdown.ts module (badge, barChart, numberedList,
collapsible, escapeTableCell) to verify the API actually finds dead code.

Integration tests now assert:
- Response shape is valid (metadata, candidates, aliveCode, entryPoints)
- Dead code count > 0
- Every candidate has file, name, line, type, confidence, reason
- Known dead functions are found by name (at least 3 of 6)
- ignore-patterns filtering works against real results
@github-actions
Copy link

Dead Code Hunter

Found 3 potentially unused code elements:

Name Type File Line Confidence
truncateString function src/dead-code.ts#L9 L9 🔴 high
groupByDirectory function src/dead-code.ts#L17 L17 🔴 high
fileSeverity function src/dead-code.ts#L34 L34 🔴 high
Analysis summary
  • Total declarations analyzed: 20
  • Dead code candidates: 3
  • Alive code: 0
  • Analysis method: symbol_level_import_analysis
  • Transitive dead: 0
  • Symbol-level dead: 3

Powered by Supermodel dead code analysis

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@src/index.ts`:
- Around line 168-171: The ignore-patterns input is parsed blindly with
JSON.parse which throws on plain glob strings; change the initialization of
ignorePatterns (currently using core.getInput('ignore-patterns')) to first read
the raw string, return [] if empty, then attempt JSON.parse in a try/catch and
on parse failure fall back to treating the raw input as a single-pattern array
(e.g., [raw]) or [] if raw is blank; update the code around commentOnPr,
failOnDeadCode, and ignorePatterns (references:
core.getInput('ignore-patterns'), ignorePatterns) accordingly to avoid unhandled
exceptions.
🧹 Nitpick comments (1)
src/dead-code.ts (1)

32-40: Consider escaping table cells to avoid broken Markdown.

Example: a symbol named foo|bar will split the table columns. Escaping | (and backticks) keeps the table stable.

Suggested tweak
-  const rows = candidates
+  const escapeCell = (value: string) =>
+    value.replace(/\|/g, '\\|').replace(/`/g, '\\`');
+
+  const rows = candidates
     .slice(0, 50)
     .map(dc => {
       const lineInfo = dc.line ? `L${dc.line}` : '';
-      const fileLink = dc.line ? `${dc.file}#L${dc.line}` : dc.file;
+      const fileLink = dc.line ? `${dc.file}#L${dc.line}` : dc.file;
       const badge = dc.confidence === 'high' ? ':red_circle:' :
                     dc.confidence === 'medium' ? ':orange_circle:' : ':yellow_circle:';
-      return `| \`${dc.name}\` | ${dc.type} | ${fileLink} | ${lineInfo} | ${badge} ${dc.confidence} |`;
+      return `| \`${escapeCell(dc.name)}\` | ${escapeCell(dc.type)} | ${escapeCell(fileLink)} | ${lineInfo} | ${badge} ${dc.confidence} |`;
     })

Comment on lines 168 to 171
const commentOnPr = core.getBooleanInput('comment-on-pr');
const failOnDeadCode = core.getBooleanInput('fail-on-dead-code');
const ignorePatterns = JSON.parse(core.getInput('ignore-patterns') || '[]');
const ignorePatterns: string[] = JSON.parse(core.getInput('ignore-patterns') || '[]');

Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Guard JSON parsing for ignore patterns.

Right now a non-JSON input (e.g., **/*.test.ts) will throw and fail the action. A friendly fallback keeps UX smooth.

Suggested fix
-    const ignorePatterns: string[] = JSON.parse(core.getInput('ignore-patterns') || '[]');
+    let ignorePatterns: string[] = [];
+    try {
+      const raw = core.getInput('ignore-patterns') || '[]';
+      const parsed = JSON.parse(raw);
+      if (!Array.isArray(parsed)) throw new Error('ignore-patterns must be an array');
+      ignorePatterns = parsed;
+    } catch {
+      core.warning('ignore-patterns should be a JSON array, e.g. ["**/*.test.ts"]');
+      ignorePatterns = [];
+    }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const commentOnPr = core.getBooleanInput('comment-on-pr');
const failOnDeadCode = core.getBooleanInput('fail-on-dead-code');
const ignorePatterns = JSON.parse(core.getInput('ignore-patterns') || '[]');
const ignorePatterns: string[] = JSON.parse(core.getInput('ignore-patterns') || '[]');
const commentOnPr = core.getBooleanInput('comment-on-pr');
const failOnDeadCode = core.getBooleanInput('fail-on-dead-code');
let ignorePatterns: string[] = [];
try {
const raw = core.getInput('ignore-patterns') || '[]';
const parsed = JSON.parse(raw);
if (!Array.isArray(parsed)) throw new Error('ignore-patterns must be an array');
ignorePatterns = parsed;
} catch {
core.warning('ignore-patterns should be a JSON array, e.g. ["**/*.test.ts"]');
ignorePatterns = [];
}
🤖 Prompt for AI Agents
In `@src/index.ts` around lines 168 - 171, The ignore-patterns input is parsed
blindly with JSON.parse which throws on plain glob strings; change the
initialization of ignorePatterns (currently using
core.getInput('ignore-patterns')) to first read the raw string, return [] if
empty, then attempt JSON.parse in a try/catch and on parse failure fall back to
treating the raw input as a single-pattern array (e.g., [raw]) or [] if raw is
blank; update the code around commentOnPr, failOnDeadCode, and ignorePatterns
(references: core.getInput('ignore-patterns'), ignorePatterns) accordingly to
avoid unhandled exceptions.

markdown.ts was never imported, so the API treated it as a root file
(entry point) and didn't flag its exports. Now dead-code.ts imports and
uses escapeTableCell, pulling markdown.ts into the import graph. The
remaining unused exports (badge, barChart, collapsible, numberedList)
should now be flagged as dead via symbol-level import analysis.

Also adds diagnostic logging of full analysis results to CI output.
@github-actions
Copy link

Dead Code Hunter

Found 7 potentially unused code elements:

Name Type File Line Confidence
truncateString function src/dead-code.ts#L10 L10 🔴 high
groupByDirectory function src/dead-code.ts#L18 L18 🔴 high
fileSeverity function src/dead-code.ts#L35 L35 🔴 high
collapsible function src/markdown.ts#L8 L8 🔴 high
badge function src/markdown.ts#L15 L15 🔴 high
barChart function src/markdown.ts#L24 L24 🔴 high
numberedList function src/markdown.ts#L40 L40 🔴 high
Analysis summary
  • Total declarations analyzed: 20
  • Dead code candidates: 7
  • Alive code: 0
  • Analysis method: symbol_level_import_analysis
  • Transitive dead: 0
  • Symbol-level dead: 7

Powered by Supermodel dead code analysis

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@src/markdown.ts`:
- Around line 24-28: The barChart function can throw RangeError when max === 0
or value > max; fix by clamping inputs: if max === 0 treat as no capacity (set
filled = 0), otherwise clamp value to the range [0, max], compute filled =
Math.round((clampedValue / max) * width) and set empty = Math.max(0, width -
filled) so neither repeat() receives a negative or non-finite count; update the
barChart function accordingly.
🧹 Nitpick comments (4)
src/markdown.ts (1)

15-19: Heads up: shields.io has special escaping rules for dashes and underscores.

encodeURIComponent won't help here because shields.io uses - as a path separator. If your label or value contains a literal dash (like "dead-code"), it'll get misinterpreted as multiple path segments, and your badge will look funky.

For example:

  • Input: badge("dead-code", "5", "red")
  • Output URL: .../dead-code-5-red → shields.io sees 4 segments instead of 2

Shields.io wants -- for a literal dash and __ for a literal underscore.

💡 Optional fix if you expect special characters
 export function badge(label: string, value: string, color: string): string {
-  const encodedLabel = encodeURIComponent(label);
-  const encodedValue = encodeURIComponent(value);
+  // shields.io uses - as separator; escape -- for dash, __ for underscore
+  const escapeShields = (s: string) =>
+    s.replace(/-/g, '--').replace(/_/g, '__');
+  const encodedLabel = encodeURIComponent(escapeShields(label));
+  const encodedValue = encodeURIComponent(escapeShields(value));
   return `![${label}](https://img.shields.io/badge/${encodedLabel}-${encodedValue}-${color})`;
 }
src/dead-code.ts (2)

9-11: Edge case with small maxLen values

Quick heads up - if someone passes maxLen <= 1, you get some quirky behavior:

  • maxLen = 1 → returns just (the ellipsis)
  • maxLen = 0 → returns all but last char plus (because slice(0, -1))

Probably not a real-world issue since you're likely using this with reasonable lengths like 50+, but a guard like if (maxLen < 2) return '…' would make it bulletproof.


69-73: File links won't be clickable in GitHub

Right now fileLink ends up as something like src/foo.ts#L42 which will just render as plain text in the markdown table. If you want clickable links, you'd need proper markdown syntax.

That said, maybe plain text is intentional here? GitHub PR comments don't always have access to link to the actual file lines anyway (depends on whether it's in the context of the PR). If you do want links, you'd need to construct full URLs which requires repo context.

Just flagging this in case it wasn't intentional - if plain text is fine for your use case, carry on!

src/__tests__/integration.test.ts (1)

12-43: Solid polling implementation with one timing quirk

The logic looks good overall. Nice touches:

  • Respects retryAfter from the API with a sensible default
  • Handles both failed and completed states
  • Has both timeout and max attempts as safety nets

One minor thing: the timeout check on line 34 happens after the API call. So if you're at 119 seconds and the API call takes 30 seconds to respond, you'd be at 149 seconds before the timeout triggers. For integration tests this is probably fine, but if you reuse this helper in production code, you might want to check the timeout before making the call too.

   for (let attempt = 1; attempt <= 30; attempt++) {
+    if (Date.now() - startTime >= timeoutMs) {
+      throw new Error(`Polling timed out after ${timeoutMs}ms`);
+    }
+
     const response: DeadCodeAnalysisResponseAsync = await api.generateDeadCodeAnalysis({

Not a big deal for test code though - just something to keep in mind!

src/markdown.ts Outdated
Comment on lines 24 to 28
export function barChart(value: number, max: number, width = 20): string {
const filled = Math.round((value / max) * width);
const empty = width - filled;
return '\u2588'.repeat(filled) + '\u2591'.repeat(empty);
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Edge cases will throw RangeError at runtime.

Two scenarios that'll crash:

  1. max === 0: You get value / 0 = Infinity, and '█'.repeat(Infinity) throws.
  2. value > max: Say barChart(15, 10)filled = 30, empty = -10, and '░'.repeat(-10) throws.

Both cause RangeError: Invalid count value.

🐛 Proposed fix with clamping
 export function barChart(value: number, max: number, width = 20): string {
+  if (max <= 0) {
+    return '\u2591'.repeat(width); // empty bar when max is invalid
+  }
-  const filled = Math.round((value / max) * width);
+  const ratio = Math.max(0, Math.min(1, value / max)); // clamp to [0, 1]
+  const filled = Math.round(ratio * width);
   const empty = width - filled;
   return '\u2588'.repeat(filled) + '\u2591'.repeat(empty);
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
export function barChart(value: number, max: number, width = 20): string {
const filled = Math.round((value / max) * width);
const empty = width - filled;
return '\u2588'.repeat(filled) + '\u2591'.repeat(empty);
}
export function barChart(value: number, max: number, width = 20): string {
if (max <= 0) {
return '\u2591'.repeat(width); // empty bar when max is invalid
}
const ratio = Math.max(0, Math.min(1, value / max)); // clamp to [0, 1]
const filled = Math.round(ratio * width);
const empty = width - filled;
return '\u2588'.repeat(filled) + '\u2591'.repeat(empty);
}
🤖 Prompt for AI Agents
In `@src/markdown.ts` around lines 24 - 28, The barChart function can throw
RangeError when max === 0 or value > max; fix by clamping inputs: if max === 0
treat as no capacity (set filled = 0), otherwise clamp value to the range [0,
max], compute filled = Math.round((clampedValue / max) * width) and set empty =
Math.max(0, width - filled) so neither repeat() receives a negative or
non-finite count; update the barChart function accordingly.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@src/dead-code.ts`:
- Around line 8-12: truncateString currently misbehaves for tiny limits; add
guards at the start of truncateString to handle maxLen <= 0 and maxLen === 1: if
maxLen <= 0 return an empty string, if maxLen === 1 return the first character
of str (no ellipsis), otherwise preserve the existing logic (for maxLen > 1 use
str.slice(0, maxLen - 1) + '\u2026'); ensure you still handle short strings
where str.length <= maxLen early and reference the truncateString function and
the maxLen parameter in your change.

src/dead-code.ts Outdated
Comment on lines 8 to 12
* Truncates a string to the given max length, appending an ellipsis if needed.
*/
export function isEntryPointFile(filePath: string): boolean {
return ENTRY_POINT_PATTERNS.some(pattern => minimatch(filePath, pattern));
export function truncateString(str: string, maxLen: number): string {
if (str.length <= maxLen) return str;
return str.slice(0, maxLen - 1) + '\u2026';
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Guard truncateString when maxLen is 0 or 1.
Right now maxLen=0 on "abc" returns "ab", which breaks the “max length” contract.

🔧 Small guard for tiny limits
 export function truncateString(str: string, maxLen: number): string {
+  if (maxLen <= 0) return '';
+  if (maxLen === 1) return str.length > 1 ? '\u2026' : str;
   if (str.length <= maxLen) return str;
   return str.slice(0, maxLen - 1) + '\u2026';
 }
🤖 Prompt for AI Agents
In `@src/dead-code.ts` around lines 8 - 12, truncateString currently misbehaves
for tiny limits; add guards at the start of truncateString to handle maxLen <= 0
and maxLen === 1: if maxLen <= 0 return an empty string, if maxLen === 1 return
the first character of str (no ellipsis), otherwise preserve the existing logic
(for maxLen > 1 use str.slice(0, maxLen - 1) + '\u2026'); ensure you still
handle short strings where str.length <= maxLen early and reference the
truncateString function and the maxLen parameter in your change.

@github-actions
Copy link

Dead Code Hunter

Found 7 potentially unused code elements:

Name Type File Line Confidence
truncateString function src/dead-code.ts#L10 L10 🔴 high
groupByDirectory function src/dead-code.ts#L18 L18 🔴 high
fileSeverity function src/dead-code.ts#L35 L35 🔴 high
collapsible function src/markdown.ts#L8 L8 🔴 high
badge function src/markdown.ts#L15 L15 🔴 high
barChart function src/markdown.ts#L24 L24 🔴 high
numberedList function src/markdown.ts#L40 L40 🔴 high
Analysis summary
  • Total declarations analyzed: 20
  • Dead code candidates: 7
  • Alive code: 0
  • Analysis method: symbol_level_import_analysis
  • Transitive dead: 0
  • Symbol-level dead: 7

Powered by Supermodel dead code analysis

Remove test dead code (truncateString, groupByDirectory, fileSeverity,
collapsible, badge, barChart, numberedList) that was used to verify
orphaned file detection. Update README and action.yml to reflect the
new API-driven architecture with confidence levels and broader type
detection. Add escapeTableCell and code type coverage to unit tests.
@github-actions
Copy link

Dead Code Hunter

No dead code found! Your codebase is clean.

@jonathanpopham jonathanpopham merged commit 655e8a4 into main Feb 11, 2026
3 checks passed
@jonathanpopham jonathanpopham deleted the issue-8/consume-dead-code-api branch February 11, 2026 02:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

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

1 participant

Comments