mosaic-headless 1.30.1 → 1.31.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (48) hide show
  1. package/README.ja.md +4 -2
  2. package/README.ko.md +4 -2
  3. package/README.md +5 -3
  4. package/README.zh-TW.md +4 -2
  5. package/SKILL.md +84 -36
  6. package/assets/templates/platforms/claude-ai.json +1 -1
  7. package/assets/templates/platforms/claude-code.json +1 -1
  8. package/assets/templates/platforms/codex-cli.json +1 -1
  9. package/assets/templates/platforms/copilot.json +1 -1
  10. package/assets/templates/platforms/gemini-cli.json +1 -1
  11. package/data/browser-verification/moksa.csv +12 -12
  12. package/data/component-wall-verification.csv +1 -1
  13. package/data/condition-comparators.csv +2 -2
  14. package/data/content-loop-verification.csv +4 -1
  15. package/data/data-class-hierarchy.csv +1 -0
  16. package/data/dialog-form-verification.csv +2 -2
  17. package/data/dialog-verification.csv +1 -1
  18. package/data/form-surface-verification.csv +3 -0
  19. package/data/interaction-types.csv +1 -0
  20. package/data/intro-verification.csv +16 -16
  21. package/data/mobile-audit.csv +22 -19
  22. package/data/navigation-verification.csv +16 -13
  23. package/data/node-properties.csv +8 -3
  24. package/data/node-types.csv +1 -0
  25. package/data/node-verification.csv +3 -0
  26. package/data/placement-rules.csv +1 -0
  27. package/data/pluggables.csv +16 -4
  28. package/data/popover-verification.csv +38 -0
  29. package/data/style-states.csv +1 -0
  30. package/data/token-verification.csv +2 -2
  31. package/package.json +2 -1
  32. package/references/custom-fields.md +24 -1
  33. package/references/dialog-and-triggers.md +199 -8
  34. package/references/dynamic-content.md +19 -0
  35. package/references/failure-modes.md +47 -4
  36. package/references/styling.md +9 -0
  37. package/references/upgrading.md +46 -1
  38. package/scripts/check-release.mjs +7 -6
  39. package/sites/_dialogs.py +18 -8
  40. package/sites/_moksa.py +69 -39
  41. package/sites/_popovers.py +570 -0
  42. package/tools/audit_mobile.py +1 -1
  43. package/tools/build_page.py +13 -0
  44. package/tools/sweep_node_types.py +55 -6
  45. package/tools/verify_dialog.py +3 -2
  46. package/tools/verify_dialog_lab.py +11 -11
  47. package/tools/verify_intro.py +5 -3
  48. package/tools/verify_popovers.py +348 -0
package/README.ja.md CHANGED
@@ -137,13 +137,13 @@ commit の成功はページが動く証拠ではないし、正しいスタイ
137
137
 
138
138
  ## 何を、どう検証したか
139
139
 
140
- すべて実際のインストールに対して実行 — WordPress 7.1、WooCommerce 11.1、Mosaic Pro 1.0.9、
140
+ すべて実際のインストールに対して実行 — WordPress 7.1、WooCommerce 11.1、Mosaic Pro 1.0.10、
141
141
  **ライセンスなし**:ライセンスが制限するのはテーマライブラリと更新であってノードファクトリ
142
142
  ではないので、Pro の型も登録・描画される。
143
143
 
144
144
  | 項目 | 結果 |
145
145
  |---|---|
146
- | **ノード型** | 122 / 122 を 1 型 1 ドキュメントでスイープ、commit → 描画 → 断言 → 削除:74 RENDERED、25 COMMITTED、15 COMMIT_5xx、12 BROKE_PAGE。1.0.8 で再スイープ:以前は黙って commit されていた 5 型が、親なしではページを落とすようになった。描画されなかった行のうち 3 つは「必要な親なしで commit した」というスイープ手法の産物で、その旨が行の横にある |
146
+ | **ノード型** | 129 / 129 を 1 型 1 ドキュメントでスイープ、commit → 描画 → 断言 → 削除:77 RENDERED、25 COMMITTED、15 COMMIT_5xx、12 BROKE_PAGE。1.0.8 で再スイープ:以前は黙って commit されていた 5 型が、親なしではページを落とすようになった。描画されなかった行のうち 3 つは「必要な親なしで commit した」というスイープ手法の産物で、その旨が行の横にある |
147
147
  | **スタイルプロパティ** | 98 / 98 を実ページに書き、コンパイル済み CSS と照合:58 COMPILED、18 ABSENT、21 SKIPPED |
148
148
  | **ノードプロパティ** | 191 / 191 を各プロパティ自身のバリデータ連鎖から導いた値で再探査:35 APPLIED、43 NO_EFFECT、55 NO_HOST、47 SKIPPED |
149
149
  | **レスポンシブ** | 2 サイト計 733 件の `_t`/`_m` 宣言を、サイトが実際に配信したスタイルシートに対して 1 件ずつ断言 — 全件検証済み |
@@ -160,6 +160,7 @@ commit の成功はページが動く証拠ではないし、正しいスタイ
160
160
  | **スキル自身** | `claude plugin eval .` — ユーザーが実際に尋ねる 5 問を各 3 回、スキルあり/なしの 2 腕、1 回ごとに LLM 審査 3 名。**あり:5 問すべて 1.00。なし:5 問すべて 0.00。** ベースラインの最善の回答は回答拒否だった |
161
161
  | **ライブ計測** | REST ルート 115、variant 156、条件サブジェクト 59、23 テーブル / 210 カラム |
162
162
  | **1.0.9 の新機能** | modal(`<dialog>`)、OpenStreetMap、exit-intent と scroll-depth のトリガー、run rules、memory アクション、modal ショートハンド — すべて実ページに作り、ブラウザで実際に操作:19 / 19。「離脱時ポップアップを 1 セッション 1 回」が配線なしのオブジェクト 1 つで済む |
163
+ | **1.0.10 の新機能** | popover — Mosaic 初のページをブロックしないダイアログ — をラボページに 8 通り作り、Chromium で実操作:37 / 37。スクロールもクリックも妨げないページ読み込み時の通知、アンカー付きメニューとカード、画面 9 マス、keepInView の反転とそのスタイル状態、`afterClose` でつないだ 3 ステップのツアー。加えて modal の Popover API 移行:top layer、`requestClose()`、host の `display` で閉じなくなる問題の解消 |
163
164
  | **slider** | ファクトリが要求する入れ子でブラウザ実操作、19 / 19:宣言どおりの間隔で自走、矢印・ドット・キーボードで駆動、`prefers-reduced-motion` では自ら停止。ドットは実はテンプレートで、スライド数だけ複製され id は全部同じ |
164
165
  | **本物のサイト** | 変換済み 19 ページを 1 つのサイトに:実メニューとページごとのモーダル。ナビ 46 / 46、モーダル 19 / 19、トリガー/ルール/記憶/閉じ方の組み合わせは 6 種 |
165
166
  | **カスタムフィールド** | ACF と Meta Box、1 ページに 40 フィールド、`@VAR` / `@LOOP` で配信 HTML から読み戻し:62 のうち 59 が解決、3 つの空は理由付き;複数値フィールドのループはフィールドの行数どおりに描画。`tools/list_fields.php` が Mosaic の実際の登録名を出す |
@@ -243,6 +244,7 @@ loop grid、フォーム、カウントダウン、サードパーティ addon
243
244
  | `theme_zip.py` / `theme_zip_compare.php` / `theme_delete.php` | Mosaic 自身の ZIP 書き出し/読み込みをエディタの外から駆動、コピーを元とツリー単位で照合、ライブテーマを拒否する完全削除 |
244
245
  | `list_fields.php` | ある投稿のカスタムフィールドが登録する `@VAR` / `@LOOP` 名をすべて、値付きで |
245
246
  | `verify_dialog.py` | 1.0.9 の modal・トリガー・run rules・memory をブラウザで実操作 |
247
+ | `verify_popovers.py` | 1.0.10 の popover の配置・ブロック・closedby・反転・連鎖をブラウザで実操作 |
246
248
  | `data_upgrade.py` | プラグイン更新後、Mosaic のデータ移行を自身の milestone ルートで実行 — 終わるまでエディタ API は存在しない |
247
249
  | `sweep_*.py` / `probe_*.py` | 表を作った計測器そのもの |
248
250
  | `bootstrap_probe_theme.php` / `mint_session.php` | ライセンス不要の実験用テーマと、WP-CLI から作る REST セッション |
package/README.ko.md CHANGED
@@ -133,13 +133,13 @@ commit 성공은 페이지가 동작한다는 증거가 아니고, 올바른 스
133
133
 
134
134
  ## 무엇을, 어떻게 검증했나
135
135
 
