# Live check (UI testing against a live install)

`tools/live-check` signs in to a running Baler and opens every UI page in a real browser, at desktop
(1440 px) and phone (390 px) width. It also opens the Cx project report and run report. Each finding
goes into the GitHub issue log, with a fingerprint so it isn't filed twice.

It is **read-only**: every request that isn't a GET is refused, from the browser and from Node.
The only exceptions are the login and the Connectors page's edge-node reads, which are POSTs by
design: the actions in `READ_ACTIONS` in `src/baler/edges.py` (`list_devices`, `list_connections`,
`modbus_list_connections`, `list_announced`), read from the checkout so the guard can't drift from
the API. So it is safe to point at production, even with an operator account.

After every deploy it also runs as the Deploy workflow's `verify` job, with performance budgets,
data-flow, edge-node, phone-layout and deploy-window checks on top of the browser pass: see
[Post-deploy verification](/post-deploy-verify) for those, the CLI options (`--phase`, `--only`) and
the runbook.

## What it finds

| Finding | Label |
|---|---|
| Uncaught JavaScript errors and `console.error` output | `bug` |
| Same-origin requests that return 4xx/5xx or fail (URL ids are folded to `:id`) | `bug` |
| A page calling an endpoint the signed-in role gets 403 from | `bug` |
| A page showing the sign-in screen although the token is valid | `bug` |
| Sideways scrolling at 390 px | `bug` |
| Any API request slower than `LIVE_CHECK_SLOW_MS` (default 2000) | `optimization` |
| axe-core WCAG 2.1 A/AA violations of impact *serious* or *critical* (desktop pass) | `accessibility` |

Every issue it files also gets the `live-check` label, and a `[live-check]` title prefix.

## Run it

You need Node 20+, Google Chrome (or set `CHROME_PATH`), and the `gh` CLI signed in with
write access to the repo.

```bash
cd tools/live-check
npm install
npm test                 # unit tests for fingerprints and the issue plan
npm run dry-run          # check and print, change no issues
npm run check            # check and sync the issue log
```

Credentials come from the environment or from `~/.config/baler-tests/baler.env` (mode 600), which
holds `BALER_TEST_URL`, `BALER_TEST_EMAIL` and `BALER_TEST_PASSWORD`. Use a viewer or operator
account. A viewer sees fewer controls, so it checks less.

| Variable | Default | Meaning |
|---|---|---|
| `BALER_TEST_ENV` | `~/.config/baler-tests/baler.env` | env file to read |
| `LIVE_CHECK_SLOW_MS` | `2000` | slow-request threshold |
| `LIVE_CHECK_SETTLE_MS` | `5000` | wait after page load before checking |
| `LIVE_CHECK_PROJECT` | `Home Edge Pilot` | Cx project whose reports are opened |
| `LIVE_CHECK_REPO` | the checkout's repo | `owner/name` to file issues in |
| `CHROME_PATH` | system Chrome | browser binary (e.g. `/opt/pw-browsers/chromium`) |

Screenshots, `findings.json`, the summaries and the `live-verify-<sha>.json` artifact land in
`tools/live-check/out/`.

## How it keeps the issue log tidy

- A new finding creates an issue. The fingerprint is `<!-- live-check fp:… -->` in the body.
- A finding that is already open is updated in place: *Last seen*, pages and viewports change, but *First
  seen* is kept. Editing a body doesn't notify anyone.
- A closed issue whose finding comes back is reopened with a comment.
- Performance-budget breaches are the exception: they open or reopen an issue only on the second
  consecutive complete run of their phase (see [Post-deploy verification](/post-deploy-verify)).
- An open `live-check` issue that a **complete** run of its check (signed in, every page and report
  loaded) no longer sees is closed with a comment. An incomplete run (the site was down, a page failed
  to load, axe failed) closes nothing.
- An issue closed as "not planned" is never reopened, and one labelled `live-check:ignore` is never
  touched.

So the loop is: fix and deploy, run `npm run check`, and the issue closes itself if the fix worked.

Issues you file by hand are never touched. The tool only reads issues that carry its fingerprint.

## What it doesn't do

It doesn't click through flows that write: adding connectors, phase moves, waivers. It doesn't judge
layout beyond sideways scroll (a squeezed column, for example). It doesn't check report content
against the data. Review the screenshots in `out/` for those, and file what you see by hand.
