From 9c9f783f52d9da2045b35bee1a9471f312d604a2 Mon Sep 17 00:00:00 2001 From: DavidBabinec Date: Sat, 26 Sep 2026 14:08:01 +0200 Subject: [PATCH] chore(repo): track the agent run-and-test, maintain and release skills The skills existed only in one local checkout, so worktrees created for PR review never had them. The maintain skill now matches the repo standard of a dateless open version instead of an Unreleased heading. --- .claude/launch.json | 11 ++ .claude/skills/maintain/SKILL.md | 157 +++++++++++++++++++++++++ .claude/skills/release/SKILL.md | 78 +++++++++++++ .claude/skills/run-and-test/SKILL.md | 166 +++++++++++++++++++++++++++ .gitignore | 11 +- 5 files changed, 422 insertions(+), 1 deletion(-) create mode 100644 .claude/launch.json create mode 100644 .claude/skills/maintain/SKILL.md create mode 100644 .claude/skills/release/SKILL.md create mode 100644 .claude/skills/run-and-test/SKILL.md diff --git a/.claude/launch.json b/.claude/launch.json new file mode 100644 index 0000000..fb44573 --- /dev/null +++ b/.claude/launch.json @@ -0,0 +1,11 @@ +{ + "version": "0.0.1", + "configurations": [ + { + "name": "www", + "runtimeExecutable": "bun", + "runtimeArgs": ["run", "dev:www"], + "port": 5173 + } + ] +} diff --git a/.claude/skills/maintain/SKILL.md b/.claude/skills/maintain/SKILL.md new file mode 100644 index 0000000..4d4afe8 --- /dev/null +++ b/.claude/skills/maintain/SKILL.md @@ -0,0 +1,157 @@ +--- +name: maintain +description: What a change owes the core-framework repo before it is finished — which document to read before touching a given area, which document goes stale when you change it, how this repo's changelog works (Keep a Changelog headings, bracketed version numbers, never an `Unreleased` section: the open version is a bracketed number with no date, and an agent asks David which bump to open rather than guessing), and the registries that must stay in step: the ten files the version bump touches, the open-source boundary gate and its allowlist, the WordPress database version that is asserted in two places at once, and the generated third-party licence inventory. Use this skill when changing code in core-framework, when deciding whether a change is finished, when a change touches docs or the changelog, or when review-pr needs to know what this repo expects of a pull request. +--- + +# Maintaining core-framework + +What a change owes this repo. For how to run and verify anything here, see `run-and-test`. + +## Read before you touch it + +| Touching | Read first | +|---|---| +| Anything at all | `CLAUDE.md` — the rulebook, including the never-change constraints | +| Shared logic, preset shape, data flow | `docs.md` → *Architecture*, *Project Data* | +| Preset schema, validation | `packages/core/src/schema/preset.schema.ts`, `packages/core/src/functions/validatePreset.ts` | +| Colors, shades, tints | `CLAUDE.md` → *Never Change*; colour-system IDs are a builder-compatibility contract | +| WordPress persistence, REST | `docs.md` → *WordPress Plugin*; routes live under `core-framework/v2` | +| Plugin activation, upgrades, options | `packages/wp/wp/Config/Setup.php` — the only place retired licence options may be named | +| Bricks / Oxygen behaviour | `packages/builder-integrations`; it is built **into** the WP ZIP, not shipped separately | +| Figma sync, connection keys | `docs.md` → *Figma Plugin*; keys are secrets | +| Release, versioning, tagging | `RELEASING.md`, and this repo's `release` skill | +| Opening a pull request | `CONTRIBUTING.md`, plus the global `pull-requests` skill | + +There is no `docs/` tree yet — `docs/` currently holds only `assets/`. The root `docs.md`, `README.md`, `CONTRIBUTING.md`, and `RELEASING.md` carry that weight for now. If you find yourself wanting `docs/architecture.md`, that gap is known and tracked against `repo-standards`; note it, finish your work, and offer the tree as its own change. + +## Update in the same change + +**A doc that lies is worse than a missing one.** When your change makes one of these wrong, fix it in the same commit — not a follow-up, not a TODO. + +| You changed | Update | +|---|---| +| Boot, setup, or prerequisites for any package | `docs.md`, and `run-and-test` if the command or its traps changed | +| The verification commands | `CONTRIBUTING.md` → *Verification*, `docs.md`, and `run-and-test` | +| Package roles or where logic lives | `docs.md` → *Architecture*, `CLAUDE.md` → *Package Structure* | +| Preset shape, migrations, persisted data | `docs.md` → *Project Data* and *Compatibility Constraints* | +| Release flow, artifacts, or required secrets | `RELEASING.md`, and the `release` skill | +| Anything a user would notice | `CHANGELOG.md` — see below | + +If a change adds a case that a registry below tracks, register it in the same commit. + +## The changelog + +`CHANGELOG.md`, Keep a Changelog format. Versions are **bracketed** headings; released ones carry a date: + +```markdown +## [2.0.1] - 2026-08-18 + +### Fixed + +- Restored the Auto BEM class generator in the Bricks structure panel. 2.0.0 moved the + builder connector into the page footer while the generator still loaded in the head, so + the generator read an undefined connector, failed its own feature check, and never started. +``` + +Theme headings in use: `### Fixed`, `### Changed`, `### Added`. Match them; never introduce a second format. + +**Voice:** write for the person upgrading. Say what changed and what they must do about it. This repo's entries routinely explain the *cause* when it helps a user understand the blast radius — copy that. Never describe which files moved. + +### No `Unreleased` section + +**Never create or write into a section called `Unreleased`.** The top section is the version currently being accumulated, written as a bracketed version number with **no date**: + +```markdown +## [2.0.3] + +### Fixed + +- ... + +## [2.0.2] - 2026-08-28 +``` + +**The missing date is what marks it unreleased.** On release, `release` adds the date to that heading. Nothing else moves. + +Deciding where your entry goes: + +1. **Top heading is a version with no date** → add your entry there, under the matching theme heading (create the theme heading if it is missing). +2. **Top heading has a date** → everything is released, so your change opens a new version. **Ask David which bump it is** (patch, minor, major), describing the change so he can judge. Do not pick a number silently, and never fall back to an `Unreleased` heading. +3. **Unsure it earns an entry at all** → ask. A missing entry is easier to spot than a wrong one. + +When several open PRs each add an entry, the first to merge opens the version; later ones rebase onto it and add under the same heading. + +Entries are written per change. `release` only *verifies* they exist and closes the version with a date. If release is reconstructing entries from `git log`, the discipline has already failed here. + +**Earns an entry:** bug fixes a user could hit, new capabilities, behaviour changes, security fixes. +**Does not:** internal refactors, test-only changes, doc edits, invisible dependency bumps. + +## Registries that must stay in step + +These are the obligations most easily forgotten and most annoying to reconstruct. + +### 1. The version is pinned in ten files + +Source of truth is `APP_VERSION` in `packages/core/src/constants/version.ts`. **Never hand-edit the others** — run `bun run bump`, which updates all ten (`scripts/version-change.ts`): + +``` +packages/blocks/src/theme-toggle/block.json +packages/core/src/constants/version.ts +packages/figma/package.json +packages/gutenberg/package.json +packages/gutenberg/plugin.php +packages/wp/gutenberg-blocks/theme-toggle/block.json +packages/wp/core-framework.php +packages/wp/package.json +packages/wp/readme.txt ← WordPress.org "Stable tag" +packages/www/package.json +``` + +The release builders **reject** a tag whose version does not match every one of these. + +### 2. The open-source boundary gate + +`bun run check:open-source` (`scripts/check-open-source-boundaries.ts`) is an **architecture test, not a lint**. It fails the build on forbidden strings in `packages/{core,figma,wp,www}/src`, `packages/wp/wp`, and — in CI — the built `packages/figma/dist` and `packages/wp/dist`: + +| Forbidden | Why | +|---|---| +| `x-api-key` | no client-side credential for the public preset importer | +| `picsum.photos` | no remote placeholder images | +| the remote Inter `fonts.googleapis.com` URL | the UI font is bundled, not fetched | +| `Version 1.0.1` | stale Figma version copy | +| `_license_key`, `free_license` | retired commercial options, **allowed only** in `packages/wp/wp/Config/Setup.php`, the deletion-only migration | + +**Never weaken this gate to make a diff pass.** If your change legitimately moves the boundary, update the check in the same change and explain why in the PR. Note it can fail on *built output* that looks clean in source. + +### 3. The WordPress database version is asserted in two places + +`CORE_FRAMEWORK_DB_VER` is defined in `packages/wp/core-framework.php:42` (currently `1.3`) and read through `packages/wp/wp/Config/Setup.php`. **`scripts/test-wp-e2e.sh` asserts the literal value** (`core_framework_db_version` == `1.3`). Bump one without the other and the E2E fails in CI, not locally. + +Stored data is not disposable: schema changes ship as new, additive, non-destructive migrations, and no change may require dropping or recreating a table. Live sites upgrade from 1.10.4 and earlier through this path. + +### 4. Generated licence inventory + +`THIRD_PARTY_NOTICES.md` and the per-artifact `third-party-licenses.txt` are generated (`scripts/generate-third-party-licenses.ts`) during the release build. Adding or removing a production dependency changes them. Do not hand-edit; explain any generated-file change in the PR, as `CONTRIBUTING.md` requires. + +### 5. The E2E assertions are a registry too + +`scripts/test-wp-e2e.sh` hard-codes expectations about activation, options, REST behaviour, CORS headers, and bundled fonts. If your change legitimately alters one of those, update the assertion in the same commit and say why. + +## Never change without a migration + +From `CLAUDE.md` and `docs.md`, because breaking these breaks live sites and builder sync: + +- **Colour-system IDs** — Bricks and Oxygen synchronise on them. +- **Shade, tint, spacing, and typography generation** — must stay deterministic. +- **The app version and migrations** when the persisted preset shape changes. + +Code has no such constraint: rename freely, delete dead code, fix bad abstractions in place. Do not add compatibility shims for internal APIs nobody has published against. + +## Done means + +1. The code works and you have **watched it work** — for the web app, in the agent browser, as a user (`run-and-test`). +2. The gate passes with exit codes you actually read, scaled to what the change touches. +3. Every doc describing what you changed is updated in the same change. +4. A changelog entry exists if a user would notice — filed under the open, dateless version heading. If the top heading is dated, ask David which bump to open; never create `Unreleased`. +5. Every registry above that your change touches has been updated. +6. Anything you could not verify is stated plainly. Bricks, Oxygen, and Figma-in-Figma have **no automated coverage** — if you changed them and did not open the editor, say so. diff --git a/.claude/skills/release/SKILL.md b/.claude/skills/release/SKILL.md new file mode 100644 index 0000000..1912931 --- /dev/null +++ b/.claude/skills/release/SKILL.md @@ -0,0 +1,78 @@ +--- +name: release +description: How core-framework ships, and the agent's operating procedure around it. Covers the three distinct release paths — the WordPress plugin (tag-driven, deployed to WordPress.org over SVN), the Figma plugin (packaged by the same tag but published to Figma Community by hand), and the web app (a static bundle this repo does not deploy at all) — plus what must be true on main first, which single version constant drives all ten pinned files, what the tag workflow does automatically, and which steps are irreversible and therefore need David's explicit go-ahead. Use this skill when cutting a release in core-framework, when preparing main for one, when a tag or publish is being considered, or when working out whether a change has actually shipped. +--- + +# Releasing core-framework + +**`RELEASING.md` is the source of truth.** Read it before acting; this skill is the agent's operating procedure around it, not a copy. + +> **Cutting a release is David's decision, never inferred.** Do not bump, tag, or publish because a change looks finished, because CI is green, or because the changelog has entries. Ask. + +## Three release paths, one tag + +They share a version and a trigger but end in different places on different cadences. Never merge them into one narrative — the wrong one gets run. + +| Artifact | Trigger | Destination | Automated? | +|---|---|---|---| +| **WordPress plugin** | push tag `v*.*.*` | WordPress.org (SVN) + GitHub Release | fully | +| **Figma plugin** | push tag `v*.*.*` | GitHub Release ZIP only | packaging only | +| **Web app** (`www`) | — | static `packages/www/dist` | **not deployed by this repo** | + +**The web app has no release path here.** No workflow builds or deploys it; `README.md:210` describes it as a static bundle to serve from any host. Hosting lives outside the repository, so "released" for www means whatever the external host does. Do not claim a www change has shipped on the strength of a tag. + +**Figma Community publishing is manual and separate.** The tag packages `core-framework-figma-X.Y.Z.zip` and attaches it to the GitHub Release, but does not touch Figma Community. That is a maintainer action through Figma Desktop (`RELEASING.md` → *Figma Community publishing*). A tagged release therefore leaves Figma Community users on the old version until David publishes. Say so rather than implying the release is complete. + +## Before a tag: what must be true on main + +1. **On `main`, clean tree, CI green.** `scripts/release.ts` enforces branch and cleanliness and stops otherwise. +2. **Version bumped via `bun run bump`.** One constant, `APP_VERSION` in `packages/core/src/constants/version.ts`, drives ten pinned files — see `maintain` → *Registries*. The release builders reject a tag that does not match all of them, including `packages/wp/readme.txt`'s WordPress.org stable tag. +3. **Changelog closed.** Per `maintain`, entries are written per change, so release only *verifies*. Confirm every PR merged since the last tag is either present or justifiably absent, then close the open version by **adding its date** to the existing dateless heading. Nothing else moves. If you are authoring entries from `git log` at this point, the discipline failed upstream — say so. +4. **The gate passes.** See `run-and-test`. Docker must be running for `e2e:wp`. + +## Cutting it + +The helper does the whole sequence and stops for confirmation before anything irreversible: + +```bash +bun run release +``` + +`scripts/release.ts` checks branch and cleanliness, resolves the version, refuses if the tag already exists, then runs `test:www`, a Composer install, PHPUnit, `release:wp`, and `release:figma` — and **only then** asks before creating and pushing the tag. If you decline, the built ZIPs remain in `.tmp/release/`. + +The manual equivalent is in `RELEASING.md` → *Manual tag flow*. + +## What the tag workflow does on its own + +`.github/workflows/release.yml`, on `v*.*.*`: + +- **verify** — audits JS and PHP dependencies, runs the web and PHP tests, lints PHP syntax, builds www/figma/wp, checks the production Vite manifest exists, and runs `check:open-source` +- **package** — builds both release ZIPs at the tag's version and **runs the full WordPress E2E against the actual ZIP being shipped** +- **publish** — deploys to WordPress.org over SVN via the `wordpress-org` environment, creates the GitHub Release if missing, and uploads both ZIPs + +It never deletes or rewrites an existing WordPress.org tag. + +Requires the protected `wordpress-org` environment with `SVN_USERNAME` and `SVN_PASSWORD`. The GitHub Release uses the built-in `GITHUB_TOKEN`. + +## Irreversible — get David's explicit go-ahead + +Ask before each, and never batch them into one approval: + +- **Pushing the tag.** It starts the whole chain, including the WordPress.org deploy. Deleting a tag afterwards does not un-publish anything. +- **The WordPress.org SVN deploy.** Public and effectively permanent; the workflow will not rewrite an existing tag, so a mistake ships as a new version. +- **Publishing to Figma Community.** Reaches every installed user through Figma's own channel. + +Reverting means shipping a *new, higher* version. Plan accordingly. + +## Ordering + +- The tag must exist and its artifacts must be built before anything is published — the workflow enforces this with `verify → package → publish`. +- **A security fix must not be described publicly before the fixed artifact exists.** Let the release complete, then publish the advisory. `SECURITY.md` covers private reporting. +- Publish to Figma Community only after the GitHub Release carries the matching Figma ZIP, so the manifest ID and the artifact agree. + +## Verifying a release actually landed + +- WordPress.org shows the new stable tag, matching `packages/wp/readme.txt`. +- The GitHub Release carries **both** `core-framework-X.Y.Z.zip` and `core-framework-figma-X.Y.Z.zip`. +- The `publish` job succeeded — a green `verify` alone means nothing shipped. +- Figma Community still shows the old version until David publishes by hand. Report that as outstanding, not done. diff --git a/.claude/skills/run-and-test/SKILL.md b/.claude/skills/run-and-test/SKILL.md new file mode 100644 index 0000000..dbb44bb --- /dev/null +++ b/.claude/skills/run-and-test/SKILL.md @@ -0,0 +1,166 @@ +--- +name: run-and-test +description: How to boot, drive, and test every deliverable in the core-framework monorepo — the web app (www), the WordPress plugin (wp), and the Figma plugin (figma), plus the three integration bundles that ship inside the WordPress ZIP. Covers the exact commands and ports, the first-run onboarding wizard that blocks a clean browser profile, the rule that www is verified live through the agent browser rather than by an automated browser suite, the Docker-backed WordPress end-to-end harness and what it already asserts, the composer-install trap that makes the PHP tests look broken, worktree setup, the full verification gate with exit codes read directly, and the known traps that make a green run misleading. Use this skill before running or testing anything in core-framework, when review-pr needs to know how to boot the project, when a change needs verifying, or when setting up a worktree here. +--- + +# Running and testing core-framework + +A bun workspace that ships **three products** from one shared core. Work out which one your change touches before running anything — the commands, the tests, and the proof differ completely. + +| Deliverable | Package | Boot | Test | Verified live by | +|---|---|---|---|---| +| Web app | `packages/www` | `bun run dev:www` | `bun run test:www` | **agent browser, as a user** | +| WordPress plugin | `packages/wp` | `bun run dev:wp` | `bun run php-test:wp`, `bun run e2e:wp` | `e2e:wp` (Docker) | +| Figma plugin | `packages/figma` | `bun run dev:figma` | `bun run --filter './packages/figma' test` | Figma Desktop, by hand | + +`packages/core` holds nearly all the logic and has no boot or test of its own — it is exercised through `test:www`. `packages/gutenberg`, `packages/blocks`, and `packages/builder-integrations` are **not** separate products: `scripts/build-wp-release.ts:81-83` builds all three into the WordPress ZIP. + +Package manager is **bun** (`packageManager: bun@1.3.11`, `engines.bun: >=1.3.0 <1.4.0`). A `preinstall` hook hard-blocks npm and yarn. There is a stray `pnpm-workspace.yaml`; ignore it, bun's `workspaces` field in the root `package.json` is what is real. + +## Live verification is done through the agent browser + +**For anything user-visible in the web app, drive it in the browser yourself and look at it.** Not a headless script, not an assertion count — open it, click it, read it. This repo deliberately has no automated browser suite for www, and adding one is not the fix for a change you have not looked at. + +``` +preview_start {name: "www"} # .claude/launch.json declares this, port 5173 +read_page # structure and refs — prefer this over screenshot for text +computer {action: "screenshot"} # what it actually looks like +read_console_messages # errors the UI swallows +``` + +Then send David a screenshot as evidence. Never ask him to check something manually. + +### The onboarding wizard will block you + +`packages/www/src/App.tsx` opens a two-step onboarding wizard whenever storage holds no valid preset, so **a clean browser profile lands on the wizard, not the editor**: + +1. *"How do you wish to start?"* — Core Framework / Variables only / Empty → **Continue** +2. *"Set up your basic preferences"* — root font size, dark mode → **Finish** + +Source: `packages/www/src/components/Onboarding.tsx`. + +**Finishing the wizard does not persist anything.** Reload and it comes straight back. `localStorage.current_framework` is written only by the explicit save/push (`packages/www/src/hooks/usePush.ts:246`) — the UI nudges you with *"Please, save changes to apply."* So: + +- To reach the editor: click through the wizard (two clicks), or press **Save changes** once to persist. +- To reproduce a first-run bug: use a fresh origin or clear `localStorage.current_framework`. +- Don't read an empty `localStorage` as broken storage. It is the documented state until the first save. + +### Ports drift, so confirm the one you are on + +Vite **silently moves to the next free port** — with 5173 busy it takes 5174 without failing. Two checkouts and a worktree can each be serving a different build. Read the port out of the dev server's own output and drive that one; never assume 5173. `preview_start` returns the port it actually bound. + +## packages/www — the web app + +```bash +bun run dev:www +``` + +Vite 6 on :5173. No account, no database, no seed, no external service — projects live in browser storage. Boots straight to the editor once a preset is saved (880 selectors / 126 variables in the default preset). + +```bash +bun run test:www +``` + +Jest with coverage, 23 suites / 147 tests, about 4s. This is the **only** automated coverage for `packages/core`, so a change to shared logic is tested here even when the change is for WordPress. + +Build is `tsc && vite build` — the type-check is part of the build, so a change that runs in dev can still fail `build:www`. + +## packages/wp — the WordPress plugin + +### PHP tests, and the trap that makes them look broken + +```bash +cd packages/wp && composer install # or: bun run composer:dev +bun run php-test:wp +``` + +**Run `composer install` first.** `bun run composer:prod` installs `--no-dev`, which leaves `packages/wp/vendor/` without phpunit, and `php-test:wp` then dies with `no such file or directory: ./vendor/bin/phpunit`. That is a missing dev dependency, not a broken test suite. With dev deps installed: 28 tests, 52 assertions. + +### The end-to-end harness + +```bash +bun run e2e:wp # builds the release ZIP, then tests it in disposable Docker +``` + +**Requires Docker running.** It builds the real release ZIP and installs it into a throwaway WordPress + MariaDB pair via wp-cli, on a random free port, tearing everything down on exit (`scripts/test-wp-e2e.sh`). It takes a few minutes. It runs on every PR in CI, and again inside the tag release workflow against the exact artifact being shipped. + +This is a genuinely strong harness — **adopt it, do not replace it.** It already asserts: + +- the plugin activates, at the expected version, with `core_framework_db_version` at `1.3` +- the `wp_core_framework_presets` table is created +- the generated stylesheet is written to uploads on activation +- REST routes reject a request with no nonce +- the Figma connection-key lifecycle: create → use → delete +- the CORS preflight allows Figma's `null` origin and the `X-Core-Framework-Key` header +- the editor CSS bundles `@font-face`/Inter Variable and makes **no** remote Google Fonts request +- deactivate → reactivate survives, the front end and REST index still respond +- retired commercial licence options are removed +- `debug.log` contains no fatal, parse, or uncaught error + +To test a ZIP you already built, pass it: `bash scripts/test-wp-e2e.sh path/to.zip`. + +### The dev server + +```bash +bun run dev:wp # builds builder integrations first, then vite +``` + +**Not verified during onboarding — it needs a real local WordPress.** Per `docs.md` it requires: a symlink from `packages/wp` into `wp-content/plugins/core-framework`, `packages/wp/.env` copied from `.env.example` and pointed at the local site (`DEV_PROTOCOL`, `DEV_URL`, `CERT_PATH`), HTTPS certificates, and `bun run composer:dev`. `dev`/`start` also rewrites `.env` to `development` via `env:dev`, and `build` rewrites it to `production` — so **the build mutates a tracked-adjacent file**; do not commit the flip. + +If a change touches Bricks, Oxygen, or Gutenberg behaviour, verify it in that editor. `e2e:wp` does not open a builder. + +## packages/figma — the Figma plugin + +```bash +bun run --filter './packages/figma' test # bun test, 7 tests, instant +bun run dev:figma # watch build +``` + +Then import `packages/figma/manifest.json` through **Figma → Plugins → Development → Import plugin from manifest**. **Not verified during onboarding** — it needs Figma Desktop, so there is no automated coverage of the plugin inside Figma. The two test files cover frame messaging and the WordPress connection only. + +## Worktrees + +Worktrees live at `/.worktrees/` (see the global `worktrees` skill). `.worktrees/` is gitignored. + +```bash +git worktree add -f --detach .worktrees/ origin/main +cd .worktrees/ +bun install --frozen-lockfile +``` + +**`bun install` is the only setup a worktree needs.** About 7s with a warm bun cache, 3690 packages. Verified from a clean worktree: `dev:www` boots and reaches the editor, `test:www` passes 147/147, and the full `e2e:wp` passes — `e2e:wp` needs no `.env` because it builds a release ZIP and runs it in Docker. + +You only need to copy `packages/wp/.env` (gitignored) if you intend to run `dev:wp` against a local WordPress from the worktree. + +## The verification gate + +Run this **once, at the end**, not after every edit. Capture exit codes directly — piping into `tail` or `grep` reports the pipe's status and will show green over a failed build. + +```bash +bun run test:www > /tmp/t.log 2>&1; echo "TEST=$?" +bun run build:www > /tmp/bw.log 2>&1; echo "BUILD_WWW=$?" +bun run build:wp > /tmp/bp.log 2>&1; echo "BUILD_WP=$?" +bun run build:figma > /tmp/bf.log 2>&1; echo "BUILD_FIGMA=$?" +bun run check:open-source > /tmp/os.log 2>&1; echo "BOUNDARIES=$?" +``` + +With Composer dev dependencies installed, and Docker running for the last one: + +```bash +bun run php-test:wp > /tmp/php.log 2>&1; echo "PHP=$?" +bun run e2e:wp > /tmp/e2e.log 2>&1; echo "E2E=$?" +``` + +Scale it to the change: a www-only change does not need `e2e:wp`; anything touching `packages/core`, `packages/wp`, or the release scripts does. + +`bun run check:open-source` is an **architecture gate**, not a lint — see `maintain` for what it forbids and why. CI runs it on the built `wp` and `figma` bundles too, so it can fail on output that looks fine in source. + +## Traps that make a run misleading + +- **`bun run lint` rewrites your files.** Both packages run `biome check --write --unsafe`. It is a formatter-with-fixes, not a read-only check; run it deliberately and read the resulting diff. `bun run format` (prettier over every package) also writes. +- **`build:wp` rewrites `packages/wp/.env` to `production`** (via `env:prod`), and `dev:wp`/`start` rewrites it back to `development` (via `env:dev`). An unexpected `.env` diff is usually this, not your change. Note `release:wp` and `e2e:wp` do **not** touch the file — they pass `APP_ENV` as an environment variable instead (`scripts/build-wp-release.ts:85-86`), so a stale `production` in `.env` came from a previous `build:wp`, not from the release path. +- **`e2e:wp` fails fast and loudly without Docker** — "Docker is required for the WordPress end-to-end test." That is an environment problem, not a regression. +- **The type-check lives in the build**, not in the tests. `test:www` passing tells you nothing about types. +- **`test:www` is the only coverage for `packages/core`.** A green WordPress PHP suite says nothing about shared logic. +- **A passing `e2e:wp` does not exercise any builder UI.** Bricks and Oxygen behaviour is unverified by every automated check in this repo. +- Vite's silent port increment (above) — the most common way to verify the wrong build. diff --git a/.gitignore b/.gitignore index c5eed7e..efd04f0 100644 --- a/.gitignore +++ b/.gitignore @@ -54,5 +54,14 @@ composer.lock # Claude-related files CLAUDE.sessions.md -.claude/ +.claude/* +!.claude/skills/ +.claude/skills/* +!.claude/skills/run-and-test/ +!.claude/skills/maintain/ +!.claude/skills/release/ +!.claude/launch.json sessions/ + +# Worktrees +.worktrees/