refactor(compat): Freigabe-Bausteine generisch

ReleaseStore, CheckReportStore, CheckReport, CheckStep und CompatibilityCheck liegen im Kern und arbeiten je Profil (Optionen lit_mcp_<id>_releases|_check_report; Divi behält Namen und Schlüssel divi_version). Divi hängt Katalog-, Format- und Schreibtest über Profile::extraSteps an. Ein roter Prüfbericht für den aktuellen Stand sperrt LockOnFailure-Profile bis zur nächsten grünen Prüfung; Sperrgründe nennen nur Schritt-Labels, Ausnahmen gehen ins Error-Log. Profile bekommt testedVersions, stateKey, extraSteps, manifestCheck und reportVersionKey und wird mit benannten Argumenten gebaut.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Jan-Niclas Loosen
2026-11-06 12:51:03 +01:00
co-authored by Claude Opus 5.5
parent c85131603b
commit 7d6a97a54e
48 changed files with 1469 additions and 647 deletions
+49 -6
View File
@@ -5,6 +5,7 @@ declare(strict_types=1);
namespace LIT\MCP\Tests\Unit\Compatibility;
use LIT\MCP\Compatibility\CompatibilityMatrix;
use LIT\MCP\Compatibility\ManifestCheck;
use LIT\MCP\Compatibility\Profile;
use LIT\MCP\Compatibility\Tier;
use LIT\MCP\Tests\Support\FakeCapability;
@@ -17,10 +18,10 @@ final class ProfileTest extends TestCase
{
$matrix = static fn (): CompatibilityMatrix => CompatibilityMatrix::allReleased([FakeCapability::Read]);
$profile = new Profile(
'fake',
'Fake Plugin',
Tier::ReleasePerVersion,
[FakeCapability::Read],
id: 'fake',
label: 'Fake Plugin',
tier: Tier::ReleasePerVersion,
capabilities: [FakeCapability::Read],
matrix: $matrix,
minVersion: '2.0'
);
@@ -34,12 +35,54 @@ final class ProfileTest extends TestCase
self::assertSame([], $profile->manifests);
}
public function testTheStoredVersionKeyDefaultsToVersionAndIsKeptWhenGiven(): void
{
$plain = new Profile(id: 'fake', label: 'Fake', tier: Tier::ReportOnly, capabilities: [FakeCapability::Read]);
$divi = new Profile(
id: 'fake',
label: 'Fake',
tier: Tier::ReportOnly,
capabilities: [FakeCapability::Read],
reportVersionKey: 'divi_version'
);
self::assertSame('version', $plain->reportVersionKey);
self::assertSame('divi_version', $divi->reportVersionKey);
}
public function testTheReleaseFieldsAreOptionalAndKeptWhenGiven(): void
{
$bare = new Profile(id: 'fake', label: 'Fake', tier: Tier::ReportOnly, capabilities: [FakeCapability::Read]);
self::assertSame([], $bare->testedVersions);
self::assertNull($bare->stateKey);
self::assertNull($bare->extraSteps);
self::assertNull($bare->manifestCheck);
$stateKey = static fn (string $version): string => 'k' . $version;
$extraSteps = static fn (bool $manifestClean): array => [];
$manifestCheck = static fn (): ManifestCheck => new ManifestCheck([], signatures: false);
$full = new Profile(
id: 'fake',
label: 'Fake',
tier: Tier::ReportOnly,
capabilities: [FakeCapability::Read],
testedVersions: ['1.0'],
stateKey: $stateKey,
extraSteps: $extraSteps,
manifestCheck: $manifestCheck
);
self::assertSame(['1.0'], $full->testedVersions);
self::assertSame($stateKey, $full->stateKey);
self::assertSame($extraSteps, $full->extraSteps);
self::assertSame($manifestCheck, $full->manifestCheck);
}
public function testAReleasePerVersionProfileWithoutMatrixIsAProgrammingError(): void
{
$this->expectException(LogicException::class);
$this->expectExceptionMessage('needs a matrix closure');
new Profile('fake', 'Fake', Tier::ReleasePerVersion, [FakeCapability::Read]);
new Profile(id: 'fake', label: 'Fake', tier: Tier::ReleasePerVersion, capabilities: [FakeCapability::Read]);
}
public function testCapabilityIdsMustBeUniqueWithinAProfile(): void
@@ -47,7 +90,7 @@ final class ProfileTest extends TestCase
$this->expectException(LogicException::class);
$this->expectExceptionMessage('fake-read');
new Profile('fake', 'Fake', Tier::ReportOnly, [FakeCapability::Read, FakeCapability::Read]);
new Profile(id: 'fake', label: 'Fake', tier: Tier::ReportOnly, capabilities: [FakeCapability::Read, FakeCapability::Read]);
}
public function testTheTiersHaveStableValues(): void