@appaflytech/zeyrek-ai-mcp 0.0.8 → 0.0.9

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 (39) hide show
  1. package/README.md +27 -21
  2. package/dist/config.js +2 -0
  3. package/dist/knowledge/componentCatalog.js +122 -27
  4. package/dist/knowledge/componentEvents.js +35 -4
  5. package/dist/knowledge/errorPath.js +1 -1
  6. package/dist/knowledge/normalize.js +15 -0
  7. package/dist/knowledge/rules.js +3 -1
  8. package/dist/knowledge/styleResolve.js +46 -4
  9. package/dist/knowledge/themeResolve.js +936 -0
  10. package/dist/knowledge/themeRules.js +221 -0
  11. package/dist/knowledge/themeSchema.js +335 -0
  12. package/dist/platform/domSummary.js +144 -0
  13. package/dist/platform/screenshot.js +414 -23
  14. package/dist/platform/screenshotMemory.js +55 -0
  15. package/dist/resources/examples/layout-app-shell.json +1 -1
  16. package/dist/resources/examples/theme-brand.json +162 -0
  17. package/dist/resources/guides/component.md +7 -1
  18. package/dist/resources/guides/getting-started.md +4 -0
  19. package/dist/resources/guides/layout.md +30 -26
  20. package/dist/resources/guides/microservice.md +55 -1
  21. package/dist/resources/guides/page.md +87 -44
  22. package/dist/resources/guides/theme.md +210 -0
  23. package/dist/resources/guides/translation.md +6 -4
  24. package/dist/resources/guides/workflow.md +91 -6
  25. package/dist/resources/schema-fingerprint.json +2 -2
  26. package/dist/server.js +52 -43
  27. package/dist/tools/components.js +8 -0
  28. package/dist/tools/designSchemaPatch.js +152 -0
  29. package/dist/tools/flows.js +15 -18
  30. package/dist/tools/layouts.js +4 -4
  31. package/dist/tools/microservices.js +5 -5
  32. package/dist/tools/pages.js +196 -323
  33. package/dist/tools/projects.js +66 -9
  34. package/dist/tools/schemaOps.js +280 -0
  35. package/dist/tools/screenWrite.js +2 -1
  36. package/dist/tools/screens.js +0 -7
  37. package/dist/tools/themes.js +163 -0
  38. package/dist/tools/workflows.js +1 -1
  39. package/package.json +1 -1
@@ -0,0 +1,162 @@
1
+ {
2
+ "_meta": {
3
+ "synthetic": true,
4
+ "note": "Studio tema panelinin ürettiği kayıtla aynı şekil. Yalnız SAPAN değerler yazılır: typeScale/radiusScale/spacingScale/actions dokunulmayan kademeleri taşımaz, böylece platform varsayılanı değişince onları izlemeye devam ederler. Preset gövdeleri sabit hex değil var(--ng-*) kullanır — preset de temayı izlesin.",
5
+ "usage": "theme_update({ theme: <themeUpdateArgs.theme> }) — kısmi yazma; tamamını kurmak için replace: true. componentPresets tipleri doğrulansın istiyorsanız applicationId verin (THEME-011)."
6
+ },
7
+ "_rules": [
8
+ "shadow.color altı haneli hex OLMALI; başka yazım üç gölgeyi birden görünmez yapar (THEME-004).",
9
+ "Oranlar 0 < r <= 20; aralık dışı değer runtime'da sessizce yok sayılır (THEME-007).",
10
+ "mode:'dark' yazılacaksa paletteDark da yazılır — karanlıkta runtime palette'e BAKMAZ (THEME-009).",
11
+ "componentPresets bir kaskad değil BAŞLANGIÇ değeridir: mevcut düğümlere dokunmaz; bir tip en fazla 5 versiyon taşır ve defaultVersion versiyonlar arasında olmalıdır (THEME-002).",
12
+ "componentStyles EMEKLİ: panel ilk kayıtta onu componentPresets'e taşır ve canlı kaskad kopar (THEME-003). Bu örnek onu hiç taşımaz."
13
+ ],
14
+ "themeUpdateArgs": {
15
+ "theme": {
16
+ "mode": "light",
17
+ "palette": {
18
+ "accent": {
19
+ "primary": "#4F46E5",
20
+ "hover": "#4338CA",
21
+ "muted": "#EEF2FF",
22
+ "subtle": "#F5F7FF"
23
+ },
24
+ "background": {
25
+ "canvas": "#F8FAFC",
26
+ "surface": "#FFFFFF",
27
+ "surfaceAlt": "#F1F5F9"
28
+ },
29
+ "border": {
30
+ "primary": "#E2E8F0",
31
+ "secondary": "#94A3B8"
32
+ },
33
+ "text": {
34
+ "primary": "#0F172A",
35
+ "secondary": "#475569",
36
+ "disabled": "#94A3B8"
37
+ },
38
+ "status": {
39
+ "success": "#15803D",
40
+ "warning": "#B45309",
41
+ "error": "#B91C1C",
42
+ "info": "#F1F5F9"
43
+ }
44
+ },
45
+ "paletteDark": {
46
+ "accent": {
47
+ "primary": "#818CF8",
48
+ "hover": "#A5B4FC",
49
+ "muted": "#1E1B4B",
50
+ "subtle": "#151338"
51
+ },
52
+ "background": {
53
+ "canvas": "#0B1120",
54
+ "surface": "#111827",
55
+ "surfaceAlt": "#0F172A"
56
+ },
57
+ "border": {
58
+ "primary": "#1F2937",
59
+ "secondary": "#475569"
60
+ },
61
+ "text": {
62
+ "primary": "#E2E8F0",
63
+ "secondary": "#94A3B8",
64
+ "disabled": "#475569"
65
+ },
66
+ "status": {
67
+ "success": "#34D399",
68
+ "warning": "#FBBF24",
69
+ "error": "#F87171",
70
+ "info": "#1F2937"
71
+ }
72
+ },
73
+ "fontFamily": "Inter Tight",
74
+ "headingFontFamily": "Sora",
75
+ "fontSize": "15px",
76
+ "fontWeight": "400",
77
+ "typeScale": {
78
+ "h1": 2.5,
79
+ "small": 0.8
80
+ },
81
+ "spacing": "12px",
82
+ "spacingScale": {
83
+ "xl": 5
84
+ },
85
+ "borderRadius": "8px",
86
+ "radiusScale": {
87
+ "lg": 2
88
+ },
89
+ "shadow": {
90
+ "offsetX": 0,
91
+ "offsetY": 6,
92
+ "blur": 12,
93
+ "spread": -2,
94
+ "color": "#1E1B4B",
95
+ "opacity": 18
96
+ },
97
+ "defaultInputSize": "md",
98
+ "actions": {
99
+ "blue": "#4F46E5",
100
+ "red": "#E11D48"
101
+ },
102
+ "presets": {
103
+ "kart": {
104
+ "padding": "16px",
105
+ "borderRadius": "var(--ng-radius-lg)",
106
+ "background": "var(--ng-background-surface)",
107
+ "border": "1px solid var(--ng-border-primary)",
108
+ "boxShadow": "var(--ng-shadow-sm)",
109
+ "transition": "border-color 140ms ease, box-shadow 140ms ease",
110
+ "&:hover": {
111
+ "borderColor": "var(--ng-accent-primary)",
112
+ "boxShadow": "var(--ng-shadow-md)"
113
+ }
114
+ },
115
+ "sessizMetin": {
116
+ "color": "var(--ng-text-secondary)",
117
+ "fontSize": "var(--ng-font-size-small)"
118
+ }
119
+ },
120
+ "componentPresets": {
121
+ "button": {
122
+ "defaultVersion": "V1",
123
+ "versions": {
124
+ "V1": {
125
+ "props": {
126
+ "size": "lg"
127
+ },
128
+ "appearance": {
129
+ "marginType": "custom",
130
+ "marginValues": {
131
+ "top": 0,
132
+ "right": 0,
133
+ "bottom": 12,
134
+ "left": 0
135
+ }
136
+ }
137
+ },
138
+ "V2": {
139
+ "props": {
140
+ "size": "sm",
141
+ "type": "secondary"
142
+ }
143
+ }
144
+ }
145
+ },
146
+ "container": {
147
+ "defaultVersion": "V1",
148
+ "versions": {
149
+ "V1": {
150
+ "props": {
151
+ "layout": "flex",
152
+ "direction": "row",
153
+ "gap": "medium",
154
+ "wrap": true
155
+ }
156
+ }
157
+ }
158
+ }
159
+ }
160
+ }
161
+ }
162
+ }
@@ -60,7 +60,10 @@ Doğrulama mesajını çeviriye bağlamak ayrı bir sözleşmedir (`t:` öneki,
60
60
  (`eventcalendar` · `importwizard` · `kanban` · `signature` · `stepper`) dolar — `kanban` ve
61
61
  `eventcalendar` yükü `self`'e HİÇ yazmaz, yalnız `event.data` ile okunur (ayrım
62
62
  `component_get` sözleşme notlarında).
