Merge nucleic/olive-jade-civet-rznt into dev

This commit is contained in:
2026-07-29 00:14:32 -07:00
parent b342860779
commit 140b358da6
6 changed files with 127 additions and 80 deletions
+72 -61
View File
@@ -1,18 +1,19 @@
namespace WslcApiDump;
/// <summary>
/// Every member <c>NucleicBroker/Wslc/WslcFacade.cs</c> calls on the preview
/// <c>Microsoft.WSL.Containers</c> API, as plain strings.
/// The <c>Microsoft.WSL.Containers</c> surface `NucleicBroker/Wslc/WslcFacade.cs` depends on.
///
/// The facade was written from Microsoft's documentation without a machine to run it on
/// (docs/WINDOWS_PORT.md §1.5), so each line here is a *claim* — and this spike's job is to say,
/// for each one, whether the shipped assembly agrees. Strings rather than typed references is the
/// entire trick: a typed spike that names <c>Session.CreateOrOpen</c> fails to COMPILE if that
/// method has a different name, which teaches us nothing. Reflection turns every wrong guess into
/// a printed line instead of a build error, so one run produces the complete worklist.
/// **This list changed meaning on 2026-07-29.** It began as a list of *guesses* — the facade was
/// transcribed from documentation on machines with no WSL — and this tool existed to find out how
/// many were wrong. That question is answered (docs/WINDOWS_PORT.md §13.1: many of them, including
/// three that were missing capability rather than a wrong name). The entries below are now the
/// surface **actually observed in package 2.9.3**, so this tool's job has changed from discovery
/// to **drift detection**: run it after bumping the pin and it says what the new version moved.
///
/// Keep in lockstep with WslcFacade.cs. A member that stops being used should leave this list;
/// a newly-used member should join it, so the next run of this tool still covers the real surface.
/// Still strings rather than typed references, for the same reason as before — a typed check fails
/// to compile on the first rename and reports one problem; this reports all of them.
///
/// Keep in lockstep with WslcFacade.cs.
/// </summary>
internal static class FacadeAssumptions
{
@@ -23,83 +24,93 @@ internal static class FacadeAssumptions
internal static readonly Assumption[] All =
[
// ---- Service entry point: onboarding (§8 step 2) ----
new("WslcService", "GetServiceVersion", Kind.Method,
"hello capabilities — hostd degrades across preview→GA churn on this string"),
new("WslcService", "GetVersion", Kind.Method,
"hello capabilities — hostd degrades across preview→GA churn on this"),
new("WslcService", "GetMissingComponents", Kind.Method,
"components.missing RPC; drives the guided-install onboarding page"),
new("WslcService", "InstallComponentsAsync", Kind.Method,
"components.install RPC"),
new("ComponentFlags", "None", Kind.EnumValue,
"the 'nothing missing' sentinel the facade filters on"),
"components.missing RPC; returns IReadOnlyList<Component>, NOT a flags enum"),
new("WslcService", "InstallWithDependencies", Kind.Method, "components.install RPC"),
new("Component", "WslPackage", Kind.EnumValue,
"one of the three components onboarding can report missing"),
new("ServiceVersion", "Major", Kind.Property, "the version triple reported in hello"),
// ---- Session: one per channel, hosts every container (§3.2) ----
new("SessionSettings", ".ctor", Kind.Constructor,
"SessionSettings(name, dataDir) — the two-arg shape the facade assumes"),
new("SessionSettings", ".ctor", Kind.Constructor, "SessionSettings(name, storagePath)"),
new("SessionSettings", "CpuCount", Kind.Property, "session.ensure cpu"),
new("SessionSettings", "MemoryMB", Kind.Property,
"session.ensure memoryMB; §3.2 notes a resize needs a sandbox restart"),
new("Session", "CreateOrOpen", Kind.Method,
"THE create-or-attach primitive. If this is absent, broker reattach after a crash "
+ "(§2.3) has no mechanism and the whole supervision design changes"),
new("SessionSettings", "MemorySizeInMB", Kind.Property,
"session.ensure memoryMB — NOT MemoryMB; a resize needs a sandbox restart (§3.2)"),
new("SessionSettings", "Timeout", Kind.Property, "idle timeout for the whole session VM"),
new("Session", ".ctor", Kind.Constructor,
"there is NO CreateOrOpen — construction is the only entry point, and whether a second "
+ "construction with an existing name attaches or throws Error.SessionReserved is the "
+ "open question broker reattach (§2.3) hangs on"),
new("Session", "Start", Kind.Method, "brings the session VM up after construction"),
new("Session", "Terminate", Kind.Method, "session.terminate RPC"),
new("Session", "SessionTerminationHandler", Kind.Property,
"session.down notification → hostd's reconcile sweep"),
new("Session", "HostGatewayAddress", Kind.Property,
"THE control-plane address (§5). ensureRunning returns it to the Swift engine and "
+ "control-bridge.js dials it. If this member does not exist, §5's primary transport "
+ "needs another source (query the vNIC) or the hvsocket fallback gets promoted"),
new("Session", "Terminated", Kind.Event,
"session.down notification (SessionTerminationReason) → hostd's reconcile sweep"),
new("SessionTerminationReason", "Crashed", Kind.EnumValue,
"distinguishes a crash from an orderly shutdown in the session.down reason"),
// ---- Images ----
new("Session", "PullImageAsync", Kind.Method, "image.pull RPC (naros-agent from GHCR)"),
new("PullImageOptions", ".ctor", Kind.Constructor, "PullImageOptions(reference)"),
new("PullImageOptions", "Credentials", Kind.Property, "GHCR auth (registryAuth)"),
new("PullImageOptions", "Progress", Kind.Event,
"image.pullProgress → the existing controlDownloadProgress UI surface"),
new("RegistryCredentials", ".ctor", Kind.Constructor, "RegistryCredentials(user, password)"),
new("Session", "PullImage", Kind.Method, "image.pull RPC (naros-agent from GHCR), sync form"),
new("Session", "PullImageAsync", Kind.Method,
"the async form, which is where pull PROGRESS comes from (ImageProgress)"),
new("PullImageOptions", ".ctor", Kind.Constructor, "PullImageOptions(uri)"),
new("PullImageOptions", "RegistryAuth", Kind.Property,
"GHCR auth — a STRING, not a credentials object"),
new("ImageProgress", "CurrentBytes", Kind.Property,
"→ image.pullProgress → the existing controlDownloadProgress UI surface"),
new("ImageProgressStatus", "Downloading", Kind.EnumValue, "pull progress phase"),
new("Session", "GetImages", Kind.Method, "image.list / image.inspect"),
new("ImageInfo", "Name", Kind.Property, "image ref — NOT .Reference"),
new("ImageInfo", "Sha256", Kind.Property, "image digest — NOT .Digest"),
new("Session", "DeleteImage", Kind.Method, "image.delete"),
// ---- Containers ----
new("Session", "CreateContainer", Kind.Method, "container.create"),
new("Session", "GetContainers", Kind.Method, "container.list; reattach re-enumeration"),
new("ContainerSettings", ".ctor", Kind.Constructor, "ContainerSettings(image)"),
new("ContainerSettings", ".ctor", Kind.Constructor, "ContainerSettings(imageName)"),
new("ContainerSettings", "Name", Kind.Property, "channel-suffixed container naming"),
new("ContainerSettings", "Hostname", Kind.Property, "container.create hostname"),
new("ContainerSettings", "HostName", Kind.Property, "container.create hostname — capital N"),
new("ContainerSettings", "NetworkingMode", Kind.Property,
"NAT vs mirrored (§5 item 4) — determines how the guest reaches the host"),
"None | Bridged — NOT the NAT/mirrored pair §5 assumed"),
new("ContainerSettings", "Volumes", Kind.Property, "the NTFS worktree bind mount (D8)"),
new("ContainerSettings", "InitProcess", Kind.Property, "naros-init as PID 1 (docs/NAROS.md)"),
new("ContainerVolume", ".ctor", Kind.Constructor,
"ContainerVolume(hostPath, guestPath, readOnly) — the 3-arg shape"),
new("ContainerNetworkingMode", "", Kind.Type, "enum parsed from the RPC's networkingMode"),
"ContainerVolume(windowsPath, containerPath, readOnly)"),
new("ContainerNetworkingMode", "Bridged", Kind.EnumValue,
"the mode a container needs to reach the host at all (§5)"),
new("Container", "Start", Kind.Method, "container.start"),
new("Container", "Stop", Kind.Method, "container.stop(signal, grace)"),
new("Container", "Delete", Kind.Method, "container.delete"),
new("Container", "Stop", Kind.Method, "container.stop(Signal, TimeSpan)"),
new("Container", "Delete", Kind.Method, "container.delete(DeleteContainerOption)"),
new("Container", "State", Kind.Property, "container.state → running/stopped/absent"),
new("Container", "GetStatistics", Kind.Method,
"container.stats → ContainerResourceSample; the Swift engine folds deltas from it"),
new("Container", "RunProcess", Kind.Method, "proc.exec — the agent's own exec path"),
new("Container", "Inspect", Kind.Method,
"the ONLY per-container introspection there is — there is no GetStatistics(), so "
+ "container.stats has to exec cgroup reads instead (§13.1 finding 2)"),
new("Container", "CreateProcess", Kind.Method,
"proc.exec — NOT RunProcess, and it does not start the process"),
new("ContainerState", "Running", Kind.EnumValue, "the one state the facade tests by name"),
new("DeleteContainerFlags", "Force", Kind.EnumValue, "container.delete force"),
new("DeleteContainerOption", "Force", Kind.EnumValue, "container.delete force"),
new("Error", "ContainerNotFound", Kind.EnumValue,
"structured failure codes — a better source for the RPC's data.kind than string matching"),
// ---- Processes: the agent stdio path (§3.2 WslcProcessHandle) ----
new("ProcessSettings", "CmdLine", Kind.Property, "argv"),
new("ProcessSettings", "Environment", Kind.Property, "env"),
new("ProcessSettings", "CommandLine", Kind.Property, "argv — NOT CmdLine"),
new("ProcessSettings", "EnvironmentVariables", Kind.Property, "env — NOT Environment"),
new("ProcessSettings", "WorkingDirectory", Kind.Property, "cwd"),
new("ProcessSettings", "OutputMode", Kind.Property, "event-mode stdio, not polling"),
new("ProcessSettings", "Terminal", Kind.Property, "tty for the Terminal panel (§7)"),
new("ProcessSettings", "UserId", Kind.Property,
"runAsUID 501 (§3.2). If absent, exec falls back to a setpriv/su wrapper argv — "
+ "interceptors and nash don't care about the numeric uid, so this is recoverable"),
new("ProcessSettings", "GroupId", Kind.Property, "runAsGID"),
new("ProcessOutputMode", "Event", Kind.EnumValue,
"the mode that makes stdio push-based; polling would change the whole broker design"),
new("Signal", "", Kind.Type, "the enum Stop/Signal take; the RPC carries POSIX ints"),
new("Process", "OutputReceived", Kind.Event, "→ proc.stdout / proc.stderr notifications"),
"the mode that makes stdio push-based; polling would change the broker design"),
new("Process", "Start", Kind.Method,
"the second half of exec — handlers are attached between CreateProcess and this, which "
+ "is precisely why the API is split in two"),
new("Process", "OutputReceived", Kind.Event, "→ proc.stdout notifications"),
new("Process", "ErrorReceived", Kind.Event,
"→ proc.stderr — a SEPARATE event, not a stderr flag on one handler"),
new("Process", "Exited", Kind.Event, "→ proc.exit; must never overtake output (OutboundWriter)"),
new("Process", "WriteStdin", Kind.Method, "proc.stdin (NDJSON to the agent)"),
new("Process", "CloseStdin", Kind.Method, "proc.closeStdin"),
new("Process", "GetInputStream", Kind.Method,
"proc.stdin — a WinRT stream, not a WriteStdin call; closing it is proc.closeStdin"),
new("Process", "Signal", Kind.Method, "proc.signal — the agent's real POSIX Stop path"),
new("Process", "ResizeTerminal", Kind.Method, "proc.resize (tty mode)"),
new("Signal", "SIGKILL", Kind.EnumValue,
"signals are a NAMED enum; the RPC carries POSIX ints, so the broker maps them, and "
+ "anything outside None/HUP/INT/QUIT/KILL/TERM is unavailable"),
];
}
+4 -1
View File
@@ -20,7 +20,10 @@ namespace WslcApiDump;
/// </summary>
internal static class Program
{
private const string AssemblyName = "Microsoft.WSL.Containers";
/// The C#/WinRT PROJECTION assembly. The NuGet package is "Microsoft.WSL.Containers" but
/// the managed assembly it ships is `lib/net8.0-windows10.0.19041.0/wslcsdkcs.dll`, so
/// loading it by package name fails — which is exactly the first thing this tool found.
private const string AssemblyName = "wslcsdkcs";
private static int Main(string[] args)
{
+2 -2
View File
@@ -11,14 +11,14 @@
<OutputType>Exe</OutputType>
<AssemblyName>wslc-api-dump</AssemblyName>
<RootNamespace>WslcApiDump</RootNamespace>
<TargetFramework>net9.0-windows10.0.26100.0</TargetFramework>
<TargetFramework>net9.0-windows10.0.19041.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<!-- Same pin as the broker (docs/WINDOWS_PORT.md §15). If restore fails because the
version moved, change it HERE first, find out what the new API looks like, and only
then bump the broker — that ordering is the whole point of this spike. -->
<PackageReference Include="Microsoft.WSL.Containers" Version="[0.1.0-preview.1]" />
<PackageReference Include="Microsoft.WSL.Containers" Version="[2.9.3]" />
</ItemGroup>
</Project>