Reverse ACDD: Document Existing Codebases
Overview
Reverse ACDD reverse engineers existing codebases to create specifications, tests, and coverage mappings. Perfect for:
- Legacy codebases without specs or tests
- Projects transitioning to ACDD workflow
- Understanding inherited code through BDD lens
- Documenting what you already built
Key feature: Interactive strategy planner guides you through the best approach based on gap analysis.
Quick Start
# Interactive mode (recommended)
fspec reverse
# Direct strategy selection
fspec reverse --strategy=A # Spec gap (generate from tests)
fspec reverse --strategy=B # Test gap (generate from code)
fspec reverse --strategy=C # Coverage gap (link tests to code)
fspec reverse --strategy=D # Full reverse ACDD
Interactive mode:
- Analyzes your codebase
- Identifies gaps (specs, tests, coverage)
- Suggests best strategy
- Guides through decision tree
- Saves session state for resumption
The Four Strategies
Strategy A: Spec Gap
When to use:
- ✅ You have tests
- ❌ You don't have specs
What it does:
- Analyzes test files
- Infers scenarios from test structure
- Generates feature files
- Links tests to scenarios
Example:
// Existing test file
describe('POST /login', () => {
it('should authenticate valid user', async () => { ... });
it('should reject invalid credentials', async () => { ... });
});
// Strategy A generates:
Feature: User Login
Scenario: Authenticate valid user
Given I have valid credentials
When I submit login form
Then I should be authenticated
Scenario: Reject invalid credentials
Given I have invalid credentials
When I submit login form
Then I should see an error message
Coverage:
Scenario → Test File (✅ linked)
Scenario → Implementation (❌ not linked)
Strategy B: Test Gap
When to use:
- ✅ You have specs (or can write them)
- ❌ You don't have tests
What it does:
- Uses existing feature files (or generates from code)
- Creates skeleton test files
- Structures tests to map to scenarios
- Links tests to specs
Example:
# Existing spec (spec/features/user-login.feature)
Feature: User Login
Scenario: Authenticate valid user
Given I have valid credentials
When I submit login form
Then I should be authenticated
# Strategy B generates skeleton:
/**
* Feature: spec/features/user-login.feature
* NOTE: Skeleton test - implement the test logic
*/
describe('Scenario: Authenticate valid user', () => {
it('should authenticate user', async () => {
// TODO: Implement this test
// Given I have valid credentials
// When I submit login form
// Then I should be authenticated
});
});
Coverage:
Scenario → Test File (✅ linked, ❌ not implemented)
Scenario → Implementation (❌ not linked)
Strategy C: Coverage Gap
When to use:
- ✅ You have specs
- ✅ You have tests
- ❌ They're not linked
What it does:
- Uses existing feature files
- Uses existing test files
- Uses similarity matching to link scenarios to tests
- Links tests to implementation code
- Generates coverage files
Example:
# Existing: spec/features/user-login.feature (scenarios)
# Existing: src/__tests__/auth.test.ts (tests)
# Existing: src/auth/login.ts (implementation)
# Strategy C links them:
fspec reverse --strategy=C
Analyzing feature files... 5 found
Analyzing test files... 8 found
Analyzing implementation... 12 files
Similarity matching:
✓ "Authenticate valid user" → auth.test.ts:15-28 (95% match)
✓ "Reject invalid credentials" → auth.test.ts:30-42 (92% match)
Creating coverage mappings...
✓ user-login.feature.coverage created
Coverage:
Scenario → Test File (✅ linked)
Scenario → Implementation (✅ linked)
Strategy D: Full Reverse ACDD
When to use:
- ❌ No specs
- ❌ No tests
- ✅ Just code
What it does:
- Analyzes code structure (routes, APIs, UI components)
- Infers user stories and scenarios
- Creates feature files
- Creates skeleton test files
- Links tests to specs
- Links implementation to tests
Example:
// Existing code only
app.post('/login', async (req, res) => {
const { email, password } = req.body;
if (!email || !password) {
return res.status(400).json({ error: 'Missing credentials' });
}
const user = await authenticateUser(email, password);
if (!user) {
return res.status(401).json({ error: 'Invalid credentials' });
}
res.json({ token: generateToken(user) });
});
// Strategy D generates:
// 1. spec/features/user-login.feature (inferred from route)
// 2. src/__tests__/auth-login.test.ts (skeleton)
// 3. user-login.feature.coverage (mappings)
Coverage:
Scenario → Test File (✅ linked, ❌ not implemented)
Scenario → Implementation (✅ linked)
Interactive Strategy Planner
How It Works
Step 1: Analysis
You: fspec reverse
AI: Analyzing your codebase for reverse ACDD...
Scanning feature files... 0 found
Scanning test files... 15 found
Analyzing routes and APIs... 23 endpoints found
GAP ANALYSIS:
❌ Spec gap: No feature files found
✅ Test coverage: 15 test files exist
⚠️ Coverage gap: Tests not linked to specs
Based on this analysis, I recommend Strategy A (Spec Gap).
Step 2: Strategy Suggestion
AI: RECOMMENDED STRATEGY: A (Spec Gap)
WHY:
- You have test files (good foundation)
- No feature files (need to generate from tests)
- Tests can guide spec creation
ALTERNATIVE STRATEGIES:
B. Test Gap (if you write specs manually first)
C. Coverage Gap (not applicable - no specs yet)
D. Full Reverse ACDD (overkill since you have tests)
Would you like to:
1. Proceed with Strategy A (recommended)
2. Choose a different strategy
3. See detailed decision tree
Step 3: Execution
You: 1
AI: Proceeding with Strategy A (Spec Gap)...
PHASE 1: Analyzing test structure
✓ Identified 15 test files
✓ Detected 47 test scenarios
✓ Grouped into 8 feature areas
PHASE 2: Generating feature files
✓ Created spec/features/user-login.feature (6 scenarios)
✓ Created spec/features/password-reset.feature (4 scenarios)
✓ Created spec/features/user-registration.feature (5 scenarios)
...
PHASE 3: Linking coverage
✓ Linked 47 scenarios to test files
✓ Generated 8 coverage files
PHASE 4: Creating work units
✓ Created AUTH-001: User Login
✓ Created AUTH-002: Password Reset
✓ Created AUTH-003: User Registration
...
REVERSE ACDD COMPLETE!
Coverage: 100% (47/47 scenarios linked to tests)
Test gap: 0 scenarios without tests
Implementation gap: 47 scenarios (run Strategy C to link implementation)
Next steps:
1. Review generated feature files
2. Run `fspec reverse --strategy=C` to link implementation
3. Implement missing tests (if any skeleton tests exist)
Session Management
Sessions are saved automatically:
AI: Reverse ACDD session started...
Session ID: rev-acdd-2025-10-21-14-30-15
Session file: .fspec-reverse-session.json
... (analysis and execution)
Session saved. You can resume later with:
fspec reverse --resume
Resume later:
You: fspec reverse --resume
AI: Resuming reverse ACDD session from 2025-10-21 14:30:15...
Previous state:
- Strategy: A (Spec Gap)
- Phase completed: Analysis
- Next phase: Generate feature files
Continuing from where we left off...
Decision Tree Guidance
The interactive planner uses this decision tree:
Do you have feature files?
→ YES: Continue to Q2
→ NO: Continue to Q3
Q2: Do you have tests?
→ YES: Strategy C (Coverage Gap - link specs to tests to code)
→ NO: Strategy B (Test Gap - generate skeleton tests from specs)
Q3: Do you have tests?
→ YES: Strategy A (Spec Gap - generate specs from tests)
→ NO: Strategy D (Full Reverse ACDD - analyze code, generate everything)
You can view this tree:
fspec reverse --help
# Shows decision tree in help output
Gap Analysis
fspec analyzes three types of gaps:
Spec Gap
Definition: Feature files missing.
Detection:
- Scans
spec/features/
directory - Counts
.feature
files - If 0, spec gap exists
Resolution: Strategy A or D
Test Gap
Definition: Test files missing or incomplete.
Detection:
- Searches for test files (*.test.ts, *.spec.ts, etc.)
- Analyzes test structure
- Checks for scenario coverage
Resolution: Strategy B or D
Coverage Gap
Definition: Specs and tests exist but aren't linked.
Detection:
- Checks for
.coverage
files - Analyzes scenario-to-test mappings
- Identifies unmapped scenarios
Resolution: Strategy C
Similarity Matching (Strategy C)
How fspec links scenarios to tests:
Hybrid Similarity Algorithm
Uses 5 algorithms weighted by accuracy:
- Exact match (100% weight) - Scenario name matches test description exactly
- Normalized match (95% weight) - After lowercasing, removing punctuation
- Keyword overlap (70% weight) - Significant word overlap
- Fuzzy match (60% weight) - Levenshtein distance similarity
- Semantic similarity (40% weight) - Meaning-based matching
Threshold: 60% minimum for automatic linking
Example:
Scenario: User logs in with valid credentials
Test candidates:
it('should authenticate user with valid credentials', ...) // 95% match
it('logs in user successfully', ...) // 75% match
it('handles login request', ...) // 45% match (below threshold)
Result: Links to first test (95% match)
Manual Review
If match < 80%:
AI: ⚠️ Low confidence match detected:
Scenario: "User logs in with valid credentials"
Test: "should authenticate user with valid credentials" (75% match)
Should I link these? (y/n)
You: y
AI: ✓ Linked scenario to test
Handling Ambiguous Code
When encountering unclear business logic:
# AMBIGUOUS: magic number 42 in discount logic - needs human clarification
Scenario: Apply special discount
Given a customer has a discount code
And the discount value is greater than 42 # Why 42? Ask human.
When they complete checkout
Then a special discount should be applied
AI creates red card:
fspec add-question DISC-001 "@human: Why is discount threshold 42? Business rule or magic number?"
After clarification:
fspec answer-question DISC-001 0 --answer "Business rule: Discounts > 42% trigger special processing"
Spec updated:
Scenario: Apply special discount
Given a customer has a discount code with value greater than 42%
When they complete checkout
Then special discount processing should be triggered
Coverage Tracking
Link existing code to scenarios:
# Strategy A or D creates skeleton tests
# You need to link implementation manually or use Strategy C
# Link implementation to test mapping
fspec link-coverage user-login \
--scenario "Authenticate valid user" \
--test-file src/__tests__/auth.test.ts \
--impl-file src/auth/login.ts \
--impl-lines 15-42
# Check coverage
fspec show-coverage user-login
Result:
Coverage for user-login:
✅ Authenticate valid user (FULLY COVERED)
Test: src/__tests__/auth.test.ts:10-22
Implementation: src/auth/login.ts:15-42
⚠️ Reject invalid credentials (PARTIAL COVERAGE)
Test: src/__tests__/auth.test.ts:24-35
Implementation: (not linked)
Coverage: 50% (1/2 scenarios fully covered)
Epics and Work Units
Reverse ACDD creates epics automatically:
Analyzing codebase structure...
Found business domains:
- Authentication (routes: /login, /logout, /register)
- User Profile (routes: /profile, /settings)
- Payment (routes: /checkout, /payment)
Creating epics:
fspec create-epic "Authentication" AUTH "User authentication features"
fspec create-epic "User Profile" PROF "User profile management"
fspec create-epic "Payment Processing" PAY "Payment and checkout"
Creating work units:
fspec create-work-unit AUTH "User Login" --epic=AUTH
fspec create-work-unit AUTH "User Registration" --epic=AUTH
fspec create-work-unit PROF "Edit Profile" --epic=PROF
...
Completion Criteria
Reverse ACDD is complete when:
- ✅ All user-facing interactions have feature files
- ✅ All epics have at least one work unit
- ✅ All scenarios linked to tests (if Strategy A/C/D)
- ✅ All tests linked to implementation (if Strategy C/D)
- ✅ Ambiguous scenarios documented with questions
- ✅ Coverage files exist for all features
Check completion:
fspec show-coverage # All features
fspec query-metrics # Coverage statistics
fspec board # Work unit status
Transitioning to Forward ACDD
After reverse ACDD, use forward ACDD for new features:
-
Create work unit
fspec create-work-unit AUTH "Password Reset" --type story
-
Example Mapping (Discovery)
fspec add-rule AUTH-004 "Reset token valid for 1 hour" fspec add-example AUTH-004 "User requests reset, receives email, clicks link, resets password"
-
Generate spec
fspec generate-scenarios AUTH-004
-
Write tests (must fail first)
-
Implement (make tests pass)
-
Validate (all tests, quality checks)
See: ACDD Workflow
Commands Reference
# Interactive mode (recommended)
fspec reverse
# Strategy selection
fspec reverse --strategy=A # Spec gap
fspec reverse --strategy=B # Test gap
fspec reverse --strategy=C # Coverage gap
fspec reverse --strategy=D # Full reverse ACDD
# Session management
fspec reverse --resume # Resume previous session
fspec reverse --clear-session # Clear saved session
# Help
fspec reverse --help # Decision tree and guidance
Best Practices
✅ DO:
- Start with interactive mode (analyzes and suggests)
- Review generated specs for accuracy
- Answer questions about ambiguous code
- Link implementation for full coverage (Strategy C)
- Use forward ACDD for new features after reverse ACDD
❌ DON'T:
- Blindly accept generated specs (review first)
- Ignore ambiguous code warnings
- Skip coverage linking
- Use reverse ACDD for new features (use forward ACDD)
Troubleshooting
"No strategy suggested"
- Codebase may be too minimal
- Try manual strategy selection
- Check that code exists in expected locations
"Low confidence matches"
- Review and manually confirm/reject
- Adjust test descriptions to match scenarios
- Use explicit linking if needed
"Ambiguous scenarios"
- Use Example Mapping to clarify with human
- Answer questions in work unit
- Update scenarios based on answers
See Also
- Getting Started - Learn forward ACDD workflow
- ACDD Workflow - Understanding the process
- Coverage Tracking - Traceability
- Work Units - Project management
Reverse ACDD: Document what you built. Then build with discipline.