63
- - Akış bağlama: `flow_create` → `page_schema_patch set_event`. İstisna: `html` komponentinin
63
+ - Akış bağlama: `flow_create` → `set_event` (sayfada `page_schema_patch`, layout'ta
64
+ `layout_schema_patch`, widget'ta `component_schema_patch`). Akış isteği barındırıcının şemasını
65
+ yazmaz; bağ yalnız bu yamayla kurulur, silmede de önce `remove_event` sonra `flow_delete`.
66
+ İstisna: `html` komponentinin
64
67
  aksiyonları kendi `flow` prop'uyla bağlanır (`platform_guide('html')`).
65
68
 
66
69
  ## Stil
@@ -87,6 +90,9 @@ Widget, kendi komponent ağacını taşıyan yeniden kullanılabilir pakettir (`
87
90
  `elementId`'leri kullanır; Studio düzenleyicisinin gösterdiği `__widget__` yer tutucusu
88
91
  yalnız editör katmanıdır (kayıt anında gerçek id'ye çevrilir) — API'den yazarken yer
89
92
  tutucu KULLANMA.
93
+ 4. **Ağacı değiştirmek:** `component_schema_patch` (widget kaydının `id`'si) sayfa ile aynı
94
+ micro-op'ları `PATCH /components/{app}/{id}/schema`'ya yazar; `component_update` ise slug alan
95
+ tam gövde PUT'tur. Widget'ın düzey olayı yoktur, `remove_event` yalnız komponent hedefler.
90
96
 
91
97
  ## `states` ve `appearance` sözlükleri
92
98
 
@@ -140,6 +140,10 @@ koda baktığını gizlemek yerine raporlamak.
140
140
  - create/update → ilgili `*_get` ile geri oku
141
141
  - microservice → `microservice_execute`, beklenmedik sonuçta `microservice_debug`
142
142
  - workflow → `workflow_preview`; automation → `automation_trigger` + `automation_histories`
143
+ - zamanlanmış iş (`schedule-job`) → ÖNCE `workflow_preview` / `microservice_debug` (rollback'li adım
144
+ izi), SONRA `microservice_schedule_control` `trigger` + `microservice_job_history`. Geçmiş
145
+ `failed` satırında patlayan adımı ve sebebini yazar ama adım izini vermez
146
+ (`platform_guide('microservice')` §Zamanlanmış işin gerçek sonucunu görmek)
143
147
  - "API 200 döndü" tek başına bitti saymaz; politika bulgularını (`policyFindings`) oku ve gereğini yap
144
148
  - Tool'un şemasında olmayan üst düzey argüman **reddedilir** ve hata okunan alanları listeler
145
149
  (GW-005). Bir argüman kabul edildiyse gateway onu okuyor demektir.
@@ -12,22 +12,29 @@ kutusu layout modülünde süzülmez — tüm katalog kullanılabilir.
12
12
 
13
13
  **2. Şema alanının adı `schema` değil `views`.** (LAY-001)
14
14
 
15
- **3. Micro-op ucu yok, ama `PATCH /layouts/{app}/{id}` var.** `page_schema_patch`'in birebir
16
- karşılığı yoktur (`PATCH /layouts/.../schema` ucu yok); onun yerine platform genel bir JSON Patch
17
- ucu verir ve `layout_patch` onu kullanır: layout'u okur, JSON Patch'i ve kendi normalizasyonlarını
18
- uygular, doğrulamadan geçirir ve **farkı** `{ baseVersion, ops }` olarak yazar — tam gövde PUT'u
19
- atılmaz. Böylece tek bir başlık düzeltmesi için 12 düğümlük ağacı yeniden göndermezsin (ölçüm:
20
- 09-04 koşusu Y-25). Yol İNDEKS yerine SEÇİCİ alır:
21
- `/views/0/children[elementId=baslik]/props/content/data`.
22
-
23
- **Sürüm ve 409.** Okunan kaydın `version` alanı `baseVersion` olarak gider. Sen okuduktan sonra
24
- başka biri yazdıysa platform **409** döner ve HİÇBİR op uygulanmaz; doğru tepki "aynı op'ları
25
- tekrar göndermek" değil, `layout_schema_get` ile yeniden okuyup patch'i güncel hâle göre kurmaktır.
26
- `version` bir **string**tir (mikrosaniye cinsinden zaman damgası, JavaScript'in güvenli tam sayı
27
- sınırının üstünde) — sayıya çevirme, olduğu gibi geri gönder. `expectedUpdatedAt` verirsen gateway
28
- ayrıca istek gitmeden önce yerel bir kontrol daha yapar. Tam ağacı kendin yazacaksan `layout_update`;
29
- `views` göndermezsen mevcut ağaç korunur. Okumak için `layout_schema_get` (summary kipi hedef bulmak
30
- için yeterlidir).
15
+ **3. Ağaç değişikliği `layout_schema_patch` ile (2026-09-14).** Platform
16
+ `PATCH /layouts/{app}/{id}/schema` ucunu verir ve sayfa ile **aynı** micro-op sözlüğünü konuşur:
17
+ `add_component`, `remove_component`, `move_component`, `replace_prop`, `set_event`, `remove_event`,
18
+ `resize_component`, `set_prop_type`, `reorder` ve diğerleri `page_schema_patch`'teki gibi yazılır.
19
+ Dokunulan düğümler tam doğrulanır, geri kalan ağaç yapısal; istek atomiktir. Sayfadan farkları:
20
+
21
+ - Kök ekleme `parent: 'root'`'a gider — layout'ta `page_container` yoktur.
22
+ - `remove_event` `target: 'page'` layout düzeyi olayları hedefler.
23
+ - `baseVersion` yoktur: son yazan kazanır. Hedefleri yazmadan hemen önce `layout_schema_get` ile oku.
24
+ - Slot'u silen ya da ikinci slot ekleyen yama yazılır ama LAY-002 / LAY-006 uyarısı döner (Kural 4).
25
+ - Bağı kalmayan akışı platform kalıcı siler; gateway böyle bir yamayı `allowFlowDeletion: true`
26
+ olmadan göndermez (G-21, sayfadakiyle aynı).
27
+
28
+ Okumak için `layout_schema_get` (summary kipi hedef bulmak için yeterlidir); tam ağacı kendin
29
+ yazacaksan `layout_update` (`views` göndermezsen mevcut ağaç korunur).
30
+
31
+ **3a. `layout_patch` düz JSON Patch içindir.** Ad, `parameters`, `events` gibi ağaç dışı alanlar ya
32
+ da yol gerektiren bir değişiklik için: layout'u okur, JSON Patch'i ve kendi normalizasyonlarını
33
+ uygular ve **farkı** `PATCH /layouts/{app}/{id}`'ye `{ baseVersion, ops }` olarak yazar (09-04 koşusu
34
+ Y-25). Yol İNDEKS yerine SEÇİCİ alır: `/views/0/children[elementId=baslik]/props/content/data`.
35
+ Okunan kaydın `version`'ı `baseVersion` olarak gider; araya başka bir yazma girdiyse **409** döner
36
+ ve hiçbir op uygulanmaz — doğru tepki `layout_schema_get` ile yeniden okuyup patch'i güncel hâle
37
+ göre kurmaktır. `version` bir **string**tir (mikrosaniye zaman damgası) — sayıya çevirme.
31
38
 
32
39
  **4. TEK slot.** Sayfa şeması **her** slot'a ayrı ayrı kopyalanır — iki slot, sayfayı iki
33
40
  kez çizer ve `elementId`'leri tekrarlar. (LAY-002 / LAY-006)
@@ -141,7 +148,8 @@ bağlantı nesnesi ya da tam yol).
141
148
  ## Çeviri: header/sidebar etiketini anahtara bağlamak
142
149
 
143
150
  Layout'un `views` ağacındaki bir etiketi çeviriye bağlamak için **bütün ağacı yeniden yazma**.
144
- `layout_patch` `set_prop_type` micro-op'unu tanır ve prop'un tipini yerinde değiştirir:
151
+ `layout_schema_patch`'in `set_prop_type` op'u prop'un tipini yerinde değiştirir (`layout_patch` de
152
+ aynı op'u tanır ve JSON Patch ile karışık kabul eder):
145
153
 
146
154
  ```jsonc
147
155
  { "op": "set_prop_type", "target": "app_header_title", "prop": "content",
@@ -151,15 +159,11 @@ Layout'un `views` ağacındaki bir etiketi çeviriye bağlamak için **bütün a
151
159
  - Anahtar **`ref`'te** yaşar, `data`'da değil — runtime `data`'yı her turda çözümlenmiş değerle
152
160
  ezer. `ref` boşsa gateway isteği göndermeden reddeder.
153
161
  - Mevcut statik metin `data`'da yedek olarak KALIR, böylece Studio canvas'ında boş kutu görünmez.
154
- - `set_prop_type` ile JSON Patch aynı `ops` listesinde karışık verilebilir; micro-op'lar önce
155
- uygulanır, sonra patch yolları çözülür.
156
- - Aynı op sayfa tarafında `page_schema_patch` ile çalışır — sözleşme birebir aynıdır. Anahtarları
157
- `translation_list` ile bulun; fallback zinciri ve `t:` doğrulama mesajı sözleşmesi
158
- `platform_guide('translation')`'da.
159
-
160
- > Layout'un diğer micro-op'ları YOKTUR: `add_component`, `remove_component`, `replace_prop` ve
161
- > arkadaşları yalnız sayfa hattındadır. Layout'ta düğüm eklemek/silmek için JSON Patch ya da
162
- > `layout_update` kullanılır.
162
+ - `layout_patch`'te `set_prop_type` ile JSON Patch aynı `ops` listesinde karışık verilebilir;
163
+ micro-op'lar önce uygulanır, sonra patch yolları çözülür.
164
+ - Aynı op sayfa tarafında `page_schema_patch`, widget'ta `component_schema_patch` ile çalışır —
165
+ sözleşme birebir aynıdır. Anahtarları `translation_list` ile bulun; fallback zinciri ve `t:`
166
+ doğrulama mesajı sözleşmesi `platform_guide('translation')`'da.
163
167
 
164
168
  ## Sayfayı layout'a bağlama
165
169
 
@@ -121,7 +121,10 @@ servis formunda görünür ve `microservice_get` outline görünümünde geri ok
121
121
 
122
122
  5. **Doğrulama akışı:** `microservice_preview` (kaydetmeden) → kaydet → `microservice_execute`
123
123
  (gerçek runtime yolu) → sonuç beklenmedikse **aynı parametrelerle `microservice_debug`** —
124
- adım adım executionItems ağacı döner.
124
+ adım adım executionItems ağacı döner. Zamanlanmış (`schedule-job`) uçta sıra farklıdır:
125
+ `workflow_preview` → `microservice_debug` → `microservice_schedule_control` `trigger` →
126
+ `microservice_job_history`; geçmişteki `completed` başarı kanıtı DEĞİLDİR (§Zamanlanmış işin
127
+ gerçek sonucunu görmek).
125
128
  Çağrı parametrelerini (sorgu parametresi, filtre değeri) üst düzey `parameters: { ad: değer }`
126
129
  ile ver; gateway GET'te query-string'e, POST/PUT'ta gövdeye koyar. Değeri NULL bağlanan query
127
130
  parametresini debug yanıtı `unboundParameters` ile söyler — ağaçta o satırın `value` anahtarı
@@ -690,6 +693,57 @@ Yeni işte tanımı `typeParameters.schedule` ile yazın ve kaydetmeden önce
690
693
  `cronExpression`'ı değiştiren PUT/PATCH `422 ScheduleCronConflict` alır — sessizce eski cron
691
694
  kalmaz. `typeParameters: null` işi zamanlayıcıdan siler.
692
695
 
696
+ ### Zamanlanmış işin gerçek sonucunu görmek: geçmiş `failed` yazar, adım izini önizleme verir
697
+
698
+ Zamanlanmış koşu Quartz işi `MicroserviceJob` içinde koşar: `ExecuteAsync(microservice, BOŞ
699
+ parametre)`. 2026-09-16'dan beri iki hata yolu da geçmişe `failed` olarak düşer ve transaction geri
700
+ alınır:
701
+
702
+ | Geçmişte görünen | Gerçekte olan |
703
+ |---|---|
704
+ | `failed`, `errorMessage: "Step 'boom' failed: <sebep>"` | fail dalı bağlanmamış adım patladı; motor `WorkflowStepFailedException` fırlattı |
705
+ | `failed`, `errorMessage: "The job's workflow returned 500 (JavaScriptException): <mesaj>"` | akış bağlı global-error dalından (gateway'in eklediği `gatewayOnError` dâhil) 2xx dışı sonuç döndü; `MicroserviceJob` `ScheduleJobWorkflowFailedException` fırlattı |
706
+ | `failed`, başka mesaj | motor dışı exception: tanım/cache hatası, sonsuz döngü, canlı `revert`, DTO davranış uyumsuzluğu |
707
+ | `completed`, beklenen süre | akış 2xx ile bitti, yazmalar commit edildi — kalıcı etkiyi yine `row_list` ile say |
708
+ | satır yok | koşu veto edildi (deployment/şablon kurulumu sürüyor) ya da zamanlayıcıda kayıt yok — `microservice_schedule_get` |
709
+
710
+ Eski davranış (2026-09-16 öncesi imaj): adım hatası exception değildi; geçmişe `completed` + kısa
711
+ süre + boş `errorMessage` yazılır, yazmalar commit edilirdi — "90 ms'de tamamlandı ama hiçbir şey
712
+ yapmadı". Karşındaki platform hâlâ bunu yapıyorsa imaj eskidir.
713
+
714
+ Dört gerçek daha:
715
+
716
+ - **Geçmiş satırı `{ status, triggeredAt, completedAt, durationMs, errorMessage }`'dan ibarettir.**
717
+ Mesaj patlayan adımı ve sebebini söyler ama adım adım girdi/çıktı vermez; son koşunun adım izini
718
+ döndüren bir MCP aracı **yoktur** (açık backend işi P-19c). Adım izi için aynı tanımı önizlemede
719
+ koştur.
720
+ - **Zamanlanmış koşunun bağlamı boştur:** girdi yok (`MicroserviceExecuteParameter.Create()`),
721
+ middleware koşmaz (`user` yok), `request` yok, `context`/`triggerSource` kurulmaz. Akış
722
+ `input.x`, `user.id`, `request.*`, `context.language` okuyorsa zamanlanmış koşuda hepsi
723
+ `undefined`'dır — önizlemede geçen akış bu yüzden zamanlayıcıda patlayabilir.
724
+ - `microservice_schedule_get` içindeki `lastExecution` aynı geçmiş satırıdır.
725
+ - Geçmiş mesajları resx varsayılanıyla (İngilizce) yazılır; iş iş parçacığında istek dili yoktur.
726
+
727
+ **Sıra — tetiklemeden önce gör** (Studio'daki akış "Önizleme"si + servis önizlemesinin MCP karşılığı):
728
+
729
+ 1. **Akışı `workflow_preview` ile koştur** (`platform_guide('workflow')` §Önizleme çıktısını
730
+ okumak): `workflow_get` gövdesini olduğu gibi ver, **`previewPayload` VERME** — iş girdisiz
731
+ koşar, önizleme de girdisiz koşsun. Akış `parameterDtoId` taşıyorsa zamanlanmış koşuda DTO boş
732
+ bağlanır; zorunlu alanı olan DTO'yu zamanlanmış akışa bağlama. Hata varsa `runtimeErrors` +
733
+ `steps[].hasError` / `errorMessage` / `input[]` patlayan adımı ve sebebini verir.
734
+ 2. **Kayıtlı ucu `microservice_debug` ile koştur:**
735
+ `{ application: '<app slug>', microservice: '<uç slug>', method: 'POST' }` — schedule-job için
736
+ de slug yolu çalışır (tip denetimi yok), rollback'lidir, `httpStatus` akışın kendi sonucudur
737
+ (4xx/5xx'te gateway `runtimeErrors` ekler) ve `executionItems` ağacı adım adım girdi/çıktıyı
738
+ verir. Düğümlerde hata bayrağı yoktur: patlayan adımın `output`'u boştur, hata gövdesi hata
739
+ dalındaki response adımının çıktısındadır. Fark: debug ucun middleware'lerini de koşturur,
740
+ zamanlayıcı koşturmaz.
741
+ 3. **`microservice_preview({ id })`** en kısa "geçer mi" sondasıdır: yanıt `httpStatus` + gövdeden
742
+ ibarettir, adım ağacı DÖNMEZ (`executionItems` yalnız `/debug/` yolunda).
743
+ 4. Ancak sonra `microservice_schedule_control` `trigger` → `microservice_job_history`. `failed`
744
+ ise mesaj patlayan adımı ve sebebini söyler; adım adım girdi/çıktı gerekiyorsa 1-2'ye dön.
745
+ `completed` ise kalıcı etkiyi `row_list` ile say.
746
+
693
747
  ## Sık hatalar
694
748
 
695
749
  - `description` boş (MS-014, block — uç listesinde ne işe yaradığı okunamaz)
@@ -83,7 +83,8 @@ mümkündür ama doğrulama duvarı ve canlı canvas yalnız `page_schema_patch`
83
83
  (applier `code` ve `translation` sarmalını tipiyle korur; gateway 2026-09-15'e kadar translation
84
84
  sarmalını reddediyordu) ya da
85
85
  `{ op: 'set_prop_type', target: '<elementId>', prop: 'content', propType: 'translation', ref: 'dashboard.kpi.total' }`
86
- (gateway emülasyonu; mevcut `data`'yı tasarım yedeği olarak taşır). Taşıyıcı alan tipe göre
86
+ (platformun kendi op'u — 2026-09-14'e kadar gateway emülasyonuydu — ve yamanın geri kalanıyla
87
+ aynı PATCH'te gider; mevcut `data`'yı tasarım yedeği olarak taşır). Taşıyıcı alan tipe göre
87
88
  değişir — `static` değeri `data`'da, `code` ve `translation` `ref`'te taşır; eksik taşıyıcı istek
88
89
  gönderilmeden reddedilir ve `page_schema_validate` aynı kararı verir. Eski yol
89
90
  `remove_component` + `add_component` idi: 2026-09-06 koşusunda on bir etiket bu yolla kuruldu ve
@@ -91,16 +92,19 @@ mümkündür ama doğrulama duvarı ve canlı canvas yalnız `page_schema_patch`
91
92
  `daterangepicker` yer tutucusunu çeviriye bağlarken tekrarlandı — setter hedefi elementId değil
92
93
  komponentin iç kimliğidir (aşağıda Kural 2, `FLOW-018`).
93
94
 
94
- - **`blocks[].size`, komponentin `component_get`'teki `maxSize`'ını aşamaz.** Dikkat: katalog
95
- varsayılanı aşabiliyor (`page-header` default `h:8`, `maxSize` `h:4`) — varsayılanı körü körüne
96
- kopyalama, doğrulayıcı `"Height of 'page-header' must be between 1 and 4."` ile reddeder.
95
+ - **`blocks[].size`'ı komponentin `component_get`'teki `minSize`..`maxSize` aralığında tut.** Dikkat:
96
+ katalog varsayılanı aşabiliyor (`page-header` default `h:8`, `maxSize` `h:4`) — varsayılanı körü
97
+ körüne kopyalama. Sınır grid kanvasının kuralıdır; API 2026-09-15'ten beri reddetmez, ama aşan
98
+ blok kanvasta boyutlandırılamaz (aşağıda Kural 7 "Boyut tuzağı").
97
99
  - **Kurulmuş bir düğümün boyutunu `resize_component` micro-op'u değiştirir.**
98
100
  `{ op: 'resize_component', target: '<elementId>', size: { w, h } }` ızgara boyutunu,
99
101
  `{ …, appearance: { heightType: 'fixed', heightString: '340px' } }` flex ölçüsünü yazar; ikisi
100
- aynı op'ta verilebilir, `breakpoint` varsayılanı 1024'tür. Bu bir **gateway emülasyonudur**:
101
- platformun micro-op sözlüğünde boyut yoktur ve `move_component` gövdesine konan `size` 200 dönüp
102
- SESSİZCE düşer (bu yüzden gateway artık onu reddeder ve buraya yönlendirir). Op şemayı okuyup
103
- sayfayı tam gövdeyle geri yazar. Ebeveynin düzeni yazdığın alanı etkisiz kılıyorsa (flex kabın
102
+ aynı op'ta verilebilir, `breakpoint` varsayılanı 1024'tür. Gateway op'u platformun
103
+ `set_block {target, breakpoint, size}` + `set_appearance {target, appearance}` +
104
+ `set_states {target, states}` op'larına çevirir ve yamanın geri kalanıyla **aynı PATCH'te** yollar
105
+ (o üç op'u doğrudan da gönderebilirsin). `move_component` gövdesine konan `size` gateway'de
106
+ reddedilir ve buraya yönlendirir; konumu belirli bir breakpoint'e yazmak için
107
+ `move_component`'e `breakpoint` ver. Ebeveynin düzeni yazdığın alanı etkisiz kılıyorsa (flex kabın
104
108
  içine `size`, ızgaranın içine `appearance`) yanıt `PAGE-019` uyarısı taşır — istek yine geçer.
105
109
  **Düğümü silip yeniden kurmayın:** o yol ona yazan akış setter'larını sessizce öldürür
106
110
  (`FLOW-018`, aşağıda Kural 2).
@@ -166,8 +170,10 @@ uymayan adı **PAGE-008** ile istek gitmeden reddeder.
166
170
  **Olay KALDIRMAK için `remove_event` kullan.** Platformun `set_event` micro-op'u olay silemez:
167
171
  `eventValue: null` verildiğinde kayıt `{ name: 'click' }` olarak (değersiz) kalır, diziden
168
172
  çıkmaz — şemada ölü bağ artığı bırakır. `{ "op": "remove_event", "target": "<elementId>",
169
- "event": "click" }` gateway emülasyonudur: şemayı okur, olayı diziden çıkarır ve sayfayı tam
170
- gövdeyle geri yazar (yanıtta `removedEvents`). Sayfa düzeyi olaylar için `target: "page"`.
173
+ "event": "click" }` platformun op'udur: olayı diziden çıkarır (yanıtta `removedEvents`); olmayan
174
+ bir olayı kaldırmaya çalışmak `missing-event` ile 422 döner. Sayfa düzeyi olaylar için
175
+ `target: "page"`. Referanssız kalan akış silineceği için `allowFlowDeletion` kuralı (G-21) bu op'ta
176
+ da geçerlidir.
171
177
 
172
178
  **Olay YÜKÜ komponente özeldir ve `component_get` onu da veriyor** (`events[].payload`, gerekirse
173
179
  `events[].reads`) — **ama yük akışa `event.data` ile GELMEZ.** Motor emit'in `data`'sını önce
@@ -610,8 +616,8 @@ Türkçe başlık `props.title` / `props.text` / `props.label` / `props.pageTitl
610
616
  > `elementId` ile eşit tutmazsan `element:` alanı çalışır ama ifadedeki değişken `undefined` kalır.
611
617
  >
612
618
  > Gateway bunu **PAGE-009** ile HER sayfa ve layout yazma yolunda istek gitmeden reddeder:
613
- > `page_create`, `page_update(schema)`, `add_component`, `layout_create`, `layout_update(views)`
614
- > ve `layout_patch`.
619
+ > `page_create`, `page_update(schema)`, `add_component` (sayfa, `layout_schema_patch` ve
620
+ > `component_schema_patch` yamalarında), `layout_create`, `layout_update(views)` ve `layout_patch`.
615
621
 
616
622
  ## Kural 1d — Sayfa iskeleti: `page_container` ve boyutlandırma
617
623
 
@@ -1051,8 +1057,9 @@ UYGULAMAZ** — koordinatları aynen kaydeder (aşağı itme yalnız `page_creat
1051
1057
  > (iç repeater bir kez `item` olmadan da değerlendiriliyor).
1052
1058
  >
1053
1059
  > **Gateway bunu `PAGE-013` ile istek gitmeden reddediyor** — `page_create` / `page_update(schema)` /
1054
- > `layout_create` / `layout_update(views)` / `layout_patch` gönderilen ağaca, `page_schema_patch` hem
1055
- > eklenen alt ağaca hem op'lar UYGULANDIKTAN SONRAKİ ağaca bakarak. Layout'ta da geçerlidir: kırılma
1060
+ > `layout_create` / `layout_update(views)` / `layout_patch` gönderilen ağaca; `page_schema_patch`,
1061
+ > `layout_schema_patch` ve `component_schema_patch` hem eklenen alt ağaca hem op'lar UYGULANDIKTAN
1062
+ > SONRAKİ ağaca bakarak. Layout'ta da geçerlidir: kırılma
1056
1063
  > `_repeaterValues` geri yazmasındadır, barındıranın sayfa mı layout mu olduğuna bakmaz.
1057
1064
  >
1058
1065
  > **Yapılacak:** satır içi listeyi tek bir `textarea`'da **satır başına bir öğe** olarak topla
@@ -1081,6 +1088,12 @@ yapmanın yolu budur — ölçülmüş kurallar (anket-doldur, 2026-08-19):
1081
1088
  > Bu kural TEMA/GÖRSELLİK içindir. Çocukların dizilimi (ortalama, yaslama, aralık, "kalanı
1082
1089
  > doldur") `style` ile değil kapsayıcının kendi `layout` prop grubuyla kurulur — Kural 1f-2.
1083
1090
 
1091
+ > **ÖNCE PROJE TEMASI.** Bir markayı uygulamanın birinci yolu `theme_update`'tir
1092
+ > (`platform_guide('theme')`): tema kaydı BÜTÜN sayfalara iner, `theme_get(view:'resolved')`
1093
+ > hangi değişkenin hangi değeri aldığını söyler. Aşağıdaki `page_container.style` yöntemi
1094
+ > yalnız O SAYFAYA özgü sapma içindir — her sayfada tekrarlanan bir ezme, temaya taşınmamış
1095
+ > bir karardır.
1096
+
1084
1097
  > **Stil anahtarları camelCase'dir: `minHeight`, `fontSize`, `letterSpacing`.** Kebab-case anahtar
1085
1098
  > (`min-height`) platform tarafından KABUL EDİLİR, `page_schema_get` ile aynen geri okunur ve
1086
1099
  > runtime onu HİÇ UYGULAMAZ; tek işaret tarayıcı konsolundaki tek satırdır ve `page_screenshot`
@@ -1141,6 +1154,8 @@ işareti taşıyan input'un **sonraki kardeşini** boya (`&__item-input:checked
1141
1154
  ### 1h-2 — Tema değişkeni envanteri (`Theme.svelte`, tamamı)
1142
1155
 
1143
1156
  Bunlar **runtime'da her sayfada tanımlıdır**; `style` içinde yeniden tanımlayarak eziyorsun.
1157
+ Bir projedeki GÜNCEL değerleri (ve buradaki listenin tamamını) `theme_get(view:'resolved')`
1158
+ `cssVars` alanından okursun — aşağıdaki tablo kümeleri anlatır, değerleri değil.
1144
1159
  Varsayılan palet `white.ts` (accent `#0052CC`, border `#dfe1e6`, text `#262626`) — yani hiçbir şey
1145
1160
  yapmazsan ekran "platform mavisi" görünür; marka rengine çevirmek tek satırdır.
1146
1161
 
@@ -1266,8 +1281,9 @@ kaldırır); sayı `0` "seçilmedi" sayılır.
1266
1281
  tipli grup alanları temayı alan alan EZER; düğümün serbest `style`'ı en üstte SON SÖZDÜR.
1267
1282
  Boyut alanları CSS uzunluğu metnidir (`'18px'`, `'1.2em'`); `radius` tek alanda preset
1268
1283
  anahtarı YA DA CSS uzunluğu kabul eder.
1269
- **Tema preset'i bağlamak:** `style: { $preset: 'card' }` (adlar `project_get` → `theme.presets`;
1270
- `componentStyles[type]` referanssız uygulanır). Bir alanı temaya bırakmak = o alanı hiç yazmamak;
1284
+ **Tema preset'i bağlamak:** `style: { $preset: 'card' }` (adlar `theme_get` → `presets`, sayfa
1285
+ bağlamında `page_runtime_get` → `theme.presets`; `componentStyles[type]` referanssız uygulanır).
1286
+ Preset'in kendisini yazmak/silmek `theme_update` işidir — `platform_guide('theme')`. Bir alanı temaya bırakmak = o alanı hiç yazmamak;
1271
1287
  studio'da bunun adı "Temaya dön"dür. Tema değerini gruba kopyalama — bağ kopar, tema değişince izlemez.
1272
1288
 
1273
1289
  **Efektif stili okumak:** `page_runtime_get(resolveStyles: true)` her düğüme `resolvedStyle`
@@ -1320,12 +1336,14 @@ dokunuldu" sorusunun kanıtı) ve **`newVersion`** (`UpdatedAt.Ticks`).
1320
1336
  > yamadan sonra şemayı okuyup gönderdiğinle karşılaştırarak söyler. Kırpma bu yüzden kanıt kaybı
1321
1337
  > değildir; `view: 'full'`e yalnız gerçekten platformun ham gövdesini incelerken düş.
1322
1338
 
1323
- **Sürüm kontrolü platformda var ama gateway bugün KULLANMIYOR.** Platform gövdede `baseVersion`
1324
- (long tick) kabul eder ve tutmazsa 409 verir; `page_state.baseVersion` bu değeri döner.
1325
- `page_schema_patch` bu alanı geçirmez — bayat plan koruması gateway tarafında
1326
- `expectedUpdatedAt` ile yapılır: sayfa okunur, `audit.updatedAt` karşılaştırılır, tutmazsa istek
1327
- hiç gönderilmez. Bu kontrol **iki çağrı arasına başka bir yazar girerse yakalamaz**; gerçek
1328
- korumayı isteyen ham HTTP ile `baseVersion` göndermelidir.
1339
+ **Sürüm kontrolü `baseVersion` ile yapılır.** `page_schema_get` yanıtı `version` taşır (mikrosaniye,
1340
+ STRING — sayıya çevirme); `page_schema_patch`'e `baseVersion` olarak ver. Sayfa o sürümden beri
1341
+ değiştiyse platform **409** döner ve hiçbir op uygulanmaz; yanıttaki `newVersion` bir sonraki
1342
+ yamanın `baseVersion`'ıdır. Kontrol platformda atomiktir (satır kilidi + sürüm koşulu tek
1343
+ `UPDATE`'te), yani iki çağrı arasına giren yazarı da yakalar. `baseVersion` vermezsen gateway yalnız
1344
+ bu çağrıda zaten okuduğu sayfanın sürümünü gönderir; hiç okumadıysa yama sürümsüz gider ve son
1345
+ yazan kazanır. Eski `expectedUpdatedAt` hâlâ çalışır ama `baseVersion`'ın yerini tutmaz.
1346
+ Yanıttaki `touched`, kaydı değişen elementId'leri listeler (eklenen alt ağaç dâhil).
1329
1347
 
1330
1348
  > **Büyük şemada çalışma sırası:** `mode:'summary'` ile ağacı çıkar (props yok, 500 KB'lık sayfada
1331
1349
  > bile küçük) → hedefin `elementId`'sini al → gerekiyorsa `mode:'subtree'` ile yalnız o dalı oku →
@@ -1340,14 +1358,15 @@ korumayı isteyen ham HTTP ile `baseVersion` göndermelidir.
1340
1358
  > `set_event` ile bağla ya da `flow_get` ile gövdesini yedekle. Ayrıntılı analiz:
1341
1359
  > `PatchPageSchemaCommandHandler` (backend) — kilit, sürüm ve hep-ya-hiç davranışının kaynağı.
1342
1360
 
1343
- ## Kural 3 — Flow yazımı barındırıcıyı da günceller
1361
+ ## Kural 3 — Flow yazımı yalnız akışı yazar, bağ ayrı yamadır
1344
1362
 
1345
- Platform `flow` uçlarında gövdede hem akışı hem barındırıcının tam güncelleme komutunu ister
1346
- (`{ flow, page | layout | component }`) — şemadaki `events[].value` = flow id bağı tek işlemde
1347
- tutarlı kalsın diye. **Silme bile gövdelidir.** Gateway barındırıcıyı okuyup gövdeye kendisi
1348
- koyar; sen yalnız akışı verirsin.
1363
+ 2026-09-14'ten beri `flow_create` / `flow_update` / `flow_delete` barındırıcının şemasına
1364
+ **dokunmaz**: gövde yalnız akıştır (silmede yalnız `id`). Eskiden gateway barındırıcının tam
1365
+ güncelleme komutunu da gönderiyordu; bu, her akış yazmasında sayfayı, layout'u ya da widget'ı
1366
+ baştan yazıyor ve açık bir Studio designer'ının kayıtlı tabanını eskitiyordu.
1349
1367
 
1350
- Akışı bir komponente bağlamak ayrı adımdır:
1368
+ Akışı bir komponente bağlamak ayrı adımdır ve akış kaydedildikten **sonra** yapılır (layout'ta
1369
+ `layout_schema_patch`, widget'ta `component_schema_patch`, op'lar aynı):
1351
1370
 
1352
1371
  ```
1353
1372
  flow_create(host:'page', hostId:<pageId>, name:'Save order', slug:'save-order', steps:[…])
@@ -1389,18 +1408,13 @@ Sonradan akış eklemen gerekirse sayfayı baştan kurmana gerek yok — **bağ
1389
1408
  `eventValue: null` olay kaydını bırakıp değerini boşaltır ve kilidi açar.
1390
1409
 
1391
1410
  > **Aynı kilit LAYOUT'ta da vardır** (ölçüm 2026-08-18: menüye yeni bağlantı eklerken
1392
- > `POST /layouts/<id>/flows` aynı hatayı verdi). Layout'un olayları komponentin kendi `events`
1393
- > dizisinde satır içidir (`{ "name": "click", "value": "<flow id>" }`) ve `page_schema_patch`
1394
- > layout'a uygulanmaz; çözüm de bu yüzden farklı yazılır:
1395
- >
1396
- > ```
1397
- > 1) layout_update → tüm komponentlerde "events": [] (bağları çöz)
1398
- > 2) flow_create × N
1399
- > 3) layout_update → tam ağaç + bütün events'ler
1400
- > ```
1411
+ > `POST /layouts/<id>/flows` aynı hatayı verdi). Layout'ta sıra sayfadakiyle aynıdır ve bağlar
1412
+ > `layout_schema_patch` ile yazılır: `flow_create × N` → TEK `layout_schema_patch` (bütün
1413
+ > `set_event`'ler). Sıfırdan kurarken kilide takılmazsın (akışları bağlamadan önce yaratırsın).
1401
1414
  >
1402
- > Sıfırdan kurarken kilide takılmazsın (akışları bağlamadan önce yaratırsın); kilit yalnız
1403
- > **mevcut ve bağlı** bir layout'a yeni akış eklerken çıkar.
1415
+ > **Yeniden ölçülmeli (2026-09-14):** iki ölçüm de flow isteğinin barındırıcıyı baştan yazdığı
1416
+ > dönemdendi. Zarfsız istekte barındırıcı yazılmadığı için kilit kalkmış olabilir; ölçülene kadar
1417
+ > kuruluş sırasını koru.
1404
1418
 
1405
1419
  ## Kural 4 — Komponent güncellemesi slug ile, silme id ile
1406
1420
 
@@ -1587,9 +1601,11 @@ de silip yeniden ekleme gerekmez:
1587
1601
  { "op": "set_appearance", "target": "box_summary", "appearance": { "heightType": "auto", "tooltip": null } }
1588
1602
  ```
1589
1603
 
1590
- Op **birleştirir**: yalnız verilen alanları yazar, gerisini korur; `null` alanı temizler. Alan
1591
- adları `page_schema_get`'in döndürdüğü appearance anahtarlarıdır; bilinmeyen alan
1592
- `unknown-appearance-field`, tanınmayan enum değeri (`heightType: "tall"`) 400 ile reddedilir.
1604
+ Op **birleştirir**: yalnız verilen alanları yazar, gerisini korur; `null` alanı temizler (null
1605
+ kabul etmeyen `heightType` gibi alanlar hariç). Alan adları `page_schema_get`'in döndürdüğü
1606
+ appearance anahtarlarıdır; bilinmeyen alan `unknown-appearance-field`, tanınmayan ya da null
1607
+ kabul etmeyen değer (`heightType: "tall"`) `invalid-appearance` ile 422 döner ve yama atomik
1608
+ olduğu için hiçbir op yazılmaz. Kurulu düğümün `states` bayrakları için eşi `set_states`'tir.
1593
1609
  **`isHidden` bir appearance alanı DEĞİLDİR** — gizlemek için `replace_prop { prop: 'isHidden' }`
1594
1610
  ya da `set_binding { prop: 'isHidden' }` (Kural 7a'daki `isHidden` notu).
1595
1611
 
@@ -1833,8 +1849,9 @@ Komponentlerin **`style` prop'u** vardır ve iç parçalara iner (`textinput.sty
1833
1849
  `&__body`). Tasarım kararlarını buradan uygula — varsayılan görünümle bırakmak zorunda değilsin.
1834
1850
 
1835
1851
  > **Boyut tuzağı:** katalog varsayılan `size`'ı `maxSize`'ı aşan komponentler var
1836
- > (`textinput` default `h:8`, `maxSize.h:5`). Varsayılanı körü körüne kopyalarsan doğrulayıcı
1837
- > reddeder; gateway aşan değeri `maxSize`'a kırpar ve `gatewayNormalized` ile bildirir.
1852
+ > (`textinput` default `h:8`, `maxSize.h:5`). Boyut sınırı grid kanvasının kuralıdır, API
1853
+ > reddetmez; ama aşan blok kanvasta boyutlandırılamaz. Gateway aşan değeri `maxSize`'a kırpar ve
1854
+ > `gatewayNormalized` ile bildirir.
1838
1855
 
1839
1856
  ## Kural 8 — Korunan sayfa: `middlewareIds` vermeden `Page.user` YOKTUR
1840
1857
 
@@ -1895,6 +1912,32 @@ hiçbiri** bağlı değildi; üç portalın da rol menüsü boş çıkıyor, pan
1895
1912
  > `Host: <org>.<suffix>` + `X-Environment` başlıklarıyla. Ham `curl` yerine tool'u kullanmak
1896
1913
  > yeterlidir.
1897
1914
  >
1915
+ > **Kareyi GÖRMEDEN doğrulamak — önce bunu dene.** `page_screenshot` her yanıtta `summaryText`
1916
+ > döner: her kök düğüm için tek satır — kimlik (tip) · görünür/GİZLİ/ekran dışı · metnin ilk 80
1917
+ > karakteri · `rows=<satır>` · `tab=<açık sekme>` · `value=<kutudaki değer>` · `BOŞ` ·
1918
+ > `errors=<sayı>`, sonda toast ve hata mesajları. "Kart göründü mü, tablo doldu mu, hata var mı"
1919
+ > sorularının cevabı budur ve **kareye gerek yoktur**: `image: 'none'` ile kare hiç çekilmez.
1920
+ > Ölçüldü (2026-09-16, 40 satırlık tablo taşıyan sayfa): özet **416** karakter, aynı sayfanın
1921
+ > `fullPage` karesi **151 276** karakter. Görsel soru (renk, hizalama, referansa sadakat) için
1922
+ > kareyi al ama küçült: `clip: { element: '<elementId>' }` yalnız o bölgeyi keser, `scale: 0.5`
1923
+ > rasteri yarıya indirir (sayfa yine 1280 CSS pikselinde çizilir — kırılım noktaları kaymaz),
1924
+ > `format: 'jpeg'` + `quality: 60` ölçekle BİRLİKTE kazandırır (tek başına neredeyse hiç).
1925
+ > Aynı sayfayı yeniden koştururken `diff: true` neyin değiştiğini listeler ve
1926
+ > `image: 'ifChanged'` değişmemiş kareyi hiç göndermez. `summary: 'full'` yapısal `domSummary`
1927
+ > dizisini de verir; runtime `data-component-type` basmıyorsa tipler yazılmaz ve `summaryNote`
1928
+ > bunu söyler.
1929
+ >
1930
+ > **Sekme, açılır kutu, form.** `actions` sözlüğünde üç fiil daha var.
1931
+ > `{ action: 'tab', target: 'tabs_settings', value: 'iot' }` sekmeyi ANAHTARIYLA seçer — sekme
1932
+ > grubunun köküne `click` göndermek DOM sırasındaki İLK sekmeye gider ve bu yüzden artık
1933
+ > reddedilir. **Etkin olmayan sekmenin içeriği DOM'da yoktur**: o sekmedeki bir düğüme yazmadan
1934
+ > ya da onu kırpmadan önce `tab` adımı koy. `{ action: 'select', target: 'dd_city', value: '34' }`
1935
+ > açılır kutudan seçer (kutu native alan değildir; `set` de aynı yola devreder) ve seçenekler
1936
+ > sorgudan geliyorsa listeyi 3 sn'ye kadar bekler — `optionsSeen: 0` görürsen kusur kutuda değil
1937
+ > sorgudadır, `query_preview` ile bak. `{ action: 'submit', target: 'frm_note' }` formu gönder
1938
+ > butonu olmadan gönderir. Her adımın raporu `matchedBy` · `activeTab` · `optionsSeen` ·
1939
+ > `waitedMs` · `submitVia` ile ne olduğunu söyler.
1940
+ >
1898
1941
  > **Yerleşimi görüntüsüz ölçmek.** Taşma/çakışma şüphesinde `page_screenshot(layoutReport: true)`:
1899
1942
  > `layoutSummary.overflowing` boş değilse içeriğine sığmayan kutu, `outsideViewport` boş değilse
1900
1943
  > hiç görünmeyen düğüm var; `zeroSized` çizilmemiş komponenti gösterir. Runtime düğümleri