Some checks failed
PR Fast Feedback / fast-feedback (pull_request) Failing after 1m11s
Added UiBloatRegressionGuardTest to enforce known UI bloat and customer/auditor safety regression patterns across configured runtime UI source paths as defined in Spec 375. Registered the test in Pest.php and added to TestLaneManifest.
180 lines
7.8 KiB
PHP
180 lines
7.8 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
use Tests\Support\TestLaneManifest;
|
|
use Tests\Support\UiBloat\UiBloatScanner;
|
|
|
|
function spec375AllowlistEntry(array $overrides = []): array
|
|
{
|
|
return array_merge([
|
|
'rule_id' => 'UIBLOAT_CUSTOMER_RAW_ID',
|
|
'file' => 'apps/platform/resources/views/filament/pages/reviews/customer-review-workspace.blade.php',
|
|
'pattern' => 'operation id',
|
|
'reason' => 'Appears only inside collapsed technical details.',
|
|
'surface_type' => 'customer-auditor',
|
|
'audience' => 'operator-support',
|
|
'review_marker' => 'manual-review-required',
|
|
'expires_or_review_after' => '2026-09-01',
|
|
'owner_spec' => 'specs/375-ui-bloat-regression-guard',
|
|
], $overrides);
|
|
}
|
|
|
|
it('keeps the ui bloat guard in surface-guard heavy-governance ownership', function (): void {
|
|
$family = TestLaneManifest::family('ui-bloat-regression-guard');
|
|
|
|
expect($family['classificationId'])->toBe('surface-guard')
|
|
->and($family['targetLaneId'])->toBe('heavy-governance')
|
|
->and($family['hotspotFiles'])->toContain('tests/Feature/Guards/UiBloatRegressionGuardTest.php');
|
|
});
|
|
|
|
it('supports report warn and fail strictness semantics', function (): void {
|
|
$file = 'apps/platform/resources/views/filament/pages/reviews/customer-review-workspace.blade.php';
|
|
$source = '<section>Customer review output <p>Operation context</p></section>';
|
|
|
|
$report = UiBloatScanner::scanSource($file, $source, UiBloatScanner::STRICTNESS_REPORT);
|
|
$warn = UiBloatScanner::scanSource($file, $source, UiBloatScanner::STRICTNESS_WARN);
|
|
$fail = UiBloatScanner::scanSource(
|
|
'apps/platform/app/Filament/Pages/Operations.php',
|
|
'<x-filament-panels::page><p>0 alerts</p></x-filament-panels::page>',
|
|
UiBloatScanner::STRICTNESS_FAIL,
|
|
);
|
|
|
|
expect($report['blocking_failures'])->toBeEmpty()
|
|
->and($warn['blocking_failures'])->not->toBeEmpty()
|
|
->and($fail['blocking_failures'])->not->toBeEmpty();
|
|
});
|
|
|
|
it('hard-fails customer raw id labels unless allowlisted', function (): void {
|
|
$file = 'apps/platform/resources/views/filament/pages/reviews/customer-review-workspace.blade.php';
|
|
$source = '<section>Customer review output <p>Operation ID</p></section>';
|
|
|
|
$result = UiBloatScanner::scanSource($file, $source);
|
|
$allowlisted = UiBloatScanner::scanSource($file, $source, UiBloatScanner::STRICTNESS_WARN, [
|
|
spec375AllowlistEntry(),
|
|
]);
|
|
|
|
expect($result['blocking_failures'])->toHaveCount(1)
|
|
->and($result['blocking_failures'][0]['rule_id'])->toBe('UIBLOAT_CUSTOMER_RAW_ID')
|
|
->and($allowlisted['blocking_failures'])->toBeEmpty()
|
|
->and($allowlisted['findings'][0]['result'])->toBe('allowlisted');
|
|
});
|
|
|
|
it('hard-fails customer internal provider or debug terms unless allowlisted', function (): void {
|
|
$file = 'apps/platform/resources/views/filament/pages/reviews/customer-review-workspace.blade.php';
|
|
$source = '<section>Customer review output <p>Raw Graph payload</p></section>';
|
|
|
|
$result = UiBloatScanner::scanSource($file, $source);
|
|
$allowlisted = UiBloatScanner::scanSource($file, $source, UiBloatScanner::STRICTNESS_WARN, [
|
|
spec375AllowlistEntry([
|
|
'rule_id' => 'UIBLOAT_CUSTOMER_INTERNAL_TERM',
|
|
'pattern' => 'raw graph payload',
|
|
'reason' => 'Fixture proves scoped exception behavior.',
|
|
]),
|
|
]);
|
|
|
|
expect($result['blocking_failures'])->toHaveCount(1)
|
|
->and($result['blocking_failures'][0]['rule_id'])->toBe('UIBLOAT_CUSTOMER_INTERNAL_TERM')
|
|
->and($allowlisted['blocking_failures'])->toBeEmpty();
|
|
});
|
|
|
|
it('keeps zero metrics and repeated status as non-blocking review findings in warn mode', function (): void {
|
|
$source = str_repeat('Status ready lifecycle completed. ', 18).'<p>0 findings</p>';
|
|
$result = UiBloatScanner::scanSource('apps/platform/app/Filament/Pages/EnvironmentDashboard.php', $source);
|
|
|
|
expect($result['blocking_failures'])->toBeEmpty()
|
|
->and(array_keys($result['summary_by_rule']))->toContain('UIBLOAT_ZERO_METRIC_CARD', 'UIBLOAT_REPEATED_STATUS')
|
|
->and($result['summary_by_result'])->toHaveKey('warning')
|
|
->and($result['summary_by_result'])->toHaveKey('manual-review-required');
|
|
});
|
|
|
|
it('reports decision hierarchy action overload evidence diagnostic mixing and metadata findings as manual review', function (): void {
|
|
$pageSource = <<<'PHP'
|
|
<?php
|
|
final class ExamplePage
|
|
{
|
|
protected function getHeaderActions(): array
|
|
{
|
|
return [
|
|
Action::make('one'),
|
|
Action::make('two'),
|
|
Action::make('three'),
|
|
Action::make('four'),
|
|
Action::make('five'),
|
|
];
|
|
}
|
|
}
|
|
// Evidence diagnostics
|
|
PHP;
|
|
|
|
$pageResult = UiBloatScanner::scanSource('apps/platform/app/Filament/Pages/ExamplePage.php', $pageSource);
|
|
$metadataResult = UiBloatScanner::scanSource(
|
|
'apps/platform/app/Filament/Resources/ExampleResource.php',
|
|
'<?php // Normalization lineage',
|
|
);
|
|
|
|
$ruleIds = array_unique(array_merge(
|
|
array_keys($pageResult['summary_by_rule']),
|
|
array_keys($metadataResult['summary_by_rule']),
|
|
));
|
|
|
|
expect($ruleIds)->toContain(
|
|
'UIBLOAT_MISSING_PRIMARY_QUESTION',
|
|
'UIBLOAT_HEADER_ACTION_OVERLOAD',
|
|
'UIBLOAT_EVIDENCE_DIAGNOSTICS_MIXED',
|
|
'UIBLOAT_TECH_METADATA_MAIN',
|
|
)
|
|
->and($pageResult['blocking_failures'])->toBeEmpty()
|
|
->and($metadataResult['blocking_failures'])->toBeEmpty();
|
|
});
|
|
|
|
it('reports diagnostic guidance and ambiguous entrypoint drift as manual review', function (): void {
|
|
$source = <<<'BLADE'
|
|
<x-filament-panels::page>
|
|
<h1>Diagnostics hub</h1>
|
|
<p>Raw payload provider context debug trace operation id diagnostic details.</p>
|
|
</x-filament-panels::page>
|
|
BLADE;
|
|
|
|
$result = UiBloatScanner::scanSource('apps/platform/app/Filament/Pages/EnvironmentDiagnostics.php', $source);
|
|
|
|
expect(array_keys($result['summary_by_rule']))->toContain(
|
|
'UIBLOAT_DIAGNOSTIC_GUIDANCE_MISSING',
|
|
'UIBLOAT_DIAGNOSTIC_ENTRYPOINT_AMBIGUOUS',
|
|
)
|
|
->and($result['blocking_failures'])->toBeEmpty();
|
|
});
|
|
|
|
it('validates allowlist entry shape and rejects blanket entries', function (): void {
|
|
$errors = UiBloatScanner::validateAllowlist([
|
|
[
|
|
'rule_id' => 'UIBLOAT_CUSTOMER_RAW_ID',
|
|
'file' => 'apps/platform/app/Filament',
|
|
],
|
|
]);
|
|
|
|
expect($errors)->not->toBeEmpty()
|
|
->and(implode("\n", $errors))->toContain('reason')
|
|
->and(implode("\n", $errors))->toContain('forbidden blanket file pattern');
|
|
});
|
|
|
|
it('excludes non-runtime paths from ui findings by default', function (): void {
|
|
expect(UiBloatScanner::isRuntimeUiPath('apps/platform/routes/web.php'))->toBeFalse()
|
|
->and(UiBloatScanner::isRuntimeUiPath('apps/platform/app/Models/User.php'))->toBeFalse()
|
|
->and(UiBloatScanner::isRuntimeUiPath('specs/375-ui-bloat-regression-guard/spec.md'))->toBeFalse()
|
|
->and(UiBloatScanner::isRuntimeUiPath('apps/platform/tests/Feature/Guards/UiBloatRegressionGuardTest.php'))->toBeFalse()
|
|
->and(UiBloatScanner::isRuntimeUiPath('apps/platform/app/Filament/Pages/ExamplePage.php'))->toBeTrue();
|
|
});
|
|
|
|
it('scans the configured runtime ui paths without unallowlisted customer safety blockers', function (): void {
|
|
$result = UiBloatScanner::scanConfiguredPaths(repo_path(), UiBloatScanner::STRICTNESS_WARN);
|
|
|
|
expect($result['files_scanned'])->toBeGreaterThan(0)
|
|
->and($result['config_errors'])->toBeEmpty()
|
|
->and($result['blocking_failures'])->toBeEmpty(
|
|
"Unexpected customer/auditor blocking UI bloat findings:\n".UiBloatScanner::formatFindings($result['blocking_failures']),
|
|
)
|
|
->and($result['absent_candidate_paths']['apps/platform/resources/views/components'])->toBe('not available')
|
|
->and($result['absent_candidate_paths']['apps/platform/app/View'])->toBe('not available');
|
|
});
|