feat(compat): Profile, Gates und Pods über den Kompatibilitätskern
Neu: Tier, Profile, Compatibility, CapabilityLocked, CapabilityGate, CompatibilityComponent, ProvidesCompatibility, DiviProfile sowie PodsFeature, PodsCompatibility und PodsIntegration. Das CapabilityGate sperrt gesperrte und unbekannte Fähigkeits-IDs (übernimmt die Sperre unbekannter IDs vom DiviFeatureGate) und delegiert nur Divi ausdrücklich. Pods-Schema, -Lesen, -Schreiben und -Feldrechte laufen über usable(PodsFeature::…); Schreiben verlangt FieldRead und FieldWrite, damit ein Rollback keine Werte verliert. lit-site-status meldet Pods über die CompatibilityComponent. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
b511ef6348
commit
c85131603b
@@ -0,0 +1,64 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace LIT\MCP\Tests\Unit\Compatibility;
|
||||
|
||||
use LIT\MCP\Abilities\ToolRefusal;
|
||||
use LIT\MCP\Compatibility\CapabilityLocked;
|
||||
use LIT\MCP\Compatibility\FeatureStatus;
|
||||
use LIT\MCP\Compatibility\Profile;
|
||||
use LIT\MCP\Compatibility\ReleaseState;
|
||||
use LIT\MCP\Compatibility\Tier;
|
||||
use LIT\MCP\Tests\Support\FakeCapability;
|
||||
use LIT\MCP\Tests\Unit\TestCase;
|
||||
use LogicException;
|
||||
|
||||
final class CapabilityLockedTest extends TestCase
|
||||
{
|
||||
public function testTheErrorNamesPluginCapabilitiesAndProblems(): void
|
||||
{
|
||||
$profile = new Profile('fake', 'Fake Plugin', Tier::LockOnFailure, [FakeCapability::Write]);
|
||||
$locked = CapabilityLocked::of(
|
||||
[new FeatureStatus(FakeCapability::Write, ReleaseState::Incompatible, ['Fake: x() fehlt'])],
|
||||
[$profile]
|
||||
);
|
||||
|
||||
self::assertInstanceOf(ToolRefusal::class, $locked);
|
||||
self::assertSame('Fake Plugin locked – fake-write refused', $locked->getMessage());
|
||||
$error = $locked->toError();
|
||||
$payload = self::assertToolError($error, 'compat_incompatible');
|
||||
self::assertSame(423, $error->get_error_data()['status']);
|
||||
self::assertStringContainsString('Fake Plugin', $payload['message']);
|
||||
self::assertStringContainsString('Fake fake-write', $payload['message']);
|
||||
self::assertNotSame('', $payload['hint']);
|
||||
self::assertSame(['fake-write'], array_column($payload['features'], 'id'));
|
||||
self::assertSame(['Fake: x() fehlt'], $payload['problems']);
|
||||
}
|
||||
|
||||
public function testALockWithoutLockedCapabilitiesIsAProgrammingError(): void
|
||||
{
|
||||
$this->expectException(LogicException::class);
|
||||
|
||||
CapabilityLocked::of([], []);
|
||||
}
|
||||
|
||||
public function testUnknownIdsLockTheCall(): void
|
||||
{
|
||||
$locked = CapabilityLocked::unknown(['fake-x', 'fake-y']);
|
||||
|
||||
$error = $locked->toError();
|
||||
$payload = self::assertToolError($error, 'compat_incompatible');
|
||||
self::assertSame(423, $error->get_error_data()['status']);
|
||||
self::assertSame(['fake-x', 'fake-y'], $payload['unknown']);
|
||||
self::assertStringContainsString('fake-x, fake-y', $payload['message']);
|
||||
self::assertSame(['fake-x', 'fake-y'], $locked->unknown);
|
||||
}
|
||||
|
||||
public function testUnknownNeedsAtLeastOneId(): void
|
||||
{
|
||||
$this->expectException(LogicException::class);
|
||||
|
||||
CapabilityLocked::unknown([]);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user