Files
StarPunk/docs/projectplan/v1.5.0/RELEASE.md
Phil Skentelbery 7be2fb0f62 docs: Add v1.5.0 "Trigger" release definition
Focus: Cleanup, test coverage, and quality of life improvements

Goals:
- 90% test coverage target
- MPO format test coverage (High backlog item)
- Debug file storage cleanup (Medium backlog item)
- Filename sanitization in debug path (Medium backlog item)
- N+1 query pattern fix (Medium backlog item)
- Atomic variant generation (Medium backlog item)
- Default slug change to timestamp format (Medium backlog item)

Backlog items marked as scheduled for v1.5.0.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-16 19:04:43 -07:00

7.3 KiB

StarPunk v1.5.0 Release

Status: Planning Codename: "Trigger" Focus: Cleanup, Test Coverage, and Quality of Life Improvements

Overview

This minor release focuses on technical debt reduction, improving test coverage to 90%, and addressing quality-of-life issues identified in previous release reviews. No new user-facing features are planned.

Goals

  1. 90% Test Coverage - Increase overall test coverage from current baseline to 90%
  2. Address Backlog Technical Debt - Resolve 6 specific backlog items
  3. Improve Code Quality - Better error handling, atomicity, and performance

Features

1. Test Coverage Target: 90%

Increase overall test coverage to 90% minimum across all modules.

Scope

  • Identify modules with coverage below 90%
  • Write missing unit tests for uncovered code paths
  • Add integration tests for critical workflows
  • Ensure edge cases and error paths are tested

Acceptance Criteria

  • uv run pytest --cov=starpunk reports ≥90% overall coverage
  • No module below 85% coverage
  • All new code in this release has 100% coverage

2. MPO Format Test Coverage

Source: Backlog - High Priority (Developer Review M1)

Add test coverage for MPO (Multi-Picture Object) format handling.

Current State

  • MPO conversion code exists at starpunk/media.py lines 163-173
  • Advertised in CHANGELOG but untested

Implementation

  • Add test_mpo_detection_and_conversion() to TestHEICSupport class
  • Create MPO test image using Pillow's MPO support
  • Test primary image extraction
  • Test conversion to JPEG

Acceptance Criteria

  • MPO detection tested
  • MPO to JPEG conversion tested
  • Edge cases (corrupted MPO, single-frame MPO) tested

3. Debug File Storage Cleanup

Source: Backlog - Medium Priority (Developer Review M2, Architect Review 1.2.2)

Implement cleanup mechanism for failed upload debug files.

Current State

  • Failed uploads saved to data/debug/ directory
  • No cleanup mechanism exists
  • Potential disk space exhaustion

Implementation

  1. Add DEBUG_SAVE_FAILED_UPLOADS config option (default: false in production)
  2. Implement automatic cleanup for files older than 7 days
  3. Add disk space check or size limit (100MB max for debug folder)
  4. Cleanup runs on application startup and periodically

Configuration

DEBUG_SAVE_FAILED_UPLOADS = False  # Enable only for debugging
DEBUG_FILE_MAX_AGE_DAYS = 7        # Auto-delete after 7 days
DEBUG_FILE_MAX_SIZE_MB = 100       # Maximum debug folder size

Acceptance Criteria

  • Debug files disabled by default in production
  • Old files automatically cleaned up when enabled
  • Disk space protected with size limit
  • Tests cover all cleanup scenarios

4. Filename Sanitization in Debug Path

Source: Backlog - Medium Priority (Architect Review 1.2.3)

Sanitize filenames before use in debug file paths.

Current State

  • Original filename used directly at starpunk/media.py line 135
  • Path traversal or special character issues possible

Implementation

safe_filename = "".join(c for c in filename if c.isalnum() or c in "._-")[:50]

Acceptance Criteria

  • Filenames sanitized before debug path construction
  • Path traversal attempts neutralized
  • Special characters removed
  • Filename length limited
  • Tests cover malicious filename patterns

5. N+1 Query Pattern Fix

Source: Backlog - Medium Priority (Architect Review 2.2.9)

Eliminate N+1 query pattern in feed generation.

Current State

  • _get_cached_notes() loads media and tags per-note
  • For 50 notes: 100 additional database queries
  • Performance degrades with note count

Implementation

  1. Create get_media_for_notes(note_ids: List[int]) batch function
  2. Create get_tags_for_notes(note_ids: List[int]) batch function
  3. Use single query with WHERE note_id IN (...)
  4. Update _get_cached_notes() to use batch loading

Example

def get_media_for_notes(note_ids: List[int]) -> Dict[int, List[dict]]:
    """Batch load media for multiple notes."""
    # Single query: SELECT * FROM note_media WHERE note_id IN (?)
    # Returns: {note_id: [media_list]}

Acceptance Criteria

  • Feed generation uses batch queries
  • Query count reduced from O(n) to O(1) for media/tags
  • Performance improvement measurable in tests
  • No change to API behavior

6. Atomic Variant Generation

Source: Backlog - Medium Priority (Architect Review 2.2.6)

Make variant file generation atomic with database commits.

Current State

  • Files written to disk before database commit
  • Database commit failure leaves orphaned files

Implementation

  1. Write variant files to temporary location first
  2. Database insert in transaction
  3. Move files to final location after successful commit
  4. Cleanup temp files on any failure

Flow

1. Generate variants to temp directory
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 DB, delete temp files

Acceptance Criteria

  • No orphaned files on database failures
  • No orphaned database records on file failures
  • Atomic operation for all media saves
  • Tests simulate failure scenarios

7. Default Slug Format Change

Source: Backlog - Medium Priority

Change default slug format from content-based to timestamp-based.

Current State

  • Slugs generated from note content
  • Can produce unwanted slugs from private content

New Format

  • Default: YYYYMMDDHHMMSS (e.g., 20251216143052)
  • Duplicate handling: append -1, -2, etc.
  • Custom slugs still supported via mp-slug

Implementation

  1. Update generate_slug() function in starpunk/slug_utils.py
  2. Generate timestamp-based slug by default
  3. Check for duplicates and append suffix if needed
  4. Preserve custom slug functionality

Example

def generate_slug(content: str = None, custom_slug: str = None) -> str:
    if custom_slug:
        return sanitize_slug(custom_slug)
    # Default: timestamp-based
    timestamp = datetime.now().strftime("%Y%m%d%H%M%S")
    return ensure_unique_slug(timestamp)

Acceptance Criteria

  • New notes use timestamp slugs by default
  • Duplicate timestamps handled with suffix
  • Custom mp-slug still works
  • Existing notes unchanged
  • Tests cover all slug generation scenarios

Out of Scope

  • New user-facing features
  • UI changes
  • New feed formats
  • Micropub extensions
  • Database schema changes (except for bug fixes)

Dependencies

  • v1.4.x complete
  • No new external dependencies expected

Success Criteria

  1. Test coverage ≥90% overall
  2. MPO format has test coverage
  3. Debug file cleanup implemented and tested
  4. Filename sanitization implemented and tested
  5. N+1 query pattern eliminated
  6. Variant generation is atomic
  7. Default slugs are timestamp-based
  8. All existing tests continue to pass
  9. No regressions in functionality

After completion, the following backlog items should be marked complete or moved to "Recently Completed":

  • MPO Format Test Coverage (High)
  • Debug File Storage Without Cleanup Mechanism (Medium)
  • Filename Not Sanitized in Debug Path (Medium)
  • N+1 Query Pattern in Feed Generation (Medium)
  • Transaction Not Atomic in Variant Generation (Medium)
  • Default Slug Change (Medium)