Infra, Ops & WorkflowAttention7373/100

Hypothesis Driven Debugging (.NET)

Investigate compiler failures, test errors, or unexpected behavior through systematic minimal reproduction, 3-hypothesis testing, and verification. Always re-run builds and tests after changes.

ou envoie-le directement à ton agent.

Installer dans ton projet

$ curl -fsSL https://arboristhree.xyz/cli/install-skill.mjs -o /tmp/arboris-install-skill.mjs && node /tmp/arboris-install-skill.mjs hypothesis-driven-debugging__dotnet-dotnet__src-fsharp-github-skills-5643bc67b46a
.NET
dotnet/dotnet
Contenu à copier
---
name: hypothesis-driven-debugging
description: Investigate compiler failures, test errors, or unexpected behavior through systematic minimal reproduction, 3-hypothesis testing, and verification. Always re-run builds and tests after changes.
metadata:
  origin: .NET
---

# Hypothesis-Driven Debugging

A systematic, rigorous approach to debugging failures in the F# compiler codebase.

## When to Use This Skill

Use this skill when:
- Investigating test failures (unit tests, integration tests, end-to-end tests)
- Debugging build errors or compilation failures
- Analyzing unexpected runtime behavior
- Troubleshooting performance regressions
- Examining warning/error message issues

> **Related:** for a build / compile / restore failure, run the `binlog-analysis` skill first — it fetches the build's MSBuild binary log and analyzes it live via the `binlog-mcp` MCP (structured errors + root-cause diagnosis), a fast way to scope the minimal reproduction below.

## Core Principles

1. **Always start with a minimal reproduction**
2. **Form multiple competing hypotheses**
3. **Design verification for each hypothesis**
4. **Document findings rigorously**
5. **Re-run builds and tests after every change**

## Process

### Step 1: Create Minimal Reproduction

Before forming hypotheses, create the smallest possible reproduction:

1. **Extract the failure**:
   ```bash
   # For test failures - run just the failing test
   dotnet test -- --filter-method "*YourTest*"
   
   # For build failures - try to isolate the problematic file
   # Create a minimal .fs file that reproduces the issue
   ```

2. **Reduce to essentials**:
   - Remove unrelated code
   - Simplify to the core issue
   - Verify the minimal case still fails

3. **Document the repro**:
   ```markdown
   ## Minimal Reproduction
   
   File: test-case.fs
   Command: dotnet test -- --filter-method "*TestName*"
   Expected: <expected behavior>
   Actual: <actual behavior>
   ```

### Step 2: Form 3 Hypotheses

Always form **at least 3 competing hypotheses** about the root cause:

```markdown
## Hypothesis 1: [Brief description]
**Theory**: The failure occurs because...
**How to verify**: Run/change X and observe Y
**Verification result**: [To be filled]
**Implications**: If true, this means...

## Hypothesis 2: [Brief description]
**Theory**: The failure occurs because...
**How to verify**: Add instrumentation/logging at point Z
**Verification result**: [To be filled]
**Implications**: If true, this means...

## Hypothesis 3: [Brief description]
**Theory**: The failure occurs because...
**How to verify**: Check assumption A by running test B
**Verification result**: [To be filled]
**Implications**: If true, this means...
```

### Step 3: Verification Methods

For each hypothesis, use one or more verification methods:

#### Code Instrumentation
```fsharp
// Add temporary debugging output
printfn "DEBUG: Value at checkpoint: %A" someValue
printfn "DEBUG: Entering function X with args: %A %A" arg1 arg2
```

#### Minimal Test Cases
```fsharp
// Create focused test to verify specific behavior
[<Test>]
let ``Hypothesis 1 verification test`` () =
    let result = functionUnderTest input
    result |> should equal expectedValue
```

#### Build with Different Flags
```bash
# Try different configurations
./build.sh -c Debug
./build.sh -c Release

# Compare outputs
diff debug-output.log release-output.log
```

#### Targeted Logging
```bash
# Enable verbose logging for specific component
export FSHARP_COMPILER_VERBOSE=1
dotnet build
```

