@appaflytech/zeyrek-ai-mcp 0.0.33 → 0.0.34

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 (169) hide show
  1. package/.env.example +0 -15
  2. package/dist/config.js +0 -11
  3. package/dist/index.js +0 -2
  4. package/dist/knowledge/boxSections.js +184 -0
  5. package/dist/knowledge/componentCatalog.js +248 -108
  6. package/dist/knowledge/componentEvents.js +22 -24
  7. package/dist/knowledge/layoutSummary.js +2 -140
  8. package/dist/knowledge/normalize.js +126 -117
  9. package/dist/knowledge/rules.js +19 -291
  10. package/dist/knowledge/styleResolve.js +38 -55
  11. package/dist/knowledge/themeResolve.js +3 -3
  12. package/dist/observability/trace.js +1 -1
  13. package/dist/platform/diagnostics.js +4 -10
  14. package/dist/platform/domSummary.js +1 -1
  15. package/dist/platform/http.js +7 -23
  16. package/dist/platform/responses.js +2 -6
  17. package/dist/platform/screenshot.js +1162 -0
  18. package/dist/platform/secrets.js +0 -9
  19. package/dist/platform/strictArguments.js +12 -68
  20. package/dist/platform/tokenVault.js +4 -187
  21. package/dist/resources/examples/layout-app-shell.json +707 -229
  22. package/dist/resources/examples/page-flex-sections.json +1 -1
  23. package/dist/resources/guides/component.md +5 -13
  24. package/dist/resources/guides/entity.md +5 -3
  25. package/dist/resources/guides/expressions.md +5 -14
  26. package/dist/resources/guides/functions.md +1 -1
  27. package/dist/resources/guides/layout.md +58 -55
  28. package/dist/resources/guides/microservice.md +2 -9
  29. package/dist/resources/guides/middleware.md +2 -34
  30. package/dist/resources/guides/page.md +171 -256
  31. package/dist/resources/guides/theme.md +2 -8
  32. package/dist/resources/guides/translation.md +1 -1
  33. package/dist/resources/guides/workflow.md +1 -7
  34. package/dist/resources/schema-fingerprint.json +4 -4
  35. package/dist/resources/schemas/GlobalFunctionUpdateResultDto.json +1 -3
  36. package/dist/resources/schemas/MicroserviceDto.json +2 -2
  37. package/dist/server.js +1 -7
  38. package/dist/tools/applications.js +3 -60
  39. package/dist/tools/components.js +16 -103
  40. package/dist/tools/datasources.js +1 -1
  41. package/dist/tools/designSchemaPatch.js +19 -23
  42. package/dist/tools/externalComponents.js +4 -25
  43. package/dist/tools/flows.js +6 -79
  44. package/dist/tools/layouts.js +20 -48
  45. package/dist/tools/microservices.js +10 -32
  46. package/dist/tools/pages.js +115 -396
  47. package/dist/tools/platformInfo.js +2 -7
  48. package/dist/tools/rows.js +1 -7
  49. package/dist/tools/schemaOps.js +4 -35
  50. package/dist/tools/screenWrite.js +37 -25
  51. package/dist/tools/screens.js +4 -91
  52. package/dist/tools/variables.js +5 -11
  53. package/package.json +2 -2
  54. package/dist/knowledge/access.js +0 -802
  55. package/dist/knowledge/case.js +0 -41
  56. package/dist/knowledge/connectDataBind.js +0 -819
  57. package/dist/knowledge/connectDataDefinition.js +0 -341
  58. package/dist/knowledge/connectDataExecute.js +0 -93
  59. package/dist/knowledge/connectDataRules.js +0 -128
  60. package/dist/knowledge/decision.js +0 -121
  61. package/dist/knowledge/expressionPrelude.js +0 -59
  62. package/dist/knowledge/microserviceParameters.js +0 -58
  63. package/dist/knowledge/mining.js +0 -94
  64. package/dist/knowledge/mobileComponentCatalog.js +0 -864
  65. package/dist/knowledge/mobileComponentEvents.js +0 -239
  66. package/dist/knowledge/mobileStore.js +0 -227
  67. package/dist/knowledge/platform/lint.js +0 -385
  68. package/dist/knowledge/platform/mobile.js +0 -142
  69. package/dist/knowledge/platform/mobileLayoutLint.js +0 -324
  70. package/dist/knowledge/platform/mobileRules.js +0 -231
  71. package/dist/knowledge/platform/mobileSpacing.js +0 -82
  72. package/dist/knowledge/platform/mobileTabs.js +0 -108
  73. package/dist/knowledge/platform/nativeBoxModel.js +0 -44
  74. package/dist/knowledge/platform/profile.js +0 -25
  75. package/dist/knowledge/platform/resolve.js +0 -122
  76. package/dist/knowledge/platform/web.js +0 -39
  77. package/dist/knowledge/process.js +0 -510
  78. package/dist/knowledge/rowFilter.js +0 -43
  79. package/dist/knowledge/styleResolveNative.js +0 -527
  80. package/dist/platform/argumentAliases.js +0 -128
  81. package/dist/platform/bodyFile.js +0 -103
  82. package/dist/platform/capture/actions.js +0 -333
  83. package/dist/platform/capture/browser.js +0 -1
  84. package/dist/platform/capture/capture.js +0 -659
  85. package/dist/platform/capture/console-log.js +0 -122
  86. package/dist/platform/capture/index.js +0 -11
  87. package/dist/platform/capture/readiness.js +0 -103
  88. package/dist/platform/capture/summary.js +0 -77
  89. package/dist/platform/capture/target.js +0 -5
  90. package/dist/platform/capture/targets/studio-mobile.js +0 -15
  91. package/dist/platform/capture/targets/studio-web.js +0 -5
  92. package/dist/platform/impersonation.js +0 -45
  93. package/dist/platform/jsonArray.js +0 -24
  94. package/dist/platform/schemaReadMemory.js +0 -60
  95. package/dist/resources/examples/bpm-gorev-kontrol.json +0 -294
  96. package/dist/resources/examples/bpm-iso-dokuman.json +0 -228
  97. package/dist/resources/examples/bpm-satinalma.json +0 -376
  98. package/dist/resources/examples/connect-data-convert-verify.json +0 -107
  99. package/dist/resources/examples/connect-data-dropdown-roles.json +0 -66
  100. package/dist/resources/examples/connect-data-edit-m2m.json +0 -73
  101. package/dist/resources/examples/connect-data-query-params.json +0 -50
  102. package/dist/resources/examples/connect-data-table-entity.json +0 -147
  103. package/dist/resources/examples/connect-data-workflow-microservice.json +0 -65
  104. package/dist/resources/examples/mobile-app-shell-drawer.json +0 -244
  105. package/dist/resources/examples/mobile-app-shell-stack.json +0 -157
  106. package/dist/resources/examples/mobile-app-shell-tab.json +0 -208
  107. package/dist/resources/examples/mobile-form-screen.json +0 -365
  108. package/dist/resources/examples/mobile-list-detail-form.json +0 -703
  109. package/dist/resources/guides/access.md +0 -796
  110. package/dist/resources/guides/bpm.md +0 -686
  111. package/dist/resources/guides/case.md +0 -153
  112. package/dist/resources/guides/decision.md +0 -185
  113. package/dist/resources/guides/mobile-layout.md +0 -193
  114. package/dist/resources/guides/mobile.md +0 -578
  115. package/dist/resources/read.js +0 -41
  116. package/dist/resources/schemas/AccessExplanationDto.json +0 -144
  117. package/dist/resources/schemas/AccessMatrixDto.json +0 -170
  118. package/dist/resources/schemas/AccessPermissionDto.json +0 -57
  119. package/dist/resources/schemas/AccessPolicyDto.json +0 -223
  120. package/dist/resources/schemas/AccessResourceDto.json +0 -86
  121. package/dist/resources/schemas/AppSessionDto.json +0 -53
  122. package/dist/resources/schemas/ConnectDataDescribeDto.json +0 -344
  123. package/dist/resources/schemas/ConnectDataRequestModel.json +0 -202
  124. package/dist/resources/schemas/ConnectDataResultDto.json +0 -421
  125. package/dist/resources/schemas/ConnectorCredentialDto.json +0 -70
  126. package/dist/resources/schemas/ConvertConnectDataToMicroserviceCommand.json +0 -37
  127. package/dist/resources/schemas/CreateAccessPolicyCommand.json +0 -209
  128. package/dist/resources/schemas/CreateDecisionCommand.json +0 -221
  129. package/dist/resources/schemas/CreateProcessDefinitionCommand.json +0 -1337
  130. package/dist/resources/schemas/DecisionDto.json +0 -302
  131. package/dist/resources/schemas/DetachConnectDataMicroserviceCommand.json +0 -28
  132. package/dist/resources/schemas/ExplainAccessQuery.json +0 -33
  133. package/dist/resources/schemas/GenerateProcessDocumentCommand.json +0 -116
  134. package/dist/resources/schemas/OrganizationProjectDto.json +0 -335
  135. package/dist/resources/schemas/OrganizationSchemaDto.json +0 -196
  136. package/dist/resources/schemas/OrganizationSchemaVersionDto.json +0 -207
  137. package/dist/resources/schemas/PatchProcessDefinitionCommand.json +0 -76
  138. package/dist/resources/schemas/ProcessDefinitionDto.json +0 -1480
  139. package/dist/resources/schemas/ProcessSimulationDto.json +0 -96
  140. package/dist/resources/schemas/SaveConnectorCredentialCommand.json +0 -90
  141. package/dist/resources/schemas/SaveProcessEventSourceCommand.json +0 -61
  142. package/dist/resources/schemas/SaveProcessMailSourceCommand.json +0 -89
  143. package/dist/resources/schemas/SignProcessTaskCommand.json +0 -73
  144. package/dist/resources/schemas/SimulateProcessDefinitionQuery.json +0 -92
  145. package/dist/resources/schemas/StartMobileBuildCommand.json +0 -54
  146. package/dist/resources/schemas/UpdateAccessPolicyCommand.json +0 -209
  147. package/dist/resources/schemas/UpdateDecisionCommand.json +0 -216
  148. package/dist/resources/schemas/UpdateProcessDefinitionCommand.json +0 -1357
  149. package/dist/resources/schemas/UpsertMobileStoreSettingsCommand.json +0 -259
  150. package/dist/resources/schemas/ValidateProcessDefinitionQuery.json +0 -1339
  151. package/dist/tools/accessOperations.js +0 -135
  152. package/dist/tools/accessPolicies.js +0 -170
  153. package/dist/tools/accessRuntime.js +0 -203
  154. package/dist/tools/bpm.js +0 -343
  155. package/dist/tools/bpmGovernance.js +0 -266
  156. package/dist/tools/bpmOperations.js +0 -230
  157. package/dist/tools/bpmReporting.js +0 -154
  158. package/dist/tools/bpmRouting.js +0 -150
  159. package/dist/tools/bpmRuntime.js +0 -396
  160. package/dist/tools/case.js +0 -178
  161. package/dist/tools/caseRuntime.js +0 -89
  162. package/dist/tools/connectData.js +0 -449
  163. package/dist/tools/connectors.js +0 -193
  164. package/dist/tools/decisions.js +0 -206
  165. package/dist/tools/mobile.js +0 -221
  166. package/dist/tools/mobileStore.js +0 -268
  167. package/dist/tools/modules.js +0 -48
  168. package/dist/tools/organizationStructure.js +0 -137
  169. package/dist/tools/profileWrite.js +0 -92
