Skip to content

winui-analyzer: add winui-analyze driver + B1-B4 rule/mapping coverage - #140

Open
shisan (qiutongMS) wants to merge 8 commits into
stagingfrom
user/qiutongshen/winui-analyzer-core
Open

winui-analyzer: add winui-analyze driver + B1-B4 rule/mapping coverage#140
shisan (qiutongMS) wants to merge 8 commits into
stagingfrom
user/qiutongshen/winui-analyzer-core

Conversation

@qiutongMS

@qiutongMS shisan (qiutongMS) commented Jul 30, 2026

Copy link
Copy Markdown

What this PR adds

Two things, source-only, for the winui-analyzer:

  1. Analyzer rule / mapping coverage (B1-B4): expanded UWP -> Windows App SDK API/feature mappings, a crash-tier classification (MigrationTiers), a UWP-only XAML control rule (WUI2003), and WUI0003 DependencyObject.Dispatcher member-access detection. +63 tests, all green.
  2. A standalone winui-analyze driver (Microsoft.WindowsAppSDK.Analyzers.Driver): a small console host that runs the analyzers over a source tree and emits a stable v1.0 JSON migration plan to stdout — per-file disposition + per-line findings + severity + fix references + feature area.

Why the driver exists

The winui-analyzer is a Roslyn analyzer — normally it runs inside the compiler during a build (that's how the winui-dev-workflow skill uses it today: injected into dotnet build).

That doesn't work for UWP -> WinUI 3 migration: the source is still UWP, references APIs that don't exist in WinUI, and does not compile mid-migration. You can't run a build-time analyzer on code that won't build — and you want the findings up front, as a plan, before touching anything.

The driver solves exactly that: it builds an in-memory Roslyn compilation from the still-UWP source (no restore, no build), runs the same analyzers, and serializes the diagnostics to JSON. So it's the analyzer's out-of-build entry point: same rules, but usable on non-compiling source and machine-readable.

What this PR intentionally does NOT include

  • No skill changes, no CLI changes, no committed tool binary. This is analyzer + driver source only.
  • No decision baked in about how the driver is distributed or who invokes it. The published-and-packaged form and the caller wiring live in a follow-up PR so this analyzer/driver work can be reviewed and stabilized on its own.

How I intend to use the output (for reviewers / collaborators)

The winui-uwp-migration skill will run this driver at Step 0 of a migration to produce the JSON plan, then drive the migration off it:

winui-analyze <uwp-source-dir> --from-uwp  >  migration-plan.json

The plan replaces the old approach of injecting // TODO markers into source: instead of mutating files, the skill reads an external, structured plan (which files to migrate, per-line findings, fix references). Steps 1-3 of the skill consume that plan unchanged.

Concretely, the follow-up will publish this driver (framework-dependent; it embeds Roslyn so it can't be AOT-trimmed) and ship it as a self-contained skill payload, invoked directly — mirroring the existing winui-design skill, which ships and directly calls winui-search.exe. This distribution/caller detail is deliberately out of scope here and open to alignment — this PR only lands the analyzer capability and the driver that exposes it.

Testing

  • dotnet test Microsoft.WindowsAppSDK.Analyzers.Tests -> 63/63 passed (Release).
  • dotnet build ...Analyzers.Driver -> build succeeded, 0 warnings.
  • Driver smoke test on a sample UWP tree -> emits valid v1.0 plan JSON, exit 0.

* run pr-validation on staging prs

* winui-search: batched CLI, background refresh, ranking + Gallery/Toolkit fetch upgrades (#83)

* winui-search: batched CLI, background refresh, ranking + Gallery/Toolkit fetch upgrades

* fix comments

* fix time

* fix comments

* change verions back

* fix local pr review

---------

Co-authored-by: Nikola Metulev <nmetulev@users.noreply.github.com>

* deps: Bump coverlet.collector from 10.0.0 to 10.0.1 (#87)

---
updated-dependencies:
- dependency-name: coverlet.collector
  dependency-version: 10.0.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Nikola Metulev <nmetulev@users.noreply.github.com>

* winui: window sizing rubric, screenshot validation, anti-self-delegation (#84)

* winui: window sizing rubric, screenshot validation, anti-self-delegation

Three connected improvements to the WinUI dev skills, motivated by repeated failure modes when building small apps:

1. winui-design SKILL.md - new Step 4 'Size the Window to the App'
   WinUI 3 has no SizeToContent, so apps default to ~1024x768 regardless
   of content - which makes utilities feel oversized. Adds an 8-step
   reasoning rubric (inventory rows, derive widest-row width, sum heights,
   round up, sanity-check ranges, prefer compact-but-not-clipping,
   aspect-ratio follows content, validate after running) and a worked
   example. Old 'Step 4: Design Anti-Patterns' renumbered to Step 5.

2. winui-ui-testing SKILL.md - new Step 3.5 'Look at the Screenshots'
   UIA assertions can't see clipping, overlap, cramped layout, or theming
   bugs. Adds explicit guidance to capture screenshots at multiple states
   (initial, post-interaction, per mode), view them after each run, and
   apply a visual checklist. Test-script template now creates a
   screenshots/ directory and captures intermediate state, not just a
   single final shot.

3. winui-dev.agent.md - 'Do The Work Yourself' section
   Agents kept re-delegating user requests to a fresh winui-dev sub-agent,
   wasting context and hiding progress. Adds an explicit prohibition
   against self-delegation while still permitting narrow helpers (explore
   for unfamiliar codebases, rubber-duck for plan critique).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* winui-design: replace PInvoke.User32 with framework DllImport; drop misleading fallback

The DPI-aware snippet in Step 4 had two real correctness issues that surfaced
in PR review and were confirmed by an empirical two-monitor test:

1. PInvoke.User32.GetDpiForWindow is a third-party NuGet not in the default
   WinUI 3 scaffold; agents copying the snippet hit "type or namespace
   PInvoke not found". Replace with a one-line [DllImport("user32.dll")] —
   no NuGet, no CsWin32 source-generator plumbing, works in the constructor.

2. SetTitleBar(AppTitleBar) referenced an XAML element the snippet never
   declares; orthogonal to sizing anyway. Removed.

Also drop the "Simpler fallback if PInvoke.User32 isn't available (ignores
DPI; fine for prototypes)" block — the empirical test showed AppWindow.Resize
takes physical pixels, so Resize(new SizeInt32(460, 860)) on a 1.25-scale
monitor (the default on many Windows laptops) produces only ~368x688 DIPs of
usable space and guarantees the clipping the rubric is designed to prevent.
The "fallback" was actively misleading. Replaced with a one-line "Why this
shape" explaining why XamlRoot.RasterizationScale (the managed WinUI 3 API)
isn't viable here (null in ctor, stale after AppWindow.Move).

Strengthened the "Pattern" header with the concrete failure mode so future
readers see why the DPI math is needed, not just that it's needed.

Also fixes a small bug in winui-dev.agent.md: "rubber-duck" was named as if
it were a real agent_type. Rephrased to "a general-purpose agent for a
rubber-duck critique" so the named agent_type is valid.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* winui-design: extract worked example to references/, dedupe visual checklist with winui-ui-testing

M2: The focus-timer walkthrough (460 x 860 derivation + 440 x 720 anti-pattern)
moves out of SKILL.md prose and into references/window-sizing-examples.md, with
SKILL.md keeping only a 1-line schematic of the rubric and a pointer to the
reference. Concrete worked numbers stay out of every loaded skill payload but
remain on-demand when an agent wants a full example to anchor against.

M6: Step 4 step 8's bulleted symptom list (5 bullets that were a strict subset
of the 9-item visual checklist in winui-ui-testing Step 3.5) collapses to a
1-paragraph pointer with inline symptom hints. The authoritative checklist
lives in winui-ui-testing, which is the skill that owns 'look at screenshots'.

Net: -11 / +50 (the +50 is the new on-demand reference file, not loaded by
default), with no change in covered guidance.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* winui: ultra-lean rewrite of window-sizing + screenshot-validation + anti-self-delegation prose

Apply the Team Lead Test more aggressively across all three files.
Cuts redundant enforcement, scenario-specific filler, and restated rubric
positives. Preserves every operational imperative.

winui-dev.agent.md (anti-self-delegation): 11 → 2 lines. The two banned
sub-types collapse into one parenthetical; the scoped-helpers ✅ shrinks to
one clause; the redundant closing 'if you catch yourself' paragraph drops
(the rule above it already says it).

winui-ui-testing/SKILL.md (Step 3.5): 33 → ~16 lines. Drops the duplicate
script example (the State Screenshots block in the script template above
already shows the pattern), the 3-bullet 'what counts as a state' list
(one sentence covers it), and the 'How to view' paragraph (tool-agnostic:
the agent picks its own view tool). Visual checklist trimmed from 9 → 9
items but with one merged pair (right-edge + overlap kept as separate
bullets after all) and one new item added: 'Content uses the available
width — no asymmetric dead zones' covers the bug where content gets
pinned to one edge with empty space on the other.

winui-design/SKILL.md (Step 4): 76 → ~30 lines. The 8-step rubric collapses
to one paragraph + a sanity-check list — the formula Sigma(row heights)
forces enumeration without needing a dedicated 'inventory' step, 'widest
row' encodes max-not-average, and 'round up' speaks for itself. Drops the
aspect-ratio step (tall→portrait is obvious), the 'compactness vs clipping'
step (subsumed by 'round up — clipped is worse'), and the 6-bullet
Anti-patterns section (5 of 6 restated the rubric's positives; the one
novel trap — Width on root Grid clips, not sizes — folds into a one-line
note after the snippet). The 3-line 'Pattern — apply the size you derived'
intro collapses to one line. Snippet using-statement comments removed.
Closing line goes tool-agnostic: 'Validate visually after build via
winui-ui-testing Step 3.5' (no longer says 'capture a screenshot' — that's
a layering violation, design owns the rubric, testing owns the validation
mechanism). 'Iterate the size or layout' covers both grow-the-window and
fix-asymmetric-padding failure modes.

Net for default-loaded payloads: -58 lines on top of the previous M2+M6
commit, total PR addition shrinks from +176 to +88 lines (-50%).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* winui-design: drop window-sizing-examples reference, make ui-testing validation user-opt-in

The reference file was 47 lines of one focus-timer instantiation of a
2-line formula. An LLM agent given the formula can derive any layout
without seeing a worked example first — 'see one, do one' is human
pedagogy, not LLM pedagogy. A single example also risks anchoring
toward focus-timer-shaped solutions.

Drop the file, drop the references-table row, drop the trailing 'See
references/...' sentence in Step 4. The rubric stands on its own.

Also reframe the Step 4 closing line: instead of prescribing
'validate visually after build' (which would auto-trigger the
ui-testing pipeline — spawn the app, capture UIA, take screenshots,
run the checklist), make it user-opt-in: 'If the user asks for UI
validation, see winui-ui-testing Step 3.5'. This matches the policy
already stated in winui-dev.agent.md that the user might ask for
ui-testing 'if desired only'. The ui-testing skill is expensive to
run; it shouldn't be the default follow-up to every window-sizing
exercise.

Net: -49 lines of repo (47 file + 2 default-loaded payload), no loss
of operational guidance.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

---------

Co-authored-by: Nikola Metulev <711864+nmetulev@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Back-merge main into staging after 0.3.1 (+ backmerge/* CI fix) (#92)

* Release 0.3.1 (#90)

* run pr-validation on staging prs

* winui-search: batched CLI, background refresh, ranking + Gallery/Toolkit fetch upgrades (#83)

* winui-search: batched CLI, background refresh, ranking + Gallery/Toolkit fetch upgrades

* fix comments

* fix time

* fix comments

* change verions back

* fix local pr review

---------

Co-authored-by: Nikola Metulev <nmetulev@users.noreply.github.com>

* deps: Bump coverlet.collector from 10.0.0 to 10.0.1 (#87)

---
updated-dependencies:
- dependency-name: coverlet.collector
  dependency-version: 10.0.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Nikola Metulev <nmetulev@users.noreply.github.com>

* winui: window sizing rubric, screenshot validation, anti-self-delegation (#84)

* winui: window sizing rubric, screenshot validation, anti-self-delegation

Three connected improvements to the WinUI dev skills, motivated by repeated failure modes when building small apps:

1. winui-design SKILL.md - new Step 4 'Size the Window to the App'
   WinUI 3 has no SizeToContent, so apps default to ~1024x768 regardless
   of content - which makes utilities feel oversized. Adds an 8-step
   reasoning rubric (inventory rows, derive widest-row width, sum heights,
   round up, sanity-check ranges, prefer compact-but-not-clipping,
   aspect-ratio follows content, validate after running) and a worked
   example. Old 'Step 4: Design Anti-Patterns' renumbered to Step 5.

2. winui-ui-testing SKILL.md - new Step 3.5 'Look at the Screenshots'
   UIA assertions can't see clipping, overlap, cramped layout, or theming
   bugs. Adds explicit guidance to capture screenshots at multiple states
   (initial, post-interaction, per mode), view them after each run, and
   apply a visual checklist. Test-script template now creates a
   screenshots/ directory and captures intermediate state, not just a
   single final shot.

3. winui-dev.agent.md - 'Do The Work Yourself' section
   Agents kept re-delegating user requests to a fresh winui-dev sub-agent,
   wasting context and hiding progress. Adds an explicit prohibition
   against self-delegation while still permitting narrow helpers (explore
   for unfamiliar codebases, rubber-duck for plan critique).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* winui-design: replace PInvoke.User32 with framework DllImport; drop misleading fallback

The DPI-aware snippet in Step 4 had two real correctness issues that surfaced
in PR review and were confirmed by an empirical two-monitor test:

1. PInvoke.User32.GetDpiForWindow is a third-party NuGet not in the default
   WinUI 3 scaffold; agents copying the snippet hit "type or namespace
   PInvoke not found". Replace with a one-line [DllImport("user32.dll")] —
   no NuGet, no CsWin32 source-generator plumbing, works in the constructor.

2. SetTitleBar(AppTitleBar) referenced an XAML element the snippet never
   declares; orthogonal to sizing anyway. Removed.

Also drop the "Simpler fallback if PInvoke.User32 isn't available (ignores
DPI; fine for prototypes)" block — the empirical test showed AppWindow.Resize
takes physical pixels, so Resize(new SizeInt32(460, 860)) on a 1.25-scale
monitor (the default on many Windows laptops) produces only ~368x688 DIPs of
usable space and guarantees the clipping the rubric is designed to prevent.
The "fallback" was actively misleading. Replaced with a one-line "Why this
shape" explaining why XamlRoot.RasterizationScale (the managed WinUI 3 API)
isn't viable here (null in ctor, stale after AppWindow.Move).

Strengthened the "Pattern" header with the concrete failure mode so future
readers see why the DPI math is needed, not just that it's needed.

Also fixes a small bug in winui-dev.agent.md: "rubber-duck" was named as if
it were a real agent_type. Rephrased to "a general-purpose agent for a
rubber-duck critique" so the named agent_type is valid.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* winui-design: extract worked example to references/, dedupe visual checklist with winui-ui-testing

M2: The focus-timer walkthrough (460 x 860 derivation + 440 x 720 anti-pattern)
moves out of SKILL.md prose and into references/window-sizing-examples.md, with
SKILL.md keeping only a 1-line schematic of the rubric and a pointer to the
reference. Concrete worked numbers stay out of every loaded skill payload but
remain on-demand when an agent wants a full example to anchor against.

M6: Step 4 step 8's bulleted symptom list (5 bullets that were a strict subset
of the 9-item visual checklist in winui-ui-testing Step 3.5) collapses to a
1-paragraph pointer with inline symptom hints. The authoritative checklist
lives in winui-ui-testing, which is the skill that owns 'look at screenshots'.

Net: -11 / +50 (the +50 is the new on-demand reference file, not loaded by
default), with no change in covered guidance.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* winui: ultra-lean rewrite of window-sizing + screenshot-validation + anti-self-delegation prose

Apply the Team Lead Test more aggressively across all three files.
Cuts redundant enforcement, scenario-specific filler, and restated rubric
positives. Preserves every operational imperative.

winui-dev.agent.md (anti-self-delegation): 11 → 2 lines. The two banned
sub-types collapse into one parenthetical; the scoped-helpers ✅ shrinks to
one clause; the redundant closing 'if you catch yourself' paragraph drops
(the rule above it already says it).

winui-ui-testing/SKILL.md (Step 3.5): 33 → ~16 lines. Drops the duplicate
script example (the State Screenshots block in the script template above
already shows the pattern), the 3-bullet 'what counts as a state' list
(one sentence covers it), and the 'How to view' paragraph (tool-agnostic:
the agent picks its own view tool). Visual checklist trimmed from 9 → 9
items but with one merged pair (right-edge + overlap kept as separate
bullets after all) and one new item added: 'Content uses the available
width — no asymmetric dead zones' covers the bug where content gets
pinned to one edge with empty space on the other.

winui-design/SKILL.md (Step 4): 76 → ~30 lines. The 8-step rubric collapses
to one paragraph + a sanity-check list — the formula Sigma(row heights)
forces enumeration without needing a dedicated 'inventory' step, 'widest
row' encodes max-not-average, and 'round up' speaks for itself. Drops the
aspect-ratio step (tall→portrait is obvious), the 'compactness vs clipping'
step (subsumed by 'round up — clipped is worse'), and the 6-bullet
Anti-patterns section (5 of 6 restated the rubric's positives; the one
novel trap — Width on root Grid clips, not sizes — folds into a one-line
note after the snippet). The 3-line 'Pattern — apply the size you derived'
intro collapses to one line. Snippet using-statement comments removed.
Closing line goes tool-agnostic: 'Validate visually after build via
winui-ui-testing Step 3.5' (no longer says 'capture a screenshot' — that's
a layering violation, design owns the rubric, testing owns the validation
mechanism). 'Iterate the size or layout' covers both grow-the-window and
fix-asymmetric-padding failure modes.

Net for default-loaded payloads: -58 lines on top of the previous M2+M6
commit, total PR addition shrinks from +176 to +88 lines (-50%).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* winui-design: drop window-sizing-examples reference, make ui-testing validation user-opt-in

The reference file was 47 lines of one focus-timer instantiation of a
2-line formula. An LLM agent given the formula can derive any layout
without seeing a worked example first — 'see one, do one' is human
pedagogy, not LLM pedagogy. A single example also risks anchoring
toward focus-timer-shaped solutions.

Drop the file, drop the references-table row, drop the trailing 'See
references/...' sentence in Step 4. The rubric stands on its own.

Also reframe the Step 4 closing line: instead of prescribing
'validate visually after build' (which would auto-trigger the
ui-testing pipeline — spawn the app, capture UIA, take screenshots,
run the checklist), make it user-opt-in: 'If the user asks for UI
validation, see winui-ui-testing Step 3.5'. This matches the policy
already stated in winui-dev.agent.md that the user might ask for
ui-testing 'if desired only'. The ui-testing skill is expensive to
run; it shouldn't be the default follow-up to every window-sizing
exercise.

Net: -49 lines of repo (47 file + 2 default-loaded payload), no loss
of operational guidance.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

---------

Co-authored-by: Nikola Metulev <711864+nmetulev@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Release 0.3.1

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: Nikola Metulev <711864+nmetulev@users.noreply.github.com>
Co-authored-by: leileizhang <leilzh@microsoft.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* release: introduce backmerge/* convention and fix CI for back-merge PRs

- version-sync skips backmerge/* (legitimately carries main's version-bump
  commit forward into staging).
- staging-up-to-date now checks PR head contains every commit on main, not
  current staging — strictly stronger, and passes naturally for backmerge PRs
  (the chicken-and-egg before required staging to already contain main before
  the very PR that would bring it there could merge).
- Document backmerge/* branch convention in CONTRIBUTING.md and RELEASING.md.
- Update hotfix back-merge reminder issue body to use the new convention.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* ci: force re-run on backmerge/0.3.1 (stale check from pre-rename)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: Nikola Metulev <711864+nmetulev@users.noreply.github.com>
Co-authored-by: leileizhang <leilzh@microsoft.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Trimming design skill (#96)

* winui-design: clean-room rewrite from public sources, ~60% size reduction

Rebuilt the skill from scratch using only public Microsoft Learn design
docs (learn.microsoft.com/en-us/windows/apps/design/) and the WinUI
Gallery (github.com/microsoft/WinUI-Gallery). Independent fresh-design
experiment confirmed both topic coverage and content density.

Structure (29 KB total, down from 73 KB):
- SKILL.md                              (always loaded)
- references/control-selection.md       (control/pattern picking)
- references/theme-accessibility.md     (brushes, theme dicts, HC, a11y)
- references/layout-review.md           (page design, responsive, typography)
- references/sources.md                 (public source URLs)

Inline runnable samples are deferred to winui-search.exe (already shipped
with the skill); exhaustive brush catalogues are deferred to Microsoft
Learn. Unique high-signal items preserved:
- WinUI 3 window-sizing rubric + GetDpiForWindow DllImport
- TextBox x:Bind TwoWay + UpdateSourceTrigger=PropertyChanged gotcha
- Attached-property C# setter pattern (vs object-initializer trap)
- Acrylic BackgroundSizing + ThemeShadow Translation/padding rules

Verification: line-overlap scan against windows-hivemind/windows-xaml
plugin shows 9 lines of accidental match across all 5 files, all of which
are syntactically-required XAML scaffolding tags and InitializeComponent()
— zero copyrightable content shared.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* winui-design: re-graft 3 SKILL.md items + add brushes-and-icons reference

Grafted back from public Microsoft Learn sources after audit identified
high-value losses worth restoring:

SKILL.md:
- App-shape anchors table with Reference-App column (Settings, Terminal,
  File Explorer, Dev Home, Calculator)
- x:Bind static-method pattern for bool->Visibility, with explicit
  'never use Converter={x:Null}' runtime-crash warning
- Anti-patterns table replaces bullet list (13 rows, contrastive)

New reference:
- references/brushes-and-icons.md (12 KB): brush catalogue + IconElement
  taxonomy, sourced from learn.microsoft.com xaml-theme-resources and
  design/style/icons pages

Total skill now 43.7 KB (vs 51.5 KB original = 15% smaller, vs 29 KB
after the initial trim = + grafted high-value content).

Verified zero prose overlap with windows-xaml plugin via 8-gram shingle
scan (only shared content is learn.microsoft.com URL fragments).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* winui-design: trim skill ~36% after 5-model review panel

A 5-model review panel (Sonnet 4.6, GPT-5.4, GPT-5.3-Codex, Opus 4.6,
Opus 4.7) unanimously rated the skill USEFUL-BUT-OVERSIZED and asked for
roughly half cut. This commit delivers that, focused on the consensus
findings.

SKILL.md (15.5 -> 10.1 KB):
- Cut typography section, generic a11y checklist, generic MVVM bullets,
  control-choice bias table, review-output-format ceremony, and fast-
  triage table — all duplicated training data or process-theater
- Added: sidebar XAML skeleton (NavigationView + SettingsCard +
  ScrollViewer), Mica/SystemBackdrop wiring with the don't-paint-root
  trap, CommunityToolkit.WinUI.Controls.SettingsControls package note,
  PaneDisplayMode enumeration — all were gaps the panel flagged
- Promoted the high-signal landmines (x:Bind OneTime default, TextBox
  UpdateSourceTrigger, attached-property setters, Converter={x:Null},
  acrylic+ThemeShadow) into a dedicated 'XAML landmines' section

references/control-selection.md: DELETED (~90% duplicated SKILL.md;
unique custom-UI gate merged into anti-patterns)

references/sources.md: DELETED (bibliography agents can't click;
citations live inline in brushes-and-icons.md)

references/layout-review.md (4 -> 2.5 KB): kept page-planning template,
responsive-techniques table, state-coverage checklist, sidebar sizing
heuristics; cut typography (model knows the type ramp), spacing
duplication, navigation review, XAML binding duplication

references/theme-accessibility.md (6.2 -> 3.1 KB): lead with deep
ThemeDictionary patterns (ResourceKey redirect, runtime theme switching,
BasedOn discipline); generic a11y/keyboard/media checklists removed
(now in training)

references/brushes-and-icons.md: trimmed the Smoke section (one brush,
ContentDialog applies it automatically)

Verified zero prose overlap with the windows-xaml plugin via 8-gram
shingle scan (only shared content is XAML scaffolding tokens and
learn.microsoft.com URL fragments).

Independent verification (Opus 4.7, blind to panel recs): verdict USEFUL,
trim successful, sidebar skeleton + SettingsCard package note + Mica
wiring + window-sizing DPI code each materially change generated output.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* winui-design: add identity-beat nudge to break NavView-grey-cards reflex

Feedback from real usage: agent-generated WinUI apps all look 'samey' —
same NavigationView Left + system grey Mica + default accent + grey
cards, regardless of app purpose. Diagnosed as ~60% skill bias (anchors
exclusively to Microsoft first-party apps, bans the moves that create
identity) and ~40% platform (Fluent is consistency by design).

Minimal middle-ground intervention, ~800 bytes:

1. Anchors table: added one row (media/canvas/hero — no NavView) and
   non-Microsoft reference apps in every row (Slack, VS Code, Outlook,
   GitHub Desktop, Spotify, Clipchamp). Three of six rows still anchor
   on NavigationView — this isn't anti-NavView, just not exclusively.

2. New short section 'Before reaching for defaults — one identity beat':
   forces ONE backdrop+accent decision before coding. Names overriding
   SystemAccentColor and tinted DesktopAcrylicBackdrop as on-pattern
   (Microsoft's own apps do this). Explicit permission to skip for
   utilities so we don't over-engineer brand identity for a calculator.

3. Anti-patterns table: replaced first two rows with two new ones that
   bless silhouette variety and brand customisation. Doesn't add new
   rows, doesn't remove the substantive bans below.

No new files, no new references, no worked code (agent knows syntax
once told the pattern is on-pattern — the unlock is permission).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* winui-design: drop baked-in sidebar skeleton — winui-search owns examples

SKILL.md contradicted itself: a whole section tells the agent to
front-load winui-search.exe lookups *before* writing XAML, then handed
them a baked-in NavigationView + SettingsCard skeleton that pre-empted
the search. That skeleton was the proximate cause of the 'every app
looks like Settings' feedback — it's always-loaded into context.

Verified the tool returns rich samples for both ('gallery-navigationview-1'
for the shell + 'toolkit-settingsexpander-*' for the cards), so the
skeleton is fully redundant.

Skill teaches decisions; tool provides samples. Restore that boundary.

PaneDisplayMode guidance dropped with the snippet — also redundant with
gallery-navigationview-1's full sample which shows all four modes.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* winui-design: shape-neutral pass — remove silhouette bias from generic guidance

Full audit of remaining over-specific examples after the sidebar-skeleton
removal. Seven biasing items found, six fixed (one was acceptable API
description in brushes-and-icons.md and was left alone).

SKILL.md:
- Mica wiring section: dropped 'MicaBackdrop { Kind = Base }' headline code
  (it's the default — showing it as 'the example' undoes the identity beat
  two paragraphs up). Replaced with a 3-option bullet list matching the
  identity-beat choices: Mica, tinted Acrylic, no backdrop.
- Window-sizing DPI snippet: replaced literal '460 * scale, 860 * scale'
  (a portrait sidebar-shaped utility window) with widthDip/heightDip
  placeholders so the agent derives values from the rubric.
- Anti-pattern 'Centered floating card on empty background': re-scoped
  to the actual bug (tiny island on oversized window). The previous
  framing banned hero/welcome/empty-state surfaces, which are legitimate.
- Anti-pattern '50/50 split → fixed sidebar 280-360 px': removed the
  Shell-prescriptive correction. Now reads 'stable size for structural
  pane, flexible for content — only if a structural pane is part of the
  silhouette at all'.

references/layout-review.md:
- Page-planning silhouette list: aligned with SKILL.md anchors table
  (added canvas-hero, dense-grid; removed redundant 'tabs', 'menu+command').
- DELETED 'Sidebar / content sizing rules of thumb' section entirely.
  It was Shell-specific (OpenPaneLength, settings cards, 'matches Windows
  Settings') sitting in a generic responsive-review reference. Same kind
  of bias as the deleted sidebar skeleton; winui-search owns those values.

references/theme-accessibility.md:
- ThemeDictionary example renamed 'CardBackgroundBrush' to 'AppSurfaceBrush'
  so the example doesn't quietly assume cards are the surface vocabulary.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* winui-design: correct XAML landmines section against analyzer + MS Learn

Validated all 5 landmines against authoritative sources (Microsoft Learn, the in-repo WinUI analyzer's own RULES.md, and a built-and-run WinUI 3 test app). Four needed corrections:

* TextBox UpdateSourceTrigger: dropped the 'silently breaks UI Automation set-value' framing. WinUI 3 TextBox does not implement IValueProvider (uses ITextProvider2). Replaced with the real concern: VM is stale until LostFocus, breaking UIA keyboard-simulation tests (WinAppDriver SendKeys, etc.).

* Attached-property initializer: changed 'compiles, does nothing' to the truth — does not compile (CS0117). 'Button' has no 'AutomationProperties' instance member; it's a static accessor class. This matches the in-repo WUI2030 analyzer rule, which already says 'Doesn't compile' — SKILL.md was internally inconsistent.

* Converter={x:Null}: clarified this hits {x:Bind} specifically (compiles, then LookupConverter(\\\) returns null, NullReferenceException at activation). Added the actual error string from WUI2012 so agents can recognize it in crash logs.

* Acrylic + ThemeShadow: BackgroundSizing=InnerBorderEdge IS the default — old text implied you had to add it. Translation=0,0,32 is the recommended popup elevation, not a hard requirement (tooltips use 16, dialogs use 128). Removed the '>=12 px parent padding' rule — fabricated, not in any MS doc; replaced with the real non-popup gotcha (must populate ThemeShadow.Receivers).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* winui-design: regraft control-mapping bullets (Navigation / Data display / Input)

Benchmark on this branch showed agents reaching for CommunityToolkit DataGrid for tabular scenarios. Root cause: the clean-room rewrite dropped the three short 'requirement -> platform control' mapping sentences that main branch had, so nothing in SKILL.md was steering agents away from cross-framework instincts (WPF DataGrid, web <select>, HTML date input).

Re-add them as a compact 'Reach-for-this control map' section with a tighter framing line. The tabular bullet now explicitly calls out the anti-pattern by package name (CommunityToolkit.WinUI.Controls.DataGrid) and the concrete reason agents should not reach for it (column bindings can't use x:Bind), and redirects to ListView + Grid-based ItemTemplate + header Grid above. Closes the regression vs main without restoring the full deleted control-selection.md reference.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* winui-design: close benchmark-identified gaps (Feedback row, destructive-action rule, search discoverability)

Three surgical additions based on a comparative benchmark run against main:

* Feedback bullet in the Reach-for-this control map (ContentDialog / Flyout / TeachingTip / InfoBar / AppNotification). Mirrors main; addresses ContentDialog and InfoBar regressions observed on this branch where agents were not picking the right feedback surface.

* Anti-patterns row for destructive actions without confirmation. This is a pre-existing gap on BOTH branches — the benchmark's 'delete with confirmation dialog' requirement was failing 4/4 trials on main and nm alike. Net new improvement, not a regression fix.

* One sentence after the winui-search quick-start naming the integration-pattern categories the tool covers (file pickers, Share, JumpList, drag-drop, app lifecycle, dialogs) and stating the don't-interleave rule explicitly. Agents were burning extra tool calls rediscovering scope of the search tool.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* winui-design: experiment — remove 'identity beat' section

Test branch for benchmark experiment: does the 'Before reaching for
defaults' section produce any visible difference in generated app
identity? Compare against nm/cleanup-design-skill (control) and
nm/exp-push-identity (stronger prescription).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* trim

* Apply suggestion from @niels9001

---------

Co-authored-by: Nikola Metulev <711864+nmetulev@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Niels Laute <niels.laute@live.nl>

* ci(deps): bump actions/checkout from 6 to 7 (#113)

Bumps [actions/checkout](https://github.com/actions/checkout) from 6 to 7.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](actions/checkout@v6...v7)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-version: '7'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Nikola Metulev <nmetulev@users.noreply.github.com>

* adding .gitattributes (#110)

Co-authored-by: Nikola Metulev <nmetulev@users.noreply.github.com>

* deps: Bump Microsoft.NET.Test.Sdk from 18.5.1 to 18.6.0 (#106)

---
updated-dependencies:
- dependency-name: Microsoft.NET.Test.Sdk
  dependency-version: 18.6.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Nikola Metulev <nmetulev@users.noreply.github.com>

* Add native OpenClaw support for the winui plugin (#114)

* Add native OpenClaw plugin support for winui

Adds openclaw.plugin.json, package.json, and a no-op plugin entry point so the winui skills load as a native OpenClaw plugin (format: openclaw). Verified all 8 winui skills load ready with no plugin issues on OpenClaw 2026.6.10. Resolves #107.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* docs: document OpenClaw install in README

Adds an OpenClaw install block to the per-host setup options, covering the no-pre-registration marketplace install and a local-clone path, with a note that OpenClaw maps skills (not agents).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* docs: add CHANGELOG entry for OpenClaw support

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Nikola Metulev <nmetulev@users.noreply.github.com>

* Fix winui-search Gallery fetch for upstream sample-format overhaul (#124)

* Fix winui-search Gallery fetch for upstream sample-format overhaul

microsoft/WinUI-Gallery reorganized AND reformatted its samples, breaking
GalleryFetcher's fetch + parser (update reported gallery=FAILED on 404).

Rewrite GalleryFetcher for the new layout:
- ControlInfoData.json -> SampleSupport/Data/; pages -> per-control
  Samples/{UniqueId}/{UniqueId}Page.xaml (Folder subpath retired).
- Parse each ControlExample's SampleDefinition ".txt" bundle by
  --- header / --- xaml / --- c# sections; keep the legacy inline
  extractor as a fallback for the few Accessibility pages not migrated.
- Flatten $(...) in XAML; drop C# sections containing $(...) (they would
  flatten to non-compileable code). Remove the now-dead code-behind and
  external SampleCode extraction machinery.
- Fix CleanGalleryContent line filter (no longer deletes lines carrying a
  tag's closing '>') and TruncateXaml tag-balancer (ignores comment text)
  so multi-line open tags in the new format stay well-formed.

Bump CacheVersion 16 -> 17 and regenerate the embedded gallery snapshot
(321 scenarios / 111 controls). Update DATA_SOURCES.md + CHANGELOG.

Fixes #120

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

* winui-search: fall back to Subtitle for empty legacy a11y headers

Review follow-up on #120: two legacy inline Accessibility samples
(accessibilitykeyboard-6, accessibilityscreenreader-5) have no leading
XML comment, so DeriveHeaderFromComment returned "" and they rendered as
"Keyboard Navigation: " with a trailing ": ".

- Legacy inline path only: when the comment-derived header is empty, fall
  back to the control's ControlInfoData Subtitle. New-format samples are
  untouched (they always carry a --- header section).
- Defensive: SearchEngine now renders "ControlName" alone (no ": ") when
  HeaderText is empty, for any residual case.
- Regenerated embedded gallery snapshot (only the 2 headers change; 321
  scenarios unchanged otherwise) and bumped CacheVersion 17 -> 18.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

* Rebuilt winui-search exe.

---------

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

* Refactor winui-search sources behind an ISearchProvider interface (#123)

* Refactor winui-search sources behind an ISearchProvider interface

Introduce ISearchProvider + CachedProviderBase (shared cache protocol) + ProviderRegistry so scenario sources are pluggable. Program.cs and SearchEngine no longer hardcode gallery/toolkit.

Fixes the wrong-prefix bug where any non-toolkit source was given the gallery- id prefix: prefixes are now derived from Scenario.Source, and GetPattern strips any known source prefix.

The update path is now async end-to-end, removing the last GetAwaiter/GetResult.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

* Rebuild winui-search.exe payload after merging #124

The staging merge brought in the WinUI-Gallery sample-format parser
changes, so the AOT-published exe shipped by the winui-design skill is
regenerated (scripts/build-tools.ps1 winui-search step: AOT publish
-r win-x64 -> plugins/winui/skills/winui-design/winui-search.exe) to keep
winui-search-provenance in sync with source.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

---------

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

* Drop VS recommendation; default BuildAndRun.ps1 to dotnet build (XAML bug fixed in current WASDK) (#130)

* Drop VS recommendation; default BuildAndRun.ps1 to dotnet build

The XAML-compiler bug where `dotnet build` surfaced no diagnostic for malformed XAML (cryptic MSB3073) is fixed in current Windows App SDK releases: >= 2.1.3 on the 2.x line and >= 1.8 on the 1.x line. The Visual Studio recommendation existed only as a workaround for that bug.

- BuildAndRun.ps1 now builds with `dotnet build` by default; MSBuild is opt-in via -UseMSBuild (--use-msbuild), with a graceful fallback + warning when VS isn't found. Analyzer injection preserved.
- README: VS is now plainly optional (an IDE); documents the historical bug, the fixed-version floors, and 'update Microsoft.WindowsAppSDK to latest' guidance.
- winui-dev-workflow/SKILL.md: reflects the new default; adds an MSB3073 troubleshooting row.
- winui-setup/SKILL.md: decouples 'don't install VS' from the workaround.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: bf5d5a65-e808-440c-919f-e35a09dbc657

* Apply suggestion from @nmetulev

* Apply suggestion from @nmetulev

* Apply suggestion from @nmetulev

* Apply suggestion from @nmetulev

* Apply suggestion from @nmetulev

---------

Co-authored-by: Nikola Metulev <711864+nmetulev@users.noreply.github.com>

* Broaden winui-ui-testing scope to any Windows app (#131)

The skill described itself as being for WinUI 3 apps, which led the agent to refuse UI testing for non-WinUI apps even though `winapp ui` drives UI Automation and works on any Windows desktop app. Update the description and add a Scope section covering Win32, WPF, WinForms, and WinUI 3, packaged or unpackaged.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: ed8d10d9-7fe4-46f8-8087-83531c04da94

Co-authored-by: Nikola Metulev <711864+nmetulev@users.noreply.github.com>

* Add reactor search provider to winui-search (#125)

* Add reactor search provider to winui-search

Index the microsoft-ui-reactor ReactorGallery as a third ISearchProvider so
winui-search surfaces Reactor (C#-only, declarative WinUI) scenarios alongside
gallery and toolkit. 93 controls fetched from the Reactor team's purpose-built
reactor-search-index.json; embedded offline snapshot baked in.

- ReactorFetcher.cs / ReactorProvider.cs mirror the gallery provider shape;
  registered in ProviderRegistry.All. JSON parsed with JsonDocument (AOT-safe).
- Curated per-control keywords map to the 3.0-weighted enrichment tag field,
  served verbatim (not stop-word cleaned) so terms like "css layout" survive.
- Control-level usings (data-grid, docking, flex, property-grid) are folded into
  each sample's C# so snippets compile standalone; code kept verbatim otherwise.
- SearchEngine.FormatScenario gains a reactor branch: [Reactor] tag + NuGet setup
  line, **Namespace:** suppressed (all 93 share Microsoft.UI.Reactor).
- CacheVersion 16 -> 17; docs (DATA_SOURCES.md, README.md) + CHANGELOG updated.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

* Address PR review: refresh committed exe + sync winui-search source docs

Resolves the findings from the pre-push multi-dimensional review of the
reactor provider:

- H1 (payloads): rebuild the committed winui-search.exe payload so the shipped
  plugin binary actually includes the reactor source. It was stale (the old exe
  rejected list --source reactor); the refreshed exe serves 93 reactor
  scenarios offline. Size 7.99MB -> 8.12MB (+1.6%, within provenance tolerance).
- M1 (docs): top-level README.md now lists Gallery + Toolkit + Reactor in all
  three winui-search descriptions (tools tree, skills table, in-repo tools table).
- M2 (skill-content): winui-design/SKILL.md no longer claims every result is
  XAML + C# (reactor samples are C#-only) and adds reactor to the bundled catalogue.
- L1 (skill-content): winui-dev.agent.md adds reactor to the winui-search
  catalogue mention.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

* Skip empty-code Reactor samples in ReactorFetcher (PR review)

Addresses the Copilot review comment on ReactorFetcher.cs: the parser emitted a
Scenario even when a sample's code was missing/empty, which could produce blank
scenarios that pollute search/get output. Now skips samples with no usable code
(guarding on the raw code before the usings prefix, so a control with only
control-level usings can't slip through as a using-only stub), mirroring
GalleryFetcher's csharp == null && xaml == null -> continue rule. index is
incremented only for kept samples so ids stay contiguous.

Current live data has no empty samples, so the embedded snapshot is byte-identical
(verified) and reactor still returns 93 controls. Committed exe rebuilt from source.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

---------

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

* Document winapp CLI 0.5 UI verbs and run crash debugging in WinUI skills (#132)

* Broaden winui-ui-testing scope to any Windows app

The skill described itself as being for WinUI 3 apps, which led the agent to refuse UI testing for non-WinUI apps even though `winapp ui` drives UI Automation and works on any Windows desktop app. Update the description and add a Scope section covering Win32, WPF, WinForms, and WinUI 3, packaged or unpackaged.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: ed8d10d9-7fe4-46f8-8087-83531c04da94

* Document winapp CLI 0.5 UI verbs and run crash debugging

Update winui-ui-testing and winui-dev-workflow for winapp CLI 0.5:
new `winapp ui` input/capture verbs (send-keys, hover, drag, touch,
pen, record) and WinUI crash diagnosis in `winapp run` (--debug-output
stowed-exception triage, --symbols). BuildAndRun.ps1 gains an opt-in
-Symbols switch. Adds CHANGELOG [Unreleased] entries.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: e5fd6834-447a-46ac-9edb-8ec19996f1eb

* Align drag coordinate wording with shipped winapp CLI 0.5.0

Revalidated the skills against the shipped v0.5.0 standalone binary
(all documented ui/run verbs and flags verified against its --cli-schema;
the command+option surface is identical to the prerelease build these
docs were written against). The one substantive change that shipped is
breaking change #660, which renamed UI coordinate terminology from "app"
to "screen". Update the drag selector description accordingly.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: e5fd6834-447a-46ac-9edb-8ec19996f1eb

* Clarify --symbols is optional for WinUI crash dispatch stack

Empirical cold-cache testing on shipped winapp v0.5.0 confirmed the WinUI
stowed-exception native dispatch stack resolves from `winapp run --debug-output`
alone -- the triage auto-downloads the WinUI/OS/CLR symbols it needs from the
Microsoft Symbol Server on first use. `--symbols` is optional/additive (a
fallback for native frames outside the WinUI stack), not what enables the
dispatch stack. Corrects the prior wording that over-attributed dispatch-stack
resolution to `--symbols`.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: e5fd6834-447a-46ac-9edb-8ec19996f1eb

* Tighten v0.5 skills prose for token efficiency

Compress the new Advanced Input / Recording / crash-diagnosis sections and
gotchas without dropping any technical detail (transports, flag semantics,
RichEditBox/accelerator notes, symbol behavior). Skills load into agent
context, so terser high-signal prose is preferred.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: e5fd6834-447a-46ac-9edb-8ec19996f1eb

* Trim crash-diagnosis section to its high-signal core

Collapse "Diagnosing Crashes with winapp run" to a single paragraph: the
--debug-output WinUI stowed-exception triage (real XAML error + symbolicated
native stack from --debug-output alone) plus the first-run gotcha (debugger
components download can look like a hang; WINAPP_DBGTOOLS_DIR skips it). Drop
the --symbols paragraph/code block and the tangential --clean/--detach line --
the actionable guidance already lives in the Common Errors table. Align the
remaining -Symbols one-liners to the accurate "optional Symbol Server fallback"
framing (symbols auto-download without the flag).

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: e5fd6834-447a-46ac-9edb-8ec19996f1eb

---------

Co-authored-by: Nikola Metulev <711864+nmetulev@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

* Release 0.5.0

Promote [Unreleased] into the 0.5.0 section: new Reactor winui-search source,
winapp CLI 0.5 UI-testing verbs + crash-diagnosis docs, and the Gallery-refresh
fix. Add Changed entries for the broadened winui-ui-testing scope and the
dotnet-build BuildAndRun default. Drop the stale OpenClaw bullet (already shipped
in 0.4.0) and repair the regenerated [Unreleased] comment.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: e5fd6834-447a-46ac-9edb-8ec19996f1eb

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: Nikola Metulev <711864+nmetulev@users.noreply.github.com>
Co-authored-by: leileizhang <leilzh@microsoft.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Niels Laute <niels.laute@live.nl>
Co-authored-by: Dinah Xiaoman G <116714259+DinahK-2SO@users.noreply.github.com>
Co-authored-by: Jaylyn Barbee <51131738+Jaylyn-Barbee@users.noreply.github.com>
Co-authored-by: Alexandre Zollinger Chohfi <chohfi@outlook.com>
…g coverage

Prepares the winui-analyzer for UWP -> WinUI 3 migration consumers (the winapp
CLI and the winui-uwp-migration skill) by adding a standalone analyze driver
and expanding rule/mapping coverage. Source-only; no skill payload here.

- New Driver project (Microsoft.WindowsAppSDK.Analyzers.Driver, AssemblyName
  winui-analyze): hosts the Roslyn analyzers over still-UWP source and emits a
  stable v1.0 JSON migration plan (per-file disposition + per-line findings +
  severity + fix refs + feature area) to stdout.
- Rules/mappings: B1 API-mapping coverage, B2 crash-tier, B3 UWP-only XAML
  control rule (WUI2003), WUI0003 DependencyObject.Dispatcher member-access
  detection; MigrationTiers, expanded ApiMappings/FeatureMappings, semantic
  reference resolution + explicit sensitive-API signal.
- --from-uwp: force MigratingFromUwp via a global analyzer-config option.
- Tests: +63 passing (ApiMapping/UwpApi/Xaml rule suites + AnalyzerTest harness).
- Docs: RULES.md + analyzer CHANGELOG.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 401212b2-aeb4-40ef-8c4b-a429ee700740
Neutralize wording that presupposed a specific downstream distribution/caller
so this analyzer+driver PR stands independent of the (still-open) decision on
how the migration tooling consumes the driver:

- Driver Program.cs / csproj: drop "invoked directly by the skill" / "committed
  into the skill payload" -> "out-of-build entry point the migration tooling
  consumes at Step 0 (read from stdout)".
- Rule comment / test comment / RULES.md / CHANGELOG: replace the stale
  `migrate analyze` label for the loose-source path with the generic "driver
  path (raw source, no WinUI metadata)".

Comments/docs only; 63/63 analyzer tests still pass.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 401212b2-aeb4-40ef-8c4b-a429ee700740
@zateutsch
Zach Teutsch (zateutsch) changed the base branch from main to staging August 1, 2026 20:05
@zateutsch

Copy link
Copy Markdown

PR Review — user/qiutongshen/winui-analyzer-core vs origin/main (23 commits, 17 files, +916/-17)

Generated by the repo's pr-review skill (6 dimensions + gpt-5.4 multi-model cross-check). Report-only — no fixes applied.

Summary

Critical: 0 · High: 3 · Medium: 9 · Low: 1

Dimension Result
skill-content ✓ clean
skill-tool-boundary ⚠ 1 finding
tool-correctness ⚠ 5 findings (4 specialist + 1 raised centrally)
payloads-and-tests ⚠ 5 findings
docs-and-manifests ⚠ 2 findings (1 narrowed after verification)
multi-model ✓ 3/3 high confirmed

Findings

ID File Domain Issue
H1 plugins/winui/skills/winui-dev-workflow/analyzer/Microsoft.WindowsAppSDK.Analyzers.dll payloads-and-tests Committed analyzer DLL/.targets not refreshed after source change — CI provenance will fail
H2 …Tests/Rules/SuppressionTests.cs payloads-and-tests New rule WUI2003 has no #pragma-suppression regression test
H3 …Tests/Rules/SuppressionTests.cs payloads-and-tests Extended rule WUI0003 (Dispatcher) has no #pragma-suppression regression test
M1 README.md docs-and-manifests New analyzer Driver tool undocumented (no per-tool README, not in tools table)
M2 scripts/build-tools.ps1 payloads-and-tests New Driver project not published by the one-verb tools build
M3 src/tools/winui-analyzer/CHANGELOG.md docs-and-manifests CHANGELOG cites corpus.yml/release.yml/run-corpus.ps1 that don't exist on branch
M4 …Analyzers.Driver/Program.cs:177-227 tool-correctness startup-crash + no-equiv API (DisplayRequest) emits contradictory JSON (migrate + "not supported")
M5 …Analyzers.Driver/Program.cs:202-225 tool-correctness Stable JSON contract recovered by parsing localizable diagnostic message strings
M6 …Analyzers/ApiMappings.g.cs:95-112 payloads-and-tests .g.cs data files hand-edited instead of regenerated (also constructor-signature change)
M7 …Analyzers/Rules/UwpApiAnalyzer.cs:127-146 tool-correctness WUI0003 calls GetSymbolInfo on every member-access node (per-keystroke perf)
M8 …Analyzers/Rules/UwpApiAnalyzer.cs:123-141 tool-correctness WUI0003 syntactic fallback not gated to migration context → FPs on any user .Dispatcher when symbol unresolved
M9 …Analyzers/Rules/XamlAnalyzer.cs:84-149 skill-tool-boundary, tool-correctness WUI2003 matches by local element name only → fires on custom controls named Pivot/Hub
L1 …Analyzers/Rules/XamlAnalyzer.cs:59-67 tool-correctness WUI2003 category Compatibility inconsistent with WUI2xxx "Runtime" range convention

Details

H1 — plugins/winui/skills/winui-dev-workflow/analyzer/Microsoft.WindowsAppSDK.Analyzers.dll

  • Severity: high · Confidence: high · Domain: payloads-and-tests · Multi-model: confirmed · Tier: 1
  • Finding: Analyzer source changed (new WUI2003, extended WUI0003, +14 mappings) but the committed DLL/.targets payload the plugin ships was not refreshed.
  • Evidence: git diff --name-only origin/main...HEAD = 17 files, all under src/tools/winui-analyzer/; the committed payloads exist in-tree but are absent from the diff. CI analyzer-provenance (sha256/size delta >256 B) and analyzer-targets-sync (byte-identical) will fail.
  • Recommendation: Run ./scripts/build-tools.ps1 and commit the refreshed Microsoft.WindowsAppSDK.Analyzers.dll (and .targets if changed).

H2 — src/tools/winui-analyzer/Microsoft.WindowsAppSDK.Analyzers.Tests/Rules/SuppressionTests.cs

  • Severity: high · Confidence: high · Domain: payloads-and-tests · Multi-model: confirmed
  • Finding: New rule WUI2003 has positive/negative tests but no suppression regression, and the repo-wide SuppressionTests suite ("every shipping rule must honor #pragma warning disable") has no WUI2003 case.
  • Evidence: XamlAnalyzerTests.cs covers fire/no-fire only; SuppressionTests.cs grep for WUI2003 → no match.
  • Recommendation: Add a WUI2003 suppression case to SuppressionTests.cs (or, since WUI2003 is a compilation-end XAML AdditionalFile diagnostic, the equivalent .editorconfig/suppression-harness assertion).

H3 — src/tools/winui-analyzer/Microsoft.WindowsAppSDK.Analyzers.Tests/Rules/SuppressionTests.cs

  • Severity: high · Confidence: high · Domain: payloads-and-tests · Multi-model: confirmed
  • Finding: The new WUI0003 Dispatcher member-access path has no suppression regression test.
  • Evidence: UwpApiAnalyzerTests.cs:154-164 only suppresses WUI0001; the #pragma warning disable WUI0003 at ~:71-73 is fixture setup inside a positive test, not a suppression assertion. SuppressionTests.cs grep for WUI0003 → no match.
  • Recommendation: Add a WUI0003 suppression case (wrap this.Dispatcher.RunAsync(...) in #pragma warning disable WUI0003, assert no diagnostic) to SuppressionTests.cs.

M1 — README.md

  • Severity: medium · Confidence: high · Domain: docs-and-manifests
  • Finding: The new Microsoft.WindowsAppSDK.Analyzers.Driver CLI has no doc surface — no src/tools/winui-analyzer/README.md coverage and it's absent from README's in-repo tools table.
  • Recommendation: Document the driver (invocation winui-analyze --root <dir> [--from-uwp], JSON contract v1.0) in the analyzer README and reference it from the top-level tools table.

M2 — scripts/build-tools.ps1

  • Severity: medium · Confidence: high · Domain: payloads-and-tests
  • Finding: The new Driver project is built (as part of the solution) but never dotnet publish-ed, so it falls outside the one-verb build/dist contract.
  • Recommendation: Decide whether the driver is a shipped artifact; if so, add a dotnet publish step and a dist destination (and matching provenance if it becomes a committed payload).

M3 — src/tools/winui-analyzer/CHANGELOG.md

  • Severity: medium · Confidence: high · Domain: docs-and-manifests
  • Finding: CHANGELOG's Unreleased section describes artifacts that don't exist on the branch.
  • Evidence: Verified present: SuppressionTests.cs, Allowlists.cs. Verified absent: tools/run-corpus.ps1, .github/workflows/corpus.yml, .github/workflows/release.yml. The corpus/release bullets read as shipped but aren't.
  • Recommendation: Remove (or move to a roadmap section) the corpus-suite and release-pipeline bullets, or land those files in this PR.

M4 — …Analyzers.Driver/Program.cs:177-227

  • Severity: medium · Confidence: medium · Domain: tool-correctness
  • Finding: An API that is both no-equivalent (WUI1002) and startup-crash (DisplayRequest) emits self-contradictory JSON: severity:"startup-crash", disposition:"migrate", fix.summary:"...is not supported...".
  • Evidence: SeverityOf returns the tier string, bypassing the WUI1002 => "unsupported" branch; DispositionOf only escalates on unsupported/sensitive → falls through to migrate; FixOf only nulls the fix when severity=="unsupported".
  • Recommendation: Track no-equiv independently of the tier so a startup-crash + no-equiv finding keeps defer/fix=null, or add a dedicated disposition. Add a driver test for the emitted JSON.

M5 — …Analyzers.Driver/Program.cs:202-225

  • Severity: medium · Confidence: high · Domain: tool-correctness
  • Finding: The versioned JSON contract's detected/featureArea are recovered by substring-parsing localizable diagnostic message text, coupling the contract to editorial wording.
  • Evidence: DetectedFrom slices on " → ", " is not supported", " ("; FeatureAreaFrom slices on " ("/"):", all keyed to the exact MessageFormat of WUI1001/1002/1010. A wording tweak silently breaks the contract with no failing test. (Culture is pinned, so localization is neutralized; structural edits are not.)
  • Recommendation: Carry qualified name / replacement / feature area on Diagnostic.Properties (same bag as MigrationTier) and read them in the driver instead of parsing messages.

M6 — …Analyzers/ApiMappings.g.cs:95-112

  • Severity: medium · Confidence: high · Domain: payloads-and-tests
  • Finding: .g.cs data files were hand-edited (+~14 rows) and their constructor signatures changed (startupCrash/sensitive), rather than regenerated via the documented Microsoft Learn data path.
  • Recommendation: Regenerate the data rows through the documented generator; keep the constructor/schema change as a reviewed edit to the generator template, not the output.

M7 — …Analyzers/Rules/UwpApiAnalyzer.cs:127-146

  • Severity: medium · Confidence: high · Domain: tool-correctness
  • Finding: The Dispatcher check runs GetSymbolInfo on every SimpleMemberAccessExpression, unlike sibling checks that gate the semantic query behind a cheap name test. Since every true positive has RightmostName=="Dispatcher", the query is wasted on ~all member accesses.
  • Recommendation: Short-circuit with if (RightmostName(targetExpr) != "Dispatcher") return; before calling GetSymbolInfo.

M8 — …Analyzers/Rules/UwpApiAnalyzer.cs:123-141

  • Severity: medium · Confidence: high · Domain: tool-correctness
  • Finding: The WUI0003 syntactic fallback (RightmostName=="Dispatcher" when the symbol doesn't bind) is not gated to migration/loose-source context, and this analyzer never consults ProjectContext. In normal IDE editing / unresolved-reference states, any user member named Dispatcher yields a startup-crash-tier warning.
  • Evidence: Fallback fires whenever targetSymbol is null; Initialize registers the action unconditionally with no ProjectContext/global-option check. RULES.md discloses the FP risk, but the rule still runs outside the --from-uwp driver.
  • Recommendation: Gate the fallback to loose-source context (reuse build_property.WinUIMigrationFromUwp, or a CompilationStartAction that enables it only when Windows.UI.Core.CoreDispatcher metadata is absent) so clean builds use only the precise semantic path. (Two models declined to upgrade to high given the RULES.md disclosure and suppressibility; raised centrally as medium because the exposure reaches ordinary consumers, not just the driver.)

M9 — …Analyzers/Rules/XamlAnalyzer.cs:84-149

  • Severity: medium · Confidence: high · Domain: skill-tool-boundary, tool-correctness · Tier: 1
  • Finding: WUI2003 matches purely on local element name, so a custom control named Pivot/Hub/VirtualizingStackPanel in a non-UWP namespace fires a false positive.
  • Recommendation: Constrain to the XAML presentation namespace (or migration context) and add a FP test for <local:Pivot xmlns:local="using:Contoso.Controls"/>. (Disclosed in RULES.md; kept because the guard is concretely feasible.)

L1 — …Analyzers/Rules/XamlAnalyzer.cs:59-67

  • Severity: low · Confidence: high · Domain: tool-correctness
  • Finding: WUI2003 uses DiagnosticCategories.Compatibility, but sits in the WUI2xxx range documented as "Runtime/layout/XAML pitfalls"; all sibling 2xxx rules use Runtime. Not functional (ID immutable, help link resolves, Warning severity).
  • Recommendation: Either switch the descriptor + RULES.md to Runtime, or add a one-line note explaining the intentional Compatibility category.

Top 3 to fix before pushing

  1. H1 — refresh + commit the analyzer payload (CI will otherwise fail).
  2. H2/H3 — add the two missing suppression tests to SuppressionTests.cs.

M8 and M5 are the most substantive design issues if hardening beyond CI-green.

🤖 Generated with the pr-review skill · multi-model cross-check ran the test suite (63 passed).

@zateutsch Zach Teutsch (zateutsch) left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I attached the review from our review skill above and attached the findings. Please review and validate and see if any of the findings make sense as changes.

As far as my manual rule, I think all the new coverage makes sense. But, I think we should drop the standalone driver and route everything through WinApp, since we are planning on migrating the analyzer over anyway.

Qiutong Shen (from Dev Box) and others added 4 commits August 3, 2026 13:50
The winui-dev-workflow skill ships a prebuilt Microsoft.WindowsAppSDK.Analyzers.dll
payload. This PR changed the analyzer source (WUI2003, extended WUI0003, +14
mappings, constructor signature changes) but did not rebuild that committed binary,
so the analyzer-provenance CI job (hash/size-compares a source build against the
committed payload) failed with an 8704-byte size delta.

Rebuilt the analyzer (dotnet build ...Analyzers.slnx -c Release) and copied the
fresh bin/Release/netstandard2.0/Microsoft.WindowsAppSDK.Analyzers.dll into the
committed payload (49664 -> 58368 bytes), so source and payload are back in sync.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 401212b2-aeb4-40ef-8c4b-a429ee700740
Rule correctness (win-dev-skills analyzer):
- M7: WUI0003 adds a `Dispatcher` name pre-filter before the syntactic path.
- M8: gate WUI0003's syntactic Dispatcher fallback on loose source
  (no Windows.UI.Core.CoreDispatcher metadata) via RegisterCompilationStartAction,
  so real WinUI builds (SDK projections present) don't get false positives.
- M9: WUI2003 only fires for controls in the WinUI/UWP presentation namespace;
  a custom `Pivot` in a `using:` namespace is no longer flagged.
- L1: WUI2003 category Compatibility -> Runtime.

Suppression coverage:
- H2: WUI2003 (XAML AdditionalFile diagnostic) can't be pragma-suppressed; add
  editorconfig-severity suppression support to the test harness (SuppressViaConfig)
  and a SuppressWui2003ViaConfig test.
- H3: add SuppressWui0003 pragma-suppression test.
- FP guards added for M8 and M9.

Driver JSON contract (M4):
- A no-equivalent API (WUI1002) that also carries a startup-crash tier no longer
  emits a contradictory migrate/fix. DispositionOf keys off the finding id (defer),
  and FixOf returns null for WUI1002/unsupported.

Docs: RULES.md updated for WUI2003/WUI0003. Refreshed committed analyzer payload DLL.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 401212b2-aeb4-40ef-8c4b-a429ee700740
The analyze driver sliced localizable diagnostic message text to recover the
detected API name and feature area (WUI1001/1002/1010), which breaks under
message localization or wording changes.

- MigrationTiers.Build merges the migration tier with machine-readable
  DetectedApi / FeatureArea property keys.
- ApiMappingAnalyzer stamps the qualified API name (WUI1001/1002) and the
  namespace prefix + area (WUI1010) onto Diagnostic.Properties.
- Driver DetectedFrom / FeatureAreaFrom read those properties (falling back to
  the rule Title for syntactic rules that don't carry them); the message-slicing
  Before() helper is removed.

Verified e2e: detected fields now emit clean qualified names
(Windows.System.Display.DisplayRequest, Windows.Media.Capture). Refreshed payload DLL.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 401212b2-aeb4-40ef-8c4b-a429ee700740
M1: document the `winui-analyze` out-of-build driver in the analyzer README —
invocation (`winui-analyze --root <dir> --from-uwp`), the v1.0 JSON contract
(severity/detected/location/fix + per-file disposition), why it's a separate
framework-dependent host, and its place in the project layout.

M3: CHANGELOG "Unreleased" cleanup —
- Remove the "Corpus regression suite" and "Release pipeline" entries that cited
  files which don't exist (tools/run-corpus.ps1, .github/workflows/corpus.yml,
  .github/workflows/release.yml).
- Add a "winui-analyze driver" entry and fold the review's rule changes into
  "Changed" (WUI0003 loose-source gate, WUI2003 Runtime category + namespace
  guard, driver no-equivalent disposition/fix consistency).
- Drop the stale SuppressionTests "(11 tests)" count.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 401212b2-aeb4-40ef-8c4b-a429ee700740
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants