pcbjam/CLAUDE.md

31 lines
3 KiB
Markdown
Raw Normal View History

The goal is to build kicad with wasm and run it in a browser
2026-01-05 11:18:44 +01:00
README.md details how to run the project
A lot of native module have to be compiled to wasm, the most complex is wxwidgets
/kicad and /wxwidgets are git submodules from our own forks
The e2e tests are in /tests, with a README and WHATWORKS md files
test(determinism): deterministic waits + stableShot screenshots; drop blind sleeps/ifs/retries Make the Playwright e2e + kicad suites deterministic so screenshot flake stops tracing to timing races. - Blind page.waitForTimeout -> condition waits (expect.poll, web-first assertions, waitUntil) + readiness helpers (waitForWxApp, waitForCanvasApp). Remaining sleeps are documented interaction dwells (annotated). - Defensive "if element exists" branches -> loud asserts; label-fallback chains -> normalized clickMenuItemByText. First-run wizard for/if loops removed by seeding calculator/gerbview/pcbnew HTMLs. - Screenshots: new stableShot(page, name) settles the render in-page (canvas hash over rAF) then writes a raw PNG to test-results/ for the existing offline gate (tools/screenshots vs baseline-screenshots). Replaces toHaveScreenshot, which did inline compare + its own baselines and had decoupled the specs from the real gate. scale:'css' pinned. - retries: 0 in both configs. - Guard: tests/tools/lint-determinism.ts (npm run lint:determinism) bans blind sleeps / toHaveScreenshot / inline retries / swallowed catches in specs; documented exceptions carry a marker. Rules in tests/TESTING.md. Assertions, coverage, and renders unchanged (semantic-equivalence reviewed; captures pixel-identical modulo inherent timer/timestamp/3d-raytrace variance). Both suites green at retries:0 (e2e 340, kicad 92); ~35-61% faster. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BVX1pHMvRPYHdp6ZfEawrk
2026-07-07 10:50:24 +02:00
Test determinism rules (no blind sleeps/ifs, `stableShot` screenshots, retries:0) are in tests/TESTING.md, enforced by `npm run lint:determinism`.
The e2e tests are separated per feature
Wxwidgets wasm port has hooks for finding positions of UI elements, tests use that
e2e/CI: dual-engine suites, per-engine screenshots, SwiftShader retired, prod web suite, CI-coverage gate Squash of experiment/ff-big-modules vs main. Big-module routing removed: native-EH shrank kicad_editor below SpiderMonkey's x86-64 code budget (runs 29355049705/29356152413 green on stock Firefox), so BIG_MODULE_SPECS routing and the baseline-only-JIT crutch are gone — kicad-firefox and kicad-chromium both run the full suite, with the module compiled the way real users' browsers compile it. Per-engine screenshots end to end: stableShot/shotPath write test-results/<engine>/<name>.png; baselines move to baseline-screenshots/{chromium,firefox}/ and the whole tools/screenshots pipeline (compare/promote/manifest/spec-map/changelog/Discord) keys on <engine>/<name>. Previously Firefox and Chromium renders of one spec overwrote each other and Firefox renders were never actually gated. Seeded from CI run 29421380806 (92 new firefox baselines, +24 chromium web-suite shots); manifest generated from the baseline tree. One merged playwright.config.ts (kicad/asyncify/coroutine/perf as projects); ~25 dead npm scripts dropped. The web suite is gated in CI for the first time ever (4 rotted specs fixed, 5 broken lib-bridge specs triaged as fixme in docs/features/web-e2e-rot/); cheap lint step after npm ci; last 26 blind-sleep violations fixed. SwiftShader retired: CI Chromium renders WebGL on ANGLE → Mesa llvmpipe (--use-gl=angle --use-angle=gl --ignore-gpu-blocklist; the blocklist flag is mandatory — llvmpipe is blocklisted and WebGL is silently unavailable without it) in BOTH configs. Under WORKERS=4 congestion SwiftShader transiently failed the first post-board-load draw and the recovery cascade ended in a silent permanent Cairo fallback — that engine flip was the "~1.2% changedRatio both directions" occ-export baseline flake. Validated 160/160 across two 80-repeat rigs; full analysis in docs/features/wx-parity-bugs/occ-export-context-eviction.md. Chromium baselines shift slightly on llvmpipe — promote once from the first green run. Deflakes the new coverage exposed: presence baselines settle before capture; presence fixtures declare current file formats; perf gets its own outputDir so CI evidence survives; occ-export settles the board paint before the export dialog; menu-item waits (waitForRenderedByLabel before clickMenuItem) in 4 specs + the TESTING.md rule. Web suite runs the PROD build, in parallel: webServer becomes backend `start` + the standalone's e2e:preview (build-preview.mjs: link-wasm → stash the public/wasm symlink aside during vite build, build-demo.mjs's move — then vite preview as the persistent server). The wasm middleware serves /wasm/* in preview and emits COOP/COEP/CORP itself (a pthread worker script's own response must carry COEP or Chrome kills it with ERR_BLOCKED_BY_RESPONSE). VITE_* flags bake at build time; VITE_ALLOW_USER_OVERRIDE joins turbo globalEnv. fullyParallel + default workers: 5.2m → 1.4m. Determinism fixes the parallel run exposed: shared-page specs become serial groups; locks.spec grabs alice's exact item via the new kicadCollabTestSelectByUuid hook (cross-tab "first footprint" order is not a ysync invariant); quit specs poll page.url() (quit supersedes its own navigation — NS_BINDING_ABORTED on Firefox). Suite: 51 passed / 12 skipped / 0 failed in 1.6m. CI-coverage gate (lint:ci-coverage): every tests/**/*.spec.ts must be reachable from the npm scripts the workflows invoke — scraped from .github/workflows/, resolved through package.json, coverage asked from playwright --list itself. Rules: uncovered-spec + orphan-project (with a documented LOCAL_ONLY_PROJECTS allowlist). Gating next to lint:determinism; 138 spec files / 13 projects accounted for. Product fixes kept from the investigations (reachable on real GPUs too): wx 7799fd1be5 — paint flags clear before dispatch + Invalidate always propagates; kicad 3dcfea5e45 — SwiftShader pass-boundary flush + per-instance font texture + first-frame GL-error drain (GAL recovery recovers instead of falling back to Cairo) + the user-facing eeschema switch navigates again under __EMSCRIPTEN__ (project-sync's FaceRegistered gate had rerouted it into the hidden sync player; caught by the newly-gated web suite). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018eUxiPApHgGiu9NFyQfhAq
2026-07-17 12:10:40 +02:00
The test screenshots are tracked with git, per engine (tests/baseline-screenshots/{chromium,firefox}/); CI's Linux render is the source of truth (tooling: tests/tools/screenshots/, see its README).
feat(tests): screenshot regression + Discord review, perf-tracked New tooling in tests/tools/screenshots/ (TypeScript via tsx): - compare.ts: one pixelmatch engine (AA-excluded), connected-component "where to look" boxes, old|new+boxes|heatmap triptych, per-engine floors. - promote.ts: churn-free updater — overwrite a baseline only when decoded pixels differ beyond the floor, copying CI bytes verbatim (no re-encode churn); pulls a CI run via `gh run download` or a local --from dir. - post-discord.ts: always-on CI-on-main report (SHA + e2e status + the track-only runtime-perf table), then screenshot triptychs, batched + size-capped + flood-collapsed + 429-aware. - perf-report.ts: perf table with Δ vs the previous main run (via gh). - changelog.ts: no-build git-history baseline differ (Discord trigger B). - noise.ts / gen-manifest.ts: calibration + manifest generation. CI wiring: - wasm-build.yml: post-test step runs the gate + report on the already- produced test-results (no extra build); report-only (continue-on-error), posts only on push to main, inert without DISCORD_WEBHOOK_URL. - ci-ubicloud.yml: secrets: inherit (pass the webhook through). - screenshot-changelog.yml: ~30s no-build changelog on baseline changes. screenshot-manifest.json: canonical 354-name set + best-effort engine tags (313 chromium-swiftshader / 41 firefox-llvmpipe). Normalize scale:'device'->'css' across 18 spec files (no-op at CI DSF=1) so committed baselines are uniformly css-scaled. Design: CI's Linux render is the single source of truth; no pinned container (accept rare env drift -> re-promote); dev commits via promote. Replaces the byte-cmp compare-screenshots.sh + file-size-proxy update-baseline-screenshots.sh (kept for now until the first re-baseline). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-01 18:01:15 +02:00
To update baselines, promote a CI run's render (churn-free — only meaningfully-changed images restage): `cd tests && npm run screenshots:promote -- --run <ci-run-id>`, then commit. `npm run screenshots:check` is the local gate; on each main push CI posts a screenshot-diff + runtime-perf report to Discord.
The tests have log files in tests/logs/{wxwidgets/kicad}/{test-name} after each run where the js console and cpp logs are visible
Always check screenshots for validating tests
e2e/CI: dual-engine suites, per-engine screenshots, SwiftShader retired, prod web suite, CI-coverage gate Squash of experiment/ff-big-modules vs main. Big-module routing removed: native-EH shrank kicad_editor below SpiderMonkey's x86-64 code budget (runs 29355049705/29356152413 green on stock Firefox), so BIG_MODULE_SPECS routing and the baseline-only-JIT crutch are gone — kicad-firefox and kicad-chromium both run the full suite, with the module compiled the way real users' browsers compile it. Per-engine screenshots end to end: stableShot/shotPath write test-results/<engine>/<name>.png; baselines move to baseline-screenshots/{chromium,firefox}/ and the whole tools/screenshots pipeline (compare/promote/manifest/spec-map/changelog/Discord) keys on <engine>/<name>. Previously Firefox and Chromium renders of one spec overwrote each other and Firefox renders were never actually gated. Seeded from CI run 29421380806 (92 new firefox baselines, +24 chromium web-suite shots); manifest generated from the baseline tree. One merged playwright.config.ts (kicad/asyncify/coroutine/perf as projects); ~25 dead npm scripts dropped. The web suite is gated in CI for the first time ever (4 rotted specs fixed, 5 broken lib-bridge specs triaged as fixme in docs/features/web-e2e-rot/); cheap lint step after npm ci; last 26 blind-sleep violations fixed. SwiftShader retired: CI Chromium renders WebGL on ANGLE → Mesa llvmpipe (--use-gl=angle --use-angle=gl --ignore-gpu-blocklist; the blocklist flag is mandatory — llvmpipe is blocklisted and WebGL is silently unavailable without it) in BOTH configs. Under WORKERS=4 congestion SwiftShader transiently failed the first post-board-load draw and the recovery cascade ended in a silent permanent Cairo fallback — that engine flip was the "~1.2% changedRatio both directions" occ-export baseline flake. Validated 160/160 across two 80-repeat rigs; full analysis in docs/features/wx-parity-bugs/occ-export-context-eviction.md. Chromium baselines shift slightly on llvmpipe — promote once from the first green run. Deflakes the new coverage exposed: presence baselines settle before capture; presence fixtures declare current file formats; perf gets its own outputDir so CI evidence survives; occ-export settles the board paint before the export dialog; menu-item waits (waitForRenderedByLabel before clickMenuItem) in 4 specs + the TESTING.md rule. Web suite runs the PROD build, in parallel: webServer becomes backend `start` + the standalone's e2e:preview (build-preview.mjs: link-wasm → stash the public/wasm symlink aside during vite build, build-demo.mjs's move — then vite preview as the persistent server). The wasm middleware serves /wasm/* in preview and emits COOP/COEP/CORP itself (a pthread worker script's own response must carry COEP or Chrome kills it with ERR_BLOCKED_BY_RESPONSE). VITE_* flags bake at build time; VITE_ALLOW_USER_OVERRIDE joins turbo globalEnv. fullyParallel + default workers: 5.2m → 1.4m. Determinism fixes the parallel run exposed: shared-page specs become serial groups; locks.spec grabs alice's exact item via the new kicadCollabTestSelectByUuid hook (cross-tab "first footprint" order is not a ysync invariant); quit specs poll page.url() (quit supersedes its own navigation — NS_BINDING_ABORTED on Firefox). Suite: 51 passed / 12 skipped / 0 failed in 1.6m. CI-coverage gate (lint:ci-coverage): every tests/**/*.spec.ts must be reachable from the npm scripts the workflows invoke — scraped from .github/workflows/, resolved through package.json, coverage asked from playwright --list itself. Rules: uncovered-spec + orphan-project (with a documented LOCAL_ONLY_PROJECTS allowlist). Gating next to lint:determinism; 138 spec files / 13 projects accounted for. Product fixes kept from the investigations (reachable on real GPUs too): wx 7799fd1be5 — paint flags clear before dispatch + Invalidate always propagates; kicad 3dcfea5e45 — SwiftShader pass-boundary flush + per-instance font texture + first-frame GL-error drain (GAL recovery recovers instead of falling back to Cairo) + the user-facing eeschema switch navigates again under __EMSCRIPTEN__ (project-sync's FaceRegistered gate had rerouted it into the hidden sync player; caught by the newly-gated web suite). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018eUxiPApHgGiu9NFyQfhAq
2026-07-17 12:10:40 +02:00
Run e2e tests from /tests folder: `npm run test:e2e` (full CI project set, one merged playwright.config.ts) or `npm run test:kicad` (firefox shortcut) — not playwright directly. One spec/engine: `npx playwright test --project=kicad-firefox kicad/pcbnew.spec.ts`. Web-app suite: `npm run test:web`.
Build kicad with docker/build.sh (includes wxwidgets build, runs in docker)
refactor: collapse dual-mode plumbing — the DOM port is the only WASM build The canvas (wxUniversal) mode is gone (wxwidgets submodule); remove every piece of side-by-side plumbing so there is exactly one build and one test flow: - scripts/build-wxuniversal-wasm.sh -> scripts/build-wx-wasm.sh; no --dom/--enable-universal; builds into build-wasm/wxwidgets - build-wasm-test.sh: no DOM_BUILD / apps-dom rsync mirror / PORT=dom; apps build straight into tests/apps (Makefile.wasm PORT conditionals collapsed; wx.js + wx-dom.js always pre-js) - docker/build.sh, build-kicad-target.sh, env.sh: WX_PORT / -dom / -universal suffixes removed; kicad builds to kicad-<app>, outputs to output/; wx.js/wx-dom.js copied from the real source path (/workspace/wxwidgets/build/wasm — the old build-wasm path never existed and silently failed) - setup-kicad-wasm.sh: single target dir; the perl wx-dom.js injection is gone — the 7 checked-in kicad pages now reference wx-dom.js directly - playwright configs serve apps/; fixtures drop the test-results/dom and logs/wxwidgets/dom namespacing; boot.spec asserts wxDomPort unconditionally; pcbnew.spec uses one reference image; appearance.spec assertions unconditional - compare/update-baseline-screenshots.sh: --port removed - tests/gal-regression/wasm/Makefile: links build-wasm/wxwidgets and carries wx-dom.js as a second pre-js — the gal-webgl suite (30 specs) now actually builds and runs here (it needed host-side boost+glm via scripts/deps; the bundle had been missing, timing the whole spec out) - tests: clickCanvas() dispatches via page.mouse (DOM widgets legitimately cover the canvas; locator actionability refused the click); the comprehensive spec drives wxChoice through its native <select> (browser-owned popup cannot be coordinate-clicked) - docs: README/CLAUDE.md/build.md script names and dirs; features/wx-dom-port README reframed (DOM is THE port), visual-notes bugs 26-28; FindwxWidgets.cmake config label drops 'wasmuniv' - wxwidgets submodule -> 9dbacc9448 (DOM-only port, fork diff shrunk) Gate: full wx e2e suite 292 passed / 1 skipped / 0 failed — first run ever with the gal-webgl specs green (28 scenarios + load + sequential). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-12 10:18:16 +02:00
Build wxwidgets standalone with scripts/build-wx-wasm.sh (runs on machine, for wxwidgets-only changes)
Build CPP wxwidgets tests with scripts/builds-wasm-test.sh
The build scripts pipe their outputs into log files so that they won't clog the LLM context.
Don't pipe outputs, just run the scripts. Maybe with flex if you need that.
Don't change the wxwidgets core unless absolutely necessary, try to fix things in the wasm layer.
Don't change kicad unless absolutely necessary - keep our fork as close to upstream as possible.
Run scripts/kicad-diff-stats.sh to see how far our KiCad fork has diverged from upstream.
It's okay to add temporary logging that will be removed for debugging.
Don't try to guess what's broken , use debug tools / symbols, supported by the build scripts
Feature docs/patches are in features/<branch-name>/. Run scripts/create-feature-patches.sh to save patches for root, kicad, wxwidgets submodules.
The landing page / website is in /site (Astro, built and deployed by Vercel on push). The footer shows a build SHA that links to the pcbjam commit the site was built from; because it pins the kicad + wxwidgets submodule revisions implicitly, it is our GPLv3 corresponding-source pointer (see /licenses). It resolves automatically at build time in site/src/components/Footer.astro (VERCEL_GIT_COMMIT_SHA on Vercel, `git rev-parse` locally) — no manual bump needed.