Add ONBOARDING.md — dev handoff guide (setup, verify loop, browser harness, gotchas, current state)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
2026-07-16 14:49:09 -05:00
parent cf1129ea8e
commit b70b4d6991

160
ONBOARDING.md Normal file
View File

@@ -0,0 +1,160 @@
# ONBOARDING — PrimeBAT Alarm Analysis Dashboard
Getting-started guide for a developer picking up this Ignition 8.3 Build-a-Thon
project mid-build. Pairs with two other docs:
- **[README.md](README.md)** — the docker stack, gateway-as-files layout, provisioning.
- **[CONTRACT.md](CONTRACT.md)** — the *frozen build contract*. This is the source of
truth for every prop name, binding pattern, session prop, script signature, style
class, and hard rule. **Read it before editing any view.**
---
## 1. What this is
A single Perspective dashboard (`PrimeControls/Dashboard`) that answers "is my alarm
system healthy, and what do I fix first?" from ISA-18.2 metrics. All data comes from
`system.alarm.queryJournal` / `queryStatus` (no SQL, no tag bindings) via one script
package, `PrimeControls.{calc, fmt, alarms}`. One journal fetch per refresh produces a
"bundle" that every tab/popup binds against.
Gateway state is version-controlled **files** under `ignition/gateway/` (see README) —
you edit JSON/Python on disk and tell the gateway to reload; there is no separate
"deploy."
## 2. Get running (5 min)
```bash
docker compose up -d # gateway :8088 (admin/password) + MariaDB
curl -s http://localhost:8088/StatusPing # {"state":"RUNNING"} when ready (~1-2 min)
```
The committed gateway files already contain the provisioned DB connection, alarm
journal, API token config, and simulator tags — a plain `up -d` restores a working
gateway. Only run `python3 tools/provision.py mint-token && … provision` if you rebuild
from a *factory-fresh* gateway (README "Reset" section). The alarm simulator timer script
is a Designer-side step — see [test-data/README.md](test-data/README.md); without it the
journal is empty and every chart shows its empty state.
Open the dashboard: <http://localhost:8088/data/perspective/client/PrimeBAT>
## 3. The edit → reload → verify loop
Everything under `ignition/gateway/projects/PrimeBAT/` is a plain file. After editing:
```bash
python3 tools/lint_project.py # MUST exit 0 (banned strings, Jython, schema)
python3 tools/provision.py scan-projects # hot-reload project resources into the gateway
# (use scan-config instead after editing config resources or tags)
sleep 5; docker logs buildathon-ignition --since 1m 2>&1 | grep -iE "error|exception|traceback"
curl -s -o /dev/null -w "%{http_code}\n" http://localhost:8088/data/perspective/client/PrimeBAT
```
`lint_project.py` is the gate — it enforces the CONTRACT's banned strings (`SELECT`,
`[default]`, `BuildathonSim`, f-strings, …), resource.json boilerplate, and style-class
references. Keep it at **0 failures / 0 warnings**.
## 4. Unit tests (pure data-layer logic)
`PrimeControls.calc` and `PrimeControls.fmt` are written to run under **both** Jython 2.7
(in the gateway) and CPython 3 (for pytest). `tests/conftest.py` imports them straight
from the project's `code.py`, so tests exercise the real gateway code.
```bash
pip install pytest # not vendored
python3 -m pytest -q tests/ # 31 tests (calc + fmt)
```
`PrimeControls.alarms` is the gateway adapter (calls `system.alarm.*`) and is **not**
unit-tested — verify it live (next section).
## 5. Browser verification harness (no Designer needed)
You can render the live Perspective client headless and screenshot it — how the tabs and
popups in this repo were actually verified (the schema lint can't catch render-time bugs).
Chromium needs a few system libs. If you have sudo: `npx playwright install --with-deps
chromium`. Without sudo (WSL2 dev boxes), fetch and extract them locally:
```bash
mkdir -p /tmp/pw && cd /tmp/pw && npm init -y && npm install playwright
npx playwright install chromium
mkdir libs && cd libs
apt-get download libnspr4 libnss3 libasound2t64 libasound2-data
for d in *.deb; do dpkg-deb -x "$d" root; done
export LD_LIBRARY_PATH="$PWD/root/usr/lib/x86_64-linux-gnu" # then run node from /tmp/pw
```
Minimal probe (`/tmp/pw/probe.js`) — load, wait for the bundle to fetch, screenshot,
capture console errors:
```js
const { chromium } = require('playwright');
(async () => {
const b = await chromium.launch();
const p = await b.newPage({ viewport: { width: 1600, height: 1000 } });
p.on('console', m => m.type() === 'error' && console.log('ERR', m.text().slice(0, 200)));
p.on('pageerror', e => console.log('PAGEERR', e.message.slice(0, 200)));
await p.goto('http://localhost:8088/data/perspective/client/PrimeBAT', { waitUntil: 'networkidle' });
await p.waitForTimeout(11000); // onStartup sets range -> bundle fetch -> render
await p.screenshot({ path: 'dash.png' });
// click a tab: await p.getByText('Bad Actors').first().click(); await p.waitForTimeout(4000);
await b.close();
})();
```
`node probe.js` → inspect `dash.png`. A live gateway-side data probe (runs the real
`getDashboardBundle` against the journal) lives at `ignition/gateway/projects/SimHarness/
ignition/script-python/probe/` — enable the `ProbeTick` timer, scan, read
`ignition/gateway/projects/.probe/out.json`.
## 6. Gotchas that already bit us (all in CONTRACT.md, repeated here)
- **Jython 2.7 in all gateway scripts/transforms:** `%` formatting only (no f-strings),
no `typing`/`statistics`, every inline-script line starts with a tab. Wrap any
`system.*` / `PrimeControls.alarms.*` call in a **bare `except:`** — Java exceptions
bypass `except Exception`. Every transform must tolerate `null`/empty (the bundle can
be `None`).
- **A view cannot nest sub-views inside its own folder.** `Dashboard` is a view, so
Header/FilterBar had to move to `PrimeControls/Shell/` — nesting them under
`Dashboard/` made them resolve as "view does not exist." Put shared/child views under
a *pure folder* (`Tabs/`, `Components/`, `Popups/`, `Shell/`).
- **Input params must be `persistent: false`.** With `persistent: true`, Perspective
bakes the last-received value into `view.json` on render — the live bundle (with sim
tag paths) got serialized into a tab and broke lint. Parents/openers always supply
these params, so persistence is never needed.
- **No SQL, no tag bindings, no `journalName=` literals, no docked views.** All resources
under `PrimeControls/` namespaces.
- The gateway writes runtime churn to `ignition/gateway/config/ignition/tags/
valueStore.idb` and the trial-clock system properties — don't commit those. (Worth
adding to `.gitignore`.)
## 7. Where things are
| Path | What |
| --- | --- |
| `…/views/PrimeControls/Dashboard/view.json` | Main view: onStartup range init, `custom.bundle` binding, tab embeds |
| `…/views/PrimeControls/Shell/{Header,FilterBar}` | Health score + KPI ribbon + date range; filter bar |
| `…/views/PrimeControls/Tabs/{Overview,Analysis,BadActors,Journal}` | Tab content (embedded, tab-visibility bound) |
| `…/views/PrimeControls/Popups/{HealthScore,ShiftReport,AlarmDetail,EventDetail}` | Popups (IDs are constants — see CONTRACT) |
| `…/views/PrimeControls/Components/*` | Shared components (KpiCard, SourceRow, HeatmapCell, …) |
| `…/script-python/PrimeControls/{calc,fmt,alarms}/code.py` | Data layer (calc/fmt pure; alarms = gateway adapter) |
| `tools/lint_project.py`, `tools/provision.py` | Lint gate; gateway provisioning/reload |
| `tests/` | pytest for calc + fmt |
## 8. Current state & what's next
**Done (Phase 2, committed):** all 4 tabs + 4 popups built; Overview timeline and the
Bad Actors ranked "Top Sources" table are **browser-verified**. Lint clean.
**Not yet live-verified:** Analysis, Journal, and the 4 popups were schema-verified and
reload-clean but never rendered/clicked — do a browser pass (section 5) before trusting
them.
**Next phase — the Header.** It renders now (after the Shell relocation) but is slated
for rework, and a benign `React.cloneElement … null` console warning still needs chasing
(the KPI ribbon / dropdowns are the suspects, since it fires even with the header
painting correctly).
See [plan.md](plan.md) for the overall design and the remaining "build if time allows"
ideas (compare-to-prior-period deltas, native drawing gauge, shift report polish).