Skip to content

Investigating #3509: Images fail to render on macOS#3522

Draft
mattleibow wants to merge 27 commits intomainfrom
dev/issue-3509-macos-drawimage-fix
Draft

Investigating #3509: Images fail to render on macOS#3522
mattleibow wants to merge 27 commits intomainfrom
dev/issue-3509-macos-drawimage-fix

Conversation

@mattleibow
Copy link
Contributor

Investigation: #3509 - Images fail to render on macOS with SkiaSharp 3.116.0

Status: 🔍 Investigating

Issue Summary

  • Title: Images fail to render on macOS with SkiaSharp 3.116.0
  • Symptoms: SKCanvas.DrawImage with SKImage.FromBitmap or SKImage.FromEncodedData results in transparent/empty output.
  • Platform: macOS ARM64, SkiaSharp 3.116.0
  • Reproduction: See repro_3509/ folder. Create a red bitmap, draw to blue surface, verify pixel is red.

Related Issues

Issue Title Why Similar Status
TBD

Links from related issues:

  • TBD

Reproduction Results

Environment SkiaSharp Version Result
macOS ARM64 3.116.0 ❌ Fails (Transparent output)
macOS ARM64 2.88.9 ✅ Works

Current Hypothesis

Regression in SKImage.FromBitmap or SKCanvas.DrawImage implementation in 3.116.0, possibly related to memory ownership or P/Invoke signature changes.

Investigation Plan

  • Fetch issue and extract details
  • Search for related issues
  • Read all comments on related issues
  • Reproduce on target platform
  • Compare working vs broken versions (code diff)
  • Identify fix location

Progress Log

Action Result
Reproduced issue Confirmed regression in 3.116.0

Alternatives Tried

Approach Result Next Step
SKImage.FromBitmap Failed Try SKImage.FromEncodedData
SKImage.FromEncodedData Failed Try 2.88.9
2.88.9 Passed Confirm regression

mattleibow and others added 27 commits February 13, 2026 03:06
…rkflow

- Rewrite docker-testing.md with verified configurations (tested 1.68.3, 2.88.8, 3.116.1)
- Document required libfontconfig dependency (root cause of DllNotFoundException in Docker)
- Add NativeAssets.Linux version matrix (1.x: x64 only, 2.x+: x64/arm64/musl/arm)
- Add Docker repro pattern to SKILL.md Phase 3 step 5
- Update conclusion-guide.md: try Docker before concluding needs-platform for Linux
- Update repro-strategies.md: Docker is reliable (not unreliable), add 1.68.x arm64 note
- Add anti-pattern #12: never skip Docker for Linux bugs
Redesign the bug-repro skill to dispatch to platform-specific playbooks
instead of hard-coding console app patterns.

New platform files (references/):
- platform-console.md: default dotnet new console (extracted from SKILL.md)
- platform-wasm-blazor.md: Blazor WASM + Playwright browser testing
- platform-docker-linux.md: Linux in Docker (Debian/Alpine)
- platform-windows-desktop.md: WPF/WinForms/WinUI stub
- platform-mobile.md: iOS/Android/MAUI stub

SKILL.md changes:
- Phase 2: platform dispatch table + triage-informed selection
- Phase 2: .NET forward-compatibility rule (net8.0 works on net10.0)
- Phase 3A: delegates to platform file instead of inline code
- Phase 3D: cross-platform verification (conditional, 5min cap)
- Phase 4: new 'scope' field (universal/platform-specific/unknown)
- Anti-patterns #13-18: TFM compat, build≠runtime, cross-platform

