   - However, if you do it, Untangled merges with the following rules:
       - If the query *asks* for an attribute, and the *response does not include it*, then it is always removed from the app state since the
       server has clearly indicated it is gone.
-      - The the query *does not ask* for an attribute (which means the response cannot possibly contain it), then Untangled
+      - If the query *does not ask* for an attribute (which means the response cannot possibly contain it), then Untangled
       will avoid removing it, even if other attributes come back (e.g. it will be a merge leaving the property that was
       not asked for alone). This does indicate that your UI is possibly in a state inconsistent with the server, which
       is the reason for the \"avoid this case\" advice.


  ### Optimistic (client) changes

  TODO: Just like Om

  ### Server writes

  TODO: Just like Om (`:remote true` or `:remote ast`); however Untangled adds in error handling triggering via tx fallbacks:

  ```
  (om/transact! this '[(app/f) (tx/fallback {:action mutation-symbol :param 1})])
  ```

  assuming the `app/f` mutation returns `{:remote true}` (or `{:remote AST}`)  this sends `app/f` to the server.
  If the server throws an error
  (via ex-info) then the fallback action's mutation symbol (a dispatch key for mutate) is invoked on the client with
  params that include the client fallback params (`:param 1` in the example) and an `:error` key that includes the
  details of the server exception (error type, message, and ex-info's data). Be sure to only include serializable data
  in the server exception!

  You can have any number of fallbacks in a tx, and they will run in order if the transaction fails.



  ## Reads

  Remote reads in Untangled are explicit calls to the load functions in the `untangled.client.data-fetch` namespace, of
  which there are two pairs:

  1. `load-data` and `load-data-action`
  2. `load-field` and `load-field-action`

  ### Load Data vs. Load Field

  Both of these function families are calls to the built-in `untangled/load` mutation, so requests made by either function
  go through the same networking layer and have the same customizations through their named parameters (see the doc strings
  in the [data-fetch namespace](https://github.com/untangled-web/untangled-client/blob/master/src/untangled/client/data_fetch.cljs)).
  The only difference is that `load-data` must be passed a complete query while `load-field` uses the passed-in component
  to create its query.

  So, `load-field` focuses the component's query to the specified field, associates the component's ident with the query,
  and asks the UI to re-render all components with the calling component's ident after the load is complete. Since `load-field`
  requires a component to build the query sent to the server, it cannot be used with the reconciler. If you want to load data
  from your server when the app initially loads, you must use `load-data` with the reconciler passed to the
  `:started-callback` function when creating a new untangled client application.

  #### Use case - Lazy loading

  One common operation is to load data in response to a user interaction. Interestingly, the query that you might
  have used in the initial load use case might have included UI queries for data you didn't want to fetch yet. So, we want
  to note that the initial load use-case supports eliding part of the query. For example, you can load an item without,
  say, comments. Later, when the user wants to see comments you can supply a button that can load the comments on demand.

  This is directly supported by `load-field`, which derives the query to send to the server from the component itself!

  ```
  (load-field this :comments)
  ```

  The only requirements are that the component has an Ident and the query for the component includes a join or property
  named `:comments` in the query.

  For example, say you had:

  ```
  (defui Item
     static om/IQuery
     (query [this] [:id :value {:comments (om/get-query Comment)}])
     static om/Ident
     (ident [this props] [:item/by-id (:id props)])
     Object
     (render [this]
        ...
        (dom/button #js { :onClick #(df/load-field this :comments) } \"Load comments\")
        ...)

  ;; Note that the call to load field above is the same as:
      (df/load-data this (om/full-query this [:comments])
        :ident (om/get-ident this)
        :refresh [(om/get-ident this)])
  ```

  then clicking the button will result in the following query to the server:

  ```
  [{[:item/by-id 32] [{:comments [:other :props]]}]
  ```

  and the code to write for the server is now trivial. The dispatch key is :item/by-id, the 32 is accessible on the AST,
  and the query is a pull fragment that will work relative to an item in your (assuming Datomic) database!

  Furthermore, the underlying code can easily put a marker in place of that data in the app state so you can show the
  'load in progress' marker of your choice.

  Untangled has supplied all of the Om plumbing for you.

  ### Load vs. Load-Action

  Both `load-field` and `load-data` will call `om/transact!` under the hood, targeting untangled's built-in `untangled/load`
  mutation, which is responsible for sending your request to the server. By contrast, `load-field-action` and `load-data-action`,
  **do not** call `om/transact!`, and are used to initialize a load inside of one of your custom client-side mutations.

  Let's look at an example of a standard load. Say you want to load a list of people from the server:
  ```
  (require [untangled.client.data-fetch :as df])

  (defui Person
    static om/IQuery (query [this] [:id :name :ui/fetch-state])
    ... )
  (def ui-person (om/factory Person))

  (defui PeopleList
    static om/IQuery (query [this] [:db/id :list-title {:people (om/get-query Person}]
    static om/Ident (ident [this props] [:people-list/by-id (:db/id props)])
    Object
    (render [this]
      (let [{:keys [people]} (om/props this)]
        ;; people starts out as nil
        (dom/div nil
          (df/lazily-loaded #(map ui-person %) people
            :not-present-render #(dom/button #js {:onClick #(df/load-field this :people)}
                                   \"Load People\"))))))
  ```

  Since we are in the UI and not inside of a mutation's action thunk, we want to use `load-field` to initialize the
  call to `om/transact!`. The use of `lazily-loaded` above will show a button to load people when `people` is `nil`
  (for example, when the app initially loads), and will render each person in the list of people once the button is
  clicked and the data has been loaded. By including `:ui/fetch-state` in the subcomponent's query, `lazily-loaded`
  is able to render different UIs for ready, loading, and failure states as well. See the
  [lazy loading cookbook recipe](https://github.com/untangled-web/untangled-cookbook/tree/master/recipes/lazy-loading-visual-indicators)
  for a running example.

  The action-suffixed load functions are useful when performing an action in the user interface that must *both* modify
  the client-side database *and* load data from the server. They must be used with `untangled.client.data-fetch/remote-load`,
  which converts the remote mutation key for your mutation to the `untangled/load` key:

  ```
  (require [untangled.client.data-fetch :as df]
           [untangled.client.mutations :refer [mutate]]
           [app.ui :as ui] ;; namespace with defuis
           )

  (defmethod mutate 'app/change-view [{:keys [state] as env} _ {:keys [new-view]}]
    {:remote (df/remote-load env)
     :action (fn []
                (let [new-view-query (cond
                                       (= new-view :main) (om/get-query ui/Main)
                                       (= new-view :settings) (om/get-query ui/Settings)]
                (df/load-data-action state new-view-query)
                (swap! state update :app/current-view new-view))})
  ```
  This snippet defines a mutation that (1) modifies the app state to display the view passed in via the mutation parameters,
  and (2) loads the data for that view. A few important points:

  1. If an action thunk calls an action-suffixed load, then it MUST call `remote-load` for the remote keyword.
  2. The `remote-load` function *changes* the mutation's dispatch key to `untangled/load` when sending it to the remote.
  So, a mutation that uses an action-suffixed load cannot have a server-side implementation.
  3. If you find yourself wanting to put a call to `load-data` or `load-field` in a React Lifecycle method, try reworking
  the code to use the action-suffixed load instead. To learn more about the dangers of loads and lifecycle methods, see
  the [reference on loading data]().

  ### How reads work : `untangled/load`

  The helper functions described above simply trigger a built-in Untangled mutation called `untangled/load`, which you are
  allowed (and sometimes encouraged) to use directly. It is the Untangled method of doing follow-on reads after a remote
  mutation:

  ```
  (om/transact! this '[(app/do-some-thing) (untangled/load {:query [:a]})])
  ```

  The normal form of follow-on keywords (for re-rendering the UI) works fine, it will just never trigger remote
  reads.

  The `untangled/load` mutation does a very simple thing: It puts a state marker in a well-known location in your app state
  to indicate that you're wanting to load something (and returns `:remote true`). This causes the network
  plumbing to be triggered. The network plumbing only receives mutations that are marked remote, so it does the following:

  - It looks for the special mutations `untangled/load` and `tx/fallback`. The latter is part of the unhappy path handling.
     - For each load, it places a state marker in the app state at the target destination for the query data
     - All loads that are present are combined together into a single Om query
  - It looks for other mutations
  - It puts the 'other mutations' on the send queue
  - It puts the derived query from the `untangled/load` onto the send queue

  A separate \"thread\" (core async go block) watches the send queue, and sends things one-at-a-time (e.g. each entry
  in the queue is processed in a sequence, ensuring you can reason about things sequentially). The one-at-a-time
  semantics are very important for handling tempid reassignment, rational optimistic updates, and unhappy path handling.

  The send processing block (uses core async to make a thread-like infinite loop):

  - Pulls an item from the queue (or \"blocks\" when empty)
  - Sends it over the network
  - Updates the marker in the app state to `loading` (which causes a re-render, so you can render loading UI)
  - \"waits\" for the response
      - On success: merges the data
      - On error: updates the state marker to an error state (which re-renders allowing the UI to show error UI)
  - Repeats in an infinite loop

  ### UI attributes

