Skip to content
docsv0.8.0

CapabilityProvision

A `provides` capability record. Declares that a plugin offers a concrete implementation (`service`) of a stable contract (`interface`) at a given `contractVersion`. Also accepts the legacy bare-FQCN string form via {@see fromInterface()} so legacy manifests (`contracts.provides = ["Foo\\BarInterface"]`) keep working until the capability records are fully adopted. The primary constructor validates exactly like {@see fromArray()} does: `id` and `interface` must be non-empty and `contractVersion` must be valid semver. There is no "trusted, pre-validated" construction path — hand-building a record (e.g. `new CapabilityProvision(...)` from reflected `#[PluginMetadata]` data) is validated identically to parsing one from a manifest. `exclusive` is TRI-STATE, and NULL means nobody decided. It used to default TRUE for a rich record and FALSE for a bare FQCN, so the same capability admitted one or several providers depending on HOW IT WAS WRITTEN — and the documented migration path runs bare → rich, so migrating a multi-provider capability as the docs recommend would have blocked boot. {@see \Milpa\Services\CapabilityMatcher} killed the same shape for `contractVersion`; this is the same lie one field over. ADR-0037 measured that nobody decides the cardinality of a capability today and refused to legislate who should. So this field stops inventing an answer: an explicit `true`/`false` is a decision, absence is the absence of one, and what the resolver does with an undecided cardinality is the resolver's to report — never this record's to guess.

CapabilityProvision::__construct()

public function __construct(string $id, string $interface, ?string $contractVersion, ?string $service = null, int $priority = 0, ?bool $exclusive = null):

Parameters

Parameters of __construct()
NameTypeDescription
$idstring
$interfacestring
$contractVersion(string | null)NULL means nobody declared one. Only {@see fromInterface()} produces it: a rich record must still declare its version.
$service?string
$priorityint
$exclusive?bool

Throws

\InvalidArgumentException If `id`/`interface` are empty or `contractVersion` is not valid semver.

CapabilityProvision::fromArray()

public static function fromArray(array $record): self

Build a provision record from a decoded `provides` manifest entry. Coerces raw (possibly untyped) array values to their expected shape; validation of the result (`id`/`interface` non-empty, `contractVersion` valid semver) happens in the constructor, not here.

Parameters

Parameters of fromArray()
NameTypeDescription
$recordarray<string, mixed>

Throws

\InvalidArgumentException If `id`/`interface` are empty or `contractVersion` is not valid semver.

CapabilityProvision::fromInterface()

public static function fromInterface(string $interface): self

Wrap a legacy bare-FQCN declaration as a record whose contract version is UNKNOWN. Leaves `exclusive` NULL: a legacy declaration predates the field, so it says nothing about how many providers the capability admits. It used to pin `false` — the mirror of the rich record's `true` — and between the two, cardinality was decided by SPELLING. Neither pin was a policy; §3.1's exclusive-by-default was retired in P17.3 for the same reason (ADR-0037).

Parameters

Parameters of fromInterface()
NameTypeDescription
$interfacestring

CapabilityProvision::parse()

public static function parse(array|string $record): self

Parse a `provides` manifest entry in either the legacy bare-FQCN string form or the structured-record array form, dispatching to {@see fromInterface()} or {@see fromArray()}.

Parameters

Parameters of parse()
NameTypeDescription
$record(string | array<string, mixed>)