feat: complete shared platform UI contracts

This commit is contained in:
2026-07-31 04:21:34 +02:00
parent 5b55f59a92
commit 7b8072d049
19 changed files with 764 additions and 285 deletions
+16
View File
@@ -222,11 +222,13 @@ DocumentationSourceKind = Literal[
"route",
"capability",
"policy",
"release_catalog",
"configuration_package",
"wiki",
"repository",
]
DocumentationSourceState = Literal["configured", "disabled", "unavailable"]
CapabilityStability = Literal["experimental", "stable", "deprecated"]
@dataclass(frozen=True, slots=True)
@@ -336,12 +338,25 @@ class DocumentationSourceDefinition:
documentation_types: tuple[DocumentationType, ...] = ("admin",)
condition: DocumentationCondition = field(default_factory=DocumentationCondition)
state: DocumentationSourceState = "configured"
state_reason: str | None = None
provenance: Mapping[str, Any] = field(default_factory=dict)
inspection: Mapping[str, Any] = field(default_factory=dict)
link: DocumentationLink | None = None
configuration_key: str | None = None
@dataclass(frozen=True, slots=True)
class CapabilityDocumentation:
"""Provider-owned capability metadata safe for generic platform consumers."""
label: str
summary: str
contract_version: str | None = None
stability: CapabilityStability = "stable"
documentation_types: tuple[DocumentationType, ...] = ("admin",)
audience: tuple[str, ...] = ()
class ResourceAclProvider(Protocol):
resource_type: str
@@ -412,6 +427,7 @@ class ModuleManifest:
delete_veto_providers: Mapping[str, Sequence[DeleteVetoProvider]] = field(default_factory=dict)
uninstall_guard_providers: tuple[UninstallGuardProvider, ...] = ()
capability_factories: Mapping[str, CapabilityFactory] = field(default_factory=dict)
capability_documentation: Mapping[str, CapabilityDocumentation] = field(default_factory=dict)
search_providers: tuple["SearchProviderRegistration", ...] = ()
search_sources: tuple["SearchSourceProviderRegistration", ...] = ()
compatibility: ModuleCompatibility = field(default_factory=ModuleCompatibility)
+22
View File
@@ -614,6 +614,28 @@ def _validate_manifest_shape(manifest: ModuleManifest) -> None:
def _validate_documentation_extensions(manifest: ModuleManifest) -> None:
for capability, metadata in manifest.capability_documentation.items():
if capability not in manifest.capability_factories:
raise RegistryError(
f"Module {manifest.id!r} documents capability {capability!r} "
"but does not provide it"
)
if not metadata.label.strip():
raise RegistryError(
f"Module {manifest.id!r} capability {capability!r} "
"documentation must have a label"
)
if not metadata.summary.strip():
raise RegistryError(
f"Module {manifest.id!r} capability {capability!r} "
"documentation must have a summary"
)
if metadata.contract_version is not None and not metadata.contract_version.strip():
raise RegistryError(
f"Module {manifest.id!r} capability {capability!r} "
"documentation contract version must not be empty"
)
provider_keys: set[str] = set()
for registration in manifest.documentation_configuration_providers:
if not registration.keys: