# Seeing what a page cost

> Every call your app makes to the local platform reports how many database round trips answered it, beside how long it took. A duration alone cannot tell one query from nineteen, and that difference is usually the thing to fix.

<!-- id: local-seeing-what-a-page-cost · area: local · stability: stable · html: https://osysharp.com/reference/local/seeing-what-a-page-cost/ -->

## Summary        {#summary}

The dev panel's **Net** tab shows, for every call your app made: how long it took **and what the server did to answer
it** — the database round trips, the statements they carried, and how much of the time was spent waiting on SQL.

A millisecond number on its own cannot tell you whether 340ms was one query or nineteen, and that is usually the
question worth asking. The count makes it visible without having to suspect it first.

## Signature      {#signature}

```text
Ctrl+Shift+D  →  Net           the panel, on any page served by the local platform
window.__osy.net                the same rows as data, for a script or an agent
```

Each row reads:

```text
GET   200   /api/data/Contact       41ms   19rt/27q   23ms sql   9f3c…
                                    └ wall  └ round     └ of which  └ correlation id
                                      clock   trips       waiting
                                              /statements on SQL
```

## Description    {#description}

**`19rt` is the number: NETWORK ROUND TRIPS.** Not statements, and the two are not the same count — the platform
pipelines, so a batch of forty statements is **one** trip. The row shows the statements alongside whenever they
differ (`1rt/40q`), because that gap *is* the batching and `1rt` on its own reads better than it deserves.

⚠ **Do not call either of them "queries".** Round trips are what latency is made of and what this page is about;
the statement count is a different question, and a read-in-a-loop that got batched hides in the first and shows in
the second.

**`23ms sql` tells you which of two problems you have.** Close to the row's total: the time is round-trip *latency*,
and the fix is fewer, bigger queries. Far below it: the time went somewhere else — CPU, or waiting on something that
is not the database — and the query count is not your bug however large it looks.

**A count is only meaningful against what the call was for.** Nineteen queries to paint a report page is ordinary;
nineteen behind a button press is usually a read inside a loop. The panel tints a high count as a nudge to look, not
as a verdict.

**The query shapes are deliberately not here.** They are in the server log, under the correlation id on the same row:

```bash
make logs-corr ID=9f3c1a2b-…
```

That line carries the top shapes by frequency *and* by rows — the second ranking matters because one unfiltered read
of a big table is a single round trip and never appears in a by-frequency list, while being most of the work. Keeping
one copy of the shapes is why the panel shows the number and the log shows the detail.

**Local dev host only.** The `X-Osy-Db` header this reads is emitted only by a platform started with `osy launch` /
`osyrin dev`, on the same gate as the panel itself. A deployed host sends nothing: in production a query-shape
description is free information to anyone with a browser, for the benefit of nobody. On a host that does not send it
the field reads as **not measured**, never as zero.

**What it counts is the request, all of it** — everything the call awaited, including work in functions it invoked.
The one thing outside the number is a query issued *while the response body is being written*; nothing in the
platform does that today (rows are materialised before they are serialised).

## Examples       {#examples}

Find the page that got slow, from a script:

```js
// syntax — the dev handle is a browser global, not Osy# source.
window.__osy.net
  .filter((c) => c.db && c.db.net >= 10)
  .map((c) => `${c.method} ${c.url} — ${c.ms}ms, ${c.db.net} queries, ${c.db.sqlMs}ms sql`);
```

Then read the shapes behind the worst one:

```bash
make logs-corr ID=<the correlation id on that row>
```

## See also       {#see-also}

- [Seeing what happened when your code ran](https://osysharp.com/reference/local/seeing-what-happened/) — `osy inspect`, for what the code did rather than what it cost
- [Recording a run](https://osysharp.com/reference/local/recording-a-run/) — `osy trace`, when you need the steps and not the totals
- [Running a local platform](https://osysharp.com/reference/local/running-a-local-platform/) — the host that emits this