### Step 4: Document Findings

Maintain a `HYPOTHESIS.md` file in the working directory:

```markdown
# Hypothesis Investigation

## Issue Summary
Brief description of the failure/bug being investigated.

## Minimal Reproduction
[Code/commands to reproduce]

## Hypotheses

### Hypothesis 1: Token position tracking issue
**Theory**: The warning check compares line numbers but lastNonCommentTokenLine is not being updated correctly.
**How to verify**: Add printfn debugging in LexFilter.fs to log every token and its line number.
**Verification result**: ✅ CONFIRMED - Logging showed LBRACE tokens were updating the tracking when they shouldn't.
**Implications**: Need to exclude LBRACE and potentially other structural tokens from tracking.

### Hypothesis 2: Lexer pattern matching order
**Theory**: The /// pattern might be matched after other patterns, losing context.
**How to verify**: Check lex.fsl pattern order and add logging in the /// rule.
**Verification result**: ❌ DENIED - Pattern order is correct; /// is matched specifically.
**Implications**: Issue is not in the lexer pattern matching.

### Hypothesis 3: Test expectations wrong
**Theory**: The test expectations might not match actual compiler behavior.
**How to verify**: Manually compile test code and check actual warning positions.
**Verification result**: ⚠️ PARTIAL - Some tests had wrong expectations, but underlying issue still exists.
**Implications**: Fixed test expectations, but still need to address token tracking.

## Resolution
[Final solution and verification]

## Lessons Learned
- What worked well
- What to do differently next time
- Patterns to remember
```

### Step 5: Critical - Always Re-run Tests

**ABSOLUTELY REQUIRED**: After implementing any fix:

1. **Build from scratch**:
   ```bash
   ./build.sh -c Release
   # Record: Time, exit code, number of errors
   ```

2. **Run affected tests**:
   ```bash
   # For targeted testing
   dotnet test -- --filter-class "*AffectedTestSuite*"
   
   # Record: Passed, Failed, Skipped, Time
   ```

3. **Verify the fix**:
   - Run the minimal reproduction - confirm it passes
   - Run related tests - confirm no regressions
   - Build the full project - confirm no new errors

4. **Document results**:
   ```markdown
   ## Verification Results
   
   Build:
   - Command: ./build.sh -c Release
   - Time: 4m 23s
   - Errors: 0
   
   Tests:
   - Command: dotnet test -- --filter-class "*XmlDocTests*"
   - Total: 61
   - Passed: 56
   - Failed: 0
   - Skipped: 5
   - Time: 2.1s
   
   Minimal Repro:
   - Status: ✅ PASSING
   ```

## Example Workflow

```bash
# 1. Observe failure
dotnet test -- --filter-class "*XmlDocTests*"
# Result: 15 tests failing

# 2. Create minimal repro
cat > test-case.fs <<EOF
type R = { /// field doc
    Field: int
}
EOF
dotnet fsc test-case.fs
# Observe: Warning FS3879 incorrectly triggered

# 3. Form hypotheses (in HYPOTHESIS.md)
# - H1: LBRACE token incorrectly tracked
# - H2: Lexer pattern issue
# - H3: Test expectations wrong

# 4. Verify H1
# Add: printfn "DEBUG: Token %A at line %d" token lineNum
./build.sh -c Release && dotnet test ...
# Result: Confirms LBRACE is being tracked

# 5. Implement fix
# Exclude LBRACE from tracking in LexFilter.fs

# 6. CRITICAL: Re-run everything
./build.sh -c Release
# 4m 44.9s, 0 errors

dotnet test -- --filter-class "*XmlDocTests*"
# 61 total, 56 passed, 0 failed, 5 skipped, 2s

# 7. Verify minimal repro
dotnet fsc test-case.fs
# No warning - ✅ FIXED

# 8. Update HYPOTHESIS.md with results
# 9. Commit with evidence
```

## Anti-Patterns to Avoid

❌ **Don't**:
- Skip the minimal reproduction
- Form only one hypothesis
- Make changes without verification
- Forget to re-run tests after fixes
- Claim "fixed" without build evidence