136
- 전부 실제 설치에서 실행 — WordPress 7.1, WooCommerce 11.1, Mosaic Pro 1.0.9, **라이선스 없음**:
136
+ 전부 실제 설치에서 실행 — WordPress 7.1, WooCommerce 11.1, Mosaic Pro 1.0.10, **라이선스 없음**:
137
137
  라이선스가 막는 것은 테마 라이브러리와 업데이트지 노드 팩토리가 아니라서 Pro 타입도 등록되고
138
138
  렌더링된다.
139
139
 
140
140
  | 항목 | 결과 |
141
141
  |---|---|
142
- | **노드 타입** | 122 / 122를 문서당 하나씩 스윕, commit → 렌더 → 단언 → 삭제: 74 RENDERED, 25 COMMITTED, 15 COMMIT_5xx, 12 BROKE_PAGE. 1.0.8에서 재스윕: 전에는 조용히 commit되던 5개 타입이 부모 없이는 페이지를 죽인다. 렌더되지 않은 행 중 셋은 "필요한 부모 없이 commit"한 스윕 방식의 산물이며, 그 사실이 행 옆에 적혀 있다 |
142
+ | **노드 타입** | 129 / 129를 문서당 하나씩 스윕, commit → 렌더 → 단언 → 삭제: 77 RENDERED, 25 COMMITTED, 15 COMMIT_5xx, 12 BROKE_PAGE. 1.0.8에서 재스윕: 전에는 조용히 commit되던 5개 타입이 부모 없이는 페이지를 죽인다. 렌더되지 않은 행 중 셋은 "필요한 부모 없이 commit"한 스윕 방식의 산물이며, 그 사실이 행 옆에 적혀 있다 |
143
143
  | **스타일 프로퍼티** | 98 / 98을 실제 페이지에 쓰고 컴파일된 CSS와 대조: 58 COMPILED, 18 ABSENT, 21 SKIPPED |
144
144
  | **노드 프로퍼티** | 191 / 191을 각 프로퍼티 자신의 검증기 체인에서 도출한 값으로 재탐사: 35 APPLIED, 43 NO_EFFECT, 55 NO_HOST, 47 SKIPPED |
145
145
  | **반응형** | 두 사이트 합쳐 733개의 `_t`/`_m` 선언을, 사이트가 실제로 내보낸 스타일시트에 대해 하나씩 단언 — 전부 검증됨 |
@@ -156,6 +156,7 @@ commit 성공은 페이지가 동작한다는 증거가 아니고, 올바른 스
156
156
  | **스킬 자체** | `claude plugin eval .` — 사용자가 실제로 묻는 5문항을 각 3회, 스킬 있음/없음 두 팔로, 매회 LLM 심사 3명. **있음: 5문항 모두 1.00. 없음: 5문항 모두 0.00.** 베이스라인의 최선은 답변 거부였다 |
157
157
  | **라이브 측정** | REST 라우트 115, variant 156, 조건 subject 59, 23 테이블 / 210 컬럼 |
158
158
  | **1.0.9 신기능** | modal(`<dialog>`), OpenStreetMap, exit-intent·scroll-depth 트리거, run rules, memory 액션, modal 숏핸드를 실제 페이지에 만들고 브라우저에서 직접 조작: 19/19. "이탈 의도 팝업, 세션당 한 번"이 배선 없이 객체 하나 |
159
+ | **1.0.10 신기능** | popover — Mosaic 최초의 페이지를 막지 않는 다이얼로그 — 를 실험 페이지에 8가지로 만들고 Chromium에서 직접 조작: 37 / 37. 스크롤도 클릭도 막지 않는 페이지 로드 알림, 앵커 메뉴와 카드, 화면 9칸, keepInView 반전과 그 스타일 상태, `afterClose`로 이은 3단계 투어. 그리고 modal의 Popover API 이전: top layer, `requestClose()`, host의 `display`가 더 이상 닫히지 않게 만들지 않음 |
159
160
  | **slider** | 팩토리가 요구하는 중첩으로 브라우저에서 실제 조작, 19/19: 선언한 간격으로 자동 전진, 화살표·불릿·키보드로 구동, `prefers-reduced-motion`에서 스스로 멈춤. 불릿은 사실 템플릿이라 슬라이드 수만큼 복제되고 id가 전부 같다 |
160
161
  | **진짜 사이트** | 변환된 19개 페이지를 하나의 사이트로: 실제 메뉴와 페이지별 모달. 내비 46/46, 모달 19/19, 트리거·규칙·기억·닫기 조합 6종 |
161
162
  | **커스텀 필드** | ACF와 Meta Box, 한 페이지에 40개 필드, `@VAR` / `@LOOP`로 전달된 HTML에서 읽어냄: 62개 중 59개 해석, 빈 3개는 이유 있음; 다중값 필드 루프는 필드의 행 수 그대로 렌더링. `tools/list_fields.php`가 Mosaic이 실제 등록하는 이름을 출력 |
@@ -237,6 +238,7 @@ loop grid, 폼, 카운트다운, 서드파티 addon — 은 동적이라 될 노
237
238
  | `theme_zip.py` / `theme_zip_compare.php` / `theme_delete.php` | Mosaic 자체 ZIP 내보내기/가져오기를 에디터 밖에서 구동, 사본을 원본과 트리 단위로 대조, 라이브 테마를 거부하는 깨끗한 삭제 |
238
239
  | `list_fields.php` | 한 글의 커스텀 필드가 등록하는 모든 `@VAR` / `@LOOP` 이름을 값과 함께 |
239
240
  | `verify_dialog.py` | 1.0.9의 modal·트리거·run rules·memory를 브라우저에서 실제 조작 |
241
+ | `verify_popovers.py` | 1.0.10 popover의 배치·차단·closedby·반전·연쇄를 브라우저에서 직접 조작 |
240
242
  | `data_upgrade.py` | 플러그인 업데이트 후 Mosaic의 데이터 이관을 자체 milestone 라우트로 실행 — 끝나기 전까지 에디터 API는 존재하지 않는다 |
241
243
  | `sweep_*.py` / `probe_*.py` | 표를 만든 계측기 그 자체 |
242
244
  | `bootstrap_probe_theme.php` / `mint_session.php` | 라이선스 없는 실험용 테마와 WP-CLI에서 만드는 REST 세션 |
package/README.md CHANGED
@@ -167,7 +167,7 @@ the HTTP status code:
167
167
 