@@ -5,7 +5,6 @@ import { headersAccessNames, isHeadersAccessGuarded } from './flowGuards.js';
5
5
  import { callsItself, functionCallRefs, isValidParameterName, mentionsAwait, nameProblem, sourceOf, callPrefix } from './functionGuards.js';
6
6
  import { backendPolicyRules } from './backendConstraints.js';
7
7
  import { themePolicyRules } from './themeRules.js';
8
- import { mobileStorePolicyRules } from './mobileStore.js';
9
8
  const terminalStepTypes = new Set(['response', 'convert', 'revert']);
10
9
  const DESCRIPTION_EXEMPT_STEPS = new Set(['start']);
11
10
  const stepKindMatrix = {
@@ -147,21 +146,13 @@ export function readsBeforeGuard(source, root) {
147
146
  * code.ts:49). Eşleşme yoksa flow-engine.ts:79 sessizce durur. Studio tarafında da zincir
148
147
  * `sourceBranch === 'always'` ile çizilir (EventActionsStart.svelte:47, EventActionsItem.svelte:298).
149
148
  * condition dalları rule id'sidir (serbest), microservice'te 'success' yalnız eski şema için
150
- * yaşatılır (microservice.ts:174 `isHasSuccess`). 'error' dalı 2026-09-26'dan beri motorun
151
- * KENDİSİ tanır (ADR 0004, ZM-07/g-02): bağlıysa hata anında `always` hiç koşmaz, sürer
152
- * (microservice.ts:182 `hasBranch`) — eski motor tanımadığı dalı hiç aramadığı için bu ekleme
153
- * geriye dönük zararsızdır.
149
+ * yaşatılır (microservice.ts:144).
154
150
  */
155
151
  const flowBranchNames = {
156
152
  start: ['always'],
157
- microservice: ['always', 'success', 'error'],
153
+ microservice: ['always', 'success'],
158
154
  confirm: ['yes', 'no', 'always'],
159
155
  function: ['always'],
160
- haptic: ['always'],
161
- location: ['always', 'error'],
162
- 'notification-permission': ['always'],
163
- 'notification-schedule': ['always', 'error'],
164
- 'notification-cancel': ['always'],
165
156
  end: []
166
157
  };
167
158
  /**
@@ -172,16 +163,8 @@ const flowBranchNames = {
172
163
  */
173
164
  export const knownFlowStepTypes = new Set([
174
165
  'start', 'end', 'query', 'setter', 'download', 'condition', 'redirect', 'setcookie', 'alert', 'confirm',
175
- 'microservice', 'validation', 'flow-trigger', 'storage', 'navigate', 'code', 'function', 'share',
176
- 'haptic', 'location', 'notification-permission', 'notification-schedule', 'notification-cancel'
166
+ 'microservice', 'validation', 'flow-trigger', 'storage', 'navigate', 'code', 'function'
177
167
  ]);
178
- /**
179
- * Cihaz yeteneği adımlarının kapalı kümeleri — `@ng-apps/flow` `tasks/device/device.functions.ts`
180
- * `HAPTIC_STYLES`/`LOCATION_ACCURACIES`'in aynası (`test/flow-step-parity.test.ts` bağlar); backend
181
- * `FlowDtoValidator` aynı kümeyle 400 döner. Kök `docs/adr/0003-cihaz-yetenegi-adimlari.md`.
182
- */
183
- export const hapticStyles = new Set(['success', 'warning', 'error', 'light', 'medium', 'heavy', 'selection']);
184
- export const locationAccuracies = new Set(['low', 'balanced', 'high']);
185
168
  const flowFreeBranchTypes = new Set(['condition']);
186
169
  /** `condition.types.ts` ConditionArgumentRuleType — motorun tanıdığı üçlü. */
187
170
  const conditionRuleTypes = new Set(['if', 'else-if', 'else']);
@@ -193,17 +176,16 @@ const conditionRuleIdPattern = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}
193
176
  // Runtime.svelte'de HAM verilir (`argument: step.args`), yani bu alanlarda ifade değerlendirilmez.
194
177
  const flowLiteralTextFields = new Map([
195
178
  ['alert', ['message', 'description']],
196
- ['confirm', ['message', 'title', 'confirmText', 'cancelText']],
197
- ['share', ['title']],
198
- ['notification-schedule', ['name', 'title', 'path']],
199
- ['notification-cancel', ['name']]
179
+ ['confirm', ['message', 'title', 'confirmText', 'cancelText']]
200
180
  ]);
