From prepare-delivery
Use when validating test coverage quality for new code. Checks that tests exist, are meaningful, and actually exercise new code - not just path matching.
npx claudepluginhub agent-sh/agentsys --plugin prepare-deliveryThis skill uses the workspace's default tool permissions.
Validate that new work has appropriate, meaningful test coverage.
Creates isolated Git worktrees for feature branches with prioritized directory selection, gitignore safety checks, auto project setup for Node/Python/Rust/Go, and baseline verification.
Executes implementation plans in current session by dispatching fresh subagents per independent task, with two-stage reviews: spec compliance then code quality.
Dispatches parallel agents to independently tackle 2+ tasks like separate test failures or subsystems without shared state or dependencies.
Validate that new work has appropriate, meaningful test coverage. Advisory only - reports coverage gaps but does NOT block the workflow.
Validates test QUALITY, not just test EXISTENCE. A test file that exists but doesn't meaningfully exercise the new code is flagged as a gap.
Analyze files in: git diff --name-only origin/${BASE_BRANCH}..HEAD
BASE_BRANCH=$(git symbolic-ref refs/remotes/origin/HEAD 2>/dev/null | sed 's@^refs/remotes/origin/@@' || echo "main")
CHANGED_SOURCE=$(git diff --name-only origin/${BASE_BRANCH}..HEAD 2>/dev/null | \
grep -E '\.(js|ts|jsx|tsx|py|rs|go|rb|java|kt|swift|cpp|c|cs)$' | \
grep -v -E '(test|spec|_test|Test)\.')
CHANGED_TESTS=$(git diff --name-only origin/${BASE_BRANCH}..HEAD 2>/dev/null | \
grep -E '(test|spec|_test|Test)\.')
Optional - enriches coverage checks with historical risk signals.
const { binary } = require('@agentsys/lib');
const fs = require('fs');
const path = require('path');
const { getStateDirPath } = require('@agentsys/lib/platform/state-dir');
const cwd = process.cwd();
const mapFile = path.join(getStateDirPath(cwd), 'repo-intel.json');
let repoIntel = null;
if (fs.existsSync(mapFile)) {
repoIntel = {};
try {
repoIntel.testGaps = JSON.parse(binary.runAnalyzer([
'repo-intel', 'query', 'test-gaps', '--top', '20', '--map-file', mapFile, cwd
]));
} catch (e) { repoIntel.testGaps = null; }
try {
repoIntel.bugspots = JSON.parse(binary.runAnalyzer([
'repo-intel', 'query', 'bugspots', '--top', '20', '--map-file', mapFile, cwd
]));
} catch (e) { repoIntel.bugspots = null; }
}
const testGapSet = new Set((repoIntel?.testGaps || []).map(g => g.path));
const bugspotMap = new Map((repoIntel?.bugspots || []).map(b => [b.path, b]));
# Detect test directory
for dir in tests __tests__ test spec; do
[ -d "$dir" ] && echo "TEST_DIR=$dir" && break
done
# Detect naming convention
for pattern in "*.test.*" "*.spec.*" "test_*.*"; do
ls **/$pattern 2>/dev/null | head -1 && echo "TEST_PATTERN=$pattern" && break
done
function findTestFile(sourceFile) {
const basename = sourceFile.split('/').pop().replace(/\.[^.]+$/, '');
const dir = sourceFile.split('/').slice(0, -1).join('/');
const ext = sourceFile.split('.').pop();
return [
`tests/${basename}.test.${ext}`, `tests/${basename}.spec.${ext}`,
`test/${basename}.test.${ext}`, `__tests__/${basename}.test.${ext}`,
`${dir}/${basename}.test.${ext}`, `${dir}/${basename}.spec.${ext}`,
`${dir}/__tests__/${basename}.test.${ext}`,
`tests/test_${basename}.${ext}`, `test/test_${basename}.${ext}`,
`${dir}/${basename}_test.${ext}`
];
}
For each changed source file, find test file and check if it was updated.
const gaps = [];
const covered = [];
for (const sourceFile of changedSourceFiles) {
const testCandidates = findTestFile(sourceFile);
const existingTest = testCandidates.find(t => fileExists(t));
if (!existingTest) {
gaps.push({ file: sourceFile, reason: 'No test file found', candidates: testCandidates.slice(0, 3) });
continue;
}
const testModified = changedTestFiles.includes(existingTest);
if (!testModified) {
gaps.push({ file: sourceFile, reason: 'Source modified but test file not updated', testFile: existingTest });
} else {
covered.push({ file: sourceFile, testFile: existingTest });
}
}
When repo-intel data is available, apply stricter checks to historically risky files.
const riskIssues = [];
const trivialPatterns = [
/expect\s*\(\s*true\s*\)/, /expect\s*\(\s*1\s*\)\.toBe\s*\(\s*1\s*\)/,
/assert\s*\(\s*True\s*\)/, /\.toBeDefined\s*\(\s*\)/
];
for (const sourceFile of changedSourceFiles) {
const inTestGaps = testGapSet.has(sourceFile);
const bugspot = bugspotMap.get(sourceFile);
const existingTest = findTestFile(sourceFile).find(t => fileExists(t));
const testModified = existingTest && changedTestFiles.includes(existingTest);
if (inTestGaps && bugspot && !testModified) {
riskIssues.push({
file: sourceFile, severity: 'critical', type: 'high-risk-untested',
bugFixRate: bugspot.bugFixRate,
message: `${sourceFile} has ${(bugspot.bugFixRate * 100).toFixed(0)}% bug-fix rate AND no co-changing test - coverage required`
});
}
if (bugspot && bugspot.bugFixRate > 0.3 && testModified && existingTest) {
const testContent = await readFile(existingTest);
if (trivialPatterns.some(p => p.test(testContent))) {
riskIssues.push({
file: sourceFile, severity: 'warning', type: 'weak-test-for-risky-file',
bugFixRate: bugspot.bugFixRate, testFile: existingTest,
message: `${sourceFile} has ${(bugspot.bugFixRate * 100).toFixed(0)}% bug-fix rate but test only has trivial assertions`
});
}
}
}
async function findNewExports(file) {
const diff = await run('git', ['diff', `origin/${BASE_BRANCH}..HEAD`, '--', file]);
const newExports = [];
const patterns = [
/^\+\s*export\s+(function|const|class|async function)\s+(\w+)/gm,
/^\+\s*export\s+default\s+(function|class)\s*(\w*)/gm,
/^\+\s*module\.exports\s*=\s*\{([^}]+)\}/gm,
/^\+\s*def\s+(\w+)\(/gm,
/^\+\s*pub\s+fn\s+(\w+)/gm,
/^\+\s*func\s+(\w+)/gm
];
for (const pattern of patterns) {
let match;
while ((match = pattern.exec(diff)) !== null) {
newExports.push(match[2] || match[1]);
}
}
return newExports;
}
Verify tests actually exercise the new code.
async function validateTestQuality(sourceFile, testFile, newExports) {
const testContent = await readFile(testFile);
const issues = [];
// Check new exports are tested
for (const exportName of newExports) {
if (!testContent.match(new RegExp(exportName, 'g'))) {
issues.push({ type: 'untested-export', export: exportName,
message: `New export '${exportName}' not referenced in test file` });
}
}
// Check for trivial assertions
if (trivialPatterns.some(p => p.test(testContent))) {
issues.push({ type: 'trivial-assertion',
message: 'Test contains trivial assertions that do not validate behavior' });
}
// Check test structure
if (!/describe\s*\(/.test(testContent) && !/it\s*\(/.test(testContent)) {
issues.push({ type: 'no-test-structure', message: 'Test file lacks describe/it blocks' });
}
// Check edge case coverage
const edgeCasePatterns = ['null', 'undefined', 'empty', 'error', 'invalid', 'boundary'];
if (!edgeCasePatterns.some(p => testContent.toLowerCase().includes(p)) && newExports.length > 0) {
issues.push({ type: 'missing-edge-cases', message: 'Tests may lack edge case coverage', severity: 'warning' });
}
// Check source import
const sourceBasename = sourceFile.split('/').pop().replace(/\.[^.]+$/, '');
const importPatterns = [
new RegExp(`from\\s+['"][^'"]*${sourceBasename}['"]`),
new RegExp(`require\\s*\\(\\s*['"][^'"]*${sourceBasename}['"]`)
];
if (!importPatterns.some(p => p.test(testContent))) {
issues.push({ type: 'no-source-import', message: `Test does not import '${sourceBasename}'`, severity: 'critical' });
}
return {
testFile, sourceFile,
quality: issues.length === 0 ? 'good' : issues.some(i => i.severity === 'critical') ? 'poor' : 'needs-improvement',
issues
};
}
async function analyzeTestDepth(sourceFile, testFile, diff) {
const analysis = { sourceComplexity: 'unknown', testCoverage: 'unknown', suggestions: [] };
const branchPatterns = [/^\+.*if\s*\(/gm, /^\+.*else\s*\{/gm, /^\+.*\?\s*.*:/gm,
/^\+.*switch\s*\(/gm, /^\+.*case\s+/gm, /^\+.*catch\s*\(/gm];
const newBranches = branchPatterns.flatMap(p => diff.match(p) || []);
if (newBranches.length > 3) {
analysis.sourceComplexity = 'high';
analysis.suggestions.push('New code has multiple branches - ensure each path is tested');
}
if (/^\+.*async\s+|^\+.*await\s+/m.test(diff)) {
const testContent = await readFile(testFile);
if (!/\.rejects|\.resolves|async.*expect|try.*catch.*expect/i.test(testContent)) {
analysis.suggestions.push('New async code detected - add tests for promise rejection scenarios');
}
}
return analysis;
}
Return structured JSON between markers:
=== TEST_COVERAGE_RESULT ===
{
"scope": "new-work-only",
"coverage": { "filesAnalyzed": 5, "filesWithTests": 3, "filesMissingTests": 2, "coveragePercent": 60 },
"gaps": [...],
"qualityIssues": [...],
"covered": [...],
"riskIssues": [...],
"summary": { "status": "...", "recommendation": "...", "riskSummary": "..." }
}
=== END_RESULT ===