Skip to content
Alex Soto edited this page Jun 23, 2026 · 3 revisions

name: xcode-api-diff-noise-cleaner description: > Analyze and triage Xcode SDK API diffs between betas for the dotnet/macios binding season. USE FOR: reviewing API diffs, classifying diffs as nothing or actionable, understanding xcode diff folder structure, cleaning up comment-only diffs, checking binding status, running make diff or make all. DO NOT USE FOR: writing C# bindings code (that's a separate task after triage).

Xcode API Diff Analysis

Knowledge skill for triaging Xcode SDK header diffs in the macios.wiki repo. Helps classify diffs as actionable API changes vs noise (comments, macros, formatting) and understand the binding status tracking system.

When to Use This Skill

  • Reviewing raw framework diffs between Xcode beta versions
  • Classifying whether a diff contains real API changes or only noise
  • Understanding the xcode diff folder structure and Makefile workflow
  • Cleaning up diffs that only contain comment/documentation changes
  • Checking or updating the Bindings-Status table
  • Running make diff or make all after Xcode updates

Repository Structure

macios.wiki/
├── Makefile                        # Drives diff generation and status table updates
├── xcode-diff.cs                   # Script that diffs SDK framework headers
├── update.cs                       # Script that regenerates the Bindings-Status table
├── xcode{version}/
│   ├── xcode{version}-Bindings-Status.md   # Auto-generated status table (NEVER edit directly)
│   ├── b1/ b2/ b3/ rc/            # Per-beta/release diff directories
│   │   ├── iOS/
│   │   ├── tvOS/
│   │   ├── macOS/
│   │   └── MacCatalyst/
│   │       └── {Framework}-{platform}-xcode{ver}-{suffix}.md

Diff File Naming

{Framework}-{platform}-xcode{version}-{suffix}.md — e.g. AVKit-iOS-xcode26.4-b2.md

An empty diff file contains only #{Framework}.framework with no content below it.

Bindings-Status Table Conventions

The status table is generated — never edit it directly. Instead, edit the diff files and run make all -j.

Marker Meaning
~~strikeout~~ + *nothing* No new APIs — diff was reviewed and contains no actionable changes
bold + **???** Has changes, not yet bound
[PR{number}]({url}) Binding work in progress or done
:warning: Tracked via GitHub issue
- Framework not available on that platform

Claiming Work

To mark a diff as "nothing": edit the diff file to contain only the framework header (remove all diff content), then make all -j regenerates the table with strikeout styling.

To claim a binding: add your PR link to the diff file following the existing format.

Classifying Diffs

When reviewing a diff, classify it into one of these categories:

🔍 Read each +/- line in its real header context first. A changed line can sit inside a block comment, a multi-line HeaderDoc tag, or a \-continued macro — you often can't tell from the diff hunk alone. When in doubt, open the actual installed SDK header at the line numbers in the @@ hunk and reconstruct the surrounding context. Misreading a comment line as code (or code as comment) is the most common triage error.

✅ Actionable — Real API Changes

New or modified: classes, protocols, methods, properties, enums, typedefs, constants, or delegate methods. These need C# bindings.

Availability & deprecation changes are also actionable — even when they ride on an attribute or macro rather than a brand-new declaration. A change to when or where an API exists is real binding work (it maps to [SupportedOSPlatform] / [ObsoletedOSPlatform] / [UnsupportedOSPlatform]). Treat as actionable:

  • API_AVAILABLE / API_DEPRECATED / API_UNAVAILABLE / API_DEPRECATED_WITH_REPLACEMENT, and the NS_AVAILABLE* / NS_DEPRECATED* / __attribute__((availability(...))) families
  • An existing API that gains, tightens, or loses a platform/version (e.g. a property that newly carries API_AVAILABLE(ios(27.0)))

The macro-redefinition trap. A #define change is not automatically noise. If the macro expands to an availability/deprecation/attribute and is applied to public API, redefining it rewrites that whole API surface — actionable. Real case (xcode27.0 b1): ExposureNotification redefined EN_API_AVAILABLE from API_AVAILABLE( ios( 12.5 ) ) to API_DEPRECATED( "No longer supported.", ios( 12.5, 27.0 ) ) — one line that deprecated ~75 public symbols framework-wide. Before dismissing any #define edit, check what it expands to and whether public API uses it.

❌ Noise — Mark as "Nothing"

Category 1: Comment/documentation-only changes

  • /* ... *//// ... doc comment format rewrites
  • Typo fixes in comments (e.g. "labelling" → "labeling")
  • @c/@p → backtick formatting changes
  • Reformatted multi-line doc comments
  • Copyright-year / license-header rewrites

Category 2: Internal/build-system changes

  • Preprocessor guard reordering (#ifdef, #elif, #endif)
  • Macro renames/edits whose expansion does not change public API (internal-only names, e.g. TARGET_OS_LINUX_CLOUD → internal name). ⚠️ A macro that expands to availability/deprecation/attributes IS public API — see "The macro-redefinition trap" above.
  • Version / build-number #define bumps (e.g. SPRITEKIT_VERSION 4000041000)
  • Swift sendability macros (NS_SWIFT_SENDABLE, NS_SWIFT_UNAVAILABLE)
  • Header audit pragmas (#pragma clang assume_nonnull)
  • extern "C" guard shuffling
  • #include/#import reordering

Category 3: Empty or boilerplate-only

  • Diff file has no content below the framework header. Already marked correctly.
  • A brand-new header/framework whose diff is only #import/#include lines, include-guard boilerplate, or an empty umbrella with no public declarations — nothing to bind yet (real cases: AppIntentsTypeSupport, MediaDevice, MetalPerformanceShaders, SpatialPreview, AppManagedFeatures).

⚠️ Mixed diffs: If a diff contains both noise AND real API changes, it is actionable. NEVER clean out the noise portions — the binding author WILL HANDLE everything.

NEVER mark a diff as "nothing" if it contains any new method signatures, property declarations, enum values, class/protocol declarations, or typedef changes — even if surrounded by comment noise.

Borderline Calls

Only for genuinely hard cases — availability/deprecation shifts, macro redefinitions, brand-new frameworks. Don't apply this to obvious noise or obvious new API.

  1. Check prior-season precedent. See how the same or a similar framework was triaged in an earlier season (xcode26.x/) and stay consistent. Real calls kept ExposureNotification consistent with MetricKit, and treated a boilerplate-only new framework per the AlarmKit-26.0 precedent.
  2. Validate your rule against prior decisions before bulk-marking. Replay your classification over a previous season's already-triaged diffs; if it would mark any real API as "nothing", the rule is too aggressive. (Validating against 233 prior-season files caught zero false negatives in xcode27.0 b1.)
  3. Rubber-duck the borderline ones with a second model before committing a "nothing".

Makefile Workflow

Generating Diffs for a New Beta

  1. Install both the old and new Xcode versions
  2. Update Makefile variables: XCODE_OLD, XCODE_NEW, BRANCH, SUFFIX
  3. Run make diff -j — generates per-framework, per-platform diff files
  4. Run make all -j — regenerates the Bindings-Status table
  5. Commit and push all new/updated files

After Reviewing/Claiming Diffs

Run make all -j to regenerate the status table, then commit.

Stop Signals

Stop analysis when:

  • You've classified all diffs requested by the user
  • You've determined whether a specific diff is actionable or noise
  • The user has the information needed to decide next steps
  • Do NOT start writing C# bindings — that's a separate task

Clone this wiki locally