code-coverage-orphan-class-cleanup
Use when an org's overall Apex coverage is sliding toward 75% because of orphaned (uncovered, unreferenced) classes inflating the denominator. Triggers: 'production deploy blocked at 74% coverage', 'find apex classes with 0% coverage', 'orphan apex class report', 'org coverage dropping despite green test runs'. NOT for writing tests on actively used classes (use apex/test-class-standards) or for raising coverage on partially-covered classes.
Best use case
code-coverage-orphan-class-cleanup is best used when you need a repeatable AI agent workflow instead of a one-off prompt.
Use when an org's overall Apex coverage is sliding toward 75% because of orphaned (uncovered, unreferenced) classes inflating the denominator. Triggers: 'production deploy blocked at 74% coverage', 'find apex classes with 0% coverage', 'orphan apex class report', 'org coverage dropping despite green test runs'. NOT for writing tests on actively used classes (use apex/test-class-standards) or for raising coverage on partially-covered classes.
Teams using code-coverage-orphan-class-cleanup should expect a more consistent output, faster repeated execution, less prompt rewriting.
When to use this skill
- You want a reusable workflow that can be run more than once with consistent structure.
When not to use this skill
- You only need a quick one-off answer and do not need a reusable workflow.
- You cannot install or maintain the underlying files, dependencies, or repository context.
Installation
Claude Code / Cursor / Codex
Manual Installation
- Download SKILL.md from GitHub
- Place it in
.claude/skills/code-coverage-orphan-class-cleanup/SKILL.mdinside your project - Restart your AI agent — it will auto-discover the skill
How code-coverage-orphan-class-cleanup Compares
| Feature / Agent | code-coverage-orphan-class-cleanup | Standard Approach |
|---|---|---|
| Platform Support | Not specified | Limited / Varies |
| Context Awareness | High | Baseline |
| Installation Complexity | Unknown | N/A |
Frequently Asked Questions
What does this skill do?
Use when an org's overall Apex coverage is sliding toward 75% because of orphaned (uncovered, unreferenced) classes inflating the denominator. Triggers: 'production deploy blocked at 74% coverage', 'find apex classes with 0% coverage', 'orphan apex class report', 'org coverage dropping despite green test runs'. NOT for writing tests on actively used classes (use apex/test-class-standards) or for raising coverage on partially-covered classes.
Where can I find the source code?
You can find the source code on GitHub using the link provided at the top of the page.
SKILL.md Source
# Code Coverage Orphan Class Cleanup Activate when an org's overall Apex coverage has crept toward the 75% deploy threshold and the source of the drag is *uncovered, unreferenced* classes accumulated over years of half-finished features. The skill produces a ranked list of orphan classes, separates "delete-safe" from "test-required-to-keep," and emits a destructive-changes manifest. --- ## Before Starting Gather this context before working on anything in this domain: - Current org-wide coverage and the gap to 75%. The Tooling API query against `ApexOrgWideCoverage` gives a single number; per-class data lives in `ApexCodeCoverageAggregate`. - Whether managed-package classes are inflating the denominator. Salesforce excludes managed-package code from the org-wide calculation, but unmanaged code from a previously-installed-then-uninstalled package may still be present. - Any classes flagged as `@deprecated` already, since those telegraph the team's intent. - Whether any of the candidate classes are referenced from non-Apex artifacts: Flow Apex action invocations, LWC `@AuraEnabled` callers, REST endpoints (URL mappings), Process Builder Apex actions, scheduled jobs, custom buttons. Coverage-only signals miss these references. --- ## Core Concepts ### Coverage denominator The 75% threshold is computed across **all unmanaged Apex** in the org (classes + triggers, excluding test classes). Removing a 200-line class with 0% coverage subtracts 200 from both the numerator and the denominator's "uncovered" portion — net positive on the percentage. ### "Orphan" definition A class is an *orphan* candidate when **all** of the following hold: - 0% coverage in `ApexCodeCoverageAggregate` over the last full test run. - No source-code reference: no `extends`, `implements`, `new <Class>`, static call, or type usage in any other Apex. - No metadata reference: not invoked from a Flow, Process Builder, scheduled job, REST mapping, custom button/link, validation rule formula (`$Apex`), or LWC's `@AuraEnabled` calls. - Not annotated `@RestResource`, `@HttpGet/Post/...` (otherwise it's an external entry point even if no Apex calls it). If all four hold, the class is delete-safe. If only the first three hold and the class has, e.g., a custom button reference, it must keep its test. ### Coverage queries that lie `ApexCodeCoverage` (per-test) and `ApexCodeCoverageAggregate` (latest-run) only reflect the **last test run**. If the run was incomplete or skipped a class because a dependency failed, coverage shows zero for that class for reasons other than missing tests. Always run a clean `--test-level RunLocalTests` before treating coverage as authoritative. --- ## Common Patterns ### Pattern: pre-deploy coverage rescue **When to use:** Friday's deploy fails at 74.3%. You need to ship by Monday. **How it works:** Query `ApexCodeCoverageAggregate` for 0%-coverage classes ordered by NumLinesCovered DESC + NumLinesUncovered DESC. Static-reference-check the top 20. Of those that pass all four orphan criteria, build a destructive-changes manifest and deploy with `--purge-on-delete=true` (sandbox first). **Why not the alternative:** Writing 4,000 lines of stub tests under deadline pressure produces brittle tests that obscure real coverage signal. ### Pattern: scheduled tech-debt cleanup **When to use:** Quarterly engineering tax. **How it works:** Same query, but instead of destructive deploy, file a per-class issue with the orphan evidence. Engineers triage: delete, test, or document why kept. ### Pattern: package-deprecation cleanup **When to use:** A managed package was uninstalled but unmanaged "ghost" classes remain (e.g., from an early-stage 1GP install). **How it works:** Filter classes by namespace prefix in name, age, and zero-reference. Most are bulk-deletable. --- ## Decision Guidance | Class state | Action | Reason | |---|---|---| | 0% coverage, 0 source refs, 0 metadata refs, no `@RestResource` | Delete | Pure dead weight on the denominator | | 0% coverage, used by a Flow/button/REST mapping | Write test or document waiver | Active code; test debt is real debt | | Low (<75%) coverage, actively referenced | Out of scope — see apex/test-class-standards | Different problem (improve tests) | | 0% coverage, looks unused, but team uncertain | Mark `@deprecated`, deploy, watch one cycle | Cheap reversibility before destructive change | --- ## Recommended Workflow 1. Run a clean `sf apex run test --test-level RunLocalTests --code-coverage --result-format json` to refresh `ApexCodeCoverageAggregate`. Without a clean run, coverage data is unreliable. 2. Query orphan candidates: `SELECT ApexClassOrTrigger.Name, NumLinesCovered, NumLinesUncovered FROM ApexCodeCoverageAggregate WHERE NumLinesCovered = 0`. 3. For each candidate, search the source tree for references: name token in `.cls`, `.trigger`, `.flow-meta.xml`, `.weblink-meta.xml`, `.flexipage-meta.xml`, REST URL mappings. 4. Check metadata-only references: `aura:component`, LWC `@AuraEnabled` callers via `connectedCallback` patterns, Process Builder bindings. 5. Categorize each candidate: delete-safe, needs-test-to-stay, deprecated-but-kept-for-back-compat. 6. Build destructive-changes manifest for delete-safe classes. Deploy in sandbox first; verify no tests start failing because of compile-time references the search missed. 7. Promote to higher environments. Track org-wide coverage delta — should jump cleanly upward. --- ## Review Checklist - [ ] Coverage data refreshed via clean local-tests run, not a stale snapshot - [ ] Each candidate verified against four orphan criteria (coverage, source ref, metadata ref, REST entry) - [ ] Sandbox deploy of the destructive manifest passes all tests - [ ] Org-wide coverage measured before and after; delta documented - [ ] Classes kept-but-untested have a tracked issue or `@deprecated` annotation --- ## Salesforce-Specific Gotchas 1. **Coverage queries reflect only the last run** — Skipping the clean test run before querying produces phantom orphans (and phantom keeps). 2. **REST endpoint classes have no Apex callers but are not orphans** — `@RestResource(urlMapping='/api/v1/things')` is invoked by an HTTP request, never by Apex. Filter by annotation before declaring orphan. 3. **Scheduled-job classes can be invoked from `System.schedule` calls in *other* classes or from Setup-only schedule entries** — Setup → Apex Jobs → Scheduled Jobs lists schedules that have no Apex caller record. Check before deleting any `Schedulable` class. 4. **Deleting a class fails if it's referenced by a Flow** — The destructive deploy returns a clear error, but only after the apparently-clean static check. Flow XML must be searched for `<actionName>ClassName</actionName>`. --- ## Output Artifacts | Artifact | Description | |---|---| | orphan-candidates.csv | Class name, lines, last-modified date, reference-search summary | | delete-safe.xml | destructiveChanges.xml for verified-orphan classes | | keep-with-test.md | Classes that must stay, with the test gap they need | | coverage-before-after.txt | Org-wide coverage delta proof | --- ## Related Skills - apex/test-class-standards — for the actively-referenced classes that need a real test, not a deletion - devops/destructive-changes-deployment — for safely shipping the delete manifest - architect/technical-debt-assessment — when the orphan list is large enough to be a strategic conversation, not a tactical sweep
Related Skills
data-classification-labels
Classify Salesforce fields by data sensitivity and compliance category using the four built-in classification attributes (SecurityClassification, ComplianceGroup, BusinessOwnerId, BusinessStatus). Covers Metadata API deployment, Tooling API querying, and Einstein Data Detect recommendations. NOT for data masking, Shield Platform Encryption, or runtime access control enforcement.
metadata-api-coverage-gaps
Use this skill when a deployment, source push, or package version fails because a metadata type is unsupported, partially supported, or behaves differently across Metadata API, source tracking, unlocked packages, and 2GP managed packages. Covers identifying coverage gaps, building release runbooks for manual post-deployment steps, and choosing workarounds such as post-deploy scripts, Tooling API calls, or manual configuration. NOT for general deployment error troubleshooting, Metadata API usage tutorials, or architecture-level metadata dependency mapping.
batch-data-cleanup-patterns
Use when scheduling automated deletion of temporary records, enforcing data retention policies, running nightly cleanup jobs, reclaiming org storage, managing recycle bin, or performing async bulk deletion of aged records. Trigger keywords: batch delete, retention policy, purge records, cleanup job, recycle bin, emptyRecycleBin, hard delete, nightly purge, storage optimization. NOT for data archival to external storage (use data-archival-strategies).
metadata-coverage-and-dependencies
Assessing metadata type coverage across Salesforce deployment channels (Metadata API, SFDX, unlocked packages, managed packages) and mapping component dependency graphs using Tooling API MetadataComponentDependency. Use when planning packaging strategies, evaluating deployment risk, performing impact analysis before component deletion, or mapping tightly coupled metadata for modular architecture. Trigger keywords: metadata coverage report, dependency graph, MetadataComponentDependency, impact analysis, unsupported metadata types, packaging eligibility. NOT for deployment mechanics (use destructive-changes-deployment). NOT for CI/CD pipeline design (use continuous-integration-testing).
test-class-standards
Use when writing, reviewing, or debugging Apex test classes, test data factories, async test behavior, negative-path assertions, or callout mocking. Triggers: 'SeeAllData', 'Test.startTest', 'HttpCalloutMock', 'test data factory', 'missing assertions'. NOT for LWC Jest tests or code-coverage-only conversations detached from test design.
apex-wrapper-class-patterns
Use when designing wrapper or inner classes in Apex to combine SObjects with computed fields, shape data for LWC consumption, or sort collections with Comparable or Comparator. Trigger keywords: wrapper class, inner class, Comparable, Comparator, @AuraEnabled fields, @JsonAccess. NOT for JSON serialization mechanics — use apex-json-serialization. NOT for LWC data-binding patterns — use lwc-reactive-state-patterns or lwc-lightning-record-forms.
apex-class-decomposition-pattern
When and how to split an Apex class into Domain / Service / Selector layers using this repo's lightweight base classes (BaseDomain, BaseService, BaseSelector). Covers splitting signals, ordering of extraction, and naming conventions. NOT for full fflib migration — see fflib-enterprise-patterns. NOT for trigger framework choice — see trigger-framework.
org-cleanup-and-technical-debt
Use when executing admin-level cleanup in a Salesforce org: deleting unused fields, removing inactive Flow versions, deactivating legacy automation, running Salesforce Optimizer or Org Check, and performing destructive metadata deploys. Triggers: 'clean up unused fields', 'delete inactive flows', 'run Optimizer', 'org has too many custom fields', 'remove old workflow rules', 'Flow version limit'. NOT for assessing or reporting on technical debt (use architect/technical-debt-assessment). NOT for code-level refactoring or Apex cleanup (use apex/ skills).
knowledge-classic-to-lightning
Migrating Classic Knowledge (KnowledgeArticleVersion / Article Types) to Lightning Knowledge (Knowledge__kav with record types): article-type-to-record-type mapping, multi-language translation preservation, data category re-architecture, file attachment porting, version and publication-state retention, channel visibility translation, and downstream Case Feed / Community / Bot rewiring. NOT for new Lightning Knowledge setup (use admin/knowledge-base-administration) or for editorial workflow design (use admin/knowledge-publishing-workflow).
classic-email-template-migration
Migrating Classic email templates (Text, HTML with Letterhead, Custom HTML, Visualforce email) to Lightning Email Templates (LET) and the Email Template Builder. Covers merge-field translation, Letterhead-to-Enhanced-Letterhead conversion, Visualforce email retention strategy, folder reorganization, sender-context (OrgWideEmailAddress) preservation, and downstream Email Alert / Process Builder / Flow rewiring. NOT for transactional Apex email sending (use apex/apex-outbound-email-patterns) or marketing email broadcasts (use Marketing Cloud / Account Engagement).
xss-and-injection-prevention
Use when writing or reviewing Visualforce pages, Apex controllers, or LWC components that output user-supplied data, build dynamic queries, or construct HTTP responses. Triggers: 'XSS in Visualforce', 'SOQL injection vulnerability', 'how to encode output in Apex', 'JSENCODE Visualforce', 'open redirect prevention'. NOT for Apex CRUD/FLS enforcement (use soql-security or apex-crud-and-fls), NOT for Shield encryption (use shield-encryption-key-management), NOT for AppExchange security review process (use secure-coding-review-checklist).
visualforce-security-and-modernization
Use when hardening or modernizing legacy Visualforce pages — covers the platform CSRF token model and when disabling it is a security regression, view state encryption guarantees and the 170 KB ceiling, FLS/CRUD enforcement gaps on `<apex:outputField>` and on getters that return sObjects, `<apex:includeScript>` interaction with the org Content Security Policy, hosting LWC inside a VF page via `lightning:container` / `lightning-out`, and the retire-vs-harden-vs-leave-alone decision for an inventory of legacy pages. Triggers: 'should I rewrite this Visualforce page in LWC', 'CSRF protection disabled on Visualforce page is that safe', 'community user sees a field they should not on a Visualforce page', 'view state encryption is that enough for sensitive data', 'how do I host an LWC inside a Visualforce page', 'apex:dynamicComponent and apex:actionFunction safe to keep'. NOT for greenfield Visualforce architecture (use apex/visualforce-fundamentals — controller types, view state pattern selection, PDF rendering); NOT for Visualforce email template authoring (use apex/visualforce-email-templates if/when that skill is authored); NOT for general Apex security review across triggers and async (use apex/soql-security and security/secure-coding-review-checklist).