201
181
  const flowExpressionLooking = /\$\{|\b(?:Steps|Page|Row|Widget|LocalStorage|state|self|item|event|error|cookie)\s*(?:\?\.|\.|\[)/;
202
- // Barındırıcıya özel tipler BURADA kural üretmez. `navigate`i gateway normalizasyonu zaten
203
- // `redirect`e çeviriyor (normalize.ts `normalizeFlowHostGaps`) — `redirect` iki barındırıcıda da
204
- // koşar, yani vaka uyarılmaz, ORTADAN KALKAR. Gateway uygulamanın tipini platform profilinden bilir
205
- // ve barındırıcı sözlüğü `platform/*.ts`'tedir (`profile.steps`); mobil farkları orada `MOB-005`
206
- // olarak konuşulur (`platform/lint.ts`). Yeni mobil runtime `confirm`/`download`'ı kaydeder.
182
+ // Barındırıcıya özel tipler (`navigate` web'de, `confirm`/`download` mobilde register edilmez)
183
+ // BURADA kural üretmez. `navigate`i gateway normalizasyonu zaten `redirect`e çeviriyor
184
+ // (normalize.ts `normalizeFlowHostGaps`) — `redirect` iki barındırıcıda da koşar, yani vaka
185
+ // uyarılmaz, ORTADAN KALKAR. Geriye kalan `confirm`/`download` tek başına kusur değildir: sayfa
186
+ // tek bir uygulamaya aittir (`Page.ApplicationId`), uygulamanın tipi web ya da mobile'dır
187
+ // (`ApplicationType.cs`) ve gateway hangisi olduğunu bilmez. Mobil ayağı uygulama tarafında
188
+ // kapanır (`ScreenRuntime.tsx`), lint'te değil.
207
189
  const flowUnregisteredStepTypes = new Set(['end', 'query']);
208
190
  const flowSetterIterateeTypes = new Set(['change', 'fill']);
209
191
  function flowStepList(value) {
@@ -323,71 +305,25 @@ function writesRolesWithoutSlug(entityId, parameters) {
323
305
  }
324
306
  const rolesSlugMessage = "Built-in 'roles' entity'sine slug YAZMADAN rol satırı ÜRETİLİYOR (operation create/upsert). Insert 200 döner, satır role_list'te görünür ve page.roleIds ile bağlanır — ama yetkilendirme SLUG karşılaştırır: platformun get-user sorgusu roles+user_roles join'inden slug dizisi üretir ve Authorized(user.roles) o rol için hiçbir zaman tutmaz. fields'a slug'ı ekleyin ('super-admin' slug'ını vermeyin — platform süper yöneticiyi o slug ile arar). Upsert'te slug'ı İFADEYLE üretmeyin: UPDATE yolunda ifade yeniden değerlendirilir ve var olan rolün slug'ı sessizce değişir (MS-016) — üretilen slug'ı yalnız create ucunda yazın. Rolü kullanıcıya bağlamak ayrı bir user_roles satırıdır.";
325
307
  const contractKeys = ['returnDtoId', 'parameterDtoId', 'returnBehavior', 'parameterBehavior'];
326
- /**
327
- * Filtre işleci sözlüğü — backend `OperatorType` enum'u (paketlenmiş `Filter` şeması; eşitliği
328
- * `test/filter-operators.test.ts` kilitler). Studio filtre ARAYÜZÜNÜN sözlüğü (`notContains`, `between`…,
329
- * `componentCatalog.ts`) ayrı bir kavramdır: arayüz onları bu işleçlere çevirir.
330
- */
331
- export const filterOperators = new Set(['eq', 'neq', 'lt', 'lte', 'gt', 'gte', 'contains', 'icontains', 'in', 'notin', 'startswith', 'endswith', 'istartswith', 'iendswith', 'isnull', 'isnotnull']);
332
- /** Ajanların sık yazdığı yanlış adlar → doğru işleç. Yalnız ÖNERİLİR, sessizce çevrilmez. */
333
- const filterOperatorSuggestions = {
334
- ne: 'neq', '!=': 'neq', '<>': 'neq', noteq: 'neq', notequal: 'neq', notequals: 'neq', not_eq: 'neq',
335
- '=': 'eq', '==': 'eq', equal: 'eq', equals: 'eq',
336
- '<': 'lt', '<=': 'lte', '>': 'gt', '>=': 'gte',
337
- like: 'contains', ilike: 'icontains', nin: 'notin', 'not in': 'notin', not_in: 'notin'
338
- };
308
+ const filterOperators = new Set(['eq', 'neq', 'lt', 'lte', 'gt', 'gte', 'contains', 'icontains', 'in', 'notin', 'startswith', 'endswith', 'istartswith', 'iendswith', 'isnull', 'isnotnull']);
339
309
  function flattenFilterTree(filters) {
340
310
  return filters
341
311
  .filter((filter) => Boolean(filter) && typeof filter === 'object')
342
312
  .flatMap(filter => [filter, ...flattenFilterTree(asArray(filter.children))]);
343
313
  }
344
- /**
345
- * Bilinmeyen işleçler, öneriyle: `status: 'ne' (neq mı demek istedin?)`. Grup çocukları da okunur. Ad
346
- * büyük/küçük harfe DUYARLI eşlenir — backend de öyle eşler (`GetValueFromDescription` `==`); `NEQ`
347
- * bilinmeyendir ve küçük harfli adı önerilir.
348
- */
349
- function unknownFilterOperators(filters) {
350
- return flattenFilterTree(filters)
351
- .filter(filter => filter.operator !== undefined && filter.operator !== null && !filterOperators.has(String(filter.operator)))
352
- .map(filter => {
353
- const operator = String(filter.operator);
354
- const lower = operator.toLowerCase();
355
- const suggestion = filterOperators.has(lower) ? lower : filterOperatorSuggestions[lower];
356
- return `${String(filter.fieldSlug ?? filter.fieldId ?? '?')}: '${operator}'${suggestion ? ` (${suggestion} mı demek istedin?)` : ''}`;
357
- });
358
- }
359
- const unknownOperatorConsequence = "Bilinmeyen işleç yola ve backend sürümüne göre ya 400 alır ya sessizce 'eq'e düşer ve sorgu yanlış sonuç döner (2026-09-27'den sonraki backend uç çağrısının `filters` parametresini 400 ile reddeder; workflow tablo adımı hâlâ sessizce 'eq' yapar); ad büyük/küçük harfe duyarlıdır — doğru işleci yazın";
360
314
  function unknownOperatorFindings(ruleId, owner, filters) {
361
- const unknownOperators = unknownFilterOperators(filters);
315
+ const unknownOperators = flattenFilterTree(filters)
316
+ .filter(filter => filter.operator !== undefined && filter.operator !== null && !filterOperators.has(String(filter.operator).toLowerCase()))
317
+ .map(filter => `${String(filter.fieldSlug ?? filter.fieldId ?? '?')}: '${String(filter.operator)}'`);
362
318
  return unknownOperators.length > 0
363
319
  ? [{
364
320
  ruleId,
365
321
  severity: 'block',
366
- message: `${owner}: bilinmeyen filtre işleci — ${unknownOperators.join(', ')}. ${unknownOperatorConsequence}. Geçerli sözlük: ${[...filterOperators].join(' · ')} ('like' yok — metin araması için 'contains'/'icontains').`,
322
+ message: `${owner}: bilinmeyen filtre operatörü — ${unknownOperators.join(', ')}. Platform bilinmeyen operatörü 400 ile REDDETMEZ, sessizce 'eq'e düşürür (EnumExtensions.GetValueFromDescription null → default) ve uç testten geçip yanlış çalışır. Geçerli sözlük: ${[...filterOperators].join(' · ')} ('like' yok — metin araması için 'contains'/'icontains').`,
367
323
  guide: 'ngapps://guides/microservice'
368
324
  }]
369
325
  : [];
370
326
  }
371
- /**
372
- * Çalışma anında gelen filtre (`row_list.filters`, `microservice_execute` `filters` parametresi): dizi ya
373
- * da JSON dizesi. Bilinmeyen işleç varsa hata METNİ döner — araç isteği göndermeden 400 verir
374
- * (plans/mobil-plantcare-acigi g-03). Ayrıştırılamayan değer backend'e bırakılır.
375
- */
376
- export function filterOperatorError(owner, filters) {
377
- let parsed = filters;
378
- if (typeof filters === 'string') {
379
- try {
380
- parsed = JSON.parse(filters);
381
- }
382
- catch {
383
- return undefined;
384
- }
385
- }
386
- const unknownOperators = Array.isArray(parsed) ? unknownFilterOperators(parsed) : [];
387
- return unknownOperators.length > 0
388
- ? `${owner}: bilinmeyen filtre işleci — ${unknownOperators.join(', ')}. İstek GÖNDERİLMEDİ. ${unknownOperatorConsequence}. Geçerli sözlük: ${[...filterOperators].join(' · ')}.`
389
- : undefined;
390
- }
391
327
  function isReadOperation(parameters) {
392
328
  const operation = String(parameters?.operation ?? '').toLowerCase();
393
329
  return !writeOperations.has(operation);
@@ -2315,48 +2251,6 @@ export const policyRules = [
2315
2251
  }];
2316
2252
  })
2317
2253
  },