✅ **Do**:
- Start with smallest possible repro
- Consider multiple explanations
- Verify each hypothesis systematically
- Always re-run build and tests
- Document commands, timings, and results

## Integration with Development Workflow

After using this skill:

1. Clean up temporary debugging code
2. Remove or archive `HYPOTHESIS.md`
3. Update documentation with lessons learned
4. Add regression tests if appropriate
5. Consider whether findings reveal deeper issues

## References

- [Software Debugging Techniques](https://en.wikipedia.org/wiki/Debugging#Techniques)
- [Scientific Method Applied to Software](https://en.wikipedia.org/wiki/Scientific_method)
- F# Compiler build guide: `docs/DEVGUIDE.md`
- F# Compiler testing guide: `docs/testing.md`
Colle ce Markdown dans ton agent ou utilise les boutons ci-dessus pour l’écrire dans ton projet.

Ce que fait Hypothesis Driven Debugging (.NET)

Investigating test failures (unit tests, integration tests, end-to-end tests)
Debugging build errors or compilation failures
Analyzing unexpected runtime behavior
Troubleshooting performance regressions

Comment utiliser Hypothesis Driven Debugging (.NET)

1
Copie le prompt
Un clic copie le prompt packagé (ou l'envoie à ton agent).
2
L'agent installe le skill
Il ajoute le SKILL.md et ses ressources à ton projet.
3
Activation automatique
Le skill s'active dès que le contexte correspond.

Déclencheurs pour Hypothesis Driven Debugging (.NET)

Dis simplement à ton agent quelque chose comme :

Applique le skill hypothesis-driven-debugging__dotnet-dotnet__src-fsharp-github-skills-5643bc67b46a à cette tâche
Utilise hypothesis-driven-debugging__dotnet-dotnet__src-fsharp-github-skills-5643bc67b46a pour améliorer cette implémentation
Passe en revue ce sujet avec hypothesis-driven-debugging__dotnet-dotnet__src-fsharp-github-skills-5643bc67b46a

Skills liés à Hypothesis Driven Debugging (.NET)

Add CLI Command (.NET)
Add or change a dotnet CLI command, subcommand, or option across the relevant CLI projects. USE FOR: adding or changing a dotnet CLI command/subcommand, adding a new Option<T> or Argument<T>, registering a subcommand in the command tree, changing an option's help description or a command's runtime message, wiring a command parser, or updating --help output.
Add Dotnet Aot Command (.NET)
Add, enable, or review a dotnet CLI command or feature in the Native AOT CLI (src/Cli/dotnet-aot) and prove its compatibility. USE FOR: migrating a command or option to AOT, reviewing an AOT migration PR, defining conservative eligibility and managed fallback, changing AotSourceFiles.props or AotDependencies.props, validating AOT/managed parity, NativeAOT-publishing tests, checking binary-size impact, or using the dn harness and separated SDK layout. DO NOT USE FOR: resolving IL trim/AOT analyzer warnings alone (use dotnet-aot-compat), running dotnet.Tests incrementally (use incremental-test), or pure managed CLI work.
Add Net Analyzer (.NET)
Add, port, or change a .NET code analysis rule (CA####) under src/Microsoft.CodeAnalysis.NetAnalyzers. USE FOR: implementing a new CA analyzer and its code fixer, porting a rule or PR from the retired dotnet/roslyn-analyzers repo, allocating a diagnostic ID from DiagnosticCategoryAndIdRanges.txt, choosing RuleLevel/severity/category, wiring resx + xlf strings, recording the rule in AnalyzerReleases.Unshipped.md, regenerating the analyzer documentation/sarif files, and writing MSTest analyzer/code-fix tests with the VerifyCS/VerifyVB harness. DO NOT USE FOR: NETSDK#### MSBuild diagnostics (src/Tasks), CS####/BC#### compiler diagnostics or IDE#### analyzers (dotnet/roslyn), or CONTAINER#### diagnostics (src/Containers).