{"owner":"microsoft","repo":"WSL","hasSkills":true,"totalSkillsCount":6,"totalTokensCount":11250,"categories":["copilot-instructions"],"hasMcp":false,"mcpConfig":null,"found":[".github/copilot/review.md",".github/copilot/test.md",".github/copilot/commit.md",".github/copilot/wslg-logs.md",".github/copilot/localization-bugs.md",".github/copilot-instructions.md"],"skills":{".github/copilot/review.md":"## Code Review Guidelines for WSL\n\nWhen reviewing code, enforce the conventions in `.github/copilot-instructions.md`. Focus especially on these high-risk areas:\n\n### ABI Safety (Critical)\nOnly the SDK-facing and public surfaces require a backward-compatible ABI. Every other COM interface (`wslc.idl`, `wslservice.idl`, etc.) is internal and non-stable: shipped in lockstep with its only clients, with the proxy/stub regenerated each build, so methods may be appended to those freely. Do **not** flag internal, non-stable interfaces.\n- **Flag** ABI-breaking changes (new, removed, or reordered methods, changed struct layouts) only in the stable surfaces: `WSLCCompat.idl` (the WSLC SDK-facing layer, which must stay backward compatible) and the public plugin API (`WSLPluginHooksV1` / `WSLPluginAPIV1` structs in `WslPluginApi.h`).\n- **Do not flag** new methods appended to internal, non-stable interfaces such as `IWSLCSession` in `wslc.idl`, or interfaces in `wslservice.idl`.\n\n### Resource Safety\n- **Flag** raw `CloseHandle()`, `delete`, `free()`, or manual resource cleanup — require WIL smart pointers\n- **Flag** missing `NON_COPYABLE()` / `NON_MOVABLE()` on classes that hold resources\n- **Flag** lock usage without `_Guarded_by_()` SAL annotations\n\n### User-Facing Changes\n- **Flag** hardcoded English strings — require `Localization::MessageXxx()` and Resources.resw entry\n- **Flag** new `.wslconfig` settings without corresponding Resources.resw localization string\n- **Flag** silent fallback on invalid config values — require `EMIT_USER_WARNING()`\n\n### Error Handling\n- **Flag** bare `if (FAILED(hr))` — require WIL macros\n- **Flag** silently swallowed errors — require `CATCH_LOG()` or `LOG_IF_FAILED()`\n- **Flag** telemetry events missing privacy data tags\n",".github/copilot/test.md":"## Test Generation Guidelines for WSL\n\nWhen generating tests for this repository, follow these patterns:\n\n### Framework\nTests use TAEF (Test Authoring and Execution Framework). Always include `\"Common.h\"`.\n\n### Test Class Structure\n```cpp\n#include \"Common.h\"\n\nnamespace MyFeatureTests\n{\nclass MyFeatureTests\n{\n    WSL_TEST_CLASS(MyFeatureTests)\n\n    TEST_CLASS_SETUP(TestClassSetup)\n    {\n        VERIFY_ARE_EQUAL(LxsstuInitialize(FALSE), TRUE);\n        return true;\n    }\n\n    TEST_CLASS_CLEANUP(TestClassCleanup)\n    {\n        LxsstuUninitialize(FALSE);\n        return true;\n    }\n\n    TEST_METHOD(DescriptiveTestName)\n    {\n        // Test implementation\n    }\n};\n}\n```\n\n### Key Rules\n- Use `WSL_TEST_CLASS(Name)` — never raw `BEGIN_TEST_CLASS`\n- Setup/cleanup methods must `return true` on success\n- Use `VERIFY_*` macros for assertions — never `assert()` or exceptions for test validation\n\n### Assertion Macros\n- `VERIFY_ARE_EQUAL(expected, actual)` — value equality\n- `VERIFY_ARE_NOT_EQUAL(a, b)` — value inequality\n- `VERIFY_IS_TRUE(condition)` — boolean check\n- `VERIFY_IS_FALSE(condition)` — negative boolean check\n- `VERIFY_IS_NULL(ptr)` — null check\n- `VERIFY_IS_NOT_NULL(ptr)` — non-null check\n- `VERIFY_WIN32_BOOL_SUCCEEDED(expr)` — Win32 BOOL result\n- `VERIFY_SUCCEEDED(hr)` — HRESULT success\n\n### Logging in Tests\n- `LogInfo(fmt, ...)` — informational messages\n- `LogError(fmt, ...)` — error messages\n- `LogWarning(fmt, ...)` — warnings\n- `LogPass(fmt, ...)` — explicit pass messages\n- `LogSkipped(fmt, ...)` — skip messages\n\n### Conditional Skipping\nAdd skip macros at the start of a test method body when the test only applies to certain environments:\n```cpp\nTEST_METHOD(Wsl2SpecificTest)\n{\n    WSL2_TEST_ONLY();\n    // ... test code ...\n}\n```\n\nAvailable skip macros:\n- `WSL1_TEST_ONLY()` — skip unless WSL1\n- `WSL2_TEST_ONLY()` — skip unless WSL2\n- `SKIP_TEST_ARM64()` — skip on ARM64\n- `SKIP_TEST_UNSTABLE()` — skip known-flaky tests\n- `WINDOWS_11_TEST_ONLY()` — skip on pre-Windows 11\n- `WSL_TEST_VERSION_REQUIRED(version)` — skip if WSL version too old\n\n### RAII Test Helpers\n- `WslKeepAlive` — prevents UVM timeout during long-running tests; create at test start\n- `WslConfigChange` — RAII wrapper that applies a temporary `.wslconfig` and restores the original on destruction:\n```cpp\nTEST_METHOD(TestWithCustomConfig)\n{\n    WslConfigChange config(L\"[wsl2]\\nmemory=4GB\\n\");\n    // ... test with custom config ...\n    // Original .wslconfig restored when config goes out of scope\n}\n```\n\n### Memory in Tests\n- Use `ALLOC(size)` / `FREE(ptr)` macros for direct heap allocation in tests\n- Prefer RAII wrappers and smart pointers for production-like code paths\n\n### Test Naming\n- Use descriptive PascalCase names that describe the scenario: `CreateInstanceWithInvalidGuidFails`, `EchoTest`, `MountPlan9Share`\n- Group related tests in the same test class\n",".github/copilot/commit.md":"## Commit Message Guidelines for WSL\n\nThis repo has no strict commit message format. Follow these general practices:\n\n- Write a concise summary under 72 characters\n- Use imperative mood (\"Fix crash\" not \"Fixed crash\")\n- Reference GitHub issues with `(#123)` or `Fixes #123`\n- Add a body paragraph for non-obvious changes explaining *why*\n",".github/copilot/wslg-logs.md":"# Analyzing WSLg logs\n\nWSLg is the component that runs graphical (GUI) and audio Linux applications on WSL. Its\nsource lives in a separate repository: https://github.com/microsoft/wslg. The canonical list\nof diagnostics to request for a WSLg bug is the WSLg repo bug report template\n(`.github/ISSUE_TEMPLATE/bug_report.yml` in microsoft/wslg).\n\n`diagnostics/collect-wsl-logs.ps1` collects the logs into a `wslg/` subfolder of the log archive\n(via `wsl.exe --system --user root`, with a timeout so a wedged service can't hang collection), so a\nstandard WSL log collection already contains the log files below. Crash dumps (`dumps/`,\n`wsl-crashes/`) are only collected when the script is run with `-Dump`.\n\n## Architecture (just enough to read the logs)\n\nWSLg runs a **system distro** (a small Azure Linux VM, separate from the user distro) that hosts:\n- **weston** (Wayland compositor) with the `rdp-backend.so` / `rdprail-shell.so` modules\n- **Xwayland** for X11 apps\n- **pulseaudio** with an RDP sink/source for audio\n- **FreeRDP** to stream the surfaces over an hvsocket to the Windows RDP client (`msrdc.exe`)\n\n`weston.log` and `wlog.log` are written by weston/FreeRDP, `pulseaudio.log` by pulseaudio, and\n`stderr.log` is the combined stderr of `WSLGd` and the processes it launches.\n\n## Files (in the `wslg/` folder, sourced from `/mnt/wslg`)\n\n| File | Contents |\n|---|---|\n| `versions.txt` | WSLg version, architecture, build date, component git hashes (weston, FreeRDP, mesa, pulseaudio) |\n| `weston.log` | Weston compositor + RDP backend log |\n| `wlog.log` | FreeRDP (WLog) log |\n| `pulseaudio.log` | PulseAudio log |\n| `stderr.log` | `WSLGd` and child-process stderr |\n| `dumps/` | Legacy WSLg crash dumps (older builds only; collected with `-Dump`) |\n| `wsl-crashes/` | Host-side WSLg crash dumps copied from `%TEMP%\\wsl-crashes` (newer builds, e.g. `core.weston`; collected with `-Dump`) |\n\n## Reading tips and common signatures\n\n- **`weston.log` is truncated on every boot.** Weston is started with `--log=/mnt/wslg/weston.log`\n  and opens it truncating, so the file only ever contains the **latest** system-distro boot. To\n  tell whether weston restarted, compare the boot timestamp on the first line (`weston 9.0.0 ...`)\n  across snapshots, or correlate with `dmesg`.\n\n- **System distro cycling / teardown.** In `dmesg` (collected via the ETL `GuestLog` events or\n  the debug console), this pair means the WSLg system distro's `init` exited and the distro was\n  torn down (idle timeout or shutdown), which also restarts weston:\n  ```\n  Exception: Operation canceled @p9io.cpp:258 (AcceptAsync)\n  WSL (1 - init()) ERROR: InitEntryUtilityVm:2551: Init has exited. Terminating distribution\n  ```\n  Repeating every ~25-60s with no GUI client attached is usually normal idle teardown, not a crash.\n  A genuine weston crash instead leaves a core dump in `wsl-crashes/` (or `dumps/`).\n\n- **No GPU acceleration (software rendering).** This means the virtual GPU (`/dev/dxg`, d3d12 mesa)\n  is not usable, so rendering falls back to CPU:\n  ```\n  Xwayland glamor: GBM Wayland interfaces not available\n  Failed to initialize glamor, falling back to sw\n  ```\n  Investigate GPU driver presence, `/dev/dxg`, and the `mesa`/`d3d12` stack if the user reports\n  black windows, slow rendering, or missing 3D.\n\n- **Audio sink not connected (usually benign at boot).** Expected until an RDP/audio client attaches:\n  ```\n  [rdp-sink] RDP Sink - Trying to connect to /mnt/wslg/PulseAudioRDPSink\n  [rdp-sink] Connected failed\n  ```\n  If it persists while audio is actively broken, look at the RDP client (`msrdc`) audio channel.\n\n- **Mostly-benign startup noise** (not a root cause on its own):\n  - `WSLGd: Exception: No such file or directory @FontMonitor.cpp:280` - font share not mounted.\n  - `XDG_RUNTIME_DIR \"/mnt/wslg/runtime-dir\" ... mode 040777` (should be 0700) - common warning.\n  - `dbus: Unknown username \"pulse\"` / `Option \"-listen\" is deprecated` - harmless.\n\n## When to escalate to the WSLg repo\n\nWSLg code is not in this repository. Fixes to weston, FreeRDP, pulseaudio, or the RDP backend\nbelong in https://github.com/microsoft/wslg. Use a commit-pinned permalink when referencing files\nthere so the link does not drift, e.g.\n`https://github.com/microsoft/wslg/blob/<commit-sha>/<path>`.\n",".github/copilot/localization-bugs.md":"## Creating Localization Tracking Bugs (GCS Azure DevOps)\n\nCommunity members report localization problems in two ways: by filing a GitHub **issue** about a bad\ntranslation, or by opening a **pull request** that edits a localized file (the per-locale UI strings in\n`localization/strings/<locale>/Resources.resw`, or the per-locale Intune/group-policy templates in\n`intune/<locale>/WSL.adml`), or that adds a brand-new locale file. Both are valid signals and you should\nlook for **both** when triaging.\n\nEither way, the fix is handled by the Microsoft Global Collaboration Service (GCS) localization pipeline,\n**not** merged directly from GitHub: every non-`en-US` localized file is generated by the GCS team and\nregenerated downstream, so any translation edit merged here would be overwritten. (PRs that touch\nlocalized files should be declined with a pointer to `CONTRIBUTING.md`; only the `en-US` sources and the\nlanguage-neutral `intune/WSL.admx` live in this repo.) To route a report for review, file a tracking\n**Bug** in the GCS Azure DevOps project for each issue or PR.\n\n> **GCS requirement — be specific: list the exact resource IDs to fix.** The loc team will **not**\n> triage abstract reports. A bug that only names the file, language, and a few quoted strings gets\n> rejected (moved to the **More Info** state) because the team does not have capacity to parse a vague\n> report into the concrete strings that need work — that translation has to be done up front by the\n> filer. Every bug must therefore carry an explicit list of the **resource IDs** (the `name` attribute\n> of the `<data name=\"...\">` elements in `localization/strings/<locale>/Resources.resw`) that need\n> fixing. The gold-standard level of detail is **Bug 1223866** (`.../GlobalCollaborationService/Global%20Collaboration%20Service%20Project/_workitems/edit/1223866`):\n> for each resource ID it gives the current (bad) value and the proposed value, e.g.\n>\n> ```text\n> MessageDistroAlreadySet\n>   current:  Der Verteilungsname wurde bereits festgelegt.\n>   proposed: Der Distributionsname wurde bereits festgelegt.\n> ```\n\n### Deriving the resource-ID list\n\nHow you obtain the IDs depends on the report type:\n\n- **PR editing an existing locale file** — the changed resource IDs are exactly the `<data name>`\n  blocks whose `<value>` differs between the repo's current file and the PR head. Load both and diff\n  by name. The PR \"Files changed\" view already shows current→proposed for each, so post the **compact\n  ID list plus a link to the PR diff** rather than re-inlining every value (a 160-row inline table is\n  unwieldy; the PR diff is the source of truth for the old/new text).\n\n  ```powershell\n  # changed resource IDs between two Resources.resw files (master vs PR head)\n  function Get-ChangedIds($baseResw, $headResw) {\n    function Load($p) { $x = [xml](Get-Content $p -Raw); $h = @{}; foreach ($d in $x.root.data) { $h[$d.name] = $d.value }; $h }\n    $b = Load $baseResw; $h = Load $headResw\n    $h.Keys | Where-Object { $b[$_] -ne $h[$_] }\n  }\n  ```\n\n- **Issue citing line numbers** (e.g. `Resources.resw#L185`) — fetch the file **at the exact commit\n  the issue links to**, then walk upward from each cited line to the nearest `data name=\"...\"` to get\n  the enclosing resource ID. Line numbers drift between commits, so always pin to the linked SHA.\n\n- **Issue quoting bad strings** — grep the locale `Resources.resw` for each quoted value to find the\n  `<data name>` that contains it. One displayed term often maps to several IDs (`.Header`,\n  `.Description`, `...TextBox.AutomationProperties.Name`/`.HelpText`, shell-nav `.Content`), so list\n  them all.\n\n- **PR adding a brand-new locale** — this is a net-new whole-file contribution, **not** a correction\n  list, so there is nothing pre-existing to \"fix\". Give the team the actionable file-level items\n  instead: (1) hard parity failures vs `en-US` that block `tools/devops/validate-localization.py` —\n  placeholder/insert-count mismatches and missing `{Locked=\"...\"}` tokens, listed by resource ID;\n  (2) the coverage gap (which `en-US` IDs are missing, and how many of N total); (3) any strings\n  present in the file but absent from `en-US` (obsolete — drop them); and (4) that a new locale needs\n  build registration, not just a file drop.\n\n### Coordinates\n\n| | |\n|---|---|\n| Org | `https://dev.azure.com/GlobalCollaborationService` |\n| Project | `Global Collaboration Service Project` |\n| Process | `GCS_Agile` |\n| Work item type | `Bug` |\n| Web \"create from template\" link | `https://dev.azure.com/GlobalCollaborationService/Global%20Collaboration%20Service%20Project/_workitems/create/Bug?templateId=b97df4d3-4106-4099-a3a9-1782b5891bec` |\n\n### Required fields (and known-good values for a community loc PR)\n\nThe Bug type has several required custom picklist fields. Values that work for \"community translation PR\nneeds review\":\n\n| Field (reference name) | Value |\n|---|---|\n| `System.Title` | `WSL: Review community <locale> localization report (GitHub #<issue or PR>)` |\n| `System.Description` / `Microsoft.VSTS.TCM.ReproSteps` | GitHub link + scope + action (see below) |\n| `Custom.IssueType` | `Incorrect Translation` |\n| `Custom.ProductArea` | `Software` |\n| `Custom.How_Found` | `Community` |\n| `Custom.Severity_Impact` | `S3 - Medium` (field default) |\n| `Microsoft.VSTS.Common.ValueArea` | `Business` (field default) |\n| `Custom.HaveyouattachedEnglishandlocalizedscreenshots` | `No` (allowed: `Yes`/`No`; no default — must be set) |\n| `Custom.Language` | picklist — see mapping below (the WSL locale code is **not** accepted) |\n\nOther required custom flags (`Custom.BugBlocked`, `Custom.XLanguage`,\n`Custom.OverrideMaxStringsThreshold`, `Custom.SkipSourceAudioFilesValidation`,\n`Custom.DidCopilotrespondinthesamelanguage`, `Custom.Copilotattachallfiles`) default to `0` and\nauto-fill; leave them unset.\n\n### `Custom.Language` mapping (picklist values, not locale codes)\n\n`Custom.Language` is a 148-value picklist keyed by display name. Map the WSL `Resources.resw` locale\nfolder to the picklist value:\n\n| WSL locale | `Custom.Language` value |\n|---|---|\n| `es-ES` | `Spanish (Spain, International Sort)` |\n| `zh-CN` | `Chinese (Simplified) - PRC` |\n| `el-GR` | `Greek (Greece)` |\n| `tr-TR` | `Turkish (Turkey)` |\n\nFor other locales, list the allowed values and match by display name:\n\n```powershell\n$org=\"https://dev.azure.com/GlobalCollaborationService\"\n$projEnc=\"Global%20Collaboration%20Service%20Project\"\n$res=\"499b84ac-1321-427f-aa17-267ca6975798\"   # Azure DevOps AAD resource id\naz rest --method get --resource $res `\n  --uri \"$org/$projEnc/_apis/wit/workitemtypes/Bug/fields/Custom.Language?`$expand=all\" `\n  --headers \"Accept=application/json;api-version=7.1-preview.3\" |\n  ConvertFrom-Json | Select-Object -ExpandProperty allowedValues\n```\n\n### Suggested description body\n\n```\nCommunity localization report on GitHub microsoft/WSL needs review by the loc pipeline.\n\nGitHub: https://github.com/microsoft/WSL/<issues or pull>/<number>\nLanguage: <locale>\nType: <issue reporting a bad translation | PR editing the localized file>\nScope: localized file (localization/strings/<locale>/Resources.resw or intune/<locale>/WSL.adml).\n  For a PR: <edits to existing | brand-new>, +A/-B, 1 file. For an issue: the specific string(s) reported.\nResource IDs to fix: <explicit list of <data name> keys - see the dedicated comment with the full\n  list, or paste it here>. This is required; see \"Deriving the resource-ID list\" above.\nAction: validate placeholder/locked-token parity vs en-US (tools/devops/validate-localization.py),\nthen incorporate or advise. New locales additionally need build registration, not just a file drop.\nNote: do not merge the GitHub PR - localized files are regenerated by GCS and edits here are overwritten.\n```\n\nThe resource-ID list is the part GCS actually needs. If it is long, post it as a work-item **comment**\n(ADO comments accept HTML and can be edited in place via `PATCH .../comments/<id>`) and reference that\ncomment from the description.\n\n### Creating via CLI (`az boards`)\n\nRequires the `azure-devops` az extension and an identity with **create/edit work item** permission in\nthe project (see caveat below).\n\n```powershell\n$org=\"https://dev.azure.com/GlobalCollaborationService\"\n$proj=\"Global Collaboration Service Project\"\n$area=\"Global Collaboration Service Project\\Global\\Windows\"   # working area path, see Permissions gotcha\n$desc=\"Community es-ES localization PR. PR: https://github.com/microsoft/WSL/pull/14109 ...\"\naz boards work-item create --org $org --project $proj --type \"Bug\" `\n  --title \"WSL: Review community es-ES localization PR (GitHub #14109)\" `\n  --area \"$area\" --description $desc `\n  --fields \"Microsoft.VSTS.TCM.ReproSteps=$desc\" `\n           \"Custom.Language=Spanish (Spain, International Sort)\" `\n           \"Custom.IssueType=Incorrect Translation\" `\n           \"Custom.ProductArea=Software\" `\n           \"Custom.How_Found=Community\" `\n           \"Custom.Severity_Impact=S3 - Medium\" `\n           \"Microsoft.VSTS.Common.ValueArea=Business\" `\n           \"Custom.HaveyouattachedEnglishandlocalizedscreenshots=No\"\n```\n\n### Gotchas\n\n- **`az.cmd` eats `&` in URLs.** When using `az rest`, never put `&` (multiple query params) in\n  `--uri` on Windows — cmd truncates the URL there. Pass `api-version` via the **Accept header**\n  instead: `--headers \"Accept=application/json;api-version=7.1\"`, keeping at most one `?param` in the URI.\n- **Permissions are area-path-scoped, and the path matters.** Creating work items requires explicit rights on\n  the *specific area path*, not the project as a whole. The correct, durable path for WSL localization bugs is\n  `Global Collaboration Service Project\\Global\\Windows` (confirmed against existing manually-filed WSL loc\n  bugs). Always set `System.AreaPath` (or `--area`) to that path. A `@ntdev.microsoft.com` identity is denied\n  at the project root and most other paths (`TF237111: ... does not have permissions to save work items under\n  the specified area path`). Do NOT file under `...\\C and AI\\Unspecified`: an identity may briefly appear to\n  have access there, but bugs filed there get cleaned up and the access is not stable. To probe a path without\n  creating anything, POST with `?validateOnly=true`. If your identity lacks rights everywhere, create the bug\n  through the web template link above.\n- **`System.Description` is required, separately from repro steps.** The Bug type rejects a create with\n  `TF401320: Rule Error for field Description ... Required, InvalidEmpty` unless `System.Description` is set.\n  Set both `System.Description` and `Microsoft.VSTS.TCM.ReproSteps` (the same body is fine). When POSTing a\n  JSON-patch document via `az rest`, use newline-to-`<br>` so the HTML-rendered fields keep their line breaks.\n- **Picklist discovery.** Field allowed-values often don't expand through the plain field endpoint; use\n  `?$expand=all` on `.../workitemtypes/Bug/fields/<ref>` as shown above.\n- **\"Not found\" can mean \"no access,\" not \"doesn't exist.\"** WIQL and `GET .../workitems/<id>` honor ACLs:\n  a `CreatedBy=@me` query returning zero rows, or `TF401232: Work item <id> does not exist, or you do not\n  have permissions to read it`, often just means your identity can't read that area path. Don't assume the\n  bug was deleted. A gap in sequential work-item IDs is a tell that items were created but are now invisible\n  to you (e.g. filed under a path whose access got revoked, then reaped) - which is exactly why you should\n  stick to the durable `Global\\Windows` path above.\n- **Read the bug back after creating it.** Immediately `GET` each new work item id (or open the URL) to\n  confirm it's actually persisted and readable under your identity. A create that \"succeeds\" against a flaky\n  area path can vanish later; a read-back catches that while you can still re-file.\n- **Non-ASCII gets mangled, and `az` errors poison `ConvertFrom-Json`.** Locale content (Turkish, Greek, CJK)\n  comes back cp1252-garbled unless you set `[Console]::OutputEncoding=[System.Text.Encoding]::UTF8` first.\n  Also, `az` prints errors to the stream, so piping straight into `ConvertFrom-Json` throws on any failure;\n  capture with `Out-String` and parse, or check `$LASTEXITCODE`. Pass JSON-patch bodies via `--body \"@file\"`\n  (content type `application/json-patch+json`) rather than inline to dodge quoting hell.\n- **Don't inline huge diffs into a comment.** For a PR that touches many strings, post the resource-ID\n  list and link the PR \"Files changed\" page for the current→proposed values; a 100+ row HTML table\n  makes the bug unreadable and can bump against comment-size limits. ADO comments can be edited in\n  place (`PATCH .../comments/<id>?api-version=7.1-preview.4`), so trim/replace rather than re-posting.\n\n### After creating\n\nKeep the GitHub link in the ADO Bug's description/repro steps (it's already there from the body above) so the\nloc team can trace back to the report. Do **not** paste the internal ADO Bug ID into the public GitHub PR or\nissue. Then read each new bug back (see gotcha above) to confirm it persisted under `Global\\Windows`.\n\nIf GCS moves a bug to **More Info**, it almost always means the resource-ID detail is missing or too\nabstract: supply the explicit `<data name>` list (see \"Deriving the resource-ID list\"), then move the\nbug back to **Active** and reassign it to the requesting GCS reviewer.\n\n### What happens after you file (automated pipeline)\n\nFiling the Bug under `Global\\Windows` is usually the end of the manual work. A **Fabric Self Service** bot\n(`FabricClient-Prod`) automatically picks the Bug up and creates a **DTT (Direct-To-Translator) job** for the\nlocale, posting its progress as Bug discussion comments. So a stream of `FabricClient-Prod` comments is the\n**expected, healthy** path — not something a human has to act on:\n\n- `Bug picked up for processing by the Fabric Self Service process.`\n- `Successfully created 1 DTT Jobs: ... <locale> ...` → the report is now in the translation pipeline; **no\n  further action**.\n\nWatch for these exceptions, which **do** need action:\n\n- **New locale not onboarded.** If the locale isn't onboarded to **TDBuild** for the WSL subtenant\n  (`WindowsUndocking` / `LiftedWSL`), the DTT job can't be created and a human comments pointing you to file an\n  onboarding request at the **Global Services Hub** (`https://globalservices.powerappsportals.com/global/`).\n  This is GCS-side onboarding and is *separate from* (and in addition to) the WSL-repo build registration a new\n  locale needs. Greek (`el-GR`, GitHub #40244) hit exactly this.\n- **Oversized report.** A non-retriable `Rqf query exceeded threshold of 1000 words` failure means the report's\n  scope is too large; reduce the scope or set `Custom.OverrideMaxStringsThreshold` and re-file.\n\nIf you only see `FabricClient-Prod` \"Successfully created ... DTT Jobs\" comments, you're done.\n",".github/copilot-instructions.md":"# Windows Subsystem for Linux (WSL)\n\n**ALWAYS reference these instructions first and fallback to search or bash commands only when you encounter unexpected information that does not match the info here.**\n\nWSL is the Windows Subsystem for Linux - a compatibility layer for running Linux binary executables natively on Windows. This repository contains the core Windows components that enable WSL functionality.\n\n## Coding Conventions\n\n### Naming\n\n- **Classes/Structs**: `PascalCase` (e.g., `ConsoleProgressBar`, `DeviceHostProxy`)\n- **Functions/Methods**: `PascalCase()` (e.g., `GetFamilyName()`, `MultiByteToWide()`)\n- **Member variables**: `m_camelCase` (e.g., `m_isOutputConsole`, `m_outputHandle`)\n- **Local variables**: `camelCase` (e.g., `distroGuidString`, `asyncResponse`)\n- **Constants**: `c_camelCase` with `constexpr` (e.g., `constexpr size_t c_progressBarWidth = 58;`)\n- **Namespaces**: lowercase with `::` nesting (e.g., `wsl::windows::common::registry`)\n- **Enums**: `PascalCaseValue` (e.g., `LxssDistributionStateInstalled`)\n- **Windows types**: Keep as-is (`LPCWSTR`, `HRESULT`, `DWORD`, `ULONG`, `GUID`)\n\n### Error Handling\n\nUse WIL (Windows Implementation Libraries) macros — **never** bare `if (FAILED(hr))`:\n- `THROW_IF_FAILED(hr)` — throw on HRESULT failure\n- `THROW_HR_IF(hr, condition)` — conditional throw\n- `THROW_HR_IF_MSG(hr, condition, fmt, ...)` — conditional throw with message\n- `THROW_IF_NULL_ALLOC(ptr)` — throw on null allocation\n- `THROW_LAST_ERROR_IF(condition)` — throw last Win32 error\n- `RETURN_IF_FAILED(hr)` — return HRESULT on failure (no throw)\n- `RETURN_LAST_ERROR_IF_EXPECTED(condition)` — expected failure path\n- `LOG_IF_FAILED(hr)` — log but don't throw\n- `CATCH_LOG()` — catch and log exceptions\n\nFor user-facing errors, set a localized message before throwing:\n```cpp\nTHROW_HR_WITH_USER_ERROR(E_INVALIDARG, Localization::MessageConfigInvalidBoolean(name, value));\n```\n\nAt API boundaries (COM interfaces), return `HRESULT` with out params. Internal code throws exceptions.\n\n### Memory Management and RAII\n\nUse WIL smart pointers — **never** raw `CloseHandle()` or manual cleanup:\n- `wil::unique_handle` — kernel handles\n- `wil::com_ptr<T>` — COM objects\n- `wil::unique_hfile` — file handles\n- `wil::unique_hkey` — registry keys\n- `wil::unique_event` — events\n- `wil::unique_hlocal_string` — HLOCAL strings\n- `wil::unique_cotaskmem_string` — CoTaskMem strings\n\nFor non-standard resource types, use `wil::unique_any<Type, Deleter, Fn>`.\n\nFor cleanup scopes, use `wil::scope_exit`:\n```cpp\nauto cleanup = wil::scope_exit([&] { registry::DeleteKey(LxssKey, guid.c_str()); });\n// ... work ...\ncleanup.release(); // dismiss on success\n```\n\n### Synchronization\n\nUse `wil::srwlock` (Slim Reader/Writer locks) with SAL annotations:\n```cpp\nmutable wil::srwlock m_lock;\n_Guarded_by_(m_lock) std::vector<Entry> m_entries;\n```\n\n### Strings\n\n- `std::wstring` / `std::wstring_view` are dominant throughout the codebase\n- Use `MultiByteToWide()` / `WideToMultiByte()` from `stringshared.h` for conversions\n- Use `std::format()` for formatting (the repo defines `std::formatter<std::wstring, char>` for wide-to-narrow support)\n- The `STRING_TO_WIDE_STRING()` macro handles compile-time conversion\n\n### Copy/Move Semantics\n\nUse macros from `defs.h` to declare copy/move behavior:\n```cpp\nNON_COPYABLE(MyClass);\nNON_MOVABLE(MyClass);\nDEFAULT_MOVABLE(MyClass);\n```\n\n### Headers\n\n- Use `#pragma once` (no traditional `#ifndef` include guards)\n- In Windows C++ components, every `.cpp` file must start with `#include \"precomp.h\"`\n- Linux-side code (`src/linux/`) does not use precompiled headers\n- Use `.h` for C-compatible headers, `.hpp` for C++-only headers\n- Include order is enforced by `.clang-format` (precomp first, then system, then project)\n\n### Copyright Headers\n\nUse this single-line format for new files:\n```cpp\n// Copyright (C) Microsoft Corporation. All rights reserved.\n```\n\nSome older files use the block format (`/*++ Copyright (c) Microsoft. All rights reserved. ... --*/`). Match the surrounding files in the same directory when editing.\n\n### Localization\n\n- Use `wsl::shared::Localization::MessageXxx()` static methods for user-facing strings\n- Use `EMIT_USER_WARNING(Localization::MessageXxx(...))` for non-fatal config warnings\n- All new user-facing strings must have entries in `localization/strings/en-US/Resources.resw`\n- In Resources.resw comments, use `{Locked=\"...\"}` to prevent translation of `.wslconfig` property key names\n- Localized files are generated by a separate localization team and regenerated downstream, so translation edits in a GitHub PR cannot be merged (they would be overwritten). This covers the per-locale `localization/strings/<locale>/Resources.resw` UI strings and the per-locale `intune/<locale>/WSL.adml` policy templates (anything other than the `en-US` sources and the neutral `intune/WSL.admx`). Filing a GitHub issue is the correct path for contributors; see `CONTRIBUTING.md`. Ignore this guidance for automated localization-service PRs that are generated by that pipeline.\n- Community localization reports come in as **both GitHub issues and pull requests** - when triaging, look for both and file a tracking Bug for each. These are tracked via Bugs in the GCS Azure DevOps project, not merged directly. See `.github/copilot/localization-bugs.md` for the project coordinates, required fields, and `az boards` workflow.\n\n### Telemetry and Logging\n\n- `WSL_LOG(Name, ...)` — standard trace event\n- `WSL_LOG_DEBUG(Name, ...)` — debug-only (compiled out in release via `if constexpr`)\n- `WSL_LOG_TELEMETRY(Name, Tag, ...)` — metrics with privacy tag and version info\n- Provider: `g_hTraceLoggingProvider`, initialized via `WslTraceLoggingInitialize()`\n\n### Platform Conditionals\n\nPrefer `constexpr` checks over `#ifdef` where possible:\n```cpp\nif constexpr (wsl::shared::Debug) { /* debug-only code */ }\nif constexpr (wsl::shared::Arm64) { /* ARM64-specific code */ }\n```\n\nFor compiler-specific code, use `#ifdef _MSC_VER` (Windows) / `#ifdef __GNUC__` (Linux).\n\n### Formatting\n\nEnforced by `.clang-format`:\n- 130 character column limit\n- 4-space indentation, no tabs\n- Allman-style braces (opening brace on new line for classes, functions, structs, control statements)\n- Left-aligned pointers (`int* ptr`, not `int *ptr`)\n- `InsertBraces: true` — all control statements must have braces\n\n### IDL / COM Conventions\n\nWhen modifying service interfaces (`src/windows/service/inc/`):\n- Interface attributes on separate lines: `[uuid(...), pointer_default(unique), object]`\n- String params: `[in, unique] LPCWSTR` with `[string]` for marshaled strings\n- Handle params: `[in, system_handle(sh_file)] HANDLE`\n- User-facing errors: pass `[in, out] LXSS_ERROR_INFO* Error`\n- **ABI stability applies only to SDK-facing and public surfaces.** `WSLCCompat.idl` (the WSLC SDK-facing layer) and the public plugin API (`WslPluginApi.h`) must stay backward compatible: do not add, remove, or reorder methods on their existing interfaces, and do not change struct layouts. Introduce a new versioned interface with a new IID instead. Every other interface (`IWSLCSession` in `wslc.idl`, the interfaces in `wslservice.idl`, etc.) is internal and non-stable: rebuilt and shipped in lockstep with its only clients, so appending new methods to those is fine.\n- Custom error codes: `WSL_E_xxx` via `MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, WSL_E_BASE + N)`\n\n### Config File (.wslconfig) Conventions\n\nWhen adding settings to `src/shared/configfile/`:\n- Format is `.gitconfig`-style INI: `[section]`, `key = value`, `#` comments, `\\` line continuation\n- Use the `ConfigKey` template class for type-safe parsing\n- Supported types: `bool`, `int` (hex/octal), `std::string`, `std::wstring`, `MemoryString`, `MacAddress`, enum maps\n- Report invalid values with `EMIT_USER_WARNING(Localization::MessageConfigXxx(...))`\n- New settings require a corresponding localization string in Resources.resw\n\n## Architecture\n\n- `wsl.exe` is a thin entry point into `src/windows/common/WslClient.cpp`. Client commands reach the SYSTEM `wslservice.exe` through the internal COM interfaces in `src/windows/service/inc/wslservice.idl`; `LxssUserSession` owns per-user distribution operations.\n- For WSL2, the service creates/manages the VM through HCS in `WslCoreVm.cpp` and communicates over hvsockets with Linux `mini_init`. `mini_init` configures the VM, starts `gns` for networking, and launches a per-distribution `init`; the service's `WslCoreInstance` talks to that `init` to launch sessions. The session leader launches a relay and the requested Linux process; Windows client I/O is relayed over hvsockets. Shared wire messages live in `src/shared/inc/lxinitshared.h` and use `SocketChannel`.\n- `src/windows/wslc/` contains the container CLI, `src/windows/wslcsession/` the container session process, and the service hosts its session manager; their internal interface is `wslc.idl`. The SDK-facing compatibility contract is separate (`WSLCCompat.idl`). See `doc/docs/technical-documentation/index.md` and `boot-process.md` for the process and boot diagrams.\n\n## Repository Navigation\n\n### Key Directories\n- `src/windows/` — Main Windows WSL service components\n- `src/linux/` — Linux-side WSL components\n- `src/shared/` — Shared code between Windows and Linux\n- `test/windows/` — Windows-based tests (TAEF framework): `common/`, `wsl/`, `wslc/`, `testplugin/`\n- `test/linux/unit_tests/` — Linux unit test suite\n- `doc/` — Documentation source (MkDocs)\n- `tools/` — Build and deployment scripts\n- `distributions/` — Distribution validation and metadata\n- `localization/` — Localized string resources\n\n### Namespace → Directory Map\n\n| Namespace | Location |\n|---|---|\n| `wsl::shared::` | `src/shared/` |\n| `wsl::windows::common::` | `src/windows/common/` |\n| `wsl::windows::service::` | `src/windows/service/exe/` |\n| `wsl::core::` | `src/windows/service/exe/` |\n| `wsl::core::networking::` | `src/windows/common/` + `src/windows/service/exe/` |\n| `wsl::linux::` | `src/linux/init/` |\n\n### Key Files\n- `src/shared/inc/defs.h` — Shared platform definitions (NON_COPYABLE, Debug, Arm64, etc.)\n- `src/shared/inc/stringshared.h` — String conversion utilities\n- `src/windows/common/WslTelemetry.h` — Telemetry macros\n- `src/windows/common/ExecutionContext.h` — Error context and user-facing error macros\n- `src/windows/service/inc/wslservice.idl` — Main service COM interface definitions\n- `src/windows/service/inc/wslc.idl` — Container COM interface definitions\n- `src/windows/inc/WslPluginApi.h` — Plugin API header\n- `src/shared/configfile/configfile.h` — Config file parser\n- `.clang-format` — Code formatting rules (130 col, 4-space indent, Allman braces)\n\n## Building and Deploying\n\n### Critical Platform Requirements\n- **Full builds ONLY work on Windows** with Visual Studio and Windows SDK 26100\n- **DO NOT attempt to build the main WSL components on Linux** — they require Windows-specific APIs, MSBuild, and Visual Studio toolchain\n- Many validation and development tasks CAN be performed on Linux (documentation, formatting, Python validation scripts)\n\n### Windows Build Requirements\n- CMake >= 3.25 (`winget install Kitware.CMake`)\n- Visual Studio with these components:\n  - Windows SDK 26100\n  - MSBuild\n  - Universal Windows platform support for v143 build tools (X64 and ARM64)\n  - MSVC v143 - VS 2022 C++ ARM64 build tools (Latest + Spectre) (X64 and ARM64)\n  - C++ core features\n  - C++ ATL for latest v143 tools (X64 and ARM64)\n  - C++ Clang compiler for Windows\n  - .NET desktop development\n  - .NET WinUI app development tools\n- Enable Developer Mode in Windows Settings OR run with Administrator privileges (required for symbolic link support)\n\n### Building WSL (Windows Only)\n1. Install prerequisites with `tools\\setup-dev-env.ps1` (or follow `doc/docs/dev-loop.md` and `.vsconfig`)\n2. Generate Visual Studio solution: `cmake .`\n3. Build: `cmake --build . -- -m` OR open `wsl.sln` in Visual Studio\n\nBuild parameters:\n- `cmake . -A arm64` — Build for ARM64\n- `cmake . -DCMAKE_BUILD_TYPE=Release` — Release build\n- `cmake . -DBUILD_BUNDLE=TRUE` — Build bundle MSIX package (requires ARM64 built first)\n\n### Deploying WSL (Windows Only)\n- Install MSI: `bin\\<platform>\\<target>\\wsl.msi`\n- OR use script: `powershell tools\\deploy\\deploy-to-host.ps1`\n- For Hyper-V VM: `powershell tools\\deploy\\deploy-to-vm.ps1 -VmName <vm> -Username <user> -Password <pass>`\n\n## Testing\n\n### Writing Tests (TAEF Framework)\n\nTests use TAEF. See `.github/copilot/test.md` for detailed patterns and macros.\n\nKey points:\n- Use `WSL_TEST_CLASS(Name)` — not raw `BEGIN_TEST_CLASS`\n- Use `VERIFY_*` macros for assertions (`VERIFY_ARE_EQUAL`, `VERIFY_IS_TRUE`, etc.)\n- Skip macros: `WSL1_TEST_ONLY()`, `WSL2_TEST_ONLY()`, `SKIP_TEST_ARM64()`\n- Test infrastructure is in `test/windows/common/Common.h` (include it as `\"Common.h\"`)\n- Test layout under `test/windows/`:\n  - `common/` — shared fixtures and helpers, plus unit tests for `src/windows/common`\n  - `wsl/` — WSL tests\n  - `wslc/` — WSLC tests\n  - `testplugin/` — test plugin used by the plugin tests\n\n### Running Tests (Windows Only)\n\n**CRITICAL: ALWAYS build the ENTIRE project before running tests:**\n```powershell\ncmake --build . -- -m\nbin\\<platform>\\<target>\\test.bat\n```\n\n**Why full build is required:**\n- Tests depend on multiple components (libwsl.dll, wsltests.dll, wslservice.exe, etc.)\n- Partial builds will cause test failures\n- **DO NOT skip the full build step even if only one file changed**\n\nTest execution:\n- Run all tests: `bin\\<platform>\\<target>\\test.bat`\n- Run subset: `bin\\<platform>\\<target>\\test.bat /name:*UnitTest*`\n- Run specific test: `bin\\<platform>\\<target>\\test.bat /name:<class>::<test>` (for example, `bin\\x64\\debug\\test.bat /name:UnitTests::UnitTests::ModernInstall`)\n- WSL1 tests: Add `-Version 1` flag\n- Fast mode (after first run): Add `-f` flag (requires `wsl --set-default test_distro`)\n- **Requires Administrator privileges**\n\nTest debugging:\n- Attach WinDbgX automatically: `/attachdebugger`\n- Wait for debugger (manual attach): `/waitfordebugger`\n- Break on failure: `/breakonfailure`\n- Run in-process: `/inproc`\n\n### Linux Unit Tests (Linux Only)\n- Location: `test/linux/unit_tests/`\n- Build script: `test/linux/unit_tests/build_tests.sh`\n- **Note**: Requires specific Linux build environment setup not covered in main build process\n\n## Cross-Platform Validation Tasks\n\n### Documentation (Works on Linux/Windows)\n- Install tools: `pip install mkdocs-mermaid2-plugin mkdocs --break-system-packages`\n- Build docs: `mkdocs build -f doc/mkdocs.yml`\n- Output location: `doc/site/`\n- **Note**: May show warnings about mermaid CDN access on restricted networks\n\n### Code Formatting and Validation\n- Format modified source (Windows, requires `cmake .` first): `.\\FormatSource.ps1`\n- Format all source: `.\\FormatSource.ps1 -ModifiedOnly $false`; format/check files touched by the branch: `.\\FormatSource.ps1 -Branch` / `.\\FormatSource.ps1 -Branch -Verify $true` (defaults to local `master`; use `-BaseBranch` if needed)\n- Format check (Linux/cross-platform): `clang-format --dry-run --style=file <files>`\n- Validate copyright headers: `python3 tools/devops/validate-copyright-headers.py`\n  - **Note**: Will report missing headers in generated/dependency files (`_deps/`), which is expected\n- Validate localization: `python3 tools/devops/validate-localization.py`\n  - **Note**: Only works after Windows build (requires `localization/strings/en-US/Resources.resw`)\n\n### Distribution Validation (Limited on Linux)\n- Validate distribution info: `python3 distributions/validate.py distributions/DistributionInfo.json`\n- **Note**: May fail on Linux due to network restrictions accessing distribution URLs\n\n### Pre-commit Checklist\nAlways run before committing:\n1. `.\\FormatSource.ps1 -Verify $true` to check formatting on changed C++ files\n2. `python3 tools/devops/validate-copyright-headers.py` (ignore `_deps/` warnings)\n3. `mkdocs build -f doc/mkdocs.yml` if documentation changed\n4. Full Windows build if core components changed\n\n**Note**: The `.gitignore` properly excludes build artifacts (`*.sln`, `*.dll`, `*.pdb`, `obj/`, `bin/`, etc.) — do not commit these files.\n\n## Frequently Used Commands\n\n### Windows Development\n```powershell\n# Initial setup\ncmake .\ncmake --build . -- -m\n\n# Deploy and test\npowershell tools\\deploy\\deploy-to-host.ps1\nwsl --version\n\n# Run tests\nbin\\x64\\debug\\test.bat\n```\n\n### Cross-Platform Validation\n```powershell\n# Documentation\nmkdocs build -f doc/mkdocs.yml\n\n# Code formatting (Windows)\n.\\FormatSource.ps1\n\n# Copyright header validation (reports expected issues in _deps/)\npython3 tools/devops/validate-copyright-headers.py\n\n# Distribution validation (may fail on networks without external access)\npython3 distributions/validate.py distributions/DistributionInfo.json\n```\n\n## Debugging and Logging\n\n### ETL Tracing (Windows Only)\n```powershell\n# Collect traces\nwpr -start diagnostics\\wsl.wprp -filemode\n# [reproduce issue]\nwpr -stop logs.ETL\n\n# Available profiles:\n# - WSL (default) - General WSL tracing\n# - WSL-Storage - Enhanced storage tracing\n# - WSL-Networking - Comprehensive networking tracing\n# - WSL-HvSocket - HvSocket-specific tracing\n# Example: wpr -start diagnostics\\wsl.wprp!WSL -filemode\n```\n\n### Log Analysis Tools\n- Use WPA (Windows Performance Analyzer) for ETL traces\n- Key providers: `Microsoft.Windows.Lxss.Manager`, `Microsoft.Windows.Subsystem.Lxss`\n- For graphical/audio (WSLg) issues, see `.github/copilot/wslg-logs.md`. `collect-wsl-logs.ps1` gathers WSLg logs (`/mnt/wslg`: weston.log, pulseaudio.log, wlog.log, stderr.log, versions.txt) into a `wslg/` folder using `wsl.exe --system --user root`; crash dumps (`%TEMP%\\wsl-crashes`, legacy `/mnt/wslg/dumps`) are only collected with `-Dump`. WSLg code lives in https://github.com/microsoft/wslg, not this repo.\n\n### Debug Console (Linux)\nAdd to `%USERPROFILE%\\.wslconfig`:\n```ini\n[wsl2]\ndebugConsole=true\n```\n\n### Common Debugging Commands\n- Debug shell: `wsl --debug-shell`\n- Collect WSL logs: `powershell diagnostics\\collect-wsl-logs.ps1`\n- Network logs: `powershell diagnostics\\collect-wsl-logs.ps1 -LogProfile networking`\n\n## Timing and Timeout Guidelines\n\n**NEVER CANCEL these operations — always wait for completion:**\n\n| Operation | Typical Duration | Minimum Timeout |\n|---|---|---|\n| Full Windows build | 20-45 minutes | 60+ minutes |\n| Full test suite | 30-60 minutes | 90+ minutes |\n| Unit test subset | 5-15 minutes | 30+ minutes |\n| Documentation build | ~0.5 seconds | 5+ minutes |\n| Distribution validation | 2-5 minutes | 15+ minutes |\n\n## CI/CD Integration\n\n### GitHub Actions\n- **distributions.yml** — Validates distribution metadata (Linux)\n- **documentation.yml** — Builds and deploys docs (Linux)\n- **modern-distributions.yml** — Tests modern distribution support\n\n## Development Environment Setup\n\n### Windows (Full Development)\n1. Install Visual Studio with required components (listed above)\n2. Install CMake 3.25+\n3. Enable Developer Mode\n4. Clone repository\n5. Run `cmake .` to generate solution\n\n### Linux (Documentation/Validation Only)\n1. Install Python 3.8+\n2. Install docs tools: `pip install mkdocs-mermaid2-plugin mkdocs`\n3. Clone repository\n4. Run validation commands as needed\n\nRemember: **This is a Windows-focused project**. While some tasks can be performed on Linux, full WSL development requires Windows with Visual Studio."},"files":{".github/copilot/review.md":"## Code Review Guidelines for WSL\n\nWhen reviewing code, enforce the conventions in `.github/copilot-instructions.md`. Focus especially on these high-risk areas:\n\n### ABI Safety (Critical)\nOnly the SDK-facing and public surfaces require a backward-compatible ABI. Every other COM interface (`wslc.idl`, `wslservice.idl`, etc.) is internal and non-stable: shipped in lockstep with its only clients, with the proxy/stub regenerated each build, so methods may be appended to those freely. Do **not** flag internal, non-stable interfaces.\n- **Flag** ABI-breaking changes (new, removed, or reordered methods, changed struct layouts) only in the stable surfaces: `WSLCCompat.idl` (the WSLC SDK-facing layer, which must stay backward compatible) and the public plugin API (`WSLPluginHooksV1` / `WSLPluginAPIV1` structs in `WslPluginApi.h`).\n- **Do not flag** new methods appended to internal, non-stable interfaces such as `IWSLCSession` in `wslc.idl`, or interfaces in `wslservice.idl`.\n\n### Resource Safety\n- **Flag** raw `CloseHandle()`, `delete`, `free()`, or manual resource cleanup — require WIL smart pointers\n- **Flag** missing `NON_COPYABLE()` / `NON_MOVABLE()` on classes that hold resources\n- **Flag** lock usage without `_Guarded_by_()` SAL annotations\n\n### User-Facing Changes\n- **Flag** hardcoded English strings — require `Localization::MessageXxx()` and Resources.resw entry\n- **Flag** new `.wslconfig` settings without corresponding Resources.resw localization string\n- **Flag** silent fallback on invalid config values — require `EMIT_USER_WARNING()`\n\n### Error Handling\n- **Flag** bare `if (FAILED(hr))` — require WIL macros\n- **Flag** silently swallowed errors — require `CATCH_LOG()` or `LOG_IF_FAILED()`\n- **Flag** telemetry events missing privacy data tags\n",".github/copilot/test.md":"## Test Generation Guidelines for WSL\n\nWhen generating tests for this repository, follow these patterns:\n\n### Framework\nTests use TAEF (Test Authoring and Execution Framework). Always include `\"Common.h\"`.\n\n### Test Class Structure\n```cpp\n#include \"Common.h\"\n\nnamespace MyFeatureTests\n{\nclass MyFeatureTests\n{\n    WSL_TEST_CLASS(MyFeatureTests)\n\n    TEST_CLASS_SETUP(TestClassSetup)\n    {\n        VERIFY_ARE_EQUAL(LxsstuInitialize(FALSE), TRUE);\n        return true;\n    }\n\n    TEST_CLASS_CLEANUP(TestClassCleanup)\n    {\n        LxsstuUninitialize(FALSE);\n        return true;\n    }\n\n    TEST_METHOD(DescriptiveTestName)\n    {\n        // Test implementation\n    }\n};\n}\n```\n\n### Key Rules\n- Use `WSL_TEST_CLASS(Name)` — never raw `BEGIN_TEST_CLASS`\n- Setup/cleanup methods must `return true` on success\n- Use `VERIFY_*` macros for assertions — never `assert()` or exceptions for test validation\n\n### Assertion Macros\n- `VERIFY_ARE_EQUAL(expected, actual)` — value equality\n- `VERIFY_ARE_NOT_EQUAL(a, b)` — value inequality\n- `VERIFY_IS_TRUE(condition)` — boolean check\n- `VERIFY_IS_FALSE(condition)` — negative boolean check\n- `VERIFY_IS_NULL(ptr)` — null check\n- `VERIFY_IS_NOT_NULL(ptr)` — non-null check\n- `VERIFY_WIN32_BOOL_SUCCEEDED(expr)` — Win32 BOOL result\n- `VERIFY_SUCCEEDED(hr)` — HRESULT success\n\n### Logging in Tests\n- `LogInfo(fmt, ...)` — informational messages\n- `LogError(fmt, ...)` — error messages\n- `LogWarning(fmt, ...)` — warnings\n- `LogPass(fmt, ...)` — explicit pass messages\n- `LogSkipped(fmt, ...)` — skip messages\n\n### Conditional Skipping\nAdd skip macros at the start of a test method body when the test only applies to certain environments:\n```cpp\nTEST_METHOD(Wsl2SpecificTest)\n{\n    WSL2_TEST_ONLY();\n    // ... test code ...\n}\n```\n\nAvailable skip macros:\n- `WSL1_TEST_ONLY()` — skip unless WSL1\n- `WSL2_TEST_ONLY()` — skip unless WSL2\n- `SKIP_TEST_ARM64()` — skip on ARM64\n- `SKIP_TEST_UNSTABLE()` — skip known-flaky tests\n- `WINDOWS_11_TEST_ONLY()` — skip on pre-Windows 11\n- `WSL_TEST_VERSION_REQUIRED(version)` — skip if WSL version too old\n\n### RAII Test Helpers\n- `WslKeepAlive` — prevents UVM timeout during long-running tests; create at test start\n- `WslConfigChange` — RAII wrapper that applies a temporary `.wslconfig` and restores the original on destruction:\n```cpp\nTEST_METHOD(TestWithCustomConfig)\n{\n    WslConfigChange config(L\"[wsl2]\\nmemory=4GB\\n\");\n    // ... test with custom config ...\n    // Original .wslconfig restored when config goes out of scope\n}\n```\n\n### Memory in Tests\n- Use `ALLOC(size)` / `FREE(ptr)` macros for direct heap allocation in tests\n- Prefer RAII wrappers and smart pointers for production-like code paths\n\n### Test Naming\n- Use descriptive PascalCase names that describe the scenario: `CreateInstanceWithInvalidGuidFails`, `EchoTest`, `MountPlan9Share`\n- Group related tests in the same test class\n",".github/copilot/commit.md":"## Commit Message Guidelines for WSL\n\nThis repo has no strict commit message format. Follow these general practices:\n\n- Write a concise summary under 72 characters\n- Use imperative mood (\"Fix crash\" not \"Fixed crash\")\n- Reference GitHub issues with `(#123)` or `Fixes #123`\n- Add a body paragraph for non-obvious changes explaining *why*\n",".github/copilot/wslg-logs.md":"# Analyzing WSLg logs\n\nWSLg is the component that runs graphical (GUI) and audio Linux applications on WSL. Its\nsource lives in a separate repository: https://github.com/microsoft/wslg. The canonical list\nof diagnostics to request for a WSLg bug is the WSLg repo bug report template\n(`.github/ISSUE_TEMPLATE/bug_report.yml` in microsoft/wslg).\n\n`diagnostics/collect-wsl-logs.ps1` collects the logs into a `wslg/` subfolder of the log archive\n(via `wsl.exe --system --user root`, with a timeout so a wedged service can't hang collection), so a\nstandard WSL log collection already contains the log files below. Crash dumps (`dumps/`,\n`wsl-crashes/`) are only collected when the script is run with `-Dump`.\n\n## Architecture (just enough to read the logs)\n\nWSLg runs a **system distro** (a small Azure Linux VM, separate from the user distro) that hosts:\n- **weston** (Wayland compositor) with the `rdp-backend.so` / `rdprail-shell.so` modules\n- **Xwayland** for X11 apps\n- **pulseaudio** with an RDP sink/source for audio\n- **FreeRDP** to stream the surfaces over an hvsocket to the Windows RDP client (`msrdc.exe`)\n\n`weston.log` and `wlog.log` are written by weston/FreeRDP, `pulseaudio.log` by pulseaudio, and\n`stderr.log` is the combined stderr of `WSLGd` and the processes it launches.\n\n## Files (in the `wslg/` folder, sourced from `/mnt/wslg`)\n\n| File | Contents |\n|---|---|\n| `versions.txt` | WSLg version, architecture, build date, component git hashes (weston, FreeRDP, mesa, pulseaudio) |\n| `weston.log` | Weston compositor + RDP backend log |\n| `wlog.log` | FreeRDP (WLog) log |\n| `pulseaudio.log` | PulseAudio log |\n| `stderr.log` | `WSLGd` and child-process stderr |\n| `dumps/` | Legacy WSLg crash dumps (older builds only; collected with `-Dump`) |\n| `wsl-crashes/` | Host-side WSLg crash dumps copied from `%TEMP%\\wsl-crashes` (newer builds, e.g. `core.weston`; collected with `-Dump`) |\n\n## Reading tips and common signatures\n\n- **`weston.log` is truncated on every boot.** Weston is started with `--log=/mnt/wslg/weston.log`\n  and opens it truncating, so the file only ever contains the **latest** system-distro boot. To\n  tell whether weston restarted, compare the boot timestamp on the first line (`weston 9.0.0 ...`)\n  across snapshots, or correlate with `dmesg`.\n\n- **System distro cycling / teardown.** In `dmesg` (collected via the ETL `GuestLog` events or\n  the debug console), this pair means the WSLg system distro's `init` exited and the distro was\n  torn down (idle timeout or shutdown), which also restarts weston:\n  ```\n  Exception: Operation canceled @p9io.cpp:258 (AcceptAsync)\n  WSL (1 - init()) ERROR: InitEntryUtilityVm:2551: Init has exited. Terminating distribution\n  ```\n  Repeating every ~25-60s with no GUI client attached is usually normal idle teardown, not a crash.\n  A genuine weston crash instead leaves a core dump in `wsl-crashes/` (or `dumps/`).\n\n- **No GPU acceleration (software rendering).** This means the virtual GPU (`/dev/dxg`, d3d12 mesa)\n  is not usable, so rendering falls back to CPU:\n  ```\n  Xwayland glamor: GBM Wayland interfaces not available\n  Failed to initialize glamor, falling back to sw\n  ```\n  Investigate GPU driver presence, `/dev/dxg`, and the `mesa`/`d3d12` stack if the user reports\n  black windows, slow rendering, or missing 3D.\n\n- **Audio sink not connected (usually benign at boot).** Expected until an RDP/audio client attaches:\n  ```\n  [rdp-sink] RDP Sink - Trying to connect to /mnt/wslg/PulseAudioRDPSink\n  [rdp-sink] Connected failed\n  ```\n  If it persists while audio is actively broken, look at the RDP client (`msrdc`) audio channel.\n\n- **Mostly-benign startup noise** (not a root cause on its own):\n  - `WSLGd: Exception: No such file or directory @FontMonitor.cpp:280` - font share not mounted.\n  - `XDG_RUNTIME_DIR \"/mnt/wslg/runtime-dir\" ... mode 040777` (should be 0700) - common warning.\n  - `dbus: Unknown username \"pulse\"` / `Option \"-listen\" is deprecated` - harmless.\n\n## When to escalate to the WSLg repo\n\nWSLg code is not in this repository. Fixes to weston, FreeRDP, pulseaudio, or the RDP backend\nbelong in https://github.com/microsoft/wslg. Use a commit-pinned permalink when referencing files\nthere so the link does not drift, e.g.\n`https://github.com/microsoft/wslg/blob/<commit-sha>/<path>`.\n",".github/copilot/localization-bugs.md":"## Creating Localization Tracking Bugs (GCS Azure DevOps)\n\nCommunity members report localization problems in two ways: by filing a GitHub **issue** about a bad\ntranslation, or by opening a **pull request** that edits a localized file (the per-locale UI strings in\n`localization/strings/<locale>/Resources.resw`, or the per-locale Intune/group-policy templates in\n`intune/<locale>/WSL.adml`), or that adds a brand-new locale file. Both are valid signals and you should\nlook for **both** when triaging.\n\nEither way, the fix is handled by the Microsoft Global Collaboration Service (GCS) localization pipeline,\n**not** merged directly from GitHub: every non-`en-US` localized file is generated by the GCS team and\nregenerated downstream, so any translation edit merged here would be overwritten. (PRs that touch\nlocalized files should be declined with a pointer to `CONTRIBUTING.md`; only the `en-US` sources and the\nlanguage-neutral `intune/WSL.admx` live in this repo.) To route a report for review, file a tracking\n**Bug** in the GCS Azure DevOps project for each issue or PR.\n\n> **GCS requirement — be specific: list the exact resource IDs to fix.** The loc team will **not**\n> triage abstract reports. A bug that only names the file, language, and a few quoted strings gets\n> rejected (moved to the **More Info** state) because the team does not have capacity to parse a vague\n> report into the concrete strings that need work — that translation has to be done up front by the\n> filer. Every bug must therefore carry an explicit list of the **resource IDs** (the `name` attribute\n> of the `<data name=\"...\">` elements in `localization/strings/<locale>/Resources.resw`) that need\n> fixing. The gold-standard level of detail is **Bug 1223866** (`.../GlobalCollaborationService/Global%20Collaboration%20Service%20Project/_workitems/edit/1223866`):\n> for each resource ID it gives the current (bad) value and the proposed value, e.g.\n>\n> ```text\n> MessageDistroAlreadySet\n>   current:  Der Verteilungsname wurde bereits festgelegt.\n>   proposed: Der Distributionsname wurde bereits festgelegt.\n> ```\n\n### Deriving the resource-ID list\n\nHow you obtain the IDs depends on the report type:\n\n- **PR editing an existing locale file** — the changed resource IDs are exactly the `<data name>`\n  blocks whose `<value>` differs between the repo's current file and the PR head. Load both and diff\n  by name. The PR \"Files changed\" view already shows current→proposed for each, so post the **compact\n  ID list plus a link to the PR diff** rather than re-inlining every value (a 160-row inline table is\n  unwieldy; the PR diff is the source of truth for the old/new text).\n\n  ```powershell\n  # changed resource IDs between two Resources.resw files (master vs PR head)\n  function Get-ChangedIds($baseResw, $headResw) {\n    function Load($p) { $x = [xml](Get-Content $p -Raw); $h = @{}; foreach ($d in $x.root.data) { $h[$d.name] = $d.value }; $h }\n    $b = Load $baseResw; $h = Load $headResw\n    $h.Keys | Where-Object { $b[$_] -ne $h[$_] }\n  }\n  ```\n\n- **Issue citing line numbers** (e.g. `Resources.resw#L185`) — fetch the file **at the exact commit\n  the issue links to**, then walk upward from each cited line to the nearest `data name=\"...\"` to get\n  the enclosing resource ID. Line numbers drift between commits, so always pin to the linked SHA.\n\n- **Issue quoting bad strings** — grep the locale `Resources.resw` for each quoted value to find the\n  `<data name>` that contains it. One displayed term often maps to several IDs (`.Header`,\n  `.Description`, `...TextBox.AutomationProperties.Name`/`.HelpText`, shell-nav `.Content`), so list\n  them all.\n\n- **PR adding a brand-new locale** — this is a net-new whole-file contribution, **not** a correction\n  list, so there is nothing pre-existing to \"fix\". Give the team the actionable file-level items\n  instead: (1) hard parity failures vs `en-US` that block `tools/devops/validate-localization.py` —\n  placeholder/insert-count mismatches and missing `{Locked=\"...\"}` tokens, listed by resource ID;\n  (2) the coverage gap (which `en-US` IDs are missing, and how many of N total); (3) any strings\n  present in the file but absent from `en-US` (obsolete — drop them); and (4) that a new locale needs\n  build registration, not just a file drop.\n\n### Coordinates\n\n| | |\n|---|---|\n| Org | `https://dev.azure.com/GlobalCollaborationService` |\n| Project | `Global Collaboration Service Project` |\n| Process | `GCS_Agile` |\n| Work item type | `Bug` |\n| Web \"create from template\" link | `https://dev.azure.com/GlobalCollaborationService/Global%20Collaboration%20Service%20Project/_workitems/create/Bug?templateId=b97df4d3-4106-4099-a3a9-1782b5891bec` |\n\n### Required fields (and known-good values for a community loc PR)\n\nThe Bug type has several required custom picklist fields. Values that work for \"community translation PR\nneeds review\":\n\n| Field (reference name) | Value |\n|---|---|\n| `System.Title` | `WSL: Review community <locale> localization report (GitHub #<issue or PR>)` |\n| `System.Description` / `Microsoft.VSTS.TCM.ReproSteps` | GitHub link + scope + action (see below) |\n| `Custom.IssueType` | `Incorrect Translation` |\n| `Custom.ProductArea` | `Software` |\n| `Custom.How_Found` | `Community` |\n| `Custom.Severity_Impact` | `S3 - Medium` (field default) |\n| `Microsoft.VSTS.Common.ValueArea` | `Business` (field default) |\n| `Custom.HaveyouattachedEnglishandlocalizedscreenshots` | `No` (allowed: `Yes`/`No`; no default — must be set) |\n| `Custom.Language` | picklist — see mapping below (the WSL locale code is **not** accepted) |\n\nOther required custom flags (`Custom.BugBlocked`, `Custom.XLanguage`,\n`Custom.OverrideMaxStringsThreshold`, `Custom.SkipSourceAudioFilesValidation`,\n`Custom.DidCopilotrespondinthesamelanguage`, `Custom.Copilotattachallfiles`) default to `0` and\nauto-fill; leave them unset.\n\n### `Custom.Language` mapping (picklist values, not locale codes)\n\n`Custom.Language` is a 148-value picklist keyed by display name. Map the WSL `Resources.resw` locale\nfolder to the picklist value:\n\n| WSL locale | `Custom.Language` value |\n|---|---|\n| `es-ES` | `Spanish (Spain, International Sort)` |\n| `zh-CN` | `Chinese (Simplified) - PRC` |\n| `el-GR` | `Greek (Greece)` |\n| `tr-TR` | `Turkish (Turkey)` |\n\nFor other locales, list the allowed values and match by display name:\n\n```powershell\n$org=\"https://dev.azure.com/GlobalCollaborationService\"\n$projEnc=\"Global%20Collaboration%20Service%20Project\"\n$res=\"499b84ac-1321-427f-aa17-267ca6975798\"   # Azure DevOps AAD resource id\naz rest --method get --resource $res `\n  --uri \"$org/$projEnc/_apis/wit/workitemtypes/Bug/fields/Custom.Language?`$expand=all\" `\n  --headers \"Accept=application/json;api-version=7.1-preview.3\" |\n  ConvertFrom-Json | Select-Object -ExpandProperty allowedValues\n```\n\n### Suggested description body\n\n```\nCommunity localization report on GitHub microsoft/WSL needs review by the loc pipeline.\n\nGitHub: https://github.com/microsoft/WSL/<issues or pull>/<number>\nLanguage: <locale>\nType: <issue reporting a bad translation | PR editing the localized file>\nScope: localized file (localization/strings/<locale>/Resources.resw or intune/<locale>/WSL.adml).\n  For a PR: <edits to existing | brand-new>, +A/-B, 1 file. For an issue: the specific string(s) reported.\nResource IDs to fix: <explicit list of <data name> keys - see the dedicated comment with the full\n  list, or paste it here>. This is required; see \"Deriving the resource-ID list\" above.\nAction: validate placeholder/locked-token parity vs en-US (tools/devops/validate-localization.py),\nthen incorporate or advise. New locales additionally need build registration, not just a file drop.\nNote: do not merge the GitHub PR - localized files are regenerated by GCS and edits here are overwritten.\n```\n\nThe resource-ID list is the part GCS actually needs. If it is long, post it as a work-item **comment**\n(ADO comments accept HTML and can be edited in place via `PATCH .../comments/<id>`) and reference that\ncomment from the description.\n\n### Creating via CLI (`az boards`)\n\nRequires the `azure-devops` az extension and an identity with **create/edit work item** permission in\nthe project (see caveat below).\n\n```powershell\n$org=\"https://dev.azure.com/GlobalCollaborationService\"\n$proj=\"Global Collaboration Service Project\"\n$area=\"Global Collaboration Service Project\\Global\\Windows\"   # working area path, see Permissions gotcha\n$desc=\"Community es-ES localization PR. PR: https://github.com/microsoft/WSL/pull/14109 ...\"\naz boards work-item create --org $org --project $proj --type \"Bug\" `\n  --title \"WSL: Review community es-ES localization PR (GitHub #14109)\" `\n  --area \"$area\" --description $desc `\n  --fields \"Microsoft.VSTS.TCM.ReproSteps=$desc\" `\n           \"Custom.Language=Spanish (Spain, International Sort)\" `\n           \"Custom.IssueType=Incorrect Translation\" `\n           \"Custom.ProductArea=Software\" `\n           \"Custom.How_Found=Community\" `\n           \"Custom.Severity_Impact=S3 - Medium\" `\n           \"Microsoft.VSTS.Common.ValueArea=Business\" `\n           \"Custom.HaveyouattachedEnglishandlocalizedscreenshots=No\"\n```\n\n### Gotchas\n\n- **`az.cmd` eats `&` in URLs.** When using `az rest`, never put `&` (multiple query params) in\n  `--uri` on Windows — cmd truncates the URL there. Pass `api-version` via the **Accept header**\n  instead: `--headers \"Accept=application/json;api-version=7.1\"`, keeping at most one `?param` in the URI.\n- **Permissions are area-path-scoped, and the path matters.** Creating work items requires explicit rights on\n  the *specific area path*, not the project as a whole. The correct, durable path for WSL localization bugs is\n  `Global Collaboration Service Project\\Global\\Windows` (confirmed against existing manually-filed WSL loc\n  bugs). Always set `System.AreaPath` (or `--area`) to that path. A `@ntdev.microsoft.com` identity is denied\n  at the project root and most other paths (`TF237111: ... does not have permissions to save work items under\n  the specified area path`). Do NOT file under `...\\C and AI\\Unspecified`: an identity may briefly appear to\n  have access there, but bugs filed there get cleaned up and the access is not stable. To probe a path without\n  creating anything, POST with `?validateOnly=true`. If your identity lacks rights everywhere, create the bug\n  through the web template link above.\n- **`System.Description` is required, separately from repro steps.** The Bug type rejects a create with\n  `TF401320: Rule Error for field Description ... Required, InvalidEmpty` unless `System.Description` is set.\n  Set both `System.Description` and `Microsoft.VSTS.TCM.ReproSteps` (the same body is fine). When POSTing a\n  JSON-patch document via `az rest`, use newline-to-`<br>` so the HTML-rendered fields keep their line breaks.\n- **Picklist discovery.** Field allowed-values often don't expand through the plain field endpoint; use\n  `?$expand=all` on `.../workitemtypes/Bug/fields/<ref>` as shown above.\n- **\"Not found\" can mean \"no access,\" not \"doesn't exist.\"** WIQL and `GET .../workitems/<id>` honor ACLs:\n  a `CreatedBy=@me` query returning zero rows, or `TF401232: Work item <id> does not exist, or you do not\n  have permissions to read it`, often just means your identity can't read that area path. Don't assume the\n  bug was deleted. A gap in sequential work-item IDs is a tell that items were created but are now invisible\n  to you (e.g. filed under a path whose access got revoked, then reaped) - which is exactly why you should\n  stick to the durable `Global\\Windows` path above.\n- **Read the bug back after creating it.** Immediately `GET` each new work item id (or open the URL) to\n  confirm it's actually persisted and readable under your identity. A create that \"succeeds\" against a flaky\n  area path can vanish later; a read-back catches that while you can still re-file.\n- **Non-ASCII gets mangled, and `az` errors poison `ConvertFrom-Json`.** Locale content (Turkish, Greek, CJK)\n  comes back cp1252-garbled unless you set `[Console]::OutputEncoding=[System.Text.Encoding]::UTF8` first.\n  Also, `az` prints errors to the stream, so piping straight into `ConvertFrom-Json` throws on any failure;\n  capture with `Out-String` and parse, or check `$LASTEXITCODE`. Pass JSON-patch bodies via `--body \"@file\"`\n  (content type `application/json-patch+json`) rather than inline to dodge quoting hell.\n- **Don't inline huge diffs into a comment.** For a PR that touches many strings, post the resource-ID\n  list and link the PR \"Files changed\" page for the current→proposed values; a 100+ row HTML table\n  makes the bug unreadable and can bump against comment-size limits. ADO comments can be edited in\n  place (`PATCH .../comments/<id>?api-version=7.1-preview.4`), so trim/replace rather than re-posting.\n\n### After creating\n\nKeep the GitHub link in the ADO Bug's description/repro steps (it's already there from the body above) so the\nloc team can trace back to the report. Do **not** paste the internal ADO Bug ID into the public GitHub PR or\nissue. Then read each new bug back (see gotcha above) to confirm it persisted under `Global\\Windows`.\n\nIf GCS moves a bug to **More Info**, it almost always means the resource-ID detail is missing or too\nabstract: supply the explicit `<data name>` list (see \"Deriving the resource-ID list\"), then move the\nbug back to **Active** and reassign it to the requesting GCS reviewer.\n\n### What happens after you file (automated pipeline)\n\nFiling the Bug under `Global\\Windows` is usually the end of the manual work. A **Fabric Self Service** bot\n(`FabricClient-Prod`) automatically picks the Bug up and creates a **DTT (Direct-To-Translator) job** for the\nlocale, posting its progress as Bug discussion comments. So a stream of `FabricClient-Prod` comments is the\n**expected, healthy** path — not something a human has to act on:\n\n- `Bug picked up for processing by the Fabric Self Service process.`\n- `Successfully created 1 DTT Jobs: ... <locale> ...` → the report is now in the translation pipeline; **no\n  further action**.\n\nWatch for these exceptions, which **do** need action:\n\n- **New locale not onboarded.** If the locale isn't onboarded to **TDBuild** for the WSL subtenant\n  (`WindowsUndocking` / `LiftedWSL`), the DTT job can't be created and a human comments pointing you to file an\n  onboarding request at the **Global Services Hub** (`https://globalservices.powerappsportals.com/global/`).\n  This is GCS-side onboarding and is *separate from* (and in addition to) the WSL-repo build registration a new\n  locale needs. Greek (`el-GR`, GitHub #40244) hit exactly this.\n- **Oversized report.** A non-retriable `Rqf query exceeded threshold of 1000 words` failure means the report's\n  scope is too large; reduce the scope or set `Custom.OverrideMaxStringsThreshold` and re-file.\n\nIf you only see `FabricClient-Prod` \"Successfully created ... DTT Jobs\" comments, you're done.\n",".github/copilot-instructions.md":"# Windows Subsystem for Linux (WSL)\n\n**ALWAYS reference these instructions first and fallback to search or bash commands only when you encounter unexpected information that does not match the info here.**\n\nWSL is the Windows Subsystem for Linux - a compatibility layer for running Linux binary executables natively on Windows. This repository contains the core Windows components that enable WSL functionality.\n\n## Coding Conventions\n\n### Naming\n\n- **Classes/Structs**: `PascalCase` (e.g., `ConsoleProgressBar`, `DeviceHostProxy`)\n- **Functions/Methods**: `PascalCase()` (e.g., `GetFamilyName()`, `MultiByteToWide()`)\n- **Member variables**: `m_camelCase` (e.g., `m_isOutputConsole`, `m_outputHandle`)\n- **Local variables**: `camelCase` (e.g., `distroGuidString`, `asyncResponse`)\n- **Constants**: `c_camelCase` with `constexpr` (e.g., `constexpr size_t c_progressBarWidth = 58;`)\n- **Namespaces**: lowercase with `::` nesting (e.g., `wsl::windows::common::registry`)\n- **Enums**: `PascalCaseValue` (e.g., `LxssDistributionStateInstalled`)\n- **Windows types**: Keep as-is (`LPCWSTR`, `HRESULT`, `DWORD`, `ULONG`, `GUID`)\n\n### Error Handling\n\nUse WIL (Windows Implementation Libraries) macros — **never** bare `if (FAILED(hr))`:\n- `THROW_IF_FAILED(hr)` — throw on HRESULT failure\n- `THROW_HR_IF(hr, condition)` — conditional throw\n- `THROW_HR_IF_MSG(hr, condition, fmt, ...)` — conditional throw with message\n- `THROW_IF_NULL_ALLOC(ptr)` — throw on null allocation\n- `THROW_LAST_ERROR_IF(condition)` — throw last Win32 error\n- `RETURN_IF_FAILED(hr)` — return HRESULT on failure (no throw)\n- `RETURN_LAST_ERROR_IF_EXPECTED(condition)` — expected failure path\n- `LOG_IF_FAILED(hr)` — log but don't throw\n- `CATCH_LOG()` — catch and log exceptions\n\nFor user-facing errors, set a localized message before throwing:\n```cpp\nTHROW_HR_WITH_USER_ERROR(E_INVALIDARG, Localization::MessageConfigInvalidBoolean(name, value));\n```\n\nAt API boundaries (COM interfaces), return `HRESULT` with out params. Internal code throws exceptions.\n\n### Memory Management and RAII\n\nUse WIL smart pointers — **never** raw `CloseHandle()` or manual cleanup:\n- `wil::unique_handle` — kernel handles\n- `wil::com_ptr<T>` — COM objects\n- `wil::unique_hfile` — file handles\n- `wil::unique_hkey` — registry keys\n- `wil::unique_event` — events\n- `wil::unique_hlocal_string` — HLOCAL strings\n- `wil::unique_cotaskmem_string` — CoTaskMem strings\n\nFor non-standard resource types, use `wil::unique_any<Type, Deleter, Fn>`.\n\nFor cleanup scopes, use `wil::scope_exit`:\n```cpp\nauto cleanup = wil::scope_exit([&] { registry::DeleteKey(LxssKey, guid.c_str()); });\n// ... work ...\ncleanup.release(); // dismiss on success\n```\n\n### Synchronization\n\nUse `wil::srwlock` (Slim Reader/Writer locks) with SAL annotations:\n```cpp\nmutable wil::srwlock m_lock;\n_Guarded_by_(m_lock) std::vector<Entry> m_entries;\n```\n\n### Strings\n\n- `std::wstring` / `std::wstring_view` are dominant throughout the codebase\n- Use `MultiByteToWide()` / `WideToMultiByte()` from `stringshared.h` for conversions\n- Use `std::format()` for formatting (the repo defines `std::formatter<std::wstring, char>` for wide-to-narrow support)\n- The `STRING_TO_WIDE_STRING()` macro handles compile-time conversion\n\n### Copy/Move Semantics\n\nUse macros from `defs.h` to declare copy/move behavior:\n```cpp\nNON_COPYABLE(MyClass);\nNON_MOVABLE(MyClass);\nDEFAULT_MOVABLE(MyClass);\n```\n\n### Headers\n\n- Use `#pragma once` (no traditional `#ifndef` include guards)\n- In Windows C++ components, every `.cpp` file must start with `#include \"precomp.h\"`\n- Linux-side code (`src/linux/`) does not use precompiled headers\n- Use `.h` for C-compatible headers, `.hpp` for C++-only headers\n- Include order is enforced by `.clang-format` (precomp first, then system, then project)\n\n### Copyright Headers\n\nUse this single-line format for new files:\n```cpp\n// Copyright (C) Microsoft Corporation. All rights reserved.\n```\n\nSome older files use the block format (`/*++ Copyright (c) Microsoft. All rights reserved. ... --*/`). Match the surrounding files in the same directory when editing.\n\n### Localization\n\n- Use `wsl::shared::Localization::MessageXxx()` static methods for user-facing strings\n- Use `EMIT_USER_WARNING(Localization::MessageXxx(...))` for non-fatal config warnings\n- All new user-facing strings must have entries in `localization/strings/en-US/Resources.resw`\n- In Resources.resw comments, use `{Locked=\"...\"}` to prevent translation of `.wslconfig` property key names\n- Localized files are generated by a separate localization team and regenerated downstream, so translation edits in a GitHub PR cannot be merged (they would be overwritten). This covers the per-locale `localization/strings/<locale>/Resources.resw` UI strings and the per-locale `intune/<locale>/WSL.adml` policy templates (anything other than the `en-US` sources and the neutral `intune/WSL.admx`). Filing a GitHub issue is the correct path for contributors; see `CONTRIBUTING.md`. Ignore this guidance for automated localization-service PRs that are generated by that pipeline.\n- Community localization reports come in as **both GitHub issues and pull requests** - when triaging, look for both and file a tracking Bug for each. These are tracked via Bugs in the GCS Azure DevOps project, not merged directly. See `.github/copilot/localization-bugs.md` for the project coordinates, required fields, and `az boards` workflow.\n\n### Telemetry and Logging\n\n- `WSL_LOG(Name, ...)` — standard trace event\n- `WSL_LOG_DEBUG(Name, ...)` — debug-only (compiled out in release via `if constexpr`)\n- `WSL_LOG_TELEMETRY(Name, Tag, ...)` — metrics with privacy tag and version info\n- Provider: `g_hTraceLoggingProvider`, initialized via `WslTraceLoggingInitialize()`\n\n### Platform Conditionals\n\nPrefer `constexpr` checks over `#ifdef` where possible:\n```cpp\nif constexpr (wsl::shared::Debug) { /* debug-only code */ }\nif constexpr (wsl::shared::Arm64) { /* ARM64-specific code */ }\n```\n\nFor compiler-specific code, use `#ifdef _MSC_VER` (Windows) / `#ifdef __GNUC__` (Linux).\n\n### Formatting\n\nEnforced by `.clang-format`:\n- 130 character column limit\n- 4-space indentation, no tabs\n- Allman-style braces (opening brace on new line for classes, functions, structs, control statements)\n- Left-aligned pointers (`int* ptr`, not `int *ptr`)\n- `InsertBraces: true` — all control statements must have braces\n\n### IDL / COM Conventions\n\nWhen modifying service interfaces (`src/windows/service/inc/`):\n- Interface attributes on separate lines: `[uuid(...), pointer_default(unique), object]`\n- String params: `[in, unique] LPCWSTR` with `[string]` for marshaled strings\n- Handle params: `[in, system_handle(sh_file)] HANDLE`\n- User-facing errors: pass `[in, out] LXSS_ERROR_INFO* Error`\n- **ABI stability applies only to SDK-facing and public surfaces.** `WSLCCompat.idl` (the WSLC SDK-facing layer) and the public plugin API (`WslPluginApi.h`) must stay backward compatible: do not add, remove, or reorder methods on their existing interfaces, and do not change struct layouts. Introduce a new versioned interface with a new IID instead. Every other interface (`IWSLCSession` in `wslc.idl`, the interfaces in `wslservice.idl`, etc.) is internal and non-stable: rebuilt and shipped in lockstep with its only clients, so appending new methods to those is fine.\n- Custom error codes: `WSL_E_xxx` via `MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, WSL_E_BASE + N)`\n\n### Config File (.wslconfig) Conventions\n\nWhen adding settings to `src/shared/configfile/`:\n- Format is `.gitconfig`-style INI: `[section]`, `key = value`, `#` comments, `\\` line continuation\n- Use the `ConfigKey` template class for type-safe parsing\n- Supported types: `bool`, `int` (hex/octal), `std::string`, `std::wstring`, `MemoryString`, `MacAddress`, enum maps\n- Report invalid values with `EMIT_USER_WARNING(Localization::MessageConfigXxx(...))`\n- New settings require a corresponding localization string in Resources.resw\n\n## Architecture\n\n- `wsl.exe` is a thin entry point into `src/windows/common/WslClient.cpp`. Client commands reach the SYSTEM `wslservice.exe` through the internal COM interfaces in `src/windows/service/inc/wslservice.idl`; `LxssUserSession` owns per-user distribution operations.\n- For WSL2, the service creates/manages the VM through HCS in `WslCoreVm.cpp` and communicates over hvsockets with Linux `mini_init`. `mini_init` configures the VM, starts `gns` for networking, and launches a per-distribution `init`; the service's `WslCoreInstance` talks to that `init` to launch sessions. The session leader launches a relay and the requested Linux process; Windows client I/O is relayed over hvsockets. Shared wire messages live in `src/shared/inc/lxinitshared.h` and use `SocketChannel`.\n- `src/windows/wslc/` contains the container CLI, `src/windows/wslcsession/` the container session process, and the service hosts its session manager; their internal interface is `wslc.idl`. The SDK-facing compatibility contract is separate (`WSLCCompat.idl`). See `doc/docs/technical-documentation/index.md` and `boot-process.md` for the process and boot diagrams.\n\n## Repository Navigation\n\n### Key Directories\n- `src/windows/` — Main Windows WSL service components\n- `src/linux/` — Linux-side WSL components\n- `src/shared/` — Shared code between Windows and Linux\n- `test/windows/` — Windows-based tests (TAEF framework): `common/`, `wsl/`, `wslc/`, `testplugin/`\n- `test/linux/unit_tests/` — Linux unit test suite\n- `doc/` — Documentation source (MkDocs)\n- `tools/` — Build and deployment scripts\n- `distributions/` — Distribution validation and metadata\n- `localization/` — Localized string resources\n\n### Namespace → Directory Map\n\n| Namespace | Location |\n|---|---|\n| `wsl::shared::` | `src/shared/` |\n| `wsl::windows::common::` | `src/windows/common/` |\n| `wsl::windows::service::` | `src/windows/service/exe/` |\n| `wsl::core::` | `src/windows/service/exe/` |\n| `wsl::core::networking::` | `src/windows/common/` + `src/windows/service/exe/` |\n| `wsl::linux::` | `src/linux/init/` |\n\n### Key Files\n- `src/shared/inc/defs.h` — Shared platform definitions (NON_COPYABLE, Debug, Arm64, etc.)\n- `src/shared/inc/stringshared.h` — String conversion utilities\n- `src/windows/common/WslTelemetry.h` — Telemetry macros\n- `src/windows/common/ExecutionContext.h` — Error context and user-facing error macros\n- `src/windows/service/inc/wslservice.idl` — Main service COM interface definitions\n- `src/windows/service/inc/wslc.idl` — Container COM interface definitions\n- `src/windows/inc/WslPluginApi.h` — Plugin API header\n- `src/shared/configfile/configfile.h` — Config file parser\n- `.clang-format` — Code formatting rules (130 col, 4-space indent, Allman braces)\n\n## Building and Deploying\n\n### Critical Platform Requirements\n- **Full builds ONLY work on Windows** with Visual Studio and Windows SDK 26100\n- **DO NOT attempt to build the main WSL components on Linux** — they require Windows-specific APIs, MSBuild, and Visual Studio toolchain\n- Many validation and development tasks CAN be performed on Linux (documentation, formatting, Python validation scripts)\n\n### Windows Build Requirements\n- CMake >= 3.25 (`winget install Kitware.CMake`)\n- Visual Studio with these components:\n  - Windows SDK 26100\n  - MSBuild\n  - Universal Windows platform support for v143 build tools (X64 and ARM64)\n  - MSVC v143 - VS 2022 C++ ARM64 build tools (Latest + Spectre) (X64 and ARM64)\n  - C++ core features\n  - C++ ATL for latest v143 tools (X64 and ARM64)\n  - C++ Clang compiler for Windows\n  - .NET desktop development\n  - .NET WinUI app development tools\n- Enable Developer Mode in Windows Settings OR run with Administrator privileges (required for symbolic link support)\n\n### Building WSL (Windows Only)\n1. Install prerequisites with `tools\\setup-dev-env.ps1` (or follow `doc/docs/dev-loop.md` and `.vsconfig`)\n2. Generate Visual Studio solution: `cmake .`\n3. Build: `cmake --build . -- -m` OR open `wsl.sln` in Visual Studio\n\nBuild parameters:\n- `cmake . -A arm64` — Build for ARM64\n- `cmake . -DCMAKE_BUILD_TYPE=Release` — Release build\n- `cmake . -DBUILD_BUNDLE=TRUE` — Build bundle MSIX package (requires ARM64 built first)\n\n### Deploying WSL (Windows Only)\n- Install MSI: `bin\\<platform>\\<target>\\wsl.msi`\n- OR use script: `powershell tools\\deploy\\deploy-to-host.ps1`\n- For Hyper-V VM: `powershell tools\\deploy\\deploy-to-vm.ps1 -VmName <vm> -Username <user> -Password <pass>`\n\n## Testing\n\n### Writing Tests (TAEF Framework)\n\nTests use TAEF. See `.github/copilot/test.md` for detailed patterns and macros.\n\nKey points:\n- Use `WSL_TEST_CLASS(Name)` — not raw `BEGIN_TEST_CLASS`\n- Use `VERIFY_*` macros for assertions (`VERIFY_ARE_EQUAL`, `VERIFY_IS_TRUE`, etc.)\n- Skip macros: `WSL1_TEST_ONLY()`, `WSL2_TEST_ONLY()`, `SKIP_TEST_ARM64()`\n- Test infrastructure is in `test/windows/common/Common.h` (include it as `\"Common.h\"`)\n- Test layout under `test/windows/`:\n  - `common/` — shared fixtures and helpers, plus unit tests for `src/windows/common`\n  - `wsl/` — WSL tests\n  - `wslc/` — WSLC tests\n  - `testplugin/` — test plugin used by the plugin tests\n\n### Running Tests (Windows Only)\n\n**CRITICAL: ALWAYS build the ENTIRE project before running tests:**\n```powershell\ncmake --build . -- -m\nbin\\<platform>\\<target>\\test.bat\n```\n\n**Why full build is required:**\n- Tests depend on multiple components (libwsl.dll, wsltests.dll, wslservice.exe, etc.)\n- Partial builds will cause test failures\n- **DO NOT skip the full build step even if only one file changed**\n\nTest execution:\n- Run all tests: `bin\\<platform>\\<target>\\test.bat`\n- Run subset: `bin\\<platform>\\<target>\\test.bat /name:*UnitTest*`\n- Run specific test: `bin\\<platform>\\<target>\\test.bat /name:<class>::<test>` (for example, `bin\\x64\\debug\\test.bat /name:UnitTests::UnitTests::ModernInstall`)\n- WSL1 tests: Add `-Version 1` flag\n- Fast mode (after first run): Add `-f` flag (requires `wsl --set-default test_distro`)\n- **Requires Administrator privileges**\n\nTest debugging:\n- Attach WinDbgX automatically: `/attachdebugger`\n- Wait for debugger (manual attach): `/waitfordebugger`\n- Break on failure: `/breakonfailure`\n- Run in-process: `/inproc`\n\n### Linux Unit Tests (Linux Only)\n- Location: `test/linux/unit_tests/`\n- Build script: `test/linux/unit_tests/build_tests.sh`\n- **Note**: Requires specific Linux build environment setup not covered in main build process\n\n## Cross-Platform Validation Tasks\n\n### Documentation (Works on Linux/Windows)\n- Install tools: `pip install mkdocs-mermaid2-plugin mkdocs --break-system-packages`\n- Build docs: `mkdocs build -f doc/mkdocs.yml`\n- Output location: `doc/site/`\n- **Note**: May show warnings about mermaid CDN access on restricted networks\n\n### Code Formatting and Validation\n- Format modified source (Windows, requires `cmake .` first): `.\\FormatSource.ps1`\n- Format all source: `.\\FormatSource.ps1 -ModifiedOnly $false`; format/check files touched by the branch: `.\\FormatSource.ps1 -Branch` / `.\\FormatSource.ps1 -Branch -Verify $true` (defaults to local `master`; use `-BaseBranch` if needed)\n- Format check (Linux/cross-platform): `clang-format --dry-run --style=file <files>`\n- Validate copyright headers: `python3 tools/devops/validate-copyright-headers.py`\n  - **Note**: Will report missing headers in generated/dependency files (`_deps/`), which is expected\n- Validate localization: `python3 tools/devops/validate-localization.py`\n  - **Note**: Only works after Windows build (requires `localization/strings/en-US/Resources.resw`)\n\n### Distribution Validation (Limited on Linux)\n- Validate distribution info: `python3 distributions/validate.py distributions/DistributionInfo.json`\n- **Note**: May fail on Linux due to network restrictions accessing distribution URLs\n\n### Pre-commit Checklist\nAlways run before committing:\n1. `.\\FormatSource.ps1 -Verify $true` to check formatting on changed C++ files\n2. `python3 tools/devops/validate-copyright-headers.py` (ignore `_deps/` warnings)\n3. `mkdocs build -f doc/mkdocs.yml` if documentation changed\n4. Full Windows build if core components changed\n\n**Note**: The `.gitignore` properly excludes build artifacts (`*.sln`, `*.dll`, `*.pdb`, `obj/`, `bin/`, etc.) — do not commit these files.\n\n## Frequently Used Commands\n\n### Windows Development\n```powershell\n# Initial setup\ncmake .\ncmake --build . -- -m\n\n# Deploy and test\npowershell tools\\deploy\\deploy-to-host.ps1\nwsl --version\n\n# Run tests\nbin\\x64\\debug\\test.bat\n```\n\n### Cross-Platform Validation\n```powershell\n# Documentation\nmkdocs build -f doc/mkdocs.yml\n\n# Code formatting (Windows)\n.\\FormatSource.ps1\n\n# Copyright header validation (reports expected issues in _deps/)\npython3 tools/devops/validate-copyright-headers.py\n\n# Distribution validation (may fail on networks without external access)\npython3 distributions/validate.py distributions/DistributionInfo.json\n```\n\n## Debugging and Logging\n\n### ETL Tracing (Windows Only)\n```powershell\n# Collect traces\nwpr -start diagnostics\\wsl.wprp -filemode\n# [reproduce issue]\nwpr -stop logs.ETL\n\n# Available profiles:\n# - WSL (default) - General WSL tracing\n# - WSL-Storage - Enhanced storage tracing\n# - WSL-Networking - Comprehensive networking tracing\n# - WSL-HvSocket - HvSocket-specific tracing\n# Example: wpr -start diagnostics\\wsl.wprp!WSL -filemode\n```\n\n### Log Analysis Tools\n- Use WPA (Windows Performance Analyzer) for ETL traces\n- Key providers: `Microsoft.Windows.Lxss.Manager`, `Microsoft.Windows.Subsystem.Lxss`\n- For graphical/audio (WSLg) issues, see `.github/copilot/wslg-logs.md`. `collect-wsl-logs.ps1` gathers WSLg logs (`/mnt/wslg`: weston.log, pulseaudio.log, wlog.log, stderr.log, versions.txt) into a `wslg/` folder using `wsl.exe --system --user root`; crash dumps (`%TEMP%\\wsl-crashes`, legacy `/mnt/wslg/dumps`) are only collected with `-Dump`. WSLg code lives in https://github.com/microsoft/wslg, not this repo.\n\n### Debug Console (Linux)\nAdd to `%USERPROFILE%\\.wslconfig`:\n```ini\n[wsl2]\ndebugConsole=true\n```\n\n### Common Debugging Commands\n- Debug shell: `wsl --debug-shell`\n- Collect WSL logs: `powershell diagnostics\\collect-wsl-logs.ps1`\n- Network logs: `powershell diagnostics\\collect-wsl-logs.ps1 -LogProfile networking`\n\n## Timing and Timeout Guidelines\n\n**NEVER CANCEL these operations — always wait for completion:**\n\n| Operation | Typical Duration | Minimum Timeout |\n|---|---|---|\n| Full Windows build | 20-45 minutes | 60+ minutes |\n| Full test suite | 30-60 minutes | 90+ minutes |\n| Unit test subset | 5-15 minutes | 30+ minutes |\n| Documentation build | ~0.5 seconds | 5+ minutes |\n| Distribution validation | 2-5 minutes | 15+ minutes |\n\n## CI/CD Integration\n\n### GitHub Actions\n- **distributions.yml** — Validates distribution metadata (Linux)\n- **documentation.yml** — Builds and deploys docs (Linux)\n- **modern-distributions.yml** — Tests modern distribution support\n\n## Development Environment Setup\n\n### Windows (Full Development)\n1. Install Visual Studio with required components (listed above)\n2. Install CMake 3.25+\n3. Enable Developer Mode\n4. Clone repository\n5. Run `cmake .` to generate solution\n\n### Linux (Documentation/Validation Only)\n1. Install Python 3.8+\n2. Install docs tools: `pip install mkdocs-mermaid2-plugin mkdocs`\n3. Clone repository\n4. Run validation commands as needed\n\nRemember: **This is a Windows-focused project**. While some tasks can be performed on Linux, full WSL development requires Windows with Visual Studio."},"items":[{"name":"copilot-instructions.md","path":".github/copilot-instructions.md","rawUrl":"https://raw.githubusercontent.com/microsoft/WSL/HEAD/.github/copilot-instructions.md","title":"GitHub Copilot Instructions","category":"copilot-instructions","format":"markdown","content":"# Windows Subsystem for Linux (WSL)\n\n**ALWAYS reference these instructions first and fallback to search or bash commands only when you encounter unexpected information that does not match the info here.**\n\nWSL is the Windows Subsystem for Linux - a compatibility layer for running Linux binary executables natively on Windows. This repository contains the core Windows components that enable WSL functionality.\n\n## Coding Conventions\n\n### Naming\n\n- **Classes/Structs**: `PascalCase` (e.g., `ConsoleProgressBar`, `DeviceHostProxy`)\n- **Functions/Methods**: `PascalCase()` (e.g., `GetFamilyName()`, `MultiByteToWide()`)\n- **Member variables**: `m_camelCase` (e.g., `m_isOutputConsole`, `m_outputHandle`)\n- **Local variables**: `camelCase` (e.g., `distroGuidString`, `asyncResponse`)\n- **Constants**: `c_camelCase` with `constexpr` (e.g., `constexpr size_t c_progressBarWidth = 58;`)\n- **Namespaces**: lowercase with `::` nesting (e.g., `wsl::windows::common::registry`)\n- **Enums**: `PascalCaseValue` (e.g., `LxssDistributionStateInstalled`)\n- **Windows types**: Keep as-is (`LPCWSTR`, `HRESULT`, `DWORD`, `ULONG`, `GUID`)\n\n### Error Handling\n\nUse WIL (Windows Implementation Libraries) macros — **never** bare `if (FAILED(hr))`:\n- `THROW_IF_FAILED(hr)` — throw on HRESULT failure\n- `THROW_HR_IF(hr, condition)` — conditional throw\n- `THROW_HR_IF_MSG(hr, condition, fmt, ...)` — conditional throw with message\n- `THROW_IF_NULL_ALLOC(ptr)` — throw on null allocation\n- `THROW_LAST_ERROR_IF(condition)` — throw last Win32 error\n- `RETURN_IF_FAILED(hr)` — return HRESULT on failure (no throw)\n- `RETURN_LAST_ERROR_IF_EXPECTED(condition)` — expected failure path\n- `LOG_IF_FAILED(hr)` — log but don't throw\n- `CATCH_LOG()` — catch and log exceptions\n\nFor user-facing errors, set a localized message before throwing:\n```cpp\nTHROW_HR_WITH_USER_ERROR(E_INVALIDARG, Localization::MessageConfigInvalidBoolean(name, value));\n```\n\nAt API boundaries (COM interfaces), return `HRESULT` with out params. Internal code throws exceptions.\n\n### Memory Management and RAII\n\nUse WIL smart pointers — **never** raw `CloseHandle()` or manual cleanup:\n- `wil::unique_handle` — kernel handles\n- `wil::com_ptr<T>` — COM objects\n- `wil::unique_hfile` — file handles\n- `wil::unique_hkey` — registry keys\n- `wil::unique_event` — events\n- `wil::unique_hlocal_string` — HLOCAL strings\n- `wil::unique_cotaskmem_string` — CoTaskMem strings\n\nFor non-standard resource types, use `wil::unique_any<Type, Deleter, Fn>`.\n\nFor cleanup scopes, use `wil::scope_exit`:\n```cpp\nauto cleanup = wil::scope_exit([&] { registry::DeleteKey(LxssKey, guid.c_str()); });\n// ... work ...\ncleanup.release(); // dismiss on success\n```\n\n### Synchronization\n\nUse `wil::srwlock` (Slim Reader/Writer locks) with SAL annotations:\n```cpp\nmutable wil::srwlock m_lock;\n_Guarded_by_(m_lock) std::vector<Entry> m_entries;\n```\n\n### Strings\n\n- `std::wstring` / `std::wstring_view` are dominant throughout the codebase\n- Use `MultiByteToWide()` / `WideToMultiByte()` from `stringshared.h` for conversions\n- Use `std::format()` for formatting (the repo defines `std::formatter<std::wstring, char>` for wide-to-narrow support)\n- The `STRING_TO_WIDE_STRING()` macro handles compile-time conversion\n\n### Copy/Move Semantics\n\nUse macros from `defs.h` to declare copy/move behavior:\n```cpp\nNON_COPYABLE(MyClass);\nNON_MOVABLE(MyClass);\nDEFAULT_MOVABLE(MyClass);\n```\n\n### Headers\n\n- Use `#pragma once` (no traditional `#ifndef` include guards)\n- In Windows C++ components, every `.cpp` file must start with `#include \"precomp.h\"`\n- Linux-side code (`src/linux/`) does not use precompiled headers\n- Use `.h` for C-compatible headers, `.hpp` for C++-only headers\n- Include order is enforced by `.clang-format` (precomp first, then system, then project)\n\n### Copyright Headers\n\nUse this single-line format for new files:\n```cpp\n// Copyright (C) Microsoft Corporation. All rights reserved.\n```\n\nSome older files use the block format (`/*++ Copyright (c) Microsoft. All rights reserved. ... --*/`). Match the surrounding files in the same directory when editing.\n\n### Localization\n\n- Use `wsl::shared::Localization::MessageXxx()` static methods for user-facing strings\n- Use `EMIT_USER_WARNING(Localization::MessageXxx(...))` for non-fatal config warnings\n- All new user-facing strings must have entries in `localization/strings/en-US/Resources.resw`\n- In Resources.resw comments, use `{Locked=\"...\"}` to prevent translation of `.wslconfig` property key names\n- Localized files are generated by a separate localization team and regenerated downstream, so translation edits in a GitHub PR cannot be merged (they would be overwritten). This covers the per-locale `localization/strings/<locale>/Resources.resw` UI strings and the per-locale `intune/<locale>/WSL.adml` policy templates (anything other than the `en-US` sources and the neutral `intune/WSL.admx`). Filing a GitHub issue is the correct path for contributors; see `CONTRIBUTING.md`. Ignore this guidance for automated localization-service PRs that are generated by that pipeline.\n- Community localization reports come in as **both GitHub issues and pull requests** - when triaging, look for both and file a tracking Bug for each. These are tracked via Bugs in the GCS Azure DevOps project, not merged directly. See `.github/copilot/localization-bugs.md` for the project coordinates, required fields, and `az boards` workflow.\n\n### Telemetry and Logging\n\n- `WSL_LOG(Name, ...)` — standard trace event\n- `WSL_LOG_DEBUG(Name, ...)` — debug-only (compiled out in release via `if constexpr`)\n- `WSL_LOG_TELEMETRY(Name, Tag, ...)` — metrics with privacy tag and version info\n- Provider: `g_hTraceLoggingProvider`, initialized via `WslTraceLoggingInitialize()`\n\n### Platform Conditionals\n\nPrefer `constexpr` checks over `#ifdef` where possible:\n```cpp\nif constexpr (wsl::shared::Debug) { /* debug-only code */ }\nif constexpr (wsl::shared::Arm64) { /* ARM64-specific code */ }\n```\n\nFor compiler-specific code, use `#ifdef _MSC_VER` (Windows) / `#ifdef __GNUC__` (Linux).\n\n### Formatting\n\nEnforced by `.clang-format`:\n- 130 character column limit\n- 4-space indentation, no tabs\n- Allman-style braces (opening brace on new line for classes, functions, structs, control statements)\n- Left-aligned pointers (`int* ptr`, not `int *ptr`)\n- `InsertBraces: true` — all control statements must have braces\n\n### IDL / COM Conventions\n\nWhen modifying service interfaces (`src/windows/service/inc/`):\n- Interface attributes on separate lines: `[uuid(...), pointer_default(unique), object]`\n- String params: `[in, unique] LPCWSTR` with `[string]` for marshaled strings\n- Handle params: `[in, system_handle(sh_file)] HANDLE`\n- User-facing errors: pass `[in, out] LXSS_ERROR_INFO* Error`\n- **ABI stability applies only to SDK-facing and public surfaces.** `WSLCCompat.idl` (the WSLC SDK-facing layer) and the public plugin API (`WslPluginApi.h`) must stay backward compatible: do not add, remove, or reorder methods on their existing interfaces, and do not change struct layouts. Introduce a new versioned interface with a new IID instead. Every other interface (`IWSLCSession` in `wslc.idl`, the interfaces in `wslservice.idl`, etc.) is internal and non-stable: rebuilt and shipped in lockstep with its only clients, so appending new methods to those is fine.\n- Custom error codes: `WSL_E_xxx` via `MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, WSL_E_BASE + N)`\n\n### Config File (.wslconfig) Conventions\n\nWhen adding settings to `src/shared/configfile/`:\n- Format is `.gitconfig`-style INI: `[section]`, `key = value`, `#` comments, `\\` line continuation\n- Use the `ConfigKey` template class for type-safe parsing\n- Supported types: `bool`, `int` (hex/octal), `std::string`, `std::wstring`, `MemoryString`, `MacAddress`, enum maps\n- Report invalid values with `EMIT_USER_WARNING(Localization::MessageConfigXxx(...))`\n- New settings require a corresponding localization string in Resources.resw\n\n## Architecture\n\n- `wsl.exe` is a thin entry point into `src/windows/common/WslClient.cpp`. Client commands reach the SYSTEM `wslservice.exe` through the internal COM interfaces in `src/windows/service/inc/wslservice.idl`; `LxssUserSession` owns per-user distribution operations.\n- For WSL2, the service creates/manages the VM through HCS in `WslCoreVm.cpp` and communicates over hvsockets with Linux `mini_init`. `mini_init` configures the VM, starts `gns` for networking, and launches a per-distribution `init`; the service's `WslCoreInstance` talks to that `init` to launch sessions. The session leader launches a relay and the requested Linux process; Windows client I/O is relayed over hvsockets. Shared wire messages live in `src/shared/inc/lxinitshared.h` and use `SocketChannel`.\n- `src/windows/wslc/` contains the container CLI, `src/windows/wslcsession/` the container session process, and the service hosts its session manager; their internal interface is `wslc.idl`. The SDK-facing compatibility contract is separate (`WSLCCompat.idl`). See `doc/docs/technical-documentation/index.md` and `boot-process.md` for the process and boot diagrams.\n\n## Repository Navigation\n\n### Key Directories\n- `src/windows/` — Main Windows WSL service components\n- `src/linux/` — Linux-side WSL components\n- `src/shared/` — Shared code between Windows and Linux\n- `test/windows/` — Windows-based tests (TAEF framework): `common/`, `wsl/`, `wslc/`, `testplugin/`\n- `test/linux/unit_tests/` — Linux unit test suite\n- `doc/` — Documentation source (MkDocs)\n- `tools/` — Build and deployment scripts\n- `distributions/` — Distribution validation and metadata\n- `localization/` — Localized string resources\n\n### Namespace → Directory Map\n\n| Namespace | Location |\n|---|---|\n| `wsl::shared::` | `src/shared/` |\n| `wsl::windows::common::` | `src/windows/common/` |\n| `wsl::windows::service::` | `src/windows/service/exe/` |\n| `wsl::core::` | `src/windows/service/exe/` |\n| `wsl::core::networking::` | `src/windows/common/` + `src/windows/service/exe/` |\n| `wsl::linux::` | `src/linux/init/` |\n\n### Key Files\n- `src/shared/inc/defs.h` — Shared platform definitions (NON_COPYABLE, Debug, Arm64, etc.)\n- `src/shared/inc/stringshared.h` — String conversion utilities\n- `src/windows/common/WslTelemetry.h` — Telemetry macros\n- `src/windows/common/ExecutionContext.h` — Error context and user-facing error macros\n- `src/windows/service/inc/wslservice.idl` — Main service COM interface definitions\n- `src/windows/service/inc/wslc.idl` — Container COM interface definitions\n- `src/windows/inc/WslPluginApi.h` — Plugin API header\n- `src/shared/configfile/configfile.h` — Config file parser\n- `.clang-format` — Code formatting rules (130 col, 4-space indent, Allman braces)\n\n## Building and Deploying\n\n### Critical Platform Requirements\n- **Full builds ONLY work on Windows** with Visual Studio and Windows SDK 26100\n- **DO NOT attempt to build the main WSL components on Linux** — they require Windows-specific APIs, MSBuild, and Visual Studio toolchain\n- Many validation and development tasks CAN be performed on Linux (documentation, formatting, Python validation scripts)\n\n### Windows Build Requirements\n- CMake >= 3.25 (`winget install Kitware.CMake`)\n- Visual Studio with these components:\n  - Windows SDK 26100\n  - MSBuild\n  - Universal Windows platform support for v143 build tools (X64 and ARM64)\n  - MSVC v143 - VS 2022 C++ ARM64 build tools (Latest + Spectre) (X64 and ARM64)\n  - C++ core features\n  - C++ ATL for latest v143 tools (X64 and ARM64)\n  - C++ Clang compiler for Windows\n  - .NET desktop development\n  - .NET WinUI app development tools\n- Enable Developer Mode in Windows Settings OR run with Administrator privileges (required for symbolic link support)\n\n### Building WSL (Windows Only)\n1. Install prerequisites with `tools\\setup-dev-env.ps1` (or follow `doc/docs/dev-loop.md` and `.vsconfig`)\n2. Generate Visual Studio solution: `cmake .`\n3. Build: `cmake --build . -- -m` OR open `wsl.sln` in Visual Studio\n\nBuild parameters:\n- `cmake . -A arm64` — Build for ARM64\n- `cmake . -DCMAKE_BUILD_TYPE=Release` — Release build\n- `cmake . -DBUILD_BUNDLE=TRUE` — Build bundle MSIX package (requires ARM64 built first)\n\n### Deploying WSL (Windows Only)\n- Install MSI: `bin\\<platform>\\<target>\\wsl.msi`\n- OR use script: `powershell tools\\deploy\\deploy-to-host.ps1`\n- For Hyper-V VM: `powershell tools\\deploy\\deploy-to-vm.ps1 -VmName <vm> -Username <user> -Password <pass>`\n\n## Testing\n\n### Writing Tests (TAEF Framework)\n\nTests use TAEF. See `.github/copilot/test.md` for detailed patterns and macros.\n\nKey points:\n- Use `WSL_TEST_CLASS(Name)` — not raw `BEGIN_TEST_CLASS`\n- Use `VERIFY_*` macros for assertions (`VERIFY_ARE_EQUAL`, `VERIFY_IS_TRUE`, etc.)\n- Skip macros: `WSL1_TEST_ONLY()`, `WSL2_TEST_ONLY()`, `SKIP_TEST_ARM64()`\n- Test infrastructure is in `test/windows/common/Common.h` (include it as `\"Common.h\"`)\n- Test layout under `test/windows/`:\n  - `common/` — shared fixtures and helpers, plus unit tests for `src/windows/common`\n  - `wsl/` — WSL tests\n  - `wslc/` — WSLC tests\n  - `testplugin/` — test plugin used by the plugin tests\n\n### Running Tests (Windows Only)\n\n**CRITICAL: ALWAYS build the ENTIRE project before running tests:**\n```powershell\ncmake --build . -- -m\nbin\\<platform>\\<target>\\test.bat\n```\n\n**Why full build is required:**\n- Tests depend on multiple components (libwsl.dll, wsltests.dll, wslservice.exe, etc.)\n- Partial builds will cause test failures\n- **DO NOT skip the full build step even if only one file changed**\n\nTest execution:\n- Run all tests: `bin\\<platform>\\<target>\\test.bat`\n- Run subset: `bin\\<platform>\\<target>\\test.bat /name:*UnitTest*`\n- Run specific test: `bin\\<platform>\\<target>\\test.bat /name:<class>::<test>` (for example, `bin\\x64\\debug\\test.bat /name:UnitTests::UnitTests::ModernInstall`)\n- WSL1 tests: Add `-Version 1` flag\n- Fast mode (after first run): Add `-f` flag (requires `wsl --set-default test_distro`)\n- **Requires Administrator privileges**\n\nTest debugging:\n- Attach WinDbgX automatically: `/attachdebugger`\n- Wait for debugger (manual attach): `/waitfordebugger`\n- Break on failure: `/breakonfailure`\n- Run in-process: `/inproc`\n\n### Linux Unit Tests (Linux Only)\n- Location: `test/linux/unit_tests/`\n- Build script: `test/linux/unit_tests/build_tests.sh`\n- **Note**: Requires specific Linux build environment setup not covered in main build process\n\n## Cross-Platform Validation Tasks\n\n### Documentation (Works on Linux/Windows)\n- Install tools: `pip install mkdocs-mermaid2-plugin mkdocs --break-system-packages`\n- Build docs: `mkdocs build -f doc/mkdocs.yml`\n- Output location: `doc/site/`\n- **Note**: May show warnings about mermaid CDN access on restricted networks\n\n### Code Formatting and Validation\n- Format modified source (Windows, requires `cmake .` first): `.\\FormatSource.ps1`\n- Format all source: `.\\FormatSource.ps1 -ModifiedOnly $false`; format/check files touched by the branch: `.\\FormatSource.ps1 -Branch` / `.\\FormatSource.ps1 -Branch -Verify $true` (defaults to local `master`; use `-BaseBranch` if needed)\n- Format check (Linux/cross-platform): `clang-format --dry-run --style=file <files>`\n- Validate copyright headers: `python3 tools/devops/validate-copyright-headers.py`\n  - **Note**: Will report missing headers in generated/dependency files (`_deps/`), which is expected\n- Validate localization: `python3 tools/devops/validate-localization.py`\n  - **Note**: Only works after Windows build (requires `localization/strings/en-US/Resources.resw`)\n\n### Distribution Validation (Limited on Linux)\n- Validate distribution info: `python3 distributions/validate.py distributions/DistributionInfo.json`\n- **Note**: May fail on Linux due to network restrictions accessing distribution URLs\n\n### Pre-commit Checklist\nAlways run before committing:\n1. `.\\FormatSource.ps1 -Verify $true` to check formatting on changed C++ files\n2. `python3 tools/devops/validate-copyright-headers.py` (ignore `_deps/` warnings)\n3. `mkdocs build -f doc/mkdocs.yml` if documentation changed\n4. Full Windows build if core components changed\n\n**Note**: The `.gitignore` properly excludes build artifacts (`*.sln`, `*.dll`, `*.pdb`, `obj/`, `bin/`, etc.) — do not commit these files.\n\n## Frequently Used Commands\n\n### Windows Development\n```powershell\n# Initial setup\ncmake .\ncmake --build . -- -m\n\n# Deploy and test\npowershell tools\\deploy\\deploy-to-host.ps1\nwsl --version\n\n# Run tests\nbin\\x64\\debug\\test.bat\n```\n\n### Cross-Platform Validation\n```powershell\n# Documentation\nmkdocs build -f doc/mkdocs.yml\n\n# Code formatting (Windows)\n.\\FormatSource.ps1\n\n# Copyright header validation (reports expected issues in _deps/)\npython3 tools/devops/validate-copyright-headers.py\n\n# Distribution validation (may fail on networks without external access)\npython3 distributions/validate.py distributions/DistributionInfo.json\n```\n\n## Debugging and Logging\n\n### ETL Tracing (Windows Only)\n```powershell\n# Collect traces\nwpr -start diagnostics\\wsl.wprp -filemode\n# [reproduce issue]\nwpr -stop logs.ETL\n\n# Available profiles:\n# - WSL (default) - General WSL tracing\n# - WSL-Storage - Enhanced storage tracing\n# - WSL-Networking - Comprehensive networking tracing\n# - WSL-HvSocket - HvSocket-specific tracing\n# Example: wpr -start diagnostics\\wsl.wprp!WSL -filemode\n```\n\n### Log Analysis Tools\n- Use WPA (Windows Performance Analyzer) for ETL traces\n- Key providers: `Microsoft.Windows.Lxss.Manager`, `Microsoft.Windows.Subsystem.Lxss`\n- For graphical/audio (WSLg) issues, see `.github/copilot/wslg-logs.md`. `collect-wsl-logs.ps1` gathers WSLg logs (`/mnt/wslg`: weston.log, pulseaudio.log, wlog.log, stderr.log, versions.txt) into a `wslg/` folder using `wsl.exe --system --user root`; crash dumps (`%TEMP%\\wsl-crashes`, legacy `/mnt/wslg/dumps`) are only collected with `-Dump`. WSLg code lives in https://github.com/microsoft/wslg, not this repo.\n\n### Debug Console (Linux)\nAdd to `%USERPROFILE%\\.wslconfig`:\n```ini\n[wsl2]\ndebugConsole=true\n```\n\n### Common Debugging Commands\n- Debug shell: `wsl --debug-shell`\n- Collect WSL logs: `powershell diagnostics\\collect-wsl-logs.ps1`\n- Network logs: `powershell diagnostics\\collect-wsl-logs.ps1 -LogProfile networking`\n\n## Timing and Timeout Guidelines\n\n**NEVER CANCEL these operations — always wait for completion:**\n\n| Operation | Typical Duration | Minimum Timeout |\n|---|---|---|\n| Full Windows build | 20-45 minutes | 60+ minutes |\n| Full test suite | 30-60 minutes | 90+ minutes |\n| Unit test subset | 5-15 minutes | 30+ minutes |\n| Documentation build | ~0.5 seconds | 5+ minutes |\n| Distribution validation | 2-5 minutes | 15+ minutes |\n\n## CI/CD Integration\n\n### GitHub Actions\n- **distributions.yml** — Validates distribution metadata (Linux)\n- **documentation.yml** — Builds and deploys docs (Linux)\n- **modern-distributions.yml** — Tests modern distribution support\n\n## Development Environment Setup\n\n### Windows (Full Development)\n1. Install Visual Studio with required components (listed above)\n2. Install CMake 3.25+\n3. Enable Developer Mode\n4. Clone repository\n5. Run `cmake .` to generate solution\n\n### Linux (Documentation/Validation Only)\n1. Install Python 3.8+\n2. Install docs tools: `pip install mkdocs-mermaid2-plugin mkdocs`\n3. Clone repository\n4. Run validation commands as needed\n\nRemember: **This is a Windows-focused project**. While some tasks can be performed on Linux, full WSL development requires Windows with Visual Studio.","isInternal":false,"tokens":4986,"sizeBytes":19502},{"name":"commit.md","path":".github/copilot/commit.md","rawUrl":"https://raw.githubusercontent.com/microsoft/WSL/HEAD/.github/copilot/commit.md","title":"GitHub Copilot Instructions","category":"copilot-instructions","format":"markdown","content":"## Commit Message Guidelines for WSL\n\nThis repo has no strict commit message format. Follow these general practices:\n\n- Write a concise summary under 72 characters\n- Use imperative mood (\"Fix crash\" not \"Fixed crash\")\n- Reference GitHub issues with `(#123)` or `Fixes #123`\n- Add a body paragraph for non-obvious changes explaining *why*\n","isInternal":false,"tokens":75,"sizeBytes":338},{"name":"localization-bugs.md","path":".github/copilot/localization-bugs.md","rawUrl":"https://raw.githubusercontent.com/microsoft/WSL/HEAD/.github/copilot/localization-bugs.md","title":"GitHub Copilot Instructions","category":"copilot-instructions","format":"markdown","content":"## Creating Localization Tracking Bugs (GCS Azure DevOps)\n\nCommunity members report localization problems in two ways: by filing a GitHub **issue** about a bad\ntranslation, or by opening a **pull request** that edits a localized file (the per-locale UI strings in\n`localization/strings/<locale>/Resources.resw`, or the per-locale Intune/group-policy templates in\n`intune/<locale>/WSL.adml`), or that adds a brand-new locale file. Both are valid signals and you should\nlook for **both** when triaging.\n\nEither way, the fix is handled by the Microsoft Global Collaboration Service (GCS) localization pipeline,\n**not** merged directly from GitHub: every non-`en-US` localized file is generated by the GCS team and\nregenerated downstream, so any translation edit merged here would be overwritten. (PRs that touch\nlocalized files should be declined with a pointer to `CONTRIBUTING.md`; only the `en-US` sources and the\nlanguage-neutral `intune/WSL.admx` live in this repo.) To route a report for review, file a tracking\n**Bug** in the GCS Azure DevOps project for each issue or PR.\n\n> **GCS requirement — be specific: list the exact resource IDs to fix.** The loc team will **not**\n> triage abstract reports. A bug that only names the file, language, and a few quoted strings gets\n> rejected (moved to the **More Info** state) because the team does not have capacity to parse a vague\n> report into the concrete strings that need work — that translation has to be done up front by the\n> filer. Every bug must therefore carry an explicit list of the **resource IDs** (the `name` attribute\n> of the `<data name=\"...\">` elements in `localization/strings/<locale>/Resources.resw`) that need\n> fixing. The gold-standard level of detail is **Bug 1223866** (`.../GlobalCollaborationService/Global%20Collaboration%20Service%20Project/_workitems/edit/1223866`):\n> for each resource ID it gives the current (bad) value and the proposed value, e.g.\n>\n> ```text\n> MessageDistroAlreadySet\n>   current:  Der Verteilungsname wurde bereits festgelegt.\n>   proposed: Der Distributionsname wurde bereits festgelegt.\n> ```\n\n### Deriving the resource-ID list\n\nHow you obtain the IDs depends on the report type:\n\n- **PR editing an existing locale file** — the changed resource IDs are exactly the `<data name>`\n  blocks whose `<value>` differs between the repo's current file and the PR head. Load both and diff\n  by name. The PR \"Files changed\" view already shows current→proposed for each, so post the **compact\n  ID list plus a link to the PR diff** rather than re-inlining every value (a 160-row inline table is\n  unwieldy; the PR diff is the source of truth for the old/new text).\n\n  ```powershell\n  # changed resource IDs between two Resources.resw files (master vs PR head)\n  function Get-ChangedIds($baseResw, $headResw) {\n    function Load($p) { $x = [xml](Get-Content $p -Raw); $h = @{}; foreach ($d in $x.root.data) { $h[$d.name] = $d.value }; $h }\n    $b = Load $baseResw; $h = Load $headResw\n    $h.Keys | Where-Object { $b[$_] -ne $h[$_] }\n  }\n  ```\n\n- **Issue citing line numbers** (e.g. `Resources.resw#L185`) — fetch the file **at the exact commit\n  the issue links to**, then walk upward from each cited line to the nearest `data name=\"...\"` to get\n  the enclosing resource ID. Line numbers drift between commits, so always pin to the linked SHA.\n\n- **Issue quoting bad strings** — grep the locale `Resources.resw` for each quoted value to find the\n  `<data name>` that contains it. One displayed term often maps to several IDs (`.Header`,\n  `.Description`, `...TextBox.AutomationProperties.Name`/`.HelpText`, shell-nav `.Content`), so list\n  them all.\n\n- **PR adding a brand-new locale** — this is a net-new whole-file contribution, **not** a correction\n  list, so there is nothing pre-existing to \"fix\". Give the team the actionable file-level items\n  instead: (1) hard parity failures vs `en-US` that block `tools/devops/validate-localization.py` —\n  placeholder/insert-count mismatches and missing `{Locked=\"...\"}` tokens, listed by resource ID;\n  (2) the coverage gap (which `en-US` IDs are missing, and how many of N total); (3) any strings\n  present in the file but absent from `en-US` (obsolete — drop them); and (4) that a new locale needs\n  build registration, not just a file drop.\n\n### Coordinates\n\n| | |\n|---|---|\n| Org | `https://dev.azure.com/GlobalCollaborationService` |\n| Project | `Global Collaboration Service Project` |\n| Process | `GCS_Agile` |\n| Work item type | `Bug` |\n| Web \"create from template\" link | `https://dev.azure.com/GlobalCollaborationService/Global%20Collaboration%20Service%20Project/_workitems/create/Bug?templateId=b97df4d3-4106-4099-a3a9-1782b5891bec` |\n\n### Required fields (and known-good values for a community loc PR)\n\nThe Bug type has several required custom picklist fields. Values that work for \"community translation PR\nneeds review\":\n\n| Field (reference name) | Value |\n|---|---|\n| `System.Title` | `WSL: Review community <locale> localization report (GitHub #<issue or PR>)` |\n| `System.Description` / `Microsoft.VSTS.TCM.ReproSteps` | GitHub link + scope + action (see below) |\n| `Custom.IssueType` | `Incorrect Translation` |\n| `Custom.ProductArea` | `Software` |\n| `Custom.How_Found` | `Community` |\n| `Custom.Severity_Impact` | `S3 - Medium` (field default) |\n| `Microsoft.VSTS.Common.ValueArea` | `Business` (field default) |\n| `Custom.HaveyouattachedEnglishandlocalizedscreenshots` | `No` (allowed: `Yes`/`No`; no default — must be set) |\n| `Custom.Language` | picklist — see mapping below (the WSL locale code is **not** accepted) |\n\nOther required custom flags (`Custom.BugBlocked`, `Custom.XLanguage`,\n`Custom.OverrideMaxStringsThreshold`, `Custom.SkipSourceAudioFilesValidation`,\n`Custom.DidCopilotrespondinthesamelanguage`, `Custom.Copilotattachallfiles`) default to `0` and\nauto-fill; leave them unset.\n\n### `Custom.Language` mapping (picklist values, not locale codes)\n\n`Custom.Language` is a 148-value picklist keyed by display name. Map the WSL `Resources.resw` locale\nfolder to the picklist value:\n\n| WSL locale | `Custom.Language` value |\n|---|---|\n| `es-ES` | `Spanish (Spain, International Sort)` |\n| `zh-CN` | `Chinese (Simplified) - PRC` |\n| `el-GR` | `Greek (Greece)` |\n| `tr-TR` | `Turkish (Turkey)` |\n\nFor other locales, list the allowed values and match by display name:\n\n```powershell\n$org=\"https://dev.azure.com/GlobalCollaborationService\"\n$projEnc=\"Global%20Collaboration%20Service%20Project\"\n$res=\"499b84ac-1321-427f-aa17-267ca6975798\"   # Azure DevOps AAD resource id\naz rest --method get --resource $res `\n  --uri \"$org/$projEnc/_apis/wit/workitemtypes/Bug/fields/Custom.Language?`$expand=all\" `\n  --headers \"Accept=application/json;api-version=7.1-preview.3\" |\n  ConvertFrom-Json | Select-Object -ExpandProperty allowedValues\n```\n\n### Suggested description body\n\n```\nCommunity localization report on GitHub microsoft/WSL needs review by the loc pipeline.\n\nGitHub: https://github.com/microsoft/WSL/<issues or pull>/<number>\nLanguage: <locale>\nType: <issue reporting a bad translation | PR editing the localized file>\nScope: localized file (localization/strings/<locale>/Resources.resw or intune/<locale>/WSL.adml).\n  For a PR: <edits to existing | brand-new>, +A/-B, 1 file. For an issue: the specific string(s) reported.\nResource IDs to fix: <explicit list of <data name> keys - see the dedicated comment with the full\n  list, or paste it here>. This is required; see \"Deriving the resource-ID list\" above.\nAction: validate placeholder/locked-token parity vs en-US (tools/devops/validate-localization.py),\nthen incorporate or advise. New locales additionally need build registration, not just a file drop.\nNote: do not merge the GitHub PR - localized files are regenerated by GCS and edits here are overwritten.\n```\n\nThe resource-ID list is the part GCS actually needs. If it is long, post it as a work-item **comment**\n(ADO comments accept HTML and can be edited in place via `PATCH .../comments/<id>`) and reference that\ncomment from the description.\n\n### Creating via CLI (`az boards`)\n\nRequires the `azure-devops` az extension and an identity with **create/edit work item** permission in\nthe project (see caveat below).\n\n```powershell\n$org=\"https://dev.azure.com/GlobalCollaborationService\"\n$proj=\"Global Collaboration Service Project\"\n$area=\"Global Collaboration Service Project\\Global\\Windows\"   # working area path, see Permissions gotcha\n$desc=\"Community es-ES localization PR. PR: https://github.com/microsoft/WSL/pull/14109 ...\"\naz boards work-item create --org $org --project $proj --type \"Bug\" `\n  --title \"WSL: Review community es-ES localization PR (GitHub #14109)\" `\n  --area \"$area\" --description $desc `\n  --fields \"Microsoft.VSTS.TCM.ReproSteps=$desc\" `\n           \"Custom.Language=Spanish (Spain, International Sort)\" `\n           \"Custom.IssueType=Incorrect Translation\" `\n           \"Custom.ProductArea=Software\" `\n           \"Custom.How_Found=Community\" `\n           \"Custom.Severity_Impact=S3 - Medium\" `\n           \"Microsoft.VSTS.Common.ValueArea=Business\" `\n           \"Custom.HaveyouattachedEnglishandlocalizedscreenshots=No\"\n```\n\n### Gotchas\n\n- **`az.cmd` eats `&` in URLs.** When using `az rest`, never put `&` (multiple query params) in\n  `--uri` on Windows — cmd truncates the URL there. Pass `api-version` via the **Accept header**\n  instead: `--headers \"Accept=application/json;api-version=7.1\"`, keeping at most one `?param` in the URI.\n- **Permissions are area-path-scoped, and the path matters.** Creating work items requires explicit rights on\n  the *specific area path*, not the project as a whole. The correct, durable path for WSL localization bugs is\n  `Global Collaboration Service Project\\Global\\Windows` (confirmed against existing manually-filed WSL loc\n  bugs). Always set `System.AreaPath` (or `--area`) to that path. A `@ntdev.microsoft.com` identity is denied\n  at the project root and most other paths (`TF237111: ... does not have permissions to save work items under\n  the specified area path`). Do NOT file under `...\\C and AI\\Unspecified`: an identity may briefly appear to\n  have access there, but bugs filed there get cleaned up and the access is not stable. To probe a path without\n  creating anything, POST with `?validateOnly=true`. If your identity lacks rights everywhere, create the bug\n  through the web template link above.\n- **`System.Description` is required, separately from repro steps.** The Bug type rejects a create with\n  `TF401320: Rule Error for field Description ... Required, InvalidEmpty` unless `System.Description` is set.\n  Set both `System.Description` and `Microsoft.VSTS.TCM.ReproSteps` (the same body is fine). When POSTing a\n  JSON-patch document via `az rest`, use newline-to-`<br>` so the HTML-rendered fields keep their line breaks.\n- **Picklist discovery.** Field allowed-values often don't expand through the plain field endpoint; use\n  `?$expand=all` on `.../workitemtypes/Bug/fields/<ref>` as shown above.\n- **\"Not found\" can mean \"no access,\" not \"doesn't exist.\"** WIQL and `GET .../workitems/<id>` honor ACLs:\n  a `CreatedBy=@me` query returning zero rows, or `TF401232: Work item <id> does not exist, or you do not\n  have permissions to read it`, often just means your identity can't read that area path. Don't assume the\n  bug was deleted. A gap in sequential work-item IDs is a tell that items were created but are now invisible\n  to you (e.g. filed under a path whose access got revoked, then reaped) - which is exactly why you should\n  stick to the durable `Global\\Windows` path above.\n- **Read the bug back after creating it.** Immediately `GET` each new work item id (or open the URL) to\n  confirm it's actually persisted and readable under your identity. A create that \"succeeds\" against a flaky\n  area path can vanish later; a read-back catches that while you can still re-file.\n- **Non-ASCII gets mangled, and `az` errors poison `ConvertFrom-Json`.** Locale content (Turkish, Greek, CJK)\n  comes back cp1252-garbled unless you set `[Console]::OutputEncoding=[System.Text.Encoding]::UTF8` first.\n  Also, `az` prints errors to the stream, so piping straight into `ConvertFrom-Json` throws on any failure;\n  capture with `Out-String` and parse, or check `$LASTEXITCODE`. Pass JSON-patch bodies via `--body \"@file\"`\n  (content type `application/json-patch+json`) rather than inline to dodge quoting hell.\n- **Don't inline huge diffs into a comment.** For a PR that touches many strings, post the resource-ID\n  list and link the PR \"Files changed\" page for the current→proposed values; a 100+ row HTML table\n  makes the bug unreadable and can bump against comment-size limits. ADO comments can be edited in\n  place (`PATCH .../comments/<id>?api-version=7.1-preview.4`), so trim/replace rather than re-posting.\n\n### After creating\n\nKeep the GitHub link in the ADO Bug's description/repro steps (it's already there from the body above) so the\nloc team can trace back to the report. Do **not** paste the internal ADO Bug ID into the public GitHub PR or\nissue. Then read each new bug back (see gotcha above) to confirm it persisted under `Global\\Windows`.\n\nIf GCS moves a bug to **More Info**, it almost always means the resource-ID detail is missing or too\nabstract: supply the explicit `<data name>` list (see \"Deriving the resource-ID list\"), then move the\nbug back to **Active** and reassign it to the requesting GCS reviewer.\n\n### What happens after you file (automated pipeline)\n\nFiling the Bug under `Global\\Windows` is usually the end of the manual work. A **Fabric Self Service** bot\n(`FabricClient-Prod`) automatically picks the Bug up and creates a **DTT (Direct-To-Translator) job** for the\nlocale, posting its progress as Bug discussion comments. So a stream of `FabricClient-Prod` comments is the\n**expected, healthy** path — not something a human has to act on:\n\n- `Bug picked up for processing by the Fabric Self Service process.`\n- `Successfully created 1 DTT Jobs: ... <locale> ...` → the report is now in the translation pipeline; **no\n  further action**.\n\nWatch for these exceptions, which **do** need action:\n\n- **New locale not onboarded.** If the locale isn't onboarded to **TDBuild** for the WSL subtenant\n  (`WindowsUndocking` / `LiftedWSL`), the DTT job can't be created and a human comments pointing you to file an\n  onboarding request at the **Global Services Hub** (`https://globalservices.powerappsportals.com/global/`).\n  This is GCS-side onboarding and is *separate from* (and in addition to) the WSL-repo build registration a new\n  locale needs. Greek (`el-GR`, GitHub #40244) hit exactly this.\n- **Oversized report.** A non-retriable `Rqf query exceeded threshold of 1000 words` failure means the report's\n  scope is too large; reduce the scope or set `Custom.OverrideMaxStringsThreshold` and re-file.\n\nIf you only see `FabricClient-Prod` \"Successfully created ... DTT Jobs\" comments, you're done.\n","isInternal":false,"tokens":3826,"sizeBytes":14933},{"name":"review.md","path":".github/copilot/review.md","rawUrl":"https://raw.githubusercontent.com/microsoft/WSL/HEAD/.github/copilot/review.md","title":"GitHub Copilot Instructions","category":"copilot-instructions","format":"markdown","content":"## Code Review Guidelines for WSL\n\nWhen reviewing code, enforce the conventions in `.github/copilot-instructions.md`. Focus especially on these high-risk areas:\n\n### ABI Safety (Critical)\nOnly the SDK-facing and public surfaces require a backward-compatible ABI. Every other COM interface (`wslc.idl`, `wslservice.idl`, etc.) is internal and non-stable: shipped in lockstep with its only clients, with the proxy/stub regenerated each build, so methods may be appended to those freely. Do **not** flag internal, non-stable interfaces.\n- **Flag** ABI-breaking changes (new, removed, or reordered methods, changed struct layouts) only in the stable surfaces: `WSLCCompat.idl` (the WSLC SDK-facing layer, which must stay backward compatible) and the public plugin API (`WSLPluginHooksV1` / `WSLPluginAPIV1` structs in `WslPluginApi.h`).\n- **Do not flag** new methods appended to internal, non-stable interfaces such as `IWSLCSession` in `wslc.idl`, or interfaces in `wslservice.idl`.\n\n### Resource Safety\n- **Flag** raw `CloseHandle()`, `delete`, `free()`, or manual resource cleanup — require WIL smart pointers\n- **Flag** missing `NON_COPYABLE()` / `NON_MOVABLE()` on classes that hold resources\n- **Flag** lock usage without `_Guarded_by_()` SAL annotations\n\n### User-Facing Changes\n- **Flag** hardcoded English strings — require `Localization::MessageXxx()` and Resources.resw entry\n- **Flag** new `.wslconfig` settings without corresponding Resources.resw localization string\n- **Flag** silent fallback on invalid config values — require `EMIT_USER_WARNING()`\n\n### Error Handling\n- **Flag** bare `if (FAILED(hr))` — require WIL macros\n- **Flag** silently swallowed errors — require `CATCH_LOG()` or `LOG_IF_FAILED()`\n- **Flag** telemetry events missing privacy data tags\n","isInternal":false,"tokens":429,"sizeBytes":1782},{"name":"test.md","path":".github/copilot/test.md","rawUrl":"https://raw.githubusercontent.com/microsoft/WSL/HEAD/.github/copilot/test.md","title":"GitHub Copilot Instructions","category":"copilot-instructions","format":"markdown","content":"## Test Generation Guidelines for WSL\n\nWhen generating tests for this repository, follow these patterns:\n\n### Framework\nTests use TAEF (Test Authoring and Execution Framework). Always include `\"Common.h\"`.\n\n### Test Class Structure\n```cpp\n#include \"Common.h\"\n\nnamespace MyFeatureTests\n{\nclass MyFeatureTests\n{\n    WSL_TEST_CLASS(MyFeatureTests)\n\n    TEST_CLASS_SETUP(TestClassSetup)\n    {\n        VERIFY_ARE_EQUAL(LxsstuInitialize(FALSE), TRUE);\n        return true;\n    }\n\n    TEST_CLASS_CLEANUP(TestClassCleanup)\n    {\n        LxsstuUninitialize(FALSE);\n        return true;\n    }\n\n    TEST_METHOD(DescriptiveTestName)\n    {\n        // Test implementation\n    }\n};\n}\n```\n\n### Key Rules\n- Use `WSL_TEST_CLASS(Name)` — never raw `BEGIN_TEST_CLASS`\n- Setup/cleanup methods must `return true` on success\n- Use `VERIFY_*` macros for assertions — never `assert()` or exceptions for test validation\n\n### Assertion Macros\n- `VERIFY_ARE_EQUAL(expected, actual)` — value equality\n- `VERIFY_ARE_NOT_EQUAL(a, b)` — value inequality\n- `VERIFY_IS_TRUE(condition)` — boolean check\n- `VERIFY_IS_FALSE(condition)` — negative boolean check\n- `VERIFY_IS_NULL(ptr)` — null check\n- `VERIFY_IS_NOT_NULL(ptr)` — non-null check\n- `VERIFY_WIN32_BOOL_SUCCEEDED(expr)` — Win32 BOOL result\n- `VERIFY_SUCCEEDED(hr)` — HRESULT success\n\n### Logging in Tests\n- `LogInfo(fmt, ...)` — informational messages\n- `LogError(fmt, ...)` — error messages\n- `LogWarning(fmt, ...)` — warnings\n- `LogPass(fmt, ...)` — explicit pass messages\n- `LogSkipped(fmt, ...)` — skip messages\n\n### Conditional Skipping\nAdd skip macros at the start of a test method body when the test only applies to certain environments:\n```cpp\nTEST_METHOD(Wsl2SpecificTest)\n{\n    WSL2_TEST_ONLY();\n    // ... test code ...\n}\n```\n\nAvailable skip macros:\n- `WSL1_TEST_ONLY()` — skip unless WSL1\n- `WSL2_TEST_ONLY()` — skip unless WSL2\n- `SKIP_TEST_ARM64()` — skip on ARM64\n- `SKIP_TEST_UNSTABLE()` — skip known-flaky tests\n- `WINDOWS_11_TEST_ONLY()` — skip on pre-Windows 11\n- `WSL_TEST_VERSION_REQUIRED(version)` — skip if WSL version too old\n\n### RAII Test Helpers\n- `WslKeepAlive` — prevents UVM timeout during long-running tests; create at test start\n- `WslConfigChange` — RAII wrapper that applies a temporary `.wslconfig` and restores the original on destruction:\n```cpp\nTEST_METHOD(TestWithCustomConfig)\n{\n    WslConfigChange config(L\"[wsl2]\\nmemory=4GB\\n\");\n    // ... test with custom config ...\n    // Original .wslconfig restored when config goes out of scope\n}\n```\n\n### Memory in Tests\n- Use `ALLOC(size)` / `FREE(ptr)` macros for direct heap allocation in tests\n- Prefer RAII wrappers and smart pointers for production-like code paths\n\n### Test Naming\n- Use descriptive PascalCase names that describe the scenario: `CreateInstanceWithInvalidGuidFails`, `EchoTest`, `MountPlan9Share`\n- Group related tests in the same test class\n","isInternal":false,"tokens":721,"sizeBytes":2917},{"name":"wslg-logs.md","path":".github/copilot/wslg-logs.md","rawUrl":"https://raw.githubusercontent.com/microsoft/WSL/HEAD/.github/copilot/wslg-logs.md","title":"GitHub Copilot Instructions","category":"copilot-instructions","format":"markdown","content":"# Analyzing WSLg logs\n\nWSLg is the component that runs graphical (GUI) and audio Linux applications on WSL. Its\nsource lives in a separate repository: https://github.com/microsoft/wslg. The canonical list\nof diagnostics to request for a WSLg bug is the WSLg repo bug report template\n(`.github/ISSUE_TEMPLATE/bug_report.yml` in microsoft/wslg).\n\n`diagnostics/collect-wsl-logs.ps1` collects the logs into a `wslg/` subfolder of the log archive\n(via `wsl.exe --system --user root`, with a timeout so a wedged service can't hang collection), so a\nstandard WSL log collection already contains the log files below. Crash dumps (`dumps/`,\n`wsl-crashes/`) are only collected when the script is run with `-Dump`.\n\n## Architecture (just enough to read the logs)\n\nWSLg runs a **system distro** (a small Azure Linux VM, separate from the user distro) that hosts:\n- **weston** (Wayland compositor) with the `rdp-backend.so` / `rdprail-shell.so` modules\n- **Xwayland** for X11 apps\n- **pulseaudio** with an RDP sink/source for audio\n- **FreeRDP** to stream the surfaces over an hvsocket to the Windows RDP client (`msrdc.exe`)\n\n`weston.log` and `wlog.log` are written by weston/FreeRDP, `pulseaudio.log` by pulseaudio, and\n`stderr.log` is the combined stderr of `WSLGd` and the processes it launches.\n\n## Files (in the `wslg/` folder, sourced from `/mnt/wslg`)\n\n| File | Contents |\n|---|---|\n| `versions.txt` | WSLg version, architecture, build date, component git hashes (weston, FreeRDP, mesa, pulseaudio) |\n| `weston.log` | Weston compositor + RDP backend log |\n| `wlog.log` | FreeRDP (WLog) log |\n| `pulseaudio.log` | PulseAudio log |\n| `stderr.log` | `WSLGd` and child-process stderr |\n| `dumps/` | Legacy WSLg crash dumps (older builds only; collected with `-Dump`) |\n| `wsl-crashes/` | Host-side WSLg crash dumps copied from `%TEMP%\\wsl-crashes` (newer builds, e.g. `core.weston`; collected with `-Dump`) |\n\n## Reading tips and common signatures\n\n- **`weston.log` is truncated on every boot.** Weston is started with `--log=/mnt/wslg/weston.log`\n  and opens it truncating, so the file only ever contains the **latest** system-distro boot. To\n  tell whether weston restarted, compare the boot timestamp on the first line (`weston 9.0.0 ...`)\n  across snapshots, or correlate with `dmesg`.\n\n- **System distro cycling / teardown.** In `dmesg` (collected via the ETL `GuestLog` events or\n  the debug console), this pair means the WSLg system distro's `init` exited and the distro was\n  torn down (idle timeout or shutdown), which also restarts weston:\n  ```\n  Exception: Operation canceled @p9io.cpp:258 (AcceptAsync)\n  WSL (1 - init()) ERROR: InitEntryUtilityVm:2551: Init has exited. Terminating distribution\n  ```\n  Repeating every ~25-60s with no GUI client attached is usually normal idle teardown, not a crash.\n  A genuine weston crash instead leaves a core dump in `wsl-crashes/` (or `dumps/`).\n\n- **No GPU acceleration (software rendering).** This means the virtual GPU (`/dev/dxg`, d3d12 mesa)\n  is not usable, so rendering falls back to CPU:\n  ```\n  Xwayland glamor: GBM Wayland interfaces not available\n  Failed to initialize glamor, falling back to sw\n  ```\n  Investigate GPU driver presence, `/dev/dxg`, and the `mesa`/`d3d12` stack if the user reports\n  black windows, slow rendering, or missing 3D.\n\n- **Audio sink not connected (usually benign at boot).** Expected until an RDP/audio client attaches:\n  ```\n  [rdp-sink] RDP Sink - Trying to connect to /mnt/wslg/PulseAudioRDPSink\n  [rdp-sink] Connected failed\n  ```\n  If it persists while audio is actively broken, look at the RDP client (`msrdc`) audio channel.\n\n- **Mostly-benign startup noise** (not a root cause on its own):\n  - `WSLGd: Exception: No such file or directory @FontMonitor.cpp:280` - font share not mounted.\n  - `XDG_RUNTIME_DIR \"/mnt/wslg/runtime-dir\" ... mode 040777` (should be 0700) - common warning.\n  - `dbus: Unknown username \"pulse\"` / `Option \"-listen\" is deprecated` - harmless.\n\n## When to escalate to the WSLg repo\n\nWSLg code is not in this repository. Fixes to weston, FreeRDP, pulseaudio, or the RDP backend\nbelong in https://github.com/microsoft/wslg. Use a commit-pinned permalink when referencing files\nthere so the link does not drift, e.g.\n`https://github.com/microsoft/wslg/blob/<commit-sha>/<path>`.\n","isInternal":false,"tokens":1213,"sizeBytes":4294}],"systemPromptSnippet":"<yakaai_skills repo=\"microsoft/WSL\">\n<!-- File: .github/copilot-instructions.md (Tokens: ~4986 | Category: copilot-instructions) -->\n# Windows Subsystem for Linux (WSL)\n\n**ALWAYS reference these instructions first and fallback to search or bash commands only when you encounter unexpected information that does not match the info here.**\n\nWSL is the Windows Subsystem for Linux - a compatibility layer for running Linux binary executables natively on Windows. This repository contains the core Windows components that enable WSL functionality.\n\n## Coding Conventions\n\n### Naming\n\n- **Classes/Structs**: `PascalCase` (e.g., `ConsoleProgressBar`, `DeviceHostProxy`)\n- **Functions/Methods**: `PascalCase()` (e.g., `GetFamilyName()`, `MultiByteToWide()`)\n- **Member variables**: `m_camelCase` (e.g., `m_isOutputConsole`, `m_outputHandle`)\n- **Local variables**: `camelCase` (e.g., `distroGuidString`, `asyncResponse`)\n- **Constants**: `c_camelCase` with `constexpr` (e.g., `constexpr size_t c_progressBarWidth = 58;`)\n- **Namespaces**: lowercase with `::` nesting (e.g., `wsl::windows::common::registry`)\n- **Enums**: `PascalCaseValue` (e.g., `LxssDistributionStateInstalled`)\n- **Windows types**: Keep as-is (`LPCWSTR`, `HRESULT`, `DWORD`, `ULONG`, `GUID`)\n\n### Error Handling\n\nUse WIL (Windows Implementation Libraries) macros — **never** bare `if (FAILED(hr))`:\n- `THROW_IF_FAILED(hr)` — throw on HRESULT failure\n- `THROW_HR_IF(hr, condition)` — conditional throw\n- `THROW_HR_IF_MSG(hr, condition, fmt, ...)` — conditional throw with message\n- `THROW_IF_NULL_ALLOC(ptr)` — throw on null allocation\n- `THROW_LAST_ERROR_IF(condition)` — throw last Win32 error\n- `RETURN_IF_FAILED(hr)` — return HRESULT on failure (no throw)\n- `RETURN_LAST_ERROR_IF_EXPECTED(condition)` — expected failure path\n- `LOG_IF_FAILED(hr)` — log but don't throw\n- `CATCH_LOG()` — catch and log exceptions\n\nFor user-facing errors, set a localized message before throwing:\n```cpp\nTHROW_HR_WITH_USER_ERROR(E_INVALIDARG, Localization::MessageConfigInvalidBoolean(name, value));\n```\n\nAt API boundaries (COM interfaces), return `HRESULT` with out params. Internal code throws exceptions.\n\n### Memory Management and RAII\n\nUse WIL smart pointers — **never** raw `CloseHandle()` or manual cleanup:\n- `wil::unique_handle` — kernel handles\n- `wil::com_ptr<T>` — COM objects\n- `wil::unique_hfile` — file handles\n- `wil::unique_hkey` — registry keys\n- `wil::unique_event` — events\n- `wil::unique_hlocal_string` — HLOCAL strings\n- `wil::unique_cotaskmem_string` — CoTaskMem strings\n\nFor non-standard resource types, use `wil::unique_any<Type, Deleter, Fn>`.\n\nFor cleanup scopes, use `wil::scope_exit`:\n```cpp\nauto cleanup = wil::scope_exit([&] { registry::DeleteKey(LxssKey, guid.c_str()); });\n// ... work ...\ncleanup.release(); // dismiss on success\n```\n\n### Synchronization\n\nUse `wil::srwlock` (Slim Reader/Writer locks) with SAL annotations:\n```cpp\nmutable wil::srwlock m_lock;\n_Guarded_by_(m_lock) std::vector<Entry> m_entries;\n```\n\n### Strings\n\n- `std::wstring` / `std::wstring_view` are dominant throughout the codebase\n- Use `MultiByteToWide()` / `WideToMultiByte()` from `stringshared.h` for conversions\n- Use `std::format()` for formatting (the repo defines `std::formatter<std::wstring, char>` for wide-to-narrow support)\n- The `STRING_TO_WIDE_STRING()` macro handles compile-time conversion\n\n### Copy/Move Semantics\n\nUse macros from `defs.h` to declare copy/move behavior:\n```cpp\nNON_COPYABLE(MyClass);\nNON_MOVABLE(MyClass);\nDEFAULT_MOVABLE(MyClass);\n```\n\n### Headers\n\n- Use `#pragma once` (no traditional `#ifndef` include guards)\n- In Windows C++ components, every `.cpp` file must start with `#include \"precomp.h\"`\n- Linux-side code (`src/linux/`) does not use precompiled headers\n- Use `.h` for C-compatible headers, `.hpp` for C++-only headers\n- Include order is enforced by `.clang-format` (precomp first, then system, then project)\n\n### Copyright Headers\n\nUse this single-line format for new files:\n```cpp\n// Copyright (C) Microsoft Corporation. All rights reserved.\n```\n\nSome older files use the block format (`/*++ Copyright (c) Microsoft. All rights reserved. ... --*/`). Match the surrounding files in the same directory when editing.\n\n### Localization\n\n- Use `wsl::shared::Localization::MessageXxx()` static methods for user-facing strings\n- Use `EMIT_USER_WARNING(Localization::MessageXxx(...))` for non-fatal config warnings\n- All new user-facing strings must have entries in `localization/strings/en-US/Resources.resw`\n- In Resources.resw comments, use `{Locked=\"...\"}` to prevent translation of `.wslconfig` property key names\n- Localized files are generated by a separate localization team and regenerated downstream, so translation edits in a GitHub PR cannot be merged (they would be overwritten). This covers the per-locale `localization/strings/<locale>/Resources.resw` UI strings and the per-locale `intune/<locale>/WSL.adml` policy templates (anything other than the `en-US` sources and the neutral `intune/WSL.admx`). Filing a GitHub issue is the correct path for contributors; see `CONTRIBUTING.md`. Ignore this guidance for automated localization-service PRs that are generated by that pipeline.\n- Community localization reports come in as **both GitHub issues and pull requests** - when triaging, look for both and file a tracking Bug for each. These are tracked via Bugs in the GCS Azure DevOps project, not merged directly. See `.github/copilot/localization-bugs.md` for the project coordinates, required fields, and `az boards` workflow.\n\n### Telemetry and Logging\n\n- `WSL_LOG(Name, ...)` — standard trace event\n- `WSL_LOG_DEBUG(Name, ...)` — debug-only (compiled out in release via `if constexpr`)\n- `WSL_LOG_TELEMETRY(Name, Tag, ...)` — metrics with privacy tag and version info\n- Provider: `g_hTraceLoggingProvider`, initialized via `WslTraceLoggingInitialize()`\n\n### Platform Conditionals\n\nPrefer `constexpr` checks over `#ifdef` where possible:\n```cpp\nif constexpr (wsl::shared::Debug) { /* debug-only code */ }\nif constexpr (wsl::shared::Arm64) { /* ARM64-specific code */ }\n```\n\nFor compiler-specific code, use `#ifdef _MSC_VER` (Windows) / `#ifdef __GNUC__` (Linux).\n\n### Formatting\n\nEnforced by `.clang-format`:\n- 130 character column limit\n- 4-space indentation, no tabs\n- Allman-style braces (opening brace on new line for classes, functions, structs, control statements)\n- Left-aligned pointers (`int* ptr`, not `int *ptr`)\n- `InsertBraces: true` — all control statements must have braces\n\n### IDL / COM Conventions\n\nWhen modifying service interfaces (`src/windows/service/inc/`):\n- Interface attributes on separate lines: `[uuid(...), pointer_default(unique), object]`\n- String params: `[in, unique] LPCWSTR` with `[string]` for marshaled strings\n- Handle params: `[in, system_handle(sh_file)] HANDLE`\n- User-facing errors: pass `[in, out] LXSS_ERROR_INFO* Error`\n- **ABI stability applies only to SDK-facing and public surfaces.** `WSLCCompat.idl` (the WSLC SDK-facing layer) and the public plugin API (`WslPluginApi.h`) must stay backward compatible: do not add, remove, or reorder methods on their existing interfaces, and do not change struct layouts. Introduce a new versioned interface with a new IID instead. Every other interface (`IWSLCSession` in `wslc.idl`, the interfaces in `wslservice.idl`, etc.) is internal and non-stable: rebuilt and shipped in lockstep with its only clients, so appending new methods to those is fine.\n- Custom error codes: `WSL_E_xxx` via `MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, WSL_E_BASE + N)`\n\n### Config File (.wslconfig) Conventions\n\nWhen adding settings to `src/shared/configfile/`:\n- Format is `.gitconfig`-style INI: `[section]`, `key = value`, `#` comments, `\\` line continuation\n- Use the `ConfigKey` template class for type-safe parsing\n- Supported types: `bool`, `int` (hex/octal), `std::string`, `std::wstring`, `MemoryString`, `MacAddress`, enum maps\n- Report invalid values with `EMIT_USER_WARNING(Localization::MessageConfigXxx(...))`\n- New settings require a corresponding localization string in Resources.resw\n\n## Architecture\n\n- `wsl.exe` is a thin entry point into `src/windows/common/WslClient.cpp`. Client commands reach the SYSTEM `wslservice.exe` through the internal COM interfaces in `src/windows/service/inc/wslservice.idl`; `LxssUserSession` owns per-user distribution operations.\n- For WSL2, the service creates/manages the VM through HCS in `WslCoreVm.cpp` and communicates over hvsockets with Linux `mini_init`. `mini_init` configures the VM, starts `gns` for networking, and launches a per-distribution `init`; the service's `WslCoreInstance` talks to that `init` to launch sessions. The session leader launches a relay and the requested Linux process; Windows client I/O is relayed over hvsockets. Shared wire messages live in `src/shared/inc/lxinitshared.h` and use `SocketChannel`.\n- `src/windows/wslc/` contains the container CLI, `src/windows/wslcsession/` the container session process, and the service hosts its session manager; their internal interface is `wslc.idl`. The SDK-facing compatibility contract is separate (`WSLCCompat.idl`). See `doc/docs/technical-documentation/index.md` and `boot-process.md` for the process and boot diagrams.\n\n## Repository Navigation\n\n### Key Directories\n- `src/windows/` — Main Windows WSL service components\n- `src/linux/` — Linux-side WSL components\n- `src/shared/` — Shared code between Windows and Linux\n- `test/windows/` — Windows-based tests (TAEF framework): `common/`, `wsl/`, `wslc/`, `testplugin/`\n- `test/linux/unit_tests/` — Linux unit test suite\n- `doc/` — Documentation source (MkDocs)\n- `tools/` — Build and deployment scripts\n- `distributions/` — Distribution validation and metadata\n- `localization/` — Localized string resources\n\n### Namespace → Directory Map\n\n| Namespace | Location |\n|---|---|\n| `wsl::shared::` | `src/shared/` |\n| `wsl::windows::common::` | `src/windows/common/` |\n| `wsl::windows::service::` | `src/windows/service/exe/` |\n| `wsl::core::` | `src/windows/service/exe/` |\n| `wsl::core::networking::` | `src/windows/common/` + `src/windows/service/exe/` |\n| `wsl::linux::` | `src/linux/init/` |\n\n### Key Files\n- `src/shared/inc/defs.h` — Shared platform definitions (NON_COPYABLE, Debug, Arm64, etc.)\n- `src/shared/inc/stringshared.h` — String conversion utilities\n- `src/windows/common/WslTelemetry.h` — Telemetry macros\n- `src/windows/common/ExecutionContext.h` — Error context and user-facing error macros\n- `src/windows/service/inc/wslservice.idl` — Main service COM interface definitions\n- `src/windows/service/inc/wslc.idl` — Container COM interface definitions\n- `src/windows/inc/WslPluginApi.h` — Plugin API header\n- `src/shared/configfile/configfile.h` — Config file parser\n- `.clang-format` — Code formatting rules (130 col, 4-space indent, Allman braces)\n\n## Building and Deploying\n\n### Critical Platform Requirements\n- **Full builds ONLY work on Windows** with Visual Studio and Windows SDK 26100\n- **DO NOT attempt to build the main WSL components on Linux** — they require Windows-specific APIs, MSBuild, and Visual Studio toolchain\n- Many validation and development tasks CAN be performed on Linux (documentation, formatting, Python validation scripts)\n\n### Windows Build Requirements\n- CMake >= 3.25 (`winget install Kitware.CMake`)\n- Visual Studio with these components:\n  - Windows SDK 26100\n  - MSBuild\n  - Universal Windows platform support for v143 build tools (X64 and ARM64)\n  - MSVC v143 - VS 2022 C++ ARM64 build tools (Latest + Spectre) (X64 and ARM64)\n  - C++ core features\n  - C++ ATL for latest v143 tools (X64 and ARM64)\n  - C++ Clang compiler for Windows\n  - .NET desktop development\n  - .NET WinUI app development tools\n- Enable Developer Mode in Windows Settings OR run with Administrator privileges (required for symbolic link support)\n\n### Building WSL (Windows Only)\n1. Install prerequisites with `tools\\setup-dev-env.ps1` (or follow `doc/docs/dev-loop.md` and `.vsconfig`)\n2. Generate Visual Studio solution: `cmake .`\n3. Build: `cmake --build . -- -m` OR open `wsl.sln` in Visual Studio\n\nBuild parameters:\n- `cmake . -A arm64` — Build for ARM64\n- `cmake . -DCMAKE_BUILD_TYPE=Release` — Release build\n- `cmake . -DBUILD_BUNDLE=TRUE` — Build bundle MSIX package (requires ARM64 built first)\n\n### Deploying WSL (Windows Only)\n- Install MSI: `bin\\<platform>\\<target>\\wsl.msi`\n- OR use script: `powershell tools\\deploy\\deploy-to-host.ps1`\n- For Hyper-V VM: `powershell tools\\deploy\\deploy-to-vm.ps1 -VmName <vm> -Username <user> -Password <pass>`\n\n## Testing\n\n### Writing Tests (TAEF Framework)\n\nTests use TAEF. See `.github/copilot/test.md` for detailed patterns and macros.\n\nKey points:\n- Use `WSL_TEST_CLASS(Name)` — not raw `BEGIN_TEST_CLASS`\n- Use `VERIFY_*` macros for assertions (`VERIFY_ARE_EQUAL`, `VERIFY_IS_TRUE`, etc.)\n- Skip macros: `WSL1_TEST_ONLY()`, `WSL2_TEST_ONLY()`, `SKIP_TEST_ARM64()`\n- Test infrastructure is in `test/windows/common/Common.h` (include it as `\"Common.h\"`)\n- Test layout under `test/windows/`:\n  - `common/` — shared fixtures and helpers, plus unit tests for `src/windows/common`\n  - `wsl/` — WSL tests\n  - `wslc/` — WSLC tests\n  - `testplugin/` — test plugin used by the plugin tests\n\n### Running Tests (Windows Only)\n\n**CRITICAL: ALWAYS build the ENTIRE project before running tests:**\n```powershell\ncmake --build . -- -m\nbin\\<platform>\\<target>\\test.bat\n```\n\n**Why full build is required:**\n- Tests depend on multiple components (libwsl.dll, wsltests.dll, wslservice.exe, etc.)\n- Partial builds will cause test failures\n- **DO NOT skip the full build step even if only one file changed**\n\nTest execution:\n- Run all tests: `bin\\<platform>\\<target>\\test.bat`\n- Run subset: `bin\\<platform>\\<target>\\test.bat /name:*UnitTest*`\n- Run specific test: `bin\\<platform>\\<target>\\test.bat /name:<class>::<test>` (for example, `bin\\x64\\debug\\test.bat /name:UnitTests::UnitTests::ModernInstall`)\n- WSL1 tests: Add `-Version 1` flag\n- Fast mode (after first run): Add `-f` flag (requires `wsl --set-default test_distro`)\n- **Requires Administrator privileges**\n\nTest debugging:\n- Attach WinDbgX automatically: `/attachdebugger`\n- Wait for debugger (manual attach): `/waitfordebugger`\n- Break on failure: `/breakonfailure`\n- Run in-process: `/inproc`\n\n### Linux Unit Tests (Linux Only)\n- Location: `test/linux/unit_tests/`\n- Build script: `test/linux/unit_tests/build_tests.sh`\n- **Note**: Requires specific Linux build environment setup not covered in main build process\n\n## Cross-Platform Validation Tasks\n\n### Documentation (Works on Linux/Windows)\n- Install tools: `pip install mkdocs-mermaid2-plugin mkdocs --break-system-packages`\n- Build docs: `mkdocs build -f doc/mkdocs.yml`\n- Output location: `doc/site/`\n- **Note**: May show warnings about mermaid CDN access on restricted networks\n\n### Code Formatting and Validation\n- Format modified source (Windows, requires `cmake .` first): `.\\FormatSource.ps1`\n- Format all source: `.\\FormatSource.ps1 -ModifiedOnly $false`; format/check files touched by the branch: `.\\FormatSource.ps1 -Branch` / `.\\FormatSource.ps1 -Branch -Verify $true` (defaults to local `master`; use `-BaseBranch` if needed)\n- Format check (Linux/cross-platform): `clang-format --dry-run --style=file <files>`\n- Validate copyright headers: `python3 tools/devops/validate-copyright-headers.py`\n  - **Note**: Will report missing headers in generated/dependency files (`_deps/`), which is expected\n- Validate localization: `python3 tools/devops/validate-localization.py`\n  - **Note**: Only works after Windows build (requires `localization/strings/en-US/Resources.resw`)\n\n### Distribution Validation (Limited on Linux)\n- Validate distribution info: `python3 distributions/validate.py distributions/DistributionInfo.json`\n- **Note**: May fail on Linux due to network restrictions accessing distribution URLs\n\n### Pre-commit Checklist\nAlways run before committing:\n1. `.\\FormatSource.ps1 -Verify $true` to check formatting on changed C++ files\n2. `python3 tools/devops/validate-copyright-headers.py` (ignore `_deps/` warnings)\n3. `mkdocs build -f doc/mkdocs.yml` if documentation changed\n4. Full Windows build if core components changed\n\n**Note**: The `.gitignore` properly excludes build artifacts (`*.sln`, `*.dll`, `*.pdb`, `obj/`, `bin/`, etc.) — do not commit these files.\n\n## Frequently Used Commands\n\n### Windows Development\n```powershell\n# Initial setup\ncmake .\ncmake --build . -- -m\n\n# Deploy and test\npowershell tools\\deploy\\deploy-to-host.ps1\nwsl --version\n\n# Run tests\nbin\\x64\\debug\\test.bat\n```\n\n### Cross-Platform Validation\n```powershell\n# Documentation\nmkdocs build -f doc/mkdocs.yml\n\n# Code formatting (Windows)\n.\\FormatSource.ps1\n\n# Copyright header validation (reports expected issues in _deps/)\npython3 tools/devops/validate-copyright-headers.py\n\n# Distribution validation (may fail on networks without external access)\npython3 distributions/validate.py distributions/DistributionInfo.json\n```\n\n## Debugging and Logging\n\n### ETL Tracing (Windows Only)\n```powershell\n# Collect traces\nwpr -start diagnostics\\wsl.wprp -filemode\n# [reproduce issue]\nwpr -stop logs.ETL\n\n# Available profiles:\n# - WSL (default) - General WSL tracing\n# - WSL-Storage - Enhanced storage tracing\n# - WSL-Networking - Comprehensive networking tracing\n# - WSL-HvSocket - HvSocket-specific tracing\n# Example: wpr -start diagnostics\\wsl.wprp!WSL -filemode\n```\n\n### Log Analysis Tools\n- Use WPA (Windows Performance Analyzer) for ETL traces\n- Key providers: `Microsoft.Windows.Lxss.Manager`, `Microsoft.Windows.Subsystem.Lxss`\n- For graphical/audio (WSLg) issues, see `.github/copilot/wslg-logs.md`. `collect-wsl-logs.ps1` gathers WSLg logs (`/mnt/wslg`: weston.log, pulseaudio.log, wlog.log, stderr.log, versions.txt) into a `wslg/` folder using `wsl.exe --system --user root`; crash dumps (`%TEMP%\\wsl-crashes`, legacy `/mnt/wslg/dumps`) are only collected with `-Dump`. WSLg code lives in https://github.com/microsoft/wslg, not this repo.\n\n### Debug Console (Linux)\nAdd to `%USERPROFILE%\\.wslconfig`:\n```ini\n[wsl2]\ndebugConsole=true\n```\n\n### Common Debugging Commands\n- Debug shell: `wsl --debug-shell`\n- Collect WSL logs: `powershell diagnostics\\collect-wsl-logs.ps1`\n- Network logs: `powershell diagnostics\\collect-wsl-logs.ps1 -LogProfile networking`\n\n## Timing and Timeout Guidelines\n\n**NEVER CANCEL these operations — always wait for completion:**\n\n| Operation | Typical Duration | Minimum Timeout |\n|---|---|---|\n| Full Windows build | 20-45 minutes | 60+ minutes |\n| Full test suite | 30-60 minutes | 90+ minutes |\n| Unit test subset | 5-15 minutes | 30+ minutes |\n| Documentation build | ~0.5 seconds | 5+ minutes |\n| Distribution validation | 2-5 minutes | 15+ minutes |\n\n## CI/CD Integration\n\n### GitHub Actions\n- **distributions.yml** — Validates distribution metadata (Linux)\n- **documentation.yml** — Builds and deploys docs (Linux)\n- **modern-distributions.yml** — Tests modern distribution support\n\n## Development Environment Setup\n\n### Windows (Full Development)\n1. Install Visual Studio with required components (listed above)\n2. Install CMake 3.25+\n3. Enable Developer Mode\n4. Clone repository\n5. Run `cmake .` to generate solution\n\n### Linux (Documentation/Validation Only)\n1. Install Python 3.8+\n2. Install docs tools: `pip install mkdocs-mermaid2-plugin mkdocs`\n3. Clone repository\n4. Run validation commands as needed\n\nRemember: **This is a Windows-focused project**. While some tasks can be performed on Linux, full WSL development requires Windows with Visual Studio.\n\n<!-- File: .github/copilot/commit.md (Tokens: ~75 | Category: copilot-instructions) -->\n## Commit Message Guidelines for WSL\n\nThis repo has no strict commit message format. Follow these general practices:\n\n- Write a concise summary under 72 characters\n- Use imperative mood (\"Fix crash\" not \"Fixed crash\")\n- Reference GitHub issues with `(#123)` or `Fixes #123`\n- Add a body paragraph for non-obvious changes explaining *why*\n\n<!-- File: .github/copilot/localization-bugs.md (Tokens: ~3826 | Category: copilot-instructions) -->\n## Creating Localization Tracking Bugs (GCS Azure DevOps)\n\nCommunity members report localization problems in two ways: by filing a GitHub **issue** about a bad\ntranslation, or by opening a **pull request** that edits a localized file (the per-locale UI strings in\n`localization/strings/<locale>/Resources.resw`, or the per-locale Intune/group-policy templates in\n`intune/<locale>/WSL.adml`), or that adds a brand-new locale file. Both are valid signals and you should\nlook for **both** when triaging.\n\nEither way, the fix is handled by the Microsoft Global Collaboration Service (GCS) localization pipeline,\n**not** merged directly from GitHub: every non-`en-US` localized file is generated by the GCS team and\nregenerated downstream, so any translation edit merged here would be overwritten. (PRs that touch\nlocalized files should be declined with a pointer to `CONTRIBUTING.md`; only the `en-US` sources and the\nlanguage-neutral `intune/WSL.admx` live in this repo.) To route a report for review, file a tracking\n**Bug** in the GCS Azure DevOps project for each issue or PR.\n\n> **GCS requirement — be specific: list the exact resource IDs to fix.** The loc team will **not**\n> triage abstract reports. A bug that only names the file, language, and a few quoted strings gets\n> rejected (moved to the **More Info** state) because the team does not have capacity to parse a vague\n> report into the concrete strings that need work — that translation has to be done up front by the\n> filer. Every bug must therefore carry an explicit list of the **resource IDs** (the `name` attribute\n> of the `<data name=\"...\">` elements in `localization/strings/<locale>/Resources.resw`) that need\n> fixing. The gold-standard level of detail is **Bug 1223866** (`.../GlobalCollaborationService/Global%20Collaboration%20Service%20Project/_workitems/edit/1223866`):\n> for each resource ID it gives the current (bad) value and the proposed value, e.g.\n>\n> ```text\n> MessageDistroAlreadySet\n>   current:  Der Verteilungsname wurde bereits festgelegt.\n>   proposed: Der Distributionsname wurde bereits festgelegt.\n> ```\n\n### Deriving the resource-ID list\n\nHow you obtain the IDs depends on the report type:\n\n- **PR editing an existing locale file** — the changed resource IDs are exactly the `<data name>`\n  blocks whose `<value>` differs between the repo's current file and the PR head. Load both and diff\n  by name. The PR \"Files changed\" view already shows current→proposed for each, so post the **compact\n  ID list plus a link to the PR diff** rather than re-inlining every value (a 160-row inline table is\n  unwieldy; the PR diff is the source of truth for the old/new text).\n\n  ```powershell\n  # changed resource IDs between two Resources.resw files (master vs PR head)\n  function Get-ChangedIds($baseResw, $headResw) {\n    function Load($p) { $x = [xml](Get-Content $p -Raw); $h = @{}; foreach ($d in $x.root.data) { $h[$d.name] = $d.value }; $h }\n    $b = Load $baseResw; $h = Load $headResw\n    $h.Keys | Where-Object { $b[$_] -ne $h[$_] }\n  }\n  ```\n\n- **Issue citing line numbers** (e.g. `Resources.resw#L185`) — fetch the file **at the exact commit\n  the issue links to**, then walk upward from each cited line to the nearest `data name=\"...\"` to get\n  the enclosing resource ID. Line numbers drift between commits, so always pin to the linked SHA.\n\n- **Issue quoting bad strings** — grep the locale `Resources.resw` for each quoted value to find the\n  `<data name>` that contains it. One displayed term often maps to several IDs (`.Header`,\n  `.Description`, `...TextBox.AutomationProperties.Name`/`.HelpText`, shell-nav `.Content`), so list\n  them all.\n\n- **PR adding a brand-new locale** — this is a net-new whole-file contribution, **not** a correction\n  list, so there is nothing pre-existing to \"fix\". Give the team the actionable file-level items\n  instead: (1) hard parity failures vs `en-US` that block `tools/devops/validate-localization.py` —\n  placeholder/insert-count mismatches and missing `{Locked=\"...\"}` tokens, listed by resource ID;\n  (2) the coverage gap (which `en-US` IDs are missing, and how many of N total); (3) any strings\n  present in the file but absent from `en-US` (obsolete — drop them); and (4) that a new locale needs\n  build registration, not just a file drop.\n\n### Coordinates\n\n| | |\n|---|---|\n| Org | `https://dev.azure.com/GlobalCollaborationService` |\n| Project | `Global Collaboration Service Project` |\n| Process | `GCS_Agile` |\n| Work item type | `Bug` |\n| Web \"create from template\" link | `https://dev.azure.com/GlobalCollaborationService/Global%20Collaboration%20Service%20Project/_workitems/create/Bug?templateId=b97df4d3-4106-4099-a3a9-1782b5891bec` |\n\n### Required fields (and known-good values for a community loc PR)\n\nThe Bug type has several required custom picklist fields. Values that work for \"community translation PR\nneeds review\":\n\n| Field (reference name) | Value |\n|---|---|\n| `System.Title` | `WSL: Review community <locale> localization report (GitHub #<issue or PR>)` |\n| `System.Description` / `Microsoft.VSTS.TCM.ReproSteps` | GitHub link + scope + action (see below) |\n| `Custom.IssueType` | `Incorrect Translation` |\n| `Custom.ProductArea` | `Software` |\n| `Custom.How_Found` | `Community` |\n| `Custom.Severity_Impact` | `S3 - Medium` (field default) |\n| `Microsoft.VSTS.Common.ValueArea` | `Business` (field default) |\n| `Custom.HaveyouattachedEnglishandlocalizedscreenshots` | `No` (allowed: `Yes`/`No`; no default — must be set) |\n| `Custom.Language` | picklist — see mapping below (the WSL locale code is **not** accepted) |\n\nOther required custom flags (`Custom.BugBlocked`, `Custom.XLanguage`,\n`Custom.OverrideMaxStringsThreshold`, `Custom.SkipSourceAudioFilesValidation`,\n`Custom.DidCopilotrespondinthesamelanguage`, `Custom.Copilotattachallfiles`) default to `0` and\nauto-fill; leave them unset.\n\n### `Custom.Language` mapping (picklist values, not locale codes)\n\n`Custom.Language` is a 148-value picklist keyed by display name. Map the WSL `Resources.resw` locale\nfolder to the picklist value:\n\n| WSL locale | `Custom.Language` value |\n|---|---|\n| `es-ES` | `Spanish (Spain, International Sort)` |\n| `zh-CN` | `Chinese (Simplified) - PRC` |\n| `el-GR` | `Greek (Greece)` |\n| `tr-TR` | `Turkish (Turkey)` |\n\nFor other locales, list the allowed values and match by display name:\n\n```powershell\n$org=\"https://dev.azure.com/GlobalCollaborationService\"\n$projEnc=\"Global%20Collaboration%20Service%20Project\"\n$res=\"499b84ac-1321-427f-aa17-267ca6975798\"   # Azure DevOps AAD resource id\naz rest --method get --resource $res `\n  --uri \"$org/$projEnc/_apis/wit/workitemtypes/Bug/fields/Custom.Language?`$expand=all\" `\n  --headers \"Accept=application/json;api-version=7.1-preview.3\" |\n  ConvertFrom-Json | Select-Object -ExpandProperty allowedValues\n```\n\n### Suggested description body\n\n```\nCommunity localization report on GitHub microsoft/WSL needs review by the loc pipeline.\n\nGitHub: https://github.com/microsoft/WSL/<issues or pull>/<number>\nLanguage: <locale>\nType: <issue reporting a bad translation | PR editing the localized file>\nScope: localized file (localization/strings/<locale>/Resources.resw or intune/<locale>/WSL.adml).\n  For a PR: <edits to existing | brand-new>, +A/-B, 1 file. For an issue: the specific string(s) reported.\nResource IDs to fix: <explicit list of <data name> keys - see the dedicated comment with the full\n  list, or paste it here>. This is required; see \"Deriving the resource-ID list\" above.\nAction: validate placeholder/locked-token parity vs en-US (tools/devops/validate-localization.py),\nthen incorporate or advise. New locales additionally need build registration, not just a file drop.\nNote: do not merge the GitHub PR - localized files are regenerated by GCS and edits here are overwritten.\n```\n\nThe resource-ID list is the part GCS actually needs. If it is long, post it as a work-item **comment**\n(ADO comments accept HTML and can be edited in place via `PATCH .../comments/<id>`) and reference that\ncomment from the description.\n\n### Creating via CLI (`az boards`)\n\nRequires the `azure-devops` az extension and an identity with **create/edit work item** permission in\nthe project (see caveat below).\n\n```powershell\n$org=\"https://dev.azure.com/GlobalCollaborationService\"\n$proj=\"Global Collaboration Service Project\"\n$area=\"Global Collaboration Service Project\\Global\\Windows\"   # working area path, see Permissions gotcha\n$desc=\"Community es-ES localization PR. PR: https://github.com/microsoft/WSL/pull/14109 ...\"\naz boards work-item create --org $org --project $proj --type \"Bug\" `\n  --title \"WSL: Review community es-ES localization PR (GitHub #14109)\" `\n  --area \"$area\" --description $desc `\n  --fields \"Microsoft.VSTS.TCM.ReproSteps=$desc\" `\n           \"Custom.Language=Spanish (Spain, International Sort)\" `\n           \"Custom.IssueType=Incorrect Translation\" `\n           \"Custom.ProductArea=Software\" `\n           \"Custom.How_Found=Community\" `\n           \"Custom.Severity_Impact=S3 - Medium\" `\n           \"Microsoft.VSTS.Common.ValueArea=Business\" `\n           \"Custom.HaveyouattachedEnglishandlocalizedscreenshots=No\"\n```\n\n### Gotchas\n\n- **`az.cmd` eats `&` in URLs.** When using `az rest`, never put `&` (multiple query params) in\n  `--uri` on Windows — cmd truncates the URL there. Pass `api-version` via the **Accept header**\n  instead: `--headers \"Accept=application/json;api-version=7.1\"`, keeping at most one `?param` in the URI.\n- **Permissions are area-path-scoped, and the path matters.** Creating work items requires explicit rights on\n  the *specific area path*, not the project as a whole. The correct, durable path for WSL localization bugs is\n  `Global Collaboration Service Project\\Global\\Windows` (confirmed against existing manually-filed WSL loc\n  bugs). Always set `System.AreaPath` (or `--area`) to that path. A `@ntdev.microsoft.com` identity is denied\n  at the project root and most other paths (`TF237111: ... does not have permissions to save work items under\n  the specified area path`). Do NOT file under `...\\C and AI\\Unspecified`: an identity may briefly appear to\n  have access there, but bugs filed there get cleaned up and the access is not stable. To probe a path without\n  creating anything, POST with `?validateOnly=true`. If your identity lacks rights everywhere, create the bug\n  through the web template link above.\n- **`System.Description` is required, separately from repro steps.** The Bug type rejects a create with\n  `TF401320: Rule Error for field Description ... Required, InvalidEmpty` unless `System.Description` is set.\n  Set both `System.Description` and `Microsoft.VSTS.TCM.ReproSteps` (the same body is fine). When POSTing a\n  JSON-patch document via `az rest`, use newline-to-`<br>` so the HTML-rendered fields keep their line breaks.\n- **Picklist discovery.** Field allowed-values often don't expand through the plain field endpoint; use\n  `?$expand=all` on `.../workitemtypes/Bug/fields/<ref>` as shown above.\n- **\"Not found\" can mean \"no access,\" not \"doesn't exist.\"** WIQL and `GET .../workitems/<id>` honor ACLs:\n  a `CreatedBy=@me` query returning zero rows, or `TF401232: Work item <id> does not exist, or you do not\n  have permissions to read it`, often just means your identity can't read that area path. Don't assume the\n  bug was deleted. A gap in sequential work-item IDs is a tell that items were created but are now invisible\n  to you (e.g. filed under a path whose access got revoked, then reaped) - which is exactly why you should\n  stick to the durable `Global\\Windows` path above.\n- **Read the bug back after creating it.** Immediately `GET` each new work item id (or open the URL) to\n  confirm it's actually persisted and readable under your identity. A create that \"succeeds\" against a flaky\n  area path can vanish later; a read-back catches that while you can still re-file.\n- **Non-ASCII gets mangled, and `az` errors poison `ConvertFrom-Json`.** Locale content (Turkish, Greek, CJK)\n  comes back cp1252-garbled unless you set `[Console]::OutputEncoding=[System.Text.Encoding]::UTF8` first.\n  Also, `az` prints errors to the stream, so piping straight into `ConvertFrom-Json` throws on any failure;\n  capture with `Out-String` and parse, or check `$LASTEXITCODE`. Pass JSON-patch bodies via `--body \"@file\"`\n  (content type `application/json-patch+json`) rather than inline to dodge quoting hell.\n- **Don't inline huge diffs into a comment.** For a PR that touches many strings, post the resource-ID\n  list and link the PR \"Files changed\" page for the current→proposed values; a 100+ row HTML table\n  makes the bug unreadable and can bump against comment-size limits. ADO comments can be edited in\n  place (`PATCH .../comments/<id>?api-version=7.1-preview.4`), so trim/replace rather than re-posting.\n\n### After creating\n\nKeep the GitHub link in the ADO Bug's description/repro steps (it's already there from the body above) so the\nloc team can trace back to the report. Do **not** paste the internal ADO Bug ID into the public GitHub PR or\nissue. Then read each new bug back (see gotcha above) to confirm it persisted under `Global\\Windows`.\n\nIf GCS moves a bug to **More Info**, it almost always means the resource-ID detail is missing or too\nabstract: supply the explicit `<data name>` list (see \"Deriving the resource-ID list\"), then move the\nbug back to **Active** and reassign it to the requesting GCS reviewer.\n\n### What happens after you file (automated pipeline)\n\nFiling the Bug under `Global\\Windows` is usually the end of the manual work. A **Fabric Self Service** bot\n(`FabricClient-Prod`) automatically picks the Bug up and creates a **DTT (Direct-To-Translator) job** for the\nlocale, posting its progress as Bug discussion comments. So a stream of `FabricClient-Prod` comments is the\n**expected, healthy** path — not something a human has to act on:\n\n- `Bug picked up for processing by the Fabric Self Service process.`\n- `Successfully created 1 DTT Jobs: ... <locale> ...` → the report is now in the translation pipeline; **no\n  further action**.\n\nWatch for these exceptions, which **do** need action:\n\n- **New locale not onboarded.** If the locale isn't onboarded to **TDBuild** for the WSL subtenant\n  (`WindowsUndocking` / `LiftedWSL`), the DTT job can't be created and a human comments pointing you to file an\n  onboarding request at the **Global Services Hub** (`https://globalservices.powerappsportals.com/global/`).\n  This is GCS-side onboarding and is *separate from* (and in addition to) the WSL-repo build registration a new\n  locale needs. Greek (`el-GR`, GitHub #40244) hit exactly this.\n- **Oversized report.** A non-retriable `Rqf query exceeded threshold of 1000 words` failure means the report's\n  scope is too large; reduce the scope or set `Custom.OverrideMaxStringsThreshold` and re-file.\n\nIf you only see `FabricClient-Prod` \"Successfully created ... DTT Jobs\" comments, you're done.\n\n<!-- File: .github/copilot/review.md (Tokens: ~429 | Category: copilot-instructions) -->\n## Code Review Guidelines for WSL\n\nWhen reviewing code, enforce the conventions in `.github/copilot-instructions.md`. Focus especially on these high-risk areas:\n\n### ABI Safety (Critical)\nOnly the SDK-facing and public surfaces require a backward-compatible ABI. Every other COM interface (`wslc.idl`, `wslservice.idl`, etc.) is internal and non-stable: shipped in lockstep with its only clients, with the proxy/stub regenerated each build, so methods may be appended to those freely. Do **not** flag internal, non-stable interfaces.\n- **Flag** ABI-breaking changes (new, removed, or reordered methods, changed struct layouts) only in the stable surfaces: `WSLCCompat.idl` (the WSLC SDK-facing layer, which must stay backward compatible) and the public plugin API (`WSLPluginHooksV1` / `WSLPluginAPIV1` structs in `WslPluginApi.h`).\n- **Do not flag** new methods appended to internal, non-stable interfaces such as `IWSLCSession` in `wslc.idl`, or interfaces in `wslservice.idl`.\n\n### Resource Safety\n- **Flag** raw `CloseHandle()`, `delete`, `free()`, or manual resource cleanup — require WIL smart pointers\n- **Flag** missing `NON_COPYABLE()` / `NON_MOVABLE()` on classes that hold resources\n- **Flag** lock usage without `_Guarded_by_()` SAL annotations\n\n### User-Facing Changes\n- **Flag** hardcoded English strings — require `Localization::MessageXxx()` and Resources.resw entry\n- **Flag** new `.wslconfig` settings without corresponding Resources.resw localization string\n- **Flag** silent fallback on invalid config values — require `EMIT_USER_WARNING()`\n\n### Error Handling\n- **Flag** bare `if (FAILED(hr))` — require WIL macros\n- **Flag** silently swallowed errors — require `CATCH_LOG()` or `LOG_IF_FAILED()`\n- **Flag** telemetry events missing privacy data tags\n\n<!-- File: .github/copilot/test.md (Tokens: ~721 | Category: copilot-instructions) -->\n## Test Generation Guidelines for WSL\n\nWhen generating tests for this repository, follow these patterns:\n\n### Framework\nTests use TAEF (Test Authoring and Execution Framework). Always include `\"Common.h\"`.\n\n### Test Class Structure\n```cpp\n#include \"Common.h\"\n\nnamespace MyFeatureTests\n{\nclass MyFeatureTests\n{\n    WSL_TEST_CLASS(MyFeatureTests)\n\n    TEST_CLASS_SETUP(TestClassSetup)\n    {\n        VERIFY_ARE_EQUAL(LxsstuInitialize(FALSE), TRUE);\n        return true;\n    }\n\n    TEST_CLASS_CLEANUP(TestClassCleanup)\n    {\n        LxsstuUninitialize(FALSE);\n        return true;\n    }\n\n    TEST_METHOD(DescriptiveTestName)\n    {\n        // Test implementation\n    }\n};\n}\n```\n\n### Key Rules\n- Use `WSL_TEST_CLASS(Name)` — never raw `BEGIN_TEST_CLASS`\n- Setup/cleanup methods must `return true` on success\n- Use `VERIFY_*` macros for assertions — never `assert()` or exceptions for test validation\n\n### Assertion Macros\n- `VERIFY_ARE_EQUAL(expected, actual)` — value equality\n- `VERIFY_ARE_NOT_EQUAL(a, b)` — value inequality\n- `VERIFY_IS_TRUE(condition)` — boolean check\n- `VERIFY_IS_FALSE(condition)` — negative boolean check\n- `VERIFY_IS_NULL(ptr)` — null check\n- `VERIFY_IS_NOT_NULL(ptr)` — non-null check\n- `VERIFY_WIN32_BOOL_SUCCEEDED(expr)` — Win32 BOOL result\n- `VERIFY_SUCCEEDED(hr)` — HRESULT success\n\n### Logging in Tests\n- `LogInfo(fmt, ...)` — informational messages\n- `LogError(fmt, ...)` — error messages\n- `LogWarning(fmt, ...)` — warnings\n- `LogPass(fmt, ...)` — explicit pass messages\n- `LogSkipped(fmt, ...)` — skip messages\n\n### Conditional Skipping\nAdd skip macros at the start of a test method body when the test only applies to certain environments:\n```cpp\nTEST_METHOD(Wsl2SpecificTest)\n{\n    WSL2_TEST_ONLY();\n    // ... test code ...\n}\n```\n\nAvailable skip macros:\n- `WSL1_TEST_ONLY()` — skip unless WSL1\n- `WSL2_TEST_ONLY()` — skip unless WSL2\n- `SKIP_TEST_ARM64()` — skip on ARM64\n- `SKIP_TEST_UNSTABLE()` — skip known-flaky tests\n- `WINDOWS_11_TEST_ONLY()` — skip on pre-Windows 11\n- `WSL_TEST_VERSION_REQUIRED(version)` — skip if WSL version too old\n\n### RAII Test Helpers\n- `WslKeepAlive` — prevents UVM timeout during long-running tests; create at test start\n- `WslConfigChange` — RAII wrapper that applies a temporary `.wslconfig` and restores the original on destruction:\n```cpp\nTEST_METHOD(TestWithCustomConfig)\n{\n    WslConfigChange config(L\"[wsl2]\\nmemory=4GB\\n\");\n    // ... test with custom config ...\n    // Original .wslconfig restored when config goes out of scope\n}\n```\n\n### Memory in Tests\n- Use `ALLOC(size)` / `FREE(ptr)` macros for direct heap allocation in tests\n- Prefer RAII wrappers and smart pointers for production-like code paths\n\n### Test Naming\n- Use descriptive PascalCase names that describe the scenario: `CreateInstanceWithInvalidGuidFails`, `EchoTest`, `MountPlan9Share`\n- Group related tests in the same test class\n\n<!-- File: .github/copilot/wslg-logs.md (Tokens: ~1213 | Category: copilot-instructions) -->\n# Analyzing WSLg logs\n\nWSLg is the component that runs graphical (GUI) and audio Linux applications on WSL. Its\nsource lives in a separate repository: https://github.com/microsoft/wslg. The canonical list\nof diagnostics to request for a WSLg bug is the WSLg repo bug report template\n(`.github/ISSUE_TEMPLATE/bug_report.yml` in microsoft/wslg).\n\n`diagnostics/collect-wsl-logs.ps1` collects the logs into a `wslg/` subfolder of the log archive\n(via `wsl.exe --system --user root`, with a timeout so a wedged service can't hang collection), so a\nstandard WSL log collection already contains the log files below. Crash dumps (`dumps/`,\n`wsl-crashes/`) are only collected when the script is run with `-Dump`.\n\n## Architecture (just enough to read the logs)\n\nWSLg runs a **system distro** (a small Azure Linux VM, separate from the user distro) that hosts:\n- **weston** (Wayland compositor) with the `rdp-backend.so` / `rdprail-shell.so` modules\n- **Xwayland** for X11 apps\n- **pulseaudio** with an RDP sink/source for audio\n- **FreeRDP** to stream the surfaces over an hvsocket to the Windows RDP client (`msrdc.exe`)\n\n`weston.log` and `wlog.log` are written by weston/FreeRDP, `pulseaudio.log` by pulseaudio, and\n`stderr.log` is the combined stderr of `WSLGd` and the processes it launches.\n\n## Files (in the `wslg/` folder, sourced from `/mnt/wslg`)\n\n| File | Contents |\n|---|---|\n| `versions.txt` | WSLg version, architecture, build date, component git hashes (weston, FreeRDP, mesa, pulseaudio) |\n| `weston.log` | Weston compositor + RDP backend log |\n| `wlog.log` | FreeRDP (WLog) log |\n| `pulseaudio.log` | PulseAudio log |\n| `stderr.log` | `WSLGd` and child-process stderr |\n| `dumps/` | Legacy WSLg crash dumps (older builds only; collected with `-Dump`) |\n| `wsl-crashes/` | Host-side WSLg crash dumps copied from `%TEMP%\\wsl-crashes` (newer builds, e.g. `core.weston`; collected with `-Dump`) |\n\n## Reading tips and common signatures\n\n- **`weston.log` is truncated on every boot.** Weston is started with `--log=/mnt/wslg/weston.log`\n  and opens it truncating, so the file only ever contains the **latest** system-distro boot. To\n  tell whether weston restarted, compare the boot timestamp on the first line (`weston 9.0.0 ...`)\n  across snapshots, or correlate with `dmesg`.\n\n- **System distro cycling / teardown.** In `dmesg` (collected via the ETL `GuestLog` events or\n  the debug console), this pair means the WSLg system distro's `init` exited and the distro was\n  torn down (idle timeout or shutdown), which also restarts weston:\n  ```\n  Exception: Operation canceled @p9io.cpp:258 (AcceptAsync)\n  WSL (1 - init()) ERROR: InitEntryUtilityVm:2551: Init has exited. Terminating distribution\n  ```\n  Repeating every ~25-60s with no GUI client attached is usually normal idle teardown, not a crash.\n  A genuine weston crash instead leaves a core dump in `wsl-crashes/` (or `dumps/`).\n\n- **No GPU acceleration (software rendering).** This means the virtual GPU (`/dev/dxg`, d3d12 mesa)\n  is not usable, so rendering falls back to CPU:\n  ```\n  Xwayland glamor: GBM Wayland interfaces not available\n  Failed to initialize glamor, falling back to sw\n  ```\n  Investigate GPU driver presence, `/dev/dxg`, and the `mesa`/`d3d12` stack if the user reports\n  black windows, slow rendering, or missing 3D.\n\n- **Audio sink not connected (usually benign at boot).** Expected until an RDP/audio client attaches:\n  ```\n  [rdp-sink] RDP Sink - Trying to connect to /mnt/wslg/PulseAudioRDPSink\n  [rdp-sink] Connected failed\n  ```\n  If it persists while audio is actively broken, look at the RDP client (`msrdc`) audio channel.\n\n- **Mostly-benign startup noise** (not a root cause on its own):\n  - `WSLGd: Exception: No such file or directory @FontMonitor.cpp:280` - font share not mounted.\n  - `XDG_RUNTIME_DIR \"/mnt/wslg/runtime-dir\" ... mode 040777` (should be 0700) - common warning.\n  - `dbus: Unknown username \"pulse\"` / `Option \"-listen\" is deprecated` - harmless.\n\n## When to escalate to the WSLg repo\n\nWSLg code is not in this repository. Fixes to weston, FreeRDP, pulseaudio, or the RDP backend\nbelong in https://github.com/microsoft/wslg. Use a commit-pinned permalink when referencing files\nthere so the link does not drift, e.g.\n`https://github.com/microsoft/wslg/blob/<commit-sha>/<path>`.\n</yakaai_skills>"}