Skip to content

audit(xaml): emit the Phase-2 facts layer (xaml-facts.json)#115

Merged
PhysShell merged 3 commits into
mainfrom
claude/oun-net-html-analyzer-drff2t
Jun 26, 2026
Merged

audit(xaml): emit the Phase-2 facts layer (xaml-facts.json)#115
PhysShell merged 3 commits into
mainfrom
claude/oun-net-html-analyzer-drff2t

Conversation

@PhysShell

@PhysShell PhysShell commented Jun 26, 2026

Copy link
Copy Markdown
Owner

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):
    • XamlResourceGraphresources (keyed type + scope + line) and merged_dictionaries.
    • XamlBindingFactsbindings (a parsed binding-markup parser: path / mode / UpdateSourceTrigger / converter / Delay / RelativeSource), event_handlers (Click= / EventSetter), converters_used, and the file's x:Class. These are the pointers into C# the Roslyn join resolves.
    • Envelope mirrors OwnIR's *.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 — 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 (does not re-derive) 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 under audit/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

    • Added generation of a new XAML “facts” report (xaml-facts.json) alongside existing analysis output.
    • Added/extended XAML self-tests to cover the new facts extraction step.
  • Bug Fixes

    • Improved XAML analysis robustness by safely handling malformed markup.
    • Reduced redundant parsing by reusing a single parse pass for findings and facts.
  • Documentation

    • Updated audit README and XAML analyzer design notes to describe the new Phase-1 → Phase-2 facts seam.

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
@coderabbitai

coderabbitai Bot commented Jun 26, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 6476ffd1-6c6e-49cc-93c0-7409c40af6de

📥 Commits

Reviewing files that changed from the base of the PR and between 892cdd1 and a55f50f.

📒 Files selected for processing (2)
  • audit/static/tools/xaml_check.py
  • audit/static/tools/xaml_facts.py
🚧 Files skipped from review as they are similar to previous changes (1)
  • audit/static/tools/xaml_facts.py

📝 Walkthrough

Walkthrough

Adds a new XAML facts extractor, updates xaml_check.py to emit xaml-facts.json alongside SARIF, and extends CI, README, and design notes to cover the new selftest and Phase-1/Phase-2 seam.

Changes

XAML Phase-2 seam

Layer / File(s) Summary
Facts parsing and binding
audit/static/tools/xaml_facts.py
Defines binding and resource-key parsing helpers, scope detection, and document-level extraction for binding facts and keyed resources.
Facts document CLI and selftest
audit/static/tools/xaml_facts.py
Builds per-document and per-module fact envelopes, scans XAML files, exposes the CLI, and validates the output with embedded selftests.
Runner integration
audit/static/tools/xaml_check.py
Reuses parsed XAML trees, collects per-file facts during the scan, and writes both xaml-check.sarif and xaml-facts.json.
CI and docs alignment
.github/workflows/ci.yml, audit/README.md, docs/notes/xaml-analyzer-design.md
Adds the new selftest step and documents the XAML Phase-1 to Phase-2 seam and emitted artifact.

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
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~30-90 minutes

Poem

🐇 I sniffed the XAML morning air,
and facts.json hopped everywhere.
SARIF glowed bright,
the seam felt right,
my whiskers say “ship it” with care.

🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main change: adding the XAML Phase-2 facts layer and emitting xaml-facts.json.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch claude/oun-net-html-analyzer-drff2t

Comment @coderabbitai help to get the list of available commands.

@chatgpt-codex-connector chatgpt-codex-connector Bot 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.

💡 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".

Comment thread audit/static/tools/xaml_facts.py Outdated
Comment thread audit/static/tools/xaml_facts.py
…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

@coderabbitai coderabbitai Bot 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.

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

📥 Commits

Reviewing files that changed from the base of the PR and between 52ce8c7 and 892cdd1.

📒 Files selected for processing (5)
  • .github/workflows/ci.yml
  • audit/README.md
  • audit/static/tools/xaml_check.py
  • audit/static/tools/xaml_facts.py
  • docs/notes/xaml-analyzer-design.md

Comment thread audit/static/tools/xaml_check.py Outdated
Comment thread audit/static/tools/xaml_facts.py
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
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.

2 participants