option('from') ?: now()->subDays(29)->toDateString()); $to = (string) ($this->option('to') ?: now()->toDateString()); if ($from > $to) { $this->error('Invalid range: --from must be <= --to'); return self::FAILURE; } $baseline = (string) $this->argument('baseline'); $candidate = (string) $this->argument('candidate'); $comparison = $this->evaluator->compareBaselineCandidate($baseline, $candidate, $from, $to); if ((bool) $this->option('json')) { $this->line((string) json_encode($comparison, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES)); return self::SUCCESS; } $this->table( ['algo_version', 'ctr', 'save_rate', 'long_dwell_share', 'bounce_rate', 'objective_score'], [[ (string) $comparison['baseline']['algo_version'], (float) $comparison['baseline']['ctr'], (float) $comparison['baseline']['save_rate'], (float) $comparison['baseline']['long_dwell_share'], (float) $comparison['baseline']['bounce_rate'], (float) $comparison['baseline']['objective_score'], ], [ (string) $comparison['candidate']['algo_version'], (float) $comparison['candidate']['ctr'], (float) $comparison['candidate']['save_rate'], (float) $comparison['candidate']['long_dwell_share'], (float) $comparison['candidate']['bounce_rate'], (float) $comparison['candidate']['objective_score'], ]] ); $delta = (array) $comparison['delta']; $this->line('Δ objective_score: ' . (string) $delta['objective_score']); $this->line('Δ objective_lift_pct: ' . (string) ($delta['objective_lift_pct'] ?? 'n/a')); return self::SUCCESS; } }