# What this batch is for Pairing and the plugin catalog (notes 1–2) answered “who is allowed to talk to the live site” and “what may ever be installed.” This batch answers the other three kill-shots before any product UI exists: 3. Can we tell if the model actually did the WordPress thing? 4. Do we know which store holds the page (Gutenberg vs Elementor vs Classic)? 5. Can a 2GB site still show a preview in time if we refuse to copy the media library? If 3 is vibes, we will ship a confident liar. If 4 is wrong, we will edit `post_content` while Elementor renders JSON from post meta — the preview will not change and we will not know why. If 5 is a full copy, the five-minute product is dead on any real business site. None of this is the chat app. It is the measuring stick the chat app has to pass. ## 3 — Golden-task harness ### What it does It keeps twenty English requests, two fake but structured WordPress sites, and a scorer. A prompt is not “make it modern.” It is “change the homepage heading to Welcome to My Business.” The assertion is not “the model sounded sure.” It is: after the tool call is applied to the fixture, that string is in the page (or that option equals that value). Sites: - `gutenberg-business` — Twenty Twenty-Four, block markup, a dental practice. - `elementor-restaurant` — Hello Elementor, `_elementor_data` JSON, a trattoria. Ten prompts each. Mix of heading edits, text replace, `blogname` / `blogdescription` / `blog_public`, and two `screenshot` rows that today still assert on fixture text (see uncertainties). ### How it was implemented TDD first. Tests imported modules that did not exist. Vitest failed. Then: - `applyTool` mutates a `SiteFixture` (heading regex or Elementor `title`, string replace, option set). - `checkAssertion` reads the result. - `scoreGrokResponse` parses an xAI/OpenAI-shaped `tool_calls` payload, applies, asserts. - `run-golden.ts` scores the twenty expected traces and, if `XAI_API_KEY` is set, sends `gb-01` to `api.x.ai`. Proof on this machine: ``` pnpm test:e2e → 21 passed pnpm --filter @wursor/e2e golden → 20/20 fixture traces → live Grok skipped (no key) ``` ### Why this shape WordPress work is slot filling (`page`, `old`, `new`) plus a deterministic write. If we score free-form chat, Grok can narrate a heading change that never happened. If we only score “did the API return 200,” we learn nothing about the page. Applying the tool to a fixture is the smallest thing that can fail for the right reason. JSON sites instead of Docker WP because Docker was not available here; the assertion types stay valid when real sandboxes exist — swap `applyTool` for a REST/`wp post update` runner and keep `prompts.json`. Expected traces are an answer key for the *harness*, not a grade for Grok. A live grade is one HTTP call away. That is deliberate: unit tests stay offline (TDD rule: no network in unit tests). ## 4 — Builder detect ### What it does Given theme, plugin slugs, post content, and post meta, it returns exactly one of: `elementor | beaver | divi | gutenberg | classic` That value is what `site-info` will send. Playbooks are required to branch on it. ### How it was implemented Same TDD file: six cases, one assertion each. Rules use **slug plus the meta key that builder actually writes**. Gutenberg is `