168
168
  ```
169
169
  clean validator rejection HTTP 200 + an `exceptions` array in the body
170
- PHP fatal during commit HTTP 500 (15 of 122 types do this from a plain div)
170
+ PHP fatal during commit HTTP 500 (15 of 129 types do this from a plain div)
171
171
  structurally invalid node HTTP 200, committed, row in the DB, and the whole
172
172
  public page becomes a 54-byte error string
173
173
  wrong value SHAPE HTTP 200, stored, and the CSS rule is simply absent
@@ -194,12 +194,12 @@ than any naive healthy-page floor.
194
194
  ## What was verified, and how
195
195
 
196
196
  Everything ran against a live install — WordPress 7.1, WooCommerce 11.1, Mosaic Pro
197
- 1.0.9, **unlicensed**: the licence gates the theme library and updates, not the node
197
+ 1.0.10, **unlicensed**: the licence gates the theme library and updates, not the node
198
198
  factories, so Pro types register and render regardless.
199
199
 
200
200
  | pass | result |
201
201
  |---|---|
202
- | **node types** | 122 / 122 swept one per document, committed → rendered → asserted → deleted: 74 RENDERED, 25 COMMITTED, 15 COMMIT_5xx, 12 BROKE_PAGE. Re-swept on 1.0.8: five types that used to commit silently now kill the page unparented. The non-rendering rows that are artefacts of committing without the required parent say so beside the row |
202
+ | **node types** | 129 / 129 swept one per document, committed → rendered → asserted → deleted: 77 RENDERED, 25 COMMITTED, 15 COMMIT_5xx, 12 BROKE_PAGE. Re-swept on 1.0.8: five types that used to commit silently now kill the page unparented. The non-rendering rows that are artefacts of committing without the required parent say so beside the row |
203
203
  | **style properties** | 98 / 98 written to a live page and checked against the compiled CSS: 58 COMPILED, 18 ABSENT, 21 SKIPPED |
204
204
  | **node properties** | 191 / 191 re-probed with a value shaped by each property's own validator chain: 35 APPLIED, 43 NO_EFFECT, 55 NO_HOST, 47 SKIPPED |
205
205
  | **responsive** | 733 `_t`/`_m` declarations across two sites asserted against the stylesheet the site actually served — all verified |
@@ -216,6 +216,7 @@ factories, so Pro types register and render regardless.
216
216
  | **the skill itself** | `claude plugin eval .` — five cases a user would ask, three runs each, with and without the skill loaded, three LLM judges a run. **With: 1.00 on all five. Without: 0.00 on all five.** The baseline's best answer was to refuse |
217
217
  | **measured live** | 115 REST routes, 156 variants, 59 condition subjects, 23 tables / 210 columns |
218
218
  | **1.0.9 features** | the modal (`<dialog>`), OpenStreetMap, the exit-intent and scroll-depth triggers, run rules, memory actions and the modal shorthand, each built on a live page and exercised in a real browser: 19 of 19. An exit-intent popup that fires once a session is one object, no wiring |
219
+ | **1.0.10 features** | the popover - Mosaic's first non-blocking dialog - built eight ways on a lab page and driven in Chromium: 37 of 37. A page-load notice that leaves the page scrollable and clickable, anchored menus and cards, the nine screen cells, the keepInView flip and its style state, a three-step tour on `afterClose`. Plus the modal's move onto the Popover API: top layer, `requestClose()`, and `display` on its host no longer pinning it open |
219
220
  | **slider** | the whole family nested as its factories require and driven in a browser, 19 of 19: advances on its own delay, arrows and bullets and the keyboard move it, holds still under `prefers-reduced-motion`. The bullet turns out to be a template repeated per slide - same id on every copy |
220
221
  | **a real site** | the nineteen converted Elementor pages assembled into one site with a real menu and a modal per page: 46 of 46 navigation checks, 19 of 19 modals, six distinct trigger / run-rule / memory / dismissal configurations |
221
222
  | **custom fields** | ACF and Meta Box, forty fields on a page, read back through `@VAR` / `@LOOP` off the delivered HTML: 59 of 62 resolve, 3 empties explained; loops over multi-value fields rendered exactly the field's rows. `tools/list_fields.php` prints the names Mosaic actually registers |
@@ -303,6 +304,7 @@ and heading level — and it earned its place at once: it caught the converter l
303
304
  | `theme_zip.py` / `theme_zip_compare.php` / `theme_delete.php` | Mosaic's own ZIP export/import from outside the editor, the copy held against the source, and a clean delete that refuses the live theme |
304
305
  | `list_fields.php` | every `@VAR` / `@LOOP` name a post's custom fields register, with values |
305
306
  | `verify_dialog.py` | the 1.0.9 modal, triggers, run rules and memory, driven in a browser |
307
+ | `verify_popovers.py` | the 1.0.10 popover: placement, blocking, closedby, flip, chaining, driven in a browser |
306
308
  | `verify_slider.py` / `verify_navigation.py` | does the slider actually move; is every menu item a real link and every page reachable |
307
309
  | `data_upgrade.py` | after a plugin update, Mosaic's data migration over its own milestone route - the editor API is gone until it runs |
308
310
  | `sweep_*.py` / `probe_*.py` | the instruments the tables were made with |
package/README.zh-TW.md CHANGED
@@ -159,12 +159,12 @@ commit 成功不代表頁面能用,樣式表正確也不代表。這裡每個
159
159
 
160
160
  ## 驗證了什麼,怎麼驗的
161
161
 
162
- 全部在真實站台上跑——WordPress 7.1、WooCommerce 11.1、Mosaic Pro 1.0.9,**未授權**:
162
+ 全部在真實站台上跑——WordPress 7.1、WooCommerce 11.1、Mosaic Pro 1.0.10,**未授權**:
163
163
  授權鎖的是主題庫和更新,不是節點工廠,所以 Pro 型別照樣註冊、照樣渲染。
164
164
 
165
165
  | 項目 | 結果 |
166
166
  |---|---|
167
- | **節點型別** | 122 / 122 逐一放進獨立文件,寫入 → 渲染 → 斷言 → 刪除:74 RENDERED、25 COMMITTED、15 COMMIT_5xx、12 BROKE_PAGE。在 1.0.8 上重掃:五個以前默默寫入的型別,沒放對父節點現在會直接弄死頁面。未渲染的當中有三個是「沒給父層」的掃描方法產物,註記就在列旁 |
167
+ | **節點型別** | 129 / 129 逐一放進獨立文件,寫入 → 渲染 → 斷言 → 刪除:77 RENDERED、25 COMMITTED、15 COMMIT_5xx、12 BROKE_PAGE。在 1.0.8 上重掃:五個以前默默寫入的型別,沒放對父節點現在會直接弄死頁面。未渲染的當中有三個是「沒給父層」的掃描方法產物,註記就在列旁 |
168
168
  | **樣式屬性** | 98 / 98 寫進真實頁面、對照編譯出的 CSS:58 COMPILED、18 ABSENT、21 SKIPPED |
169
169
  | **節點屬性** | 191 / 191 用各自驗證鏈推出的值重新探測:35 APPLIED、43 NO_EFFECT、55 NO_HOST、47 SKIPPED |
170
170
  | **響應式** | 兩個站共 733 條 `_t`/`_m` 宣告,對照網站實際送出的樣式表逐條斷言——全數通過 |
@@ -181,6 +181,7 @@ commit 成功不代表頁面能用,樣式表正確也不代表。這裡每個
181
181
  | **技能本身** | `claude plugin eval .`——五個使用者真的會問的問題,各跑三次,有載技能和沒載各一臂,每次三個 LLM 裁判。**有:五題全 1.00。沒有:五題全 0.00。** 基準線最好的回答是拒答 |
182
182
  | **線上量測** | 115 條 REST 路由、156 個 variant、59 個條件主體、23 張表 / 210 個欄位 |
183
183
  | **1.0.9 新功能** | modal(`<dialog>`)、OpenStreetMap、exit-intent 與 scroll-depth 觸發、run rules、memory action 與 modal shorthand,全部建在真實頁面上並用瀏覽器實際操作:19 之 19。「離開意圖彈窗、每個 session 只出現一次」只需要一個物件,不用接線 |
184
+ | **1.0.10 新功能** | popover——Mosaic 第一個不阻擋頁面的浮動層——在實驗頁上做了八種,用 Chromium 實際操作:37 / 37。頁面載入時出現的通知不擋捲動也不擋點擊、錨定選單與資訊卡、螢幕九宮格、keepInView 翻面與它的樣式狀態、用 `afterClose` 串起來的三步導覽。另外是 modal 改用 Popover API:進入 top layer、改用 `requestClose()`、host 上寫 `display` 不再讓它關不起來 |
184
185
  | **slider** | 整組照工廠要求嵌套後在瀏覽器裡實際操作,19 之 19:會自己按宣告的間隔前進、箭頭與圓點與鍵盤都能驅動、`prefers-reduced-motion` 下會自己停。圓點其實是樣板,依 slide 數複製,每個複製品 id 相同 |
185
186
  | **真正的網站** | 19 個轉換頁組成一個站:真實選單、每頁一個彈窗。導覽 46 之 46、彈窗 19 之 19,六種不同的觸發/規則/記憶/關閉設定 |
186
187
  | **自訂欄位** | ACF 與 Meta Box,一頁四十個欄位,透過 `@VAR` / `@LOOP` 從送達的 HTML 讀回:62 個裡 59 個解析正確、3 個空值有解釋;多值欄位的迴圈剛好渲染出欄位的列數。`tools/list_fields.php` 列出 Mosaic 真正註冊的名字 |
@@ -258,6 +259,7 @@ button / html / icon-list / divider / image 佔了全部元素的 99.6%。長尾
258
259
  | `theme_zip.py` / `theme_zip_compare.php` / `theme_delete.php` | 在編輯器外驅動 Mosaic 自己的 ZIP 匯出匯入、副本對來源逐樹比對、以及拒絕刪 live 主題的乾淨刪除 |
259
260
  | `list_fields.php` | 一篇文章的自訂欄位註冊了哪些 `@VAR` / `@LOOP` 名字,連值一起列出 |
260
261
  | `verify_dialog.py` | 在瀏覽器裡實際操作 1.0.9 的 modal、觸發、run rules 與 memory |
262
+ | `verify_popovers.py` | 在瀏覽器裡實際操作 1.0.10 的 popover:位置、是否阻擋、closedby、翻面、串接 |
261
263
  | `verify_slider.py` / `verify_navigation.py` | slider 真的會動嗎;選單每一項是不是真連結、每頁是不是都到得了 |
262
264
  | `data_upgrade.py` | 外掛更新後,走 Mosaic 自己的 milestone 路由跑資料遷移——沒跑完之前編輯器 API 是不存在的 |
263
265
  | `sweep_*.py` / `probe_*.py` | 那些表格是用這些儀器量出來的 |
package/SKILL.md CHANGED
@@ -1,11 +1,11 @@
1
1
  ---
2
2
  name: "mosaic-headless"
3
3
  description: |
4
- Build and modify Mosaic Pro (Nextend) sites by writing the underlying data model directly - no visual editor, no DOM. Query the real surface with `mo.py`, which joins every source table to the live sweeps so a lookup leads with the measured verdict rather than the declaration (128 node types, 191 properties, 98 style properties with 20 structured value shapes pinned down, 53 style states, 156 variants, 74 dynamic variables, 15 interaction triggers, 115 REST routes, 23 tables) instead of guessing, with every node type placed on a live site one at a time and asserted against the delivered HTML, the design-token and element-class layers verified against compiled CSS, the @VAR() dynamic language verified against rendered output, nine designed pages built through the tables themselves, and the delivered pages re-read in Chromium at three viewports so a rule that is present, correct and still wrong cannot pass. Drives Mosaic's own theme export/import and its plugin data upgrade from outside the editor and holds the copy against the source tree for tree. Measured on Mosaic Pro 1.0.9: the modal (`<dialog>`), OpenStreetMap, the exit-intent and scroll-depth triggers, run rules and the memory actions all built on a live page and read back, and the 1.0.7 -> 1.0.8 -> 1.0.9 migrations driven from outside wp-admin.
4
+ Build and modify Mosaic Pro (Nextend) WordPress sites by writing the data model directly - no visual editor, no DOM. Query the real surface with `mo.py` (129 node types, 196 node properties, 98 style properties, 54 style states, 156 variants, 74 dynamic variables, 16 interaction triggers, 115 REST routes) where every lookup leads with the measured verdict, not the declaration: each node type placed on a live site one at a time, each style and node property swept against compiled CSS and markup, the delivered pages re-read in Chromium at three viewports. Measured on Mosaic Pro 1.0.10: the popover (anchored or screen-placed, the flip state, afterClose-chained tours), the modal on the Popover API, OpenStreetMap, exit-intent and scroll-depth triggers, run rules and memory. Drives theme export/import and the 1.0.7 -> 1.0.10 data upgrades from outside wp-admin.
5
5
  license: "MIT"
6
6
  metadata:
7
7
  author: "moksa (https://moksaweb.com)"
8
- version: "1.30.1"
8
+ version: "1.31.1"
9
9
  homepage: "https://github.com/Moksa1123/mosaic-headless"
10
10
  ---
11
11
 
@@ -58,14 +58,14 @@ python tools/mo.py skeleton # a minimal valid page spec
58
58
 
59
59
  `--json` on any of them for machine-readable output. Every answer leads with the
60
60
  measured verdict rather than the declaration, because on this platform the two
61
- disagree for 52 of the 122 types.
61
+ disagree for 52 of the 122 types they were first counted on.
62
62
 
63
63
  Then check the page. Mosaic has eight failure modes and **only three of them change the
64
64
  HTTP status code**:
65
65
 
66
66
  ```
