From d749e50966baa4bdab223a02a9a216148feca664 Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 18 Oct 2026 14:00:23 +0000 Subject: [PATCH 1/5] verify-graph: drive the graph page with the Playwright CLI Swap the Playwright MCP calls for playwright-cli (one session per branch, so parallel checks don't share a browser), and refresh the checks to match develop and the zenoh simulator: BMS/Segment_Total_Volt/0 as the topic, the Quick Select historical range, and develop's known NG0100 console errors as the baseline. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01PVbhpw5Qyzvh4MP7UgZJx9 --- .../.claude/skills/verify-graph/SKILL.md | 18 ++++++++++-------- .../.claude/skills/verify-graph/helpers.js | 18 +++--------------- 2 files changed, 13 insertions(+), 23 deletions(-) diff --git a/software/application-software/argos/workspace-inherit/.claude/skills/verify-graph/SKILL.md b/software/application-software/argos/workspace-inherit/.claude/skills/verify-graph/SKILL.md index cd04379..ee7e2cc 100644 --- a/software/application-software/argos/workspace-inherit/.claude/skills/verify-graph/SKILL.md +++ b/software/application-software/argos/workspace-inherit/.claude/skills/verify-graph/SKILL.md @@ -1,21 +1,23 @@ --- name: verify-graph -description: Playwright MCP verification of the graph page — modes, controls, topic selection, and data rendering. Use after any change to graph-page components, graph rendering, data flow, or mode switching logic. +description: Playwright CLI verification of the graph page — modes, controls, topic selection, and data rendering. Use after any change to graph-page components, graph rendering, data flow, or mode switching logic. user-invocable: true --- Get the ticket's branch running with `run-local `; that branch's client URL is `BASE_URL`. Historical runs with data must exist. Screenshots go to `pictures//verify-graph/NN-.png` (gitignored). -Per check: `browser_navigate` → `browser_snapshot` (assert) → `browser_click` or `browser_run_code` → `browser_take_screenshot`. Two clicks need `browser_run_code` with a body from `helpers.js`: **selectRun** ("Select this Run" sits under a PrimeNG overlay) and **selectTopic** (a tree click on a leaf navigates away). Run the groups in order; stop and fix at the first failure. +Drive the page with `playwright-cli` (`npm i -g @playwright/cli`), in a session named after the branch so parallel checks don't share a browser: `P="playwright-cli -s="`, then `$P open "$BASE_URL/graph"`. Where no Playwright browser is installed (`playwright-cli install-browser`), as in cloud containers, add `--config=` to `open`, with `{"browser":{"browserName":"chromium","launchOptions":{"executablePath":"/opt/pw-browsers/chromium","headless":true}},"outputDir":""}`; `outputDir` keeps its snapshot and console files out of the repo (`.playwright-cli/` otherwise). + +Per check: act with `$P click "button:has-text('Pause')"` (or `role=combobox[name='Quick Select']`, `role=option[name='5 minutes']`, or a ref from a snapshot) → assert with `$P find ""` or `$P snapshot` → `$P screenshot --filename=pictures//verify-graph/NN-.png`. "Select this Run" sits under a PrimeNG overlay: click it with `$P run-code --filename=helpers.js`. Run the groups in order; stop and fix at the first failure. `$P close` at the end. | # | Do | Assert | |---|---|---| -| 1 | Open `{BASE_URL}/graph` | Header "Real Time"; Pause, Time Range, Select Run, Clear Graph; "X (sec):", Y Min/Max, "Select Range"; no Realtime button | -| 2 | Expand BMS › Pack, selectTopic "Voltage", wait 3s | URL has `?topics=BMS/Pack/Voltage`; a series is drawn | -| 3 | Pause↔Play; Time Range↔Point Range; Tog Sidebar twice | Labels flip ("X (points):" in point range); sidebar hides, then returns | -| 4 | Select Run, then selectRun, wait 3s | Header "Run #N"; Realtime shown; no Pause or Time Range; Y Min/Max remain; x-axis spans more than 30s | -| 5 | Realtime; open Select Range, pick "5 minutes" | 7 options (1, 2, 5, 10, 15, 30 min, 1 hour); header "Hist Range"; Realtime shown, no Pause; x-axis about 5 min | -| 6 | Cycle Realtime → Run → Realtime → "1 minute" → Realtime | Headers match each mode; no console errors (`browser_console_messages`) | +| 1 | Open `{BASE_URL}/graph` | Header "Real Time"; Pause, Time Range, Select Run, Clear Graph; "X (sec):", Y Min/Max, "Historical:" Quick Select and Custom; no Realtime button | +| 2 | Expand BMS › Segment_Total_Volt (click the tree toggles), click leaf "0", wait 3s | URL has `?topics=BMS%2FSegment_Total_Volt%2F0`; a series is drawn | +| 3 | Pause↔Play; Time Range↔Point Range; Tog Sidebar twice | Labels flip ("X (points):" in point range); sidebar hides, then returns. Leave it playing, in time range | +| 4 | Select Run, then helpers.js, wait 3s | Header "Run #N"; Realtime shown; no Pause or Time Range; Y Min/Max remain; x-axis spans more than 30s | +| 5 | Realtime; open Quick Select, pick "5 minutes" | 11 options (1, 2, 5, 10, 15, 30 min, 1, 2, 4, 8, 24 hours); header "Historical"; Realtime shown, no Pause; x-axis about 5 min, or since the data starts | +| 6 | `$P console --clear`; cycle Realtime → Run → Realtime → "1 minute" → Realtime | Headers match each mode; no console errors in `$P console error` beyond develop's: NG0100 in `_MessagesPerSecondComponent` and, after mode switches, in `_GraphPageComponent` | | 7 | In real time, wait 10s | x-axis about 30s, not the whole session (historical auto-fit doesn't leak) | Report a checklist (one line per group, `[x]` or `[ ]` with the failure) and the screenshot folder. diff --git a/software/application-software/argos/workspace-inherit/.claude/skills/verify-graph/helpers.js b/software/application-software/argos/workspace-inherit/.claude/skills/verify-graph/helpers.js index 09a6304..be6355a 100644 --- a/software/application-software/argos/workspace-inherit/.claude/skills/verify-graph/helpers.js +++ b/software/application-software/argos/workspace-inherit/.claude/skills/verify-graph/helpers.js @@ -1,7 +1,6 @@ -// Bodies for Playwright MCP `browser_run_code` in the verify-graph skill. Paste one function as-is. - -// selectRun: the run carousel's "Select this Run" button sits under a PrimeNG overlay, so click it -// with a synthetic event instead of browser_click. +// selectRun, for `playwright-cli run-code --filename=` in the verify-graph skill: the run +// carousel's "Select this Run" button sits under a PrimeNG overlay, so click it with a synthetic event +// instead of `playwright-cli click`. async (page) => { await page.waitForTimeout(1500); await page.evaluate(() => { @@ -11,14 +10,3 @@ async (page) => { }); await page.waitForTimeout(2000); } - -// selectTopic: clicking a leaf in the tree navigates away, so click its label instead. -// Change 'Voltage' to the leaf you want. -async (page) => { - await page.evaluate((topicName) => { - const p = Array.from(document.querySelectorAll('p')) - .find(el => el.textContent?.trim() === topicName); - if (p) p.click(); - }, 'Voltage'); - await page.waitForTimeout(3000); -} From 4a84f81b912cb0d08a0fa63ebfccf4ed97849738 Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 18 Oct 2026 15:19:38 +0000 Subject: [PATCH 2/5] run-local, verify-graph: parallel-safe ports, a shared multi-day seed run, per-branch browser output serve.sh claims its port under a short mkdir lock, so parallel runs stop picking the same port while ng serve starts. verify-graph gets scripts: seed.sh makes one 50-hour run spanning two midnights (once, under a lock) and prints its id; select-run.sh picks a run by id in the autoplaying carousel; open.sh opens a per-branch session with its output under pictures//verify-graph/. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01PVbhpw5Qyzvh4MP7UgZJx9 --- .../.claude/skills/run-local/SKILL.md | 2 +- .../.claude/skills/run-local/scripts/serve.sh | 11 ++++++- .../.claude/skills/verify-graph/SKILL.md | 8 ++--- .../skills/verify-graph/scripts/open.sh | 12 +++++++ .../skills/verify-graph/scripts/seed.sh | 31 +++++++++++++++++++ .../skills/verify-graph/scripts/select-run.sh | 18 +++++++++++ 6 files changed, 76 insertions(+), 6 deletions(-) create mode 100755 software/application-software/argos/workspace-inherit/.claude/skills/verify-graph/scripts/open.sh create mode 100755 software/application-software/argos/workspace-inherit/.claude/skills/verify-graph/scripts/seed.sh create mode 100755 software/application-software/argos/workspace-inherit/.claude/skills/verify-graph/scripts/select-run.sh diff --git a/software/application-software/argos/workspace-inherit/.claude/skills/run-local/SKILL.md b/software/application-software/argos/workspace-inherit/.claude/skills/run-local/SKILL.md index d99b18a..8618099 100644 --- a/software/application-software/argos/workspace-inherit/.claude/skills/run-local/SKILL.md +++ b/software/application-software/argos/workspace-inherit/.claude/skills/run-local/SKILL.md @@ -9,6 +9,6 @@ Run the branches the user is asking about: a PR or ticket means its branch (make bash scripts/run-local.sh ... ``` -It starts the backend if it's down (`client-dev`, or `scylla-dev` plus `cargo run` when a target changes `scylla-server/`), and serves each target's client on the next free port. With no branches it reports what's running. +It starts the backend if it's down (`client-dev`, or `scylla-dev` plus `cargo run` when a target changes `scylla-server/`), and serves each target's client on the next free port; parallel runs (one per session or agent) each get their own. With no branches it reports what's running. Report each branch's client URL and the backend. A failed compile or a stale-backend warning is a finding: show it to the user. Stop a client with `kill ` from its line. diff --git a/software/application-software/argos/workspace-inherit/.claude/skills/run-local/scripts/serve.sh b/software/application-software/argos/workspace-inherit/.claude/skills/run-local/scripts/serve.sh index cf98f99..99d5095 100755 --- a/software/application-software/argos/workspace-inherit/.claude/skills/run-local/scripts/serve.sh +++ b/software/application-software/argos/workspace-inherit/.claude/skills/run-local/scripts/serve.sh @@ -18,9 +18,18 @@ if [ -f "$key.pid" ] && kill -0 "$(cat "$key.pid")" 2>/dev/null && up "$(cat "$k exit 0 fi +# Claim the port under a lock, or parallel calls all pick the same one while ng serve starts. A port is +# taken once a client listens on it or a live serve.sh has claimed it. mkdir is the lock (no flock on +# macOS); it is held only for the claim, so nothing started below can keep it. +lock=$state/port.lock +n=0; until mkdir "$lock" 2>/dev/null; do n=$((n + 1)); [ $n -lt 100 ] || rm -rf "$lock"; sleep 0.1; done # stale after 10s +trap 'rmdir "$lock" 2>/dev/null || true' EXIT +claimed() { for f in "$state"/*.port; do [ -f "$f" ] && [ "$(cat "$f")" = "$1" ] && kill -0 "$(cat "${f%.port}.pid")" 2>/dev/null && return; done; return 1; } port= -for p in $(seq 4200 4210); do up "$p" || { port=$p && break; }; done +for p in $(seq 4200 4210); do up "$p" || claimed "$p" || { port=$p && break; }; done [ -n "$port" ] || { echo "serve: no free port in 4200-4210" >&2 && exit 1; } +echo $$ >"$key.pid" && echo "$port" >"$key.port" # claimed by this script until ng serve's pid replaces it +rmdir "$lock" && trap - EXIT cd "$wt/angular-client" [ -x node_modules/.bin/ng ] || npm ci --no-audit --no-fund >"$log" 2>&1 || diff --git a/software/application-software/argos/workspace-inherit/.claude/skills/verify-graph/SKILL.md b/software/application-software/argos/workspace-inherit/.claude/skills/verify-graph/SKILL.md index ee7e2cc..e400eaa 100644 --- a/software/application-software/argos/workspace-inherit/.claude/skills/verify-graph/SKILL.md +++ b/software/application-software/argos/workspace-inherit/.claude/skills/verify-graph/SKILL.md @@ -4,18 +4,18 @@ description: Playwright CLI verification of the graph page — modes, controls, user-invocable: true --- -Get the ticket's branch running with `run-local `; that branch's client URL is `BASE_URL`. Historical runs with data must exist. Screenshots go to `pictures//verify-graph/NN-.png` (gitignored). +Get the ticket's branch running with `run-local `; that branch's client URL is `BASE_URL`. Then `RUN=$(bash scripts/seed.sh)`: the id of a 50-hour run spanning two midnights, made once in the local database and shared by parallel checks, so other sessions starting runs can't change which run you check. Screenshots go to `pictures//verify-graph/NN-.png` (gitignored). -Drive the page with `playwright-cli` (`npm i -g @playwright/cli`), in a session named after the branch so parallel checks don't share a browser: `P="playwright-cli -s="`, then `$P open "$BASE_URL/graph"`. Where no Playwright browser is installed (`playwright-cli install-browser`), as in cloud containers, add `--config=` to `open`, with `{"browser":{"browserName":"chromium","launchOptions":{"executablePath":"/opt/pw-browsers/chromium","headless":true}},"outputDir":""}`; `outputDir` keeps its snapshot and console files out of the repo (`.playwright-cli/` otherwise). +Drive the page with `playwright-cli` (`npm i -g @playwright/cli`): `bash scripts/open.sh "$BASE_URL/graph"` opens a session named after the branch, with its snapshot and console files in `pictures//verify-graph/playwright-cli/`; then `P="playwright-cli -s="`. -Per check: act with `$P click "button:has-text('Pause')"` (or `role=combobox[name='Quick Select']`, `role=option[name='5 minutes']`, or a ref from a snapshot) → assert with `$P find ""` or `$P snapshot` → `$P screenshot --filename=pictures//verify-graph/NN-.png`. "Select this Run" sits under a PrimeNG overlay: click it with `$P run-code --filename=helpers.js`. Run the groups in order; stop and fix at the first failure. `$P close` at the end. +Per check: act with `$P click "button:has-text('Pause')"` (or `role=combobox[name='Quick Select']`, `role=option[name='5 minutes']`, or a ref from a snapshot) → assert with `$P find ""` or `$P snapshot` → `$P screenshot --filename=pictures//verify-graph/NN-.png`. To pick the seeded run, click Select Run, then `bash scripts/select-run.sh $RUN`. Run the groups in order; stop and fix at the first failure. `$P close` at the end. | # | Do | Assert | |---|---|---| | 1 | Open `{BASE_URL}/graph` | Header "Real Time"; Pause, Time Range, Select Run, Clear Graph; "X (sec):", Y Min/Max, "Historical:" Quick Select and Custom; no Realtime button | | 2 | Expand BMS › Segment_Total_Volt (click the tree toggles), click leaf "0", wait 3s | URL has `?topics=BMS%2FSegment_Total_Volt%2F0`; a series is drawn | | 3 | Pause↔Play; Time Range↔Point Range; Tog Sidebar twice | Labels flip ("X (points):" in point range); sidebar hides, then returns. Leave it playing, in time range | -| 4 | Select Run, then helpers.js, wait 3s | Header "Run #N"; Realtime shown; no Pause or Time Range; Y Min/Max remain; x-axis spans more than 30s | +| 4 | Select Run, then select-run.sh, wait 3s | Header "Run #$RUN"; Realtime shown; no Pause or Time Range; Y Min/Max remain; x-axis spans the run's 50 hours, with a dated day-boundary line at each midnight | | 5 | Realtime; open Quick Select, pick "5 minutes" | 11 options (1, 2, 5, 10, 15, 30 min, 1, 2, 4, 8, 24 hours); header "Historical"; Realtime shown, no Pause; x-axis about 5 min, or since the data starts | | 6 | `$P console --clear`; cycle Realtime → Run → Realtime → "1 minute" → Realtime | Headers match each mode; no console errors in `$P console error` beyond develop's: NG0100 in `_MessagesPerSecondComponent` and, after mode switches, in `_GraphPageComponent` | | 7 | In real time, wait 10s | x-axis about 30s, not the whole session (historical auto-fit doesn't leak) | diff --git a/software/application-software/argos/workspace-inherit/.claude/skills/verify-graph/scripts/open.sh b/software/application-software/argos/workspace-inherit/.claude/skills/verify-graph/scripts/open.sh new file mode 100755 index 0000000..038a875 --- /dev/null +++ b/software/application-software/argos/workspace-inherit/.claude/skills/verify-graph/scripts/open.sh @@ -0,0 +1,12 @@ +#!/usr/bin/env bash +# open.sh : open a playwright-cli session named on , so parallel checks don't +# share a browser. Its snapshot and console files go to pictures//verify-graph/playwright-cli/ +# (gitignored), not .playwright-cli/ wherever it runs. Uses the preinstalled Chromium in cloud +# containers (/opt/pw-browsers); elsewhere, Playwright's own (`playwright-cli install-browser`). +set -euo pipefail +branch=${1:?usage: open.sh }; url=${2:?usage: open.sh } +out=${DELPHI_ROOT:?unset: start the session at the workspace root}/pictures/$branch/verify-graph/playwright-cli +mkdir -p "$out" +launch=; [ -x /opt/pw-browsers/chromium ] && launch=',"launchOptions":{"executablePath":"/opt/pw-browsers/chromium","headless":true}' +printf '{"browser":{"browserName":"chromium"%s},"outputDir":"%s"}\n' "$launch" "$out" >"$out/cli.config.json" +playwright-cli -s="$branch" open --config="$out/cli.config.json" "$url" diff --git a/software/application-software/argos/workspace-inherit/.claude/skills/verify-graph/scripts/seed.sh b/software/application-software/argos/workspace-inherit/.claude/skills/verify-graph/scripts/seed.sh new file mode 100755 index 0000000..fdb2631 --- /dev/null +++ b/software/application-software/argos/workspace-inherit/.claude/skills/verify-graph/scripts/seed.sh @@ -0,0 +1,31 @@ +#!/usr/bin/env bash +# seed.sh: make sure the local database holds verify-graph's multi-day run, and print its id. The run is +# 50 hours of BMS/Segment_Total_Volt/0, one point every 30s, from noon UTC four days ago, so it crosses +# two midnights in any time zone and stays out of the 24-hour Quick Select window. Parallel checks share +# one run: it is made once, under a lock, and found by its notes after that. +set -euo pipefail +db=$(docker ps --filter name=odyssey-db --format '{{.Names}}' | head -1) +[ -n "$db" ] || { echo "seed: no odyssey-db container; start the backend with run-local first" >&2 && exit 1; } +sql() { docker exec -i "$db" psql -U postgres -v ON_ERROR_STOP=1 -qAt "$@"; } +tag='verify-graph multi-day seed' +state=${TMPDIR:-/tmp}; state=${state%/}/argos-run-local; mkdir -p "$state" +lock=$state/seed.lock +n=0; until mkdir "$lock" 2>/dev/null; do n=$((n + 1)); [ $n -lt 600 ] || rm -rf "$lock"; sleep 0.1; done # stale after 60s +trap 'rmdir "$lock" 2>/dev/null || true' EXIT +id=$(sql -c "select \"runId\" from run where notes = '$tag' limit 1") +[ -n "$id" ] || id=$(sql < : with the Select Run dialog open in 's session, pick run +# . The carousel autoplays and its "Select this Run" button sits under a PrimeNG overlay, so this +# finds the run's card by id and clicks its button with a synthetic event instead of `playwright-cli click`. +set -euo pipefail +branch=${1:?usage: select-run.sh }; id=${2:?usage: select-run.sh } +case $id in '' | *[!0-9]*) echo "select-run: run id must be a number, got '$id'" >&2 && exit 1 ;; esac +playwright-cli -s="$branch" run-code "async (page) => { + await page.waitForSelector('.run-card'); + const found = await page.evaluate((id) => { + const card = [...document.querySelectorAll('.run-card')] + .find((c) => [...c.querySelectorAll('*')].some((e) => !e.childElementCount && e.textContent.trim() === 'Run #' + id)); + const button = card?.parentElement?.querySelector('.run-select-button button'); + button?.dispatchEvent(new MouseEvent('click', { bubbles: true, cancelable: true })); + return !!button; + }, $id); + if (!found) throw new Error('select-run: no Run #$id in the Select Run dialog'); +}" From 8a32c72a46b5d69357c298138b8c73a1bca2eac3 Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 18 Oct 2026 15:34:50 +0000 Subject: [PATCH 3/5] verify-graph: script the base checks, leave the rest to the agent check.sh seeds the shared run, opens the branch's session and runs check.js: page load, a tree topic drawing live, the seeded run, historical Quick Select, back to real time and new console errors. It prints a checklist and screenshots to judge. The skill now points the agent at hand checks for what the diff touches, with the CLI patterns to drive them. helpers.js is gone: select-run.sh replaced it. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01PVbhpw5Qyzvh4MP7UgZJx9 --- .../.claude/skills/verify-graph/SKILL.md | 25 +++--- .../.claude/skills/verify-graph/helpers.js | 12 --- .../skills/verify-graph/scripts/check.js | 82 +++++++++++++++++++ .../skills/verify-graph/scripts/check.sh | 14 ++++ 4 files changed, 108 insertions(+), 25 deletions(-) delete mode 100644 software/application-software/argos/workspace-inherit/.claude/skills/verify-graph/helpers.js create mode 100644 software/application-software/argos/workspace-inherit/.claude/skills/verify-graph/scripts/check.js create mode 100755 software/application-software/argos/workspace-inherit/.claude/skills/verify-graph/scripts/check.sh diff --git a/software/application-software/argos/workspace-inherit/.claude/skills/verify-graph/SKILL.md b/software/application-software/argos/workspace-inherit/.claude/skills/verify-graph/SKILL.md index e400eaa..5447094 100644 --- a/software/application-software/argos/workspace-inherit/.claude/skills/verify-graph/SKILL.md +++ b/software/application-software/argos/workspace-inherit/.claude/skills/verify-graph/SKILL.md @@ -4,20 +4,19 @@ description: Playwright CLI verification of the graph page — modes, controls, user-invocable: true --- -Get the ticket's branch running with `run-local `; that branch's client URL is `BASE_URL`. Then `RUN=$(bash scripts/seed.sh)`: the id of a 50-hour run spanning two midnights, made once in the local database and shared by parallel checks, so other sessions starting runs can't change which run you check. Screenshots go to `pictures//verify-graph/NN-.png` (gitignored). +Get the branch's client running with `run-local `; its URL is `BASE_URL`. Then run the base checks: -Drive the page with `playwright-cli` (`npm i -g @playwright/cli`): `bash scripts/open.sh "$BASE_URL/graph"` opens a session named after the branch, with its snapshot and console files in `pictures//verify-graph/playwright-cli/`; then `P="playwright-cli -s="`. +``` +bash scripts/check.sh "$BASE_URL" +``` -Per check: act with `$P click "button:has-text('Pause')"` (or `role=combobox[name='Quick Select']`, `role=option[name='5 minutes']`, or a ref from a snapshot) → assert with `$P find ""` or `$P snapshot` → `$P screenshot --filename=pictures//verify-graph/NN-.png`. To pick the seeded run, click Select Run, then `bash scripts/select-run.sh $RUN`. Run the groups in order; stop and fix at the first failure. `$P close` at the end. +It seeds a 50-hour run spanning two midnights (once, shared by parallel checks), opens a `playwright-cli` session named after the branch, and runs `scripts/check.js`. That covers: page loads in real time, a topic from the tree draws live, the seeded run, historical Quick Select, back to real time, and no console errors beyond develop's NG0100. It prints `[x]`/`[ ]` per check and exits 1 on a failure. Each `look:` line names a screenshot and what it should show: open it and judge it, since only a picture shows whether a chart is right. -| # | Do | Assert | -|---|---|---| -| 1 | Open `{BASE_URL}/graph` | Header "Real Time"; Pause, Time Range, Select Run, Clear Graph; "X (sec):", Y Min/Max, "Historical:" Quick Select and Custom; no Realtime button | -| 2 | Expand BMS › Segment_Total_Volt (click the tree toggles), click leaf "0", wait 3s | URL has `?topics=BMS%2FSegment_Total_Volt%2F0`; a series is drawn | -| 3 | Pause↔Play; Time Range↔Point Range; Tog Sidebar twice | Labels flip ("X (points):" in point range); sidebar hides, then returns. Leave it playing, in time range | -| 4 | Select Run, then select-run.sh, wait 3s | Header "Run #$RUN"; Realtime shown; no Pause or Time Range; Y Min/Max remain; x-axis spans the run's 50 hours, with a dated day-boundary line at each midnight | -| 5 | Realtime; open Quick Select, pick "5 minutes" | 11 options (1, 2, 5, 10, 15, 30 min, 1, 2, 4, 8, 24 hours); header "Historical"; Realtime shown, no Pause; x-axis about 5 min, or since the data starts | -| 6 | `$P console --clear`; cycle Realtime → Run → Realtime → "1 minute" → Realtime | Headers match each mode; no console errors in `$P console error` beyond develop's: NG0100 in `_MessagesPerSecondComponent` and, after mode switches, in `_GraphPageComponent` | -| 7 | In real time, wait 10s | x-axis about 30s, not the whole session (historical auto-fit doesn't leak) | +Go further where the diff points, by hand in the same session (`P="playwright-cli -s="`): controls the diff touches (Pause↔Play, Time Range↔Point Range, Tog Sidebar, Tog Mult Yaxis, Y Min/Max, Custom range, Clear Graph), zoom, pan and hover, several topics, or mode switching for console errors. Reproduce a failed check the same way before fixing it; `check.js` has its steps. -Report a checklist (one line per group, `[x]` or `[ ]` with the failure) and the screenshot folder. +- Act: `$P click "button:has-text('Pause')"`, `role=combobox[name='Quick Select']`, `role=option[name='5 minutes']`, or a ref from `$P snapshot`. +- Assert: `$P find ""`, `$P snapshot`, `$P console error`; longer Playwright code with `$P run-code "async (page) => {…}"`. +- The seeded run: click Select Run, then `bash scripts/select-run.sh $(bash scripts/seed.sh)`. +- Screenshots: `$P screenshot --filename=pictures//verify-graph/NN-.png` (gitignored). + +When a hand check keeps coming back, add it to `check.js`. Report `check.sh`'s lines plus one line per hand check, and the screenshot folder. `$P close` at the end. diff --git a/software/application-software/argos/workspace-inherit/.claude/skills/verify-graph/helpers.js b/software/application-software/argos/workspace-inherit/.claude/skills/verify-graph/helpers.js deleted file mode 100644 index be6355a..0000000 --- a/software/application-software/argos/workspace-inherit/.claude/skills/verify-graph/helpers.js +++ /dev/null @@ -1,12 +0,0 @@ -// selectRun, for `playwright-cli run-code --filename=` in the verify-graph skill: the run -// carousel's "Select this Run" button sits under a PrimeNG overlay, so click it with a synthetic event -// instead of `playwright-cli click`. -async (page) => { - await page.waitForTimeout(1500); - await page.evaluate(() => { - const btn = Array.from(document.querySelectorAll('button')) - .find(b => b.textContent?.includes('Select this Run')); - if (btn) btn.dispatchEvent(new MouseEvent('click', { bubbles: true, cancelable: true })); - }); - await page.waitForTimeout(2000); -} diff --git a/software/application-software/argos/workspace-inherit/.claude/skills/verify-graph/scripts/check.js b/software/application-software/argos/workspace-inherit/.claude/skills/verify-graph/scripts/check.js new file mode 100644 index 0000000..bd1e8b0 --- /dev/null +++ b/software/application-software/argos/workspace-inherit/.claude/skills/verify-graph/scripts/check.js @@ -0,0 +1,82 @@ +// The base verify-graph checks, for check.sh to run with `playwright-cli run-code` (it fills in __URL__, +// __RUN__ and __OUT__). Each check asserts what the DOM can show; what only a picture can show (a series +// drawn, the x-axis span) is a screenshot with a `look:` line for the agent to judge. +async (page) => { + const URL = '__URL__', RUN = __RUN__, OUT = '__OUT__'; + const lines = [], errors = []; + page.on('console', (m) => { + if (m.type() === 'error' && !m.text().includes('NG0100')) errors.push(m.text().split('\n')[0].slice(0, 160)); + }); // develop already logs NG0100 (ExpressionChangedAfterItHasBeenChecked) + const text = (t) => page.getByText(t, { exact: true }); + const button = (name) => page.getByRole('button', { name, exact: true }); + const tree = page.getByRole('tree'); + const absent = async (name) => { if (await button(name).isVisible()) throw new Error(`"${name}" is shown`); }; + const shot = async (name, look) => { + await page.screenshot({ path: `${OUT}/${name}.png` }); + lines.push(` look: ${OUT}/${name}.png: ${look}`); + }; + const check = async (name, steps) => { + const at = lines.length; + try { + await steps(); + lines.splice(at, 0, `[x] ${name}`); + } catch (e) { + lines.push(`[ ] ${name}: ${String(e.message).split('\n')[0]}`); + } + }; + + await check('1 page loads in real time', async () => { + await page.goto(`${URL}/graph`); + await text('Real Time').waitFor({ timeout: 30000 }); + for (const b of ['Pause', 'Time Range', 'Select Run', 'Clear Graph', 'Custom']) await button(b).waitFor({ timeout: 2000 }); + await page.getByRole('combobox', { name: 'Quick Select' }).waitFor({ timeout: 2000 }); + await absent('Realtime'); + }); + await check('2 topic from the tree draws live', async () => { + const node = (name) => tree.getByRole('treeitem').filter({ has: page.getByText(name, { exact: true }) }).last(); // innermost + for (const name of ['BMS', 'Segment_Total_Volt']) await node(name).locator('.p-tree-node-toggle-button').first().click(); + await tree.getByText('0', { exact: true }).first().click(); + await page.waitForURL(/topics=BMS%2FSegment_Total_Volt%2F0/, { timeout: 5000 }); + await page.waitForTimeout(3000); + await shot('02-live-topic', 'a live series is drawn'); + }); + await check(`3 seeded run #${RUN}`, async () => { + await button('Select Run').click(); + await page.locator('.run-card').first().waitFor({ timeout: 10000 }); + await page.evaluate((id) => { + const card = [...document.querySelectorAll('.run-card')] + .find((c) => [...c.querySelectorAll('*')].some((e) => !e.childElementCount && e.textContent.trim() === 'Run #' + id)); + const pick = card?.parentElement?.querySelector('.run-select-button button'); + if (!pick) throw new Error(`no Run #${id} in the Select Run dialog`); + pick.dispatchEvent(new MouseEvent('click', { bubbles: true, cancelable: true })); // under a PrimeNG overlay + }, RUN); + await page.locator('.run-card').first().waitFor({ state: 'detached', timeout: 5000 }); + await text(`Run #${RUN}`).waitFor({ timeout: 10000 }); + await button('Realtime').waitFor({ timeout: 2000 }); + await absent('Pause'); + await page.waitForTimeout(3000); + await shot('03-seeded-run', 'x-axis spans 50 hours, with a dated day-boundary line at each of the two midnights'); + }); + await check('4 historical Quick Select', async () => { + await button('Realtime').click(); + await text('Real Time').waitFor({ timeout: 5000 }); + await page.getByRole('combobox', { name: 'Quick Select' }).click(); + const options = await page.getByRole('option').count(); + if (options !== 11) throw new Error(`${options} Quick Select options, not 11`); + await page.getByRole('option', { name: '5 minutes', exact: true }).click(); + await text('Historical').waitFor({ timeout: 5000 }); + await absent('Pause'); + await page.waitForTimeout(3000); + await shot('04-historical-5-min', 'x-axis about 5 minutes, or since the data starts'); + }); + await check('5 back to real time', async () => { + await button('Realtime').click(); + await text('Real Time').waitFor({ timeout: 5000 }); + await page.waitForTimeout(10000); + await shot('05-real-time-after', 'x-axis about 30 seconds, not the whole session'); + }); + await check('6 no new console errors', async () => { + if (errors.length) throw new Error(`${errors.length}, first: ${errors[0]}`); + }); + return lines.join('\n'); +} diff --git a/software/application-software/argos/workspace-inherit/.claude/skills/verify-graph/scripts/check.sh b/software/application-software/argos/workspace-inherit/.claude/skills/verify-graph/scripts/check.sh new file mode 100755 index 0000000..c8710cd --- /dev/null +++ b/software/application-software/argos/workspace-inherit/.claude/skills/verify-graph/scripts/check.sh @@ -0,0 +1,14 @@ +#!/usr/bin/env bash +# check.sh : run the base verify-graph checks (check.js) in 's playwright-cli +# session, opening it if needed, against the seeded multi-day run. Prints one `[x]`/`[ ]` line per check +# and `look:` lines for screenshots in pictures//verify-graph/; exits 1 if a check failed. +set -euo pipefail +here=$(cd "$(dirname "$0")" && pwd) +branch=${1:?usage: check.sh }; url=${2:?usage: check.sh }; url=${url%/} +run=$(bash "$here/seed.sh") +out=${DELPHI_ROOT:?unset: start the session at the workspace root}/pictures/$branch/verify-graph +playwright-cli list | grep -q "^- $branch:" || bash "$here/open.sh" "$branch" "$url/graph" >/dev/null +code=$(sed -e "s|__URL__|$url|; s|__RUN__|$run|; s|__OUT__|$out|" "$here/check.js") +result=$(playwright-cli -s="$branch" --raw run-code "$code" | node -e 'process.stdout.write(JSON.parse(require("fs").readFileSync(0, "utf8")))') +echo "$result" +! grep -q '^\[ \]' <<<"$result" From 8a8bf1ebcb696697c20c1c4634452516d6f259da Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 18 Oct 2026 16:00:28 +0000 Subject: [PATCH 4/5] verify-graph: open.sh sends output to pictures//, config and throwaway code to .playwright-cli// Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01PVbhpw5Qyzvh4MP7UgZJx9 --- .../.claude/skills/verify-graph/SKILL.md | 4 ++-- .../.claude/skills/verify-graph/scripts/open.sh | 16 +++++++++------- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/software/application-software/argos/workspace-inherit/.claude/skills/verify-graph/SKILL.md b/software/application-software/argos/workspace-inherit/.claude/skills/verify-graph/SKILL.md index 5447094..64167c9 100644 --- a/software/application-software/argos/workspace-inherit/.claude/skills/verify-graph/SKILL.md +++ b/software/application-software/argos/workspace-inherit/.claude/skills/verify-graph/SKILL.md @@ -10,12 +10,12 @@ Get the branch's client running with `run-local `; its URL is `BASE_URL` bash scripts/check.sh "$BASE_URL" ``` -It seeds a 50-hour run spanning two midnights (once, shared by parallel checks), opens a `playwright-cli` session named after the branch, and runs `scripts/check.js`. That covers: page loads in real time, a topic from the tree draws live, the seeded run, historical Quick Select, back to real time, and no console errors beyond develop's NG0100. It prints `[x]`/`[ ]` per check and exits 1 on a failure. Each `look:` line names a screenshot and what it should show: open it and judge it, since only a picture shows whether a chart is right. +It seeds a 50-hour run spanning two midnights (once, shared by parallel checks), opens a `playwright-cli` session named after the branch (`scripts/open.sh`: output to `pictures//`, config to `.playwright-cli//`), and runs `scripts/check.js`. That covers: page loads in real time, a topic from the tree draws live, the seeded run, historical Quick Select, back to real time, and no console errors beyond develop's NG0100. It prints `[x]`/`[ ]` per check and exits 1 on a failure. Each `look:` line names a screenshot and what it should show: open it and judge it, since only a picture shows whether a chart is right. Go further where the diff points, by hand in the same session (`P="playwright-cli -s="`): controls the diff touches (Pause↔Play, Time Range↔Point Range, Tog Sidebar, Tog Mult Yaxis, Y Min/Max, Custom range, Clear Graph), zoom, pan and hover, several topics, or mode switching for console errors. Reproduce a failed check the same way before fixing it; `check.js` has its steps. - Act: `$P click "button:has-text('Pause')"`, `role=combobox[name='Quick Select']`, `role=option[name='5 minutes']`, or a ref from `$P snapshot`. -- Assert: `$P find ""`, `$P snapshot`, `$P console error`; longer Playwright code with `$P run-code "async (page) => {…}"`. +- Assert: `$P find ""`, `$P snapshot`, `$P console error`; longer Playwright code with `$P run-code "async (page) => {…}"`, or `--filename` for a file kept in `.playwright-cli//`. - The seeded run: click Select Run, then `bash scripts/select-run.sh $(bash scripts/seed.sh)`. - Screenshots: `$P screenshot --filename=pictures//verify-graph/NN-.png` (gitignored). diff --git a/software/application-software/argos/workspace-inherit/.claude/skills/verify-graph/scripts/open.sh b/software/application-software/argos/workspace-inherit/.claude/skills/verify-graph/scripts/open.sh index 038a875..5a1b49b 100755 --- a/software/application-software/argos/workspace-inherit/.claude/skills/verify-graph/scripts/open.sh +++ b/software/application-software/argos/workspace-inherit/.claude/skills/verify-graph/scripts/open.sh @@ -1,12 +1,14 @@ #!/usr/bin/env bash # open.sh : open a playwright-cli session named on , so parallel checks don't -# share a browser. Its snapshot and console files go to pictures//verify-graph/playwright-cli/ -# (gitignored), not .playwright-cli/ wherever it runs. Uses the preinstalled Chromium in cloud -# containers (/opt/pw-browsers); elsewhere, Playwright's own (`playwright-cli install-browser`). +# share a browser. Its output (snapshots, console logs, unnamed screenshots) goes to pictures//; +# its config, and any throwaway Playwright code, to .playwright-cli//. Both are gitignored. Uses +# the preinstalled Chromium in cloud containers (/opt/pw-browsers); elsewhere, Playwright's own +# (`playwright-cli install-browser`). set -euo pipefail branch=${1:?usage: open.sh }; url=${2:?usage: open.sh } -out=${DELPHI_ROOT:?unset: start the session at the workspace root}/pictures/$branch/verify-graph/playwright-cli -mkdir -p "$out" +root=${DELPHI_ROOT:?unset: start the session at the workspace root} +out=$root/pictures/$branch scratch=$root/.playwright-cli/$branch +mkdir -p "$out" "$scratch" launch=; [ -x /opt/pw-browsers/chromium ] && launch=',"launchOptions":{"executablePath":"/opt/pw-browsers/chromium","headless":true}' -printf '{"browser":{"browserName":"chromium"%s},"outputDir":"%s"}\n' "$launch" "$out" >"$out/cli.config.json" -playwright-cli -s="$branch" open --config="$out/cli.config.json" "$url" +printf '{"browser":{"browserName":"chromium"%s},"outputDir":"%s"}\n' "$launch" "$out" >"$scratch/cli.config.json" +playwright-cli -s="$branch" open --config="$scratch/cli.config.json" "$url" From 34f5d97e3d6957e56fa87e8abd33d8c5ee01aaeb Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 18 Oct 2026 16:07:13 +0000 Subject: [PATCH 5/5] Argos workspaces park .playwright-cli/ (open.sh's per-branch config and throwaway code), so it's excluded too Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01PVbhpw5Qyzvh4MP7UgZJx9 --- .../application-software/argos/workspace-defaults/workspace.yml | 1 + .../argos/workspaces/argos-dev/workspace.yml | 1 + .../argos/workspaces/experimental/workspace.yml | 1 + 3 files changed, 3 insertions(+) diff --git a/software/application-software/argos/workspace-defaults/workspace.yml b/software/application-software/argos/workspace-defaults/workspace.yml index 10db5da..d4a70f2 100644 --- a/software/application-software/argos/workspace-defaults/workspace.yml +++ b/software/application-software/argos/workspace-defaults/workspace.yml @@ -4,6 +4,7 @@ plugins: # `- [.]`: plugin sets to enable; CI lists park: # `- `: root folders that park with this workspace on a switch (.delphi/park.sh), besides the ones it always parks - pictures - .playwright-mcp + - .playwright-cli # .delphi/setup.sh checks out everything below (git-ignored); re-run it after any change. repos: # `: `: code you change; bare store at repos/, default branch at worktrees// argos: https://github.com/Northeastern-Electric-Racing/Argos.git diff --git a/software/application-software/argos/workspaces/argos-dev/workspace.yml b/software/application-software/argos/workspaces/argos-dev/workspace.yml index f2722ac..7358ba7 100644 --- a/software/application-software/argos/workspaces/argos-dev/workspace.yml +++ b/software/application-software/argos/workspaces/argos-dev/workspace.yml @@ -6,6 +6,7 @@ plugins: # `- [.]`: plugin sets to enable; CI lists park: # `- `: root folders that park with this workspace on a switch (.delphi/park.sh), besides the ones it always parks - pictures - .playwright-mcp + - .playwright-cli # .delphi/setup.sh checks out everything below (git-ignored); re-run it after any change. repos: # `: `: code you change; bare store at repos/, default branch at worktrees// argos: https://github.com/Northeastern-Electric-Racing/Argos.git diff --git a/software/application-software/argos/workspaces/experimental/workspace.yml b/software/application-software/argos/workspaces/experimental/workspace.yml index 739548c..08d1e3e 100644 --- a/software/application-software/argos/workspaces/experimental/workspace.yml +++ b/software/application-software/argos/workspaces/experimental/workspace.yml @@ -6,6 +6,7 @@ plugins: # `- [.]`: plugin sets to enable; CI lists park: # `- `: root folders that park with this workspace on a switch (.delphi/park.sh), besides the ones it always parks - pictures - .playwright-mcp + - .playwright-cli # .delphi/setup.sh checks out everything below (git-ignored); re-run it after any change. repos: # `: `: code you change; bare store at repos/, default branch at worktrees// argos: https://github.com/Northeastern-Electric-Racing/Argos.git