Files
WP-LIT-MCP/docs/superpowers/plans/2026-11-06-kompatibilitaetsschicht.md
T
Jan-Niclas LoosenandClaude Opus 5.5 9beb55e228 refactor(compat): Capability-Interface, DiviFeature implementiert es
Grundlage der generischen Kompatibilitätsschicht für Fremd-Plugins mit inoffiziellen Schnittstellen (Plan docs/superpowers/plans/2026-11-06-kompatibilitaetsschicht.md).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-06 12:03:30 +01:00

10 KiB
Raw Blame History

Kompatibilitätsschicht für Fremd-Plugins (Phase 0–2)

Stand 2026-11-06, Branch feat/compatibility-layer. Gate 1: voller Architektur-Entwurf (Benutzerentscheidung), weil Pods künftig komplett über den Kern laufen soll und WP Super Cache direkt folgt.

Regeln für jeden Task: zuerst ein fehlschlagender Test, dann die kleinste Änderung; nach jedem Task composer test grün und composer lint ohne neue Befunde (zwei Warnungen bestehen schon: wp-lit-mcp.php:6, RegisteredMetaSourceTest.php:78). DiviBoundaryTest und CoreIndependenceTest laufen immer mit. Ein roter Divi-Test heißt anhalten. Verschiebe-Tasks sind mechanisch (Namespace + use), keine Verhaltensänderung. Keine Commits durch Umsetzungs-Agents (Gate 2 je Commit-Block).

Entscheidungen

  • Kern src/Compatibility/ (Namespace LIT\MCP\Compatibility), importiert kein Divi (CoreIndependenceTest).
  • Capability (id(), label(), isWrite()); DiviFeature implements Capability, id() = value.
  • Kein eigenes RequiresCapabilities: Tools deklarieren Fähigkeits-IDs über das vorhandene DeclaresRequirements.
  • Tier: ReportOnly (nie sperren), LockOnFailure (hartes Problem sperrt, sonst frei; signatures:false), ReleasePerVersion (nur Divi; Matrix kommt per Closure aus ReleaseGate::status()->matrix). ReleaseStore, Resolver-Workflow, WriteProbe, CLI, FeatureSets bleiben Divi-eigen.
  • Gates: CapabilityGate überspringt IDs von ReleasePerVersion-Profilen, prüft IDs anderer Profile über Compatibility::lockOf und sperrt IDs, die kein Profil kennt. DiviFeatureGate ignoriert Nicht-Divi-IDs wieder. Umstellung atomar in 1.13.
  • Pods-IDs mit Präfix pods-, WPSC mit wpsc-; Divi-IDs bleiben unpräfixiert. Eindeutigkeitstest über alle Profile.
  • Pods und WPSC werden Integrationen ohne Abilities, die ProvidesCompatibility implementieren; leere Gruppen dürfen weder im Tools-Tab noch in den Server-Anweisungen erscheinen.
  • Admin: ein gemeinsamer Reiter „Compatibility“ (Slug compatibility); Divi-Freigabe wird Sektion darin (lit_mcp_compat_sections). Kein Redirect vom alten Slug divi, DiviTab wird nicht umbenannt.
  • WPSC: Hook lit_mcp_changed in ChangeLog::record (nur result = ok, eigenes try/catch); Listener nutzt wp_cache_post_edit bzw. wp_cache_clear_cache(blog); kein lit/cache-clear.

Phase 0 – Sicherheitsfixes (erledigt: 8f3a4e7, 234fd1e, 691231f)

Phase 1 – Kern, Pods, Reiter

