AttributeLoader
Reads the ecosystem's second real metadata source — the `#[PluginMetadata]` attribute a plugin's main class carries — into a {@see VersionManifest}. The attribute's `provides`/`requires`/`suggests` accept BOTH real entry shapes, exactly like the manifest loader does: - a bare interface FQCN string (legacy) — synthesized into exactly the same unversioned records the legacy manifest loader produces (`contractVersion 0.0.0` / `constraint *`, with `exclusive: false` pinned by core's `fromInterface()`); - a structured capability record (canonical 012, T087) — routed through core's `fromArray()` verbatim, so it validates and normalizes exactly like a canonical `milpa.json` record (real `contractVersion`/`service`, and `exclusive` left NULL when undeclared — the §3.1 default was retired in P17.3 because it made cardinality depend on syntax, per ADR-0037). Mixing both shapes in one attribute is valid — that is the incremental migration path. The attribute's `type` — the only surface declaration available at the attribute level — rides through as `metadata['pluginType']`. The manifest is marked `metadata['shape'] = 'attribute'`, never `legacy-contracts`: that marker belongs to legacy-shaped FILES, so an attribute-declared record — rich or bare — resolves through the engine's non-legacy path. Following the metadataOf pattern of {@see \Milpa\Services\CapabilityGraphChecker}, a `PluginMetadata` record may also be handed in directly (via {@see fromMetadata()}) when it was already extracted and no reflection is needed.
AttributeLoader::fromClass()
public function fromClass(string $class): Milpa\Resolver\Manifest\VersionManifestReflect the `#[PluginMetadata]` off `$class` and build its manifest.
Parameters
| Name | Type | Description |
|---|---|---|
| $class | (class-string | string) |
Throws
InvalidManifestException When the class cannot be loaded or carries no `#[PluginMetadata]`.
AttributeLoader::fromMetadata()
public function fromMetadata(Milpa\Attributes\PluginMetadata $metadata): Milpa\Resolver\Manifest\VersionManifestBuild a manifest from an already-resolved `#[PluginMetadata]` record.
Parameters
| Name | Type | Description |
|---|---|---|
| $metadata | Milpa\Attributes\PluginMetadata |
Throws
InvalidManifestException When the metadata's name/version do not form a valid manifest.