homebridge-rabbitair
Version:
Homebridge plugin for RabbitAir air purifiers
1,091 lines (854 loc) • 28.1 kB
Markdown
# Implementation Plan: Migrate to hap-fluent & hap-test
**Refactor ID**: refactor-001
**Branch**: `refactor/001-migrate-hap-fluent`
**Created**: 2025-12-30
**Status**: Planning → Ready for Phase 0
## Plan Overview
This plan breaks down the refactoring into actionable tasks across 6 phases. Each phase has clear deliverables, success criteria, and dependencies.
**Total Estimated Time**: 25-36 hours
**Recommended Approach**: 1 week intensive OR 2-3 weeks part-time
**Risk Level**: MEDIUM
## Constitution Compliance Check
### Refactor-Specific Quality Gates
✅ **Testing Gap Assessment** (Phase 0)
- Coverage gaps identified in [testing-gaps.md](./testing-gaps.md)
- Critical gaps documented: Service registration, Network resilience, E2E workflows
- Acceptance criteria defined for each gap
- Must complete before baseline capture
✅ **Baseline Metrics Capture** (Post-Phase 0)
- Baseline metrics partially captured in [metrics-before.md](./metrics-before.md)
- Must capture comprehensive metrics after Phase 0 test additions
- Metrics will establish comparison point
✅ **Behavior Preservation**
- All behaviors documented in [behavioral-snapshot.md](./behavioral-snapshot.md)
- Immutable contracts defined (HomeKit services, UDP protocol, configuration)
- Test suite will validate no behavior changes
✅ **Incremental Validation**
- Each phase ends with all tests passing
- Rollback points at phase boundaries
- Mocha tests run in parallel with Vitest during migration
### Constitution Principles Alignment
| Principle | How This Refactor Aligns |
|-----------|--------------------------|
| **I. Test-First Discipline** | Phase 0 fills testing gaps BEFORE refactoring code; new tests written for all changes |
| **II. TypeScript Strict Mode** | hap-fluent improves type safety; eliminates string-based characteristic keys |
| **III. Semantic Versioning** | No breaking changes = PATCH version bump only |
| **IV. HomeKit Protocol Fidelity** | Behavior preservation guarantees no HomeKit contract changes |
| **V. Code Quality Standards** | All code passes oxlint/oxfmt; strict mode enforced |
**Constitution Verdict**: ✅ **APPROVED** - Refactor aligns with all constitution principles
## Phase 0: Testing Gap Assessment (CRITICAL FIRST STEP)
**Timeline**: 4-6 hours
**Status**: 🔴 NOT STARTED
**Priority**: CRITICAL - Must complete before any refactoring
### Objectives
- Address critical test coverage gaps identified in testing-gaps.md
- Establish baseline test suite to validate behavior preservation
- Improve coverage from ~30% to ≥60%
- Verify all tests passing before capturing baseline metrics
### Prerequisites
- ✅ Refactor branch created: `refactor/001-migrate-hap-fluent`
- ✅ Testing gaps identified and documented
- ✅ Behavioral snapshot documented
### Tasks
#### Task 0.1: Install Vitest & hap-test (30 min)
```bash
pnpm add -D vitest @vitest/coverage-istanbul @pmouli/hap-test
```
**Create**: `vitest.config.ts`
```typescript
import { defineConfig } from 'vitest/config';
export default defineConfig({
test: {
globals: true,
environment: 'node',
coverage: {
enabled: true,
provider: 'istanbul',
reporter: ['text', 'json', 'html', 'lcov'],
reportsDirectory: './coverage',
include: ['src/**/*.ts'],
exclude: ['**/*.d.ts', 'test/**', 'dist/**'],
},
include: ['test/**/*.test.ts'],
testTimeout: 5000,
},
});
```
**Update**: `package.json` scripts
```json
{
"scripts": {
"test": "mocha --require tsx 'test/**/*.test.ts'",
"test:vitest": "vitest run",
"test:vitest:watch": "vitest",
"test:coverage": "vitest run --coverage"
}
}
```
**Verify**:
- [ ] `pnpm test:vitest` runs successfully (even with 0 tests)
- [ ] TypeScript imports resolve for vitest and hap-test
#### Task 0.2: Service Registration Tests (2 hours)
**Gap**: ❌ Service registration - 0% coverage → 100%
**File**: Create `test/unit/platform-accessory-services.test.ts`
**Tests to Write**:
```typescript
describe('RabbitAirAccessory - Service Registration', () => {
it('should register Air Purifier service', () => {
// Assert service exists with correct UUID
});
it('should register Air Quality Sensor service', () => {
// Assert service exists with correct UUID
});
it('should register all required characteristics for Air Purifier', () => {
// Assert: Active, CurrentState, TargetState, RotationSpeed,
// FilterLifeLevel, FilterChangeIndication all present
});
it('should register Air Quality characteristic', () => {
// Assert AirQuality characteristic present
});
it('should set correct characteristic types and ranges', () => {
// Assert RotationSpeed 0-100, FilterLifeLevel 0-100, etc.
});
});
```
**Success Criteria**:
- [ ] All service registration tests pass
- [ ] Both services verified to exist
- [ ] All characteristics verified with correct types
- [ ] Ranges validated
#### Task 0.3: Characteristic Handler Tests (3 hours)
**Gap**: ⚠️ Characteristic handlers - 40% → 100% coverage
**File**: Expand `test/unit/platformAccessory.test.ts`
**Tests to Write**:
```typescript
describe('RabbitAirAccessory - Characteristic Handlers', () => {
describe('Active Characteristic', () => {
it('should call setActive when Active is set', async () => {
// Mock client.setPower()
// Set Active = 1
// Verify client.setPower(true) called
});
it('should return active state from getActive', async () => {
// Mock device state power = true
// Get Active characteristic
// Verify returns 1
});
});
describe('RotationSpeed Characteristic', () => {
it('should transform HomeKit 0-25% to Silent speed', async () => {
// Set RotationSpeed = 20
// Verify client.setSpeed('silent') called
});
it('should transform HomeKit 50% to Medium speed', async () => {
// Set RotationSpeed = 50
// Verify client.setSpeed('medium') called
});
it('should transform HomeKit 100% to Turbo speed', async () => {
// Set RotationSpeed = 100
// Verify client.setSpeed('turbo') called
});
it('should return correct percentage from device speed', async () => {
// Mock device speed = 'high'
// Get RotationSpeed
// Verify returns 75
});
});
describe('FilterLifeLevel Characteristic', () => {
it('should return filter life percentage', async () => {
// Mock device filterLife = 85
// Get FilterLifeLevel
// Verify returns 85
});
});
describe('FilterChangeIndication', () => {
it('should indicate change needed when life < 10%', async () => {
// Mock device filterLife = 5
// Get FilterChangeIndication
// Verify returns 1 (change needed)
});
it('should indicate no change when life >= 10%', async () => {
// Mock device filterLife = 75
// Get FilterChangeIndication
// Verify returns 0 (OK)
});
});
describe('Error Handling', () => {
it('should handle client errors gracefully', async () => {
// Mock client.setPower() to throw error
// Set Active = 1
// Verify error caught and logged, doesn't crash
});
});
});
```
**Success Criteria**:
- [ ] All handler tests pass
- [ ] All onSet handlers tested
- [ ] All onGet handlers tested
- [ ] Value transformations validated
- [ ] Error handling tested
#### Task 0.4: Network Protocol Tests (1 hour)
**Gap**: ⚠️ Network timeout/retry logic - 30% → 100%
**File**: Expand `test/unit/rabbitair-client.test.ts`
**Tests to Write**:
```typescript
describe('RabbitAirClient - Network Resilience', () => {
it('should timeout after 3 seconds with no response', async () => {
// Mock socket to never call callback
// Call client.setPower()
// Verify timeout after 3 seconds
});
it('should retry on network error', async () => {
// Mock socket.send to fail once, then succeed
// Call client.setPower()
// Verify send called twice (retry)
});
it('should fail after 3 retry attempts', async () => {
// Mock socket.send to always fail
// Call client.setPower()
// Verify throws error after 3 attempts
});
it('should parse device response correctly', async () => {
// Mock device response buffer
// Call client.getState()
// Verify state parsed correctly
});
});
```
**Success Criteria**:
- [ ] Timeout tests pass
- [ ] Retry logic tests pass
- [ ] Max retries enforcement tested
- [ ] Response parsing tested
#### Task 0.5: Platform Lifecycle Tests (1 hour)
**Gap**: ⚠️ Platform lifecycle - 20% → 100%
**File**: Expand `test/unit/platform.test.ts`
**Tests to Write**:
```typescript
describe('RabbitAirPlatform - Lifecycle', () => {
it('should initialize with valid configuration', async () => {
// Create platform with valid config
// Assert platform initialized
});
it('should discover devices from config', async () => {
// Config with 2 devices
// Assert 2 accessories registered
});
it('should restore cached accessories', async () => {
// Provide cached accessories
// Assert restored and configured
});
it('should validate device token length', async () => {
// Config with invalid token (31 chars)
// Assert error logged, device skipped
});
it('should validate required host field', async () => {
// Config missing host
// Assert error logged, device skipped
});
});
```
**Success Criteria**:
- [ ] Platform initialization tested
- [ ] Device discovery tested
- [ ] Cached accessory restoration tested
- [ ] Configuration validation tested
#### Task 0.6: Network Resilience Smoke Tests (1 hour)
**Gap**: ❌ Network resilience - 0% → Basic coverage
**File**: Create `test/integration/network-resilience.test.ts`
**Tests to Write**:
```typescript
import { TestHarness, NetworkSimulator } from '@pmouli/hap-test';
describe('Network Resilience - Smoke Tests', () => {
let harness: TestHarness;
let simulator: NetworkSimulator;
beforeEach(async () => {
harness = await TestHarness.create({
platformConstructor: RabbitAirPlatform,
platformConfig: { /* ... */ },
});
simulator = new NetworkSimulator();
});
it('should handle 200ms latency', async () => {
simulator.setLatency(200);
// Set characteristic with latency
// Assert eventually succeeds
});
it('should handle 50% packet loss', async () => {
simulator.setPacketLoss(0.5);
// Set characteristic with packet loss
// Assert eventually succeeds via retries
});
});
```
**Success Criteria**:
- [ ] Basic latency test passes
- [ ] Basic packet loss test passes
- [ ] hap-test integration working
#### Task 0.7: E2E Workflow Skeleton (1 hour)
**Gap**: ❌ E2E workflows - 0% → Basic coverage
**File**: Create `test/e2e/rabbitair-plugin.test.ts`
**Tests to Write**:
```typescript
describe('RabbitAir Plugin E2E - Smoke Test', () => {
it('should complete basic workflow', async () => {
// 1. Initialize platform
// 2. Verify accessory registered
// 3. Turn on device
// 4. Verify state updates
// Assert basic flow works
});
});
```
**Success Criteria**:
- [ ] Basic E2E test passes
- [ ] E2E test infrastructure working
### Phase 0 Completion Checklist
**Tests Added**:
- [ ] Service registration tests (5+ tests)
- [ ] Characteristic handler tests (15+ tests)
- [ ] Network protocol tests (4+ tests)
- [ ] Platform lifecycle tests (5+ tests)
- [ ] Network resilience smoke tests (2+ tests)
- [ ] E2E workflow skeleton (1+ test)
**Verification**:
- [ ] All Mocha tests still pass: `pnpm test`
- [ ] All Vitest tests pass: `pnpm test:vitest`
- [ ] Coverage improved to ≥60%: `pnpm test:coverage`
- [ ] No test failures or errors
- [ ] Code passes oxlint: `pnpm lint`
**Deliverables**:
- [ ] vitest.config.ts created
- [ ] package.json updated with test scripts
- [ ] 30+ new tests added across unit/integration/e2e
- [ ] All tests passing
- [ ] Coverage report generated
**Ready for Baseline Capture**:
- [ ] Run comprehensive baseline metrics capture
- [ ] Update metrics-before.md with coverage data
- [ ] Tag commit: `git tag refactor-001-baseline`
## Phase 1: Setup & Dependencies
**Timeline**: 2-3 hours
**Status**: 🟡 WAITING (blocked by Phase 0)
**Prerequisites**: Phase 0 complete, baseline captured
### Objectives
- Install hap-fluent library
- Configure TypeScript for fluent API
- Verify existing tests still pass
- Establish dual test framework (Mocha + Vitest)
### Tasks
#### Task 1.1: Install hap-fluent (15 min)
```bash
pnpm add hap-fluent
```
**Verify**:
- [ ] hap-fluent installed in package.json dependencies
- [ ] TypeScript can import from 'hap-fluent'
#### Task 1.2: Update TypeScript Configuration (15 min)
**File**: `tsconfig.json`
Ensure test files included:
```json
{
"compilerOptions": {
"types": ["node", "vitest/globals"]
},
"include": ["src/**/*", "test/**/*"]
}
```
**Verify**:
- [ ] TypeScript compilation passes: `pnpm build`
- [ ] No type errors in IDE
#### Task 1.3: Verify Test Framework Coexistence (30 min)
Run both frameworks:
```bash
pnpm test # Mocha (existing tests)
pnpm test:vitest # Vitest (Phase 0 tests)
```
**Troubleshoot if needed**:
- Resolve any import conflicts
- Adjust test timeouts if needed
- Fix any environment-specific issues
**Verify**:
- [ ] All Mocha tests pass
- [ ] All Vitest tests pass
- [ ] No conflicts between frameworks
#### Task 1.4: Document Setup (30 min)
Update `README.md`:
- Add hap-fluent to dependencies section
- Document new test commands
- Add development setup instructions
**Verify**:
- [ ] README.md updated
- [ ] Setup instructions clear and complete
### Phase 1 Completion Checklist
- [ ] hap-fluent installed and imports resolve
- [ ] TypeScript configuration updated
- [ ] Both test frameworks pass
- [ ] Documentation updated
- [ ] No regressions in existing functionality
- [ ] Ready to begin refactoring code
## Phase 2: Refactor with hap-fluent
**Timeline**: 4-6 hours
**Status**: 🟡 WAITING (blocked by Phase 1)
**Prerequisites**: Phase 1 complete
### Objectives
- Migrate RabbitAirAccessory to fluent API
- Migrate RabbitAirPlatform for fluent compatibility
- **GUARANTEE**: No external behavior changes
- All existing Mocha tests must pass unmodified
### Tasks
#### Task 2.1: Create Fluent Accessory Handler (2 hours)
**File**: `src/platformAccessory.ts`
**Changes**:
1. Import AccessoryHandler from hap-fluent
2. Add private handler field
3. Replace service setup in constructor with fluent API
**Before**:
```typescript
const service = this.accessory.getService(this.platform.Service.AirPurifier)
|| this.accessory.addService(this.platform.Service.AirPurifier);
service.getCharacteristic(this.platform.Characteristic.Active)
.onSet(this.setActive.bind(this))
.onGet(this.getActive.bind(this));
// ... repeated for 8+ characteristics
```
**After**:
```typescript
import { AccessoryHandler } from 'hap-fluent';
export class RabbitAirAccessory {
private handler: AccessoryHandler;
constructor(
private readonly platform: RabbitAirPlatform,
private readonly accessory: PlatformAccessory,
) {
this.handler = new AccessoryHandler(this, accessory);
const { airPurifier, airQuality } = this.handler
.service('AirPurifier', 'Air Purifier')
.characteristic('active')
.onGet(async () => this.getActive())
.onSet(async (value) => this.setActive(value))
.parent
.characteristic('currentAirPurifierState')
.onGet(async () => this.getCurrentState())
.parent
.characteristic('targetAirPurifierState')
.onSet(async (value) => this.setTargetState(value))
.onGet(async () => this.getTargetState())
.parent
.characteristic('rotationSpeed')
.onSet(async (value) => this.setRotationSpeed(value))
.onGet(async () => this.getRotationSpeed())
.parent
.characteristic('filterLifeLevel')
.onGet(async () => this.getFilterLife())
.parent
.characteristic('filterChangeIndication')
.onGet(async () => this.getFilterChangeIndication())
.parent
.service('AirQualitySensor', 'Air Quality')
.characteristic('airQuality')
.onGet(async () => this.getAirQuality())
.parent
.build();
}
}
```
**Verify**:
- [ ] TypeScript compiles without errors
- [ ] All existing Mocha tests still pass
- [ ] Code passes oxlint
#### Task 2.2: Add Type-Safe Interfaces (1 hour)
**File**: `src/platformAccessory.ts`
```typescript
import type { InterfaceFor } from 'hap-fluent';
import { Service } from 'hap-nodejs';
type AirPurifierInterface = InterfaceFor<typeof Service.AirPurifier>;
type AirQualitySensorInterface = InterfaceFor<typeof Service.AirQualitySensor>;
```
Use in methods for type safety:
```typescript
private async updateAirPurifierState(state: AirPurifierInterface['currentAirPurifierState']): Promise<void> {
// Type-safe state updates
}
```
**Verify**:
- [ ] Type interfaces compile
- [ ] Methods use typed interfaces
- [ ] No `any` types introduced
#### Task 2.3: Update Platform Initialization (1 hour)
**File**: `src/platform.ts`
Ensure platform initialization compatible with fluent accessory:
- Verify accessory construction still works
- No changes needed if accessory handles own setup
**Verify**:
- [ ] Platform initializes correctly
- [ ] Accessories registered successfully
- [ ] All existing tests pass
#### Task 2.4: Run Full Test Suite (30 min)
```bash
pnpm test # All Mocha tests must pass
pnpm test:vitest # All Vitest tests must pass
pnpm lint # Must pass oxlint
pnpm build # Must compile successfully
```
**Verify**:
- [ ] **CRITICAL**: All existing Mocha tests pass WITHOUT modification
- [ ] All Vitest tests pass
- [ ] No lint errors
- [ ] Build succeeds
- [ ] No behavior changes observed
### Phase 2 Completion Checklist
- [ ] RabbitAirAccessory uses fluent API
- [ ] Type-safe interfaces implemented
- [ ] Platform initialization updated
- [ ] **ALL existing tests pass unmodified**
- [ ] Code passes oxlint/oxfmt
- [ ] TypeScript strict mode compliance
- [ ] Commit with message: `refactor: migrate platformAccessory to hap-fluent`
## Phase 3: Unit Testing with hap-test
**Timeline**: 6-8 hours
**Status**: 🟡 WAITING (blocked by Phase 2)
**Prerequisites**: Phase 2 complete
### Objectives
- Expand unit test coverage to >80%
- Test all fluent API setup
- Test all characteristic handlers comprehensively
- Establish testing patterns
### Tasks
#### Task 3.1: Expand RabbitAirClient Tests (2 hours)
**File**: `test/unit/rabbitair-client.test.ts`
Add comprehensive protocol tests:
- All UDP command formats
- Response parsing for all commands
- Error scenarios
- Edge cases
**Target**: 100% coverage of rabbitAirClient.ts
#### Task 3.2: Expand platformAccessory Tests (3 hours)
**File**: `test/unit/platform-accessory.test.ts`
Test all aspects:
- Fluent service setup verification
- All characteristic handler operations
- Value transformations in detail
- Error handling scenarios
- State update mechanisms
**Target**: 90%+ coverage of platformAccessory.ts
#### Task 3.3: Expand Platform Tests (2 hours)
**File**: `test/unit/platform.test.ts`
Test platform thoroughly:
- Configuration loading variations
- Multi-device scenarios
- Cached accessory handling
- Error scenarios
**Target**: 85%+ coverage of platform.ts
#### Task 3.4: Generate Coverage Report (30 min)
```bash
pnpm test:coverage
```
Review coverage report:
- Check line coverage by file
- Identify any remaining gaps
- Document justified exclusions
**Verify**:
- [ ] Overall coverage >80%
- [ ] src/ directory coverage >80%
- [ ] Critical paths 100% covered
### Phase 3 Completion Checklist
- [ ] Unit test coverage >80%
- [ ] All protocol tests comprehensive
- [ ] All handler tests comprehensive
- [ ] Platform tests comprehensive
- [ ] Coverage report generated and reviewed
- [ ] All tests passing
- [ ] Commit: `test: expand unit test coverage with hap-test`
## Phase 4: Integration Testing
**Timeline**: 4-6 hours
**Status**: 🟡 WAITING (blocked by Phase 3)
**Prerequisites**: Phase 3 complete
### Objectives
- Test component interactions
- Validate network resilience with NetworkSimulator
- Test state synchronization flows end-to-end
### Tasks
#### Task 4.1: Platform Lifecycle Integration (2 hours)
**File**: `test/integration/platform-lifecycle.test.ts`
Tests:
- Full startup sequence
- Cached accessory restoration
- Multi-device scenarios
- Platform restart scenarios
#### Task 4.2: Network Resilience Tests (2 hours)
**File**: `test/integration/network-resilience.test.ts`
Comprehensive network testing:
- Latency scenarios (50ms, 200ms, 500ms)
- Packet loss scenarios (10%, 50%, 90%)
- Disconnection/reconnection flows
- Timeout behavior validation
- Concurrent request handling
#### Task 4.3: State Synchronization Tests (1 hour)
**File**: `test/integration/accessory-updates.test.ts`
Tests:
- Device → HomeKit characteristic updates
- HomeKit → Device command flow
- Bidirectional state consistency
- Polling behavior
- Filter status updates
### Phase 4 Completion Checklist
- [ ] All integration tests pass
- [ ] Network resilience thoroughly tested
- [ ] State synchronization validated
- [ ] No test flakiness
- [ ] Commit: `test: add comprehensive integration tests`
## Phase 5: E2E Testing & Documentation
**Timeline**: 3-4 hours
**Status**: 🟡 WAITING (blocked by Phase 4)
**Prerequisites**: Phase 4 complete
### Objectives
- Complete E2E workflow tests
- Update all documentation
- Create developer guides
### Tasks
#### Task 5.1: Complete E2E Tests (2 hours)
**File**: `test/e2e/rabbitair-plugin.test.ts`
Full workflow tests:
- Complete user workflow (power on → mode change → speed adjust)
- Multi-device workflow
- Error recovery workflow
- Long-running stability test
#### Task 5.2: Update Documentation (1-2 hours)
**TESTING.md**:
- Add hap-test usage guide
- Document test structure
- Add testing best practices
- Network resilience testing patterns
**README.md**:
- Add hap-fluent examples
- Update development section
- Document new test commands
**Create MIGRATION.md**:
- Document refactoring changes
- Explain fluent API benefits
- Guide for future contributors
### Phase 5 Completion Checklist
- [ ] E2E tests comprehensive
- [ ] TESTING.md updated
- [ ] README.md updated
- [ ] MIGRATION.md created
- [ ] All documentation reviewed
- [ ] Commit: `docs: update for hap-fluent and hap-test`
## Phase 6: Framework Migration & Cleanup
**Timeline**: 2-3 hours
**Status**: 🟡 WAITING (blocked by Phase 5)
**Prerequisites**: Phase 5 complete
### Objectives
- Migrate remaining Mocha tests to Vitest
- Remove Mocha dependencies
- Finalize testing infrastructure
### Tasks
#### Task 6.1: Migrate Mocha Tests (1-2 hours)
Convert test files from Mocha format to Vitest:
- Update imports (Mocha → Vitest)
- Update describe/it syntax if needed
- Update assertion style
- Update mock syntax
**Files to migrate**:
- `test/unit/*.test.ts` (if any remain)
- `test/integration/*.test.ts` (if any remain)
#### Task 6.2: Remove Mocha Dependencies (30 min)
**File**: `package.json`
Remove:
- mocha
- chai
- sinon
- @types/mocha
- @types/chai
- @types/sinon
Update scripts:
```json
{
"scripts": {
"test": "vitest run",
"test:watch": "vitest",
"test:coverage": "vitest run --coverage"
}
}
```
#### Task 6.3: Update CI/CD Pipeline (30 min)
**File**: `.github/workflows/*.yml` (if exists)
Update test commands to use Vitest:
```yaml
- name: Run tests
run: pnpm test
- name: Generate coverage
run: pnpm test:coverage
```
#### Task 6.4: Final Verification (30 min)
Run complete test suite:
```bash
pnpm test
pnpm test:coverage
pnpm lint
pnpm build
```
**Verify**:
- [ ] All tests pass
- [ ] Coverage >80%
- [ ] No lint errors
- [ ] Build succeeds
- [ ] No Mocha remnants
### Phase 6 Completion Checklist
- [ ] All tests migrated to Vitest
- [ ] Mocha dependencies removed
- [ ] CI/CD updated
- [ ] All tests passing
- [ ] Final coverage >80%
- [ ] Commit: `chore: complete migration to Vitest`
## Post-Refactor Validation
### Final Verification Steps
1. **Capture After Metrics**
```bash
# Build time
time pnpm build
# Test execution time
time pnpm test
# Coverage report
pnpm test:coverage
# Bundle size
du -sh dist/
```
2. **Update metrics-after.md**
- Compare with metrics-before.md
- Document improvements
- Note any regressions
3. **Verify Behavioral Snapshot**
- All behaviors from behavioral-snapshot.md still valid
- No observable changes
- HomeKit contracts preserved
4. **Run Extended Tests**
- Let tests run multiple times to catch flakiness
- Test on different environments if possible
### Success Validation Checklist
**Absolute Requirements** (MUST ALL PASS):
- [ ] All tests pass (100% pass rate)
- [ ] Coverage >80% for src/
- [ ] No breaking changes (behavioral snapshot validated)
- [ ] No lint errors
- [ ] Build succeeds
- [ ] TypeScript strict mode compliance
- [ ] No `any` types introduced
**Strong Goals**:
- [ ] Boilerplate reduced by 30%+
- [ ] Type safety improved
- [ ] Test execution faster than before
- [ ] Developer experience improved
### Merge to Main
Once all validation passes:
1. **Commit final changes**
```bash
git add .
git commit -m "refactor: complete migration to hap-fluent and hap-test
- Migrate platformAccessory to fluent API
- Replace Mocha with Vitest
- Add comprehensive test coverage (>80%)
- Improve type safety with hap-fluent
- Add network resilience testing with hap-test
BREAKING CHANGE: None (all external behavior preserved)"
```
2. **Create PR**
- Title: "Refactor: Migrate to hap-fluent & hap-test"
- Link to refactor-spec.md
- Summarize changes
- Highlight no breaking changes
3. **Merge and tag**
```bash
git checkout latest
git merge refactor/001-migrate-hap-fluent
git tag v1.0.6 # PATCH version (no breaking changes)
git push origin latest --tags
```
## Rollback Procedures
If issues discovered at any phase:
### Immediate Rollback
```bash
# Discard all changes and return to baseline
git reset --hard refactor-001-baseline
```
### Selective Rollback
```bash
# Rollback to specific phase
git log --oneline
git reset --hard <phase-commit-sha>
```
### Emergency Rollback
If merged to main and issues found:
```bash
# Revert the merge commit
git revert -m 1 <merge-commit-sha>
git push origin latest
```
## Risk Management
### High-Risk Areas
1. **Service registration changes** - Most likely to break HomeKit
- Mitigation: Phase 0 tests validate before refactor
- Rollback: Can revert platformAccessory.ts only
2. **Network protocol behavior** - Could affect device communication
- Mitigation: RabbitAirClient untouched; only test coverage added
- Rollback: Phase-specific rollback
3. **State synchronization** - Could cause inconsistent states
- Mitigation: Integration tests validate bidirectional flow
- Rollback: Phase 4 boundary
### Monitoring Post-Merge
- Watch for GitHub issues related to HomeKit connectivity
- Monitor for device communication failures
- Check for test failures in CI/CD
## Summary
**Total Tasks**: ~35 tasks across 6 phases
**Total Estimated Time**: 25-36 hours
**Risk Level**: MEDIUM (with comprehensive mitigation)
**Critical Path**:
Phase 0 (testing gaps) → Phase 1 (setup) → Phase 2 (refactor) → Phase 3-6 (testing & cleanup)
**Key Success Factors**:
1. Complete Phase 0 before any code refactoring
2. Keep all existing tests passing throughout
3. Validate at each phase boundary
4. Comprehensive testing at all levels
**Next Action**: Begin Phase 0 - Testing Gap Assessment