67
67
  clean validator rejection HTTP 200 + an `exceptions` array in the body
68
- PHP fatal during commit HTTP 500 (15 of 122 types do this from a plain div)
68
+ PHP fatal during commit HTTP 500 (15 of 129 types do this from a plain div)
69
69
  structurally invalid node HTTP 200, committed, row in the DB, and the whole
70
70
  public page becomes a 54-byte error string
71
71
  wrong value SHAPE HTTP 200, stored, and the CSS rule is simply absent -
@@ -133,24 +133,28 @@ measured.
133
133
  ## What was verified, and how
134
134
 
135
135
  Everything ran against a live install: WordPress 7.1, WooCommerce 11.1,
136
- Mosaic Pro 1.0.9, **unlicensed** — the licence gates the theme library and updates,
136
+ Mosaic Pro 1.0.10, **unlicensed** — the licence gates the theme library and updates,
137
137
  not the node factories, so the Pro types register and render regardless. The
138
- site was built on 1.0.7 and upgraded in place twice: both data migrations
139
- (`tools/data_upgrade.py`) ran over the real theme, and every sweep below was
140
- re-run on the result, so the tables describe 1.0.9 as delivered, not as declared.
138
+ site was built on 1.0.7 and upgraded in place three times: every data migration
139
+ (`tools/data_upgrade.py`) ran over the real theme, and the source tables were
140
+ re-extracted from 1.0.10 and every demo verifier re-run on the result, so the
141
+ tables describe 1.0.10 as delivered, not as declared. Where a row is still a 1.0.9
142
+ measurement - the full node sweep, the property sweeps - the section says so.
141
143
 
142
144
  ```
143
145
  WRITE PATH verified end to end over REST
144
146
  theme -> master -> healed node tree -> template -> nodes -> public HTML
145
147
 
146
- NODE SWEEP 122 of 122 node types, ONE PER DOCUMENT, committed then rendered then
148
+ NODE SWEEP 129 of 129 node types, ONE PER DOCUMENT, committed then rendered then
147
149
  deleted, asserting each type's attrID against the delivered HTML:
148
- RENDERED 74 id found; tag and classes recorded
150
+ RENDERED 77 id found; tag and classes recorded
149
151
  COMMITTED 25 row exists, nothing reached the page
150
152
  COMMIT_5xx 15 PHP fatal on commit
151
153
  BROKE_PAGE 12 committed, then the whole page died
152
154
  data/node-verification.csv. 1.0.9's four new types - modal,
153
- modal-window, modal-overlay, openstreetmap - all render.
155
+ modal-window, modal-overlay, openstreetmap - all render, and so
156
+ does 1.0.10's one, popover (<div popover=manual>, swept on 1.0.10;
157
+ the other rows are the 1.0.9 sweep).
154
158
  Re-swept on 1.0.8: five types that used to commit and render
155
159
  nothing (accordion-title, loop-pagination and its two buttons,
156
160
  multi-steps-form-step) now kill the page instead - the render
@@ -206,7 +210,23 @@ DIALOG 1.0.9's features built on a live page and read back out of the
206
210
  runs once a session and again in a new one, which is the cap rule
207
211
  holding. The OpenStreetMap element carries the coordinates only in
208
212
  the {"v": ...} object form. data/dialog-verification.csv,
209
- references/dialog-and-triggers.md
213
+ references/dialog-and-triggers.md. Re-run on 1.0.10, 19 of 19, with
214
+ one row changed: the open modal is now in the top layer (1.0.10
215
+ moved it onto the Popover API - `dialog.open` is always false, read
216
+ `:popover-open`; close from script with `mosaicDialog.requestClose()`)
217
+
218
+ POPOVER 1.0.10's non-blocking surface on a lab page, 37 of 37 in Chromium:
219
+ a page-load notice leaves the page scrollable and clickable;
220
+ closedby nothing / clickOutside / everything each honoured; an
221
+ unanchored menu on its trigger to the pixel, an anchored card on
222
+ the element it names, the nine screen cells where they say;
223
+ keepInView flips and ___popover--flipped styles the flipped one -
224
+ and without it the popover does not overflow but slides back over
225
+ its own trigger. A three-step tour taught the two rules that decide
226
+ how any sequence is built: a dialog opened from inside another is
227
+ its child and closes with it, and closing a popover suspends the
228
+ interactions inside it - so steps advance on afterClose, never on a
229
+ button that opens the next one. data/popover-verification.csv
210
230
 
211
231
  FIELDS ACF 6.8 and Meta Box 5.15, forty fields registered in code on a page,
212
232
  read back off the delivered HTML: 59 of 62 expressions resolve to the
@@ -383,9 +403,10 @@ UPGRADE 1.0.7 -> 1.0.8 driven over the plugin's own milestone route from
383
403
  one selector on the worked example that named an emitted class
384
404
  stopped matching until it was rewritten. references/upgrading.md
385
405
 
386
- FROM SOURCE 128 node types, 191 properties (61 with enums), 249 pluggable IDs,
387
- 126 placement rules, 10 composite default structures, 98 style
388
- properties, 53 style states, 15 interaction triggers.
406
+ FROM SOURCE 129 node types, 196 properties (68 with enums), 261 pluggable IDs,
407
+ 129 placement rules, 25 composite default structures (10 declared,
408
+ 15 healed in), 98 style properties, 54 style states, 16 interaction
409
+ triggers - re-extracted from the 1.0.10 tree.
389
410
  ```
390
411
 
391
412
  **Coverage, stated as a fraction rather than as a headline.** The verification
@@ -393,11 +414,15 @@ counts above are real, but they are not the same as "the surface is verified", a
393
414
  the difference is worth being exact about:
394
415
 
