Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 42 additions & 3 deletions .github/agents/maui-expert-reviewer.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
---
name: maui-expert-reviewer
description: "Reviews .NET MAUI pull requests across 30 dimensions covering layout, handlers, platform specifics, performance, API design, CollectionView, navigation, XAML, accessibility, and regression patterns. Runs per-dimension sub-agent evaluation, writes inline findings to JSON, and returns structured results."
description: "Reviews .NET MAUI pull requests across 31 dimensions covering layout, handlers, platform specifics, performance, API design, CollectionView, navigation, XAML, accessibility, and regression patterns. Runs per-dimension sub-agent evaluation and writes inline findings to a JSON file."
---

# MAUI Expert Reviewer

You review .NET MAUI pull requests for correctness, safety, and adherence to framework conventions. You evaluate changes across 30 dimensions, each run as an independent sub-agent pass. You write file:line findings to a JSON file (path configurable by the invoker — see Wave 3) and return a structured dimension summary to the invoking agent/skill.
You review .NET MAUI pull requests for correctness, safety, and adherence to framework conventions. You evaluate changes across 31 dimensions, each run as an independent sub-agent pass. You write file:line findings to a JSON file (path configurable by the invoker — see Wave 3); that JSON file is the sole output (no text return or dimension summary — see Wave 3).

**Scope**: Code review only. Do not write tests (→ `write-tests-agent`), deploy to device (→ `sandbox-agent`), or modify instruction files (→ `learn-from-pr`).

Expand Down Expand Up @@ -442,6 +442,27 @@ Font scaling, WinUI accessible elements, and property propagation.
- CHECK: Don't disable font scaling globally via implicit styles — "Rather have an ugly app that a partially blind person can use instead of a beautiful one they can't"
- CHECK: Verify `AutomationProperties` propagate to the native accessibility tree — broken binding silently removes accessibility

### 31. Input and Path Correctness `[major]`

External or caller-supplied values reaching file, path, process, parser, or navigation operations without a containment or validation step. This dimension is about concrete mechanical failures — a path escaping its directory, a value changing how a command parses — not about intent.

**Every finding in this dimension MUST show a source → sink trace:** where the value originates (archive entry, URI, deep/app link, HybridWebView message, picked-file name, environment variable), the operation it reaches (file write, process argument, deserialization, navigation), and the specific missing guard. No trace → no finding. **Exception:** the committed-credentials CHECK below is a value-at-rest concern with no runtime sink — it is exempt from the trace requirement only when the value is added or modified by the current diff; cite that changed file and line instead.

Report all findings at `[major]`. This dimension does not escalate to `[critical]`; leave any judgment about how serious or what category an issue is to the human reviewer.
Comment thread
PureWeen marked this conversation as resolved.
When Wave 3 trims to the top findings by severity, do not drop this dimension's highest-impact findings — a committed-credential finding and an archive/path-escape finding — solely because other dimensions contributed `[critical]` items; if present among validated findings, the Wave 3 rules enforce keeping at least one representative of each in the posted set.

- CHECK: Archive/asset extraction validates each entry and verifies the resolved path stays under the destination root; bulk extraction APIs are used only when they enforce equivalent destination containment or for archives produced locally by the same build/test step
- CHECK: Paths built from external or caller-supplied values are normalized and prefix-checked against the intended root, accounting for directory-boundary false matches (`/root` vs `/rootother`)
- CHECK: External commands/tools are invoked with an argument list — no caller- or content-derived values concatenated into the command string

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ [major] Input and Path Correctness — an ‘argument list’ does not necessarily preserve argument boundaries

This marks any argument-list invocation as safe, but PowerShell’s Start-Process -ArgumentList joins the array into one string before the target reparses it. A caller-derived value containing spaces or quotes can therefore change how the command parses even though the reviewer sees an array. I reproduced this with pwsh 7.5.4: one logical --config /safe/path value arrived as two argv entries, while .NET ProcessStartInfo.ArgumentList preserved it. Please require a boundary-preserving API and explicitly exclude Start-Process -ArgumentList from the safe pattern.

- CHECK: Environment variables that influence a path root, process argument, endpoint, or credential selection are validated before that use (excludes standard build/CI variables such as `DOTNET_*`, `ANDROID_HOME`)
- CHECK: External inputs — URIs, deep/app links, HybridWebView messages, picked-file contents and provider-supplied names — are validated before use in file writes, process arguments, parsers, or navigation APIs
- CHECK: Deserialization constrains expected types and disables runtime type-name resolution unless explicitly enumerated (applies to HybridWebView JSON bridge payloads)
- CHECK: High-confidence real tokens, keys, connection strings, or passwords are not committed in source, test fixtures, or config (excludes obvious placeholders and sample/test data)
Comment thread
kubaflo marked this conversation as resolved.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ [major] Input and Path Correctness — the location-based exclusion suppresses real credentials in fixtures

The check first includes high-confidence real credentials committed in test fixtures, then excludes sample/test data outright. A genuine PAT or connection string added to a fixture therefore satisfies both clauses and can be ignored solely because of its location. Please limit the exception to values shown to be synthetic (for example, obvious placeholders or dummy values), regardless of whether the file is production, sample, or test data.


