Impact Analysis
Core feature since v5.1 | Enhanced in v7.5-v7.6 | Test mapping in v7.5
Impact Analysis answers three critical questions before every code change:
- "What downstream code might break?" — Blast radius analysis
- "Which tests should I run?" — Targeted test selection
- "Who needs to review this?" — Affected owners identification
This is something LLMs fundamentally cannot do without tooling — they can't reason about the full dependency graph, test mappings, or cross-file relationships at scale.
Table of Contents
- Prerequisites
- Quick Start
- prepareChange Tool (v8.0)
- Single Symbol Impact Analysis
- Git Diff Impact Analysis
- Affected Tests (v7.5)
- Reviewer Suggestions
- Configuration
- CI/CD Integration
- Best Practices
- Limitations
prepareChange Tool (v8.0)
New in v8.0: The prepareChange compound tool combines multiple impact analysis queries into a single call, reducing AI tool invocations by 60-70%.
{
"tool": "prepareChange",
"params": {
"target": "ckb:repo:sym:abc123",
"changeType": "modify"
}
}
Change types: modify | rename | delete | extract
What it returns:
- Direct dependents from
analyzeImpact - Affected tests from
getAffectedTests - Co-change files from
analyzeCoupling - Risk assessment with severity and mitigation suggestions
Example response:
{
"impact": {
"directCallers": 8,
"transitiveCallers": 23,
"blastRadius": { "level": "medium", "modules": 3, "files": 12 }
},
"tests": {
"affected": ["auth_test.go", "handler_test.go"],
"runCommand": "go test ./internal/auth/..."
},
"coupling": {
"coChangeFiles": ["config.go", "middleware.go"],
"correlation": 0.72
},
"risk": {
"level": "medium",
"factors": ["public API", "multiple callers"],
"suggestions": ["Add tests before modifying", "Review callers in api module"]
}
}
When to use prepareChange vs granular tools:
- Use
prepareChangefor most pre-modification analysis (recommended) - Use
analyzeImpactalone when you only need caller information - Use
getAffectedTestsalone when you just need test selection
Prerequisites
Impact analysis quality depends on your indexing setup. Here's what you need for each level of accuracy:
Minimum: Tree-sitter (Fast Tier)
Works out of the box with no additional setup.
- Provides: Basic symbol detection, file-level analysis
- Limitations: No cross-file references, confidence scores are low (0.3)
- Best for: Quick checks, unsupported languages
Recommended: SCIP Index (Standard Tier)
Full semantic analysis with cross-file references.
# Install SCIP indexer for your language
go install github.com/sourcegraph/scip-go/cmd/scip-go@latest # Go
npm install -g @anthropic/scip-typescript # TypeScript
# Generate index
ckb index
Provides:
- Exact symbol definitions and references
- Call graph traversal (callers and callees)
- Transitive impact analysis (depth 2-4)
- High confidence scores (0.85-1.0)
Language support for SCIP:
| Language | Indexer | Quality |
|---|---|---|
| Go | scip-go | Tier 1 (full) |
| TypeScript/JS | scip-typescript | Tier 2 (full, minor edge cases) |
| Python | scip-python | Tier 2 |
| Rust | rust-analyzer | Tier 3 |
| Java/Kotlin | scip-java | Tier 3 |
See Language-Support for full compatibility matrix.
Enhanced: Telemetry Integration (Full Tier)
Add runtime observability for production-aware impact analysis.
{
"telemetry": {
"enabled": true,
"serviceMap": {
"my-api-service": "my-repo"
}
}
}
Provides:
- Observed callers from production traffic
blendedConfidencecombining static + runtime analysis- Detection of dynamic dispatch and reflection calls
- "Observed only" callers that static analysis misses
See Telemetry for setup instructions.
Test Mapping: Coverage Files (v7.5)
For precise test selection, provide coverage data:
Go:
# Generate coverage file
go test -coverprofile=coverage.out ./...
# CKB will auto-detect coverage.out in the project root
JavaScript/TypeScript (Jest):
# Generate lcov coverage
jest --coverage --coverageReporters=lcov
# Coverage will be at coverage/lcov.info
Python (pytest):
# Generate coverage
pytest --cov=. --cov-report=lcov
# Coverage will be at coverage.lcov or lcov.info
Dart (flutter/dart test):
# Generate coverage (Flutter)
flutter test --coverage
# Coverage will be at coverage/lcov.info
Rust (cargo-tarpaulin):
# Install tarpaulin
cargo install cargo-tarpaulin
# Generate coverage
cargo tarpaulin --out Lcov
# Coverage will be at lcov.info
Java (JaCoCo):
# Maven with JaCoCo plugin
mvn test jacoco:report
# Coverage will be at target/site/jacoco/jacoco.xml
# Or configure for lcov output
Provides:
- Precise line-level test mapping
affectedTestsfield in impact analysisckb affected-testscommand
Fallback strategies (when no coverage file):
- Naming convention:
foo.go→foo_test.go - Import analysis: tests importing changed package
- Package-level: all tests in affected directories
See Configuration for custom coverage file locations.
Reviewer Suggestions: CODEOWNERS
For automated reviewer routing, add a CODEOWNERS file:
# .github/CODEOWNERS (GitHub) or CODEOWNERS (GitLab)
# Default owner
* @default-team
# Module-specific owners
/internal/api/ @api-team
/internal/auth/ @security-team
/internal/payments/ @payments-team @finance-team
# File-specific owners
/go.mod @platform-team
Provides:
affectedOwnersin impact analysisckb reviewerscommand- Suggested reviewers in
ckb pr-summary
Without CODEOWNERS, CKB falls back to git blame for ownership signals.
Keeping the Index Fresh
Impact analysis is only as accurate as your index. Stale indexes produce stale results.
# Check freshness
ckb status
# Manual refresh
ckb index
# Watch mode (auto-refresh on file changes)
ckb index --watch
# MCP with watch mode
ckb mcp --watch
Use --strict mode to fail when the index is stale:
ckb impact diff --strict # Fails if index is behind HEAD
Checking Your Setup
Use ckb status to verify impact analysis prerequisites:
$ ckb status
Repository: /Users/lisa/code/myproject
Index: ✓ Fresh (indexed 5 minutes ago, 8,432 symbols)
Language: Go
Change Impact Analysis:
Coverage: ✓ Found (coverage.out, 2 hours old)
CODEOWNERS: ✓ Found (.github/CODEOWNERS, 15 patterns)
Missing components show actionable guidance:
Change Impact Analysis:
Coverage: ⚠ Not found (test mapping will use heuristics)
Generate: go test -coverprofile=coverage.out ./...
CODEOWNERS: ⚠ Not found (reviewer suggestions unavailable)
Create: .github/CODEOWNERS
Quick Start
# 1. Initialize and index
cd /your/project
ckb init
ckb index
# 2. (Optional) Generate coverage for test mapping
go test -coverprofile=coverage.out ./...
# 3. Analyze impact of your changes
ckb impact diff # Uncommitted changes
ckb impact diff --staged # Staged changes only
ckb impact diff --base=main # Compare to branch
# 4. Get affected tests
ckb affected-tests # Tests to run for your changes
ckb affected-tests --output=command # Ready-to-run command
# 5. Get suggested reviewers
ckb reviewers # Who should review this?
Single Symbol Impact Analysis
Analyze what depends on a specific symbol before changing it.
CLI
# Basic impact analysis
ckb impact "UserService.Authenticate"
# With transitive callers (depth 2-4)
ckb impact "Engine.Start" --depth=3
# Include telemetry data
ckb impact "HandleRequest" --include-telemetry
MCP Tool: analyzeImpact
{
"name": "analyzeImpact",
"arguments": {
"symbolId": "scip-go gomod example.com/api internal/auth/user.go/UserService#Authenticate",
"depth": 2,
"includeTelemetry": true,
"telemetryPeriod": "90d"
}
}
Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
symbolId |
string | required | Symbol ID or qualified name |
depth |
number | 2 | Transitive depth (1-4). Depth 1 = direct callers only |
includeTelemetry |
boolean | true | Include runtime observability data |
telemetryPeriod |
string | "90d" | Telemetry window: "7d", "30d", "90d", "all" |
Response
{
"symbol": {
"stableId": "scip-go gomod example.com/api ...",
"name": "Authenticate",
"kind": "function"
},
"visibility": {
"visibility": "public",
"confidence": 0.9
},
"riskScore": {
"score": 0.72,
"level": "high",
"explanation": "High risk: 15 direct caller(s) across 4 module(s).",
"factors": [
{ "name": "visibility", "value": 0.9, "weight": 0.3 },
{ "name": "direct-callers", "value": 0.8, "weight": 0.35 },
{ "name": "module-spread", "value": 0.6, "weight": 0.25 },
{ "name": "impact-kind", "value": 0.7, "weight": 0.1 }
]
},
"blastRadius": {
"moduleCount": 4,
"fileCount": 12,
"uniqueCallerCount": 18,
"riskLevel": "medium"
},
"directImpact": [
{
"stableId": "...",
"name": "LoginHandler",
"kind": "direct-caller",
"distance": 1,
"confidence": 0.95
}
],
"transitiveImpact": [
{
"stableId": "...",
"name": "ServeHTTP",
"kind": "transitive-caller",
"distance": 2,
"confidence": 0.85
}
],
"modulesAffected": [
{ "moduleId": "internal/api", "name": "api", "impactCount": 8 },
{ "moduleId": "internal/auth", "name": "auth", "impactCount": 5 }
],
"observedUsage": {
"hasTelemetry": true,
"totalCalls": 1250,
"trend": "stable"
},
"blendedConfidence": 0.89,
"relatedDecisions": [...],
"docsToUpdate": [...]
}
Blast Radius (v7.6)
The blastRadius field provides a quick summary of impact spread:
| Risk Level | Criteria |
|---|---|
| Low | ≤2 modules AND ≤5 callers |
| Medium | 3-5 modules OR 6-20 callers |
| High | >5 modules OR >20 callers |
Transitive Impact (v7.6)
When depth > 1 and SCIP is available, CKB traces callers-of-callers:
| Depth | Confidence | Use Case |
|---|---|---|
| 1 | 0.95 | Direct callers only |
| 2 | 0.85 | Default, catches most impact |
| 3 | 0.75 | For high-risk refactors |
| 4 | 0.65 | Maximum coverage, more noise |
Risk Score Calculation
Risk is computed from 4 weighted factors:
| Factor | Weight | Description |
|---|---|---|
visibility |
30% | Public symbols are riskier |
direct-callers |
35% | More callers = higher risk |
module-spread |
25% | Cross-module impact is riskier |
impact-kind |
10% | Breaking changes vs additive |
Risk levels:
- Low < 0.4
- Medium 0.4-0.6
- High 0.6-0.8
- Critical > 0.8
Cross-Repo Outgoing Impact (v9.2)
analyzeImpact answers "who depends on this symbol inside this repo". analyzeOutgoingImpact extends that across federated repos by routing through LIP's query_outgoing_impact RPC.
MCP tool: analyzeOutgoingImpact
{
"symbol": "ckb:repo-a:sym:abc123",
"depth": 2
}
Returns per-repo caller counts, aggregated risk, and the LIP edges traversed. Only meaningful when LIP v2.3+ is running across multiple federated repos. Degrades silently to single-repo analyzeImpact semantics if no remote LIPs are reachable.
Symbol Existence Probe (v9.2)
symbolExists is a cheap pre-flight check: returns { exists, confidence, alias_chain? } without loading the full symbol record. Use it in agent planning loops before expensive analyzeImpact or findReferences calls.
Git Diff Impact Analysis
Analyze the impact of pending code changes from git diffs.
CLI
# Analyze current working tree changes
ckb impact diff
# Analyze only staged changes
ckb impact diff --staged
# Compare against a different branch
ckb impact diff --base=main
# Analyze a commit range (for CI)
ckb impact --range=main..HEAD
# Deeper transitive analysis
ckb impact diff --depth=3
# Strict mode (fail if index is stale)
ckb impact diff --strict
# Output formats
ckb impact diff --format=json # Machine-readable JSON
ckb impact diff --format=markdown # PR comment-ready markdown
Output Formats
| Format | Use Case |
|---|---|
text |
Human-readable terminal output (default) |
json |
Machine-readable, for scripting and CI |
markdown |
PR comments, GitHub/GitLab integration |
Markdown Output (--format=markdown)
Generates formatted markdown suitable for PR comments:
ckb impact --range=origin/main..HEAD --format=markdown > comment.md
Example output:
## 🟡 Change Impact Analysis
| Metric | Value |
|--------|------:|
| Risk Level | **medium** |
| Symbols Changed | 12 |
| Directly Affected | 28 |
| Transitively Affected | 45 |
| Modules in Blast Radius | 3 |
### Changed Symbols
- `UserService.Authenticate` (internal/auth/user.go)
- `LoginHandler` (internal/api/login.go)
### Affected Modules
| Module | Impact Count |
|--------|-------------:|
| internal/api | 15 |
| internal/auth | 8 |
| internal/session | 5 |
### Recommendations
- ⚠️ High-risk change affecting 3 modules. Consider additional code review.
- ⚠️ Run tests for affected modules before merging.
This output is designed for the sticky-pull-request-comment GitHub Action pattern.
MCP Tool: analyzeChange
{
"name": "analyzeChange",
"arguments": {
"staged": false,
"baseBranch": "HEAD",
"depth": 2,
"includeTests": false,
"strict": false
}
}
Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
diffContent |
string | - | Raw diff (if empty, uses git diff) |
staged |
boolean | false | Analyze staged changes only |
baseBranch |
string | HEAD | Base for comparison |
depth |
number | 2 | Transitive depth (1-4) |
includeTests |
boolean | false | Include test files |
strict |
boolean | false | Fail if index is stale |
How It Works
Git Diff → Parse Hunks → Map to Symbols → Analyze Impact → Aggregate Results
- Parse Diff: Uses
sourcegraph/go-diffto parse unified diffs - Map to Symbols: Matches changed lines to SCIP symbol definitions
- Analyze Impact: Runs single-symbol impact analysis on each changed symbol
- Aggregate Results: Deduplicates, computes module spread, calculates risk
Response
{
"summary": {
"filesChanged": 5,
"symbolsChanged": 23,
"directlyAffected": 12,
"transitivelyAffected": 45,
"estimatedRisk": "medium"
},
"changedSymbols": [
{
"symbolId": "scip-go gomod example.com/api Handler().",
"name": "Handler",
"file": "internal/api/handler.go",
"changeType": "modified",
"lines": [45, 46, 47],
"confidence": 1.0
}
],
"affectedSymbols": [
{
"stableId": "...",
"name": "ServeHTTP",
"kind": "direct-caller",
"distance": 1,
"moduleId": "internal/server",
"confidence": 0.9
}
],
"blastRadius": {
"moduleCount": 3,
"fileCount": 8,
"uniqueCallerCount": 15,
"riskLevel": "medium"
},
"recommendations": [
{
"type": "review",
"severity": "warning",
"message": "High-risk change affecting 5 modules. Consider additional code review.",
"action": "Request review from module owners"
},
{
"type": "test",
"severity": "warning",
"message": "Significant transitive impact (45 symbols). Run comprehensive test suite.",
"action": "Run full test suite before merging"
}
],
"indexStaleness": {
"isStale": false,
"commitsBehind": 0,
"indexedCommit": "abc123",
"headCommit": "abc123"
}
}
Confidence Scoring
Symbol mapping confidence based on match precision:
| Confidence | Meaning |
|---|---|
| 1.0 | Exact definition line match |
| 0.8 | Change within symbol body |
| 0.7 | Reference on changed line |
| 0.3 | File-level only (no SCIP data) |
Aggregated Risk Scoring
Four weighted factors determine overall risk:
| Factor | Weight | Thresholds |
|---|---|---|
symbols_changed |
20% | >5 = 0.5, >10 = 0.7, >20 = 1.0 |
direct_impact |
30% | >10 = 0.5, >20 = 0.7, >50 = 1.0 |
transitive_impact |
20% | >20 = 0.5, >50 = 0.7, >100 = 1.0 |
module_spread |
30% | >1 = 0.4, >3 = 0.7, >5 = 1.0 |
Risk levels: low (<0.4), medium (0.4-0.6), high (0.6-0.8), critical (>0.8)
Affected Tests (v7.5)
Get a list of tests to run based on your code changes. Dramatically reduces CI time by running only relevant tests.
CLI
# Get tests for uncommitted changes
ckb affected-tests
# Output as runnable command
ckb affected-tests --output=command
# → go test -run 'TestAuth|TestLogin|TestSession' ./...
# Output as simple list (one test per line)
ckb affected-tests --format=list
# → TestAuth
# → TestLogin
# → TestSession
# Specify coverage file location
ckb affected-tests --coverage=./coverage/lcov.info
# Strategy options
ckb affected-tests --strategy=precise # Only tests directly covering changes
ckb affected-tests --strategy=safe # Include transitive tests (default)
ckb affected-tests --strategy=full # All tests in affected packages
MCP Tool: getAffectedTests
{
"name": "getAffectedTests",
"arguments": {
"commit": "HEAD",
"strategy": "safe"
}
}
Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
files |
string[] | - | Changed file paths |
symbols |
string[] | - | Changed symbol IDs |
commit |
string | - | Git commit SHA |
commitRange |
string | - | "base..head" format |
strategy |
string | "safe" | Test selection strategy |
Test Selection Strategies
| Strategy | Description | Use Case |
|---|---|---|
precise |
Only tests that directly cover changed lines | Fast feedback, may miss edge cases |
safe |
Include tests for transitive callers (1 level) | Default, good balance |
full |
All tests in affected packages | Pre-merge, paranoid mode |
Response
{
"strategy": "safe",
"confidence": 0.92,
"tests": [
{
"name": "TestUserAuthenticate",
"path": "internal/auth/user_test.go",
"reason": "Directly covers changed symbol UserService.Authenticate",
"priority": 1
},
{
"name": "TestLoginHandler",
"path": "internal/api/login_test.go",
"reason": "Tests caller of changed symbol",
"priority": 2
}
],
"commands": {
"go": "go test -run 'TestUserAuthenticate|TestLoginHandler' ./internal/..."
},
"warnings": {
"uncoveredSymbols": ["internal/legacy/handler.go:OldFunc"],
"staleData": false
}
}
Confidence Scoring
Confidence reflects data quality:
| Confidence | Data Source |
|---|---|
| 0.95+ | Coverage file with line-level mapping |
| 0.80-0.94 | Naming convention + import analysis |
| 0.60-0.79 | Package-level mapping only |
| < 0.60 | Heuristics, consider running full suite |
CI Integration Example
- name: Run Affected Tests
run: |
# Get test command
CMD=$(ckb affected-tests --output=command --strategy=safe)
CONFIDENCE=$(ckb affected-tests --format=json | jq '.confidence')
if (( $(echo "$CONFIDENCE < 0.7" | bc -l) )); then
echo "Low confidence, running full suite"
go test ./...
else
echo "Running: $CMD"
eval "$CMD"
fi
Reviewer Suggestions
Identify who should review changes based on CODEOWNERS and git history.
CLI
# Get reviewers for uncommitted changes
ckb reviewers
# Include owners of affected (not just changed) code
ckb reviewers --include-affected
# JSON output for scripting
ckb reviewers --format=json
MCP Tool: getChangeOwners
{
"name": "getChangeOwners",
"arguments": {
"commit": "HEAD",
"includeSecondary": true
}
}
Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
files |
string[] | - | Changed file paths |
symbols |
string[] | - | Changed symbol IDs |
commit |
string | - | Git commit SHA |
includeSecondary |
boolean | false | Include owners of affected (not changed) code |
Response
{
"primary": [
{
"owner": "@security-team",
"source": "codeowners",
"pattern": "/internal/auth/*",
"confidence": 1.0
},
{
"owner": "@alice",
"source": "git-blame",
"files": ["internal/auth/user.go"],
"confidence": 0.85
}
],
"secondary": [
{
"owner": "@api-team",
"source": "codeowners",
"reason": "Owns caller of changed symbol",
"confidence": 0.7
}
],
"reviewStrategy": {
"minimum": ["@security-team"],
"recommended": ["@security-team", "@alice", "@api-team"]
}
}
Review Strategy
| Category | Description |
|---|---|
minimum |
Must approve — CODEOWNERS with full match |
recommended |
Should approve — includes secondary owners and git contributors |
CI Integration Example
- name: Request Reviews
run: |
REVIEWERS=$(ckb reviewers --format=json | jq -r '.reviewStrategy.recommended | join(",")')
gh pr edit --add-reviewer "$REVIEWERS"
Configuration
Configure impact analysis behavior in .ckb/config.json:
{
"coverage": {
"paths": [
"coverage.out",
"coverage/lcov.info",
"coverage.lcov"
],
"autoDetect": true,
"maxAge": "168h"
},
"ownership": {
"paths": [
".github/CODEOWNERS",
"CODEOWNERS"
]
},
"impact": {
"defaultDepth": 2,
"strict": false,
"includeTests": true
}
}
| Field | Description |
|---|---|
coverage.paths |
Checked in order, first found wins |
coverage.autoDetect |
Also check common locations (default: true) |
coverage.maxAge |
Warn if older than this (default: 168h / 7 days) |
ownership.paths |
CODEOWNERS file locations |
impact.defaultDepth |
Transitive depth 1-4 (default: 2) |
impact.strict |
Fail on stale index (default: false) |
impact.includeTests |
Include test files in analysis (default: true) |
Environment Variables
| Variable | Description |
|---|---|
CKB_COVERAGE_PATH |
Override coverage file location |
CKB_IMPACT_DEPTH |
Default transitive depth |
CKB_IMPACT_STRICT |
Set to 1 to fail on stale index |
CI/CD Integration
Impact analysis integrates with CI pipelines for automated risk assessment and PR comments.
GitHub Actions: PR Comment Widget
The simplest integration — post impact analysis as a PR comment:
# .github/workflows/impact-comment.yml
name: Impact Comment
on:
pull_request:
types: [opened, synchronize]
permissions:
contents: read
pull-requests: write
jobs:
comment:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Setup CKB
run: npm install -g @tastehub/ckb
- name: Generate Impact Report
run: |
ckb index --if-stale=24h
ckb impact \
--range="${{ github.event.pull_request.base.sha }}..${{ github.sha }}" \
--format=markdown \
> impact.md
- name: Post Comment
uses: marocchino/sticky-pull-request-comment@v2
with:
header: ckb-impact
path: impact.md
The sticky-pull-request-comment action updates the same comment on each push (via header: ckb-impact) instead of creating duplicates.
GitHub Actions: Full Workflow
Complete workflow with risk gates, reviewer assignment, and affected tests:
# .github/workflows/impact-analysis.yml
name: Change Impact Analysis
on:
pull_request:
types: [opened, synchronize, reopened]
permissions:
contents: read
pull-requests: write
checks: write
jobs:
impact:
name: Analyze Impact
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0 # Full history for commit range analysis
- name: Setup CKB
run: npm install -g @tastehub/ckb
- name: Index Repository
run: ckb index --if-stale=24h
- name: Analyze PR Impact
id: impact
run: |
ckb impact \
--range="${{ github.event.pull_request.base.sha }}..${{ github.sha }}" \
--format=json \
> impact.json
echo "risk=$(jq -r '.summary.estimatedRisk' impact.json)" >> $GITHUB_OUTPUT
echo "affected=$(jq -r '.summary.transitivelyAffected' impact.json)" >> $GITHUB_OUTPUT
echo "files=$(jq -r '.summary.filesChanged' impact.json)" >> $GITHUB_OUTPUT
- name: Generate PR Comment
run: |
ckb impact \
--range="${{ github.event.pull_request.base.sha }}..${{ github.sha }}" \
--format=markdown \
> comment.md
- name: Post Impact Summary
uses: marocchino/sticky-pull-request-comment@v2
with:
header: impact-analysis
path: comment.md
- name: Get Suggested Reviewers
id: reviewers
run: |
reviewers=$(ckb reviewers \
--range="${{ github.event.pull_request.base.sha }}..${{ github.sha }}" \
--format=gh)
echo "list=$reviewers" >> $GITHUB_OUTPUT
- name: Request Reviewers
if: steps.reviewers.outputs.list != ''
run: |
gh pr edit ${{ github.event.pull_request.number }} \
--add-reviewer "${{ steps.reviewers.outputs.list }}"
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Risk Gate
if: steps.impact.outputs.risk == 'critical'
run: |
echo "::error::Critical risk detected. Manual review required."
echo "## ⛔ Critical Risk Detected" >> $GITHUB_STEP_SUMMARY
echo "This PR affects critical paths. Please review carefully." >> $GITHUB_STEP_SUMMARY
exit 1
outputs:
risk: ${{ steps.impact.outputs.risk }}
affected: ${{ steps.impact.outputs.affected }}
Risk-Based Test Strategy
Run different test suites based on impact risk:
- name: Determine Test Strategy
run: |
RISK=$(jq -r '.summary.estimatedRisk' impact.json)
MODULES=$(jq '.blastRadius.moduleCount' impact.json)
if [ "$RISK" = "critical" ] || [ "$MODULES" -gt 5 ]; then
echo "Running full test suite"
go test ./...
else
echo "Running affected tests only"
ckb affected-tests --strategy=safe --output=command | bash
fi
Pre-commit Hook
Block critical-risk commits locally:
#!/bin/bash
# .git/hooks/pre-commit
# Check if CKB is installed
if ! command -v ckb &> /dev/null; then
exit 0
fi
RESULT=$(ckb impact diff --staged --format=json 2>/dev/null || echo '{}')
RISK=$(echo "$RESULT" | jq -r '.summary.estimatedRisk // "unknown"')
if [ "$RISK" = "critical" ]; then
echo ""
echo "⛔ CRITICAL RISK DETECTED"
echo " Review the impact before committing:"
echo " $ ckb impact diff --staged"
echo ""
echo " To bypass: git commit --no-verify"
exit 1
elif [ "$RISK" = "high" ]; then
echo "⚠️ HIGH RISK CHANGE - consider running full test suite"
fi
exit 0
Make executable: chmod +x .git/hooks/pre-commit
Ready-to-Use Templates
| Template | Description |
|---|---|
examples/github-actions/impact-comment.yml |
Simple PR comment widget |
examples/github-actions/impact-analysis.yml |
Full workflow with risk gates |
examples/gitlab-ci/ckb.yml |
GitLab CI template |
examples/hooks/pre-commit |
Git pre-commit hook |
examples/hooks/husky/ |
Husky integration for JS/TS |
See CI-CD-Integration for more CI templates and examples/README for installation instructions.
Best Practices
When to Use Each Tool
| Scenario | Tool | Flags |
|---|---|---|
| "What breaks if I change this function?" | ckb impact <symbol> |
--depth=2 |
| "Is this refactor safe?" | ckb impact diff |
--staged |
| "Should I merge this PR?" | ckb impact diff |
--base=main |
| "What tests should I run?" | ckb affected-tests |
--strategy=safe |
| "Who needs to review this?" | ckb reviewers |
--include-affected |
Keeping Coverage Fresh
Coverage data can become stale as tests change. Regenerate periodically:
# In CI: regenerate before impact analysis
- name: Generate Coverage
run: go test -coverprofile=coverage.out ./...
- name: Analyze Impact
run: ckb affected-tests --strategy=safe
CKB warns when coverage is older than max_age (default: 7 days).
Handling Large Diffs
For changes with >20 symbols changed:
- Break into smaller PRs: Use the
splitrecommendation - Use shallow depth:
--depth=1for faster analysis - Focus on high confidence: Filter by
confidence >= 0.7 - Check staleness: Ensure index is fresh with
--strict
Interpreting Low Confidence
Low confidence (< 0.7) means:
- The changed file isn't in the SCIP index
- The language isn't fully supported
- The index is stale
Actions:
- Regenerate index:
ckb index - Check language support:
ckb doctor --tier=standard - For unsupported languages, use file-level analysis
Limitations
- Go has best support: Full SCIP with incremental indexing
- Static analysis only: Can't detect runtime-only dependencies (use telemetry)
- New files: Added files not in the index get low-confidence entries
- Deleted symbols: Deletion detection limited to what was indexed
- Dynamic dispatch: Interface implementations may be missed
- Single-repo only: Cross-repo impact requires federation (planned for future)
- Local coverage files: CKB uses local coverage files, not Codecov/Coveralls APIs
For dynamic dispatch and reflection, use --depth=3 or enable telemetry for observed callers.
Why Local Coverage, Not Codecov API?
CKB uses local coverage files (coverage.out, lcov.info) rather than cloud coverage APIs because:
- No API tokens required — Works immediately without setup
- Precise line-level mapping — Local files contain exact line coverage
- Offline capable — No network dependency for test mapping
- Codecov's "Impact Analysis" is different — Codecov's feature uses OpenTelemetry production telemetry, not test coverage
Generate coverage locally in your CI pipeline before running CKB impact analysis.
Example Prompts
"What will break if I rename
UserService?"
"Analyze the risk of my current changes"
"Is it safe to refactor
LegacyHandler?"
"Show me the blast radius of changing
ProcessPayment"
"What tests should I run for my changes?"
"Who should review this PR?"
"Give me the affected tests as a runnable command"
Related Pages
- MCP-Tools#analyzeImpact - MCP tool reference
- MCP-Tools#analyzeChange - MCP tool reference
- CI-CD-Integration - Full CI/CD workflows
- Telemetry - Runtime observability setup
- Language-Support - SCIP indexer compatibility
- Features#impact-analysis--safety - Feature overview