بنقرة واحدة
repro-and-fix
// Use when the user asks to investigate, reproduce, or fix a GitHub issue (e.g. "let's work on issue
// Use when the user asks to investigate, reproduce, or fix a GitHub issue (e.g. "let's work on issue
| name | repro-and-fix |
| description | Use when the user asks to investigate, reproduce, or fix a GitHub issue (e.g. "let's work on issue |
A user pointed you at a GitHub issue and asked you to reproduce + fix it. Run the workflow below. The whole point is that the dev loop is self-contained: you build the repro, launch the sample at that repro automatically, verify the bug yourself (screenshot or logs), fix it, verify the fix, and commit. Don't ask the user for visual confirmations you can get yourself.
Shared with Copilot Coding Agent.
.github/copilot-instructions.mdlinks here as the canonical issue → reproduce → fix → PR workflow. Edit this file when changing the workflow; keep the Copilot doc as a thin pointer to avoid drift.
If the user is asking about theory ("why does the gauge use a doughnut geometry?") or a non-issue task (refactor, doc update, perf), this skill is not the right tool — fall back to general workflow.
Read the issue's labels and repro snippet to choose. The workflow is the same on every XAML platform — only paths and launch commands change.
| Platform | Sample dir | Launch project (Debug build) | In-app screenshot |
|---|---|---|---|
| Avalonia | samples/AvaloniaSample/ | samples/AvaloniaSample/Platforms/AvaloniaSample.Desktop/.../*.Desktop.exe | ✅ supported |
| WPF | samples/WPFSample/ | samples/WPFSample/.../WPFSample.exe | ✅ supported |
| WinUI | samples/WinUISample/WinUISample/ | samples/WinUISample/WinUISample/.../WinUISample.exe | ✅ supported |
| MAUI | samples/MauiSample/ | per-platform; dotnet build -t:Run -f net10.0-windows10.0.19041.0 | ❌ use OS tool |
| Uno | samples/UnoPlatformSample/UnoPlatformSample/ | per-platform | ❌ use OS tool |
If the issue is platform-agnostic (a core engine bug), prefer Avalonia for the fastest dev loop on Windows (no WindowsAppSDK / packaged-build overhead).
These are durable rules from ~/.claude/projects/.../memory/MEMORY.md. Re-read
the relevant memory file if uncertain — these are not optional:
../LiveCharts2-fix-<issue>-<slug> first
(feedback_worktree_per_issue). Don't work in the primary tree.feedback_commit_separation).tests/SnapshotTests/ before claiming done — unit
tests have missed catastrophic regressions
(feedback_run_snapshots_for_render_changes).feedback_update_docs_for_api).Directory.Build.props for <LiveChartsVersion> and use that value in
user-facing text (project_current_version).gh issue view <N> --repo Live-Charts/LiveCharts2 --json title,body,labels,state,comments
Pay attention to comments, not just the body. Issues commonly evolve:
GaugeValue TemplateBinding
bug in the title was already resolved; the live bug was a CornerRadius=0
override in the comments.If you suspect the title bug is already fixed: build the original repro verbatim and verify first, before doing diagnosis. Cite the commenter who said it's fixed in your PR description.
git worktree add ../LiveCharts2-fix-<issue>-<short-slug> -b fix/issue-<N>-<short-slug>
All edits, builds, and runs happen in the worktree. The primary tree stays clean for other work.
The repro convention is a sample view inside the platform sample app:
samples/<Platform>Sample/VisualTest/Issue<N>Repro/View.<axaml|xaml>
samples/<Platform>Sample/VisualTest/Issue<N>Repro/View.<axaml|xaml>.cs
Match the issue's repro setup as closely as you can — same ControlTemplate
shape, same property values, same paints. Don't simplify until you've
confirmed the bug fires; over-minimization can accidentally avoid the trigger.
Existing repros to mirror:
samples/AvaloniaSample/VisualTest/Issue1986Repro/ — TabControl + ScrollViewersamples/AvaloniaSample/VisualTest/Issue1417Repro/ — GeoMap reattachThe View's code-behind should expose helpers that a Factos test can call
(e.g. FindTemplatedGaugeSeries()). This is how the regression test hooks in
without going through the visual tree.
Do not commit changes to samples/ViewModelsSamples/Index.cs for repro
views. Factos navigates to a sample by path via LVC_SAMPLE regardless of
whether the path is listed in the index, and the index is shared across every
platform sample. If you add VisualTest/Issue<N>Repro there and the view only
exists in samples/AvaloniaSample/, every other platform sample (WPF, MAUI,
WinUI, Uno) will throw when it loads the index. Leave the file untouched on
your branch.
If it's genuinely easier for your local dev loop to pick the repro from the
sample selector dropdown rather than via LVC_SAMPLE, edit Index.cs
temporarily — but revert it before committing. git restore samples/ViewModelsSamples/Index.cs before each commit, or just don't stage
the file.
All XAML platform samples read LVC_SAMPLE at startup and load that sample
instead of the default landing screen. Set it before launching:
# bash / WSL
LVC_SAMPLE=VisualTest/Issue<N>Repro \
./samples/AvaloniaSample/Platforms/AvaloniaSample.Desktop/bin/Debug/net10.0/AvaloniaSample.Desktop.exe
# PowerShell
$env:LVC_SAMPLE = "VisualTest/Issue<N>Repro"
.\samples\WPFSample\bin\Debug\net10.0-windows\WPFSample.exe
Build first if needed: dotnet build samples/<Platform>Sample/... -c Debug.
Two paths — pick based on the bug type:
A. In-app screenshot for visual bugs (color, shape, position, rendering
artifacts). Avalonia/WPF/WinUI samples support LVC_SCREENSHOT: when set,
the sample renders its main window via the framework's native
RenderTargetBitmap after a short delay (default 3 s, override with
LVC_SCREENSHOT_DELAY_MS) and exits. No external tooling, no race against
a screenshot tool launching too early. The capture is scaled to the
window's physical pixels (RenderScaling on Avalonia,
VisualTreeHelper.GetDpi on WPF) so HiDPI displays produce a sharp PNG
that matches what's on screen:
LVC_SAMPLE=VisualTest/Issue<N>Repro \
LVC_SCREENSHOT=$(pwd)/.claude/screenshots/<N>-before.png \
./samples/AvaloniaSample/Platforms/AvaloniaSample.Desktop/bin/Debug/net10.0/AvaloniaSample.Desktop.exe
# PowerShell
$env:LVC_SAMPLE = "VisualTest/Issue<N>Repro"
$env:LVC_SCREENSHOT = "$pwd\.claude\screenshots\<N>-before.png"
.\samples\WPFSample\bin\Debug\net10.0-windows\WPFSample.exe
After it exits, Read the PNG. You're multimodal — describe what you see,
compare to a control sample (often Pies/Gauge1 or General/FirstChart for
"what should this look like"). If the bug is subtle (a few pixels), make the
repro larger (Width=380, Height=380) so it's clearly visible.
Fallback for MAUI/Uno or other-OS edge cases: use the OS-appropriate
helper script. They all take <ProcessName> <OutPath> [WaitSeconds] and
poll for the target window before capturing:
| OS | Script | Underlying tool |
|---|---|---|
| Windows | .claude/scripts/capture-window.ps1 | PrintWindow via Win32 (works occluded) |
| macOS | .claude/scripts/capture-window-macos.sh | osascript + screencapture -l <id> |
| Linux | .claude/scripts/capture-window-linux.sh | xdotool+import / swaymsg+grim / gnome-screenshot |
The Linux script tries X11 → sway → GNOME in priority order; install the
matching package if none are present (the script prints the apt/dnf hint).
Use these only when LVC_SCREENSHOT isn't supported on the target platform
(MAUI, Uno) — for Avalonia/WPF/WinUI prefer in-app capture.
B. Console logs for state/dataflow bugs (binding doesn't fire, value doesn't propagate, event order is wrong):
Add temporary Console.WriteLine calls along the suspected path:
Console.WriteLine($"[issue<N>] OnPropertyChanged: {change.Property.Name} old={change.OldValue} new={change.NewValue}");
The platform sample writes to stdout when launched from the terminal. Run via
the bash tool with run_in_background=true (no LVC_SCREENSHOT so the app
stays open), wait a few seconds, kill the app, then grep the captured output
file. Remove the diagnostics before committing.
If neither approach decisively confirms the bug, escalate to the user with one well-framed question, not a chain of polling questions. Example:
"The before-fix capture shows the gauge endcaps as flat, contrary to the issue's screenshot. Did you toggle CornerRadius after the screenshot was taken in the original report?"
Trace from symptom backward through the rendering/data pipeline. Cross-check
against MEMORY.md — many bugs in this repo have related ancestors
(z-index issues, theme overrides, motion-property defaults, source-gen
behavior). If you find a matching memory note, use its diagnosis as a starting
point but verify against current code; memories go stale.
Common gotchas in this codebase:
OnPropertyChanged and _userSets never gets
populated. XamlGaugeSeries.EndInit syncs IsSet DPs as a remediation; if
you see this pattern in another wrapper, the same fix shape applies.OnInitialized and
TemplatedParent may not fire/be set the way you'd expect. Use EndInit
instead._isInternalSet + _userSets is the existing precedence mechanism — don't
reinvent it.Test-first: by the end of step 6 you understand the root cause and the observable that would catch a regression. Write the test now, before applying the fix, and run it — it must fail for the right reason. A test written after the fix risks passing against both versions of the code; a test that fails first proves it's gated on the broken behavior, and you skip the awkward "comment out the fix, rebuild, re-run" verification dance.
Test choice depends on the bug nature:
tests/SharedUITests/. Navigate to the repro,
query a helper method on the View that exposes the state under test,
assert. Gate by #if <PLATFORM>_UI_TESTING if platform-specific (most
XAML-platform-quirk bugs are).tests/SnapshotTests/.tests/CoreTests/AnimationBaselines/ driven by
tests/CoreTests/Helpers/SeriesAnimationCapture.cs. The helper steps
CoreMotionCanvas.DebugElapsedMilliseconds, captures the visual's geometry
at each sample timestamp, and AssertTrajectoryMatches compares the
trajectory to a committed .json. First run writes the new trajectory to
AnimationBaselinesNew/ and fails with a "review and commit" message —
inspect the file, then move it into AnimationBaselines/. Re-baseline the
same way: delete the JSON, re-run, move from New/ back. On mismatch the
helper also drops [EXPECTED]/[RESULT] files into
AnimationBaselinesDiff/ so you can diff them directly. Caller must use
EasingFunctions.Lineal + fixed MinLimit/MaxLimit so interpolation is
deterministic; the existing tests/CoreTests/SeriesTests/*AnimationTests.cs
files are the templates. Prefer this over a plain MSTest whenever the
observable is "how the value changes between two states" — a single
before/after assertion can't catch a regression that only mis-paints the
intermediate frames.tests/CoreTests/.Run the test and confirm the failure message matches the symptom you saw in step 5 — not, for example, a setup error or NullRef from missing test infrastructure. If it fails for an unrelated reason, the test isn't yet catching the bug; fix the test before moving on.
To run a single Factos UI test:
# In tests/UITests/Program.cs, set: var appToRun = "<platform>-desktop"
# (avalonia-desktop / wpf-net10 / winui / maui / uno).
dotnet build tests/UITests/UITests.csproj -c Debug
cd tests/UITests/bin/Debug/net10.0 && dotnet UITests.dll
# Revert the appToRun change before committing — it's a local dev-loop tweak.
Smallest possible change. Don't refactor surrounding code. Don't add comments unless the WHY is non-obvious — but if the bug is a subtle interaction (Avalonia behavior, theme precedence, source-gen quirk), a comment explaining why this fix is necessary is warranted because future readers won't reconstruct it from memory.
Re-run the failing test from step 7 — it must now pass. Then re-run step 5 with the fix in place to capture an "after" screenshot at a sibling path and compare visually:
LVC_SAMPLE=VisualTest/Issue<N>Repro \
LVC_SCREENSHOT=$(pwd)/.claude/screenshots/<N>-after.png \
./samples/<Platform>Sample/.../<Platform>Sample.exe
Read both images. Don't claim the fix works without comparing. The test
passing is necessary but not sufficient for visual bugs — pixel-equivalent
output can still look subtly wrong if the assertion was too narrow.
You developed test-first, but commit fix-first. Two commits, in this order:
fix(<scope>): <one-line summary> (#<N>) — only the fix.test(<scope>): regression for <symptom> (#<N>) — only the test +
repro view. Do not stage samples/ViewModelsSamples/Index.cs; see step 3
for why.Why fix-first commit order despite test-first development: every commit on
the branch should be individually green so git bisect lands on a usable
state. If the test commit landed first it would be a failing-test commit
that bisect would (correctly) flag as broken. Fix-then-test keeps both
commits green while still satisfying the project rule that reverting the
fix must surface the regression — revert commit 1 alone and the test from
commit 2 fails.
Commit message style follows recent history (git log --oneline -10).
Body: imperative, mention the root-cause mechanism, why the test catches it.
End with the standard Co-Authored-By line.
Push and open the PR with gh pr create. The PR body should include:
After the PR is open, write a project_issue_<N>.md memory and add a one-line
entry to MEMORY.md. Capture: what was non-obvious about the bug, what
diagnosis steps led to the fix, and what conventions/files the next person
needs. Don't re-document the code — just the insights.
gh issue view <N> --repo Live-Charts/LiveCharts2LVC_SAMPLE=<path> env var (Avalonia, WPF, WinUI,
MAUI, Uno).LVC_SCREENSHOT=<path> env var (Avalonia, WPF,
WinUI). Sample renders to PNG after LVC_SCREENSHOT_DELAY_MS (default
3000) and exits.<ProcessName> <OutPath> [WaitSeconds] shape:
.claude/scripts/capture-window.ps1 (also accepts
-WindowTitle <substring> instead of -ProcessName).claude/scripts/capture-window-macos.sh.claude/scripts/capture-window-linux.sh (X11 / sway / GNOME)tests/UITests/, set appToRun in Program.cs for
local runs.LiveCharts.<Platform>.slnx solutions.