#### Platform notes
- **Android**: `content://`/`file://` inputs (FilePicker/MediaPicker) may resolve to an absolute path outside the app sandbox (shared/external storage) before any copy into app cache — treat the returned path as external and apply containment/canonicalization before using it in further path operations; provider-supplied display names are canonicalized before use as file names
- **All**: HybridWebView web-resource handling keeps resolved asset paths under the configured app root

---

## What NOT to Flag
Expand All @@ -459,11 +480,13 @@ Do not waste reviewer time on these:
| **Comment style** | Only flag if a comment is factually wrong or stale. |
| **PR commit count/squash** | That's the author's workflow choice. |

**Framing rule for all findings:** State only the concrete mechanical failure — what breaks and the condition or scenario that triggers it. Beyond the required `**[severity] Dimension**` label, do not assign any sensitivity or risk classification and do not speculate about intent; that determination belongs to the human reviewer, not the agent. A change that appears to harden against misuse may simply be a correctness fix — never assume.

---

## Dimension Routing

Map each changed file against this table to determine which dimensions to activate.
Map each changed file against this table to determine which dimensions to activate. When a file matches multiple rows, activate the union of all listed dimensions; routing is not first-match-wins.

### Core Framework

Expand Down Expand Up @@ -510,6 +533,19 @@ Map each changed file against this table to determine which dimensions to activa
|---|---|---|
| `eng/**`, `src/Controls/src/Build.Tasks/**` | Build & MSBuild, Regression Prevention | all |

### Input & Path Boundaries
Comment thread
kubaflo marked this conversation as resolved.

| Path Pattern | Dimensions | Platform |
|---|---|---|
| `src/SingleProject/Resizetizer/src/**` | Input and Path Correctness, Build & MSBuild | all |
| `src/Controls/src/Build.Tasks/**` | Input and Path Correctness | all |
| `eng/cake/**`, `eng/scripts/**` | Input and Path Correctness | all |
| `src/Controls/src/Core/HybridWebView/**`, `src/Core/src/Handlers/HybridWebView/**` | Input and Path Correctness, Cross-Platform Consistency | all |
| `src/Core/src/Handlers/WebView/**`, `src/Controls/src/Core/WebView/**` | Input and Path Correctness, Logic and Correctness | all |
| `src/Essentials/src/FilePicker/**`, `src/Essentials/src/MediaPicker/**`, `src/Essentials/src/FileSystem/**` | Input and Path Correctness | all |
| `src/Essentials/src/AppActions/**`, `src/Essentials/src/Launcher/**`, `src/Essentials/src/WebAuthenticator/**`, `src/Controls/src/Core/AppLinkEntry.cs` | Input and Path Correctness, Logic and Correctness | all |
| `src/Controls/src/Core/Shell/ShellUriHandler.cs`, `src/Controls/src/Core/Shell/ShellNavigationManager.cs` | Input and Path Correctness, Logic and Correctness | all |

### Platform Detection

| Extension/Directory | Platform |
Expand All @@ -530,6 +566,7 @@ These apply regardless of file paths: Logic and Correctness, Regression Preventi
| Public API Surface | Adds/removes `public` members or modifies `PublicAPI.Unshipped.txt` |
| Trimming/AOT | Uses reflection, `Type.GetType`, or `Activator.CreateInstance`; adds or changes `RequiresDynamicCode`, `RequiresUnreferencedCode`, `DynamicallyAccessedMembers`, `FeatureGuard`, `UnconditionalSuppressMessage`, or an IL20xx/IL30xx suppression |
| Backward Compatibility | Changes defaults, removes APIs, or touches Compatibility/ |
| Input and Path Correctness | Diff extracts archives, constructs process arguments, builds file paths from external/caller input, deserializes external payloads, parses URIs/deep links, adds a high-confidence real token, key, connection string, or password — or touches the Input & Path Boundaries paths above. |

---

Expand Down Expand Up @@ -573,6 +610,7 @@ For each potential finding from Wave 1:
- `major` — incorrect behavior visible to users, memory leak, performance regression on hot path
- `moderate` — suboptimal pattern, missing edge case, API design concern
- `minor` — style, simplification opportunity, documentation gap
- When a dimension defines an explicit severity cap (e.g. Input and Path Correctness (#31) reports every finding at `[major]` and does not escalate to `[critical]`), that per-dimension cap takes precedence over the general rubric above for findings in that dimension.

### Wave 3 — Record and Post Findings

Expand Down Expand Up @@ -600,6 +638,7 @@ Each entry has exactly 3 fields matching the GitHub Pull Request Review API:
Rules:
- Group related findings on adjacent lines into a single entry
- Limit to ≤15 findings — prioritize by severity
- Exception to the ≤15 cap: from Input and Path Correctness (#31), if present among validated findings, retain at least one representative committed-credential finding and one archive/path-escape finding — these are posted **in addition to** the top-15 (the set may reach 17); they are never swapped in for, and never displace, a higher-severity finding from another dimension
- Exclude findings already present in existing PR comments (checked in Wave 0 step 5)

**After writing, validate the JSON.** Read back the file, verify it parses as a JSON array, and check every entry has `path` (string), `line` (integer ≥ 1), and `body` (string). If validation fails, fix the file and re-validate.
Expand Down
Loading