M1 spikes (docs/WINDOWS_PORT.md §13)
Programs that answer questions the port is currently guessing at. They are checked in and runnable on purpose: a spike whose answer nobody can reproduce six months later is a rumour.
They are deliberately not in windows/Nucleic.sln. The solution's broker contract tests must
keep running on any machine against FakeWslc; these need the Microsoft.WSL.Containers preview
NuGet and a real WSL stack, so they are built by path.
WslcApiDump — what does the wslc API actually look like?
Status: it has served its original purpose (docs/WINDOWS_PORT.md §13.1). The real API is
known, and it was obtained without a Windows machine at all — the package is public, so the
.nupkg was downloaded, its projection assembly extracted, and its metadata read with
MetadataLoadContext. What this tool is for has therefore changed: its assumption list now
describes the surface actually observed in 2.9.3, so running it says what the next package
version moved, not what we guessed wrong.
Why it is still reflection. Same reason as before: a typed check fails to compile on the first rename and reports one problem, where this reports all of them at once. That property is worth keeping for a preview API whose next version can break anything.
Two facts it discovered that anything referencing this package needs:
- the assembly is
wslcsdkcs.dll, notMicrosoft.WSL.Containers.dll— loading it by package name fails; - the only published version is 2.9.3, targeting
net8.0-windows10.0.19041.0. The0.1.0-preview.1pin this repo carried could never have restored.
cd windows/spikes/WslcApiDump
dotnet run # dump the API + check every facade assumption
dotnet run -- --probe # + call the two read-only statics (service version, missing components)
dotnet run -- --session # + create a real session and print its live property VALUES
It writes the full public object model to wslc-api-dump.txt (--out to relocate) and prints an
ok / MISSING line per assumption, each with why that member matters and a nearest-name hint.
It exits 0 even when assumptions fail — a mismatch is the product, not an error. Only a genuinely
broken run (the assembly won't load) exits non-zero.
What to send back: the console output, and wslc-api-dump.txt if anything is MISSING —
which now means the package moved under us, not that we guessed wrong.
Why --session earns its risk
--session creates a real wslc session named nucleic-spike under
%LOCALAPPDATA%\Nucleic\spike\wslc and leaves it running. It exists for one question that type
metadata cannot answer: where does the WSL-facing host gateway address come from? §5 makes
gateway TCP the primary control-plane transport, WslcContainerEngine.ensureRunning returns that
address to the Swift side, and control-bridge.js dials it. The facade guesses
Session.HostGatewayAddress. Dumping the live values of every session property lets us
recognise a gateway IP whatever it is called — and if nothing on the session looks like one,
that is itself the finding, and §5's hvsocket fallback gets promoted from upside to dependency.
Leaving the session running is also the cheap version of a §2.3 question: broker supervision
assumes wslc state is service-backed, so that a crashed nucleic-brokerd can reattach and
re-enumerate rather than orphaning containers. If wslc session ls still shows nucleic-spike
after this process exits, that assumption holds. Tear it down with wslc when you're done.
The three answers that change the design
Most mismatches are a one-line edit in WslcFacade.cs — that is exactly what the IWslc seam is
for, and nothing above it should move. These three are different:
| Finding | Consequence |
|---|---|
| No container enumeration, stats, or pty in the SDK | Not fatal — wslc.exe has all three and addresses containers by name, so WslcFacade becomes a hybrid (SDK hot path + CLI cold paths). Confirmed by the native header and the API reference, and publicly reported in microsoft/WSL#41024, which Microsoft has not answered. |
No create-or-attach on Session |
Still open. The native-only WSLC_CONTAINER_START_FLAG_ATTACH may be it; the C# Start() takes no flags. Needs a live answer before item 11. |
| No gateway address anywhere on the API | §5's primary transport must source it from GetAdaptersAddresses over the vEthernet (WSL) adapter instead. If a Bridged container can't reach the host there, promote the AF_HYPERV/AF_VSOCK fallback. |
No uid on ProcessSettings |
Recoverable, and already planned for: exec wraps argv in setpriv/su agent -c. Interceptors and nash don't care about the numeric uid (§3.2). |
Not yet written
WslcSpike— the typed happy path: session → GHCR pull ofnaros-agent→ container with an NTFSContainerVolume→exec git statusin the bind-mounted worktree → stdio round-trip → SIGTERM, plus the 9P latency numbers §15 wants (git statusandnpm installon a real repo, mounted vs. in-VM). Deliberately held back untilWslcApiDumphas run: written now, against guessed names, it would not compile, and fixing it blind is the mistake this whole approach exists to avoid.HvSocketSpike— M1 (b): AF_HYPERV host listener ↔ AF_VSOCK dial from inside a wslc container, plus gateway-TCP reachability and default-firewall behaviour in NAT and mirrored modes. Only worth building once a container can be started at all.