# StarPunk v1.1.2 "Syndicate" - Implementation Guide
## Overview
This guide provides a phased approach to implementing v1.1.2 "Syndicate" features. The release is structured in three phases totaling 14-16 hours of focused development.
## Pre-Implementation Checklist
- [x] Review v1.1.1 performance monitoring specification
- [x] Ensure development environment has Python 3.11+
- [x] Create feature branch: `feature/v1.1.2-syndicate`
- [ ] Review feed format specifications (RSS 2.0, ATOM 1.0, JSON Feed 1.1)
- [ ] Set up feed reader test clients
## Phase 1: Metrics Instrumentation (4-6 hours) ✅ COMPLETE
### Objective
Complete the metrics instrumentation that was partially implemented in v1.1.1, adding comprehensive coverage across all system operations.
### 1.1 Database Operation Timing (1.5 hours) ✅
**Location**: `starpunk/monitoring/database.py`
**Implementation Steps**:
1. **Create Database Monitor Wrapper**
```python
class MonitoredConnection:
"""Wrapper for SQLite connections with timing"""
def execute(self, query, params=None):
# Start timer
# Execute query
# Record metric
# Return result
```
2. **Instrument All Query Types**
- SELECT queries (with row count)
- INSERT operations (with affected rows)
- UPDATE operations (with affected rows)
- DELETE operations (rare, but instrumented)
- Transaction boundaries (BEGIN/COMMIT)
3. **Add Query Pattern Detection**
- Identify query type (SELECT, INSERT, etc.)
- Extract table name
- Detect slow queries (>1s)
- Track prepared statement usage
**Metrics to Collect**:
- `db.query.duration` - Query execution time
- `db.query.count` - Number of queries by type
- `db.rows.returned` - Result set size
- `db.transaction.duration` - Transaction time
- `db.connection.wait` - Connection acquisition time
### 1.2 HTTP Request/Response Metrics (1.5 hours) ✅
**Location**: `starpunk/monitoring/http.py`
**Implementation Steps**:
1. **Enhance Request Middleware**
```python
@app.before_request
def start_request_metrics():
g.metrics = {
'start_time': time.perf_counter(),
'start_memory': get_memory_usage(),
'request_id': generate_request_id()
}
```
2. **Capture Response Metrics**
```python
@app.after_request
def capture_response_metrics(response):
# Calculate duration
# Measure memory delta
# Record response size
# Track status codes
```
3. **Add Endpoint-Specific Metrics**
- Feed generation timing
- Micropub processing time
- Static file serving
- Admin operations
**Metrics to Collect**:
- `http.request.duration` - Total request time
- `http.request.size` - Request body size
- `http.response.size` - Response body size
- `http.status.{code}` - Status code distribution
- `http.endpoint.{name}` - Per-endpoint timing
### 1.3 Memory Monitoring Thread (1 hour) ✅
**Location**: `starpunk/monitoring/memory.py`
**Implementation Steps**:
1. **Create Background Monitor**
```python
class MemoryMonitor(Thread):
def run(self):
while self.running:
# Get RSS memory
# Check for growth
# Detect potential leaks
# Sleep interval
```
2. **Track Memory Patterns**
- Process RSS memory
- Virtual memory size
- Memory growth rate
- High water mark
- Garbage collection stats
3. **Add Leak Detection**
- Baseline after startup
- Track growth over time
- Alert on sustained growth
- Identify allocation sources
**Metrics to Collect**:
- `memory.rss` - Resident set size
- `memory.vms` - Virtual memory size
- `memory.growth_rate` - MB/hour
- `memory.gc.collections` - GC runs
- `memory.high_water` - Peak usage
### 1.4 Business Metrics for Syndication (1 hour) ✅
**Location**: `starpunk/monitoring/business.py`
**Implementation Steps**:
1. **Track Feed Operations**
- Feed requests by format
- Cache hit/miss rates
- Generation timing
- Format negotiation results
2. **Monitor Content Flow**
- Notes published per day
- Average note length
- Media attachments
- Syndication success
3. **User Behavior Metrics**
- Popular feed formats
- Reader user agents
- Request patterns
- Geographic distribution
**Metrics to Collect**:
- `feed.requests.{format}` - Requests by format
- `feed.cache.hit_rate` - Cache effectiveness
- `feed.generation.time` - Generation duration
- `content.notes.published` - Publishing rate
- `content.syndication.success` - Successful syndications
### Phase 1 Completion Status ✅
**Completed**: 2025-11-25
**Developer**: StarPunk Fullstack Developer (AI)
**Review**: Approved by Architect on 2025-11-26
**Test Results**: 28/28 tests passing
**Performance**: <1% overhead achieved
**Next Step**: Begin Phase 2 - Feed Formats
**Note**: All Phase 1 metrics instrumentation is complete and ready for production use. Business metrics functions are available for integration into notes.py and feed.py during Phase 2.
## Phase 2: Feed Formats (6-8 hours)
### Objective
Fix RSS feed ordering regression, then implement ATOM and JSON Feed formats alongside existing RSS, with proper content negotiation and caching.
### 2.0 Fix RSS Feed Ordering Regression (0.5 hours) - CRITICAL
**Location**: `starpunk/feed.py`
**Critical Production Bug**: RSS feed currently shows oldest entries first instead of newest first. This violates RSS standards and user expectations.
**Root Cause**: Incorrect `reversed()` calls on lines 100 and 198 that flip the correct DESC order from database.
**Implementation Steps**:
1. **Remove Incorrect Reversals**
- Line 100: Remove `reversed()` from `for note in reversed(notes[:limit]):`
- Line 198: Remove `reversed()` from `for note in reversed(notes[:limit]):`
- Update/remove misleading comments about feedgen reversing order
2. **Verify Expected Behavior**
- Database returns notes in DESC order (newest first) - confirmed line 440 of notes.py
- Feed should maintain this order (newest entries first)
- This is the standard for ALL feed formats (RSS, ATOM, JSON Feed)
3. **Add Feed Order Tests**
```python
def test_rss_feed_newest_first():
"""Test RSS feed shows newest entries first"""
# Create notes with different timestamps
old_note = create_note(title="Old", created_at=yesterday)
new_note = create_note(title="New", created_at=today)
# Generate feed
feed = generate_rss_feed([old_note, new_note])
# Parse and verify order
items = parse_feed_items(feed)
assert items[0].title == "New"
assert items[1].title == "Old"
```
**Important**: This MUST be fixed before implementing ATOM and JSON feeds to ensure all formats have consistent, correct ordering.
### 2.1 ATOM Feed Generation (2.5 hours)
**Location**: `starpunk/feed/atom.py`
**Implementation Steps**:
1. **Create ATOM Generator Class**
```python
class AtomGenerator:
def generate(self, notes, config):
# Yield XML declaration
# Yield feed element
# Yield entries
# Stream output
```
2. **Implement ATOM 1.0 Elements**
- Required: id, title, updated
- Recommended: author, link, category
- Optional: contributor, generator, icon, logo, rights, subtitle
3. **Handle Content Types**
- Text content (escaped)
- HTML content (in CDATA)
- XHTML content (inline)
- Base64 for binary
4. **Date Formatting**
- RFC 3339 format
- Timezone handling
- Updated vs published
**ATOM Structure**:
```xml
HTML content
", "date_published": "2024-11-25T12:00:00Z", "tags": ["tag1", "tag2"] } ] } ``` ### 2.3 Content Negotiation (1.5 hours) **Location**: `starpunk/feed/negotiator.py` **Implementation Steps**: 1. **Create Content Negotiator** ```python class FeedNegotiator: def negotiate(self, accept_header): # Parse Accept header # Score each format # Return best match ``` 2. **Parse Accept Header** - Split on comma - Extract MIME type - Parse quality factors (q=) - Handle wildcards (*/*) 3. **Score Formats** - Exact match: 1.0 - Wildcard match: 0.5 - Type/* match: 0.7 - Default RSS: 0.1 4. **Format Mapping** ```python FORMAT_MIME_TYPES = { 'rss': ['application/rss+xml', 'application/xml', 'text/xml'], 'atom': ['application/atom+xml'], 'json': ['application/json', 'application/feed+json'] } ``` ### 2.4 Feed Validation (1.5 hours) **Location**: `starpunk/feed/validators.py` **Implementation Steps**: 1. **Create Validation Framework** ```python class FeedValidator(Protocol): def validate(self, content: str) -> List[ValidationError]: pass ``` 2. **RSS Validator** - Check required elements - Verify date formats - Validate URLs - Check CDATA escaping 3. **ATOM Validator** - Verify namespace - Check required elements - Validate RFC 3339 dates - Verify ID uniqueness 4. **JSON Feed Validator** - Validate against schema - Check required fields - Verify URL formats - Validate date strings **Validation Levels**: - ERROR: Feed is invalid - WARNING: Non-critical issue - INFO: Suggestion for improvement ## Phase 3: Feed Enhancements (4 hours) ### Objective Add caching, statistics, and operational improvements to the feed system. ### 3.1 Feed Caching Layer (1.5 hours) **Location**: `starpunk/feed/cache.py` **Implementation Steps**: 1. **Create Cache Manager** ```python class FeedCache: def __init__(self, max_size=100, ttl=300): self.cache = LRU(max_size) self.ttl = ttl ``` 2. **Cache Key Generation** - Format type - Item limit - Content checksum - Last modified 3. **Cache Operations** - Get with TTL check - Set with expiration - Invalidate on changes - Clear entire cache 4. **Memory Management** - Monitor cache size - Implement eviction - Track hit rates - Report statistics **Cache Strategy**: ```python def get_or_generate(format, limit): key = generate_cache_key(format, limit) cached = cache.get(key) if cached and not expired(cached): metrics.record_cache_hit() return cached content = generate_feed(format, limit) cache.set(key, content, ttl=300) metrics.record_cache_miss() return content ``` ### 3.2 Statistics Dashboard (1.5 hours) **Location**: `starpunk/admin/syndication.py` **Template**: `templates/admin/syndication.html` **Implementation Steps**: 1. **Create Dashboard Route** ```python @app.route('/admin/syndication') @require_admin def syndication_dashboard(): stats = gather_syndication_stats() return render_template('admin/syndication.html', stats=stats) ``` 2. **Gather Statistics** - Requests by format (pie chart) - Cache hit rates (line graph) - Generation times (histogram) - Popular user agents (table) - Recent errors (log) 3. **Create Dashboard UI** - Overview cards - Time series graphs - Format breakdown - Performance metrics - Configuration status **Dashboard Sections**: - Feed Format Usage - Cache Performance - Generation Times - Client Analysis - Error Log - Configuration ### 3.3 OPML Export (1 hour) **Location**: `starpunk/feed/opml.py` **Implementation Steps**: 1. **Create OPML Generator** ```python def generate_opml(site_config): # Generate OPML header # Add feed outlines # Include metadata return opml_content ``` 2. **OPML Structure** ```xml