Files
lingua-engine/src/Engine.Kernel/Events/NullEventBus.cs
T
EmilandClaude Sonnet 5 978f34727f Implement PluginHost: two-ALC plugin loading, unloading verified live
The centerpiece of the whole "no domain reload" claim, now proven
empirically rather than argued on paper: 200 load/unload cycles against
a real plugin (sandbox.echo), each one checked with a WeakReference
that the collectible ALC actually collected — docs/kernel-contract.md
§4's leak test, previously Skip-marked since the very first scaffold,
now runs and passes (stable across repeated runs).

New pieces, minimal by design:

- PluginLoadContext: the collectible ALC a plugin's implementation
  loads into. Load() defers to whatever's already in the Default ALC
  (Engine.Kernel, the plugin's own Contracts assembly) before
  consulting AssemblyDependencyResolver for genuinely private
  dependencies — the standard .NET plugin pattern, needed so component
  types stay identical across the plugin boundary instead of loading
  as two distinct, incompatible copies.
- PluginHost: reads plugin.json, loads Contracts into the Default ALC
  (once — verified directly, not just inferred from the leak test),
  loads the implementation into a fresh PluginLoadContext, finds the
  IPlugin type via reflection, calls Configure(). Unload() calls
  Shutdown() first, then .Unload()s the ALC and hands back a
  WeakReference for the caller to check.
- Schedule, ServiceRegistry, NullEventBus, ConsoleLogger: minimal real
  implementations of the remaining IPluginContext pieces — no stage
  execution or parallelism in Schedule yet, that's separate Scheduler
  work. Schedule.RemoveAllFrom is the one piece that has to be
  correct now, not later: it's what lets a plugin's Shutdown() actually
  drop the delegate reference into its own collectible ALC, which is
  exactly what the leak test is checking end to end.

Explicitly out of scope for this pass: resolving a project's or
plugin's dependsOn graph to order loading across multiple plugins.
Nothing to test that against yet — sandbox.echo is deliberately the
only, dependency-free fixture. Noted as a TODO on PluginHost rather
than built speculatively.

Sandbox.Echo.csproj gets <EnableDynamicLoading>true</EnableDynamicLoading>
(future plugins with real dependencies will need the deps.json this
generates). Engine.ConformanceHarness.csproj now copies plugin.json and
both built DLLs into one flat directory under its own output, matching
the layout PluginHost.Load(directory) expects — via $(Configuration)/
$(TargetFramework)-aware CopyToOutputDirectory items, correct in
Release too, not just Debug.

17 tests total now (13 in Engine.Kernel.Tests, 4 in
Engine.ConformanceHarness), all passing on a clean build.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01N1qPfzq8TDCUMFMV3UwV5N
2026-09-02 00:47:23 +03:00

8 lines
244 B
C#

namespace Engine.Kernel.Events;
/// <summary>
/// IEventBus has no members yet — see the open question in
/// docs/kernel-contract.md's footer. Nothing to implement until it does.
/// </summary>
public sealed class NullEventBus : IEventBus;