Skip to content

Add impact analysis, test coverage, and circular dependency endpoints#3

Draft
jonathanpopham wants to merge 2 commits intomainfrom
1-add-analysis-endpoints
Draft

Add impact analysis, test coverage, and circular dependency endpoints#3
jonathanpopham wants to merge 2 commits intomainfrom
1-add-analysis-endpoints

Conversation

@jonathanpopham
Copy link

@jonathanpopham jonathanpopham commented Feb 11, 2026

Summary

  • Integrates three new Supermodel API endpoints: impact analysis, test coverage map, and circular dependencies
  • All four endpoints fire concurrently via goroutines; new endpoints degrade gracefully on failure
  • Enriches graph2md markdown with analysis data (frontmatter fields + body sections)
  • Adds coverage bar visualization: per-file progress bars with percentage, file path, and tested/total ratio
  • File entities show function-level tested/untested breakdown; directory entities show sorted child file bars

Test plan

  • Run against a test repository with the staging API endpoints
  • Verify coverage bars render correctly on file entity pages
  • Verify directory/module pages show sorted child file coverage
  • Confirm graceful degradation when analysis endpoints are unavailable
  • Check that existing graph-only flow still works unchanged

Summary by CodeRabbit

Release Notes

  • New Features
    • Added impact analysis with color-coded visual indicators on entity pages
    • Added test coverage metrics display with coverage progress bars
    • Added circular dependency health analysis section
    • Enhanced markdown enrichment with analysis metadata in page frontmatter and sections
    • Improved styling for coverage indicators, status pills, and analysis sections

Calls all three new analysis endpoints in parallel alongside the
existing supermodel graph endpoint. Analysis results are used to
enrich the generated entity pages with:

- Impact analysis: blast radius, risk score, affected entry points
- Test coverage: tested/untested status per function, coverage % per file
- Circular dependencies: cycle membership, severity, breaking suggestions

Adds new pills (impact level, test coverage, dependency health),
new body sections on entity pages, and three new taxonomies for
browsing by impact level, test coverage status, and dependency health.

Analysis endpoints fail gracefully with warnings — the site still
generates normally if any of the new endpoints are unavailable.

Resolves #1
Renders per-file coverage as styled progress bars with percentage,
file path, and tested/total ratio. File entities show function-level
breakdown with check/x indicators. Directory/Module entities show
sorted child file bars.
@coderabbitai
Copy link

coderabbitai bot commented Feb 11, 2026

Walkthrough

The PR adds concurrent API calls to four endpoints (supermodel, impact, test-coverage, circular-deps), introduces response models for analysis data, and implements a markdown enrichment workflow that injects impact metrics, test coverage, and dependency health information into generated documentation files.

Changes

Cohort / File(s) Summary
API Parallelization & Response Models
main.go
Introduces parallelized concurrent goroutines for four API endpoints with shared call logic, adds four new response type structs (ImpactResponse, ImpactEntry, TestCoverageResponse, CircularDepsResponse), and refactors API communication to use dynamic endpoint URLs with generalized postWithZip function.
Markdown Enrichment Logic
main.go
Adds enrichMarkdown function that reads impact, test coverage, and circular dependency JSON responses and injects structured frontmatter and content sections into markdown files; includes helper utilities for frontmatter extraction (extractFrontmatterValue) and HTML/markdown coverage rendering (coverageBarHTML, joinCoverageItems).
Coverage Visualization Styles
templates/_styles.css
Introduces CSS classes for coverage bar UI components (.cov-row, .cov-bar, .cov-fill, .cov-pct, .cov-label, .cov-ratio, .cov-func, .cov-check, .cov-x) and a new .pill-red class for highlighting indicators.
Entity UI Extensions
templates/entity.html
Adds three new header pills (Impact, Test Coverage, Dependency Health) with conditional rendering and color-coding, plus three new detail sections (Impact Analysis, Test Coverage, Circular Dependencies) that display analysis data as lists.

Sequence Diagram

sequenceDiagram
    participant Client as Main Process
    participant SM as Supermodel API
    participant IM as Impact API
    participant TC as Test Coverage API
    participant CD as Circular Deps API
    participant FS as File System
    
    rect rgba(100, 150, 255, 0.5)
    Note over Client,CD: Parallel API Calls
    par Supermodel Call
        Client->>SM: POST /supermodel with zip
        SM-->>Client: graphJSON response
    and Impact Call
        Client->>IM: POST /impact with zip
        IM-->>Client: impactJSON response
    and Test Coverage Call
        Client->>TC: POST /test-coverage with zip
        TC-->>Client: testCoverageJSON response
    and Circular Deps Call
        Client->>CD: POST /circular-deps with zip
        CD-->>Client: circularDepsJSON response
    end
    end
    
    rect rgba(150, 200, 100, 0.5)
    Note over Client,FS: Enrichment & File Writing
    Client->>Client: enrichMarkdown with JSON responses
    Client->>FS: Extract frontmatter & inject enrichment data
    Client->>FS: Write enhanced markdown files with sections
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related issues

  • supermodeltools/supermodel-public-api#392: This PR implements the client-side integration of the Impact, Circular Dependencies, and Test Coverage analysis endpoints that the API issue provides, completing the end-to-end flow for parallel analysis data delivery.

