audit: add build-free XAML analyzer (Phase 1, markup-only)#114
Conversation
Implements Phase 1 of the XAML analyzer design note as a build-free static runner feeding the existing audit/ pipeline as a second fact source (not a parallel linter). Pure stdlib XML via an expat tree builder, so it has no toolchain prerequisite and runs on Linux CI like the other build-free runners. - audit/static/tools/xaml_check.py: line-preserving parse + rules XAML101/102/103/104/106/107/108/109 (virtualization-off, per-keystroke binding, template complexity, Freezable/x:Shared/DynamicResource/merged- dictionary perf), with the design note's exception lists. Emits the canonical SARIF record; file-level findings stay file-level (line 0). WPF-only rules short-circuit on Avalonia. Embedded-fixture selftest covers every rule, the line-preservation requirement, and the SARIF round-trip. - run_static.py: wire "xaml" into the build-free tier (+ integration selftest). - desktop-wpf profile: add xaml to build_free; category 8 (broken virtualization) is no longer NO-TOOL static now that XAML107/109 cover it. - taxonomy: map XAML rules to Plan.md §2 categories (6/8/9) + a XAML1* safety net; add category-8 severity (P2). - docs/notes/xaml-analyzer-design.md: the design note, alongside the impl. - ci.yml + audit/README.md: run and document the new selftest. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015zoG4YNCUf7RA5r8GAXMmb
… note
Folds in the cheap, markup-detectable rules surfaced by the research-comb
feedback, and pins the Phase-2 architecture decision in the design note.
New Phase-1 rules in xaml_check.py (all stdlib, all selftested):
- XAML110 ImageDecodedAtFullSize — thumbnail Image with a plain-URI Source
(no decode-to-size possible without BitmapImage/DecodePixelWidth). WPF-only.
- XAML111 LayoutTransformSuspicious — LayoutTransform forces a measure/arrange
pass; RenderTransform is cheaper unless layout must reflow. WPF-only candidate.
- XAML112 TemplateBindingOpportunity — a TemplatedParent Binding with no
converter/two-way inside a ControlTemplate could be {TemplateBinding}.
- XAML113 InlineFreezableDuplication — identical inline brush/geometry declared
more than once; hoist to one shared keyed resource (the inline case of XAML100).
- taxonomy: map XAML110/112/113 -> cat 9, XAML111 -> cat 8 (layout cost).
- README + design-note catalogue: document the four rules.
- design note: add "Phase 2 mechanics — the binding-path join" section. It keeps
the link-extractor in own-check (canonical in Own.NET), NOT a parallel
OwnAudit.Xaml C# project (that is the post-lift-out product form), and ties the
static binding-join candidate to runtime confirmation via correlate.py.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015zoG4YNCUf7RA5r8GAXMmb
|
Caution Review failedPull request was closed or merged during review 📝 WalkthroughWalkthroughThis PR adds a build-free XAML analyzer, maps its rule IDs into audit categories, and wires the new tier into static execution, CI selftests, and documentation. ChangesXAML analyzer integration
Sequence Diagram(s)sequenceDiagram
participant Profile as desktop-wpf.yml
participant Static as run_static.py
participant Xaml as audit/static/tools/xaml_check.py
participant Sarif as xaml-check.sarif
Profile->>Static: enables build_free xaml
Static->>Xaml: run_xaml_check(target, out_dir)
Xaml->>Sarif: write SARIF results
Static->>Static: append SARIF to sarif_inputs
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 4✅ Passed checks (4 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment |
No behavior change — the 31-check selftest still passes. Resolves the ruff failures on PR #114: - B033: drop the duplicate "ListView" in ITEMS_CONTROLS - UP037: unquote the Node self-referencing annotations (from __future__ is on) - UP035: import Callable from collections.abc, not typing - F841: remove the dead `flags` dict in _rule_virtualization - E501: wrap the over-long SARIF round-trip line in the selftest Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015zoG4YNCUf7RA5r8GAXMmb
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 0f0a3b552b
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
|
Caution Failed to replace (edit) comment. This is likely due to insufficient permissions or the comment being deleted. Error details |
|
Caution Failed to replace (edit) comment. This is likely due to insufficient permissions or the comment being deleted. Error details |
…view) Two correctness fixes from the Codex review on PR #114: - _resource_dictionaries now also yields implicit <X.Resources> property elements (the common WPF syntax: keyed resources as direct children with no <ResourceDictionary> wrapper). Without this, XAML101/102/106 only fired on files that explicitly wrapped resources in <ResourceDictionary>, silently missing most real WPF files despite the claimed category-9 coverage. No double counting: when <X.Resources> wraps an explicit <ResourceDictionary>, the wrapper has no direct keyed children, so the inner dictionary is still the one that matches. - run_xaml_check reads bytes and lets expat honor the BOM / XML-declaration encoding, instead of forcing read_text(utf-8). Legacy WPF XAML saved as UTF-16 was corrupted by the forced decode, parse_xaml returned None, and the file was silently skipped while still counted as scanned. Selftest grows to 34 checks: an implicit-<X.Resources> dictionary (with line preservation) and a UTF-16 (BOM + declaration) document that must parse. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015zoG4YNCUf7RA5r8GAXMmb
Implements Phase 1 of the XAML analyzer design note as a build-free static
runner feeding the existing audit/ pipeline as a second fact source (not a
parallel linter). Pure stdlib XML via an expat tree builder, so it has no
toolchain prerequisite and runs on Linux CI like the other build-free runners.
XAML101/102/103/104/106/107/108/109 (virtualization-off, per-keystroke
binding, template complexity, Freezable/x:Shared/DynamicResource/merged-
dictionary perf), with the design note's exception lists. Emits the canonical
SARIF record; file-level findings stay file-level (line 0). WPF-only rules
short-circuit on Avalonia. Embedded-fixture selftest covers every rule, the
line-preservation requirement, and the SARIF round-trip.
virtualization) is no longer NO-TOOL static now that XAML107/109 cover it.
net; add category-8 severity (P2).
Co-Authored-By: Claude Opus 4.8 noreply@anthropic.com
Claude-Session: https://claude.ai/code/session_015zoG4YNCUf7RA5r8GAXMmb
Summary by CodeRabbit
New Features
Documentation
Tests