Technical debt identification, quantification, and prioritization for informed remediation planning
Identifies, quantifies, and prioritizes technical debt using principal/interest models and impact analysis.
/plugin marketplace add melodic-software/claude-code-plugins/plugin install estimation-planning@melodic-softwareThis skill is limited to using the following tools:
Use this skill when:
Systematic identification, quantification, and prioritization of technical debt to enable informed decisions about remediation investments.
Before providing tech debt guidance:
docs-management skill for code quality documentation Deliberate
│
┌─────────────┼─────────────┐
│ │ │
│ Prudent/ │ Reckless/ │
│ Deliberate │ Deliberate │
│ │ │
│ "We know │ "We don't │
│ the trade- │ have time │
│ offs" │ for design" │
Prudent ──┼─────────────┼─────────────┼── Reckless
│ │ │
│ Prudent/ │ Reckless/ │
│ Inadvertent │ Inadvertent │
│ │ │
│ "Now we │ "What's │
│ know how │ layering?" │
│ to do it" │ │
└─────────────┼─────────────┘
│
Inadvertent
public enum DebtQuadrant
{
PrudentDeliberate, // Conscious trade-off for business reasons
PrudentInadvertent, // Learned better approach after implementation
RecklessDeliberate, // Cut corners knowingly
RecklessInadvertent // Don't know good practices
}
public enum DebtCategory
{
// Code Level
CodeSmells, // Duplications, long methods, dead code
TestingDebt, // Missing tests, flaky tests, slow tests
DocumentationDebt, // Missing/outdated docs, tribal knowledge
// Design Level
DesignDebt, // Violated principles, poor abstractions
DependencyDebt, // Outdated libraries, version conflicts
ConfigurationDebt, // Hardcoded values, environment coupling
// Architecture Level
ArchitectureDebt, // Violated boundaries, coupling, scalability limits
InfrastructureDebt, // Manual processes, poor CI/CD, missing monitoring
SecurityDebt // Known vulnerabilities, outdated practices
}
public sealed record TechnicalDebtItem(
string Id,
string Title,
string Description,
DebtCategory Category,
DebtQuadrant Quadrant,
string Location, // File(s), module, service
DebtSeverity Severity,
DebtQuantification Quantification,
DebtImpact Impact,
string Origin, // When/how debt was introduced
DateOnly IdentifiedDate,
string IdentifiedBy,
DebtStatus Status);
public enum DebtSeverity
{
Low, // Minor inconvenience
Medium, // Noticeable slowdown
High, // Significant impediment
Critical // Blocking development
}
public enum DebtStatus
{
Identified,
Analyzed,
Prioritized,
Scheduled,
InProgress,
Resolved,
Accepted // Deliberately not addressing
}
public sealed record DebtQuantification(
decimal Principal, // Cost to fix now (hours or $)
decimal InterestRate, // Additional cost per time period (%)
TimeSpan PaymentPeriod, // How often interest compounds
decimal AccruedInterest, // Interest already accumulated
decimal TotalOwed, // Principal + Accrued Interest
DateOnly BreakEvenDate); // When fixing pays for itself
public sealed class DebtCalculator
{
/// <summary>
/// Calculate when paying off debt becomes worthwhile
/// </summary>
public DebtQuantification Quantify(
decimal fixCostHours,
decimal hourlyRate,
decimal weeklyInterestHours,
int weeksAccrued)
{
var principal = fixCostHours * hourlyRate;
var weeklyInterest = weeklyInterestHours * hourlyRate;
var interestRate = weeklyInterest / principal;
var accruedInterest = weeklyInterest * weeksAccrued;
var totalOwed = principal + accruedInterest;
// Break even when cumulative interest > principal
var weeksToBreakEven = (int)Math.Ceiling(principal / weeklyInterest);
return new DebtQuantification(
Principal: principal,
InterestRate: interestRate,
PaymentPeriod: TimeSpan.FromDays(7),
AccruedInterest: accruedInterest,
TotalOwed: totalOwed,
BreakEvenDate: DateOnly.FromDateTime(DateTime.UtcNow.AddDays(weeksToBreakEven * 7)));
}
}
public static class DebtInterestExamples
{
/// <summary>
/// Missing unit tests: extra debugging time per bug
/// </summary>
public static DebtQuantification MissingTestsDebt(
int untestedMethods,
decimal debuggingHoursPerBug,
decimal bugsPerMonth,
decimal testWritingHoursPerMethod)
{
var principal = untestedMethods * testWritingHoursPerMethod;
var monthlyInterest = debuggingHoursPerBug * bugsPerMonth;
return new DebtQuantification(
Principal: principal,
InterestRate: monthlyInterest / principal,
PaymentPeriod: TimeSpan.FromDays(30),
AccruedInterest: 0,
TotalOwed: principal,
BreakEvenDate: DateOnly.FromDateTime(DateTime.UtcNow.AddMonths(
(int)Math.Ceiling(principal / monthlyInterest))));
}
/// <summary>
/// Legacy framework: time spent on workarounds
/// </summary>
public static DebtQuantification LegacyFrameworkDebt(
decimal migrationCostHours,
decimal weeklyWorkaroundHours)
{
return new DebtQuantification(
Principal: migrationCostHours,
InterestRate: weeklyWorkaroundHours / migrationCostHours,
PaymentPeriod: TimeSpan.FromDays(7),
AccruedInterest: 0,
TotalOwed: migrationCostHours,
BreakEvenDate: DateOnly.FromDateTime(DateTime.UtcNow.AddDays(
(int)Math.Ceiling(migrationCostHours / weeklyWorkaroundHours) * 7)));
}
}
public sealed class DebtIdentifier
{
public async Task<IReadOnlyList<TechnicalDebtItem>> IdentifyFromAnalysis(
string projectPath)
{
var debts = new List<TechnicalDebtItem>();
// Code quality tools
debts.AddRange(await RunSonarQube(projectPath));
debts.AddRange(await RunCodeClimate(projectPath));
// Dependency analysis
debts.AddRange(await AnalyzeDependencies(projectPath));
// Test coverage gaps
debts.AddRange(await AnalyzeTestCoverage(projectPath));
// Documentation analysis
debts.AddRange(await AnalyzeDocumentation(projectPath));
// Architecture conformance
debts.AddRange(await CheckArchitectureRules(projectPath));
return debts;
}
private async Task<IEnumerable<TechnicalDebtItem>> AnalyzeDependencies(
string projectPath)
{
// Check for outdated packages
// dotnet list package --outdated
// npm outdated
var outdated = await GetOutdatedPackages(projectPath);
return outdated.Select(pkg => new TechnicalDebtItem(
Id: $"DEP-{pkg.Name}",
Title: $"Outdated: {pkg.Name}",
Description: $"Package {pkg.Name} is {pkg.VersionsBehind} versions behind. Current: {pkg.CurrentVersion}, Latest: {pkg.LatestVersion}",
Category: DebtCategory.DependencyDebt,
Quadrant: DebtQuadrant.PrudentInadvertent,
Location: pkg.ProjectFile,
Severity: pkg.HasSecurityIssues ? DebtSeverity.Critical : DebtSeverity.Medium,
Quantification: EstimateUpgradeEffort(pkg),
Impact: AssessDependencyImpact(pkg),
Origin: "Dependency became outdated over time",
IdentifiedDate: DateOnly.FromDateTime(DateTime.UtcNow),
IdentifiedBy: "Automated scan",
Status: DebtStatus.Identified));
}
}
public static class CommonDebtPatterns
{
public static IEnumerable<DebtPattern> GetPatterns()
{
yield return new DebtPattern(
Name: "God Class",
Category: DebtCategory.DesignDebt,
Indicators: new[] { "Class > 500 lines", "Class has > 20 methods", "Low cohesion" },
TypicalPrincipal: "8-40 hours to refactor",
TypicalInterest: "1-2 hours/week in confusion and merge conflicts");
yield return new DebtPattern(
Name: "Duplicated Code",
Category: DebtCategory.CodeSmells,
Indicators: new[] { "Copy-paste violations", "Similar logic in multiple places" },
TypicalPrincipal: "1-4 hours per duplication",
TypicalInterest: "0.5-1 hours per change (must update multiple places)");
yield return new DebtPattern(
Name: "Missing Tests",
Category: DebtCategory.TestingDebt,
Indicators: new[] { "Low code coverage", "Fear of refactoring", "Bugs in production" },
TypicalPrincipal: "0.5-2 hours per method",
TypicalInterest: "2-4 hours per bug in debugging");
yield return new DebtPattern(
Name: "Hardcoded Configuration",
Category: DebtCategory.ConfigurationDebt,
Indicators: new[] { "Magic strings", "Environment-specific values in code" },
TypicalPrincipal: "0.5-1 hour per instance",
TypicalInterest: "Deployment failures, environment issues");
yield return new DebtPattern(
Name: "Outdated Documentation",
Category: DebtCategory.DocumentationDebt,
Indicators: new[] { "Docs don't match code", "Tribal knowledge", "Onboarding issues" },
TypicalPrincipal: "4-8 hours per component",
TypicalInterest: "1-2 hours per new team member onboarding");
yield return new DebtPattern(
Name: "Monolithic Architecture",
Category: DebtCategory.ArchitectureDebt,
Indicators: new[] { "Tight coupling", "Deployment bottleneck", "Can't scale independently" },
TypicalPrincipal: "Months of refactoring",
TypicalInterest: "Slower releases, harder scaling");
}
}
public sealed record DebtImpact(
DeveloperProductivityImpact Productivity,
QualityImpact Quality,
VelocityImpact Velocity,
MoraleImpact Morale,
BusinessImpact Business);
public sealed record DeveloperProductivityImpact(
int AffectedDevelopers,
decimal HoursLostPerWeek,
string Description);
public sealed record QualityImpact(
int AdditionalBugsPerMonth,
bool IncreasesSecurityRisk,
bool ReducesReliability,
string Description);
public sealed record VelocityImpact(
decimal DeliverySlowdownPercent,
bool BlocksNewFeatures,
int FeaturesBlocked,
string Description);
public sealed record MoraleImpact(
bool CausesFrustration,
bool ContributesToBurnout,
bool AffectsRetention,
string Description);
public sealed record BusinessImpact(
decimal RevenueLossPerMonth,
decimal CustomerChurnRisk,
bool AffectsCompliance,
string Description);
public sealed class ImpactScorer
{
public int CalculateImpactScore(DebtImpact impact)
{
var score = 0;
// Productivity (0-25 points)
score += Math.Min(25, impact.Productivity.AffectedDevelopers *
(int)impact.Productivity.HoursLostPerWeek);
// Quality (0-25 points)
score += impact.Quality.IncreasesSecurityRisk ? 15 : 0;
score += impact.Quality.ReducesReliability ? 10 : 0;
// Velocity (0-25 points)
score += impact.Velocity.BlocksNewFeatures ? 20 : 0;
score += Math.Min(5, impact.Velocity.FeaturesBlocked);
// Business (0-25 points)
score += impact.Business.AffectsCompliance ? 25 : 0;
score += impact.Business.CustomerChurnRisk > 0.1m ? 15 : 0;
return Math.Min(100, score);
}
}
public sealed class DebtPrioritizer
{
public IReadOnlyList<TechnicalDebtItem> Prioritize(
IEnumerable<TechnicalDebtItem> debts)
{
return debts
.Select(d => (Debt: d, Score: CalculatePriorityScore(d)))
.OrderByDescending(x => x.Score)
.Select(x => x.Debt)
.ToList();
}
private double CalculatePriorityScore(TechnicalDebtItem debt)
{
// Weighted scoring
var impactScore = CalculateImpactScore(debt.Impact) * 0.4;
var effortScore = (100 - CalculateEffortScore(debt.Quantification.Principal)) * 0.2;
var interestScore = CalculateInterestScore(debt.Quantification) * 0.3;
var ageScore = CalculateAgeScore(debt.IdentifiedDate) * 0.1;
return impactScore + effortScore + interestScore + ageScore;
}
private double CalculateInterestScore(DebtQuantification quantification)
{
// Higher interest rate = higher priority
return Math.Min(100, (double)quantification.InterestRate * 1000);
}
private double CalculateAgeScore(DateOnly identifiedDate)
{
// Older debt gets slightly higher priority (avoid perpetual deferral)
var age = DateOnly.FromDateTime(DateTime.UtcNow).DayNumber - identifiedDate.DayNumber;
return Math.Min(100, age / 3.65); // Max score at 1 year old
}
}
public sealed class CostOfDelayPrioritizer
{
/// <summary>
/// CD3: Cost of Delay Divided by Duration
/// Higher values = higher priority
/// </summary>
public double CalculateCD3(TechnicalDebtItem debt)
{
// Cost of Delay = Weekly interest being paid
var weeklyInterest = debt.Quantification.InterestRate *
debt.Quantification.Principal;
// Duration = Time to fix (in weeks)
var durationWeeks = (double)debt.Quantification.Principal / 40; // 40 hour weeks
return (double)weeklyInterest / durationWeeks;
}
public IReadOnlyList<TechnicalDebtItem> PrioritizeByCD3(
IEnumerable<TechnicalDebtItem> debts)
{
return debts
.Select(d => (Debt: d, CD3: CalculateCD3(d)))
.OrderByDescending(x => x.CD3)
.Select(x => x.Debt)
.ToList();
}
}
public enum RemediationStrategy
{
PayOff, // Fix completely
Refinance, // Reduce interest without full fix
Consolidate, // Combine multiple debts into one fix
Accept, // Acknowledge and don't fix
Strangler, // Gradually replace
ScheduledPayment // Fix incrementally over time
}
public sealed record RemediationPlan(
IReadOnlyList<TechnicalDebtItem> Debts,
RemediationStrategy Strategy,
TimeSpan EstimatedDuration,
decimal EstimatedEffort,
IReadOnlyList<string> Prerequisites,
IReadOnlyList<string> Risks,
IReadOnlyList<Milestone> Milestones);
public sealed class RemediationPlanner
{
public RemediationStrategy RecommendStrategy(TechnicalDebtItem debt)
{
// High interest + low principal = Pay off
if (debt.Quantification.InterestRate > 0.1m &&
debt.Quantification.Principal < 40)
return RemediationStrategy.PayOff;
// Very high principal = Strangler or scheduled
if (debt.Quantification.Principal > 200)
return debt.Category == DebtCategory.ArchitectureDebt
? RemediationStrategy.Strangler
: RemediationStrategy.ScheduledPayment;
// Low interest = Consider accepting
if (debt.Quantification.InterestRate < 0.01m)
return RemediationStrategy.Accept;
// Multiple related debts = Consolidate
// (would need to analyze relationships)
return RemediationStrategy.PayOff;
}
}
public sealed class TechnicalDebtRegister
{
private readonly List<TechnicalDebtItem> _debts = new();
public DebtSummary GetSummary()
{
var openDebts = _debts.Where(d => d.Status != DebtStatus.Resolved).ToList();
return new DebtSummary(
TotalDebtItems: openDebts.Count,
TotalPrincipal: openDebts.Sum(d => d.Quantification.Principal),
TotalAccruedInterest: openDebts.Sum(d => d.Quantification.AccruedInterest),
WeeklyInterestPayment: openDebts.Sum(d =>
d.Quantification.Principal * d.Quantification.InterestRate),
ByCategory: openDebts
.GroupBy(d => d.Category)
.ToDictionary(g => g.Key, g => g.Count()),
BySeverity: openDebts
.GroupBy(d => d.Severity)
.ToDictionary(g => g.Key, g => g.Count()),
TopDebtors: openDebts
.OrderByDescending(d => d.Quantification.TotalOwed)
.Take(10)
.ToList());
}
public DebtTrend GetTrend(int months = 12)
{
// Track debt over time
var monthlySnapshots = GetMonthlySnapshots(months);
return new DebtTrend(
Snapshots: monthlySnapshots,
IsIncreasing: monthlySnapshots.Last().TotalDebt > monthlySnapshots.First().TotalDebt,
AverageMonthlyChange: CalculateAverageChange(monthlySnapshots));
}
}
When assessing technical debt:
For detailed templates:
Last Updated: 2025-12-26
Creating algorithmic art using p5.js with seeded randomness and interactive parameter exploration. Use this when users request creating art using code, generative art, algorithmic art, flow fields, or particle systems. Create original algorithmic art rather than copying existing artists' work to avoid copyright violations.
Applies Anthropic's official brand colors and typography to any sort of artifact that may benefit from having Anthropic's look-and-feel. Use it when brand colors or style guidelines, visual formatting, or company design standards apply.
Create beautiful visual art in .png and .pdf documents using design philosophy. You should use this skill when the user asks to create a poster, piece of art, design, or other static piece. Create original visual designs, never copying existing artists' work to avoid copyright violations.