audit(xaml): emit the Phase-2 facts layer (xaml-facts.json)#115
Conversation
Builds the Phase-1 -> Phase-2 seam from the design note: the markup pass now
emits a structured fact document alongside its SARIF, so the existing Roslyn
extractor (frontend/roslyn/OwnSharp.Extractor -> OwnIR) and the binding-path
join have something to read instead of re-parsing XAML.
- xaml_facts.py: extracts the two fact families from the parsed tree —
XamlResourceGraph (resources, merged_dictionaries) and XamlBindingFacts
(bindings with a parsed binding-markup parser: path / mode /
UpdateSourceTrigger / converter / Delay / RelativeSource, plus event_handlers,
converters_used, and the file's x:Class). Envelope mirrors OwnIR's
*.facts.json ({xaml_facts_version, module, documents, totals}). Pure stdlib.
- xaml_check: split analyze_text into analyze_root + analyze_text so run_xaml_check
parses each file once and feeds the same tree to both the rules and the facts
extractor; it now writes xaml-facts.json next to xaml-check.sarif.
- selftest (16 checks): the binding-markup parser (positional path, nested
Converter, RelativeSource, TemplateBinding, non-binding rejection, brace-aware
comma split), document facts on a representative view, EventSetter handlers,
and the OwnIR-parallel envelope. Wired into CI.
- design note + README: document the seam and that Phase 2 consumes (not
re-derives) xaml-facts.json.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015zoG4YNCUf7RA5r8GAXMmb
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (2)
🚧 Files skipped from review as they are similar to previous changes (1)
📝 WalkthroughWalkthroughAdds a new XAML facts extractor, updates ChangesXAML Phase-2 seam
Sequence Diagram(s)sequenceDiagram
participant run_xaml_check
participant parse_xaml
participant analyze_root
participant document_facts
participant module_facts
participant Sarif as xaml-check.sarif
participant Facts as xaml-facts.json
run_xaml_check->>parse_xaml: parse each XAML file once
run_xaml_check->>analyze_root: run Phase-1 rules on the tree
run_xaml_check->>document_facts: collect per-file facts
run_xaml_check->>module_facts: aggregate document facts
run_xaml_check->>Sarif: write findings
run_xaml_check->>Facts: write facts artifact
Estimated code review effort🎯 4 (Complex) | ⏱️ ~30-90 minutes Poem
🚥 Pre-merge checks | ✅ 4✅ Passed checks (4 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 892cdd1246
ℹ️ 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".
…Codex review) Two correctness fixes from the Codex review on PR #115: - _resource_scope derives a keyed resource's scope from its nearest owning <X.Resources> ancestor, not the dictionary element. The explicit-wrapper form <UserControl.Resources><ResourceDictionary>... previously recorded scope "root" (the inner ResourceDictionary is not a property element), collapsing the view-local-vs-global distinction the Phase-2 resource graph relies on. Now it keeps "UserControl". - document_facts also captures property-element bindings — <TextBlock.Text> <Binding Path="Name" Converter="{StaticResource money}"/></...> — via a new binding_from_element (attributes read like parse_binding reads the markup-ext string, incl. a nested <Binding.RelativeSource>). The owning control/property come from the parent <Type.Prop> element. These forms are common once a binding needs a converter/relative-source, and were silently missing from bindings / converters_used, so the Roslyn join would skip those paths. Selftest grows to 19 checks (explicit-wrapper scope + property-element binding). 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.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@audit/static/tools/xaml_check.py`:
- Around line 735-737: The artifact writes in run_xaml_check are still
unconditional, so a permission or disk failure from sarif_path.write_text or
facts_path.write_text can abort the run despite the best-effort contract. Wrap
the SARIF and facts file writes in separate try/except blocks inside
run_xaml_check, log or otherwise record the failure, and continue so the
function preserves the “never a crash” behavior; use the existing helpers around
_to_sarif, module_facts, sarif_path, and facts_path to locate the write
sequence.
In `@audit/static/tools/xaml_facts.py`:
- Around line 169-177: The binding collector in xaml_facts.py only handles
attribute-value bindings in the n.attrib loop, so property-element bindings like
TextBlock.Text/Binding are missed. Update the binding extraction logic around
the current parse_binding path to also inspect child elements representing
verbose/property-element bindings, convert them into the same bindings record
shape used in bindings.append, and keep updating converters from any discovered
b["converter"]. Reference the existing parse_binding, bindings.append, and
converters.add flow so the new handling stays consistent with the current
attribute-based parsing.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro Plus
Run ID: b03b93b0-ed08-4f24-8525-577e4bf9854b
📒 Files selected for processing (5)
.github/workflows/ci.ymlaudit/README.mdaudit/static/tools/xaml_check.pyaudit/static/tools/xaml_facts.pydocs/notes/xaml-analyzer-design.md
run_xaml_check documents a never-crash, best-effort contract, but the xaml-check.sarif / xaml-facts.json write_text calls were unconditional, so a permission/disk error would raise and abort the run. Wrap both writes in a single try/except OSError that records the failure as the tier reason and returns available=False — consistent with how a missing target or absent SDK is handled. (The other CodeRabbit comment, property-element bindings, was already addressed in cdd089d.) Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015zoG4YNCUf7RA5r8GAXMmb
Builds the Phase-1 → Phase-2 seam from the XAML analyzer design note: the markup pass now emits a structured fact document alongside its SARIF, so the existing Roslyn extractor (
frontend/roslyn/OwnSharp.Extractor→ OwnIR) and the binding-path join have something to read instead of re-parsing XAML.This is the follow-up to #114 (the Phase-1 markup runner). It adds the facts layer only — no rule changes, no findings changes.
What's in it
audit/static/tools/xaml_facts.py— extracts the two fact families from the parsed tree (the design note's split):resources(keyed type + scope + line) andmerged_dictionaries.bindings(a parsed binding-markup parser:path/mode/UpdateSourceTrigger/converter/Delay/RelativeSource),event_handlers(Click=/EventSetter),converters_used, and the file'sx:Class. These are the pointers into C# the Roslyn join resolves.*.facts.json({xaml_facts_version, module, documents, totals}) so the two fact sources read alike. Pure stdlib — no toolchain, runs on Linux CI.xaml_check.py— splitanalyze_textintoanalyze_root+analyze_textsorun_xaml_checkparses each file once and feeds the same tree to both the rules and the facts extractor; it now writesxaml-facts.jsonnext toxaml-check.sarif.Converter,RelativeSource,TemplateBinding, non-binding rejection, brace-aware comma split), document facts on a representative view,EventSetterhandlers, and the OwnIR-parallel envelope. Wired into CI.xaml-facts.json.Why
Phase 2 (the Roslyn-linked binding-path join →
XAML2xx) needs structured XAML facts to join against OwnIR. The "Layer 2" machinery it joins to —OwnSharp.Extractor(→ OwnIR) and the ClrMD collectors underaudit/runtime/— already exists in this repo; what was missing was the XAML-side fact input. This PR supplies it. The join itself and Phase 3 (runtime correlation) remain deferred.Validation
Full audit selftest suite green (normalize/score/report/xaml_check/xaml_facts/run_static/ingest) and
ruff check .clean. The new module gates on Linux CI like the other build-free runners.🤖 Generated with Claude Code
Generated by Claude Code
Summary by CodeRabbit
New Features
xaml-facts.json) alongside existing analysis output.Bug Fixes
Documentation