Poem

🚀 Four APIs dance in lockstep rhythm,
Parallel threads weave data wisdom,
Markdown glows with enriched delight,
Coverage bars shine burnished bright.

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately reflects the main change: adding three new API endpoints (impact analysis, test coverage, circular dependencies) alongside the existing infrastructure for parallel calls and markdown enrichment.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ 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 1-add-analysis-endpoints

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

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: 2

🤖 Fix all issues with AI agents
In `@main.go`:
- Around line 416-430: The three os.WriteFile calls for impactJSON,
testCoverageJSON, and circularDepsJSON currently ignore errors; update each
block (the branches guarding impactJSON, testCoverageJSON, circularDepsJSON) to
capture the error returned by os.WriteFile and, on error, log a warning with
fmt.Printf (or a logger) that includes the file path (constructed with
filepath.Join(tmpDir, "...")) and the error details instead of silently
swallowing it; keep the existing success printf behavior.
- Line 1246: The os.WriteFile call currently ignores its error; change the call
at os.WriteFile(path, []byte(newContent), info.Mode()) to capture the returned
error and handle it: if err != nil, log a warning that includes the filename
(path) and the error (and optionally the content length or mode for context)
using your project's logger (or log.Printf) so write failures are visible and
actionable; ensure you keep the same variables (path, newContent, info.Mode())
when reporting the error.
🧹 Nitpick comments (5)
templates/_styles.css (1)

189-189: Consider using modern CSS color notation.

The static analysis tool flags the legacy rgba() syntax. Modern CSS prefers rgb(255 255 255 / 6%) over rgba(255,255,255,0.06). It's functionally the same but aligns with current CSS specs.

💅 Proposed fix
-.cov-bar { width: 120px; height: 10px; background: rgba(255,255,255,0.06); border-radius: 3px; overflow: hidden; flex-shrink: 0; }
+.cov-bar { width: 120px; height: 10px; background: rgb(255 255 255 / 6%); border-radius: 3px; overflow: hidden; flex-shrink: 0; }
main.go (4)

1086-1094: The impact level logic works but could be clearer.

Right now you have two separate if blocks where the second one (> 100) can override the first. It works, but reading it makes you do a double-take.

Think of it like: if someone is 25 years old, you don't first say "they're a teenager" then correct yourself to "actually an adult." Just check the thresholds in descending order:

♻️ Cleaner threshold ordering
 level := "Low"
