# `Dala.Diag`
[🔗](https://github.com/manhvu/dala/blob/main/lib/dala/diag.ex#L1)

Runtime diagnostics that run inside a Dala app's BEAM. Designed to be
invoked via Erlang RPC from a developer's machine to inspect the
actual state of a deployed app.

Pairs with dala_dev's tooling — `mix dala.verify_strip` calls into
`verify_loaded_modules/0`. Kept in the `dala` library (not `dala_dev`)
so the functions are present in every shipped app, not just at build
time on the developer's machine.

## Security warnings

This module is a **permanent target for remote execution** if distribution
credentials leak. Any node that can connect to your app's Erlang node
can call these functions.

### Mitigation strategies

1. **Use strong, unique cookies** — generate per-app random cookies:
   ```elixir
   cookie = Dala.Dist.cookie_from_env("MY_APP_DIST_COOKIE", "my_app")
   ```

2. **Never commit cookies** to source control.

3. **Rotate cookies periodically** using `Node.set_cookie/1`.

4. **Limit network exposure** — use firewalls/VPC to restrict port 9100
   and 4369 access to trusted machines only.

5. **Strip in production** — consider removing or disabling this module
   in release builds by setting `DALA_RELEASE=1` or using code trimming.

6. **Monitor connections** — log and alert on unexpected `Node.connect`
   attempts in production.

Don't expand the API surface here without thinking — anything added
is permanently shipped to every Dala app and a permanent target for
remote-execution if dist credentials leak.

# `load_failure`

```elixir
@type load_failure() :: %{module: module(), reason: term()}
```

# `load_report`

```elixir
@type load_report() :: %{
  total: non_neg_integer(),
  loaded: non_neg_integer(),
  failed: [load_failure()],
  elapsed_us: non_neg_integer(),
  otp_root: String.t() | nil
}
```

# `loaded_snapshot`

```elixir
@type loaded_snapshot() :: %{
  loaded: [module()],
  loaded_count: non_neg_integer(),
  shipped_count: non_neg_integer(),
  unloaded_in_bundle: [module()],
  otp_root: String.t() | nil,
  captured_at: DateTime.t()
}
```

# `loaded_snapshot`

```elixir
@spec loaded_snapshot() :: loaded_snapshot()
```

Snapshot of what's currently loaded in the running BEAM, plus
what's shipped-but-never-loaded (the empirical strip candidates).

In interactive mode (Dala's default), a module is loaded only when
something calls into it. So the loaded set after a representative
user session is "what the app actually needs." Anything in the
bundle but not in the loaded set is a strong strip candidate.

Better than tracing for our purposes: zero overhead, no rate-limit
worries, no risk of mailbox-overflowing a busy app.

Workflow:

  1. Deploy the app
  2. User exercises every flow they care about
  3. RPC `Dala.Diag.loaded_snapshot/0` from a Mix task
  4. Cross-reference `:unloaded_in_bundle` with the static audit:
     shipped + statically-reachable + never-loaded = high-confidence
     strip candidates.

Caveats: a flow that wasn't exercised won't show up. Run after a
thorough session, not after just opening the app.

# `verify_loaded_modules`

```elixir
@spec verify_loaded_modules() :: load_report()
```

Force-load every `.beam` file under the running app's OTP tree and
report any that fail. Used by `mix dala.verify_strip` to validate
that an aggressive strip didn't remove a module something else
needed.

Walks all entries in `:code.get_path/0`, finds the OTP root from
the first matching `.../otp/lib/...` path, and enumerates `.beam`
files under it.

Returns `t:load_report/0`. Failures usually mean a stripped lib
contained a transitive dependency of a kept module.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
