create(['name' => 'peterZ']); $a = BenchmarkRun::factory()->create([ 'suite' => 'softbench', 'label' => 'session A', 'model_id' => 'm', 'model_quant' => 'Q5_K_M', 'gpu' => 'AMD R9700', 'gpu_count' => 1, 'engine' => 'llama.cpp', 'user_id' => $me->id, 'visibility' => 'public', 'ran_at' => '2026-09-03 12:00:00', ]); SoftbenchResult::factory()->create(['benchmark_run_id' => $a->id, 'ok' => true, 'user_tps' => 60.0, 'total' => 100, 'level' => 'off']); SoftbenchResult::factory()->create(['benchmark_run_id' => $a->id, 'ok' => false, 'user_tps' => 20.0, 'total' => 300, 'level' => 'off']); $b = BenchmarkRun::factory()->create([ 'suite' => 'infrabench', 'label' => 'session A', 'model_id' => 'm', 'model_quant' => 'Q5_K_M', 'gpu' => 'AMD R9700', 'gpu_count' => 1, 'engine' => 'llama.cpp', 'user_id' => $me->id, 'visibility' => 'public', 'ran_at' => '2026-09-03 12:05:00', ]); InfrabenchResult::factory()->create(['benchmark_run_id' => $b->id, 'ok' => true, 'user_tps' => 40.0, 'total' => 200, 'level' => 'low']); $c = BenchmarkRun::factory()->create([ 'suite' => 'softbench', 'label' => 'session B', 'model_id' => 'm', 'model_quant' => 'Q5_K_M', 'gpu' => 'AMD R9700', 'gpu_count' => 1, 'engine' => 'llama.cpp', 'user_id' => $me->id, 'visibility' => 'public', 'ran_at' => '2026-09-04 12:00:00', ]); SoftbenchResult::factory()->create(['benchmark_run_id' => $c->id, 'ok' => true, 'user_tps' => 50.0, 'total' => 50, 'level' => 'medium']); Artisan::call('festbench:summary'); // Different labels → separate bands. $bands = DB::table('session_summaries')->orderBy('sequence')->get(); expect($bands)->toHaveCount(2); $bandA = $bands->firstWhere('label', 'session A'); expect($bandA->runner_name)->toBe('peterZ') ->and($bandA->gpu)->toBe('AMD R9700') ->and($bandA->gpu_count)->toBe(1) ->and($bandA->label)->toBe('session A'); $rowsA = DB::table('session_suite_rows')->where('session_summary_id', $bandA->id)->orderBy('sequence')->get(); expect($rowsA)->toHaveCount(2); $soft = $rowsA->firstWhere('suite', 'softbench'); expect($soft->passed)->toBe(1) ->and($soft->failed)->toBe(1) ->and($soft->avg_user_tps)->toBe(40.0) ->and($soft->weighted_user_tps)->toBe(30.0) ->and($soft->total_tokens)->toBe(400) ->and($soft->level)->toBe('off'); $infra = $rowsA->firstWhere('suite', 'infrabench'); expect($infra->passed)->toBe(1)->and($infra->level)->toBe('low'); }); test('devlogic and sysops totals are split by suite category', function () { $me = User::factory()->create(); $soft = BenchmarkRun::factory()->create([ 'suite' => 'softbench', 'label' => 'dual', 'model_id' => 'm', 'model_quant' => 'Q5_K_M', 'gpu' => 'GPU1', 'gpu_count' => 1, 'engine' => 'llama.cpp', 'user_id' => $me->id, 'visibility' => 'public', 'ran_at' => '2026-09-03 12:00:00', ]); SoftbenchResult::factory()->create(['benchmark_run_id' => $soft->id, 'ok' => true, 'user_tps' => 50.0, 'total' => 100, 'level' => 'off']); SoftbenchResult::factory()->create(['benchmark_run_id' => $soft->id, 'ok' => false, 'user_tps' => 10.0, 'total' => 200, 'level' => 'off']); $infra = BenchmarkRun::factory()->create([ 'suite' => 'infrabench', 'label' => 'dual', 'model_id' => 'm', 'model_quant' => 'Q5_K_M', 'gpu' => 'GPU1', 'gpu_count' => 1, 'engine' => 'llama.cpp', 'user_id' => $me->id, 'visibility' => 'public', 'ran_at' => '2026-09-03 12:05:00', ]); InfrabenchResult::factory()->create(['benchmark_run_id' => $infra->id, 'ok' => true, 'user_tps' => 30.0, 'total' => 150, 'level' => 'low']); $scen = BenchmarkRun::factory()->create([ 'suite' => 'scenariobench', 'label' => 'dual', 'model_id' => 'm', 'model_quant' => 'Q5_K_M', 'gpu' => 'GPU1', 'gpu_count' => 1, 'engine' => 'llama.cpp', 'user_id' => $me->id, 'visibility' => 'public', 'ran_at' => '2026-09-03 12:10:00', ]); ScenarioRun::factory()->create(['benchmark_run_id' => $scen->id, 'ok' => true, 'gen_tokens' => 5000, 'wall' => 100.0]); ScenarioRun::factory()->create(['benchmark_run_id' => $scen->id, 'ok' => false, 'gen_tokens' => 3000, 'wall' => 200.0]); Artisan::call('festbench:summary'); $band = DB::table('session_summaries')->where('label', 'dual')->first(); // Devlogic: softbench only — 2 observations (50, 10). // geo-mean = exp((ln(50)+ln(10))/2) = sqrt(500) ≈ 22.4 expect($band->devlogic_passed)->toBe(1) ->and($band->devlogic_failed)->toBe(1) ->and($band->devlogic_tokens)->toBe(300) ->and($band->devlogic_tps)->toBe(22.4); // Sysops: infrabench (1 obs: user_tps=30, tokens=150) + // scenariobench (2 obs: gen_tokens/wall = 50.0 and 15.0, tokens=8000). // Total sysops tokens = 150 + 8000 = 8150. expect($band->sysops_passed)->toBe(2) ->and($band->sysops_failed)->toBe(1) ->and($band->sysops_tokens)->toBe(8150); // sysops_tps is a geo-mean of 3 positive values — just verify it is // populated and roughly in range. expect($band->sysops_tps)->not->toBeNull(); expect($band->sysops_tps)->toBeGreaterThan(10.0)->toBeLessThan(50.0); }); test('private runs form their own band and are hidden from guests', function () { $me = User::factory()->create(); BenchmarkRun::factory()->create([ 'suite' => 'softbench', 'label' => 'pub', 'model_id' => 'm', 'visibility' => 'public', 'gpu' => 'g', 'gpu_count' => 1, 'user_id' => $me->id, ]); SoftbenchResult::factory()->create(['benchmark_run_id' => BenchmarkRun::latest('id')->first()->id]); BenchmarkRun::factory()->create([ 'suite' => 'softbench', 'label' => 'pub', 'model_id' => 'm', 'visibility' => 'private', 'gpu' => 'g', 'gpu_count' => 1, 'user_id' => $me->id, ]); Artisan::call('festbench:summary'); expect(DB::table('session_summaries')->count())->toBe(2) ->and(DB::table('session_summaries')->where('visibility', 'private')->count())->toBe(1); $this->get(route('home'))->assertOk()->assertSee('pub'); $bands = DB::table('session_summaries')->pluck('visibility'); expect($bands)->toContain('public')->toContain('private'); }); test('home renders the session summary and links into per-task detail', function () { $run = BenchmarkRun::factory()->create([ 'suite' => 'softbench', 'label' => 'rendered session', 'visibility' => 'public', 'model_id' => 'render/model', 'gpu' => 'AMD R9700', 'gpu_count' => 2, ]); SoftbenchResult::factory()->create(['benchmark_run_id' => $run->id, 'ok' => true, 'level' => 'off']); Artisan::call('festbench:summary'); $this->get(route('home'))->assertOk() ->assertSee('rendered session') ->assertSee('render/model') ->assertSee('AMD R9700') ->assertSee(route('runs.show', $run->run_id)) ->assertSee('All task rows'); }); test('results page still lists flat task rows', function () { $run = BenchmarkRun::factory()->create(['suite' => 'softbench', 'visibility' => 'public']); SoftbenchResult::factory()->create(['benchmark_run_id' => $run->id, 'task' => 'flat-task']); $this->get(route('results'))->assertOk() ->assertSee('All Task Rows') ->assertSee('flat-task'); });