From 44f5c2a126ddf64dc6968d7f6c86730ee7efa5ef Mon Sep 17 00:00:00 2001 From: Sean O'Connor Date: Fri, 28 Aug 2026 11:02:27 -0600 Subject: [PATCH 1/2] docs: audit top-level guidance, fix stale app/README + add missing ci.md builtin (pst-brht) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - app/README.md: replace superseded manual lib-clone prereqs with scripts/vendor-libs.sh; drop stale '33 unit tests' count; point e2e waits at waitForRenderState (status-line text pattern no longer exists); ModelStudio -> DetailPage; real zero-param note text; add unit=/group=/short=/@preset to the @param grammar; remove unverifiable specifics (250ms debounce, 3.3GB OOM, 576 files) and stale Phase-N framing; drop the artifact-server section duplicated in CLAUDE.md. - docs/ci.md: list the presets invariant builtin (st-1j9) alongside the other built-ins. README.md, AGENTS.md, CLAUDE.md, libs/README.md audited and verified accurate โ€” no changes needed. ๐Ÿค– Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- app/README.md | 70 ++++++++++++++++++++++----------------------------- docs/ci.md | 3 +++ 2 files changed, 33 insertions(+), 40 deletions(-) diff --git a/app/README.md b/app/README.md index 52deafa..21e2cd7 100644 --- a/app/README.md +++ b/app/README.md @@ -1,32 +1,25 @@ # Stuff Web Next.js App Router frontend that exposes parametric OpenSCAD models with -a live in-browser WASM preview. Phase 3 ships the model gallery, dynamic -slug routing, and Vercel deploy config. +a live in-browser WASM preview: model gallery, dynamic slug routing, +presets, and Vercel deploy. ## Prereqs 1. Node 22+ 2. Vendored OpenSCAD libraries populated under `../libs/` (the WASM - include closure walker fetches them through `/api/source`): - - ```bash - cd libs - git clone https://github.com/BelfrySCAD/BOSL2.git BOSL2 - ( cd BOSL2 && git checkout 456fcd8 ) - git clone https://github.com/AndyLevesque/QuackWorks.git QuackWorks - ( cd QuackWorks && git checkout 6123129 ) - ``` - - Both pins match `libs/README.md`. BOSL2 is held back from HEAD because - newer commits break QuackWorks' vector-spin syntax (st-kls). + include closure walker fetches them through `/api/source`). + `bash scripts/vendor-libs.sh` clones and pins all of them; it also + runs as the npm `prebuild` hook, so `npm run build` and `npm run + test:e2e` do it for you. Pins and the BOSL2 hold-back rationale live + in [`../libs/README.md`](../libs/README.md). ## Run ```bash npm install npm run dev # http://localhost:3000 -npm test # vitest, 33 unit tests +npm test # vitest (unit) npm run build # production build ``` @@ -50,9 +43,10 @@ to override. 1. Drop a `tests/e2e/.spec.ts`. Playwright auto-discovers. 2. Hit pages via `page.goto("/models/โ€ฆ")` โ€” `baseURL` is already set. -3. Lean on the status-line text pattern (`/rendered in \d+ms ยท [\d,]+ bytes/`) - when you need to wait for a WASM render to complete โ€” it's the most - stable signal the coordinator exposes. +3. Wait for a render with `waitForRenderState(page, "ready")` from + `tests/e2e/support/render.ts` โ€” it keys on the viewer's + `data-render-state` attribute (the render lifecycle itself), not a + text pattern that future UI changes will outlive. 4. For anything that might vary by render (byte counts, bboxes), assert on deltas between two states, not absolute values โ€” keeps the test robust across OpenSCAD version bumps. @@ -73,9 +67,9 @@ retry, 2 workers). Add `--headed` to watch it run. ### Silent-override regression `tests/fixtures/bug_regression.scad` + `tests/e2e/bug-regression.spec.ts` -exist specifically to guard the Phase 1/2 silent-override bug: the +guard the original silent-override bug: the class where the form reports new values but the render sees old ones. -Test asserts the STL's X-extent shifts from 40mm (default) to 160mm +It asserts the STL's X-extent shifts from 40mm (default) to 160mm (override). If `applyParamOverrides` ever becomes a no-op, the override render produces a 40mm plate and the assertion fails with a numeric diff, not a timeout. @@ -83,7 +77,7 @@ numeric diff, not a timeout. Open . The gallery lists every `.scad` file in `models/` with a thumbnail, title, and parameter count. Click a card to land on `/models/`, twiddle a slider, and watch the in-browser -render swap in (~250ms debounce, then a few seconds for Manifold). +render swap in (a few seconds for a cold Manifold build). ## Architecture @@ -91,8 +85,9 @@ render swap in (~250ms debounce, then a few seconds for Manifold). emits a CSS grid of cards. - `app/models/[slug]/page.tsx` โ€” dynamic route with `generateStaticParams()` over every `.scad` file. Falls back to - notFound() on unknown slugs. Renders `` always; shows a - "parameters not yet annotated" note when `@param` count is zero. + notFound() on unknown slugs. Renders ``; the param rail + shows a "No parameters in this model." note when `@param` count is + zero. - `app/api/thumbnail/route.ts` โ€” serves `renders//top.png` with regex stem allowlist + path confinement; 403 on hostile slug, 404 on missing render. @@ -111,11 +106,10 @@ render swap in (~250ms debounce, then a few seconds for Manifold). `openscad-wasm-prebuilt` silently ignores `-D` flags and a prepended prelude gets clobbered by OpenSCAD's last-assignment-wins scoping. - `lib/wasm/closure.ts` โ€” BFS over `include`/`use` to collect the - minimal lib-file set (avoids the 60s mount of all 576 lib files seen - in Phase 0 spike). + minimal lib-file set (avoids mounting the whole `libs/` tree). - `lib/wasm/render.ts` โ€” lazy-loaded openscad-wasm-prebuilt instance, - mounts the closure under `/libraries/`, runs with - `--backend Manifold` (CGAL OOMs at 3.3GB on BOSL2; non-negotiable). + mounts the closure under `/libraries/`, runs with `--backend Manifold` + โ€” CGAL OOMs on BOSL2. ## `@param` annotation grammar @@ -124,12 +118,14 @@ render swap in (~250ms debounce, then a few seconds for Manifold). ``` Types: `number`, `integer`, `boolean`, `string`, `enum`. Numeric attrs: -`min=`, `max=`, `step=`. Enums require `choices=a|b|c`. See -`lib/scad-params/parse.test.ts` for the full surface. +`min=`, `max=`, `step=`. Enums require `choices=a|b|c`. Optional +display hints on any param: `unit=`, `group=`, `short=`. Presets are +`// @preset id="โ€ฆ" label="โ€ฆ" =` lines inside the same +block. See `lib/scad-params/parse.test.ts` for the full surface. A model file without any `@param` annotations still appears in the -gallery and renders at compile-time defaults; the model page shows a -"parameters not yet annotated" note in place of the form. +gallery and renders at compile-time defaults; the detail page shows a +"No parameters in this model." note in place of the form. ## Vercel deploy @@ -148,12 +144,6 @@ vercel deploy vercel deploy --prod ``` -No environment variables required for Phase 3. The `models/` and -`libs/` trees ship as part of the build because the API routes read -them from disk at request time (Fluid Compute, Node.js runtime). - -## Loopback artifact server - -`scripts/serve.py` is a stdlib HTTP browser for the rendered PNG + -exported STL artifacts on a headless print rig. Independent of this -Next.js app โ€” see top-level `CLAUDE.md` for usage. +No environment variables required. The `models/` and `libs/` trees +ship as part of the build because the API routes read them from disk +at request time (Node.js runtime). diff --git a/docs/ci.md b/docs/ci.md index dcfef07..b839464 100644 --- a/docs/ci.md +++ b/docs/ci.md @@ -208,6 +208,9 @@ Built-in invariants (every model, no opt-in): - **anchor bbox drift** โ€” if the `.scad` declares `PRINT_ANCHOR_BBOX = [x, y, z]`, the exported STL's bbox extents must match within ยฑ1 mm per axis. Catches silent size regressions. +- **presets** โ€” every `@preset` key must name a declared `@param` and + coerce to its kind (st-1j9). A bad preset would crash the TS parser + and break the webapp load, so it fails CI here instead of shipping. Sidecar conventions, the minimum skeleton, and the scaffold that generates them live in the `new-model` skill From 4805693098c5156f71c8b26fd33652fcdff8d02e Mon Sep 17 00:00:00 2001 From: Sean O'Connor Date: Fri, 28 Aug 2026 11:44:56 -0600 Subject: [PATCH 2/2] docs(app): fix three factual errors in README per codex review (pst-k3wg) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - prebuild hook runs for build only; state test:e2e needs a prior build or explicit vendor-libs run (no pretest hook exists) - @preset lines are scanned anywhere in the file, not 'inside the same block' (parser does a separate pass; tests cover outside-block) - drop short= from advertised display hints: pickBaseAttrs retains only label/group/unit and no model uses it ๐Ÿค– Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- app/README.md | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/app/README.md b/app/README.md index 21e2cd7..6781035 100644 --- a/app/README.md +++ b/app/README.md @@ -10,9 +10,10 @@ presets, and Vercel deploy. 2. Vendored OpenSCAD libraries populated under `../libs/` (the WASM include closure walker fetches them through `/api/source`). `bash scripts/vendor-libs.sh` clones and pins all of them; it also - runs as the npm `prebuild` hook, so `npm run build` and `npm run - test:e2e` do it for you. Pins and the BOSL2 hold-back rationale live - in [`../libs/README.md`](../libs/README.md). + runs as the npm `prebuild` hook, so `npm run build` does it for + you. `npm run test:e2e` does not vendor โ€” it assumes a prior + `npm run build` (or an explicit script run). Pins and the BOSL2 + hold-back rationale live in [`../libs/README.md`](../libs/README.md). ## Run @@ -119,9 +120,11 @@ render swap in (a few seconds for a cold Manifold build). Types: `number`, `integer`, `boolean`, `string`, `enum`. Numeric attrs: `min=`, `max=`, `step=`. Enums require `choices=a|b|c`. Optional -display hints on any param: `unit=`, `group=`, `short=`. Presets are -`// @preset id="โ€ฆ" label="โ€ฆ" =` lines inside the same -block. See `lib/scad-params/parse.test.ts` for the full surface. +display hints on any param: `unit=`, `group=`. Presets are +`// @preset id="โ€ฆ" label="โ€ฆ" =` lines; the parser scans +them anywhere in the file, with the convention of clustering them near +the parameter block. See `lib/scad-params/parse.test.ts` for the full +surface. A model file without any `@param` annotations still appears in the gallery and renders at compile-time defaults; the detail page shows a