Detect and fix status desyncs between metadata.json and spec.md
Detects and fixes status mismatches between metadata.json and spec.md files. Use this to recover from desyncs that break the status line and cause commands to operate on wrong data.
/plugin marketplace add anton-abyzov/specweave/plugin install sw@specweaveCRITICAL: Detects and fixes status desyncs between metadata.json and spec.md to maintain source-of-truth integrity.
This command scans increments for status desyncs where metadata.json and spec.md have different status values. This violates CLAUDE.md Rule #7 (source-of-truth discipline) and causes:
Incident Reference: 2025-11-20 - Silent failure in /sw:done caused increment 0047 to have metadata.json="completed" while spec.md="active", breaking status line.
# Scan all increments for desyncs
/sw:sync-status
# Check specific increment
/sw:sync-status 0047
# Auto-fix all desyncs (non-interactive)
/sw:sync-status --fix
# Scan and show detailed report
/sw:sync-status --verbose
<increment-id> - Optional. Specific increment to check (e.g., "0047", "0001-test")--fix - Auto-fix all desyncs without prompting--verbose - Show detailed report including healthy incrementsWhen to use: Regular maintenance, pre-commit checks, incident investigation
Steps:
Scan all increments:
import { DesyncDetector } from '../../../src/core/increment/desync-detector.js';
const detector = new DesyncDetector();
const report = await detector.scanAll();
Display report:
console.log(detector.formatReport(report));
Example output (desyncs found):
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
STATUS DESYNC DETECTION REPORT
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Total Scanned: 47 increments
Healthy: 46
Desyncs Found: 1 ⚠️
Errors: 0
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
DESYNCS DETECTED (CRITICAL!)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
❌ 0047-us-task-linkage
metadata.json: completed
spec.md: active
Fix command: /sw:sync-status --fix
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
If desyncs found, prompt user:
if (report.totalDesyncs > 0) {
const shouldFix = await promptUser(
`Found ${report.totalDesyncs} desync(s). Fix them? (y/n): `
);
if (shouldFix) {
// Fix all desyncs
for (const desync of report.desyncs) {
const fixed = await detector.fixDesync(desync.incrementId);
if (fixed) {
console.log(`✅ Fixed ${desync.incrementId}`);
} else {
console.error(`❌ Failed to fix ${desync.incrementId}`);
}
}
console.log('');
console.log('All desyncs fixed! Run /sw:sync-status to verify.');
}
}
Example output (no desyncs):
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
STATUS DESYNC DETECTION REPORT
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Total Scanned: 47 increments
Healthy: 47
Desyncs Found: 0 ⚠️
Errors: 0
✅ All increments healthy - no desyncs detected!
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
When to use: Investigating specific increment, post-fix verification
Steps:
Check increment:
const detector = new DesyncDetector();
const result = await detector.checkIncrement(incrementId);
Display result:
if (result.error) {
console.error(`❌ Error checking ${incrementId}: ${result.error}`);
process.exit(1);
}
if (result.hasDesync) {
console.log('━'.repeat(80));
console.log(`❌ DESYNC DETECTED: ${incrementId}`);
console.log('━'.repeat(80));
console.log('');
console.log(`metadata.json: ${result.metadataStatus}`);
console.log(`spec.md: ${result.specStatus}`);
console.log('');
console.log('This violates source-of-truth discipline (CLAUDE.md Rule #7)');
console.log('');
console.log(`Fix: /sw:sync-status ${incrementId} --fix`);
console.log('━'.repeat(80));
} else {
console.log(`✅ ${incrementId} - No desync detected`);
console.log(` Status: ${result.metadataStatus}`);
}
Example output (desync found):
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
❌ DESYNC DETECTED: 0047-us-task-linkage
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
metadata.json: completed
spec.md: active
This violates source-of-truth discipline (CLAUDE.md Rule #7)
Fix: /sw:sync-status 0047 --fix
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
When to use: CI/CD pipelines, automated recovery, pre-commit hooks
Steps:
Scan and fix:
const detector = new DesyncDetector();
const report = await detector.scanAll();
if (report.totalDesyncs > 0) {
console.log(`Found ${report.totalDesyncs} desync(s) - fixing...`);
console.log('');
for (const desync of report.desyncs) {
const fixed = await detector.fixDesync(desync.incrementId);
if (fixed) {
console.log(`✅ Fixed ${desync.incrementId}: ${desync.specStatus} → ${desync.metadataStatus}`);
} else {
console.error(`❌ Failed to fix ${desync.incrementId}`);
}
}
console.log('');
console.log('✅ All desyncs fixed!');
} else {
console.log('✅ No desyncs found - all healthy');
}
Example output:
Found 1 desync(s) - fixing...
✅ Fixed 0047-us-task-linkage: active → completed
✅ All desyncs fixed!
Fix Strategy: metadata.json is considered the source of truth for status updates.
Rationale:
Fix Process:
What gets updated:
status fieldExample fix:
# Before (spec.md)
---
status: active
---
# After (spec.md)
---
status: completed
---
After fixing desyncs, the following actions happen automatically:
Status Line Cache Update:
# Automatically triggered by spec.md change
bash plugins/specweave/hooks/lib/update-status-line.sh
Git Status:
# spec.md will be modified - commit the fix
git status
git add .specweave/increments/*/spec.md
git commit -m "fix: sync spec.md status with metadata.json"
Verification:
# Verify no desyncs remain
/sw:sync-status
❌ Error: Increment 0047-us-task-linkage not found
Check increment ID and try again.
❌ Failed to fix desync for 0047-us-task-linkage
Error: EACCES: permission denied, open '.specweave/increments/0047-us-task-linkage/spec.md'
Fix permissions:
chmod u+w .specweave/increments/0047-us-task-linkage/spec.md
❌ Failed to fix desync for 0047-us-task-linkage
Error: Invalid YAML frontmatter in spec.md
Check YAML syntax:
vim .specweave/increments/0047-us-task-linkage/spec.md
To prevent future desyncs:
✅ Fixed in v0.23.0+: Atomic transaction pattern in metadata-manager.ts
✅ Added in v0.23.0+: Desync detection in /sw:done
✅ Added in v0.23.0+: Pre-commit hook validation
✅ Added in v0.23.0+: Comprehensive tests
/sw:done - Close increment (includes desync validation)/sw:validate - Validate increment quality/sw:status - Show increment status overviewsrc/core/increment/desync-detector.ts - Detection & fix logicsrc/core/increment/metadata-manager.ts - Atomic status updatessrc/core/increment/spec-frontmatter-updater.ts - spec.md updatesscripts/pre-commit-desync-check.sh - Pre-commit validationImportant: This command is part of the incident response to the 2025-11-20 silent failure bug. It ensures source-of-truth discipline is maintained across the entire increment lifecycle.
Best Practice: Run /sw:sync-status regularly (weekly or before releases) to catch any desyncs early.