# 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 Fix the 19 failing tests identified in the current test suite: | Category | Count | Tests | |----------|-------|-------| | Migration Performance | 2 | `test_single_worker_performance`, `test_concurrent_workers_performance` | | Feed Route (Streaming) | 1 | `test_feed_route_streaming` | | Feed Endpoints | 3 | `test_feed_rss_endpoint`, `test_feed_json_endpoint`, `test_feed_xml_legacy_endpoint` | | Content Negotiation | 6 | `test_accept_rss`, `test_accept_json_feed`, `test_accept_json_generic`, `test_accept_wildcard`, `test_no_accept_header`, `test_quality_factor_json_wins` | | Backward Compatibility | 1 | `test_feed_xml_contains_rss` | | Search Security | 1 | `test_search_escapes_html_in_note_content` | #### Approach 1. Investigate each failing test category 2. Determine if failure is test issue or code issue 3. Fix appropriately (prefer fixing tests over changing working code) 4. Document any behavioral changes #### Acceptance Criteria - [ ] All 879 tests pass - [ ] No test skips added (unless justified) - [ ] No test timeouts #### Dependencies None - this is the first phase --- ### Phase 1: Timestamp-Based Slugs **Priority**: High - Addresses user-reported issue #### Scope Implement ADR-062 to change default slug format from content-based to timestamp-based. #### Implementation 1. Update `starpunk/slug_utils.py`: - Change `generate_slug()` to use timestamp format `YYYYMMDDHHMMSS` - Update collision handling to use sequential suffix (`-1`, `-2`, etc.) - Preserve custom slug functionality 2. Update `starpunk/notes.py`: - Remove content parameter from slug generation calls 3. Update tests: - Modify expected slug formats in test assertions - Add tests for new timestamp format - Add tests for sequential collision handling #### Acceptance Criteria - [ ] Default slugs use `YYYYMMDDHHMMSS` format - [ ] Collision handling uses `-1`, `-2` suffix - [ ] Custom slugs via `mp-slug` work unchanged - [ ] Custom slugs via web UI work unchanged - [ ] Existing notes unaffected - [ ] ADR-062 referenced in code comments #### Dependencies - Phase 0 complete (all tests passing) --- ### Phase 2: Debug File Management **Priority**: Medium - Security and operations concern #### Scope Implement cleanup mechanism for failed upload debug files and add configuration controls. #### Implementation 1. Add configuration options: ```python DEBUG_SAVE_FAILED_UPLOADS = False # Default: disabled in production DEBUG_FILE_MAX_AGE_DAYS = 7 # Auto-delete threshold DEBUG_FILE_MAX_SIZE_MB = 100 # Maximum debug folder size ``` 2. Implement cleanup logic in `starpunk/media.py`: - Check config before saving debug files - Implement `cleanup_old_debug_files()` function - Add size limit check before saving 3. Add startup cleanup: - Run cleanup on application startup - Log cleanup actions 4. Sanitize filenames: - Sanitize filename before debug path construction - Pattern: `"".join(c for c in filename if c.isalnum() or c in "._-")[:50]` #### Acceptance Criteria - [ ] Debug files disabled by default - [ ] Files older than 7 days auto-deleted when enabled - [ ] Folder size limited to 100MB - [ ] Filenames sanitized (no path traversal) - [ ] Cleanup runs on startup - [ ] Tests cover all scenarios #### Dependencies - Phase 0 complete --- ### Phase 3: N+1 Query Fix (Feed Generation) **Priority**: Medium - Performance improvement #### Scope Fix N+1 query pattern in `_get_cached_notes()` only. Other N+1 patterns are deferred (documented in BACKLOG.md). #### Implementation 1. Create batch loading functions in `starpunk/media.py`: ```python def get_media_for_notes(note_ids: List[int]) -> 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