Files
StarPunk/docs/design/hotfix-v1.1.1-rc2-consolidated.md
Phil Skentelbery d565721cdb fix: Add data transformer to resolve metrics dashboard template mismatch
Root cause: Template expects flat structure (metrics.database.count) but
monitoring module provides nested structure (metrics.by_type.database.count)
with different field names (avg_duration_ms vs avg).

Solution: Route Adapter Pattern - transformer function maps data structure
at presentation layer.

Changes:
- Add transform_metrics_for_template() function to admin.py
- Update metrics_dashboard() route to use transformer
- Provide safe defaults for missing/empty metrics data
- Handle all operation types: database, http, render

Testing: All 32 admin route tests passing

Documentation:
- Updated implementation report with actual fix details
- Created consolidated hotfix design documentation
- Architectural review by architect (approved with minor concerns)

Technical debt: Adapter layer should be replaced with proper data
contracts in v1.2.0

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-25 21:24:47 -07:00

3.9 KiB

Hotfix Design: v1.1.1-rc.2 - Metrics Dashboard Template Data Mismatch

Problem Summary

Production deployment of v1.1.1-rc.1 exposed two critical issues in the metrics dashboard:

  1. Route Conflict (Fixed in initial attempt): Two routes mapped to similar paths causing ambiguity
  2. Template/Data Mismatch (Root cause): Template expects different data structure than monitoring module provides

The Template/Data Mismatch

Template Expects (metrics_dashboard.html line 163):

{{ metrics.database.count|default(0) }}
{{ metrics.database.avg|default(0) }}
{{ metrics.database.min|default(0) }}
{{ metrics.database.max|default(0) }}

Monitoring Module Returns:

{
    "by_type": {
        "database": {
            "count": 50,
            "avg_duration_ms": 12.5,
            "min_duration_ms": 2.0,
            "max_duration_ms": 45.0
        }
    }
}

Note the two mismatches:

  1. Nesting: Template wants metrics.database but gets metrics.by_type.database
  2. Field Names: Template wants avg but gets avg_duration_ms

Solution: Route Adapter Pattern

Transform data at the presentation layer (route handler) to match template expectations.

Implementation

Added a transformer function in admin.py that:

  1. Flattens the nested structure (by_type.databasedatabase)
  2. Maps field names (avg_duration_msavg)
  3. Provides safe defaults for missing data
def transform_metrics_for_template(metrics_stats):
    """Transform metrics stats to match template structure"""
    transformed = {}

    # Map by_type to direct access with field name mapping
    for op_type in ['database', 'http', 'render']:
        if 'by_type' in metrics_stats and op_type in metrics_stats['by_type']:
            type_data = metrics_stats['by_type'][op_type]
            transformed[op_type] = {
                'count': type_data.get('count', 0),
                'avg': type_data.get('avg_duration_ms', 0),  # Note field name change
                'min': type_data.get('min_duration_ms', 0),
                'max': type_data.get('max_duration_ms', 0)
            }
        else:
            # Safe defaults
            transformed[op_type] = {'count': 0, 'avg': 0, 'min': 0, 'max': 0}

    # Keep other top-level stats
    transformed['total_count'] = metrics_stats.get('total_count', 0)
    transformed['max_size'] = metrics_stats.get('max_size', 1000)
    transformed['process_id'] = metrics_stats.get('process_id', 0)

    return transformed

Why This Approach?

  1. Minimal Risk: Only changes route handler, not core monitoring module
  2. Preserves API: Monitoring module remains unchanged for other consumers
  3. No Template Changes: Avoids modifying template and JavaScript
  4. Clear Separation: Route acts as adapter between business logic and view

Additional Fixes Applied

  1. Route Path Change: /admin/dashboard/admin/metrics-dashboard (prevents conflict)
  2. Defensive Imports: Graceful handling of missing monitoring module
  3. Error Handling: Safe defaults when metrics collection fails

Testing and Validation

Created comprehensive test script validating:

  • Data structure transformation works correctly
  • All template fields accessible after transformation
  • Safe defaults provided for missing data
  • Field name mapping correct

All 32 admin route tests pass with 100% success rate.

Files Modified

  1. /starpunk/routes/admin.py:

    • Lines 218-260: Added transformer function
    • Line 263: Changed route path
    • Lines 285-314: Applied transformer and added error handling
  2. /starpunk/__init__.py: Version bump to 1.1.1-rc.2

  3. /CHANGELOG.md: Documented hotfix

Production Impact

Before: 500 error with 'dict object' has no attribute 'database' After: Metrics dashboard loads correctly with properly structured data

This is a tactical bug fix, not an architectural change, and should be documented as such.