# StarPunk v1.5.0 Release Plan **Status**: Approved **Codename**: "Trigger" **Focus**: Stability, Test Coverage, and Technical Debt Reduction **Last Updated**: 2025-12-17 ## Overview v1.5.0 is a quality-focused release that addresses failing tests, increases test coverage to 90%, implements critical fixes from the v1.4.x review cycle, and resolves technical debt. No new user-facing features are planned. ## Goals 1. **Fix Failing Tests** - Resolve all 19 currently failing tests 2. **90% Test Coverage** - Increase overall test coverage to 90% minimum 3. **Technical Debt Reduction** - Address 6 specific backlog items 4. **Code Quality** - Better error handling, atomicity, and performance ## Phased Implementation Plan ### Phase 0: Test Fixes (Critical Path) **Priority**: Must complete first - unblocks all other phases #### Scope Address flaky and broken tests per ADR-012 (Flaky Test Removal): **REMOVE (5 tests)** - Architecturally broken multiprocessing tests: | Test | Reason | |------|--------| | `test_concurrent_workers_barrier_sync` | Cannot pickle Barrier objects | | `test_sequential_worker_startup` | Missing Flask app context | | `test_worker_late_arrival` | Missing Flask app context | | `test_single_worker_performance` | Cannot pickle local functions | | `test_concurrent_workers_performance` | Cannot pickle local functions | **FIX (4 tests)** - Valuable tests needing adjustments: | Test | Fix Required | |------|--------------| | `test_debug_level_for_early_retries` | Configure logger level in test | | `test_new_connection_per_retry` | Adjust assertion count | | Feed XML tests | Change ` Dict[int, List[dict]]: """Batch load media for multiple notes in single query.""" ``` 2. Create batch loading functions in `starpunk/tags.py`: ```python def get_tags_for_notes(note_ids: List[int]) -> Dict[int, List[dict]]: """Batch load tags for multiple notes in single query.""" ``` 3. Update `_get_cached_notes()` in `starpunk/routes/public.py`: - Use batch loading instead of per-note queries - Maintain same output format #### Acceptance Criteria - [ ] Feed generation uses batch queries - [ ] Query count reduced from O(n) to O(1) for media/tags - [ ] No change to API behavior - [ ] Performance improvement verified in tests - [ ] Other N+1 locations documented in BACKLOG.md (not fixed) #### Dependencies - Phase 0 complete --- ### Phase 4: Atomic Variant Generation **Priority**: Medium - Data integrity #### Scope Make variant file generation atomic with database commits to prevent orphaned files. #### Implementation 1. Modify `generate_all_variants()` in `starpunk/media.py`: - Write variants to temporary directory first - Perform database inserts in transaction - Move files to final location after successful commit - Clean up temp files on any failure 2. Add startup recovery: - Detect orphaned variant files on startup - Log warnings for orphans found - Optionally clean up orphans #### Flow ``` 1. Generate variants to temp directory (data/media/.tmp/) 2. BEGIN TRANSACTION 3. INSERT media record 4. INSERT variant records 5. COMMIT 6. Move files from temp to final location 7. On failure: ROLLBACK, delete temp files ``` #### Acceptance Criteria - [ ] No orphaned files on database failures - [ ] No orphaned DB records on file failures - [ ] Atomic operation for all media saves - [ ] Startup recovery detects orphans - [ ] Tests simulate failure scenarios #### Dependencies - Phase 0 complete --- ### Phase 5: Test Coverage Expansion **Priority**: Medium - Quality assurance #### Scope Increase overall test coverage to 90% minimum. #### Approach 1. Run coverage report: `uv run pytest --cov=starpunk --cov-report=html` 2. Identify modules below 90% coverage 3. Prioritize based on risk and complexity 4. Write tests for uncovered paths #### Known Coverage Gaps (to verify) - MPO format handling (untested) - Edge cases in error paths - Configuration validation paths - Startup/shutdown hooks #### Specific Test Additions 1. **MPO Format Tests** (`tests/test_media_upload.py`): - `test_mpo_detection_and_conversion()` - `test_mpo_corrupted_file()` - `test_mpo_single_frame()` 2. **Debug File Tests** (new test file or extend `test_media_upload.py`): - `test_debug_file_disabled_by_default()` - `test_debug_file_cleanup_old_files()` - `test_debug_file_size_limit()` - `test_debug_filename_sanitization()` 3. **Batch Loading Tests**: - `test_get_media_for_notes_batch()` - `test_get_tags_for_notes_batch()` - `test_batch_with_empty_list()` #### Acceptance Criteria - [ ] Overall coverage >= 90% - [ ] No module below 85% coverage - [ ] All new code in v1.5.0 has 100% coverage - [ ] MPO handling fully tested #### Dependencies - Phases 1-4 complete (tests cover new functionality) --- ## Out of Scope Items explicitly excluded from v1.5.0: | Item | Reason | |------|--------| | Rate limiting | Handled by reverse proxy (Caddy/Nginx) | | Schema changes | Not needed for v1.5.0 fixes | | New user features | Quality-focused release | | N+1 fixes in admin/search | Low traffic, deferred to BACKLOG | | UI changes | No frontend work planned | --- ## Recommendation: Single Release vs. Multiple Patches **Recommendation: Single v1.5.0 Release** ### Rationale 1. **Phase Dependencies**: Most phases depend on Phase 0 (test fixes). Splitting would create artificial release boundaries. 2. **Cognitive Overhead**: Multiple patch releases (1.5.1, 1.5.2, etc.) require: - Multiple changelog entries - Multiple version bumps - Multiple release notes - More git tags/branches 3. **Test Coverage Integration**: Test coverage work (Phase 5) tests functionality from Phases 1-4. Separating them creates incomplete test coverage. 4. **User Experience**: Users prefer fewer, more significant updates over many small patches. 5. **Scope Alignment**: All v1.5.0 work is internally focused (no external API changes). Users see one "quality improvement" release. ### Exception If Phase 0 (test fixes) reveals critical bugs affecting production, those fixes should be: - Backported to a v1.4.3 patch release on the current branch - Then merged forward to v1.5.0 ### Alternative Considered Splitting into: - v1.5.0: Phase 0 (test fixes) + Phase 1 (slugs) - v1.5.1: Phase 2-4 (technical debt) - v1.5.2: Phase 5 (test coverage) **Rejected** because test coverage work must test the new functionality, making separation counterproductive. --- ## Success Criteria | # | Criterion | Verification | |---|-----------|--------------| | 1 | All tests pass | `uv run pytest` shows 0 failures | | 2 | Coverage >= 90% | `uv run pytest --cov=starpunk` | | 3 | MPO tested | MPO tests in test suite | | 4 | Debug cleanup works | Manual verification + tests | | 5 | N+1 fixed in feed | Performance tests show improvement | | 6 | Variants atomic | Failure simulation tests pass | | 7 | Slugs timestamp-based | New notes use `YYYYMMDDHHMMSS` format | | 8 | No regressions | Full test suite passes | | 9 | ADRs documented | ADR-062 in `/docs/decisions/` | --- ## Related Documentation - ADR-062: Timestamp-Based Slug Format (supersedes ADR-007) - ADR-007: Slug Generation Algorithm (superseded) - BACKLOG.md: Deferred N+1 query locations documented - v1.4.2 Architect Review: Source of many v1.5.0 items --- ## Implementation Timeline | Phase | Estimated Effort | Dependencies | |-------|------------------|--------------| | Phase 0: Test Fixes | 2-4 hours | None | | Phase 1: Timestamp Slugs | 2-3 hours | Phase 0 | | Phase 2: Debug Files | 3-4 hours | Phase 0 | | Phase 3: N+1 Fix | 3-4 hours | Phase 0 | | Phase 4: Atomic Variants | 4-6 hours | Phase 0 | | Phase 5: Coverage | 4-8 hours | Phases 1-4 | **Total Estimated**: 18-29 hours --- ## Post-Release After v1.5.0 ships, update BACKLOG.md to move completed items to "Recently Completed" section: - MPO Format Test Coverage - Debug File Storage Cleanup - Filename Sanitization - N+1 Query Fix (Feed Generation - partial) - Atomic Variant Generation - Default Slug Change