diff --git a/app/Filament/Widgets/Dashboard/BaselineCompareNow.php b/app/Filament/Widgets/Dashboard/BaselineCompareNow.php index e5f59f3..4108995 100644 --- a/app/Filament/Widgets/Dashboard/BaselineCompareNow.php +++ b/app/Filament/Widgets/Dashboard/BaselineCompareNow.php @@ -4,9 +4,9 @@ namespace App\Filament\Widgets\Dashboard; -use App\Models\BaselineCompareRun; use App\Models\BaselineTenantAssignment; use App\Models\Finding; +use App\Models\OperationRun; use App\Models\Tenant; use Filament\Facades\Filament; use Filament\Widgets\Widget; @@ -69,11 +69,12 @@ protected function getViewData(): array ->where('severity', Finding::SEVERITY_LOW) ->count(); - $latestRun = BaselineCompareRun::query() + $latestRun = OperationRun::query() ->where('tenant_id', $tenant->getKey()) - ->where('baseline_profile_id', $profile->getKey()) - ->whereNotNull('finished_at') - ->latest('finished_at') + ->where('type', 'baseline_compare') + ->where('context->baseline_profile_id', (string) $profile->getKey()) + ->whereNotNull('completed_at') + ->latest('completed_at') ->first(); return [ diff --git a/specs/feat/700-bugfix/plan.md b/specs/feat/700-bugfix/plan.md new file mode 100644 index 0000000..4d3427d --- /dev/null +++ b/specs/feat/700-bugfix/plan.md @@ -0,0 +1,26 @@ +# Implementation Plan: BaselineCompareRun model bugfix + +**Branch**: `feat/700-bugfix` | **Date**: 2026-02-20 | **Spec**: `specs/feat/700-bugfix/spec.md` + +## Summary + +Fix runtime crash caused by a missing Eloquent model referenced by a Filament dashboard widget. + +## Technical Context + +- PHP 8.4.x, Laravel 12 +- Filament v5, Livewire v4 +- PostgreSQL (Sail locally) +- Tests: Pest v4 (`vendor/bin/sail artisan test --compact`) + +## Approach + +1. Identify intended storage for baseline compare runs: + - If a `baseline_compare_runs` table already exists, implement `App\Models\BaselineCompareRun` mapped to it. + - If not, align the widget to an existing persistence type (likely `OperationRun`) without changing UX. +2. Add a regression test that exercises the tenant dashboard route and asserts a successful response. +3. Run Pint on dirty files and run the focused test. + +## Risks + +- Introducing a new model without an existing table could still fail at runtime. Prefer minimal, compatibility-first changes. diff --git a/specs/feat/700-bugfix/spec.md b/specs/feat/700-bugfix/spec.md new file mode 100644 index 0000000..9e903a0 --- /dev/null +++ b/specs/feat/700-bugfix/spec.md @@ -0,0 +1,29 @@ +# Bugfix Specification: BaselineCompareRun missing model + +**Branch**: `feat/700-bugfix` +**Created**: 2026-02-20 +**Status**: Ready + +## Problem + +Navigating to the tenant dashboard (`/admin/t/{tenant}`) throws an Internal Server Error: + +- `Class "App\Models\BaselineCompareRun" not found` + +The stack trace points to the dashboard widget `app/Filament/Widgets/Dashboard/BaselineCompareNow.php`. + +## Goal + +- Tenant dashboard loads successfully. +- Baseline compare widget can safely query baseline compare run state without a fatal error. + +## Non-Goals + +- No UX redesign. +- No new baseline-compare workflow features beyond restoring runtime stability. + +## Acceptance Criteria + +- Visiting `/admin/t/{tenant}` does not throw a 500. +- The widget renders even when there are no baseline compare runs. +- A focused automated test covers the regression. diff --git a/specs/feat/700-bugfix/tasks.md b/specs/feat/700-bugfix/tasks.md new file mode 100644 index 0000000..fc830a1 --- /dev/null +++ b/specs/feat/700-bugfix/tasks.md @@ -0,0 +1,20 @@ +--- +description: "Tasks for feat/700-bugfix (BaselineCompareRun missing model)" +--- + +# Tasks: feat/700-bugfix + +**Input**: `specs/feat/700-bugfix/spec.md` and `specs/feat/700-bugfix/plan.md` + +## Setup +- [X] T001 Confirm whether baseline compare runs table exists + +## Tests (TDD) +- [X] T010 Add regression test for tenant dashboard (no 500) + +## Core +- [X] T020 Fix missing BaselineCompareRun reference (model or widget) + +## Validation +- [X] T030 Run Pint (dirty) +- [X] T040 Run focused tests via Sail diff --git a/tests/Feature/Filament/BaselineCompareNowWidgetTest.php b/tests/Feature/Filament/BaselineCompareNowWidgetTest.php new file mode 100644 index 0000000..73708eb --- /dev/null +++ b/tests/Feature/Filament/BaselineCompareNowWidgetTest.php @@ -0,0 +1,46 @@ +create([ + 'workspace_id' => (int) $tenant->workspace_id, + 'name' => 'Baseline A', + ]); + + BaselineTenantAssignment::factory()->create([ + 'workspace_id' => (int) $tenant->workspace_id, + 'tenant_id' => (int) $tenant->getKey(), + 'baseline_profile_id' => (int) $profile->getKey(), + ]); + + OperationRun::factory()->create([ + 'tenant_id' => (int) $tenant->getKey(), + 'workspace_id' => (int) $tenant->workspace_id, + 'type' => 'baseline_compare', + 'status' => 'completed', + 'outcome' => 'succeeded', + 'initiator_name' => 'System', + 'context' => [ + 'baseline_profile_id' => (int) $profile->getKey(), + ], + 'completed_at' => now()->subDay(), + ]); + + $this->actingAs($user) + ->get(TenantDashboard::getUrl(tenant: $tenant)) + ->assertOk() + ->assertSee('Baseline Governance') + ->assertSee('Baseline A') + ->assertSee('No open drift — baseline compliant'); +});