id(); $table->string('run_id', 32)->unique()->comment('festbench run_id'); $table->dateTime('ran_at')->nullable()->comment('ts from festbench'); $table->string('suite', 32); $table->string('run_key', 255)->nullable(); // model + server identity (sensitive fields nullable, redacted by default) $table->string('model_id', 255)->nullable(); $table->string('model_quant', 64)->nullable(); $table->string('model_quant_raw', 128)->nullable(); $table->string('model_path', 512)->nullable(); $table->string('engine', 64)->nullable(); $table->string('engine_build', 128)->nullable(); $table->unsignedBigInteger('n_ctx')->nullable(); $table->unsignedInteger('slots')->nullable(); $table->string('gpu', 128)->nullable(); $table->unsignedInteger('gpu_count')->nullable(); $table->string('gpu_source', 64)->nullable(); $table->string('host', 255)->nullable(); $table->string('client', 255)->nullable(); $table->string('endpoint', 512)->nullable(); $table->string('label', 255)->nullable(); $table->string('config', 255)->nullable(); // provenance $table->string('image_digest', 512)->nullable(); $table->json('validators')->nullable(); $table->json('suite_versions')->nullable(); $table->string('harness', 32)->nullable(); $table->string('harness_ver', 64)->nullable(); $table->string('harness_mode', 64)->nullable(); // user-owned overlay — the only mutable part $table->foreignId('user_id')->nullable()->constrained()->nullOnDelete(); $table->string('visibility', 16)->default('public')->comment('public|private'); $table->text('notes')->nullable(); $table->timestamps(); $table->index('suite'); $table->index(['model_id', 'model_quant']); $table->index(['visibility', 'user_id']); }); Schema::create('run_results', function (Blueprint $table) { $table->id(); $table->foreignId('benchmark_run_id')->constrained()->cascadeOnDelete(); $table->string('suite', 32); $table->string('section', 64)->nullable(); $table->string('task', 128); $table->string('level', 16)->nullable()->comment('off|low|medium|xhigh'); $table->boolean('ok')->nullable(); $table->double('decode')->nullable(); $table->double('user_tps')->nullable(); $table->double('ttft')->nullable(); $table->double('t_answer')->nullable(); $table->double('wall')->nullable(); $table->unsignedInteger('reasoning')->nullable(); $table->unsignedInteger('visible')->nullable(); $table->unsignedInteger('total')->nullable(); $table->unsignedInteger('tool_calls')->nullable(); $table->unsignedInteger('checks_passed')->nullable(); $table->unsignedInteger('checks_total')->nullable(); $table->string('finish', 32)->nullable(); $table->text('detail')->nullable(); // complete source row, so future festbench fields need no migration $table->json('payload')->nullable(); $table->timestamps(); $table->index(['benchmark_run_id']); $table->index(['suite', 'level']); $table->index(['ok']); }); } public function down(): void { Schema::dropIfExists('run_results'); Schema::dropIfExists('benchmark_runs'); } };