-if impact.BlastRadius.RiskScore >= 30 {
+if impact.BlastRadius.RiskScore > 100 {
+	level = "Critical"
+} else if impact.BlastRadius.RiskScore >= 30 {
 	level = "High"
 } else if impact.BlastRadius.RiskScore >= 10 {
 	level = "Medium"
 }
-if impact.BlastRadius.RiskScore > 100 {
-	level = "Critical"
-}

1153-1159: Consider escaping HTML in function names.

The name variable gets dropped directly into HTML. While function names from parsed code are usually safe identifiers, if one somehow contained <script>alert(1)</script> (maybe from a weird edge case or API bug), you'd have broken HTML or worse.

Go has html.EscapeString() in the html package for exactly this:

🛡️ Escape names before interpolation

Add to imports:

import "html"

Then wrap the names:

 for _, name := range testedNamesInFile[filePath] {
-	covLines = append(covLines, fmt.Sprintf(`<span class="cov-func"><span class="cov-check">✓</span> %s</span>`, name))
+	covLines = append(covLines, fmt.Sprintf(`<span class="cov-func"><span class="cov-check">✓</span> %s</span>`, html.EscapeString(name)))
 }
 for _, name := range untestedNamesInFile[filePath] {
-	covLines = append(covLines, fmt.Sprintf(`<span class="cov-func"><span class="cov-x">✗</span> %s</span>`, name))
+	covLines = append(covLines, fmt.Sprintf(`<span class="cov-func"><span class="cov-x">✗</span> %s</span>`, html.EscapeString(name)))
 }

1268-1285: Same escaping concern for the label parameter.

File paths are generally safe, but same principle applies - if a file path contains & or <, you'd get malformed HTML.

🛡️ Escape label in coverageBarHTML
+import "html"

 func coverageBarHTML(label string, pct float64, tested, total int) string {
 	color := "var(--red)"
 	if pct >= 80 {
 		color = "var(--green)"
 	} else if pct > 0 {
 		color = "var(--orange)"
 	}
 	return fmt.Sprintf(
 		`<div class="cov-row">`+
 			`<div class="cov-bar"><div class="cov-fill" style="width:%.1f%%;background:%s"></div></div>`+
 			`<span class="cov-pct">%.1f%%</span>`+
 			`<span class="cov-label">%s</span>`+
 			`<span class="cov-ratio">(%d/%d)</span>`+
 			`</div>`,
-		pct, color, pct, label, tested, total,
+		pct, color, pct, html.EscapeString(label), tested, total,
 	)
 }

1049-1049: filepath.Walk return value is ignored.

If contentDir doesn't exist or has permission issues, Walk returns an error but this code just moves on. In practice the directory should exist since main() creates it, but for defensive coding you might want to at least log it:

♻️ Handle Walk error
-	filepath.Walk(contentDir, func(path string, info os.FileInfo, err error) error {
+	if err := filepath.Walk(contentDir, func(path string, info os.FileInfo, err error) error {
 		// ... existing callback ...
-	})
+	}); err != nil {
+		fmt.Printf("::warning::Error walking content dir: %v\n", err)
+	}

Comment on lines +416 to +430
if impactJSON != nil {
p := filepath.Join(tmpDir, "impact.json")
os.WriteFile(p, impactJSON, 0644)
fmt.Printf("Impact analysis saved to %s\n", p)
}
if testCoverageJSON != nil {
p := filepath.Join(tmpDir, "test-coverage.json")
os.WriteFile(p, testCoverageJSON, 0644)
fmt.Printf("Test coverage saved to %s\n", p)
}
if circularDepsJSON != nil {
p := filepath.Join(tmpDir, "circular-deps.json")
os.WriteFile(p, circularDepsJSON, 0644)
fmt.Printf("Circular dependencies saved to %s\n", p)
}
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

Ignored errors on WriteFile could hide problems.

You're handling the graph.json write error properly (lines 411-413), but the other three writes silently swallow errors. If one of these fails (disk full, permissions, etc.), you'd never know.

Since these are optional/degradable, a warning makes sense rather than failing:

🔧 Proposed fix: log warnings on write failures
 	if impactJSON != nil {
 		p := filepath.Join(tmpDir, "impact.json")
-		os.WriteFile(p, impactJSON, 0644)
-		fmt.Printf("Impact analysis saved to %s\n", p)
+		if err := os.WriteFile(p, impactJSON, 0644); err != nil {
+			fmt.Printf("::warning::Failed to save impact analysis: %v\n", err)
+		} else {
+			fmt.Printf("Impact analysis saved to %s\n", p)
+		}
 	}
 	if testCoverageJSON != nil {
 		p := filepath.Join(tmpDir, "test-coverage.json")
-		os.WriteFile(p, testCoverageJSON, 0644)
-		fmt.Printf("Test coverage saved to %s\n", p)
+		if err := os.WriteFile(p, testCoverageJSON, 0644); err != nil {
+			fmt.Printf("::warning::Failed to save test coverage: %v\n", err)
+		} else {
+			fmt.Printf("Test coverage saved to %s\n", p)
+		}
 	}
 	if circularDepsJSON != nil {
 		p := filepath.Join(tmpDir, "circular-deps.json")
-		os.WriteFile(p, circularDepsJSON, 0644)
-		fmt.Printf("Circular dependencies saved to %s\n", p)
+		if err := os.WriteFile(p, circularDepsJSON, 0644); err != nil {
+			fmt.Printf("::warning::Failed to save circular deps: %v\n", err)
+		} else {
+			fmt.Printf("Circular dependencies saved to %s\n", p)
+		}
 	}
🤖 Prompt for AI Agents
In `@main.go` around lines 416 - 430, The three os.WriteFile calls for impactJSON,
testCoverageJSON, and circularDepsJSON currently ignore errors; update each
block (the branches guarding impactJSON, testCoverageJSON, circularDepsJSON) to
capture the error returned by os.WriteFile and, on error, log a warning with
fmt.Printf (or a logger) that includes the file path (constructed with
filepath.Join(tmpDir, "...")) and the error details instead of silently
swallowing it; keep the existing success printf behavior.

}

newContent := newFrontmatter + "\n---\n" + newBody
os.WriteFile(path, []byte(newContent), info.Mode())
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

Another ignored WriteFile error.

Same pattern as the JSON saves - if this fails, the file doesn't get enriched and you'd never know. At minimum, logging a warning helps debugging:

🔧 Log write failures
-		os.WriteFile(path, []byte(newContent), info.Mode())
-		enriched++
+		if err := os.WriteFile(path, []byte(newContent), info.Mode()); err != nil {
+			fmt.Printf("::warning::Failed to enrich %s: %v\n", path, err)
+		} else {
+			enriched++
+		}
📝 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
os.WriteFile(path, []byte(newContent), info.Mode())
if err := os.WriteFile(path, []byte(newContent), info.Mode()); err != nil {
fmt.Printf("::warning::Failed to enrich %s: %v\n", path, err)
} else {
enriched++
}
🤖 Prompt for AI Agents
In `@main.go` at line 1246, The os.WriteFile call currently ignores its error;
change the call at os.WriteFile(path, []byte(newContent), info.Mode()) to
capture the returned error and handle it: if err != nil, log a warning that
includes the filename (path) and the error (and optionally the content length or
mode for context) using your project's logger (or log.Printf) so write failures
are visible and actionable; ensure you keep the same variables (path,
newContent, info.Mode()) when reporting the error.

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.

1 participant

Comments