2025.02.16 metrics updates - SergeiGolos/wod-wiki GitHub Wiki

Metrics Updates PRD - 2025.02.16

1. Overview

This PRD outlines a plan to refactor the metrics system in wod.wiki to create a clean separation between statement/precompile nodes and runtime blocks. The current implementation has tight coupling between these components, which makes maintenance difficult and limits extensibility.

2. Current Implementation Analysis

2.1 Current Metrics Flow

  1. StatementNodes contain fragments (effort, repetitions, resistance, distance)
  2. PrecompiledNodes wrap StatementNodes and pass fragments through
  3. RuntimeBlocks are created from statements via strategy pattern
  4. Metrics generation happens in AbstractBlockLifecycle.metrics() which:
    • Extracts metrics from sources (PrecompiledNodes)
    • Includes child metrics
    • Inherits parent metrics

2.2 Issues with Current Approach

  • Poor separation of concerns between statement structure and runtime representation
  • Metrics inheritance is complex and follows block hierarchy which may not match logical workout grouping
  • When blocks represent multiple statements, metrics relationships are unclear
  • Parent metrics impact on children is implemented in a generic way without specific workout logic
  • No clear mechanism for runtime blocks to update their own metrics during execution

3. Goals

  1. Create a clean separation between statement/precompile nodes and runtime blocks
  2. Establish a mechanism for parent metrics to properly impact child metrics
  3. Support proper metrics for runtime blocks representing multiple statement nodes
  4. Enable runtime blocks to update their own metrics during execution

4. Proposed Architecture

4.1 Core Metrics Components

4.1.1 MetricsFactory

A new component responsible for creating metrics from statements:

interface IMetricsFactory {
  // Create metrics from a statement node
  createFromStatement(node: StatementNode): RuntimeMetric[];
  
  // Create metrics from multiple statement nodes
  createFromStatements(nodes: StatementNode[]): RuntimeMetric[];
  
  // Apply parent metrics to child metrics based on workout logic
  applyParentContext(parentMetrics: RuntimeMetric[], childMetrics: RuntimeMetric[]): RuntimeMetric[];
}

4.1.2 MetricsContext

A new container class for metrics operations:

class MetricsContext {
  private metrics: RuntimeMetric[] = [];
  
  // Add metrics to the context
  addMetrics(metrics: RuntimeMetric[]): void;
  
  // Update existing metrics by sourceId
  updateMetrics(sourceId: string, updater: (metric: RuntimeMetric) => void): void;
  
  // Get metrics by source ID
  getMetricsBySourceId(sourceId: string): RuntimeMetric[];
  
  // Get all metrics
  getAllMetrics(): RuntimeMetric[];
  
  // Create a new context with these metrics as parents for child context
  createChildContext(): MetricsContext;
}

4.1.3 IMetricsProvider Interface

interface IMetricsProvider {
  // Get metrics from this provider
  getMetrics(): RuntimeMetric[];
  
  // Update metrics for this provider
  updateMetrics(updater: (metrics: RuntimeMetric[]) => RuntimeMetric[]): void;
}

4.2 Integration with Existing Architecture

  1. RuntimeBlock implementation:

    • Blocks implement IMetricsProvider
    • Each block maintains its own MetricsContext
    • Parents pass context to children during initialization
  2. Block Lifecycle:

    • During compilation, MetricsFactory creates initial metrics from statements
    • During runtime, blocks can update their metrics to reflect changes
    • When blocks complete, they push metrics to parent context
  3. Results Reporting:

    • ResultSpan objects collect metrics from blocks when events occur
    • No change to the existing metrics display components

5. Implementation Plan

5.1 Phase 1: Metrics Foundation

  1. Create the MetricsFactory and MetricsContext classes
  2. Implement IMetricsProvider interface
  3. Update AbstractBlockLifecycle to use the new metrics components
  4. Unit tests for metrics generation and inheritance

5.2 Phase 2: Block Integration

  1. Update RuntimeBlock implementations to use MetricsContext
  2. Implement context passing between parent and child blocks
  3. Refactor the metrics() method to use the new architecture
  4. Integration tests for block metrics inheritance

5.3 Phase 3: Runtime Updates

  1. Implement mechanisms for blocks to update metrics during execution
  2. Create specialized metrics updates for different block types
  3. Update ResultSpan to use the new metrics system
  4. End-to-end tests for metrics updates during workout execution

6. Migration Strategy

  1. Implement the new metrics system alongside the existing one
  2. Gradually update block implementations to use the new system
  3. Switch over completely once all blocks have been updated
  4. Remove legacy metrics handling code

7. Acceptance Criteria

  1. Clean separation between statically derived metrics (from statements) and dynamically updated metrics (from runtime)
  2. Parent metrics properly impact child metrics based on workout structure
  3. Blocks representing multiple statements have correct composite metrics
  4. Blocks can update their metrics during execution
  5. All existing unit tests pass with the new implementation
  6. No changes required to UI components that display metrics

8. Kanban Board

Future #future

  • Integration testing

ToDo

Doing 2025-05-16

  • Create tests for metrics generation and inheritance

Closed

  • Define IMetricsProvider interface @completed(2025-05-16T14:55:00)
  • Create MetricsContext implementation @completed(2025-05-16T14:55:05)
  • Create MetricsFactory implementation @completed(2025-05-16T14:55:10)
  • Update AbstractBlockLifecycle to use new components @completed(2025-05-16T15:05:00)
  • Implement parent-child metrics relationships @completed(2025-05-16T15:10:00)
  • Update specific block implementations for metrics @completed(2025-05-16T15:15:00)
  • Update ResultSpan to use new metrics system @completed(2025-05-16T15:20:00)
  • Enable runtime metric updates @completed(2025-05-16T15:25:00)
⚠️ **GitHub.com Fallback** ⚠️