# Ziel und Dateien Zuerst rot Akzeptanz Modell
1.1 src/Compatibility/Capability.php; DiviFeature implements Capability + id() DiviFeature::PageRead instanceof Capability, id()==='page-read' Divi-Tests grün haiku
1.2 ReleaseState, SourceFingerprint, LineDiff nach src/Compatibility; 'Compatibility' in CORE_PATHS CoreIndependenceTest::testEveryScannedPathExists; verschobene Tests unter neuem Namespace kein Integrations\Divi-Import im Kern haiku
1.3 Requirement (features(): list<Capability>), Call (+accepts() aus ManifestCheck::accepts, signatureKey), ConstantRequirement, Mirror, SignatureFingerprint verschieben; ManifestCheck::accepts delegiert CallTest am neuen Ort; ManifestCheckTest Regression Divi-Suite grün sonnet
1.4 Problem, FeatureStatus verschieben (Capability); Problem::fromArray(mixed, Closure(string): ?Capability); ReleaseResolver::cached übergibt DiviFeature::tryFrom(...); Transient-Format bleibt ProblemTest unbekannte ID → null; ReleaseResolverTest Transient-Rundlauf unverändert sonnet
1.5 CompatibilityMatrix generisch (list<Capability>), uniform/allIncompatible mit Capabilities, fromProblems(caps, problems, ?source, automatic) aus ReleaseResolver (~89-129); SOURCE_* auf die Matrix, Aliase in ReleaseStatus; Aufrufer ReleaseGate, ReleaseStatus, ReleaseResolver, DiviCheckCommand, tests/Support CompatibilityMatrixTest mit Fake-Capability pods-x; fromProblems gegen bisherigen Resolver-Fall ReleaseResolverTest, ReleaseStatusTest unverändert grün sonnet
1.6 DiviAreas (PAGES, LIBRARY, THEME_BUILDER, DESIGN, CATALOG) aus Manifest DiviAreasTest; ManifestTest reine Umbenennung haiku
1.7 Manifest (Capabilities), GlobalRequirement (isset($GLOBALS[name]), hart), ManifestCheck nach src/Compatibility, ohne Divi-Defaults, Option signatures; Divi\Release\DiviManifestCheck::create(); Aufrufer ReleaseResolver, CompatibilityCheck, DiviCompatibility, Tests mit new ManifestCheck() ManifestCheckTest mit signatures:false ohne reference-missing; GlobalRequirement fehlt = hartes Problem; DiviManifestCheckTest Kern ohne Divi; Divi-Release-Tests unverändert sonnet
1.8 Tier, Profile (id, label, tier, capabilities, manifests, ?matrix-Closure, ?version-Closure, ?minVersion, aktiv-Prüfung), Compatibility (matrix memoisiert, lockOf, assert, usable, problems, capability(id), active) CompatibilityTest mit Fake-Profilen je Tier, Memoisierung, unbekannte ID → null, minVersion sperrt alles rein bis auf defined()/get_file_data sonnet
1.9 CapabilityLocked (RuntimeException implements ToolRefusal, compat_incompatible, 423, details features/problems, Fabrik für unbekannte IDs) CapabilityLockedTest analog DiviLockedTest sonnet
1.10 CapabilityGate implements AbilityGuard (Vorlage DiviFeatureGate), Log refused nur bei Schreibtools; noch nicht verdrahtet CapabilityGateTest: Pods-ID gesperrt/frei, Divi-ID ignoriert, unbekannt gesperrt annotate/outputSchema reichen durch sonnet
1.11 ProvidesCompatibility, IntegrationRegistry::compatibilities() (auch nicht verfügbare), DiviProfile::profile(), DiviIntegration implements ProvidesCompatibility IntegrationRegistryTest, DiviIntegrationTest Divi neutral sonnet
1.12 PodsFeature (pods-schema-read, pods-field-read, pods-field-write, pods-field-permissions), PodsCompatibility::profile() (LockOnFailure, PODS_VERSION, min 2.8, Calls mit Argumentzahlen gegen Pods 3.3.9.2), PodsIntegration ohne Abilities PodsCompatibilityTest; Registry-Test: leere Integration nicht in grouped()/labels()/Instructions keine leere Gruppe sichtbar sonnet
1.13 CompatibilityComponent (3 Zustände, Zeile je Fähigkeit); EnvironmentProbe ohne Pods (TEC bleibt); Plugin: Guards [DiviFeatureGate, CapabilityGate], Komponenten per Closure aus der Registry; 0.3-Umzug (unknownIds entfällt, Test zieht in CapabilityGateTest); ID-Eindeutigkeit EnvironmentProbeTest; Zwei-Gate-Test über AbilityRegistrar::argsFor; PluginTest Reihenfolge Divi, Pods, TEC sonnet
1.14 PodsFieldSource + Schema-Wahl über usable(PodsFeature::…); isAvailable() entfällt; Feldrechte über usable(FieldPermissions), sonst fail-closed; 0.2-Bedingung = active && ! usable(SchemaRead) PodsFieldSourceTest je Fähigkeit; PluginTest alle Pods-Tests grün sonnet
1.15 CompatibilityTab + CompatibilitySection (Filter lit_mcp_compat_sections, lazy); Zustand (Wort + Icon) und Probleme je Fähigkeit für Nicht-ReleasePerVersion-Profile CompatibilityTabTest: drei Zustände, Sektion eingebettet, escaped CoreIndependenceTest grün sonnet
1.16 DiviTab implements CompatibilitySection (title() „Divi“); Slug/Redirects/requested()/Notice auf compatibility; DiviIntegration hängt über lit_mcp_compat_sections ein DiviTabTest, DiviIntegrationTest Release/Withdraw/Orphans/Render unverändert sonnet
1.17 Links/Texte: DiviCheckRoute, ReleaseStatus:24, docs/guides/overview.md:96, divi-release-smoke.sh, Docblock DiviCheckCommand DiviCheckRouteTest tab=compatibility; ReleaseStatusTest „→ Compatibility“ DDEV-Smoke grün haiku
1.18 Reiter in Plugin::boot registrieren (nach LogTab); Pods-Smoke erweitern PluginTest Tab-Liste DDEV: compatibility ok, Pods ohne Probleme; hohe minVersion → Pods-Felder schreibgeschützt sonnet

