agentleFS
TheAngryByrdTheAngryByrd/fsharp-skills/skills/optimize-fsharp-typecheck-graph/SKILL.md

optimize-fsharp-typecheck-graph

Skill23 starsChanged 32 days agoMITView on GitHub

Optimize an F# project's graph-based type-checking critical path with measured compiler evidence. Use when an F# build spends substantial time in type checking, a `.graph.md` file shows excessive file dependencies, shared namespaces or auto-open modules serialize checking, signature files may unblock parallel work, or a compile-performance refactor needs source- and binary-compatibility validation.

The file

Show its rules and text

We split this skill into the rules it gives an agent

15 rules. About 0 are common, 13 are distinctive, and 2 are very specific to this project.

  • ≈0

    Common · estimate

    Many files like this have a rule of this kind.

  • ≈13

    Distinctive · estimate

    This author's own choices. Worth a look.

  • 2

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Distinctive:

    Do not treat a simpler graph as proof of a faster build.

    line 9
  2. Distinctive:

    Use repeated runs and compare medians.

    line 19
  3. Distinctive:

    Keep the workload, flags, and cleanup procedure identical for both cases.

    line 20
  4. Distinctive:

    Check the untyped source constructs that make the compiler infer a dependency:

    line 48
  5. Distinctive:

    Treat the graph as a conservative superset.

    line 58
  6. Distinctive:

    Keep the existing public path when the optimization does not require a public move.

    line 85
  7. Distinctive:

    Add no facade or auto-open file unless the existing consumer contract requires that behavior.

    line 87
  8. Very specific:

    Use assembly-level AutoOpen only when implicit source lookup must remain after a justified namespace or module change.

    line 89
  9. Very specific:

    Treat assembly-level AutoOpen as one conditional compatibility tactic.

    line 91
  10. Distinctive:

    Run the repository's tests.

    line 108
  11. Distinctive:

    Use only the documented public imports and computation-expression values.

    line 110
  12. Distinctive:

    Run an already-compiled consumer when binary compatibility is required.

    line 112
  13. Distinctive:

    Check each target framework and relevant conditional-compilation branch.

    line 113
  14. Distinctive:

    Do not infer compatibility from repository tests alone.

    line 115
  15. Distinctive:

    Keep, revise, or revert decision

    line 140

≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

Optimize F# Type-check Graph

Make the compiler's conservative file-dependency graph smaller and shallower. Do not treat a simpler graph as proof of a faster build. Prove measurement, dependency structure, and compatibility separately.

1. Fix the measurement contract

Record the project, SDK, compiler version, configuration, target framework, and build command. Record the machine conditions and build state. Time the compiler phase and each file activity. Also time the complete build. Define the run count, warm-up policy, and minimum useful improvement.

Use repeated runs and compare medians. Keep the raw reports. Keep the workload, flags, and cleanup procedure identical for both cases.

Complete this step when another person can reproduce the baseline. The baseline must identify the dominant compiler activities.

2. Capture the current graph

These diagnostic flags depend on the F# compiler version. Check them with the selected SDK before collecting a baseline. Confirm that the build creates both the graph and timing report. A successful build alone does not prove diagnostic support.

Extend, rather than replace, OtherFlags for the project under test:

<OtherFlags>$(OtherFlags) --test:GraphBasedChecking --test:DumpCheckingGraph --times:report.csv</OtherFlags>

Build with the measurement contract. Preserve the generated .graph.md file and timing CSV. Identify:

  • the longest dependency chain
  • high-fan-out files that gate many successors
  • expensive CheckOneImplFile activities on that chain
  • independent files that the graph unnecessarily serializes

Complete this step when each proposed edit names its target edge or bottleneck.

3. Classify conservative edges

Check the untyped source constructs that make the compiler infer a dependency:

  • Types exposed directly in a shared namespace can link later files that use that namespace.
  • A global namespace can link the file to all later files.
  • A non-prefixed [<AutoOpen>] module can link the file to all later files.
  • A large module or file can become a genuine bottleneck for many dependents.
  • Explicit open, qualified names, inheritance, extensions, and inferred types can represent real dependencies.

Treat the graph as a conservative superset. The compiler can infer a syntactic edge that the program does not require.

4. Choose the least disruptive cut

Match one experiment to the measured cause:

  • For unnecessary shared-namespace edges, isolate internal declarations when the existing API contract permits the change.
  • For an expensive high-fan-out implementation, test an .fsi file. Its smaller signature can unblock dependent files.
  • For a global or auto-open declaration, remove false dependencies without changing its public lookup behavior.
  • For a large real boundary, test a file, module, or project split that matches the architecture.

Measure each cut before you combine cuts. Fewer edges can produce little improvement when other work dominates the build.

5. Preserve the existing public contract

Inspect current source imports, CLR names, extension lookup, reflection usage, and compiled consumers. Preserve the required behavior with the smallest repository-specific mechanism.

Apply these rules:

  • Keep the existing public path when the optimization does not require a public move.
  • Add no facade or auto-open file unless the existing consumer contract requires that behavior.
  • Use assembly-level AutoOpen only when implicit source lookup must remain after a justified namespace or module change.
  • Treat assembly-level AutoOpen as one conditional compatibility tactic. It does not restore CLR full names or binary compatibility.
  • A module with only open statements does not re-export the opened declarations.
  • Namespace moves can change the meaning or legality of private. A change to internal broadens accessibility and requires API review.
  • Namespace moves can break type aliases, extension targets, reflection names, C# callers, and compiled consumers.

Complete this step when each public change is necessary and intentional. Confirm that the experiment adds no unnecessary compatibility mechanism.

6. Prove behavior and compatibility

Validate all applicable layers:

  1. Build the exact project and the full solution.
  2. Run the repository's tests.
  3. Compile a minimal source consumer. Use only the documented public imports and computation-expression values.
  4. Compare public API/assembly metadata before and after.
  5. Run an already-compiled consumer when binary compatibility is required.
  6. Check each target framework and relevant conditional-compilation branch.

Do not infer compatibility from repository tests alone.

7. Re-measure and decide

Repeat the baseline procedure unchanged. Compare:

  • median compiler and complete-build durations
  • per-file type-check durations
  • critical-path depth and fan-out
  • variance
  • source, binary, and behavioral compatibility results

Accept the refactor only when the measured gain justifies its API and maintenance costs. Report a small or noisy gain accurately. A structural experiment still gives useful evidence when you revert it.

Report

Return an evidence table with the baseline, candidate, change, run count, and variance. Link both graphs and the raw timing reports. State these results separately:

  1. Removed false edges
  2. Remaining critical path
  3. Proven compatibility level
  4. Keep, revise, or revert decision

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.