395
416
  ```
396
- node types 122 / 122 swept live, one per document
397
- node properties 191 / 191 re-probed with a value shaped by each property's
417
+ node types 129 / 129 swept live, one per document
418
+ node properties 191 / 196 re-probed with a value shaped by each property's
398
419
  own validator chain: 38 APPLIED, 45 NO_EFFECT,
399
420
  2 EDITOR_ONLY, 55 NO_HOST (no rendering type
400
421
  declares them), 2 INSTRUMENT, 45 SKIPPED
422
+ (the five missing are 1.0.10's popover -
423
+ role, ariaLive, accessibleLabel, closedby,
424
+ positioning - measured on the popover lab
425
+ instead: data/popover-verification.csv)
401
426
  style properties 98 / 98 swept live; 58 COMPILED, 18 ABSENT, 1 NO_ELEMENT,
402
427
  21 SKIPPED (no test value could be synthesised, and
403
428
  SKIPPED is never counted as a pass)
@@ -498,8 +523,9 @@ so the pattern is in the data, not just in this paragraph.
498
523
  13. `references/custom-fields.md` — ACF and Meta Box fields as `@VAR` / `@LOOP`:
499
524
  the names, what each field type resolves to, and the loop element that walks
500
525
  a multi-value field. Measured, 62 rows.
501
- 14. `references/dialog-and-triggers.md` — 1.0.9's modal, OpenStreetMap, the
502
- exit-intent / scroll-depth triggers, run rules, memory and the shorthand.
526
+ 14. `references/dialog-and-triggers.md` — the modal (and what 1.0.10's Popover API
527
+ move changed), the 1.0.10 popover, OpenStreetMap, the exit-intent / scroll-depth
528
+ triggers, run rules, memory and the shorthand.
503
529
  15. `references/upgrading.md` — what a plugin update does to the data and to the
504
530
  delivered page, measured on 1.0.7 -> 1.0.8; how to drive the migration and what
505
531
  to re-verify afterwards.
@@ -508,14 +534,14 @@ so the pattern is in the data, not just in this paragraph.
508
534
 
509
535
  | file | rows | source |
510
536
  |---|---|---|
511
- | `data/node-verification.csv` | 122 | **swept live** — outcome, rendered tag and classes, page bytes, failure detail |
512
- | `data/node-types.csv` | 122 | source — slug, label, edition, aliases, data class |
513
- | `data/node-properties.csv` | 191 | source — property, validator chain, **accepted enum values**, `supportsInherit` |
514
- | `data/placement-rules.csv` | 122 | source — which children each type accepts |
515
- | `data/default-children.csv` | 10 | source — what a composite type needs **inside** it |
537
+ | `data/node-verification.csv` | 129 | **swept live** — outcome, rendered tag and classes, page bytes, failure detail |
538
+ | `data/node-types.csv` | 129 | source — slug, label, edition, aliases, data class |
539
+ | `data/node-properties.csv` | 196 | source — property, validator chain, **accepted enum values**, `supportsInherit` |
540
+ | `data/placement-rules.csv` | 129 | source — which children each type accepts |
541
+ | `data/default-children.csv` | 25 | source — what a composite type needs **inside** it |
516
542
  | `data/style-properties.csv` | 98 | source — every settable CSS property and its value shape |
517
543
  | `data/style-value-shapes.csv` | 22 | **probed live** — the exact JSON shape for each structured value, and what it compiled to |
518
- | `data/style-states.csv` | 53 | source — state IDs with their exact CSS selector templates |
544
+ | `data/style-states.csv` | 54 | source — state IDs with their exact CSS selector templates |
519
545
  | `data/property-verification.csv` | 170 | **probed live** — per-property effect on markup vs CSS, with unprovable enums marked INCONCLUSIVE |
520
546
  | `data/node-property-verification.csv` | 191 | **swept live** — each property probed with a value shaped by its own validator chain, on a type that declares it |
521
547
  | `data/style-verification.csv` | 98 | **swept live** — every style property written to a page and checked against the compiled CSS, with its group beside the result |
@@ -523,7 +549,7 @@ so the pattern is in the data, not just in this paragraph.
523
549
  | `data/browser-verification/` | 4132 | **computed in Chromium** - declared vs `getComputedStyle` at three viewports, `not-comparable` labelled per row. One CSV per page, named by its slug |
524
550
  | `data/design-audit-acknowledged.csv` | 3 | reviewed findings that will not be fixed, each with a written reason. An acknowledgement without a reason is a suppression wearing a better name, and the release gate refuses one |
525
551
  | `data/design-audit.csv` | 26 | **computed in Chromium** - contrast, font fallback, CJK tracking, overflow, measure. Empty means it ran and found nothing |
526
- | `data/data-class-hierarchy.csv` | 125 | source - every data class and its parent, so a type's inherited properties can be resolved |
552
+ | `data/data-class-hierarchy.csv` | 126 | source - every data class and its parent, so a type's inherited properties can be resolved |
527
553
  | `data/style-state-verification.csv` | 52 | **swept live** - each state written on a host of its own type and matched against its promised selector |
528
554
  | `data/component-verification.csv` | 8 | **driven live** - the component lifecycle, each step asserted against the row or the delivered HTML |
529
555
  | `data/loop-verification.csv` | 28 | **measured live** - a perpetual animation: periodicity by scrubbing a paused timeline, per-element occlusion of both text and controls at five widths, and the enlarged view opened by pointer and by keyboard |
@@ -532,15 +558,16 @@ so the pattern is in the data, not just in this paragraph.
532
558
  | `data/conversion-batch.csv` | 19 | **converted, built and checked live, one page after another** - every Elementor page of a production site through the converter, with per-page element and content counts |
533
559
  | `data/token-benchmark.csv` | 6 | **measured with tiktoken** - the same six lookups priced three ways: reading the plugin source, loading every table, querying `mo.py`. 71-99.5% fewer tokens than the source and 99.6%+ fewer than the tables, which total 259,539 - never load them, query them |
534
560
  | `data/slider-verification.csv` | 30 | **driven live** - two sliders, one autoplaying and one a carousel: advance, arrows, bullets, keyboard, reduced motion |
535
- | `data/navigation-verification.csv` | 36 | **fetched and opened live** - every menu item is a real `<a href>`, every page of the nineteen answers 200, and no page scrolls sideways at 390 / 768 / 1280 |
561
+ | `data/navigation-verification.csv` | 39 | **fetched and opened live** - every menu item is a real `<a href>`, each of the demo's twelve pages answers 200, every in-page anchor it links to exists, and no page scrolls sideways at 390 / 768 / 1280 |
536
562
  | `data/page-modal-verification.csv` | 19 | **read live** - one modal per page, and what each one's trigger, run rule, memory scope and dismissal policy actually came out as |
537
- | `data/dialog-verification.csv` | 19 | **driven live** - the 1.0.9 modal, its triggers, its run rules and the memory actions, each exercised in a real browser |
563
+ | `data/dialog-verification.csv` | 19 | **driven live** - the modal (re-run on 1.0.10), its triggers, its run rules and the memory actions, each exercised in a real browser |
538
564
  | `data/dialog-form-verification.csv` | 49 | **driven live** - the same three nodes made into five FORMS (sheet, drawer, corner, takeover, gate), each re-opened at 390px and 768px; also where `pickOne` on a click turned out to be a latch rather than a lottery |
565
+ | `data/popover-verification.csv` | 37 | **driven live** - 1.0.10's popover: every host a `<div popover=manual>`, a pageLoad notice that leaves the page scrollable and clickable, closedby honoured per policy, anchored placement against the trigger and against another element, the nine screen cells, keepInView flipping and the `___popover--flipped` state applying, a three-step tour advanced by afterClose and ended by interactionSuspend, and a modal whose host sets `display:flex` and still hides when closed |
539
566
  | `data/token-verification.csv` | 15 | **driven live** - every `:root` custom property declared once, non-empty, and resolved by something on the page; a token nothing points at is a token that is not working |
540
- | `data/mobile-audit.csv` | 65 | **driven live** - what a sideways-scroll check cannot see: type under the legible floor, controls too small to hit, a grid that never collapsed, content escaping its box |
567
+ | `data/mobile-audit.csv` | 68 | **driven live** - what a sideways-scroll check cannot see: type under the legible floor, controls too small to hit, a grid that never collapsed, content escaping its box |
541
568
  | `data/component-wall-verification.csv` | 26 | **driven live** - tabs switched, an accordion opened, a form's fields and Mosaic's own honeypot, and an OpenStreetMap asserted on the coordinates it was GIVEN rather than the default it falls back to |
542
- | `data/form-surface-verification.csv` | 15 | **driven live** - every field type Mosaic ships in one form: select with labelled options, radio and checkbox groups, file upload, and the browser's own validation refusing an empty submit |
543
- | `data/content-loop-verification.csv` | 12 | **driven live** - a slider, a tab bar, a list and a paginated archive whose children all come from one authored template repeated per post; the pagination is clicked and the rows asserted to CHANGE |
569
+ | `data/form-surface-verification.csv` | 18 | **driven live** - every field type Mosaic ships in one form: select with labelled options, radio and checkbox groups, file upload, and the browser's own validation refusing an empty submit |
570
+ | `data/content-loop-verification.csv` | 15 | **driven live** - a slider, a tab bar, a list and a paginated archive whose children all come from one authored template repeated per post; the pagination is clicked and the rows asserted to CHANGE |
544
571
  | `data/custom-fields-verification.csv` | 62 | **rendered live** - ACF and Meta Box fields of every common type read back through `@VAR` / `@LOOP` off the delivered page, loops included |
545
572
  | `data/theme-zip-verification.csv` | 22 | **round-tripped live** - Mosaic's own ZIP export imported in test mode and compared to its source, table by table and tree by tree |
546
573
  | `data/node-type-notes.csv` | 8 | where a sweep outcome is true but misleading on its own, why. Surfaced by `mo.py type` |
@@ -549,11 +576,11 @@ so the pattern is in the data, not just in this paragraph.
549
576
  | `data/variants.csv` | 156 | **live** — the variant catalog (Mosaic's built-in element classes); their IDs are what a `variant` record must use, and `class_name` is what the element emits |
550
577
  | `data/dynamic-variables.csv` | 74 | source — every `@VAR('ns/name')` expression, by namespace |
551
578
  | `data/evaluator-functions.csv` | 19 | source — the `@` functions with their arity |
552
- | `data/interaction-types.csv` | 15 | source — trigger types, `timed` vs `progress`; 1.0.9 adds exitIntent, scrollDepth and modal |
579
+ | `data/interaction-types.csv` | 16 | source — trigger types, `timed` vs `progress`; 1.0.9 added exitIntent, scrollDepth and modal, 1.0.10 adds popover (Popover visibility change: show / beforeClose / afterClose) |
553
580
  | `data/animatable-properties.csv` | 22 | source — what a keyframe can drive (**not** the same set as the style properties) |
554
581
  | `data/condition-subjects.csv` | 59 | **live** — condition subjects per context |
555
- | `data/condition-comparators.csv` | 12 | **live** — comparators and their operator sets |
556
- | `data/pluggables.csv` | 249 | source — every `setID()` by registry |
582
+ | `data/condition-comparators.csv` | 12 | **live** — comparators and their operator sets, captured on 1.0.9; the two date rows carry 1.0.10's four operators (after, after-or-equal, before, before-or-equal) from its source |
583
+ | `data/pluggables.csv` | 261 | source — every `setID()` by registry |
557
584
  | `data/rest-routes.csv` | 115 | **live** — method, path, args |
558
585
  | `data/db-columns.csv` | 210 | **live** — every column of all 23 tables |
559
586
 
@@ -644,7 +671,7 @@ post — `build_all.py` resets first for that reason.
644
671
 
645
672
  ## Facts worth knowing before you look anything up
646
673
 
647
- - **The REST namespace contains the plugin version** (`/wp-json/mosaic/v1.0.9`). Read
674
+ - **The REST namespace contains the plugin version** (`/wp-json/mosaic/v1.0.10`). Read
648
675
  it from `mosaicOptions.rest_api_url`, never hardcode. After a plugin update the
649
676
  editor namespace is GONE until the data upgrade has run; only
650
677
  `mosaic/<dataVersion>/<version>/upgrade` answers. `tools/data_upgrade.py`.
@@ -745,6 +772,26 @@ post — `build_all.py` resets first for that reason.
745
772
  `@media` blocks together; the old `mosaic-theme-block-editor-styles_<bp>-inline-css`
746
773
  ids are gone. And an element whose styles compile to nothing is emitted with
747
774
  no generated class at all, so "no `_token`" no longer means "did not render".
775
+ - **Since 1.0.10 the modal is a Popover-API host in the top layer.** `<dialog
776
+ popover="manual">`; `dialog.open` is always false (read `:popover-open` or
777
+ `data-mosaic-dialog-state`), the controller has `requestClose()` and no `close()`,
778
+ and the closed state is `display:none !important` - so `display` on a modal host,
779
+ a pin-it-open bug on 1.0.9, is safe now. z-index cannot put anything above it.
780
+ - **`popover` is the non-blocking dialog (1.0.10)**: no overlay, no children
781
+ required, `closedby` defaults to `nothing`, `positioning` is `screen` (nine cells)
782
+ or `element` (side / align / keepInView / anchor - no anchor = its trigger).
783
+ Actions `popoverOpen` / `popoverClose` / `popoverToggle`; trigger `popover` with
784
+ slots `show` / `beforeClose` / `afterClose`; style state `___popover--flipped`.
785
+ **A dialog opened from inside another dialog is its child and closes with it, and
786
+ closing a popover suspends the interactions inside it** - so a sequence advances
787
+ on the step's own `afterClose`, never on a button that opens the next step.
788
+ references/dialog-and-triggers.md
789
+ - **`scrollDepth`'s action slot is `reached` since 1.0.10** (plus `returned`). An
790
+ action stored under the old slot name `scrollDepth` is kept and never runs.
791
+ - **A local-context loop's `loopSource` is `@VAR('post/<loop>')`, never `@LOOP()`.**
792
+ Both render on the front end; `@LOOP` there throws in the editor
793
+ (`_loopEvaluatorFunction is not a function`) and the canvas never finishes.
794
+ `build_page.py` refuses it. `@LOOP(…)` inside text is fine.
748
795
  - **A custom field is `@VAR('post/meta_<key>')`, and a multi-value one is a LOOP.**
749
796
  ACF and Meta Box both, plus bare post meta. Derived properties hang off the
750
797
  name with two underscores (`meta_k__label`, `__url`, `__id`); an ACF group is
@@ -814,7 +861,8 @@ post — `build_all.py` resets first for that reason.
814
861
  | `theme_delete.php` | remove a theme completely through the plugin's own routine; refuses the live one |
815
862
  | `verify_slider.py` | the slider in a real browser: does it advance, do the arrows and bullets drive it, does the keyboard, does it stop when motion is not wanted - `--label`/`--append` put several sliders in one table, which is where a carousel and a plain slider can be held against each other |
816
863
  | `verify_navigation.py` | a multi-page site: is every menu item a real `<a href>`, does every page answer 200 (a template that was never bound answers 406 with an empty body, which only a logged-out visitor sees), and with `--viewports` does any page scroll SIDEWAYS - the one question no per-page checker asks - and whether every in-page `#fragment` resolves ON THE PAGE THAT CARRIES IT, which an HTTP check cannot see: a bare `#services` in a SHARED header fetches the current page, answers 200 everywhere, and does nothing on every page but the one that has that section |
