Kernel
The fresh, bootable Milpa kernel: COMPOSES the published family instead of reimplementing it. `boot()` wires, in order: a DI container ({@see \Milpa\Container\DIContainer}) -> an event dispatcher ({@see \Milpa\Eventing\EventDispatcher}) -> an architecture resolution through `milpa/resolver`'s {@see GraphResolver} (fails BEFORE any plugin boots, with a learnable message — this replaces the retired {@see \Milpa\Services\CapabilityGraphChecker}, spec §24.7) -> plugins loaded and booted in `provides`-\>`requires` order (the `loadOrder[]` the resolver's own {@see ResolutionReport} dictates — one topological pass, no second sort) -> route table assembly over `milpa/http`. Every step emits the same lifecycle events the legacy host kernel's event-driven retrofit introduced (`plugin.booting`/`plugin.booted`, `capability.resolved`, `kernel.booted` — see {@see \Milpa\Events}), plus the new `architecture.resolved` carrying the resolver's full report. Zero Doctrine, zero legacy `Milpa\Web`: the active-plugins list is whatever `list<class-string>` the caller passes via `$config['plugins']` — a config array, a file `require`d into that array, or filesystem discovery the caller performs before calling `boot()`. This class never queries a database to decide what to boot; a persistence-backed plugin registry is something a *plugin* can add later, never something the kernel requires.
Kernel::boot()
public static function boot(array $config = []): selfBoots the kernel: builds (or accepts injected) collaborators, resolves the host root, resolves the whole architecture graph through `milpa/resolver` (blocking a bad graph BEFORE any plugin boots), orders the configured plugins, boots each in order while emitting the lifecycle events, and assembles the route table from every booted `RouteProviderInterface` plugin.
Parameters
| Name | Type | Description |
|---|---|---|
| $config | array{root?: (string | null), name?: string, plugins?: list<class-string>, config?: array<string, mixed>, hostProfile?: array<string, mixed>, evaluatedAt?: string, container?: DIContainerInterface, dispatcher?: MilpaEventDispatcherInterface, logger?: LoggerInterface, toolRegistry?: (ToolRegistryInterface | null), pluginBoot?: Boot\PluginBootStrategyInterface} | Every key is optional: `root` defaults to {@see RootResolver}'s auto-detection, `plugins` defaults to an empty list, `config` is the app-config bag plugins read via `$container->get(Config::class)` (the seam that replaces plugin constructor args and env-var globals), `container`/`dispatcher`/`logger` default to fresh family instances (injecting your own is the seam tests use to observe lifecycle events before `boot()` runs), `toolRegistry` defaults to null — wiring one is the host's opt-in, `milpa/runtime` never constructs one itself. `hostProfile` (a {@see HostProfile::fromArray()} shape) is the architectural profile the resolver checks against; ABSENT it defaults to a DELIBERATELY PERMISSIVE profile — name `$config['name']` or `'host'`, version `0.0.0`, `allowedLegacyContracts: ['*']`, NO `requiredCapabilities` — so a graph that boots today (plugin `requires` all satisfied by some plugin's `provides`) resolves identically and BC holds. `evaluatedAt` (an ISO-8601 datetime) is passed straight through to the resolver as the clock for accepted-risk expiry; the resolver, not the runtime, validates it. A blocked graph throws {@see ArchitectureBlockedException} — a {@see PluginDependencyException} subclass, so every catch that worked against the retired {@see \Milpa\Services\CapabilityGraphChecker} still works (narrowing BC) — with the report's own learnable first line as the message (code + why + first fix + Academy link) and the whole {@see ResolutionReport} riding on `->report`. Boot listeners still get the report on the `architecture.resolved` event when the graph is NOT blocked. |
Throws
AttributeNotFoundException A configured plugin class carries no `#[PluginMetadata]`.
ArchitectureBlockedException The architecture graph is `blocked` (an unmet required
contract/capability, a conflict — a dependency cycle included —
or an un-permitted legacy path); carries the full report.
\Milpa\Resolver\Exceptions\InvalidManifestException The `hostProfile` array or the `evaluatedAt` clock is malformed,
or a plugin's `PluginMetadata` version is not a parseable version
string (all validated by the resolver, not the runtime).
\Milpa\Runtime\Support\RootNotFoundException The host root could not be resolved and none was given explicitly.
Kernel::container()
public function container(): Milpa\Interfaces\Di\DIContainerInterfaceThe DI container every plugin and controller was resolved through.
Kernel::dispatcher()
public function dispatcher(): Milpa\Interfaces\Event\MilpaEventDispatcherInterfaceThe event dispatcher every lifecycle event was emitted on.
Kernel::router()
public function router(): Milpa\Http\Routing\RouterThe route table assembled from every booted `RouteProviderInterface` plugin.
Kernel::plugins()
public function plugins(): arrayEvery configured plugin instance, including any vetoed via a `plugin.booting` listener.
Kernel::bootedPluginNames()
public function bootedPluginNames(): arrayNames of the plugins whose `boot()` actually ran, in boot order.
Kernel::root()
public function root(): stringThe resolved host application root directory.
Kernel::toolRegistry()
public function toolRegistry(): ?Milpa\Interfaces\Tooling\ToolRegistryInterfaceThe tool registry wired via `$config['toolRegistry']`, or null if the host opted out.
Kernel::commands()
public function commands(): arrayEvery command collected from a booted `CommandProviderInterface` plugin's `commands()`, or a `CommandProvider` plugin's `operations()` — the command-table counterpart of {@see router()}. A host CLI registers these as subcommands in addition to its own built-ins.