---
description: Execute Brownfield Upgrade Mode - spec-driven dependency modernization workflow. Runs 4-phase process: spec-guided test coverage, baseline analysis, dependency upgrade with spec-guided fixes, and spec validation. Based on thoth-cli dependency upgrade process adapted for spec-driven development.
---
# StackShift Modernize: Spec-Driven Dependency Upgrade
**Brownfield Upgrade Mode** - Execute after completing Gears 1-6
Run this command to modernize all dependencies while using specs as your guide and safety net.
---
## Quick Status Check
```bash
# Check prerequisites
echo "=== Prerequisites Check ==="
# 1. Specs exist?
SPEC_COUNT=$(find .specify/memory/specifications -name "*.md" 2>/dev/null | wc -l)
echo "Specs found: $SPEC_COUNT"
# 2. /speckit commands available?
ls .claude/commands/speckit.*.md 2>/dev/null | wc -l | xargs -I {} echo "Speckit commands: {}"
# 3. Tests passing?
npm test --silent && echo "Tests: ✅ PASSING" || echo "Tests: ❌ FAILING"
# 4. StackShift state?
cat .stackshift-state.json 2>/dev/null | jq -r '"\(.path) - Gear \(.currentStep // "complete")"' || echo "No state file"
if [ "$SPEC_COUNT" -lt 1 ]; then
echo "❌ No specs found. Run Gears 1-6 first."
exit 1
fi
```
---
## Phase 0: Spec-Guided Test Coverage Foundation
**Goal:** 85%+ coverage using spec acceptance criteria as test blueprint
**Time:** 30-90 minutes | **Mode:** Autonomous test writing
### 0.1: Load Specifications & Baseline Coverage
```bash
echo "=== Phase 0: Spec-Guided Test Coverage ==="
mkdir -p .upgrade
# List all specs
find .specify/memory/specifications -name "*.md" | sort | tee .upgrade/all-specs.txt
SPEC_COUNT=$(wc -l < .upgrade/all-specs.txt)
# Baseline coverage
npm test -- --coverage --watchAll=false 2>&1 | tee .upgrade/baseline-coverage.txt
COVERAGE=$(grep "All files" .upgrade/baseline-coverage.txt | grep -oE "[0-9]+\.[0-9]+" | head -1 || echo "0")
echo "Specs: $SPEC_COUNT"
echo "Coverage: ${COVERAGE}%"
echo "Target: 85%"
```
### 0.2: Map Tests to Specs
Create `.upgrade/spec-coverage-map.json` mapping each spec to its tests:
```bash
# For each spec, find which tests validate it
# Track which acceptance criteria are covered vs. missing
```
### 0.3: Write Tests for Missing Acceptance Criteria
**For each spec with missing coverage:**
1. Read spec file
2. Extract acceptance criteria section
3. For each criterion without a test:
- Write test directly validating that criterion
- Use Given-When-Then from spec
- Ensure test actually validates behavior
**Example:**
```typescript
// From spec: user-authentication.md
// AC-3: "Given user logs in, When session expires, Then user redirected to login"
describe('User Authentication - AC-3: Session Expiration', () => {
it('should redirect to login when session expires', async () => {
// Given: User is logged in
renderWithAuth(, { authenticated: true });
// When: Session expires
await act(async () => {
expireSession(); // Helper to expire token
});
// Then: User redirected to login
await waitFor(() => {
expect(mockNavigate).toHaveBeenCalledWith('/login');
});
});
});
```
### 0.4: Iterative Coverage Improvement
```bash
ITERATION=1
TARGET=85
MIN=80
while (( $(echo "$COVERAGE < $TARGET" | bc -l) )); do
echo "Iteration $ITERATION: ${COVERAGE}%"
# Stop conditions
if (( $(echo "$COVERAGE >= $MIN" | bc -l) )) && [ $ITERATION -gt 5 ]; then
echo "✅ Min coverage reached"
break
fi
# Find spec with lowest coverage
# Write tests for missing acceptance criteria
# Prioritize P0 > P1 > P2 specs
npm test -- --coverage --watchAll=false --silent
PREV=$COVERAGE
COVERAGE=$(jq '.total.lines.pct' coverage/coverage-summary.json)
GAIN=$(echo "$COVERAGE - $PREV" | bc)
# Diminishing returns?
if (( $(echo "$GAIN < 0.5" | bc -l) )) && (( $(echo "$COVERAGE >= $MIN" | bc -l) )); then
echo "✅ Diminishing returns (${GAIN}% gain)"
break
fi
ITERATION=$((ITERATION + 1))
[ $ITERATION -gt 10 ] && break
done
echo "✅ Phase 0 Complete: ${COVERAGE}% coverage"
```
### 0.5: Completion Marker
```bash
cat > .upgrade/stackshift-upgrade.yml < .upgrade/baseline-spec-status.txt
```
### 1.2: Dependency Analysis
```bash
# Current dependencies
npm list --depth=0 > .upgrade/dependencies-before.txt
# Outdated packages
npm outdated --json > .upgrade/outdated.json || echo "{}" > .upgrade/outdated.json
# Count major upgrades
MAJOR_COUNT=$(cat .upgrade/outdated.json | jq '[.[] | select(.current != .latest)] | length')
echo "Major upgrades: $MAJOR_COUNT"
```
### 1.3: Spec Impact Analysis
**For each major dependency upgrade, identify affected specs:**
```bash
# Create impact analysis
cat > .upgrade/spec-impact-analysis.json <<'EOF'
{
"react": {
"current": "17.0.2",
"latest": "19.2.0",
"breaking": true,
"affectedSpecs": [
"user-interface.md",
"form-handling.md"
],
"acceptanceCriteria": [
"user-interface.md: AC-1, AC-3",
"form-handling.md: AC-2"
],
"testFiles": [
"components/UserInterface.test.tsx"
],
"risk": "HIGH"
}
}
EOF
```
### 1.4: Generate Upgrade Plan
Create `.upgrade/UPGRADE_PLAN.md`:
```markdown
# Upgrade Plan
## Summary
- Dependencies to upgrade: ${MAJOR_COUNT} major versions
- Specs affected: [count from impact analysis]
- Risk level: [HIGH/MEDIUM/LOW]
- Estimated effort: 2-4 hours
## Critical Upgrades (Breaking Changes Expected)
### react: 17.0.2 → 19.2.0
- **Breaking Changes:**
- Automatic batching
- Hydration mismatches
- useId for SSR
- **Affected Specs:**
- user-interface.md (AC-1, AC-3, AC-5)
- form-handling.md (AC-2, AC-4)
- **Test Files:**
- components/UserInterface.test.tsx
- components/FormHandler.test.tsx
- **Risk:** HIGH
[Continue for all major upgrades...]
## Spec Impact Summary
### High-Risk Specs (Validate Carefully)
1. user-interface.md - React changes affect all components
2. form-handling.md - State batching changes
### Low-Risk Specs (Quick Validation)
[List specs unlikely to be affected]
## Upgrade Sequence
1. Update package.json versions
2. npm install
3. Fix TypeScript errors
4. Fix test failures (spec-guided)
5. Fix build errors
6. Validate with /speckit.analyze
```
### 1.5: Update Tracking
```bash
cat >> .upgrade/stackshift-upgrade.yml </dev/null && echo "Lint: ✅" || echo "Lint: ⚠️ OK"
# Must be green to proceed
```
### 2.2: Create Upgrade Branch
```bash
git checkout -b upgrade/dependencies-to-latest
git add .upgrade/
git commit -m "docs: upgrade baseline and plan
Phase 0: Coverage ${COVERAGE}%
Phase 1: Analysis complete
Specs: $SPEC_COUNT validated
Ready for Phase 2
"
```
### 2.3: Upgrade Dependencies
```bash
echo "=== Upgrading Dependencies ==="
# Upgrade to latest
npx npm-check-updates -u
npm install
# Update Node (optional but recommended)
echo "22.21.0" > .nvmrc
nvm install 22.21.0
nvm use
# Document changes
npm list --depth=0 > .upgrade/dependencies-after.txt
```
### 2.4: Detect Breaking Changes
```bash
echo "=== Testing After Upgrade ==="
npm test 2>&1 | tee .upgrade/test-results-post-upgrade.txt
# Extract failures
grep -E "FAIL|✕" .upgrade/test-results-post-upgrade.txt > .upgrade/failures.txt || true
FAILURE_COUNT=$(wc -l < .upgrade/failures.txt)
echo "Breaking changes: $FAILURE_COUNT test failures"
```
### 2.5: Spec-Guided Fix Loop
**Autonomous iteration until all tests pass:**
```bash
ITERATION=1
MAX_ITERATIONS=20
while ! npm test --silent 2>&1; do
echo "=== Fix Iteration $ITERATION ==="
# Get first failing test
FAILING_TEST=$(npm test 2>&1 | grep -m 1 "FAIL" | grep -oE "[^ ]+\.test\.[jt]sx?" || echo "")
if [ -z "$FAILING_TEST" ]; then
echo "No specific test file found, checking for general errors..."
npm test 2>&1 | head -50
break
fi
echo "Failing test: $FAILING_TEST"
# Find spec from coverage map
SPEC=$(jq -r "to_entries[] | select(.value.testFiles[] | contains(\"$FAILING_TEST\")) | .key" .upgrade/spec-coverage-map.json || echo "")
if [ -n "$SPEC" ]; then
echo "Validates spec: $SPEC"
echo "Loading spec acceptance criteria..."
cat ".specify/memory/specifications/$SPEC" | grep -A 20 "Acceptance Criteria"
fi
# FIX THE BREAKING CHANGE
# - Read spec acceptance criteria
# - Understand intended behavior
# - Fix code to preserve that behavior
# - Run test to verify fix
# Log fix
echo "[$ITERATION] Fixed: $FAILING_TEST (spec: $SPEC)" >> .upgrade/fixes-applied.log
# Commit incremental fix
git add -A
git commit -m "fix: breaking change in $FAILING_TEST
Spec: $SPEC
Fixed to preserve acceptance criteria behavior
"
ITERATION=$((ITERATION + 1))
if [ $ITERATION -gt $MAX_ITERATIONS ]; then
echo "⚠️ Max iterations reached - manual review needed"
break
fi
done
echo "✅ All tests passing"
```
### 2.6: Build & Lint
```bash
# Fix build
npm run build || (echo "Fixing build errors..." && [fix build])
# Fix lint (often ESLint 9 config changes)
npm run lint || (echo "Fixing lint..." && [update eslint.config.js])
```
### 2.7: Phase 2 Complete
```bash
npm test && npm run build && npm run lint
FINAL_COVERAGE=$(jq '.total.lines.pct' coverage/coverage-summary.json)
cat >> .upgrade/stackshift-upgrade.yml < .upgrade/UPGRADE_REPORT.md <> .upgrade/stackshift-upgrade.yml <&1 | grep FAIL
# 2. Find spec
jq '.[] | select(.testFiles[] | contains("failing-test.ts"))' .upgrade/spec-coverage-map.json
# 3. Read spec acceptance criteria
cat .specify/memory/specifications/[spec-name].md | grep -A 10 "Acceptance Criteria"
# 4. Fix to match spec
# 5. Verify with npm test
```
**"Can't reach 85% coverage"**
```bash
# Check which acceptance criteria lack tests
cat .upgrade/spec-coverage-map.json | jq '.[] | select(.missingCoverage | length > 0)'
# Write tests for those criteria
```
**"/speckit.analyze shows drift"**
```bash
# Review what changed
/speckit.analyze
# Fix code to match spec OR
# Update spec if intentional improvement
```
---
**Remember:** Specs are your north star. When breaking changes occur, specs tell you what behavior to preserve.