Other changes:
- repro-strategies.md renamed to bug-categories.md
- repro-schema.json: added 'platform' to versionResults, 'scope' to root
- repro-examples.md: added WASM/Blazor example (#3422)
- conclusion-guide.md: added scope derivation rules
- triage-issue/SKILL.md: added .NET forward-compat anti-pattern #6
- bug-pipeline.md: updated repro ownership with platform dispatch
…d versions

The SkiaSharp repo has global.json pinning to SDK 8.0, but test projects in
/tmp/ use the highest installed SDK (e.g., 10.0.102). This caused a repro
discrepancy for #3422: different wasm-tools versions between SDK 8 and SDK 10
produce different native WASM binaries.

Changes:
- Phase 2.3: run dotnet --info in /tmp/ test dir, not SkiaSharp repo
- Phase 4: require dotnetSdkVersion (exact SDK) and wasmToolsVersion
- repro-schema.json: add dotnetSdkVersion, wasmToolsVersion fields
- platform-wasm-blazor.md: emphasize running dotnet --info in /tmp/
…rsions

Phase 3C (main source testing) now uses samples/Basic/<platform>/ instead of
tests/SkiaSharp.Tests.Console for all platforms. A console test passing tells
nothing about WASM, mobile, or desktop bugs.

Phase 3B now requires clean builds between SkiaSharp version changes — either
fresh project directories or rm -rf bin/ obj/. WASM native compilation caches
version-specific binaries that persist across incremental rebuilds.

Changes:
- SKILL.md Phase 3C: platform dispatch table to matching samples
- SKILL.md Phase 3B: clean-build rule with fresh project recommendation
- Anti-pattern #19: reusing build artifacts across version changes
- All 5 platform files: added 'Main Source Testing (Phase 3C)' sections
- platform-wasm-blazor.md: clean-build warning in Build section
Multi-model review (Opus, Gemini, GPT-Codex, Haiku) identified:
- SKILL.md was 17% over 500-line budget with significant bloat
- 19 anti-patterns too many — consolidated to 7 critical inline
- 4 examples redundant — trimmed to 2 (API bug + WASM)
- Phase 1/2/4 over-explained things AI already knows
- Phase 3C sample table duplicated platform files
- Schema reproProject.type only allowed console/test/existing

Changes:
- SKILL.md: 583→224 lines (62% reduction)
  - Phase 1: compressed to 10-line checklist
  - Phase 2: cut explanations, kept decisions
  - Phase 3: added overview box, removed duplicate table
  - Phase 4: consolidated, pointer to conclusion-guide
  - Anti-patterns: 19→7 inline, rest in references/anti-patterns.md
  - Removed Output Limits section (in anti-patterns.md now)
- references/anti-patterns.md: NEW — full 19-item list + output limits
- references/repro-examples.md: 434→221 lines (cut examples 2+3)
- references/bug-categories.md: 266→248 lines (trimmed workflow section)
- references/repro-schema.json: added blazorwasm/docker/mobile/wpf/etc to type enum
Multi-model consensus (Sonnet, Opus, Gemini, GPT-Codex, Haiku):

CRITICAL fixes:
- Remove hardcoded /Users/matthew/... paths from all 5 platform files (3 models)
  Now uses: cd "$(git rev-parse --show-toplevel)"
- Link repro-examples.md from SKILL.md Phase 4 (3 models flagged orphaned file)

MEDIUM fixes:
- Add TOC to bug-categories.md (248 lines) and conclusion-guide.md (233 lines)
  Per skill-creator: >100 lines needs TOC (all 5 models)
- Reduce anti-patterns section in SKILL.md from 7 inline to 3 + reference pointer
  (4 models flagged duplication with anti-patterns.md)
- Remove cross-skill references (../../bug-fix/..., ../../triage-issue/...)
  Replace with local platform-docker-linux.md references (2 models)
- Fix Phase 3C contradiction: 'MANDATORY' vs 'only if latest reproduced'
  Clarified: mandatory WHEN reproduced on latest (GPT-Codex)
- Trim schema rules from SKILL.md — schema.json enforces these (2 models)

SKILL.md: 224 → 215 lines. Cleaner, less duplicated, more portable.
Consensus findings (Sonnet, Opus, Gemini, GPT-Codex, Haiku):

MEDIUM fixes:
- Add TOCs to all platform files >100 lines and repro-examples.md
  (Gemini + GPT-Codex flagged missing navigation per skill-creator rule)
- Move anti-patterns from bottom of SKILL.md to before Phase 3
  as 'Key Rules' section (Haiku: placement meant reading too late)
- Add intermittent bug guidance: run 3-5x if inconsistent (Opus)
- Add effort budget: ~30-50 min total, when to stop (Haiku)
- Add platform tie-breaking rules for multiple signals (Haiku + Sonnet)
- Simplify Phase 1: lead with read command, cache setup inline (Haiku)
- Remove cross-skill triage-issue/scripts dependency (Gemini)
- Reduce 'factual only' repetition — conclusion-guide.md covers it (Haiku)

Total: 1999 → 1809 lines across all files. SKILL.md: 220 lines.
… compliance

Round 4 review (0 CRITICAL, 3 bugs found):
- Fix docker quick pattern: dotnet run doesn't support --runtime (GPT-Codex)
- Fix Example 1 contradictory output: expected/got values were identical (Opus+GPT-Codex)
- Fix Example 2 packages array: schema requires {name,version} objects (Opus)
…osed response

- Add output property to repro-schema.json with actionability, workarounds,
  proposedResponse, actions, and missingInfo fields
- Add shared $defs: suggestedAction, confidence, actionType, actionRisk
  (matching triage schema for pipeline consistency)
- Add conditional allOf: output required for reproduced/not-reproduced/wrong-output
- Bump schema version to 2.0
- Add Phase 4 step 4 to SKILL.md with guidance tables and response templates
…ement

Cross-schema consistency pass for all 3 bug pipeline JSON schemas
(triage, repro, fix). Changes reviewed by 5 AI models across 4 rounds.

Schema-wide:
- Add descriptions to every property, container, $ref, and array items
- Unify feedback.corrections structure (repro renamed triageCorrections
  → corrections with source const)
- Add descriptions to all ~40 object array items across all 3 schemas

Triage schema:
- Clarify bugSignals.isRegression (reporter claim) vs regression.isRegression
  (analytical conclusion) with cross-references
- Clarify versionAnalysis.workedIn/brokeIn (reporter) vs regression versions
  (analysis) descriptions
- Make codeInvestigation optional (not all issue types need code investigation)
- Sharpen summary descriptions (top-level=factual restatement, analysis=hypothesis)
- Add minimum:1 to linkedIssue
- Add schemaVersion description

Repro schema:
- Change blazorwasm → blazor-wasm in reproProject.type enum
- Add result to reproductionSteps required fields
- Add wrong-output conclusion constraint (must have wrong-output step)
- Add reproProject conditional requirement for reproduced/wrong-output
- Add versionResults conditional requirement for definitive conclusions
- Self-contained actions description (remove cross-schema reference)
- Add minimum:1 to linkedIssue

Fix schema:
- Convert status from string to object {value, reason}
- Change testResult enum to passed/failed/not-run
- Increase summary minLength to 20
- Add relatedIssues items minimum:1
- Add blockers[] with allOf if/then for cannot-fix/needs-info
- Add verificationMethod enum and method field to verification
- Add rootCause.confidence field
- Add pr.number minimum:1
- Make verification.method required
- Add testsAdded items description field
- Add allOf.if required:["status"] guard
- Conditionally require pr when status=fixed
- Conditionally require relatedIssues when status=duplicate

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Fix all doc-schema mismatches found by 3-model review (Opus, GPT-5.2, Gemini).

issue-fix/SKILL.md:
- status: string → object {value, reason} with conditional requirements
- tests.result: pass/fail → passed/failed
- verification: add required method field with enum values
- rootCause: add optional confidence field
- summary: one-line → one-paragraph with content guidance
- Add blockers[] conditional requirement documentation
- Add pr/relatedIssues conditional requirements for fixed/duplicate

validate-fix.ps1:
- $fix.status → $fix.status.value (4 occurrences)
- 'fail' → 'failed' enum value

issue-repro/SKILL.md:
- feedback.triageCorrections → feedback.corrections with source field

issue-triage/SKILL.md:
- codeInvestigation: 'schema requires' → 'recommended for bugs'
- meta: add missing number and repo fields
- bugSignals: 'REQUIRED' → 'Strongly recommended'
- 'resolution is null' → 'omit analysis.resolution'

bug-pipeline.md:
- feedback.triageCorrections → feedback.corrections (3 locations)
- source: remove '(fix only)' — both repro and fix have it
- status python snippet: ['status'] → ['status']['value']
- environment handoff: add skiaSharpVersion

repro-examples.md:
- reproProject.type: blazorwasm → blazor-wasm (enum value only)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Create fix-examples.md with 2 validated examples (fixed + cannot-fix)
- Fix repro example E6: use fresh directory for version retests
- Add Phase 3C brevity note to repro examples
- Upgrade codeInvestigation from warning to error for type/bug
- Reference fix-examples.md from issue-fix SKILL.md
- All 7 examples across 3 skills validate against schemas

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- C1: Add Phase 9 to sequential execution banner in issue-fix SKILL.md
- I2: Add exitCode to all repro example 1 steps
- I3: Expand triage bug example summary with environment and symptoms
- I4: Add isRegression to triage bug example bugSignals
- I5: Add category to triage question example proposals
- I6: Add platform to repro example 1 versionResults
- I7: Mark keySignals interpretation as optional in triage SKILL.md
- All 7 examples validate against schemas

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Add 'close-as-by-design' to suggestedAction enum in triage + repro schemas
- Rename bugSignals.isRegression → bugSignals.regressionClaimed to distinguish
  reporter claim from analytical conclusion (evidence.regression.isRegression)
- Update labels.md with by-design guidance tip
- Update triage SKILL.md field references
- Update triage example to use regressionClaimed
- All 7 examples validate against schemas

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
When pwsh is unavailable, agents must validate against the actual
schema file using python3+jsonschema, not hand-rolled checks. This
prevents structural errors (like screenshots as strings instead of
objects) from passing validation.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Create standalone validate-*.py scripts that mirror the PowerShell
validators with schema validation + extra semantic checks:
- validate-triage.py: codeInvestigation mandatory for bugs, abs paths
- validate-repro.py: step numbering, output length, exitCode consistency,
  conclusion↔step-result consistency, abs paths
- validate-fix.py: status↔verification consistency, abs paths,
  regressionTestAdded↔testsAdded

Simplify SKILL.md validation sections from inline Python code blocks to:
  pwsh ... || python3 ...

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Add anti-pattern #7: triage must never create files, compile, or execute
- Add scope reminder to Phase 2: READ code, don't WRITE code
- Constrain errorType from freeform string to 9-value enum:
  crash, exception, wrong-output, missing-output, performance,
  build-error, memory-leak, platform-specific, other
- Prevents freeform sentences like 'Output missing closing SVG tag'

Driven by Phase 9 multi-model testing: Gemini created repro code
(triage should not), and 4 models used 4 different errorType strings.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
wrong-output as a conclusion was confusing models — 2/3 chose it instead
of reproduced for #3520 (SVG missing closing tag). The schema description
for reproduced already says 'even if working as designed', which covers
wrong/incomplete output cases.

Changes:
- Remove wrong-output from conclusionValue enum (6→5 values)
- Remove wrong-output from versionResults[].result enum (5→4 values)
- Remove allOf rule that required wrong-output conclusion to have
  wrong-output step result (rule no longer needed)
- Update all allOf rules referencing wrong-output as conclusion
- Keep wrong-output in stepResult enum (still valid for individual steps)
- Update conclusion-guide.md, SKILL.md, all platform guides
- Update both Python and PowerShell validators

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
… references

Triage skill:
- Add quick flow, pre-flight, and post-flight checklists to SKILL.md
- Create references/schema-cheatsheet.md (105 lines) with all fields, enums, common mistakes
- Extract 7 anti-patterns to references/anti-patterns.md with CRITICAL #0 (READ-ONLY)
- Add schema-cheatsheet.md to Phase 3 'First triage' reading list

Repro skill:
- Add quick flow, pre-flight, and post-flight checklists to SKILL.md
- Create references/schema-cheatsheet.md (66 lines) with fields, enums, common mistakes
- Add simulation strategy to Phase 3A (5-step escalation, last resort only)
- Extract proposedResponse templates to references/response-guidelines.md
- Add 'simulation' to reproProject.type enum in repro-schema.json
- Add anti-patterns #20 (never sudo) and #21 (no repo markdown artifacts)

Based on 24-run batch test analysis (12 triage + 12 repro, 3 models) and
5-model peer review of findings.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Critical fixes (C1-C5):
- Repro cheatsheet: add conditional requirements for not-reproduced
  (output + versionResults) and blocked conclusions (blockers[])
- Repro cheatsheet: add step-result constraints (not-reproduced
  requires all steps be success/skip)
- Repro cheatsheet: add proposedResponse.status to output example
- Repro post-flight: rewrite conditional items for all conclusion types

Consistency fixes (C6, M1-M6):
- Triage: add summary row to JSON groups table (was 5, said 6)
- Triage: add anti-patterns.md to pre-flight checklist and quick flow
- Triage: standardize plan guidance to 3-5 lines
- Repro: standardize plan to 3-5 lines everywhere
- Repro: fix quick flow to show 3A/3B/3C version testing (not optional)
- Repro: fix anti-patterns rule count reference
- Triage cheatsheet: list all 13 classifiedArea and 12 classifiedPlatform values
- Triage response-guidelines: allow emoji in data tables (✅/❌)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@mattleibow mattleibow added the copilot Created by GitHub Copilot label Feb 20, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

copilot Created by GitHub Copilot

Projects

Status: No status

Development

Successfully merging this pull request may close these issues.

1 participant