2318
- {
2319
- id: 'FLOW-028',
2320
- module: 'flow',
2321
- appliesTo: ['create', 'update'],
2322
- sourceRef: "Yetki şablonu (access.json 1.7.0) 33 kod adımında platformun oturum uçlarına ham fetch atıyordu ('/api/' + project + '/runtime/' + application + '/auth/me' ve '/auth/sign-in'). Ham istek ng-apps-flow/src/api/instance.ts'in yaptıklarını atlar: X-Environment çözümü (resolveRuntimeEnvironment; elle ayrıştırma /preview şeridinde index -1 verir), CSRF başlığı (çerezli POST 403 CsrfTokenMismatchException — S2-37 · S3-7), 401'de tek refresh + yeniden deneme, ve ExecuteMicroserviceBehavior'ın microservice.execute kararı ile gölge günlüğü. Düzeltme 2026-09-22: giriş ve oturum bilgisi access.session.create / access.session.get system operation'larına taşındı (backend ADR 0004); çıkış 2026-10-01'de access.session.delete ile eklendi. Dış API'ye fetch meşrudur; kural yalnız göreli platform yollarını (/api/, /m/, /runtime/) görür",
2323
- check: definition => flowAllSteps(definition)
2324
- .filter(step => step.type === 'code')
2325
- .flatMap((step) => {
2326
- const body = String((step.args ?? {}).value ?? '');
2327
- if (!/\bfetch\s*\(|XMLHttpRequest/.test(body) || !/['"`]\/(api|m|runtime)\/|\/runtime\//.test(body))
2328
- return [];
2329
- return [{
2330
- ruleId: 'FLOW-028',
2331
- severity: 'warn',
2332
- message: `'${flowStepLabel(step)}' code adımı platformun kendi ucuna ham istek atıyor. Bu yol runtime'ın istek katmanını atlar: X-Environment elle kurulur, CSRF başlığı yoktur (çerezli POST 403 CsrfTokenMismatchException), 401'de oturum yenilenmez ve istek microservice.execute kararını ve gölge günlüğünü hiç görmez. Platform davranışını çağırmanın yolu microservice adımıdır: karşılığı olan bir system operation varsa (microservice_system_operation_list — giriş için access.session.create, oturumdaki kullanıcı için access.session.get, çıkış için access.session.delete) source:'system' bir uç açın ve akışa type:'microservice' adımı koyun; sonuç Steps.<adım>.data'dadır, kod adımı yalnız onu biçimler.`,
2333
- guide: 'ngapps://guides/page'
2334
- }];
2335
- })
2336
- },
2337
- {
2338
- id: 'FLOW-037',
2339
- module: 'flow',
2340
- appliesTo: ['create', 'update'],
2341
- sourceRef: "mobile-qm koşusu 2026-10-01: çıkış akışı oturumu storage adımları (ZY_App_qm/ZY_AppRefresh_qm/ZY_Csrf_qm = '') ve kod adımında cookie.remove ile kapatmaya çalıştı. Platformun oturum çerezleri (AppSessionConstants: ZY_App_ · ZY_AppRefresh_ · ZY_Csrf_) sunucunun HttpOnly Set-Cookie'sidir: web'de document.cookie onları göremez, mobilde akışın cookie/storage deposu Keychain/kv-store'dur ve iOS NSHTTPCookieStorage'a ulaşmaz. Refresh ailesi sunucuda iptal edilmediği için kapat-aç sonrası auth/refresh oturumu yeniden yazdı (kullanıcı girişli açıldı). Çıkış access.session.delete system operation'ıdır (guard 2026-10-01'den beri session: süresi dolmuş jetonda 401, runtime yenileyip tekrarlar; uç isAnonymous:true kalır): aileyi iptal eder, üç çerezi yanıtla siler",
2342
- check: definition => flowAllSteps(definition)
2343
- .flatMap((step) => {
2344
- const args = (step.args ?? {});
2345
- const name = String(args.name ?? '');
2346
- const body = String(args.value ?? '');
2347
- const touchesSessionCookie = (step.type === 'storage' || step.type === 'setcookie')
2348
- ? /^ZY_(App|AppRefresh|Csrf)_/.test(name)
2349
- : step.type === 'code' && /\bcookie\s*\.\s*(remove|set)\s*\(/.test(body) && /['"`]ZY_(App|AppRefresh|Csrf)_/.test(body);
2350
- if (!touchesSessionCookie)
2351
- return [];
2352
- return [{
2353
- ruleId: 'FLOW-037',
2354
- severity: 'warn',
2355
- message: `'${flowStepLabel(step)}' adımı platformun oturum çerezine (ZY_App_ · ZY_AppRefresh_ · ZY_Csrf_) akıştan dokunuyor. Bu çerezler sunucunun HttpOnly çerezleridir: akışın cookie/storage deposu onlara ulaşmaz (mobilde Keychain/kv-store, web'de document.cookie) ve refresh ailesi sunucuda açık kaldığı için kullanıcı kapat-aç sonrası yeniden girişli olur. Çıkış için source:'system', systemOperation:'access.session.delete', isAnonymous:true bir uç açın ve akışa type:'microservice' adımı koyun, ardından redirect ile giriş sayfasına gidin — uç refresh ailesini iptal eder ve üç çerezi yanıtla siler. Uygulamanın kendi değerleri (ör. 'beni hatırla' bayrağı) storage'da kalabilir.`,
2356
- guide: 'ngapps://guides/access'
2357
- }];
2358
- })
2359
- },
2360
2254
  {
2361
2255
  id: 'FLOW-020',
2362
2256
  module: 'flow',
@@ -2480,7 +2374,7 @@ export const policyRules = [
2480
2374
  id: 'FLOW-022',
2481
2375
  module: 'flow',
2482
2376
  appliesTo: ['create', 'update'],
2483
- sourceRef: "alert.ts `const { message, alertType, description } = task.argument` → toast.error(message, { description }) / dialog.alert(message); confirm.ts `dialog.confirm(message, { title, confirmText, cancelText })` (boş çerçeve metni dialog.functions.ts resolveDialogFrame'de sabit metne düşer). Argüman Runtime.svelte'de HAM geçer (`argument: step.args`) — bu alanlarda hiçbir ifade değerlendirilmez, yazılan metin ekranda harfi harfine görünür (2026-09-06·2 koşusu S-13'ün ikinci turu: rehber hata mesajını göstermek için alert adımını öneriyordu). share adımında (2026-09-25) yalnız `title` düz metindir: @ng-apps/flow resolveShareContent onu olduğu gibi verir, `message` ve `path` ifadedir",
2377
+ sourceRef: "alert.ts `const { message, alertType, description } = task.argument` → toast.error(message, { description }) / dialog.alert(message); confirm.ts `dialog.confirm(message, { title, confirmText, cancelText })` (boş çerçeve metni dialog.functions.ts resolveDialogFrame'de sabit metne düşer). Argüman Runtime.svelte'de HAM geçer (`argument: step.args`) — bu alanlarda hiçbir ifade değerlendirilmez, yazılan metin ekranda harfi harfine görünür (2026-09-06·2 koşusu S-13'ün ikinci turu: rehber hata mesajını göstermek için alert adımını öneriyordu)",
2484
2378
  check: definition => flowAllSteps(definition)
2485
2379
  .flatMap((step) => {
2486
2380
  const type = String(step.type ?? '');
@@ -2493,164 +2387,16 @@ export const policyRules = [
2493
2387
  .map(field => ({
2494
2388
  ruleId: 'FLOW-022',
2495
2389
  severity: 'warn',
2496
- message: type.startsWith('notification-')
2497
- ? `'${flowStepLabel(step)}' ${type} adımının '${field}' alanı ifade içeriyor ama bu alan DÜZ METİNDİR (kök ADR 0003): ${field === 'name' ? 'bildirimin kimliği' : field === 'path' ? 'açılacak sayfanın slug\'ı' : 'bildirim başlığı'} olduğu gibi kullanılır, ifade değerlendirilmez. Değişen içeriği ifade olan 'message' (gövde) ya da 'query' (sayfanın sorgusu) alanına yazın.`
2498
- : type === 'share'
2499
- ? `'${flowStepLabel(step)}' share adımının '${field}' alanı ifade içeriyor ama bu alan DÜZ METİNDİR: başlık paylaşım penceresine olduğu gibi gider (iOS'ta e-posta konusu, Android'de seçici başlığı), ifade değerlendirilmez. Değişen içeriği ifade olan 'message' alanına yazın — ör. message: "'Şuna bak: ' + Page.properties.name"; bağlantı 'path' alanındadır.`
2500
- : `'${flowStepLabel(step)}' ${type} adımının '${field}' alanı ifade içeriyor ama bu alan DÜZ METİNDİR: ${type}.ts task.argument.${field}'i doğrudan ekrana geçirir ve args hiçbir yerde değerlendirilmez (Runtime.svelte \`argument: step.args\`). Kullanıcı ifadenin sonucunu değil ifadenin KENDİSİNİ görür. Ucun mesajını göstermek için bir setter (ya da code) adımı kullanın — value { type: 'code', ref: 'Steps.error?.message' }; hata metninin nerede durduğu page.md §hata yolu'nda.`,
2390
+ message: `'${flowStepLabel(step)}' ${type} adımının '${field}' alanı ifade içeriyor ama bu alan DÜZ METİNDİR: ${type}.ts task.argument.${field}'i doğrudan ekrana geçirir ve args hiçbir yerde değerlendirilmez (Runtime.svelte \`argument: step.args\`). Kullanıcı ifadenin sonucunu değil ifadenin KENDİSİNİ görür. Ucun mesajını göstermek için bir setter (ya da code) adımı kullanın — value { type: 'code', ref: 'Steps.error?.message' }; hata metninin nerede durduğu page.md §hata yolu'nda.`,
2501
2391
  guide: 'ngapps://guides/page'
2502
2392
  }));
2503
2393
  })
2504
2394
  },
2505
- {
2506
- id: 'FLOW-027',
2507
- module: 'flow',
2508
- appliesTo: ['create', 'update'],
2509
- sourceRef: "share adımının argümanı StepManagementArgument'ın Title/Message/Path alanlarında saklanır (StepType.cs `share`, kök docs/adr/0001-share-akis-adimi.md); url/link/text gibi anahtarlar sözleşmede YOKTUR ve platform onları 200 ile sessizce düşürür — adım hiçbir şey paylaşmadan akış sürer. `message` ve `path` İFADEDİR (@ng-apps/flow resolveShareContent → runCode): tırnaksız 'https://…' JS'te etiket + yorumdur, undefined döner",
2510
- check: definition => flowAllSteps(definition)
2511
- .filter(step => step.type === 'share')
2512
- .flatMap((step) => {
2513
- const args = (step.args ?? {});
2514
- const filled = (key) => typeof args[key] === 'string' && String(args[key]).trim().length > 0;
2515
- const findings = [];
2516
- const strayLinks = ['url', 'link', 'href'].filter(filled);
2517
- const strayTexts = ['text', 'body', 'content'].filter(filled);
2518
- if (strayLinks.length > 0) {
2519
- findings.push({
2520
- ruleId: 'FLOW-027',
2521
- severity: filled('path') ? 'warn' : 'block',
2522
- message: `'${flowStepLabel(step)}' share adımının bağlantısı args.${strayLinks.join('/args.')} alanında: bu anahtar StepManagementArgument sözleşmesinde YOK, platform onu 200 ile sessizce düşürür ve adım bağlantısız kalır. Bağlantıyı args.path'e ifade olarak yazın — ör. "'https://ornek.app/urun/' + Page.queryParams.id".`,
2523
- guide: 'ngapps://guides/page'
2524
- });
2525
- }
2526
- if (strayTexts.length > 0) {
2527
- findings.push({
2528
- ruleId: 'FLOW-027',
2529
- severity: filled('message') ? 'warn' : 'block',
2530
- message: `'${flowStepLabel(step)}' share adımının metni args.${strayTexts.join('/args.')} alanında: bu anahtar StepManagementArgument sözleşmesinde YOK, platform onu sessizce düşürür. Metni args.message'a ifade olarak yazın — ör. "'Şuna bak: ' + Page.properties.name".`,
2531
- guide: 'ngapps://guides/page'
2532
- });
2533
- }
2534
- for (const key of ['message', 'path']) {
2535
- const value = typeof args[key] === 'string' ? String(args[key]).trim() : '';
2536
- if (/^[a-z][a-z\d+\-.]*:\/\//i.test(value)) {
2537
- findings.push({
2538
- ruleId: 'FLOW-027',
2539
- severity: 'block',
2540
- message: `'${flowStepLabel(step)}' share adımının '${key}' alanı tırnaksız bir adres: '${value}'. Bu alan İFADEDİR — tırnaksız adres JS'te etiket + yorumdur, undefined döner ve hiçbir şey paylaşılmaz. Dize olarak yazın: "'${value}'".`,
2541
- guide: 'ngapps://guides/page'
2542
- });
2543
- }
2544
- }
2545
- return findings;
2546
- })
2547
- },
2548
- {
2549
- id: 'FLOW-029',
2550
- module: 'flow',
2551
- appliesTo: ['create', 'update'],
2552
- sourceRef: "Cihaz yeteneği adımlarının argümanı StepManagementArgument'ın mevcut alanlarındadır (kök docs/adr/0003-cihaz-yetenegi-adimlari.md): haptic.value = stil, location.value = doğruluk, location.isRaw = adres çözülmesin. İkisi de DÜZ METİNDİR (@ng-apps/flow hapticStyle/locationAccuracy), kümede olmayan değer backend FlowDtoValidator'da 400 alır; style/accuracy/reverseGeocode gibi anahtarlar sözleşmede YOKTUR ve platform onları 200 ile sessizce düşürür — adım varsayılanla (medium / balanced / adresli) koşar",
2553
- check: definition => flowAllSteps(definition)
2554
- .filter(step => step.type === 'haptic' || step.type === 'location')
2555
- .flatMap((step) => {
2556
- const args = (step.args ?? {});
2557
- // Backend (FlowDtoValidator) yalnız tamamen boşluk olanı boş sayar; kümeyle karşılaştırmayı kırpmadan yapar.
2558
- const raw = typeof args.value === 'string' ? args.value : '';
2559
- const value = raw.trim() ? raw : '';
2560
- const haptic = step.type === 'haptic';
2561
- const allowed = haptic ? hapticStyles : locationAccuracies;
2562
- const field = haptic ? 'stil' : 'doğruluk';
2563
- const findings = [];
2564
- const stray = (haptic ? ['style', 'type', 'feedback'] : ['accuracy', 'precision'])
2565
- .filter(key => args[key] !== undefined && args[key] !== null && args[key] !== '');
2566
- if (value && !allowed.has(value)) {
2567
- const unquoted = value.replace(/^['"`](.*)['"`]$/, '$1');
2568
- const trimmed = value.trim();
2569
- findings.push({
2570
- ruleId: 'FLOW-029',
2571
- severity: 'block',
2572
- message: allowed.has(unquoted)
2573
- ? `'${flowStepLabel(step)}' ${step.type} adımının ${field} değeri tırnaklı yazılmış: ${value}. Bu alan DÜZ METİNDİR, ifade değil — args.value: '${unquoted}' yazın.`
2574
- : allowed.has(trimmed)
2575
- ? `'${flowStepLabel(step)}' ${step.type} adımının ${field} değerinin çevresinde boşluk var: '${value}'. Platform kırpmadan karşılaştırır ve 400 döner — args.value: '${trimmed}' yazın.`
2576
- : `'${flowStepLabel(step)}' ${step.type} adımının ${field} değeri '${value}' tanınmıyor; platform 400 döner. Kullanılabilir: ${[...allowed].join(', ')} (boş → ${haptic ? 'medium' : 'balanced'}).`,
2577
- guide: 'ngapps://guides/mobile'
2578
- });
2579
- }
2580
- if (stray.length > 0) {
2581
- findings.push({
2582
- ruleId: 'FLOW-029',
2583
- severity: value ? 'warn' : 'block',
2584
- message: `'${flowStepLabel(step)}' ${step.type} adımının ${field} değeri args.${stray.join('/args.')} alanında: bu anahtar StepManagementArgument sözleşmesinde YOK, platform onu 200 ile sessizce düşürür ve adım varsayılanla (${haptic ? 'medium' : 'balanced'}) koşar. Değeri args.value'ya düz metin olarak yazın — ör. args.value: '${haptic ? 'success' : 'high'}'.`,
2585
- guide: 'ngapps://guides/mobile'
2586
- });
2587
- }
2588
- if (!haptic && ['reverseGeocode', 'address', 'geocode'].some(key => args[key] !== undefined)) {
2589
- findings.push({
2590
- ruleId: 'FLOW-029',
2591
- severity: 'warn',
2592
- message: `'${flowStepLabel(step)}' location adımında adres anahtarı sözleşmede YOK ve sessizce düşer. Adres varsayılan olarak çözülür (cihazda; web'de hep null); kapatmak için args.isRaw: true yazın.`,
2593
- guide: 'ngapps://guides/mobile'
2594
- });
2595
- }
2596
- return findings;
2597
- })
2598
- },
2599
- {
2600
- id: 'FLOW-030',
2601
- module: 'flow',
2602
- appliesTo: ['create', 'update'],
2603
- sourceRef: "Yerel bildirim adımlarının argümanı StepManagementArgument'ın mevcut alanlarındadır (kök docs/adr/0003-cihaz-yetenegi-adimlari.md): notification-schedule name = kimlik (düz metin, aynı kimlik eskisinin yerini alır), title düz metin, message ve value İFADE, path sayfa; notification-cancel name = kimlik ('*' hepsi). Zamanın türü value'nun sonucunun şeklinden okunur (@ng-apps/flow notificationTrigger): 'HH:mm' her gün, { weekday: 1-7, time: 'HH:mm' } her hafta (1 = Pazartesi), ISO tarih-saat bir kez. Eksik name/value backend FlowDtoValidator'da 400 alır; id/at/daily/weekly/body gibi anahtarlar sözleşmede YOKTUR ve platform onları 200 ile sessizce düşürür",
2604
- check: definition => flowAllSteps(definition)
2605
- .filter(step => step.type === 'notification-schedule' || step.type === 'notification-cancel')
2606
- .flatMap((step) => {
2607
- const args = (step.args ?? {});
2608
- const text = (key) => typeof args[key] === 'string' ? String(args[key]).trim() : '';
2609
- const findings = [];
2610
- const schedule = step.type === 'notification-schedule';
2611
- const stray = ['id', 'identifier', 'at', 'daily', 'weekly', 'time', 'body', 'text']
2612
- .filter(key => args[key] !== undefined && args[key] !== null && args[key] !== '');
2613
- if (!text('name')) {
2614
- findings.push({
2615
- ruleId: 'FLOW-030',
2616
- severity: 'block',
2617
- message: `'${flowStepLabel(step)}' ${step.type} adımının kimliği yok: args.name düz metin olarak yazılmalı (ör. 'sulama')${schedule ? ' — aynı kimlikle yeniden planlama eskisinin yerini alır' : " — '*' bütün planlı bildirimleri siler"}. Platform eksik kimliği 400 ile reddeder.`,
2618
- guide: 'ngapps://guides/mobile'
2619
- });
2620
- }
2621
- if (schedule && !text('value')) {
2622
- findings.push({
2623
- ruleId: 'FLOW-030',
2624
- severity: 'block',
2625
- message: `'${flowStepLabel(step)}' notification-schedule adımının zamanı yok: args.value bir İFADEDİR ve sonucu 'HH:mm' (her gün), { weekday: 1-7, time: 'HH:mm' } (her hafta, 1 = Pazartesi) ya da ISO tarih-saattir (bir kez) — ör. "tp_saat.value" ya da "'08:30'".`,
2626
- guide: 'ngapps://guides/mobile'
2627
- });
2628
- }
2629
- const literal = /^'([^']*)'$/.exec(text('value'))?.[1];
2630
- if (schedule && literal !== undefined && !/^([01]?\d|2[0-3]):[0-5]\d$/.test(literal) && Number.isNaN(Date.parse(literal))) {
2631
- findings.push({
2632
- ruleId: 'FLOW-030',
2633
- severity: 'block',
2634
- message: `'${flowStepLabel(step)}' notification-schedule adımının zamanı '${literal}' okunamaz: 'HH:mm' (00:00–23:59), ISO tarih-saat ya da { weekday, time } nesnesi yazın. Çalışmada adım error dalına düşer (status: 'invalid').`,
2635
- guide: 'ngapps://guides/mobile'
2636
- });
2637
- }
2638
- if (stray.length > 0) {
2639
- findings.push({
2640
- ruleId: 'FLOW-030',
2641
- severity: 'warn',
2642
- message: `'${flowStepLabel(step)}' ${step.type} adımında args.${stray.join('/args.')} sözleşmede YOK ve platform onu sessizce düşürür. Kimlik args.name, zaman args.value (ifade), metin args.message (ifade), başlık args.title.`,
2643
- guide: 'ngapps://guides/mobile'
2644
- });
2645
- }
2646
- return findings;
2647
- })
2648
- },
2649
2395
  {
2650
2396
  id: 'FLOW-023',
2651
2397
  module: 'flow',
2652
2398
  appliesTo: ['create', 'update'],
2653
- sourceRef: "Adım tipi sözlüğü backend'indir (StepType.cs) ama koşan tipler barındırıcıdan gelir: flow-engine.ts start·setter·code·condition·microservice·validation·flow-trigger register eder, web Runtime.svelte alert·confirm·redirect·download·storage·setcookie ekler, mobil @ng-apps/ui-native runtime-tasks.ts alert·confirm·redirect·navigate·storage·setcookie·download ekler. navigate web'de YOKTUR; end ve query hiçbir barındırıcıda yoktur (Studio kataloğu da bunu visibility ile söyler: navigate 'mobile', End eklenebilir adımlar arasında değil — EventActionsAdd.svelte). Register edilmemiş tipe gelen akış SESSİZCE durur: flow-engine.ts process() callback bulamazsa hiçbir şey yapmaz (next yok, completed/stopped yok, hata yok, log yok), run() Promise'i çözülmez ve flowRunFinished() hiç koşmaz — __ngAppsFlowActivity.running sıfıra inmez, page_screenshot'ın hazır bekleyişi her eylemde bütçesini sonuna kadar yakar",
2399
+ sourceRef: "Adım tipi sözlüğü backend'indir (StepType.cs) ama koşan tipler barındırıcıdan gelir: flow-engine.ts start·setter·code·condition·microservice·validation·flow-trigger register eder, web Runtime.svelte alert·confirm·redirect·download·storage·setcookie ekler, mobil ScreenRuntime.tsx alert·redirect·navigate·storage·setcookie ekler. navigate web'de, confirm/download mobilde YOKTUR; end ve query hiçbir barındırıcıda yoktur (Studio kataloğu da bunu visibility ile söyler: navigate 'mobile', confirm/download 'web'; End eklenebilir adımlar arasında değil — EventActionsAdd.svelte). Register edilmemiş tipe gelen akış SESSİZCE durur: flow-engine.ts process() callback bulamazsa hiçbir şey yapmaz (next yok, completed/stopped yok, hata yok, log yok), run() Promise'i çözülmez ve flowRunFinished() hiç koşmaz — __ngAppsFlowActivity.running sıfıra inmez, page_screenshot'ın hazır bekleyişi her eylemde bütçesini sonuna kadar yakar",
2654
2400
  check: definition => {
2655
2401
  const steps = flowAllSteps(definition);
2656
2402
  // Studio her akış tuvaline dekoratif bir End düğümü koyar ve onu sildirmez; zararlı olan
@@ -3217,27 +2963,9 @@ export const policyRules = [
3217
2963
  }];
3218
2964
  }
3219
2965
  },
3220
- {
3221
- id: 'MW-006',
3222
- module: 'workflow',
3223
- appliesTo: ['create', 'update', 'preview'],
3224
- sourceRef: "Kimlik devri değeri triggerSource'ta DEĞİL context'te durur: WorkflowContext.SetTriggerSource triggerSource'a { type, id, name, slug, roles, pathAndQuery }, context'e { type, name, roles, path, impersonatedUserId, language } yazar (WorkflowContext.cs:216-235). triggerSource.impersonatedUserId her zaman undefined okunur ve önizleme hep jeton yoluna düşer (ZM-22, koşu 37)",
3225
- check: (definition) => {
3226
- const readers = workflowSteps(definition).filter(step => /\btriggerSource\s*\.\s*impersonatedUserId\b/.test(JSON.stringify(step.rule ?? {})));
3227
- return readers.length === 0
3228
- ? []
3229
- : [{
3230
- ruleId: 'MW-006',
3231
- severity: 'warn',
3232
- message: `'${readers.map(stepLabel).join(', ')}' kimlik devrini triggerSource.impersonatedUserId'den okuyor; bu alan yok, değer hep undefined gelir. Doğrusu context.impersonatedUserId — ve yalnız start adımının impersonation dalında: değer yalnız doğrulanmış Studio önizlemesinde dolar, başka yerde yetki kararı için kullanılmaz (platform_guide('middleware') Tarif 1c).`,
3233
- guide: 'ngapps://guides/middleware'
3234
- }];
3235
- }
3236
- },
3237
2966
  // Backend doğrulayıcılarının aynası (ENT-015…018, MS-017, WF-026, QRY/VIEW/DTO/ROW/DS/PRJ/TR/FLD/FILE/EXT):
3238
2967
  // tek liste `backendConstraints.ts`'te durur, buradan yalnız politika motoruna katılır.
3239
2968
  ...themePolicyRules,
3240
- ...mobileStorePolicyRules,
3241
2969
  ...backendPolicyRules()
3242
2970
  ];
3243
2971
  /**
@@ -154,24 +154,6 @@ const resolveShadow = (shadow) => {
154
154
  return undefined;
155
155
  return SHADOW_VALUES[shadow] ?? String(shadow);
156
156
  };
157
- /**
158
- * Döndür / ölçekle / kaydır alanlarının kabul aralığı — frontend `style-groups/transform-fields.ts`
159
- * `TRANSFORM_RANGES`'in kopyası (altın vakalar kilitler). Aralık dışı ve birimli değer yazılmaz.
160
- */
161
- export const TRANSFORM_RANGES = {
162
- rotate: [-360, 360],
163
- scale: [10, 500],
164
- translateX: [-1000, 1000],
165
- translateY: [-1000, 1000]
166
- };
167
- /** Sayı ya da sayısal metin, aralığın içinde; aksi `undefined` — frontend `transformValue`. */
168
- export const transformValue = (value, field) => {
169
- if (typeof value !== 'number' && (typeof value !== 'string' || value.trim() === ''))
170
- return undefined;
171
- const parsed = Number(value);
172
- const [min, max] = TRANSFORM_RANGES[field];
173
- return Number.isFinite(parsed) && parsed >= min && parsed <= max ? parsed : undefined;
174
- };
175
157
  /**
176
158
  * Grupların alan listeleri — frontend `style-groups/style-group-schemas.ts`
177
159
  * `STYLE_GROUP_FIELDS`'in kopyası. Parite testi `components.json`'daki gerçek
@@ -188,11 +170,7 @@ export const STYLE_GROUP_FIELDS = {
188
170
  'borderLeft',
189
171
  'shadow',
190
172
  'contentOverflow',
191
- 'opacity',
192
- 'rotate',
193
- 'scale',
194
- 'translateX',
195
- 'translateY'
173
+ 'opacity'
196
174
  ],
197
175
  typographyStyle: [
198
176
  'textColor',
@@ -242,21 +220,6 @@ export function composeTypedStyle(input, ext) {
242
220
  if (opacity !== undefined && opacity >= 0 && opacity < 100) {
243
221
  groups.opacity = String(opacity / 100);
244
222
  }
245
- // Döndür / ölçekle / kaydır (ADR 0005): kaydır → döndür → ölçekle, köken merkez;
246
- // ölçek yüzdedir, nötr değer ve aralık dışı yazılmaz — frontend `composeSurfaceTransform`.
247
- const transform = [];
248
- const x = transformValue(surface.translateX, 'translateX') ?? 0;
249
- const y = transformValue(surface.translateY, 'translateY') ?? 0;
250
- if (x !== 0 || y !== 0)
251
- transform.push(`translate(${x}px, ${y}px)`);
252
- const rotate = transformValue(surface.rotate, 'rotate');
253
- if (rotate !== undefined && rotate !== 0)
254
- transform.push(`rotate(${rotate}deg)`);
255
- const scale = transformValue(surface.scale, 'scale');
256
- if (scale !== undefined && scale !== 100)
257
- transform.push(`scale(${scale / 100})`);
258
- if (transform.length)
259
- groups.transform = transform.join(' ');
260
223
  // `ROOT_TARGET` (`&`) kökün kendisidir: kendi derleyicisi olmayan kaplarda
261
224
  // yüzey düğüm kutusuna yazılır ve kaydırılan da odur.
262
225
  if (isSet(surface.contentOverflow) && ext?.overflowTarget) {
@@ -288,10 +251,8 @@ export function composeTypedStyle(input, ext) {
288
251
  assign(rules, 'borderColor', hover.borderColor);
289
252
  assign(rules, 'boxShadow', resolveShadow(hover.shadow));
290
253
  const lift = asDimension(hover.lift);
291
- // Kaldırma düğümün kendi transform'unu ezmez, önüne eklenir.
292
- if (lift !== undefined) {
293
- rules.transform = `translateY(calc(-1 * ${lift}))${typeof groups.transform === 'string' ? ` ${groups.transform}` : ''}`;
294
- }
254
+ if (lift !== undefined)
255
+ rules.transform = `translateY(calc(-1 * ${lift}))`;
295
256
  if (Object.keys(rules).length) {
296
257
  const duration = asNumber(hover.transitionMs) ?? 160;
297
258
  groups.transition = `background-color ${duration}ms ease, border-color ${duration}ms ease, box-shadow ${duration}ms ease, transform ${duration}ms ease`;
@@ -502,6 +463,39 @@ export const TYPED_STYLE_COMPONENTS = {
502
463
  groups: ['surfaceStyle'],
503
464
  ext: { overflowTarget: '&__body' }
504
465
  },
466
+ layout: {
467
+ // Kabuk zeminini `.ng-layout` KÖKÜNDE çizer; düğüm kutusuna yazılan zemin
468
+ // onun altında kalıyordu (LAYOUT-006, 2026-09-29). Yüzey ve taşma köke.
469
+ // navigationStyle menüye gider, resolvedStyle'a girmez.
470
+ groups: ['surfaceStyle'],
471
+ ext: { overflowTarget: ROOT_TARGET }
472
+ },
473
+ 'layout-shell': {
474
+ // Aynı kök: zemin `.ng-layout-shell` KÖKÜNDE (SHELL-006, 2026-09-29).
475
+ groups: ['surfaceStyle'],
476
+ ext: { overflowTarget: ROOT_TARGET }
477
+ },
478
+ 'layout-region': {
479
+ // Zemin `.ng-layout-region` KÖKÜNDE, taşma kaydırılan gövdede (REG-002, 2026-09-29).
480
+ groups: ['surfaceStyle'],
481
+ ext: { overflowTarget: '&__body' }
482
+ },
483
+ 'auth-layout': {
484
+ // Zemin `.ng-auth` KÖKÜNDE (AUTH-006, 2026-09-29); yüzey ve taşma köke.
485
+ groups: ['surfaceStyle'],
486
+ ext: { overflowTarget: ROOT_TARGET }
487
+ },
488
+ header: {
489
+ // Şeridin zemini ve alt çizgisi kökte (HDR-007, 2026-09-29).
490
+ groups: ['surfaceStyle'],
491
+ ext: { overflowTarget: ROOT_TARGET }
492
+ },
493
+ sidebar: {
494
+ // Yan menünün zemini ve sağ çizgisi kökte (SB-004, 2026-09-29).
495
+ // navigationStyle menüye gider, resolvedStyle'a girmez.
496
+ groups: ['surfaceStyle'],
497
+ ext: { overflowTarget: ROOT_TARGET }
498
+ },
505
499
  icon: {
506
500
  // Yalnız hover: surface çipin (chipShape/chipColor), typography da boyutun
507
501
  // (size) ve rengin (color) çift kanalı olurdu — görsel kararlar semantik
@@ -532,20 +526,9 @@ export const NODE_SURFACE_TYPES = new Set([
532
526
  'html',
533
527
  'file-viewer',
534
528
  'document-editor',
535
- 'layout',
536
- 'layout-region',
537
- 'layout-shell',
538
529
  'qm-content',
539
- 'qm-sidebar',
540
- 'auth-layout'
530
+ 'qm-sidebar'
541
531
  ]);
542
- /**
543
- * `style`'ı kendi içeriğinin CSS'i olarak alan tipler: `html`in `style`'ı uzun metindir ve yazarın
544
- * işaretlemesine kapsamlı girer — web'de emotion sınıfı (`html.functions.ts` `resolveHtmlStyleClass`),
545
- * mobilde korumalı belgenin stil bloğu (plans/mobil-plantcare-acigi f-20). "Düz CSS string style"
546
- * (PAGE-014) ve "ham CSS çizilmez" (MOB-002) uyarıları bu tiplerde yanlıştır.
547
- */
548
- export const DOCUMENT_STYLE_TYPES = new Set(['html']);
549
532
  const NODE_SURFACE_EXTENSION = { overflowTarget: ROOT_TARGET };
550
533
  /** Düğüm kutusuna inen yüzey; kap tipi değilse ya da grup boşsa yok. */
551
534
  export function composeNodeSurfaceStyle(type, surfaceStyle) {
@@ -585,7 +568,7 @@ const unwrapProp = (value) => {
585
568
  result[key] = unwrapProp(item);
586
569
  return result;
587
570
  };
588
- export const rawProp = (props, name) => {
571
+ const rawProp = (props, name) => {
589
572
  const prop = props?.[name];
590
573
  // İfadeye bağlı prop'un değeri çalışma anında oluşur, burada çözülemez.
591
574
  return prop && typeof prop === 'object' && 'data' in prop ? unwrapProp(prop.data) : undefined;
@@ -332,8 +332,8 @@ export function buildSpacingScaleVars(scale) {
332
332
  .join('\n\t');
333
333
  }
334
334
  /**
335
- * Bir seviyenin dar ekran karşılığının masaüstüne oranı — bugünkü breakpoint değerlerinden türer.
336
- * Kullanıcı tek çarpan ayarlar, dar ekran ona orantılı hareket eder.
335
+ * Bir seviyenin mobil karşılığının masaüstüne oranı — bugünkü breakpoint değerlerinden türer.
336
+ * Kullanıcı tek çarpan ayarlar, mobil ona orantılı hareket eder.
337
337
  */
338
338
  const TYPE_SCALE_MOBILE_RATIO = {
339
339
  h1: 1.7 / 2.25,
@@ -363,7 +363,7 @@ export function mergeTypeScale(overrides) {
363
363
  }
364
364
  return result;
365
365
  }
366
- /** Ölçekten `--ng-font-size-*` değişkenlerini üretir (masaüstü + dar ekran). */
366
+ /** Ölçekten `--ng-font-size-*` değişkenlerini üretir (masaüstü + mobil). */
367
367
  export function buildTypeScaleVars(scale) {
368
368
  const lines = [];
369
369
  for (const [level, factor] of Object.entries(scale)) {
@@ -351,7 +351,7 @@ export function logGatewayEvent(message) {
351
351
  */
352
352
  export function logCapabilityGap(gap) {
353
353
  const lines = [
354
- `┌─ ${clockOf(new Date())} · KABİLİYET BOŞLUĞU · ${gap.severity}${gap.module ? ` · ${gap.module}` : ''}${gap.project ? ` · proje ${gap.project}` : ''}`,
354
+ `┌─ ${clockOf(new Date())} · KABİLİYET BOŞLUĞU · ${gap.severity}${gap.module ? ` · ${gap.module}` : ''}`,
355
355
  `│ hedef : ${condense(gap.goal, maxBodyChars)}`,
356
356
  `│ engel : ${condense(gap.blocker, maxBodyChars)}`
357
357
  ];
@@ -5,9 +5,8 @@ const MAX_NOTES = 8;
5
5
  const MAX_NOTE_CHARS = 240;
6
6
  const MAX_DROPS = 5;
7
7
  export const diagnosticsParam = z.enum(['compact', 'full']).optional().describe("Yanıttaki gatewayNormalized / silentlyDropped listelerinin boyu. compact (varsayılan): aynı not tekilleşir, uzun not kısalır (en fazla 8); aynı yolun düşmeleri tek satırda sayıyla toplanır (en fazla 5 grup); droppedCount her zaman tam sayıdır. full: listelerin tamamı.");
8
- /** `adjustable`: tool `diagnostics` parametresini alıyor mu — kısaltma notu yalnız alan tool'a onu önerir (g-08). */
9
- export function runWithDiagnostics(mode, run, adjustable = true) {
10
- return activeMode.run({ mode, adjustable }, run);
8
+ export function runWithDiagnostics(mode, run) {
9
+ return activeMode.run(mode, run);
11
10
  }
12
11
  /**
13
12
  * Tanılama listeleri her yazma çağrısında yanıta girer ve aynı gerekçe cümlesi çağrı başına tekrar
@@ -19,7 +18,7 @@ export function runWithDiagnostics(mode, run, adjustable = true) {
19
18
  * listeyi görür; kısaltma yalnız `diagnostics` parametresini taşıyan yazma tool'larında devreye girer.
20
19
  */
21
20
  export function compactDiagnostics(payload) {
22
- if (activeMode.getStore()?.mode !== 'compact')
21
+ if (activeMode.getStore() !== 'compact')
23
22
  return payload;
24
23
  if (!payload || typeof payload !== 'object' || Array.isArray(payload))
25
24
  return payload;
@@ -59,12 +58,7 @@ export function compactDiagnostics(payload) {
59
58
  }
60
59
  if (hidden.length === 0)
61
60
  return result;
62
- return {
63
- ...result,
64
- diagnosticsNote: activeMode.getStore()?.adjustable === false
65
- ? 'Kısaltıldı; tam liste gateway günlüğünde (bu tool diagnostics parametresi almaz).'
66
- : "Kısaltıldı; yazmayı tekrarlamayın. Tam liste: sonraki çağrıda diagnostics:'full'."
67
- };
61
+ return { ...result, diagnosticsNote: "Kısaltıldı; yazmayı tekrarlamayın. Tam liste: sonraki çağrıda diagnostics:'full'." };
68
62
  }
69
63
  /**
70
64
  * Aynı yolun farklı öğelerindeki düşmeler (`selectFields[fieldId=a].path`, `selectFields[fieldId=b].path`, …)