Fix dotnet-maui skill regressions and sharpen decisiveness - #947
Conversation
Addresses the cross-family evaluation findings in dotnet#895 for the dotnet-maui plugin (8 skills, 48% pass, 1 P0). Every claim below was validated empirically by building a real .NET MAUI app against the current SDK, not by code reading alone. FIX-REGRESSION - maui-collectionview (P0): - ItemSizingStrategy was documented on LinearItemsLayout in both SKILL.md and references/collectionview-api.md. It is declared on StructuredItemsView, so the documented markup is a hard build break: "error MAUIX2002: No accessible property, BindableProperty, or event found for ItemSizingStrategy". Corrected to set it on CollectionView, with the invalid form kept as an explicit counter-example. - Added a "Scope Control" section with stop-conditions (do NOT act when...), narrowed the frontmatter trigger, demoted the non-essential guidance to suggestions the agent may decline, and reduced the three non-negotiable rules to those that actually break code. This targets the ~30% of trials where skilled output was worse than baseline through over-application. - Added a validation checklist. HIGH severity, non-compiling - maui-app-lifecycle: - The iOS ConfigureLifecycleEvents examples called .DidBecomeActive() and .WillResignActive(), which do not exist: "error CS1061: IiOSLifecycleBuilder does not contain a definition for DidBecomeActive". Corrected to .OnActivated() / .OnResignActivation() and documented that the builder method names deliberately differ from the UIKit selector names (the mapping tables now show both columns). Correctness - maui-data-binding: - The XC0022-XC0025 meanings table was wrong on all four rows. Corrected against Build.Tasks/BuildException.cs and ErrorMessages.resx (XC0022 = binding without x:DataType, XC0023 = x:DataType explicitly null, XC0024 = x:DataType from outer scope, XC0025 = explicit Source). Correctness - maui-safe-area: - Claimed WindowSoftInputModeAdjust.Resize was "removed". It still compiles and is not obsolete. Reframed as Android-only and superseded, preserving the skill's brevity (EFFICIENT-WIN - deliberately not grown). STRENGTHEN - decisiveness (ties dominated these skills): - Added a compact "Rules That Change the Answer" table to maui-shell-navigation, maui-data-binding, maui-dependency-injection and maui-theming, converting reference prose into when-A-do-B guidance, each with an explicit "do not churn working code" stop-condition. Notably NOT changed: - maui-theming's {AppThemeBinding Light={DynamicResource ...}} guidance. This looked invalid from source reading, but a runtime probe proved it is fully dynamic (value tracked a dictionary swap: #FF0000 -> #0000FF, while the StaticResource control stayed #FF0000). The original guidance is correct. - maui-shell-navigation fixture/SDK pinning. Per the dotnet#909 correction the errored trial was a judge-side disabled-PAT failure, not fixture nondeterminism, so the skill was treated as STRENGTHEN. - dotnet-maui-doctor (EXEMPLAR) is unchanged. Validation: - skill-validator check --plugin ./plugins/dotnet-maui -> all checks passed (8 skills, 0 errors, 26 reference files scanned). - All corrected snippets compile in a net11.0-maccatalyst MAUI app; both original buggy forms reproduce the exact errors quoted above. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 58513e0c-4086-4112-9ea1-95dbd8e8e469
There was a problem hiding this comment.
Pull request overview
This PR updates the dotnet-maui plugin’s skill documentation to fix known non-compiling snippets (regressions) and to make several skills more behaviorally decisive by adding concise “Rules That Change the Answer” / scope-control guidance.
Changes:
- Fixes MAUI documentation examples that previously produced build errors (CollectionView
ItemSizingStrategyplacement; iOS lifecycle builder method names). - Adds “Rules That Change the Answer” (and related stop-conditions / validation checklists) to reduce ties and prevent over-application.
- Clarifies/adjusts guidance around safe-area + keyboard avoidance and compiled-binding warning meanings.
Reviewed changes
Copilot reviewed 9 out of 9 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| plugins/dotnet-maui/skills/maui-theming/SKILL.md | Adds a “Rules That Change the Answer” section and clarifies combined theming guidance. |
| plugins/dotnet-maui/skills/maui-shell-navigation/SKILL.md | Adds a “Rules That Change the Answer” table and stop-conditions for Shell navigation. |
| plugins/dotnet-maui/skills/maui-safe-area/SKILL.md | Reframes WindowSoftInputModeAdjust.Resize as supported but Android-only; clarifies obsoletion status. |
| plugins/dotnet-maui/skills/maui-dependency-injection/SKILL.md | Adds a compact rules table emphasizing lifetimes and MAUI scoped behavior. |
| plugins/dotnet-maui/skills/maui-data-binding/SKILL.md | Adds rules table and corrects the XC0022–XC0025 meanings section. |
| plugins/dotnet-maui/skills/maui-collectionview/SKILL.md | Adds scope control/stop-conditions, fixes ItemSizingStrategy guidance, and adds validation checklist. |
| plugins/dotnet-maui/skills/maui-collectionview/references/collectionview-api.md | Corrects ItemSizingStrategy placement and adds explicit ✅/❌ examples. |
| plugins/dotnet-maui/skills/maui-app-lifecycle/SKILL.md | Fixes iOS lifecycle builder method names and adds a mapping table note. |
| plugins/dotnet-maui/skills/maui-app-lifecycle/references/lifecycle-api.md | Mirrors the lifecycle mapping fix + note in the reference doc. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Driven by a local skilled-vs-baseline run (vally 0.10, executor claude-opus-4.6, judge gpt-5.5, n=3 per stimulus). The judge rationales named two concrete, fixable causes for the remaining losses: 1. "Response B introduces an unresolved x:DataType prefix unless additional namespace declarations are added" (penalised on 2 trials). The skill used x:DataType="models:..." in six snippets but never declared xmlns:models, so the examples were not copy-pasteable. Basic Setup is now a complete ContentPage including the xmlns:models declaration, with an explicit instruction to carry the matching xmlns when handing over a snippet. 2. Baseline beat the skill on the ListView/ViewCell migration stimulus by supplying nuance the skill lacked - that ListView still exists, plus event/API replacements. Added a "Migrating from ListView" section with a verified mapping table (ViewCell, ItemSelected/ItemTapped -> SelectionChanged, IsPullToRefreshEnabled -> RefreshView, IsGroupingEnabled -> IsGrouped, HasUnevenRows -> ItemSizingStrategy, and the missing separator APIs). Every member was confirmed against Controls/PublicAPI.Shipped.txt. Measured effect on the same eval (12 trials per arm, identical settings): original skill 17% win rate 2 wins / 4 ties / 6 losses mean -0.13 this PR 42% win rate 5 wins / 6 ties / 1 loss mean +0.13 Losses drop 6 -> 1 and the mean impact flips from negative (the FIX-REGRESSION signal in dotnet#895) to positive. n=12 on a single executor, so directional rather than significant, but the loss collapse is the intended effect of the regression fix. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 58513e0c-4086-4112-9ea1-95dbd8e8e469
Evaluation results (skilled vs. baseline)Per @AbhitejJohn's verification guidance in #895 (comment), I ran the skilled-vs-baseline comparison for the P0 skill (
Headline
Losses 6 → 1, and mean impact flips from negative to positive. The
The second commit was driven by these resultsThe first commit only moved losses 6 → 5. Reading the judge's per-trial rationales identified two concrete causes, which b07628c fixes:
Coverage gap worth flaggingNone of the four That defect was caught by compiling the documented XAML, not by the eval. A stimulus covering item sizing / performance would close the gap. Compile validationSeparately, every corrected snippet was verified by building a real
A maintainer will still need to post |
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 58513e0c-4086-4112-9ea1-95dbd8e8e469
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 9 out of 9 changed files in this pull request and generated no new comments.
Comments suppressed due to low confidence (1)
plugins/dotnet-maui/skills/maui-theming/SKILL.md:62
- In the theming rules table, the inline code uses
\|to escape the pipe character. Because this is inside a code span, the escape isn't needed for Markdown tables and it produces an invalid C# expression if someone copies it (bitwise OR is|, not\|).
| **Runtime-swapped values must be dynamic** | `{DynamicResource Key}` | `{StaticResource Key}` | `StaticResource` resolves once at load and never updates when dictionaries are swapped. |
| **Android must declare `UiMode`** | `ConfigurationChanges = … \| ConfigChanges.UiMode` on `MainActivity` | Omitting it | Without it Android restarts the activity on theme change — navigation state is lost and it looks like a crash. |
| **Force a theme via `UserAppTheme`** | `Application.Current.UserAppTheme = AppTheme.Dark` | Manually re-assigning colors | `UserAppTheme` overrides the OS; `AppTheme.Unspecified` returns to following the system. |
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 9 out of 9 changed files in this pull request and generated no new comments.
Comments suppressed due to low confidence (1)
plugins/dotnet-maui/skills/maui-theming/SKILL.md:61
- In this table row, the escaped pipe (
\|) is inside an inline code span, so it will render with the backslash visible (and users may copy it). Consider using an HTML entity for the pipe so the rendered code shows the correct|without breaking the markdown table.
| **Android must declare `UiMode`** | `ConfigurationChanges = … \| ConfigChanges.UiMode` on `MainActivity` | Omitting it | Without it Android restarts the activity on theme change — navigation state is lost and it looks like a crash. |
Reviewed by claude-opus-5, claude-opus-4.8, gpt-5.6-sol and gpt-5.5.
Verdicts were split (2 SHIP / 1 FIX / 1 NEEDS_CHANGES), so the blocking and
consensus findings are addressed here. Every disputed factual claim was
re-verified against the dotnet/maui source before changing anything.
Factual corrections (reviewers were right, I was wrong):
- ListView IS marked [Obsolete] as of .NET 10 ("ListView is deprecated. Please
use CollectionView instead.", ListView.cs:19). Verified it is present on
main, net10.0 and release/10.0.1xx-sr7, and absent on release/9.0.1xx. The
previous "it is not removed or obsolete" wording was wrong. (gpt-5.6-sol)
- MAUI DOES create one IServiceScope per window
(MauiContextExtensions.MakeWindowScope, called from the iOS/Android/Windows/
Tizen ApplicationExtensions), so "a Scoped registration resolves from the
root scope and behaves like a Singleton" was over-broad. Reworded to keep the
rubric-rewarded "no built-in request scope like ASP.NET Core" phrasing while
stating the window-scope reality. (opus-5, gpt-5.6-sol)
- ItemTapped -> SelectionChanged is not behaviour-preserving (SelectionChanged
only fires when the selection changes), and RowHeight -> MeasureFirstItem is
not an explicit row height. Split into accurate rows. (gpt-5.6-sol)
Rules that could suppress rubric-rewarded answers (the main eval risk):
- The ListView stop-condition ("do not migrate unless the user asked to
migrate") fired on eval stimulus 4, which asks "Should I keep using ListView
in MAUI?" - the user asks *whether*, not *to*. Reworded to recommend
CollectionView when asked which control to use, while still forbidding
silent rewrites. Flagged independently by opus-5 and gpt-5.5.
- data-binding's blanket "do not convert a working binding" could talk the
agent out of the rubric-rewarded x:DataType recommendation. Scoped it. (opus-5)
- "Point out a concrete defect or say nothing" -> answer the question asked;
"say nothing" invited non-answers, which judges penalise. (opus-5)
Internal contradictions introduced by this PR:
- data-binding Common Pitfalls still said "enable XC0025 as error" for a
missing x:DataType; XC0022 is the missing-x:DataType code. (opus-4.8)
- The rules table said x:DataType "root element only" two rows above a row
requiring one per DataTemplate. Reworded to "wherever a binding scope
starts". (opus-5, gpt-5.6-sol)
- The Validation checklist re-armed items the Scope Control section had just
demoted; scoped it to markup the agent actually wrote. (opus-5)
- Dropped the "Using ListView instead of CollectionView" pitfall row, which
contradicted the new migration section. (opus-5)
Other:
- Removed the escaped pipe (\|) from the theming rules table - a model reading
raw Markdown could copy it into C#. (Copilot reviewer, opus-5)
- Softened "Apply these three rules to every theming answer" so narrow
questions don't attract unrelated UiMode/UserAppTheme guidance. (gpt-5.5)
- De-duplicated the AddScoped guidance that appeared 4x. (opus-5)
Measured effect (maui-collectionview, executor claude-opus-4.6, judge gpt-5.5,
n=3/stimulus, 12 trials/arm, base re-run in the same session):
base (main, no fix) 33% win 4 wins / 4 ties / 4 losses mean +0.00 [-0.22,+0.22]
previous commit 42% win 5 wins / 6 ties / 1 loss mean +0.13 [-0.03,+0.30]
this commit 58% win 7 wins / 5 ties / 0 losses mean +0.23 [+0.10,+0.36]
Zero losses, and the confidence interval is now entirely above zero - the
first arm in this series with a statistically significant positive impact.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 58513e0c-4086-4112-9ea1-95dbd8e8e469
Round-2 review by claude-opus-5, claude-opus-4.8, gpt-5.6-sol, gpt-5.5:
2 SHIP, 2 FIX. All blocking and consensus findings addressed.
Consensus finding (opus-5 + gpt-5.6-sol) — the flagship "complete,
copy-pasteable page" declared xmlns:models but had no root x:DataType, so its
outer ItemsSource binding was an uncompiled reflection binding. That undercut
the skill's own compiled-bindings guidance and left rubric credit unclaimed on
collectionview stimulus 1. Added xmlns:vm + root x:DataType.
opus-5 blocking claim — <WarningsAsErrors>XC0022;XC0025</WarningsAsErrors>
(pre-existing, line 110 on main) was said to break any build using Source= or
RelativeSource bindings, because XC0025 means "binding not compiled due to an
explicit Source" and MauiEnableXamlCBindingWithSourceCompilation defaults true
only under AOT/full-trim.
Tested empirically: a net11.0-maccatalyst app with that exact
WarningsAsErrors value plus both a Source={x:Reference} binding and a
RelativeSource binding BUILDS CLEAN. The XC diagnostics are not emitted on
the current SourceGen path (Descriptors.cs has XC0022/0023/0025 commented
out), so the claim does not reproduce on current MAUI.
It can still bite on the older XamlC path, and the reasoning is sound, so
the guidance now pairs the switch with the setting and states the caveat
rather than changing the rubric-rewarded value.
Other round-2 fixes:
- "A binding falls back to reflection (XC0022/XC0023) | Fix the path" still
carried pre-correction semantics; neither code concerns the binding path
(that is XC0045). Reworded. (opus-5)
- "Everything below is a suggestion the agent may decline" literally demoted
the Key Rules and the Validation checklist. Scoped it to the API reference
sections and promoted x:DataType to a fourth non-negotiable. (opus-5)
- AddScoped lifetime table row and checklist still implied a manual scope is
the only scope; both now reflect window lifetime. (gpt-5.6-sol)
- Shell "Option 2: QueryProperty — apply directly on the page class"
contradicted the new rule table and the eval rubric ("on the ViewModel, not
the page"). (opus-5)
Copilot review comment — "Always use ObservableCollection<T>, not List<T>.
Swapping a List forces a full re-render" contradicted this PR's own
"use ObservableCollection when the list mutates" rule, and the claim was
imprecise: replacing ItemsSource re-renders regardless of collection type.
Rewritten around INotifyCollectionChanged and in-place mutation.
Not changed: gpt-5.6-sol and opus-5 both suggested editing
tests/dotnet-maui/*/eval.yaml rubrics (safe-area "replaced by", DI "behaves
like Singleton") to match the corrected facts. Changing the benchmark in the
same PR that changes the skill would invalidate the comparison, so these are
left for maintainers and called out in the PR instead.
Measured (maui-collectionview, executor claude-opus-4.6, judge gpt-5.5,
n=3/stimulus, 12 trials/arm, base re-run in the same session each time):
round 3 base +0.00 this PR +0.23 delta +0.23
round 4 base -0.07 this PR +0.17 delta +0.24
Absolute numbers move with run-to-run noise (three independent base runs gave
-0.13, +0.00, -0.07), but the advantage over base is stable at ~+0.24 mean and
~+25pp win rate across every paired run.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 58513e0c-4086-4112-9ea1-95dbd8e8e469
Round-3 review by claude-opus-5, claude-opus-4.8, gpt-5.6-sol, gpt-5.5: 3 SHIP, 1 FIX. Both of gpt-5.6-sol's blocking items are fixed here, along with the non-blocking findings from opus-5 and gpt-5.5. gpt-5.6-sol (blocking): - The Shell rules table used an undeclared `pages:` prefix, and its "Not this" cell claimed `<ShellContent Content="..."/>` constructs pages eagerly. `ShellContent` is `[ContentProperty(nameof(Content))]` with `Content` typed `object` (ShellContent.cs:15,45), so the eager form is nested markup, not a string attribute. Row rewritten with a declared `xmlns:views` and the real eager form `<ShellContent><views:MyPage /></ShellContent>`. - QueryProperty prose said "ViewModel" while the example was still a ContentPage. Also flagged independently by gpt-5.5 (consensus). opus-5 (non-blocking, both real): - The rules-table cell I added in round 2 contained `</...>` — not valid XML. A model lifting that cell verbatim emits an unparseable .csproj. Reworded to prose so there is no truncated tag to copy. - The QueryProperty ViewModel example used a plain auto-property. On a page that was harmless (code-behind reads it); on a ViewModel it is the binding target, and Shell applies query attributes *after* BindingContext is set, so a non-notifying property leaves the binding on its initial value. Switched to [ObservableProperty] and explained why. - The "complete, copy-pasteable page" never set BindingContext, so pasting it renders blank — the exact failure maui-data-binding lists first. Added it. Both changed snippets were compile-verified in a net11.0-maccatalyst app (flagship CollectionView page with root x:DataType + BindingContext, and the [QueryProperty] + [ObservableProperty] ViewModel with CommunityToolkit.Mvvm). Measured (maui-collectionview, paired base + current run per round, same session, executor claude-opus-4.6, judge gpt-5.5, n=3/stimulus, 12 trials/arm): round 3 base +0.00 this PR +0.23 delta +0.23 round 4 base -0.07 this PR +0.17 delta +0.24 round 5 base +0.00 this PR +0.13 delta +0.13 Round 5 is this commit. The delta is smaller than rounds 3-4 but the 95% CIs overlap heavily at n=12 (base CI +/-0.24), so this is not a demonstrated regression. The changes in this commit are correctness fixes - invalid XML, a silently-broken binding, and an inaccurate Shell claim - which are worth making regardless of a benchmark that cannot resolve a 0.1 difference. A higher-n run follows to tighten the estimate. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 58513e0c-4086-4112-9ea1-95dbd8e8e469
The data-binding "Common Pitfalls" row said "enable XC0022 as error" while the "Enforce binding warnings as errors" section above recommends XC0022;XC0025 paired with MauiEnableXamlCBindingWithSourceCompilation - two different prescriptions for the same task. The pitfall row now points at that section as the single source of truth instead of restating a partial version. Copilot's four earlier comments on this PR (theming escaped pipe, ObservableCollection contradiction, ShellContent eager form, QueryProperty example) were already addressed in previous commits; the ShellContent and QueryProperty findings matched gpt-5.6-sol's and gpt-5.5's independently. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 58513e0c-4086-4112-9ea1-95dbd8e8e469
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 15 out of 15 changed files in this pull request and generated no new comments.
Comments suppressed due to low confidence (4)
tests/dotnet-maui/maui-theming/eval.yaml:128
- In this new stimulus, the rubric items are unquoted YAML scalars. The skill-coverage workflow only extracts rubric evidence from single-line quoted items, so these won't contribute to coverage reports. Quote each rubric entry (like the earlier rubric items in this file).
rubric:
- Removes only the previously applied theme dictionary, then adds the new one
- Does NOT call MergedDictionaries.Clear(), which would also remove the template's Colors.xaml and Styles.xaml and unstyle the whole app
- Keeps a reference to the current theme so it can be removed on the next switch
- Produces code that leaves the app's existing styles intact after repeated switches
tests/dotnet-maui/maui-shell-navigation/eval.yaml:133
- These newly added rubric items are unquoted. Skill coverage extraction only counts rubric entries that are quoted on a single line, so this scenario will show 0 rubric evidence in coverage reports. Wrap each rubric string in quotes.
rubric:
- Sets an explicit Route on the ShellContent elements in AppShell.xaml
- Explains that without Route, MAUI auto-generates an unstable name (D_FAULT_ prefixed) that shifts when pages are reordered or added
- Shows an absolute GoToAsync route (leading //) built from the explicit route names
- Does NOT rely on auto-generated route names for deep linking
tests/dotnet-maui/maui-dependency-injection/eval.yaml:125
- The rubric strings for this new scenario are unquoted YAML scalars. The skill-coverage workflow only picks up quoted rubric entries, so these won't count toward coverage evidence. Quote each rubric item.
rubric:
- Explains that ContentTemplate pages are created with Activator.CreateInstance and bypass DI entirely
- Explains that routes resolved via GoToAsync go through the service provider and inject constructor dependencies
- Does NOT claim that dependencies are silently set to null without an exception
- Recommends navigating by route, or giving the page a parameterless constructor, for the ContentTemplate case
tests/dotnet-maui/maui-collectionview/eval.yaml:129
- The new rubric entries are unquoted, but skill-coverage evidence extraction only counts rubric items written as single-line quoted strings. Quote these rubric lines so the coverage report reflects this new scenario.
rubric:
- Sets ItemSizingStrategy="MeasureFirstItem" on the CollectionView element itself
- Does NOT set ItemSizingStrategy on LinearItemsLayout or GridItemsLayout, which does not compile
- Explains that MeasureFirstItem is only safe when every item is the same size
- Warns that variable-height items will be clipped or stretched, and that MeasureAllItems is the default
|
👋 Two ways to run it:
|
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 15 out of 15 changed files in this pull request and generated no new comments.
Comments suppressed due to low confidence (4)
tests/dotnet-maui/maui-shell-navigation/eval.yaml:133
- These newly added rubric items are unquoted. The skill-coverage workflow only counts single-line quoted rubric entries, so these won’t be picked up in coverage reports unless they’re wrapped in quotes.
rubric:
- Sets an explicit Route on the ShellContent elements in AppShell.xaml
- Explains that without Route, MAUI auto-generates an unstable name (D_FAULT_ prefixed) that shifts when pages are reordered or added
- Shows an absolute GoToAsync route (leading //) built from the explicit route names
- Does NOT rely on auto-generated route names for deep linking
tests/dotnet-maui/maui-theming/eval.yaml:128
- The rubric items in this new stimulus are unquoted, but the repo’s skill-coverage tooling only extracts rubric evidence from single-line quoted items. Leaving these unquoted means they won’t count toward coverage reporting for this skill.
rubric:
- Removes only the previously applied theme dictionary, then adds the new one
- Does NOT call MergedDictionaries.Clear(), which would also remove the template's Colors.xaml and Styles.xaml and unstyle the whole app
- Keeps a reference to the current theme so it can be removed on the next switch
- Produces code that leaves the app's existing styles intact after repeated switches
tests/dotnet-maui/maui-dependency-injection/eval.yaml:125
- These rubric items were added unquoted, which means the skill-coverage script won’t extract them as evidence (it only matches quoted rubric list items). Quoting them keeps coverage reporting accurate.
rubric:
- Explains that ContentTemplate pages are created with Activator.CreateInstance and bypass DI entirely
- Explains that routes resolved via GoToAsync go through the service provider and inject constructor dependencies
- Does NOT claim that dependencies are silently set to null without an exception
- Recommends navigating by route, or giving the page a parameterless constructor, for the ContentTemplate case
tests/dotnet-maui/maui-collectionview/eval.yaml:129
- This new stimulus adds unquoted rubric items. The repo’s skill-coverage report only counts single-line quoted rubric entries, so these won’t contribute to coverage unless they’re quoted.
rubric:
- Sets ItemSizingStrategy="MeasureFirstItem" on the CollectionView element itself
- Does NOT set ItemSizingStrategy on LinearItemsLayout or GridItemsLayout, which does not compile
- Explains that MeasureFirstItem is only safe when every item is the same size
- Warns that variable-height items will be clipped or stretched, and that MeasureAllItems is the default
📊 Skill Evaluation Results7 skill(s) evaluated — 7 improved, 0 no credible improvement. A skill passes only on a credible improvement over baseline (mean preference > 0 with its 95% CI above 0);
ℹ️ Column legend
✅ maui-app-lifecycle — detailsReason: Mean preference +51.7% [95% CI 31.8%, 71.5%], win rate 91.7% (11W/1T/0L over 12 trial(s)) — credibly better
✅ maui-collectionview — detailsReason: Mean preference +32.0% [95% CI 22.8%, 41.2%], win rate 80.0% (12W/3T/0L over 15 trial(s)) — credibly better
✅ maui-data-binding — detailsReason: Mean preference +40.0% [95% CI 40.0%, 40.0%], win rate 100.0% (12W/0T/0L over 12 trial(s)) — credibly better
✅ maui-dependency-injection — detailsReason: Mean preference +41.3% [95% CI 30.7%, 52.0%], win rate 93.3% (14W/1T/0L over 15 trial(s)) — credibly better
✅ maui-safe-area — detailsReason: Mean preference +100.0% [95% CI 100.0%, 100.0%], win rate 100.0% (12W/0T/0L over 12 trial(s)) — credibly better
✅ maui-shell-navigation — detailsReason: Mean preference +46.7% [95% CI 29.6%, 63.8%], win rate 86.7% (13W/2T/0L over 15 trial(s)) — credibly better
✅ maui-theming — detailsReason: Mean preference +34.7% [95% CI 26.9%, 42.5%], win rate 86.7% (13W/2T/0L over 15 trial(s)) — credibly better
🔍 Full Results - additional metrics and failure investigation steps ▶ Sessions Visualisation -- interactive replay of all evaluation sessions |
Ready for re-review — 7/7 confirmed on the current head@Redth @jfversluis @davidortinau — this is ready whenever you have time. @AbhitejJohn / @JanKrivanek, flagging you too since you've been through the earlier rounds. The latest evaluation ran against
87 wins, 9 ties, 0 losses. Every CI clear of zero, every overfit score ✅ Low, and every skill activating 100% of the time it should. What this fixesIssue #895 had What's worth your attention as a reviewerThe substantive changes are four bugs that were teaching code that doesn't work, each verified by building or running a real MAUI app rather than by reading docs:
Plus two doc corrections: the XC0022–XC0025 table (wrong on all four rows) and the "unregistered pages get silently null dependencies" claim (false — Note the PR touches Two open questions for you
Happy to make any changes you'd like. |
📊 Skill Evaluation Results7 skill(s) evaluated — 7 improved, 0 no credible improvement. A skill passes only on a credible improvement over baseline (mean preference > 0 with its 95% CI above 0);
ℹ️ Column legend
✅ maui-app-lifecycle — detailsReason: Mean preference +51.7% [95% CI 31.8%, 71.5%], win rate 91.7% (11W/1T/0L over 12 trial(s)) — credibly better
✅ maui-collectionview — detailsReason: Mean preference +29.3% [95% CI 19.2%, 39.5%], win rate 73.3% (11W/4T/0L over 15 trial(s)) — credibly better
✅ maui-data-binding — detailsReason: Mean preference +40.0% [95% CI 40.0%, 40.0%], win rate 100.0% (12W/0T/0L over 12 trial(s)) — credibly better
✅ maui-dependency-injection — detailsReason: Mean preference +44.0% [95% CI 35.4%, 52.6%], win rate 100.0% (15W/0T/0L over 15 trial(s)) — credibly better
✅ maui-safe-area — detailsReason: Mean preference +100.0% [95% CI 100.0%, 100.0%], win rate 100.0% (12W/0T/0L over 12 trial(s)) — credibly better
✅ maui-shell-navigation — detailsReason: Mean preference +40.0% [95% CI 23.8%, 56.2%], win rate 80.0% (12W/3T/0L over 15 trial(s)) — credibly better
✅ maui-theming — detailsReason: Mean preference +37.3% [95% CI 31.6%, 43.1%], win rate 93.3% (14W/1T/0L over 15 trial(s)) — credibly better
🔍 Full Results - additional metrics and failure investigation steps |
|
Thanks @AbhitejJohn — and good catch. Straight answer: no, not on the final changes. Your cross-family run (30313685452, 23/35, no regressions) was against
Those are precisely the commits that took the gate from 4/7 to 7/7, so the old cross-family numbers understate the current state — but they equally don't prove it. A fresh matrix is the right ask. What I can vouch for on the current head
Two runs agreeing exactly on byte-identical content is itself a result — earlier in this PR, identical content flipped ✅→❌ three times at 4 scenarios. The 5th scenario per skill removed that. But that's still one executor family. It doesn't tell you whether the theming/shell/DI rewrites help or hurt sonnet/haiku/mai, which is exactly what the matrix is for. Could you re-dispatch the cross-family workflow against In the meantime I've kicked off a local cross-family approximation on the three most-changed skills (theming, shell-navigation, DI) with a GPT executor judged by Claude — judge ≠ executor family, same as your matrix rule. It's directional only (one extra family, my machine), but it should flag any obvious non-Claude regression before you spend CI on it. I'll post the numbers when it finishes.
Completely agree — @jfversluis and @Redth are the right final approvers; they're already CODEOWNERS on both Worth their attention specifically: the four fixes are things that were teaching code that doesn't work — |
|
🔄 Re-running cross-family evaluation on the latest commit (
Updated results will be posted here when the run completes. |
|
Thanks for kicking that off @AbhitejJohn — that's exactly the right call, and the official matrix is the number that counts. My local approximation finished in the meantime. Directional only, but it points the same way: Executor
What it's useful for: the three skills that changed most since your The single loss is on Shell navigation auto-resolves DI-registered pages, and the judge called it modest — baseline was more literally responsive to "full wiring from MauiProgram.cs through to GoToAsync" by including |
cf62633 unintentionally included a change to dotnet-skills.experiment.yaml: overrides: runs: 1 -> runs: 3 That file is NOT dotnet-maui-scoped - it drives the experiment for every plugin's evals, so the change tripled trial counts repo-wide. It leaked in from my local measurement loop, where I set runs: 3 to get a usable sample and restored it from a copy afterwards; on that one commit the restore was missed and the modified file was picked up by `git add -A`. Reverted to upstream/main's `runs: 1`. No skill or eval content is affected. Disclosure on how this distorted the numbers reported on this PR: gate runs from cf62633 onward executed at 3 trials per scenario instead of 1, which is why they show 12-15 trials per skill rather than 4. I previously attributed that to a maintainer-side change; it was mine. The measurements themselves are valid - more trials, not different content - but they are NOT what the gate produces at upstream's runs: 1, and the two 7/7 results on a1eec66 should be read with that in mind. This also makes my earlier "consider runs: 3 for the gate" suggestion awkwardly self-serving in hindsight. The underlying point stands on its own evidence (byte-identical content flipped pass/fail three times at 4 scenarios x 1 run), but it is the maintainers' call to make deliberately, not something that should ride in on an unnoticed diff. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 58513e0c-4086-4112-9ea1-95dbd8e8e469
|
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 14 out of 14 changed files in this pull request and generated no new comments.
Comments suppressed due to low confidence (4)
tests/dotnet-maui/maui-theming/eval.yaml:128
- These newly added rubric items are unquoted YAML scalars. Our skill-coverage tooling only extracts rubric evidence from single-line quoted items, so these won’t contribute to coverage metrics and can under-report evidence for this scenario.
rubric:
- Removes only the previously applied theme dictionary, then adds the new one
- Does NOT call MergedDictionaries.Clear(), which would also remove the template's Colors.xaml and Styles.xaml and unstyle the whole app
- Keeps a reference to the current theme so it can be removed on the next switch
- Produces code that leaves the app's existing styles intact after repeated switches
tests/dotnet-maui/maui-shell-navigation/eval.yaml:133
- These newly added rubric items are unquoted YAML scalars. Our skill-coverage tooling only extracts rubric evidence from single-line quoted items, so these won’t contribute to coverage metrics and can under-report evidence for this scenario.
rubric:
- Sets an explicit Route on the ShellContent elements in AppShell.xaml
- Explains that without Route, MAUI auto-generates an unstable name (D_FAULT_ prefixed) that shifts when pages are reordered or added
- Shows an absolute GoToAsync route (leading //) built from the explicit route names
- Does NOT rely on auto-generated route names for deep linking
tests/dotnet-maui/maui-dependency-injection/eval.yaml:125
- These newly added rubric items are unquoted YAML scalars. Our skill-coverage tooling only extracts rubric evidence from single-line quoted items, so these won’t contribute to coverage metrics and can under-report evidence for this scenario.
rubric:
- Explains that ContentTemplate pages are created with Activator.CreateInstance and bypass DI entirely
- Explains that routes resolved via GoToAsync go through the service provider and inject constructor dependencies
- Does NOT claim that dependencies are silently set to null without an exception
- Recommends navigating by route, or giving the page a parameterless constructor, for the ContentTemplate case
tests/dotnet-maui/maui-collectionview/eval.yaml:129
- These newly added rubric items are unquoted YAML scalars. Our skill-coverage tooling only extracts rubric evidence from single-line quoted items, so these won’t contribute to coverage metrics and can under-report evidence for this scenario.
rubric:
- Sets ItemSizingStrategy="MeasureFirstItem" on the CollectionView element itself
- Does NOT set ItemSizingStrategy on LinearItemsLayout or GridItemsLayout, which does not compile
- Explains that MeasureFirstItem is only safe when every item is the same size
- Warns that variable-height items will be clipped or stretched, and that MeasureAllItems is the default
|
/evaluate b02c5a2 |
📊 Skill Evaluation Results7 skill(s) evaluated — 7 improved, 0 no credible improvement. A skill passes only on a credible improvement over baseline (mean preference > 0 with its 95% CI above 0);
ℹ️ Column legend
✅ maui-app-lifecycle — detailsReason: Mean preference +55.0% [95% CI 7.3%, 102.7%], win rate 100.0% (4W/0T/0L over 4 trial(s)) — credibly better
✅ maui-collectionview — detailsReason: Mean preference +40.0% [95% CI 40.0%, 40.0%], win rate 100.0% (5W/0T/0L over 5 trial(s)) — credibly better
✅ maui-data-binding — detailsReason: Mean preference +40.0% [95% CI 40.0%, 40.0%], win rate 100.0% (4W/0T/0L over 4 trial(s)) — credibly better
✅ maui-dependency-injection — detailsReason: Mean preference +40.0% [95% CI 40.0%, 40.0%], win rate 100.0% (5W/0T/0L over 5 trial(s)) — credibly better
✅ maui-safe-area — detailsReason: Mean preference +85.0% [95% CI 37.3%, 132.7%], win rate 100.0% (4W/0T/0L over 4 trial(s)) — credibly better
✅ maui-shell-navigation — detailsReason: Mean preference +56.0% [95% CI 2.2%, 109.8%], win rate 80.0% (4W/1T/0L over 5 trial(s)) — credibly better
✅ maui-theming — detailsReason: Mean preference +32.0% [95% CI 9.8%, 54.2%], win rate 80.0% (4W/1T/0L over 5 trial(s)) — credibly better
🔍 Full Results - additional metrics and failure investigation steps ▶ Sessions Visualisation -- interactive replay of all evaluation sessions |
✅ 7/7 at the restored
|
| Skill | Δ Preference [95% CI] | W/T/L | |
|---|---|---|---|
| maui-safe-area | ✅ | +85.0% [+37.3%, +132.7%] | 4/0/0 |
| maui-shell-navigation | ✅ | +56.0% [+2.2%, +109.8%] | 4/1/0 |
| maui-app-lifecycle | ✅ | +55.0% [+7.3%, +102.7%] | 4/0/0 |
| maui-collectionview | ✅ | +40.0% [+40.0%, +40.0%] | 5/0/0 |
| maui-data-binding | ✅ | +40.0% [+40.0%, +40.0%] | 4/0/0 |
| maui-dependency-injection | ✅ | +40.0% [+40.0%, +40.0%] | 5/0/0 |
| maui-theming | ✅ | +32.0% [+9.8%, +54.2%] | 4/1/0 |
30 wins, 2 ties, 0 losses. All overfit ✅ Low, all activation 100%.
The 5-scenario design is what carried it
This run is a clean natural experiment for the tie-sensitivity point:
maui-shell-navigationandmaui-themingeach drew a tie — and both still passed, at 4W/1T over 5 scenarios.- At 4 scenarios that same 3W/1T shape yields
[−1.8%, +61.8%]and fails.
So the three skills that previously flapped are now insulated by the regression-guard scenarios, and they earned it on the first strict run. The four skills still on 4 scenarios (app-lifecycle, data-binding, safe-area) happened to draw no ties this time — they remain the ones exposed to the artifact, which is a repo-wide observation rather than anything this PR needs to fix.
Where the PR stands
- 7/7 at
runs: 1(this run) and 7/7 twice atruns: 3ona1eec661— consistent across both settings. - Cross-family on
9c02b413: 23/35 cells, no regressions, every cell net-positive or neutral. - Local cross-family smoke test on the changed skills: 19W/0T/1L (directional; high error rate disclosed).
- Scope verified: exactly 14 files, all under
plugins/dotnet-maui/andtests/dotnet-maui/.
@AbhitejJohn — the cross-family run you announced at 19:01Z hasn't posted results and I can't see an evaluation-run dispatch for it in the workflow list; it may not have taken. No rush from my side given the above, but flagging in case it failed silently.
@jfversluis @Redth — ready for your review whenever suits.
|
@kubaflo : Sorry, yes. It's underway - needed to be unstuck. |
🧪 Cross-family evaluation — re-run on latest commit (
|
| Skill | opus | gpt | sonnet46 | haiku | mai | Pass | Δ vs prev |
|---|---|---|---|---|---|---|---|
| maui-app-lifecycle | ✅ | ✅ | ✅ | ✅ | ✅ | 5/5 | = |
| maui-theming | ✅ | ✅ | ✅ | ✅ | ✅ | 5/5 | 🔼 +3 |
| maui-safe-area | ✅ | ✅ | ✅ | ✅ | 4/5 | = | |
| maui-dependency-injection | ✅ | ✅ | ✅ | ✅ | 4/5 | 🔼 +2 | |
| maui-data-binding | ➖ | ✅ | ✅ | ✅ | ✅ | 4/5 | 🔼 +1 |
| maui-shell-navigation | ✅ | ✅ | ✅ | ✅ | 4/5 | 🔽 −1 | |
| maui-collectionview | ➖ | ✅ | ✅ | ✅ | ➖ | 3/5 | 🔼 +1 |
| Per-executor | 5/7 | 7/7 | 6/7 | 5/7 | 6/7 | 29/35 |
Per-cell detail (win rate W/T/L · mean preference)
| Skill | opus | gpt | sonnet46 | haiku | mai |
|---|---|---|---|---|---|
| app-lifecycle | ✅ 83% 10/1/1 +0.45 | ✅ 100% 12/0/0 +0.45 | ✅ 92% 11/1/0 +0.52 | ✅ 100% 12/0/0 +1.00 | ✅ 100% 12/0/0 +0.75 |
| collectionview | ➖ 33% 5/6/4 +0.03 | ✅ 73% 11/4/0 +0.29 | ✅ 53% 8/6/1 +0.19 | ✅ 100% 15/0/0 +0.48 | ➖ 53% 8/5/2 +0.16 |
| data-binding | ➖ 58% 7/1/4 +0.10 | ✅ 100% 12/0/0 +0.40 | ✅ 75% 9/3/0 +0.30 | ✅ 100% 12/0/0 +0.45 | ✅ 67% 8/3/1 +0.23 |
| dependency-injection | ✅ 93% 14/0/1 +0.43 | ✅ 73% 11/2/2 +0.24 | ✅ 87% 13/0/2 +0.45 | ✅ 73% 11/4/0 +0.29 | |
| safe-area | ✅ 83% 10/2/0 +0.58 | ✅ 83% 10/1/1 +0.55 | ✅ 100% 12/0/0 +1.00 | ✅ 92% 11/1/0 +0.87 | |
| shell-navigation | ✅ 93% 14/0/1 +0.35 | ✅ 87% 13/2/0 +0.43 | ✅ 93% 14/1/0 +0.57 | ✅ 80% 12/0/3 +0.32 | |
| theming | ✅ 80% 12/3/0 +0.32 | ✅ 100% 15/0/0 +0.40 | ✅ 93% 14/1/0 +0.41 | ✅ 100% 15/0/0 +0.76 | ✅ 73% 11/2/2 +0.48 |
What changed vs the previous commit (23/35 → 29/35)
maui-themingfixed across the board — was 2/5, now 5/5 (opus, sonnet46, mai all flipped to conclusive passes).maui-dependency-injection2/5 → 4/5;maui-data-binding3/5 → 4/5;maui-collectionview2/5 → 3/5.maiexecutor jumped 2/7 → 6/7; sonnet46 4/7 → 6/7; opus 4/7 → 5/7.- Minor slips:
maui-shell-navigation5/5 → 4/5 andmaui-safe-areasonnet46 now⚠️ — both are unmatched-trajectory artifacts (still strongly positive: haiku shell-nav +0.76; sonnet46 safe-area +0.84), not quality losses.
Interpretation
- No regressions — all 35 cells net-positive. Remaining non-passes are the two familiar soft spots (
maui-collectionviewfor opus/mai, opusmaui-data-binding) where gains are real but small (CI includes 0), plus a few unmatched-trajectory inconclusives with strong positive means. - gpt 7/7 again; the latest commit meaningfully lifts the Claude-family and MAI executors. Net a clear improvement over the prior revision.
Legend:
Summary
Addresses #895 — the cross-family evaluation for the
dotnet-mauiplugin (8 skills, 48% pass, 1 P0).Every claim in this PR was validated empirically by building a real .NET MAUI app against the current SDK — not by source reading alone. That mattered: one of my initial "fixes" turned out to be wrong and was reverted (see below).
🔴 P0 —
maui-collectionview(FIX-REGRESSION)Root cause found: the skill documented markup that does not compile.
ItemSizingStrategywas shown onLinearItemsLayoutin bothSKILL.mdandreferences/collectionview-api.md. It is declared onStructuredItemsView, so the documented form is a hard build break:This is a plausible driver of the "skilled is worse than baseline" signal — the skill actively taught broken XAML. Corrected to set it on
<CollectionView>, keeping the invalid form as an explicit ❌ counter-example.Per the CTA's FIX-REGRESSION guidance, also added:
ListView, don't churn style.🔴 HIGH —
maui-app-lifecycle(non-compiling code, newly found)The iOS
ConfigureLifecycleEventsexamples called.DidBecomeActive()/.WillResignActive(), which don't exist:Corrected to
.OnActivated()/.OnResignActivation(). The platform-mapping tables now show both the UIKit selector and the builder method, because the names deliberately differ — that mismatch is exactly what made this easy to get wrong.Correctness fixes
maui-data-bindingBuild.Tasks/BuildException.cs+ErrorMessages.resx.maui-safe-areaWindowSoftInputModeAdjust.Resizewas "removed" — it still compiles and is not obsolete. Reframed as Android-only/superseded. Brevity deliberately preserved (EFFICIENT-WIN).🟡 STRENGTHEN — decisiveness
Ties dominated
maui-shell-navigation,maui-theming,maui-data-bindingandmaui-dependency-injection: the content was correct but read as reference prose the model already knows, so the judge saw no behaviour change.Each now has a compact "Rules That Change the Answer" table converting prose into when-A-do-B guidance (e.g.
IQueryAttributableon the ViewModel not the Page;ContentTemplatefor lazy page creation;AddScopedsilently behaving as Singleton without anIServiceScope), plus an explicit "don't churn working code" stop-condition to avoid trading ties for losses.maui-theming's{AppThemeBinding Light={DynamicResource …}}guidance. ReadingAppThemeBindingExtensionsuggested the nestedDynamicResourcecould never resolve, and I initially "fixed" it. A runtime probe disproved that: after swapping the dictionary the value tracked it (#FF0000→#0000FF) while aStaticResourcecontrol stayed frozen at#FF0000. The original guidance is correct — reverted. (This is why the empirical step was worth it.)maui-shell-navigationfixture/SDK pinning. Per the [skills-eval] Judge-side transient failures (disabled PAT + session.idle timeout) corrupt reliability verdicts #909 correction, the errored trial was a judge-side disabled-PAT failure, not fixture nondeterminism — so it was treated as STRENGTHEN, not FIX-RELIABILITY.dotnet-maui-doctor(EXEMPLAR) — unchanged.Validation
skill-validator check --plugin ./plugins/dotnet-maui→ ✅ all checks passed (8 skills, 0 errors, 26 reference files scanned).net11.0-maccatalystMAUI app builds clean with every corrected snippet (CollectionView grid/selection/refresh/swipe/empty-view, ShellContentTemplate,GetDeferral/Complete,ShellNavigationQueryParameters,IQueryAttributable, DI registrations, iOS lifecycle).Full cross-family re-evaluation still to be triggered per the instructions in #895.