Files
WP-LIT-MCP/docs/superpowers/notes/2026-09-26-etappe-2b-praxistest.md
T
2026-09-26 22:18:23 +02:00

177 lines
13 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# WP-LIT-MCP Trial: „Tischlerei Holzwerk Berger“
Hands-on test of the LIT MCP server as a real MCP client would use it (`initialize` → `tools/list` →
`lit-guide` → build), against the local DDEV site `https://wordpress.ddev.site:8443` (Divi 5.2.1,
WordPress 7.1.2, Pods inactive). Site was "Breva Map Dev" before this trial. All calls went through
`tests/Integration/lib.sh`'s `connect`/`tool`/`ability` helpers, run inside the DDEV web container via
throwaway scripts under `.superpowers/trial/` (deleted at the end; git-excluded). Nothing published.
## What was built
All titled with the `[Test] ` prefix, all left as drafts, as requested.
| Type | ID | Title | Notes |
|---|---|---|---|
| Page | 839 | [Test] Startseite | Hero (heading+text+button+image), 3-Leistungen-Übersicht (blurbs), Kontakt-CTA |
| Page | 834 | [Test] Leistungen | Hero, 3 service blurbs, CTA section |
| Page | 837 | [Test] Über uns | Hero, Geschichte (image+text), 3 Werte (icon-lists; one duplicated to a 4th value) |
| Page | 831 | [Test] Kontakt | Hero, Adresse+Kontaktformular, Öffnungszeiten (added afterwards via `lit-divi-insert`) |
| Post | 854 | [Test] Drei Tipps zur Pflege von Massivholzmöbeln | |
| Post | 856 | [Test] Einblick in unsere Werkstatt | text+image |
| Post | 858 | [Test] Nachhaltigkeit beginnt beim Holz | |
| Menu | 22 | [Test] Hauptmenü | assigned to `primary-menu` location in the same `lit/menu-create` call; 4 items (Startseite, Leistungen, Über uns, Kontakt) via `lit/menu-set-items` with `allow_unpublished: true` |
| Media | 828, 829, 830 | Werkstatt / Team / Massivholzmöbel (Platzhalter) | imported via `lit-media-upload-from-url` from `picsum.photos` (public hotlink-friendly placeholder service — network egress from the container worked fine, no fallback to base64 needed) |
| Site settings | – | `blogname` → "Tischlerei Holzwerk Berger", `blogdescription` → "Massivholzmöbel, Innenausbau und Restaurierung aus Berlin" | previous values (`Breva Map Dev` / empty) are in the tool's own `previous` response field if this needs reverting |
Front page: **not set**. `lit/wp-settings-update` correctly refused `page_on_front: 839` with
`"839 ist keine veröffentlichte Seite."` — consistent with the server's own "Neue Website aufsetzen"
workflow guide, which says to publish the homepage first. That step is fundamentally at odds with
"don't publish anything," so I left `show_on_front` on `posts` and flagged it here instead of guessing
which instruction should win.
Edits demonstrated with the Divi write tools (all on top of the pages above): a heading text change
(`lit-divi-update`/`set`), a whole new section inserted (`lit-divi-insert`), a module moved across
columns (`lit-divi-move`), a node duplicated and re-labelled (`lit/divi-duplicate-node`), and a
site-wide text fix via `lit/divi-replace-text` with a dry run first, then a confirmed run (see friction
log for what it was replacing).
## Chronological friction log
1. **Guide reading is thorough but not consolidated.** `lit-guide` overview lists 8 further topics
(`content-types`, `divi-attrs`, `divi-design-system`, `divi-placeholders`, `divi-shortform`,
`divi-structure`, `media`, `workflows`); getting the full picture before writing anything took 8
separate `lit-guide` calls. The content itself is excellent (dense, example-driven, in German
matching the server's own error/hint language) — no complaints about quality, only that there's no
single "give me everything" call for a first-time client that wants to front-load context once
rather than discover topics interactively.
2. **Contact-form field `type` collision (real friction, not just reading fatigue).** The
`divi-shortform` field table lists `contact-field`'s shortform fields as `title, id, type, required`
— but a paragraph *below* the table says `type` can't actually be set this way at insert time because
it collides with the node-schema key `type` (the module type). I read the table, used `type: "email"`
in a contact-field item, and got:
`"unbekanntes Modul \"divi/input\""` / `"divi/contact-form erlaubt nur divi/contact-field als Kind"`.
The error is technically correct (it really did try to parse `type` as a child module name) but it
doesn't say *why* — a reader has no way to connect "unknown module divi/input" back to the
already-read caveat about reserved field names. Fixed by omitting `type` on insert and setting it
afterwards with `lit-divi-update`'s `set` (which *is* documented and worked first try). **Suggestion:**
detect this specific case (a `contact-field`/`social-media-follow-network` item with a `type`/`label`
key that isn't a valid child module name) and return a dedicated hint, e.g. "`type` on a contact
field can't be set at insert — omit it here and set it afterwards with lit-divi-update, or use attrs
(fieldItem.advanced.type)."
3. **A section can't mix `rows` and `modules`.** Tried a section with a top-level `modules` (for a
heading) *and* `rows` (for the 3-column blurbs) — got `"divi[1]": "entweder rows oder modules
angeben"`. Fully actionable, fixed in one edit by wrapping the heading in its own single-column row.
Minor cost (one extra round trip), good error.
4. **No shortform way to link one page to another by ID.** Draft pages get an **empty** `post_name`
until published (confirmed via direct DB read — this is normal WordPress behaviour for
draft/pending posts, not a plugin bug), so there's no stable pretty permalink to put in a button's
`url` field yet. The placeholder table (`divi-placeholders`) only offers `{{post:url}}` etc. for the
*currently displayed* post, not a way to point at an arbitrary other post/page by ID. I fell back to
raw `/?page_id=<ID>` query links for the CTA/blurb/menu targets. That works for an admin/preview
session but is fragile (changes once published) and dead for anonymous visitors before publish.
**Suggestion:** a placeholder like `{{link:<post_id>}}` (or reusing the `related`/attachment-ID idiom
already used for images) that resolves through `get_permalink()` at render/save time — draft-safe now,
automatically correct after publishing. This would remove the single biggest gap between the
shortform and how a real multi-page site actually gets built.
5. **`contact-form`'s own title has no shortform heading-level control.** After building the Kontakt
page, `lit-page-render-summary` flagged `"2 Überschriften der Ebene h1 im Inhalt."` — the
contact-form module renders its `title` as a hard-coded `h1`, and unlike `heading`/`blurb` (which
both expose a `level` shortform field), `contact-form` has none. Fixed by falling back to the full
form: `lit-divi-catalog` with `module: "divi/contact-form"` to find the path, then
`attrs: {"title.decoration.font.font": {"desktop": {"value": {"headingLevel": "h2"}}}}` — which
worked and cleared the warning. This was the one case where the shortform genuinely wasn't
expressive enough for a normal homepage pattern (a contact form title next to a page's own h1).
**Suggestion:** add `level` to `contact-form`'s shortform fields (and check other title-bearing
modules — e.g. `cta`, `map`, `slider` — for the same gap) so this doesn't require discovering the
full-form path by trial and error.
6. **`preview_url` uses `http://`, `edit_url` uses `https://`, in the same response — bug.** Every
mutating tool response on this (https-only, port-8443) site shows this mismatch, e.g. the Kontakt
page creation returned
`"preview_url":"http://wordpress.ddev.site:8443/?page_id=831&preview=true"` next to
`"edit_url":"https://wordpress.ddev.site:8443/wp-admin/post.php?post=831&action=edit"`. See Bugs
below for repro.
7. **Positive: error messages throughout were excellent.** `validation_failed` always came with a
`fields` map keyed by the exact dotted input path (e.g. `divi[1].rows[0].modules[1][0].items[0].type`);
`rev_mismatch`, `confirm_required`, and `unsupported` (tried to overwrite a Divi page's `content` via
`lit-content-update`) all had a `hint` that named the exact next tool to call, and following it
worked first try every time — no case where the hint was misleading or where I had to guess.
8. **Positive: `tree_rev` chaining removed round trips.** Every Divi write response carries the fresh
`tree_rev`, so a sequence of edits on the same page (change heading → move a module → insert a
section) never needed an extra `lit-divi-outline` read in between. This is the detail I'd worry the
most about regressing — it's what makes multi-step page building on Divi tolerable turn-count-wise.
9. **`lit/menu-create` accepting `location` in the same call was a nice shortcut** (no separate
`lit/menu-assign-location` round trip needed for a fresh menu). The one remaining unavoidable extra
round trip in the menu flow was calling `lit/menu-get` immediately after `lit/menu-create` just to
obtain `menu_rev` for the following `lit/menu-set-items` — `lit/menu-create`'s own response could
include the initial `menu_rev` and save that call.
10. **`lit-divi-catalog`'s result envelope (`{modules: [...], notes: [...]}`) isn't shown anywhere** in
the tool description or the `divi-attrs`/`divi-shortform` guides (which do embed inline JSON
examples for almost everything else). Self-inflicted (my first `jq` filter assumed a bare array and
errored), but a one-line example would remove the ambiguity the same way the other guides do.
## Prioritized improvement suggestions
1. **(High)** Add an internal-link placeholder for Divi shortform/full-form URL fields that resolves an
arbitrary post/page ID to its current permalink (draft-safe), e.g. `{{link:<post_id>}}`. This is the
most concrete gap: right now there is no supported way to cross-link draft pages that survives
publishing, and `/?page_id=N` is the only fallback.
2. **(High)** Give the `contact-form` module's shortform a `level` field (matching `heading`/`blurb`),
and audit other title-bearing modules (`cta`, `map`, `slider`, …) for the same missing control —
this is exactly the kind of heading-hierarchy mistake `lit-page-render-summary` is built to catch,
but the shortform currently can't fix it without discovering a full-form attrs path.
3. **(Medium)** Fix the `http://` vs `https://` scheme mismatch between `preview_url` and `edit_url` in
write-tool responses (see Bugs).
4. **(Medium)** When a shortform field name collides with a node-schema key (`type` on contact-field
items, `label` on social-media-follow-network items — both already called out in prose in the
`divi-shortform` guide), have the resulting `validation_failed` error say so directly instead of
surfacing as "unknown module divi/<field-value>". The current message is technically accurate but
doesn't point back to the documented workaround.
5. **(Low)** Let `lit/menu-create`'s response include the new menu's initial `menu_rev`, so a
first-time `lit/menu-set-items` doesn't need a preceding `lit/menu-get` purely to fetch it.
6. **(Low)** Show a one-line example of `lit-divi-catalog`'s result shape (module list vs. single-module
detail) in its tool description or the `divi-attrs` guide, consistent with how other tools' guides
already embed inline JSON examples.
7. **(Nice-to-have)** Consider a `lit-guide` mode that returns all topics concatenated in one call for
first-connection priming, alongside the existing per-topic calls (which remain useful for targeted
lookups later in a session).
## Bugs (with repro)
**Bug: `preview_url` scheme mismatch (`http://` vs. the site's actual `https://`).**
- Repro: on this DDEV site (`https://wordpress.ddev.site:8443`, HTTPS-only), call any tool that returns
both URLs for a draft, e.g. `lit-content-create` for a page, or any `lit-divi-*` write. Example
(Kontakt page, ID 831): response includes
`"preview_url":"http://wordpress.ddev.site:8443/?page_id=831&preview=true"` while the same response's
`"edit_url":"https://wordpress.ddev.site:8443/wp-admin/post.php?post=831&action=edit"` is correctly
`https`.
- Impact: a client that opens `preview_url` as given may hit a mixed-content warning, an unwanted
http→https redirect, or fail outright depending on the site's HSTS/redirect configuration.
## Divi shortform expressiveness verdict
For a typical small-business homepage (hero, services grid, testimonials/values, contact form,
CTA, blog teaser text) the shortform covered essentially everything needed — `section`/`row`/`column`
nesting, `heading`, `text`, `button`, `image`, `blurb`, `cta`, `icon-list`, `contact-form`, placeholders
for the design system's colors — with only two genuine full-form fallbacks in this whole build: the
contact-form title heading level (§5 above), and (not really a fallback, just a two-step shortform
sequence) setting a contact-field's `type` after insert instead of at insert time. Column-width
changes, presets, and `$variable` placeholders were never needed for this content but are documented
clearly enough that I'd expect them to work the same way.
## Cleanup performed
- All 36 throwaway `lit-mcp-integration-test` application passwords created by repeated `connect()`
calls during this trial were removed via `cleanup_app_passwords_for` (verified count 36 → 0).
- `.superpowers/trial/` (the scratch scripts used to drive this session) was deleted from the container.
- No plugin source code was modified. No existing content (the 4 pre-existing pages, 1 existing post) was
touched. Nothing was published.