817
- | `verify_dialog.py` | the 1.0.9 modal in a real browser: does it open, close, answer Esc, remember, cap - and does an OpenStreetMap carry the coordinates it was given |
864
+ | `verify_dialog.py` | the modal in a real browser (1.0.9 and 1.0.10 alike: open is read as `:popover-open` or `dialog.open`): does it open, close, answer Esc, remember, cap - and does an OpenStreetMap carry the coordinates it was given |
865
+ | `verify_popovers.py` | 1.0.10's popover in a real browser: opens, lands where its positioning says, blocks nothing, closes the way closedby says, flips, chains, and ends - every check reads `:popover-open`, never an attribute |
818
866
  | `verify_dialog_lab.py` | the question after "does the modal work": can three nodes be made into a bottom sheet, a side drawer, a corner notice, a full takeover and a gate with no way out - and does each one still fit at phone width, which the page's own width check cannot see |
819
867
  | `verify_tokens.py` | the design tokens as the BROWSER resolved them: every `:root` property declared once (a changed value does not retire the old one), non-empty, and actually pointed at by something - a wrong `skinsData` shape still emits the declaration and serves white |
820
868
  | `verify_components.py` | presses the interactive components on a page and asserts the RESULT - a pane actually swapped, an accordion item actually opened, the map carries the coordinates it was given - because "these all work" is worth what the last press proved |
@@ -20,7 +20,7 @@
20
20
  "description": "Build and modify Mosaic Pro (Nextend) sites by writing the underlying data model directly - no visual editor, no DOM. Query the real surface (122 node types, 181 node properties, 98 style properties, 53 style states, 151 element classes, 74 dynamic variables, 114 REST routes, 23 tables) instead of guessing, with every node type placed on a live site one at a time and asserted against the delivered HTML, every style and node property swept against the compiled CSS and markup, and 569 responsive declarations checked against the stylesheet the site actually served.",
21
21
  "license": "MIT",
22
22
  "author": "moksa (https://moksaweb.com)",
23
- "version": "1.30.1"
23
+ "version": "1.31.1"
24
24
  },
25
25
  "loaderBehaviour": "Upload via Settings -> Skills -> Upload. Claude.ai parses SKILL.md frontmatter and surfaces the skill in your library. The extraction tool (extract-block-schema.php) needs a live WP-CLI connection and won't run in the sandbox; use it from a local terminal against your own site instead.",
