# RAN013 Signal write or Pump on a thread-pool callback

`warning RAN013`: *`temperature.Value <- 25` runs on a thread-pool thread; a write off the graph's owning thread raises
under `ThreadAffinity.Guarded`.*

**Cause.** Under the default `Guarded` affinity, a signal write or `Graph.Pump` on a thread other than the graph's owner
raises *... ran on thread N, but this graph is owned by thread M*. The rule reports a write or `Pump` in a delegate
handed to `Task.Run`, `Task.Factory.StartNew`, `ThreadPool.QueueUserWorkItem`, a new `Thread`, `Parallel.For`,
`Parallel.ForEach` or a `Timer`. `AsyncSource.Settle` and `Fail` are not reported: an off-thread settle waits in the
graph's inbox. A write to a signal, async source or memo that the delegate constructs over a graph the same delegate
constructs, or creates in that graph's `Run`, a write inside that graph's `Run`, and a `Pump` of that graph run on the
graph's own thread and are not reported. `Parallel.Invoke` and `ContinueWith` count as starters too.

**Fix.** Hand the write to `graph.Dispatch`. A graph built with `ThreadAffinity.Unchecked`, or a host that guarantees
one thread, suppresses the finding with its reason.

### Triggers

```fsharp
module Example

open System.Threading.Tasks
open Ranvier

let report (temperature: Signal<int>) = Task.Run (fun () -> temperature.Value <- 25)
```

### Fixed

```fsharp
module Example

open System.Threading.Tasks
open Ranvier

let report (graph: Graph) (temperature: Signal<int>) =
    Task.Run (fun () -> graph.Dispatch (fun () -> temperature.Value <- 25))
```

**Suppression.** `// fsharpanalyzer: ignore-line RAN013`, with the reason on the line before.
