| name | try-fix |
| description | Proposes ONE independent fix approach, applies it, runs tests, records result with failure analysis in state file, then reverts. Reads prior attempts to learn from failures. Returns exhausted=true when no more ideas. Max 5 attempts per session. |
Try Fix Skill
Proposes and tests ONE independent fix approach per invocation. The agent invokes this skill repeatedly to explore multiple alternatives.
Core Principles
- Single-shot: Each invocation = ONE fix idea, tested, recorded, reverted
- Independent: Generate fix ideas WITHOUT looking at or being influenced by the PR's fix
- Empirical: Actually implement and test - don't just theorize
- Learning: When a fix fails, analyze WHY and record the flawed reasoning
When to Use
- ✅ After Gate passes - you have a verified reproduction test
- ✅ When exploring independent fix alternatives (even if PR already has a fix)
- ✅ When the agent needs to iterate through multiple fix attempts
When NOT to Use
- ❌ Before Gate passes (you need a test that catches the bug first)
- ❌ For writing tests (use
write-testsskill) - ❌ For just running tests (use
BuildAndRunHostApp.ps1directly) - ❌ To test the PR's existing fix (Gate already validated that)
Inputs
Before invoking this skill, ensure you have:
| Input | Source | Example |
|---|---|---|
| State file path | Agent workflow | .github/agent-pr-session/pr-12345.md |
| Test filter | From test files | Issue12345 |
| Platform | From issue labels | android or ios |
| PR fix files | From Pre-Flight | Files changed by PR (to revert) |
Workflow
Step 1: Read State File and Learn from Prior Attempts
Read the state file to find prior attempts:
cat .github/agent-pr-session/pr-XXXXX.md
Look for the Fix Candidates table. For each prior attempt:
- What approach was tried?
- Did it pass or fail?
- If it failed, WHY did it fail? (This is critical for learning)
Use failure analysis to avoid repeating mistakes:
- If attempt #1 failed because "too late in lifecycle" → don't try other late-lifecycle fixes
- If attempt #2 failed because "trigger wasn't enough, calculation logic needed fixing" → focus on calculation logic
Step 2: Revert PR's Fix (Get Broken Baseline)
🚨 CRITICAL: You must work from a broken state where the bug exists.
# Identify the PR's fix files from the state file "Files Changed" section
# Revert ALL fix files (not test files)
git checkout HEAD~1 -- src/path/to/fix1.cs src/path/to/fix2.cs
# Verify the bug is present (test should FAIL)
# This is your baseline
Why? You're testing whether YOUR fix works, independent of the PR's fix.
Step 3: Check if Exhausted
Before proposing a new fix, evaluate:
- Count prior try-fix attempts - If 5+ attempts already recorded, return
exhausted=true - Review what's been tried and WHY it failed - Can you think of a meaningfully different approach?
- If no new ideas - Return
exhausted=true
Signs you're exhausted:
- All obvious approaches have been tried
- Remaining ideas are variations of failed attempts (same root flaw)
- You keep coming back to approaches similar to what failed
- The problem requires architectural changes beyond scope
If exhausted, stop here and return to the agent with exhausted=true.
Step 4: Analyze the Code (Independent of PR's Fix)
🚨 DO NOT look at the PR's fix implementation. Generate your own ideas.
Research the bug to propose a NEW approach:
# Find the affected code
grep -r "SymptomOrClassName" src/Controls/src/ --include="*.cs" -l
# Look at the implementation
cat path/to/affected/File.cs
# Check git history for context (but NOT the PR's commits)
git log --oneline -10 -- path/to/affected/File.cs
Key questions:
- What is the root cause of this bug?
- Where in the code should a fix go?
- What's the minimal change needed?
- How is this different from prior failed attempts?
Step 5: Propose ONE Fix
Design an approach that is:
- Independent - NOT influenced by the PR's solution
- Different from prior attempts in the state file
- Informed by WHY prior attempts failed
- Minimal - smallest change that fixes the issue
Document your approach before implementing:
- Which file(s) to change
- What the change is
- Why you think this will work
- How it differs from prior failed attempts
Step 6: Apply the Fix
Edit the necessary files to implement your fix.
Track which files you modify - you'll need to revert them later.
# Note the files you're about to change
git status --short
Step 7: Run Tests
Run the reproduction test to see if your fix works:
pwsh .github/scripts/BuildAndRunHostApp.ps1 -Platform $PLATFORM -TestFilter "$TEST_FILTER"
Capture the result:
- ✅ PASS - Your fix works (test now passes)
- ❌ FAIL - Your fix doesn't work (test still fails, or other tests broke)
Step 8: If Failed - Analyze WHY
🚨 CRITICAL: This step is required for failed attempts.
When your fix fails, analyze:
- What was your hypothesis? Why did you think this would work?
- What actually happened? What did the test output show?
- Why was your reasoning flawed? What did you misunderstand about the bug?
- What would be needed instead? What insight does this failure provide?
This analysis helps future try-fix invocations avoid the same mistake.
Step 9: Update State File
Add a new row to the Fix Candidates table in the state file:
For PASSING fixes:
| # | Source | Approach | Test Result | Files Changed | Model | Notes |
|---|--------|----------|-------------|---------------|-------|-------|
| N | try-fix | [Your approach] | ✅ PASS | `file.cs` (+X) | [Model Name] | Works! [any observations] |
For FAILING fixes (include failure analysis):
| # | Source | Approach | Test Result | Files Changed | Model | Notes |
|---|--------|----------|-------------|---------------|-------|-------|
| N | try-fix | [Your approach] | ❌ FAIL | `file.cs` (+X) | [Model Name] | **Why failed:** [Analysis of flawed reasoning and what you learned] |
Step 10: Revert Everything
Always revert to restore the PR's original state:
# Revert ALL changes (your fix AND the PR revert from Step 2)
git checkout -- .
Do NOT revert the state file - the new candidate row should persist.
Step 11: Return to Agent
Report back to the agent with:
| Field | Value |
|---|---|
approach |
Brief description of what was tried |
test_result |
PASS or FAIL |
exhausted |
true if no more ideas, false otherwise |
Fix Candidates Table Format
The state file should have this section:
## Fix Candidates
| # | Source | Approach | Test Result | Files Changed | Model | Notes |
|---|--------|----------|-------------|---------------|-------|-------|
| 1 | try-fix | Fix in TabbedPageManager | ❌ FAIL | `TabbedPageManager.cs` (+5) | Claude 3.5 Sonnet | **Why failed:** Too late in lifecycle - by the time OnPageSelected fires, layout already measured with stale values |
| 2 | try-fix | RequestApplyInsets only | ❌ FAIL | `ToolbarExtensions.cs` (+2) | Claude 3.5 Sonnet | **Why failed:** Trigger alone insufficient - calculation logic still used cached values |
| 3 | try-fix | Reset cache + RequestApplyInsets | ✅ PASS | `ToolbarExtensions.cs`, `InsetListener.cs` (+8) | Claude 3.5 Sonnet | Works! Similar to PR's approach |
| PR | PR #XXXXX | [PR's approach] | ✅ PASS (Gate) | [files] | Author | Original PR - validated by Gate |
**Exhausted:** Yes
**Selected Fix:** #3 or PR - both work, compare for simplicity
Note: The PR's fix is recorded as reference (validated by Gate) but is NOT tested by try-fix.
Guidelines for Proposing Fixes
Independence is Critical
🚨 DO NOT look at the PR's fix code when generating ideas.
The goal is to see if you can independently arrive at the same solution (validating the PR's approach) or find a better alternative.
If your independent fix matches the PR's approach, that's strong validation. If you find a simpler/better approach, that's valuable feedback.
Good Fix Approaches
✅ Null/state checks - Guard against unexpected null or state ✅ Lifecycle timing - Move code to correct lifecycle event ✅ Platform-specific handling - Add platform check if needed ✅ Event ordering - Fix race conditions or ordering issues ✅ Cache invalidation - Reset stale cached values
Approaches to Avoid
❌ Looking at the PR's fix first - Generate ideas independently ❌ Duplicating prior failed attempts - Check the table and learn from failures ❌ Variations of failed approaches with same root flaw - If timing was wrong, a different timing approach is needed ❌ Massive refactors - Keep changes minimal ❌ Suppressing symptoms - Fix root cause, not symptoms
Learning from Failures
When a fix fails, the failure analysis is crucial:
Bad note: "Didn't work" Good note: "Why failed: RequestApplyInsets triggers recalculation, but MeasuredHeight was still cached from previous layout pass. Need to also invalidate the cached measurement."
This helps the next try-fix invocation avoid the same mistake.
Example Session
State file before (after Gate passed):
## Fix Candidates
| # | Source | Approach | Test Result | Files Changed | Model | Notes |
|---|--------|----------|-------------|---------------|-------|-------|
| PR | PR #33359 | RequestApplyInsets + reset appBarHasContent | ✅ PASS (Gate) | 2 files | Author | Original PR |
**Exhausted:** No
**Selected Fix:** [PENDING]
try-fix invocation #1:
- Reads state → sees PR's fix passed Gate, no try-fix attempts yet
- Reverts PR's fix files → now bug exists
- Analyzes code independently → proposes: "Fix in TabbedPageManager.OnPageSelected"
- Applies fix → edits
TabbedPageManager.cs - Runs tests → ❌ FAIL
- Analyzes failure → "Too late in lifecycle, layout already measured"
- Updates state file → adds try-fix Candidate #1 with failure analysis
- Reverts everything (including restoring PR's fix)
- Returns
{approach: "Fix in TabbedPageManager", test_result: FAIL, exhausted: false}
State file after invocation #1:
## Fix Candidates
| # | Source | Approach | Test Result | Files Changed | Model | Notes |
|---|--------|----------|-------------|---------------|-------|-------|
| 1 | try-fix | Fix in TabbedPageManager.OnPageSelected | ❌ FAIL | `TabbedPageManager.cs` (+5) | Claude 3.5 Sonnet | **Why failed:** Too late in lifecycle - OnPageSelected fires after layout measured |
| PR | PR #33359 | RequestApplyInsets + reset appBarHasContent | ✅ PASS (Gate) | 2 files | Author | Original PR |
**Exhausted:** No
**Selected Fix:** [PENDING]
try-fix invocation #2:
- Reads state → sees attempt #1 failed because "too late in lifecycle"
- Reverts PR's fix → bug exists
- Learns from #1 → needs earlier timing, proposes: "Trigger in UpdateIsVisible"
- Applies fix → edits
ToolbarExtensions.cs - Runs tests → ✅ PASS
- Updates state file → adds Candidate #2
- Reverts everything
- Returns
{approach: "Trigger in UpdateIsVisible", test_result: PASS, exhausted: false}
State file after invocation #2:
## Fix Candidates
| # | Source | Approach | Test Result | Files Changed | Model | Notes |
|---|--------|----------|-------------|---------------|-------|-------|
| 1 | try-fix | Fix in TabbedPageManager.OnPageSelected | ❌ FAIL | `TabbedPageManager.cs` (+5) | Claude 3.5 Sonnet | **Why failed:** Too late in lifecycle |
| 2 | try-fix | RequestApplyInsets in UpdateIsVisible | ✅ PASS | `ToolbarExtensions.cs` (+2) | Claude 3.5 Sonnet | Works! Simpler than PR (1 file vs 2) |
| PR | PR #33359 | RequestApplyInsets + reset appBarHasContent | ✅ PASS (Gate) | 2 files | Author | Original PR |
**Exhausted:** No
**Selected Fix:** [PENDING]
Agent decides: Found a passing alternative (#2). Can continue to find more, or stop and compare #2 vs PR.
Constraints
- Max 5 try-fix attempts per session (PR's fix is NOT counted - it was validated by Gate)
- Always revert after each attempt (restore PR's original state)
- Always update state file before reverting
- Never skip testing - every fix must be validated empirically
- Never look at PR's fix when generating ideas - stay independent
- Always analyze failures - record WHY fixes didn't work