Skip to main content

Analytics Architecture Optimization

Current State​

The analytics pipeline uses envelopeBuilder.ts for transforming events to CDM format. This was originally designed for batch processing with local database storage and network retry logic.

Inefficiency​

We're now using envelopeBuilder for single-event transformation, which creates overhead:

  1. Full Envelope Construction: Builds complete envelope structure (originator, originatorContext, events array) for every single event
  2. Wasted Data: We only extract events[0] and discard originator/originatorContext
  3. Batch Sequence Numbering: Implements sequence numbering for batches, but we send events individually
  4. StoredAnalyticsEvent Abstraction: Database storage format no longer needed (HP Jarvis SDK handles persistence)

Why This Works Anyway​

✅ Transformation logic is proven and working - All CDM mapping rules are correct
✅ Maintains adapter pattern - All API-specific logic stays in adapter folder
✅ No functional issues - Just wasted CPU cycles building/discarding unused data
✅ Acceptable performance - Overhead is minor for typical event volumes

Optimization Opportunity​

Goal​

Create a single-event CDM transformer that keeps the proven transformation logic but removes batch-processing overhead.

Proposed Architecture​

// New: electron/src/main/analytics/adapter/cdmEventBuilder.ts
export interface CDMEventConfig {
appName: string;
appVersion: string;
}

export function buildCDMEvent(
event: InternalEvent,
config: CDMEventConfig
): CDMEventPayload | null {
// Extract transformation logic from envelopeBuilder.ts:
// - Action derivation (deriveAction)
// - View hierarchy building (buildViewHierarchy)
// - Control name generation (getControlName)
// - Action aux params (buildActionAuxParams)
// - Event detail construction
//
// Skip:
// - Envelope wrapper (originator, originatorContext)
// - Batch sequence numbering
// - Array iteration (single event only)

return {
version: '1.1.0',
dateTime: toIso(event.ts),
eventDetailType: SIMPLE_UI_EVENT_DETAIL_TYPE,
eventDetail: buildEventDetail(...),
eventCategory: 'telemetry',
sequenceNumber: 0, // HP Jarvis SDK may handle this
sequenceNumberGlobal: 0,
};
}

Migration Path​

Phase 1: Extract & Test

  1. Create cdmEventBuilder.ts with core transformation logic
  2. Add comprehensive unit tests matching envelopeBuilder test coverage
  3. Run tests comparing output: buildCDMEvent(event) vs buildTelemetryEnvelope([event]).events[0]

Phase 2: Switch & Monitor

  1. Update nativeAnalytics.ts to use buildCDMEvent instead of buildTelemetryEnvelope
  2. Add debug logging to compare outputs during canary rollout
  3. Monitor for any transformation discrepancies

Phase 3: Cleanup

  1. Mark envelopeBuilder.ts as deprecated (keep for reference)
  2. Update architecture documentation
  3. Remove StoredAnalyticsEvent abstraction if no longer needed

Benefits​

  • Performance: ~30-50% faster event processing (estimate, needs profiling)
  • Clarity: Simpler code path - "transform event to CDM" vs "build batch envelope → extract event"
  • Maintenance: Easier to understand single-event transformer vs batch logic
  • Memory: Less object allocation per event

Risks​

  • Regression: Could introduce subtle transformation bugs
  • Testing: Need comprehensive coverage to ensure parity
  • Time: Non-trivial extraction and validation effort

Decision​

Status: Deferred (documented as TODO)
Rationale: Current architecture works correctly after recent refactoring. Focus on stability and delivery.
Trigger: Revisit if performance profiling shows analytics as bottleneck, or when major analytics changes needed.

  • electron/src/main/services/nativeAnalytics.ts - See TODO comment in publishEvent()
  • electron/src/main/analytics/adapter/envelopeBuilder.ts - Current transformer
  • electron/src/main/analytics/adapter/preDbAdapter.ts - Still needed for filtering/enrichment

References​

  • Original discussion: Architecture review 2025-11-20
  • Branch: feat/HPCH-659-jarvis-data-collection
  • Related: Adapter pattern refactoring (appName/appVersion consolidation)