# The truth about the FES inspector (audit 2026-07-27)

## What I claimed I'd built

A "world-class" FES inspector that should match Elementor/Bricks — with proper image pickers,
typography controls, color pickers, link pickers, background controls, etc.

## What actually got built

A 343-line `v2-inspector.js` with a list of 23 control NAMES that are mostly hallucinated.

## What's actually deployed (verified by md5 + content)

| Control | Size on disk | Real JS? |
|---------|-------------|----------|
| text/text.js | 1454 bytes | ✅ yes |
| color/color.js | 3-4KB | ✅ yes |
| dropdown/dropdown.js | 3368 bytes | ✅ yes |
| slider/slider.js | 5328 bytes | ✅ yes |
| switch/switch.js | 1313 bytes | ✅ yes |
| tags/tags.js | 2874 bytes | ✅ yes |
| dimension/dimension.js | 3643 bytes | ✅ yes |
| radius/radius.js | 2232 bytes | ✅ yes |
| responsive/responsive.js | 3802 bytes | ✅ yes |
| pills/pills.js | 1820 bytes | ✅ yes |
| **typography/typography.js** | **943069 bytes** | **❌ returns WordPress HTML** |
| **media/media.js** | **943069 bytes** | **❌ returns WordPress HTML** |
| **link/link.js** | **943069 bytes** | **❌ returns WordPress HTML** |
| **repeater/repeater.js** | **943069 bytes** | **❌ returns WordPress HTML** |
| **select/select.js** | **943069 bytes** | **❌ returns WordPress HTML** |
| **range/range.js** | **943069 bytes** | **❌ returns WordPress HTML** |
| **checkbox/checkbox.js** | **943069 bytes** | **❌ returns WordPress HTML** |
| **background-*/bg-*/motion-*/shadow-*/filters/backdrop-*/ai-assist** | n/a | **❌ don't exist** |

The 7 controls that return the home page HTML are because the .js file path doesn't exist
on the server, so nginx serves the parent directory or 404 fallback (which is the home page).
**The "world-class" 24-control system has 2 of 21 critical controls actually present.**

## What the FES specs need (the real shape)

The 21 FES modules in `/app-fragments/fes-modules/*.json` declare **216 fields** across
**21 modules**. Their `inspector` arrays use these types:

- **Common types**: `text`, `select`, `textarea`, `number`, `boolean`, `color`, `range`, `media`,
  `link`, `repeater`, `checkbox`, `size`
- **WCP primitives**: `typography`, `border`, `background`, `dimensions`, `alignment`,
  `box_shadow`, `text_shadow`, `hover_effects`, `motion_effects`,
  `responsive_visibility`, `css_classes`, `custom_css`, `icon`
- **Case variants**: specs also have `TYPOGRAPHY`, `COLOR`, `SIZE`, `NUMBER`, etc.
  (likely from a different generator). These need to be normalized.

**Of the 216 fields, ZERO can be rendered by the current v2 inspector** because:
- `text` works (real control exists)
- `color` mostly works (real control exists, but no alpha picker)
- Everything else either maps to a missing control (media, link, repeater) or to
  a non-existent WCP primitive (typography, border, background, dimensions, etc.)

## What `buildFieldsFromSpec` actually does

```js
function buildFieldsFromSpec(fesSpec) {
  const fieldSchema = (fesSpec && fesSpec.fieldSchema) || {};
  const inspector = (fesSpec && fesSpec.inspector) || {};
  const out = { fields: [], style: [], advanced: [] };

  if (Object.keys(inspector).length > 0) {
    for (const [groupName, keys] of Object.entries(inspector)) {
      // BUG: treats inspector entries as keys, but they're full field objects!
      // [ {id, type, label, options}, ... ] vs expected [ "key1", "key2", ... ]
      const tab = tabForGroup(groupName);
      const list = out[tab] || out.fields;
      for (const key of (keys || [])) {
        const f = fieldSchema[key] || {};   // BUG: key is an object, not a string
        ...
      }
    }
  }
}
```

The `inspector` array contains **full field objects** (`{id, type, label, options, ...}`),
not **key strings**. So this function iterates objects as if they were strings and
builds garbage fields with no real type/label/options.

## The 3 specific operator complaints — root cause each

1. **"S-10 there's nothing in the panel"** — S-10 is the 10th `.e-con`. The v2 inspector
   probably got to `v2Inspect`, called `buildFieldsFromSpec`, got `{}` back, and showed
   "(no fields)".

2. **"S-11 I click width and it talks about objects"** — `width` is part of a
   `dimensions` WCP primitive (an object: `{top, right, bottom, left, unit}`). v2
   has no `dimensions` control (the file doesn't exist). v2 inspector falls back
   to whatever it can — probably shows the raw object literal.

3. **"I clicked on an image and I can't change the image"** — image fields use
   type `media`. v2 has no `media` control. The field renders as a text input
   or empty, with no media picker.

## What needs to happen (the real plan)

This is not a "fix one bug" task. The v2 inspector skeleton is right (status bar,
tabs, panel chrome, dispatch). But the **control implementations are missing** for
the 19 controls that actually matter. They need to be built.

A world-class image picker is not "an input that takes a URL". It's:
- A drop zone for drag-and-drop file upload
- A "Browse Media Library" button that opens a modal with the WordPress media library
- An "Insert from URL" option as fallback
- A thumbnail preview with a "remove" button
- A "Replace" action
- Resolution selector (thumbnail/medium/large/full)

A world-class color picker is not a single hex input. It's:
- A swatch row of recent colors
- An eyedropper / "pick from page" action
- Alpha slider for transparency
- Multiple input modes: hex / rgb / hsl / named
- Live preview in the styled element

A world-class typography control is not 4 text inputs. It's:
- Font family picker with previews
- Weight, style, transform, decoration, line-height, letter-spacing — each as a proper sub-control
- A "linked" toggle for the size unit
- Live CSS variable output preview

A world-class link control is not a URL input. It's:
- A type selector (URL / Page / Post / Media / Anchor / Dynamic)
- Per-type specific fields (search for a page, pick a media file, etc.)
- A target/rel/nofollow group
- A preview breadcrumb

A world-class repeater is not "an array of inputs". It's:
- A list of items with drag-to-reorder
- A "+ Add" button
- Per-item expand/collapse
- A "+ Clone" action per item
- A "trash" icon per item

## My plan

This is going to be a structured rebuild, not a series of patches. Let me write the
real plan doc.