26
26
  "uploadSteps": [
@@ -20,7 +20,7 @@
20
20
  "description": "Build and modify Mosaic Pro (Nextend) sites by writing the underlying data model directly - no visual editor, no DOM. Query the real surface (122 node types, 181 node properties, 98 style properties, 53 style states, 151 element classes, 74 dynamic variables, 114 REST routes, 23 tables) instead of guessing, with every node type placed on a live site one at a time and asserted against the delivered HTML, every style and node property swept against the compiled CSS and markup, and 569 responsive declarations checked against the stylesheet the site actually served.",
21
21
  "license": "MIT",
22
22
  "author": "moksa (https://moksaweb.com)",
23
- "version": "1.30.1"
23
+ "version": "1.31.1"
24
24
  },
25
25
  "loaderBehaviour": "Auto-loads on session start when SKILL.md frontmatter parses successfully.",
26
26
  "verified": true,
@@ -20,7 +20,7 @@
20
20
  "description": "Build and modify Mosaic Pro (Nextend) sites by writing the underlying data model directly - no visual editor, no DOM. Query the real surface (122 node types, 181 node properties, 98 style properties, 53 style states, 151 element classes, 74 dynamic variables, 114 REST routes, 23 tables) instead of guessing, with every node type placed on a live site one at a time and asserted against the delivered HTML, every style and node property swept against the compiled CSS and markup, and 569 responsive declarations checked against the stylesheet the site actually served.",
21
21
  "license": "MIT",
22
22
  "author": "moksa (https://moksaweb.com)",
23
- "version": "1.30.1"
23
+ "version": "1.31.1"
24
24
  },
25
25
  "loaderBehaviour": "Confirmed (2026-07-11): Codex CLI natively supports the SKILL.md spec. Place SKILL.md under .codex/skills/<name>/ (project) or ~/.codex/skills/<name>/ (personal) and Codex loads the name+description at session start, then the full body on demand. A parallel, broader convention .agents/skills/ (searched from cwd up to repo root, then ~/.agents/skills/) also exists across multiple tools - if your Codex CLI version prioritizes that path instead, mirror the same SKILL.md there.",
26
26
  "verified": true,
@@ -20,7 +20,7 @@
20
20
  "description": "Build and modify Mosaic Pro (Nextend) sites by writing the underlying data model directly - no visual editor, no DOM. Query the real surface (122 node types, 181 node properties, 98 style properties, 53 style states, 151 element classes, 74 dynamic variables, 114 REST routes, 23 tables) instead of guessing, with every node type placed on a live site one at a time and asserted against the delivered HTML, every style and node property swept against the compiled CSS and markup, and 569 responsive declarations checked against the stylesheet the site actually served.",
21
21
  "license": "MIT",
22
22
  "author": "moksa (https://moksaweb.com)",
23
- "version": "1.30.1"
23
+ "version": "1.31.1"
24
24
  },
25
25
  "loaderBehaviour": "CHANGED as of 2026-07-11: GitHub Copilot added a proper '.github/skills/' Agent Skills directory (December 2025), alongside the older single-file .github/copilot-instructions.md convention. This config targets the new skills-directory form. If your Copilot version predates this (pre Dec 2025), use the instructions-append fallback instead (see fallback below).",
26
26
  "fallback": {
@@ -20,7 +20,7 @@
20
20
  "description": "Build and modify Mosaic Pro (Nextend) sites by writing the underlying data model directly - no visual editor, no DOM. Query the real surface (122 node types, 181 node properties, 98 style properties, 53 style states, 151 element classes, 74 dynamic variables, 114 REST routes, 23 tables) instead of guessing, with every node type placed on a live site one at a time and asserted against the delivered HTML, every style and node property swept against the compiled CSS and markup, and 569 responsive declarations checked against the stylesheet the site actually served.",
21
21
  "license": "MIT",
22
22
  "author": "moksa (https://moksaweb.com)",
23
- "version": "1.30.1"
23
+ "version": "1.31.1"
24
24
  },
25
25
  "loaderBehaviour": "CHANGED as of 2026-07-11: Gemini CLI now natively supports the same SKILL.md standard as Claude Code and Codex CLI - the same directory-based skill works unmodified. Gemini CLI discovers skills in this precedence order: built-in, extension skills, ~/.gemini/skills/ (personal), .gemini/skills/ (project, shared via version control). At session start Gemini injects each discovered skill's name+description into the system prompt and calls activate_skill when a task matches.",
26
26
  "verified": true,
@@ -1906,8 +1906,8 @@ _t,mk-pan-loop,display,flex,flex,ok
1906
1906
  _t,mk-pan-loop,columnGap,56px,56px,ok
1907
1907
  _t,mk-pan-loop,alignItems,baseline,baseline,ok
1908
1908
  _t,mk-pan-loop,customDeclarations:white-space,nowrap,no computed value,not-comparable
1909
- _t,mk-pan-loop,customDeclarations:width,max-content,max-content resolves to a used value (3742.16px),not-comparable
1910
- _t,mk-pan-track,customDeclarations:width,max-content,max-content resolves to a used value (3742.16px),not-comparable
1909
+ _t,mk-pan-loop,customDeclarations:width,max-content,max-content resolves to a used value (3764.03px),not-comparable
1910
+ _t,mk-pan-track,customDeclarations:width,max-content,max-content resolves to a used value (3764.03px),not-comparable
1911
1911
  _t,mk-plate-in,width,100%,viewport- or parent-relative,not-comparable
1912
1912
  _t,mk-plate-in,maxWidth,1240px,1240px,ok
1913
1913
  _t,mk-plate-in,marginLeft,auto,auto resolves to a used value (0px),not-comparable
@@ -1983,12 +1983,12 @@ _t,mk-prod-s-0,marginTop,14px,14px,ok
1983
1983
  _t,mk-prod-s-0,customDeclarations:border,"1px solid rgba(255,90,54,.6)",no computed value,not-comparable
1984
1984
  _t,mk-prod-s-0,customDeclarations:padding,5px 10px,no computed value,not-comparable
1985
1985
  _t,mk-prod-s-0,customDeclarations:display,inline-block,inline-block,ok
1986
- _t,mk-prod-s-0,customDeclarations:width,max-content,max-content resolves to a used value (86.8125px),not-comparable
1986
+ _t,mk-prod-s-0,customDeclarations:width,max-content,max-content resolves to a used value (99.7656px),not-comparable
1987
1987
  _t,mk-prod-s-1,marginTop,14px,14px,ok
1988
1988
  _t,mk-prod-s-1,customDeclarations:border,"1px solid rgba(255,90,54,.6)",no computed value,not-comparable
1989
1989
  _t,mk-prod-s-1,customDeclarations:padding,5px 10px,no computed value,not-comparable
1990
1990
  _t,mk-prod-s-1,customDeclarations:display,inline-block,inline-block,ok
1991
- _t,mk-prod-s-1,customDeclarations:width,max-content,max-content resolves to a used value (72.4062px),not-comparable
1991
+ _t,mk-prod-s-1,customDeclarations:width,max-content,max-content resolves to a used value (82.4844px),not-comparable
1992
1992
  _t,mk-spec,display,grid,grid,ok
1993
1993
  _t,mk-spec,gridCols,"repeat(2, 1fr)",422px 422px,ok
1994
1994
  _t,mk-spec,columnGap,0px,0px,ok
@@ -2048,28 +2048,28 @@ _t,mk-spec2-in,marginRight,auto,auto resolves to a used value (0px),not-comparab
2048
2048
  _t,mk-spec2-pad,paddingTop,88px,88px,ok
2049
2049
  _t,mk-spec2-pad,paddingBottom,88px,88px,ok
2050
2050
  _t,mk-spec2-r-0,display,grid,grid,ok
2051
- _t,mk-spec2-r-0,gridCols,1fr auto,648.797px 167.203px,ok
2051
+ _t,mk-spec2-r-0,gridCols,1fr auto,615.359px 200.641px,ok
2052
2052
  _t,mk-spec2-r-0,columnGap,28px,28px,ok
2053
2053
  _t,mk-spec2-r-0,alignItems,baseline,baseline,ok
2054
2054
  _t,mk-spec2-r-0,paddingTop,20px,20px,ok
2055
2055
  _t,mk-spec2-r-0,paddingBottom,20px,20px,ok
2056
2056
  _t,mk-spec2-r-0,customDeclarations:border-top,"1px solid rgba(250,250,247,.18)",no computed value,not-comparable
2057
2057
  _t,mk-spec2-r-1,display,grid,grid,ok
