getFileName(); expect($fileName)->toBeString(); $contents = file_get_contents((string) $fileName); expect($contents)->not->toBeFalse(); return (string) $contents; } it('keeps the first-slice tenant-owned family inventory aligned to tenant-owned tables', function (): void { $allowedSearchPostures = ['scoped', 'disabled', 'not_applicable']; foreach (TenantOwnedModelFamilies::firstSlice() as $familyName => $family) { expect(TenantOwnedTables::contains($family['table'])) ->toBeTrue("{$familyName} must point at a known tenant-owned table."); expect(TenantOwnedTables::firstSlice()) ->toContain($family['table']); expect($allowedSearchPostures) ->toContain($family['search_posture']); expect(class_exists($family['model']))->toBeTrue(); expect(class_exists($family['resource']))->toBeTrue(); } }); it('keeps first-slice family names unique and explicit', function (): void { $names = TenantOwnedModelFamilies::names(); expect($names)->not->toBeEmpty(); expect(array_unique($names))->toBe($names); }); it('keeps the first-slice family registry exhaustive for declared first-slice tenant-owned tables', function (): void { $familyTables = array_map( static fn (array $family): string => $family['table'], TenantOwnedModelFamilies::firstSlice(), ); expect($familyTables)->toEqualCanonicalizing(TenantOwnedTables::firstSlice()); }); it('keeps the residual tenant-owned rollout inventory aligned to non-first-slice tenant-owned tables', function (): void { $residualTables = array_map( static fn (array $entry): string => $entry['table'], TenantOwnedModelFamilies::residualRolloutInventory(), ); expect($residualTables)->toEqualCanonicalizing(TenantOwnedTables::residual()); foreach (TenantOwnedModelFamilies::residualRolloutInventory() as $familyName => $entry) { expect(trim($familyName))->not->toBe(''); expect(trim($entry['likely_surface']))->not->toBe(''); expect(trim($entry['why_not_in_first_slice']))->not->toBe(''); } }); it('requires first-slice resources to use the shared tenant-owned query and record resolver entry points', function (): void { foreach (TenantOwnedModelFamilies::firstSlice() as $familyName => $family) { $resourceClass = $family['resource']; $traits = class_uses_recursive($resourceClass); $source = tenantOwnedFamilySource($resourceClass); expect(in_array(InteractsWithTenantOwnedRecords::class, $traits, true)) ->toBeTrue("{$familyName} must use the shared tenant-owned resource trait."); expect(preg_match('/public\s+static\s+function\s+getEloquentQuery\s*\(/', $source) === 1) ->toBeTrue("{$familyName} must expose an explicit scoped query entry point."); expect(preg_match('/static::(?:getTenantOwnedEloquentQuery|scopeTenantOwnedQuery)\s*\(/', $source) === 1) ->toBeTrue("{$familyName} must derive records from the canonical tenant-owned query helper."); expect(preg_match('/public\s+static\s+function\s+resolveScopedRecordOrFail\s*\(/', $source) === 1) ->toBeTrue("{$familyName} must expose an explicit scoped-record resolver."); expect(str_contains($source, 'resolveTenantOwnedRecordOrFail')) ->toBeTrue("{$familyName} must resolve detail records through the shared tenant-owned resolver."); } }); it('documents explicit scope exceptions with non-empty reasons', function (): void { $exceptions = TenantOwnedModelFamilies::explicitScopeExceptions(); $exceptionMetadata = TenantOwnedModelFamilies::scopeExceptions(); expect($exceptions)->not->toBeEmpty(); expect(array_keys($exceptionMetadata))->toEqual(array_keys($exceptions)); foreach ($exceptions as $surfaceName => $reason) { expect($surfaceName)->not->toBe(''); expect(trim($reason))->not->toBe(''); expect($exceptionMetadata[$surfaceName]['exception_kind'])->not->toBe(''); expect($exceptionMetadata[$surfaceName]['still_required_checks'])->not->toBeEmpty(); } }); it('keeps finding exception discovery tenant-scoped and global-search disabled', function (): void { $source = tenantOwnedFamilySource(FindingExceptionResource::class); expect(preg_match('/protected\s+static\s+bool\s+\$isGloballySearchable\s*=\s*false;/', $source) === 1) ->toBeTrue('FindingExceptionResource must keep global search disabled until a tenant-safe global search flow is introduced.'); expect(preg_match('/getTenantOwnedEloquentQuery\s*\(\)\s*->with\(static::relationshipsForView\(\)\)/s', $source) === 1) ->toBeTrue('FindingExceptionResource must derive list queries from the canonical tenant-owned query helper and scoped relationship loader.'); expect(preg_match('/resolveTenantOwnedRecordOrFail\s*\(\$record,\s*parent::getEloquentQuery\(\)->with\(static::relationshipsForView\(\)\)\)/s', $source) === 1) ->toBeTrue('FindingExceptionResource must resolve detail records through the shared tenant-owned resolver with the same scoped relationships.'); });