Phase 2 – WP Super Cache 3.1.5

# Ziel und Dateien Zuerst rot Akzeptanz Modell
2.1 Hook lit_mcp_changed(ability, objectType, objectId, logId) in ChangeLog::record, nur bei ok, auch bei fehlgeschlagenem Insert; werfender Listener → Log::failure ChangeLogTest bestehende Fälle grün sonnet
2.2 SuperCacheFeature (wpsc-purge-post, wpsc-purge-all), SuperCacheCompatibility::profile() (LockOnFailure, WPCACHEHOME, Version per get_file_data, GlobalRequirement('cache_path')), SuperCacheIntegration ohne Abilities SuperCacheCompatibilityTest Eindeutigkeitstest umfasst wpsc- sonnet
2.3 SuperCacheListener an lit_mcp_changed: nur bei usable() (sonst Log-Zeile) und $GLOBALS['cache_enabled']; öffentlicher Posttyp außer attachment → wp_cache_post_edit($id); sonst wp_cache_clear_cache(is_multisite() ? get_current_blog_id() : 0); eigenes try/catch SuperCacheListenerTest mit injizierten Closures lint sauber sonnet
2.4 Verdrahtung + Absatz in docs/guides/overview.md PluginTest lit-site-status listet WPSC haiku
2.5 tests/Integration/super-cache-smoke.sh (Feld-Update leert Beitrag, Einstellung leert alles; et_pb_layout öffentlich?) Smoke rot ohne 2.3 DDEV grün sonnet

Commit-Schnitt

4 refactor(compat): Capability und DiviFeature (1.1) · 5 refactor(compat): reine Release-Klassen nach src/Compatibility (1.2–1.4) · 6 refactor(compat): CompatibilityMatrix generisch mit fromProblems (1.5) · 7 refactor(compat): Manifest und ManifestCheck generisch, DiviAreas, DiviManifestCheck (1.6–1.7) · 8 feat(compat): Tier, Profile, Compatibility, CapabilityLocked, CapabilityGate (1.8–1.10) · 9 feat(compat): Profile aus Integrationen, Divi- und Pods-Profil (1.11–1.12) · 10 feat(compat): Gates, Status und Pods über den Kern verdrahten (1.13–1.14) · 11 feat(admin): Reiter „Compatibility“ mit Divi als Abschnitt (1.15–1.18) · 12 feat(changelog): Hook lit_mcp_changed (2.1) · 13 feat(cache): WP Super Cache über den Kern anbinden (2.2–2.4) · 14 test(cache): Integrations-Smoke (2.5)

Risiken

Vergessene use-Zeilen in Verschiebe-Tasks (voller Testlauf je Task); Lücke bei unbekannten IDs nur, wenn CapabilityGate fehlt (PluginTest prüft beide Guards); leere Integrationen verändern Registry-Ausgaben (1.12 prüft zuerst); signatures:false prüft nur Existenz und Argumentzahl; wp_cache_post_edit ist keine dokumentierte API (Wegfall sperrt nur den Purge, sichtbar im Reiter und in lit-site-status).