2058
- _t,mk-spec2-r-1,gridCols,1fr auto,656.391px 159.609px,ok
2058
+ _t,mk-spec2-r-1,gridCols,1fr auto,624.469px 191.531px,ok
2059
2059
  _t,mk-spec2-r-1,columnGap,28px,28px,ok
2060
2060
  _t,mk-spec2-r-1,alignItems,baseline,baseline,ok
2061
2061
  _t,mk-spec2-r-1,paddingTop,20px,20px,ok
2062
2062
  _t,mk-spec2-r-1,paddingBottom,20px,20px,ok
2063
2063
  _t,mk-spec2-r-1,customDeclarations:border-top,"1px solid rgba(250,250,247,.18)",no computed value,not-comparable
2064
2064
  _t,mk-spec2-r-2,display,grid,grid,ok
2065
- _t,mk-spec2-r-2,gridCols,1fr auto,648.797px 167.203px,ok
2065
+ _t,mk-spec2-r-2,gridCols,1fr auto,615.359px 200.641px,ok
2066
2066
  _t,mk-spec2-r-2,columnGap,28px,28px,ok
2067
2067
  _t,mk-spec2-r-2,alignItems,baseline,baseline,ok
2068
2068
  _t,mk-spec2-r-2,paddingTop,20px,20px,ok
2069
2069
  _t,mk-spec2-r-2,paddingBottom,20px,20px,ok
2070
2070
  _t,mk-spec2-r-2,customDeclarations:border-top,"1px solid rgba(250,250,247,.18)",no computed value,not-comparable
2071
2071
  _t,mk-spec2-r-3,display,grid,grid,ok
2072
- _t,mk-spec2-r-3,gridCols,1fr auto,648.797px 167.203px,ok
2072
+ _t,mk-spec2-r-3,gridCols,1fr auto,615.359px 200.641px,ok
2073
2073
  _t,mk-spec2-r-3,columnGap,28px,28px,ok
2074
2074
  _t,mk-spec2-r-3,alignItems,baseline,baseline,ok
2075
2075
  _t,mk-spec2-r-3,paddingTop,20px,20px,ok
@@ -3235,8 +3235,8 @@ _m,mk-pan-loop,display,flex,flex,ok
3235
3235
  _m,mk-pan-loop,columnGap,30px,30px,ok
3236
3236
  _m,mk-pan-loop,alignItems,baseline,baseline,ok
3237
3237
  _m,mk-pan-loop,customDeclarations:white-space,nowrap,no computed value,not-comparable
3238
- _m,mk-pan-loop,customDeclarations:width,max-content,max-content resolves to a used value (2452.34px),not-comparable
3239
- _m,mk-pan-track,customDeclarations:width,max-content,max-content resolves to a used value (2452.34px),not-comparable
3238
+ _m,mk-pan-loop,customDeclarations:width,max-content,max-content resolves to a used value (2474.22px),not-comparable
3239
+ _m,mk-pan-track,customDeclarations:width,max-content,max-content resolves to a used value (2474.22px),not-comparable
3240
3240
  _m,mk-plate-in,width,100%,viewport- or parent-relative,not-comparable
3241
3241
  _m,mk-plate-in,maxWidth,1240px,1240px,ok
3242
3242
  _m,mk-plate-in,marginLeft,auto,auto resolves to a used value (0px),not-comparable
@@ -3313,12 +3313,12 @@ _m,mk-prod-s-0,marginTop,14px,14px,ok
3313
3313
  _m,mk-prod-s-0,customDeclarations:border,"1px solid rgba(255,90,54,.6)",no computed value,not-comparable
3314
3314
  _m,mk-prod-s-0,customDeclarations:padding,5px 10px,no computed value,not-comparable
3315
3315
  _m,mk-prod-s-0,customDeclarations:display,inline-block,inline-block,ok
3316
- _m,mk-prod-s-0,customDeclarations:width,max-content,max-content resolves to a used value (86.8125px),not-comparable
3316
+ _m,mk-prod-s-0,customDeclarations:width,max-content,max-content resolves to a used value (99.7656px),not-comparable
3317
3317
  _m,mk-prod-s-1,marginTop,14px,14px,ok
3318
3318
  _m,mk-prod-s-1,customDeclarations:border,"1px solid rgba(255,90,54,.6)",no computed value,not-comparable
3319
3319
  _m,mk-prod-s-1,customDeclarations:padding,5px 10px,no computed value,not-comparable
3320
3320
  _m,mk-prod-s-1,customDeclarations:display,inline-block,inline-block,ok
3321
- _m,mk-prod-s-1,customDeclarations:width,max-content,max-content resolves to a used value (72.4062px),not-comparable
3321
+ _m,mk-prod-s-1,customDeclarations:width,max-content,max-content resolves to a used value (82.4844px),not-comparable
3322
3322
  _m,mk-spec,display,grid,grid,ok
3323
3323
  _m,mk-spec,gridCols,"repeat(2, 1fr)",177px 177px,ok
3324
3324
  _m,mk-spec,columnGap,0px,0px,ok
@@ -18,7 +18,7 @@ MEDIA/icons_inline,PASS,"3 inline <svg> - `icon` takes RAW SVG in its `svg` prop
18
18
  WORDPRESS/shortcode_ran,PASS,"3 items from the shortcode - this is WooCommerce's own output, not a reimplementation"
19
19
  MULTISTEP,SKIPPED,not on this page
20
20
  COMPONENT/instances,PASS,"3 instances: ['cs-0-cs-card', 'cs-1-cs-card', 'cs-2-cs-card']"
21
- COMPONENT/one_definition,PASS,"all share the generated class ['_fm'] - one definition, not 3 copies"
21
+ COMPONENT/one_definition,PASS,"all share the generated class ['_fp'] - one definition, not 3 copies"
22
22
  COMPONENT/content_differs,PASS,"3 instances, 3 distinct bodies - the overrides are per-instance"
23
23
  LOOP/slider,SKIPPED,not on this page
24
24
  LOOP/tabs,SKIPPED,not on this page
@@ -1,10 +1,10 @@
1
1
  context,rule_type,comparator,label,operators,settings_fields,field_types,supports_dynamic
2
2
  element,serverCondition,text,Text,equals|not-equals|contains|not-contains|starts-with|regexp,value,text,yes
3
3
  element,serverCondition,number,Number,equals|not-equals|greater-than|greater-than-or-equal|less-than|less-than-or-equal,value,number,yes
4
- element,serverCondition,date,Date,after|before,value,dateTime,yes
4
+ element,serverCondition,date,Date,after|after-or-equal|before|before-or-equal,value,dateTime,yes
5
5
  formAction,serverCondition,text,Text,equals|not-equals|contains|not-contains|starts-with|regexp,value,text,yes
6
6
  formAction,serverCondition,number,Number,equals|not-equals|greater-than|greater-than-or-equal|less-than|less-than-or-equal,value,number,yes
7
- formAction,serverCondition,date,Date,after|before,value,dateTime,yes
7
+ formAction,serverCondition,date,Date,after|after-or-equal|before|before-or-equal,value,dateTime,yes
8
8
  interaction,serverCondition,text,Text,equals|not-equals|contains|not-contains|starts-with|regexp,value,text,no
9
9
  interaction,serverCondition,number,Number,equals|not-equals|greater-than|greater-than-or-equal|less-than|less-than-or-equal,value,number,no
10
10
  interaction,browserCondition,text,Text,equals|not-equals|contains|not-contains|starts-with,value,text,no
@@ -2,12 +2,15 @@ check,result,detail
2
2
  TABS,SKIPPED,not on this page
3
3
  ACCORDION,SKIPPED,not on this page
4
4
  FORM,SKIPPED,not on this page
5
+ NAVBAR,SKIPPED,not on this page
6
+ MEDIA,SKIPPED,not on this page
7
+ WORDPRESS,SKIPPED,not on this page
5
8
  MULTISTEP,SKIPPED,not on this page
6
9
  COMPONENT/instances,SKIPPED,fewer than two on this page
7
10
  LOOP/slider,PASS,6 slides from one authored slider-slide
8
11
  LOOP/tabs,PASS,4 tabs from one authored tabs-tab
9
12
  LOOP/tab_labels_intact,PASS,"no replacement characters - @substr counts bytes, so a length that is not a multiple of the encoding cuts a glyph in half"
10
- LOOP/pagination_links,PASS,"3 page links: ['v=18823&notes=1', 'v=18823&notes=2', 'v=18823&notes=3']"
13
+ LOOP/pagination_links,PASS,"3 page links: ['notes=1', 'notes=2', 'notes=3']"
11
14
  LOOP/pagination_key_is_safe,PASS,paginationKey does not collide with a WordPress query var
12
15
  LOOP/pagination_changes_rows,PASS,page 1 3 -> page 2 3
13
16
  MAP,SKIPPED,not on this page