@adia-ai/adia-ui-forge 0.8.59 → 0.8.60

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.
@@ -1,4 +1,4 @@
1
- // GENERATED do not hand-edit. Sources:
1
+ // GENERATED, do not hand-edit. Sources:
2
2
  // scripts/lint/engine/primitives.mjs, scripts/lint/engine/run.mjs
3
3
  // scripts/lint/rules/consumer/genui-doc.mjs
4
4
  // scripts/lint/rules/consumer/hardcoded-open.mjs
@@ -13,11 +13,17 @@
13
13
  // scripts/lint/rules/generated/composition/action-list.mjs
14
14
  // scripts/lint/rules/generated/composition/admin-command.mjs
15
15
  // scripts/lint/rules/generated/composition/admin-content.mjs
16
+ // scripts/lint/rules/generated/composition/admin-entity-item.mjs
17
+ // scripts/lint/rules/generated/composition/admin-roster.mjs
16
18
  // scripts/lint/rules/generated/composition/admin-scroll.mjs
19
+ // scripts/lint/rules/generated/composition/admin-settings.mjs
17
20
  // scripts/lint/rules/generated/composition/admin-shell.mjs
18
21
  // scripts/lint/rules/generated/composition/admin-sidebar.mjs
19
22
  // scripts/lint/rules/generated/composition/admin-statusbar.mjs
20
23
  // scripts/lint/rules/generated/composition/admin-topbar.mjs
24
+ // scripts/lint/rules/generated/composition/agent-admin.mjs
25
+ // scripts/lint/rules/generated/composition/avatar-group.mjs
26
+ // scripts/lint/rules/generated/composition/chat-composer.mjs
21
27
  // scripts/lint/rules/generated/composition/chat-empty.mjs
22
28
  // scripts/lint/rules/generated/composition/chat-header.mjs
23
29
  // scripts/lint/rules/generated/composition/chat-shell.mjs
@@ -34,18 +40,30 @@
34
40
  // scripts/lint/rules/generated/composition/editor-sidebar.mjs
35
41
  // scripts/lint/rules/generated/composition/editor-statusbar.mjs
36
42
  // scripts/lint/rules/generated/composition/editor-toolbar.mjs
43
+ // scripts/lint/rules/generated/composition/embed-shell.mjs
37
44
  // scripts/lint/rules/generated/composition/feed-item.mjs
38
45
  // scripts/lint/rules/generated/composition/feed.mjs
46
+ // scripts/lint/rules/generated/composition/fields.mjs
47
+ // scripts/lint/rules/generated/composition/footer.mjs
48
+ // scripts/lint/rules/generated/composition/form-popover.mjs
49
+ // scripts/lint/rules/generated/composition/header.mjs
39
50
  // scripts/lint/rules/generated/composition/list-item.mjs
40
51
  // scripts/lint/rules/generated/composition/menu-divider.mjs
41
52
  // scripts/lint/rules/generated/composition/menu-item.mjs
42
53
  // scripts/lint/rules/generated/composition/menu-label.mjs
54
+ // scripts/lint/rules/generated/composition/menu.mjs
55
+ // scripts/lint/rules/generated/composition/nav-group.mjs
56
+ // scripts/lint/rules/generated/composition/nav-item.mjs
43
57
  // scripts/lint/rules/generated/composition/page-scroll.mjs
58
+ // scripts/lint/rules/generated/composition/radio-group.mjs
59
+ // scripts/lint/rules/generated/composition/search.mjs
60
+ // scripts/lint/rules/generated/composition/section.mjs
44
61
  // scripts/lint/rules/generated/composition/segment.mjs
45
62
  // scripts/lint/rules/generated/composition/segmented.mjs
46
63
  // scripts/lint/rules/generated/composition/simple-content.mjs
47
64
  // scripts/lint/rules/generated/composition/simple-hero.mjs
48
65
  // scripts/lint/rules/generated/composition/simple-shell.mjs
66
+ // scripts/lint/rules/generated/composition/skip-nav.mjs
49
67
  // scripts/lint/rules/generated/composition/stepper-item.mjs
50
68
  // scripts/lint/rules/generated/composition/stepper.mjs
51
69
  // scripts/lint/rules/generated/composition/tab.mjs
@@ -61,6 +79,7 @@
61
79
  // scripts/lint/rules/generated/lab-posture/internal-tier.mjs
62
80
  // scripts/lint/rules/generated/lab-posture/required-attr.mjs
63
81
  // scripts/lint/rules/generated/lab-posture/unknown-attr.mjs
82
+ // scripts/lint/rules/generated/lab-posture/unknown-slot.mjs
64
83
  // scripts/lint/rules/generated/lab-posture/unknown-tag.mjs
65
84
  // scripts/lint/rules/genui-output/anti-patterns.mjs
66
85
  // scripts/lint/rules/shared/attr-typo.mjs
@@ -69,8 +88,10 @@
69
88
  // scripts/lint/rules/shared/dead-font-token.mjs
70
89
  // scripts/lint/rules/shared/example-id-grammar.mjs
71
90
  // scripts/lint/rules/shared/example-prop-contract.mjs
91
+ // scripts/lint/rules/shared/img-dimension-reserve.mjs
72
92
  // scripts/lint/rules/shared/legacy-shell.mjs
73
93
  // scripts/lint/rules/shared/native-primitive.mjs
94
+ // scripts/lint/rules/shared/no-local-escape-html.mjs
74
95
  // scripts/lint/rules/shared/raw-color.mjs
75
96
  // scripts/lint/rules/shared/raw-px.mjs
76
97
  // scripts/lint/rules/shared/scope-extent.mjs
@@ -238,7 +259,7 @@ const RE = {
238
259
  BOOL_TRUE: /\bdefault:\s*true\b/,
239
260
  ATTR_TYPO: /\battr:\s*['"]/,
240
261
  NATIVE_PRIMITIVE: /<(?:button|input|select|textarea|dialog)(?![\w-])/,
241
- LEGACY_SHELL: /data-chat-(?:messages|input|empty|name)|data-editor-body|data-canvas\b|data-sidebar=|data-pane-(?:side|grow)|<aside-ui\b|<dialog\s+data-command/,
262
+ LEGACY_SHELL: /^(?:data-chat-(?:messages|input|empty|name)|data-editor-body|data-canvas|data-sidebar|data-pane-(?:side|grow))$/,
242
263
  PX_GE: /(?<![\w.-])(\d+)px\b/g,
243
264
  SELECTOR_RULE: /^\s*[.#:[&\w][^{}\n]*\{/m,
244
265
  SSR_SIGNAL: /['"]use client['"]|\buseEffect\b|\bonMounted\b|\bonMount\b|from\s+['"](?:react|vue|svelte|next|nuxt|@sveltejs|astro)|getServerSideProps|defineNuxtComponent/i,
@@ -385,9 +406,18 @@ const VOID_TAGS = new Set([
385
406
  * are flushed as-is) so a small fixture snippet never throws.
386
407
  *
387
408
  * Returns one node per open (or self-closing/void) tag, in document
388
- * order: `{ tag, parentTag, line, childTags }` `parentTag` is `'ROOT'`
389
- * for a top-level occurrence (the A2UI "Surface" case), `childTags` is
390
- * the ordered list of direct-child tag names only (not descendants).
409
+ * order: `{ tag, parentTag, line, childTags }`. `parentTag` is the
410
+ * nearest CUSTOM-ELEMENT ancestor (gh#3310) — the stack is walked from
411
+ * the top down past any native, non-hyphenated wrapper tag (`section`,
412
+ * `div`, `td`, `tr`, `tbody`, ...; the Custom Elements naming
413
+ * requirement means no native HTML tag is ever hyphenated, so "contains
414
+ * a hyphen" is the discriminator, not an allowlist) to the first
415
+ * hyphenated frame, and is `'ROOT'` if the walk empties the stack
416
+ * without finding one (the A2UI "Surface" case). `childTags` is the
417
+ * ordered list of DIRECT children only (not descendants, and not
418
+ * ancestor-walked — `allowedChildren` matching stays direct-children-only),
419
+ * each a `{ tag, slot }` pair (`slot` is `null` for a default-slot child —
420
+ * gh#3308, compositionFindings' own slot-aware allowedChildren check).
391
421
  *
392
422
  * gh#2937: `makeLinter`'s `lintText` calls every active rule's `match()`
393
423
  * with the SAME `text` string for one file — and each of the ~48
@@ -401,16 +431,34 @@ const VOID_TAGS = new Set([
401
431
  * the next file is a single cache miss that recomputes and replaces
402
432
  * the slot — no manual invalidation, no unbounded growth.
403
433
  */
404
- let _tagTreeCache = { text: null, nodes: null };
405
- function tagTree(text) {
406
- if (_tagTreeCache.text === text) return _tagTreeCache.nodes;
434
+ // gh#3310: the Custom Elements spec requires a hyphen in every custom
435
+ // tag name, so "contains a hyphen" is a definitional discriminator for
436
+ // "is a catalog component" — no native HTML tag is ever hyphenated, and
437
+ // no allowlist of "transparent" wrapper tags needs maintaining.
438
+ function nearestCustomElementAncestor(stack) {
439
+ for (let i = stack.length - 1; i >= 0; i -= 1) {
440
+ if (stack[i].tag.includes('-')) return stack[i].tag;
441
+ }
442
+ return 'ROOT';
443
+ }
444
+
445
+ let _tagTreeCache = { text: null, path: null, nodes: null };
446
+ // gh#3492: scans `markupScanSurface(text, path)`'s blanked output, not raw
447
+ // `text`. A `<!-- ... -->` comment naming a real tag in prose (a
448
+ // "Pattern source:" doc header) was previously read as live markup, and
449
+ // the comment's missing closing tag left every REAL element after it
450
+ // folded into a phantom nesting context. Blanking (not deleting) keeps
451
+ // line numbers aligned, same guarantee `tagOccurrences` already relies on.
452
+ function tagTree(text, path = '') {
453
+ if (_tagTreeCache.text === text && _tagTreeCache.path === path) return _tagTreeCache.nodes;
454
+ const surface = markupScanSurface(text, path);
407
455
  const nodes = [];
408
- const stack = []; // { tag, parentTag, line, children: string[] }
456
+ const stack = []; // { tag, parentTag, line, children: {tag, slot}[] }
409
457
  TAG_TOKEN_RE.lastIndex = 0;
410
458
  let m;
411
- while ((m = TAG_TOKEN_RE.exec(text))) {
412
- const [, closing, tag, , selfClose] = m;
413
- const line = lineOf(text, m.index);
459
+ while ((m = TAG_TOKEN_RE.exec(surface))) {
460
+ const [, closing, tag, attrString, selfClose] = m;
461
+ const line = lineOf(surface, m.index);
414
462
  if (closing) {
415
463
  let at = -1;
416
464
  for (let i = stack.length - 1; i >= 0; i -= 1) {
@@ -422,8 +470,8 @@ function tagTree(text) {
422
470
  stack.length = at; // pop this frame and any unclosed frames above it
423
471
  continue;
424
472
  }
425
- const parentTag = stack.length ? stack[stack.length - 1].tag : 'ROOT';
426
- if (stack.length) stack[stack.length - 1].children.push(tag);
473
+ const parentTag = nearestCustomElementAncestor(stack);
474
+ if (stack.length) stack[stack.length - 1].children.push({ tag, slot: parseAttrs(attrString).slot ?? null });
427
475
  if (selfClose || VOID_TAGS.has(tag.toLowerCase())) {
428
476
  nodes.push({ tag, parentTag, line, childTags: [] });
429
477
  } else {
@@ -434,7 +482,7 @@ function tagTree(text) {
434
482
  const frame = stack.pop();
435
483
  nodes.push({ tag: frame.tag, parentTag: frame.parentTag, line: frame.line, childTags: frame.children });
436
484
  }
437
- _tagTreeCache = { text, nodes };
485
+ _tagTreeCache = { text, path, nodes };
438
486
  return nodes;
439
487
  }
440
488
 
@@ -446,10 +494,26 @@ function tagTree(text) {
446
494
  * string/tree matcher with no registry lookup at match-time, same as
447
495
  * every other rule). The reserved catalog name `'Surface'` in
448
496
  * `allowedParents` matches a `parentTag === 'ROOT'` occurrence.
497
+ *
498
+ * gh#3308: `allowedChildren` applies to default-slot children only — a
499
+ * child carrying ANY `slot=` attribute (menu-ui's `slot=trigger`,
500
+ * context-menu-ui's wrap-mode target) is a sibling-level named slot whose
501
+ * content is deliberately unconstrained by the component's own source, not
502
+ * a default-slot member subject to the roster check. `allowedChildrenBySlot`
503
+ * is the opt-in per-slot roster for the rare case a named slot DOES want
504
+ * constraining — a slot absent from that map (or the map itself absent)
505
+ * stays exempt by design, same as an unconstrained default slot.
506
+ *
507
+ * gh#3492: `path` is optional and defaults to `''`. Every current caller
508
+ * (the generated `COMPOSITION-*` rules) has no path to give, and doesn't
509
+ * need one: `tagTree()`'s HTML-comment blanking runs unconditionally
510
+ * regardless of path, only its `.vue`-template scoping depends on it.
449
511
  */
450
- function compositionFindings(text, { tag, allowedParents, allowedChildren }) {
512
+ function compositionFindings(text, { tag, allowedParents, allowedChildren, allowedChildrenBySlot, path = '' }) {
451
513
  const out = [];
452
- for (const node of tagTree(text)) {
514
+ const hasChildRule = (allowedChildren && allowedChildren.length)
515
+ || (allowedChildrenBySlot && Object.keys(allowedChildrenBySlot).length);
516
+ for (const node of tagTree(text, path)) {
453
517
  if (node.tag !== tag) continue;
454
518
  if (allowedParents && allowedParents.length) {
455
519
  const parentOk = node.parentTag === 'ROOT'
@@ -464,13 +528,26 @@ function compositionFindings(text, { tag, allowedParents, allowedChildren }) {
464
528
  });
465
529
  }
466
530
  }
467
- if (allowedChildren && allowedChildren.length) {
531
+ if (hasChildRule) {
468
532
  for (const child of node.childTags) {
469
- if (!allowedChildren.includes(child)) {
533
+ if (child.slot) {
534
+ const slotAllowed = allowedChildrenBySlot && allowedChildrenBySlot[child.slot];
535
+ if (!slotAllowed) continue; // named slot left unconstrained by design
536
+ if (!slotAllowed.includes(child.tag)) {
537
+ out.push({
538
+ line: node.line,
539
+ snippet: `<${tag} slot="${child.slot}"> > <${child.tag}>`,
540
+ why: `<${tag}> declares a2ui.allowedChildrenBySlot.${child.slot}: [${slotAllowed.join(', ')}] — <${child.tag}> is not one of them`,
541
+ });
542
+ }
543
+ continue;
544
+ }
545
+ if (!allowedChildren || !allowedChildren.length) continue; // default slot unconstrained
546
+ if (!allowedChildren.includes(child.tag)) {
470
547
  out.push({
471
548
  line: node.line,
472
- snippet: `<${tag}> > <${child}>`,
473
- why: `<${tag}> declares a2ui.allowedChildren: [${allowedChildren.join(', ')}] — <${child}> is not one of them`,
549
+ snippet: `<${tag}> > <${child.tag}>`,
550
+ why: `<${tag}> declares a2ui.allowedChildren: [${allowedChildren.join(', ')}] — <${child.tag}> is not one of them`,
474
551
  });
475
552
  }
476
553
  }
@@ -950,6 +1027,46 @@ function requiredAttrFindings(text, manifest, path = '') {
950
1027
  return out;
951
1028
  }
952
1029
 
1030
+ /**
1031
+ * UNKNOWN-SLOT (gh#3222): a `slot="…"` value that is not a slot name ANY
1032
+ * component in the manifest declares. `manifest` here is the flat
1033
+ * `{ slotNames: [...] }` shape `trimForEmbed`'s own `'slot-names'` branch
1034
+ * produces (gen-lab-posture-rules.mjs) — not the per-tag `{ components }`
1035
+ * shape `buildManifestIndex` reads for the other five rules.
1036
+ *
1037
+ * Deliberately NOT a per-tag/nearest-ancestor check the way UNKNOWN-ATTR
1038
+ * validates an attribute against its own element's tag: Light DOM's
1039
+ * `slot=` is decorative metadata this kit's own component JS reads with
1040
+ * an unscoped selector, so the element carrying `slot="action"` is
1041
+ * routinely a `<header>`'s own descendant rather than a direct child of
1042
+ * the component that actually declares the `action` slot
1043
+ * (card.examples.html's `<header><span slot="heading">…` — `heading` is
1044
+ * `card-ui`'s slot, two levels down from `<card-ui>` itself, past a plain
1045
+ * `<header>` wrapper with no manifest entry of its own). Reliably finding
1046
+ * the "owning" tag would need a nearest-kit-ancestor tree walk that is
1047
+ * fragile against exactly this shape; checking the NAME against the
1048
+ * manifest-wide vocabulary instead still catches the real failure mode
1049
+ * (a generator inventing a slot name no component anywhere declares)
1050
+ * without that fragility — the same "name only, never placement" scope
1051
+ * this primitive's own callers document.
1052
+ */
1053
+ function slotNameFindings(text, manifest, path = '') {
1054
+ const known = new Set((manifest && manifest.slotNames) || []);
1055
+ const out = [];
1056
+ for (const occ of tagOccurrences(text, path)) {
1057
+ const value = occ.attrs.slot;
1058
+ if (value === undefined || value === null) continue;
1059
+ if (isDynamicAttr('slot', value)) continue;
1060
+ if (known.has(value)) continue;
1061
+ out.push({
1062
+ line: occ.line,
1063
+ snippet: `<${occ.tag} slot="${value}">`,
1064
+ why: `UNKNOWN-SLOT: slot="${value}" is not a slot name any component in the installed manifest declares`,
1065
+ });
1066
+ }
1067
+ return out;
1068
+ }
1069
+
953
1070
  /**
954
1071
  * Yaml-corpus primitive (LLD-0016 §C3): reads one component yaml's own
955
1072
  * top-level `component:` scalar and its `props:` mapping's first-level key
@@ -1004,6 +1121,18 @@ function extractYamlComponentPropKeys(text) {
1004
1121
  * @param {Array<{id:string, severity:string, scope:string, fileTypes:string[], match:Function}>} rules
1005
1122
  * @param {{scopes?: string[]}} [opts] which rule scopes to run — omit for all
1006
1123
  */
1124
+ // gh#3716: a `scope: 'forge-only'` rule is declared to check framework
1125
+ // source (packages/web-components, packages/web-modules), the two trees
1126
+ // that are actually authored as scoped components. `npm run lint` sweeps
1127
+ // the whole repo unscoped (the monorepo is both the framework source and
1128
+ // its own consumer), so without this restriction a forge-only rule also
1129
+ // fires against e.g. apps/* page CSS that was never authored to that
1130
+ // contract. `consumer-only`/`shared` rules carry no such corpus fence.
1131
+ const FORGE_ONLY_PATHS = ['packages/web-components/', 'packages/web-modules/'];
1132
+ function isForgeOnlyPath(path) {
1133
+ return FORGE_ONLY_PATHS.some((p) => path.startsWith(p));
1134
+ }
1135
+
1007
1136
  function makeLinter(rules, opts = {}) {
1008
1137
  const scopes = opts.scopes || null;
1009
1138
  const active = rules.filter((r) => !scopes || scopes.includes(r.scope));
@@ -1014,6 +1143,7 @@ function makeLinter(rules, opts = {}) {
1014
1143
  let findings = [];
1015
1144
  for (const rule of active) {
1016
1145
  if (rule.fileTypes && rule.fileTypes.length && !rule.fileTypes.includes(fileExt)) continue;
1146
+ if (rule.scope === 'forge-only' && !isForgeOnlyPath(path)) continue;
1017
1147
  const hits = rule.match(text, path, { scopes }) || [];
1018
1148
  for (const h of hits) {
1019
1149
  findings.push({ name: rule.id, line: h.line, snippet: h.snippet, why: h.why });
@@ -1061,16 +1191,31 @@ const RULES = [];
1061
1191
 
1062
1192
  const APPLIES_EXT = ['.html', '.htm', '.vue', '.svelte', '.astro', '.tsx', '.jsx', '.js', '.mjs', '.ts'];
1063
1193
 
1194
+ // gh#3717: a whole-file `String.includes('validate_schema')` cleared the
1195
+ // finding on ANY occurrence of the name anywhere in the file, a prose
1196
+ // comment, a docstring, an unrelated identifier, even a substring baked
1197
+ // into a fixture string. site/pages/catalogs/catalogs.setup.js passed
1198
+ // purely because a comment mentions both names while `.doc =` is set with
1199
+ // no validation ever run. The fix asks two sharper questions instead:
1200
+ // (1) is the `.doc =` assignment itself real code, not commented out
1201
+ // (stripCommentLines, gh#976's own comment-stripping primitive, the same
1202
+ // one that keeps a retired-selector rule from firing on a docstring), and
1203
+ // (2) does the SAME module actually CALL validate_schema(...) or
1204
+ // check_anti_patterns(...), a real call expression, not a bare mention.
1205
+ const VALIDATE_CALL_RE = /\b(?:validate_schema|check_anti_patterns)\s*\(/;
1206
+
1064
1207
  const genuiUnvalidated = {
1065
1208
  id: 'GENUI-UNVALIDATED',
1066
1209
  severity: 'error',
1067
1210
  scope: 'consumer-only',
1068
1211
  fileTypes: APPLIES_EXT,
1069
- match(text) {
1070
- const m = /\.doc\s*=/.exec(text);
1071
- if (!m) return [];
1072
- const line = lineOf(text, m.index);
1073
- if (text.includes('validate_schema') || text.includes('check_anti_patterns')) return [];
1212
+ match(text, filePath) {
1213
+ if (!/\.doc\s*=/.test(text)) return [];
1214
+ const stripped = stripCommentLines(text, ext(filePath)).map((l) => l.stripped).join('\n');
1215
+ const m = /\.doc\s*=/.exec(stripped);
1216
+ if (!m) return []; // every `.doc =` in the file was inside a comment
1217
+ if (VALIDATE_CALL_RE.test(stripped)) return [];
1218
+ const line = lineOf(stripped, m.index);
1074
1219
  return [{
1075
1220
  line,
1076
1221
  snippet: '.doc = … with no validate in file',
@@ -1088,6 +1233,42 @@ const genuiUnvalidated = {
1088
1233
  // a declarative `src=`/`transport=` on an instance.
1089
1234
  const RUNTIME_HOME_PATH = /(?:^|[\\/])packages[\\/]web-modules[\\/]runtime[\\/](?:a2ui-root|gen-root)[\\/]/;
1090
1235
 
1236
+ // gh#3714: the old check matched ".doc =" and "src="/"transport=" anywhere
1237
+ // in the FILE, so a2ui-root.js's own docstring (documenting both usage
1238
+ // modes side by side in one comment block) tripped it, even with the
1239
+ // RUNTIME_HOME_PATH exemption above already carved out for that one file.
1240
+ // The real bug is broader than that single case: any consumer file wiring
1241
+ // TWO root elements, one fed declaratively and one fed programmatically,
1242
+ // was also a false positive, since the old match never asked WHICH
1243
+ // element each signal belonged to.
1244
+ //
1245
+ // This is a regex heuristic, not a JS/HTML parser, so it correlates by two
1246
+ // cheap signals rather than real scope analysis:
1247
+ // 1. Single-element files: if the file has exactly one <a2ui-root>/
1248
+ // <gen-root> tag, any ".doc =" assignment anywhere in the file is
1249
+ // presumed to target that one element (nothing else for it to mean).
1250
+ // 2. Multi-element files: a ".doc =" assignment correlates to a specific
1251
+ // element only when its target variable was bound via
1252
+ // document.getElementById('id') / document.querySelector('#id') to
1253
+ // an element carrying a matching id="..." attribute.
1254
+ // Documented misses (false negatives), by design rather than oversight:
1255
+ // - A file with 2+ root elements where NONE carry an id= attribute, or
1256
+ // where the ".doc =" target variable is bound some other way (a
1257
+ // framework ref, a destructured array, ".doc =" set via "this.el"),
1258
+ // cannot be correlated and is silently allowed. The old file-wide
1259
+ // check would have (over-)caught this, at the cost of the
1260
+ // a2ui-root.js false positive this ticket exists to fix.
1261
+ // Documented possible false positive: in a single-element file, a ".doc ="
1262
+ // assignment that provably targets a DIFFERENT, unrelated object which
1263
+ // merely has its own "doc" property (e.g. an unrelated "state.doc = ...")
1264
+ // cannot be told apart from a real root reference by rule 1 above.
1265
+ const ROOT_TAG = /<(a2ui-root|gen-root)\b([^>]*)>/g;
1266
+ const ID_ATTR = /\bid\s*=\s*["']([^"']+)["']/;
1267
+ const DECLARATIVE_ATTR = /\b(?:src|transport)\s*=/;
1268
+ const VAR_TO_ID =
1269
+ /(?:const|let|var)?\s*([A-Za-z_$][\w$]*)\s*=\s*document\.(?:getElementById\(\s*['"]([\w-]+)['"]\s*\)|querySelector\(\s*['"]#([\w-]+)['"]\s*\))/g;
1270
+ const DOC_ASSIGN = /([A-Za-z_$][\w$]*)\.doc\s*=/g;
1271
+
1091
1272
  const genuiDocConflict = {
1092
1273
  id: 'GENUI-DOC-CONFLICT',
1093
1274
  severity: 'error',
@@ -1095,17 +1276,34 @@ const genuiDocConflict = {
1095
1276
  fileTypes: APPLIES_EXT,
1096
1277
  match(text, filePath) {
1097
1278
  if (typeof filePath === 'string' && RUNTIME_HOME_PATH.test(filePath)) return [];
1098
- const m = /\.doc\s*=/.exec(text);
1099
- if (!m) return [];
1100
- const line = lineOf(text, m.index);
1101
- if (/<(?:a2ui-root|gen-root)[^>]*\b(?:src|transport)=/.test(text)) {
1102
- return [{
1103
- line,
1104
- snippet: '.doc = … alongside src=/transport=',
1279
+
1280
+ const elements = [];
1281
+ for (const m of text.matchAll(ROOT_TAG)) {
1282
+ const attrs = m[2];
1283
+ const idMatch = ID_ATTR.exec(attrs);
1284
+ elements.push({ id: idMatch ? idMatch[1] : null, declarative: DECLARATIVE_ATTR.test(attrs) });
1285
+ }
1286
+ if (elements.length === 0) return [];
1287
+
1288
+ const idsWithDeclarative = new Set(elements.filter((e) => e.declarative && e.id).map((e) => e.id));
1289
+ const varToId = new Map();
1290
+ for (const m of text.matchAll(VAR_TO_ID)) {
1291
+ varToId.set(m[1], m[2] || m[3]);
1292
+ }
1293
+ const soleElementIsDeclarative = elements.length === 1 && elements[0].declarative;
1294
+
1295
+ const findings = [];
1296
+ for (const m of text.matchAll(DOC_ASSIGN)) {
1297
+ const targetId = varToId.get(m[1]);
1298
+ const conflicts = targetId ? idsWithDeclarative.has(targetId) : soleElementIsDeclarative;
1299
+ if (!conflicts) continue;
1300
+ findings.push({
1301
+ line: lineOf(text, m.index),
1302
+ snippet: '.doc = … alongside src=/transport= on the same root',
1105
1303
  why: 'two feed paths fight — a root is fed EITHER declaratively (src/transport) OR programmatically (.doc), never both',
1106
- }];
1304
+ });
1107
1305
  }
1108
- return [];
1306
+ return findings;
1109
1307
  },
1110
1308
  };
1111
1309
 
@@ -1126,6 +1324,13 @@ RULES.push(genuiUnvalidated, genuiDocConflict);
1126
1324
  // gets the exemption; scope it to that tree, not the filename alone.
1127
1325
  const EXAMPLES_FILE = /\.examples\.html$/;
1128
1326
  const CATALOG_CONTENTS_FILE = /\.contents\.html$/;
1327
+ // packages/web-components/templates/ is the Class R npm mirror of those same
1328
+ // catalog/apps/playgrounds demo fragments (ADR-0084, built by
1329
+ // scripts/build/templates-mirror.mjs). The mirror step renames each file to
1330
+ // `pattern-library-<name>.html` and drops the `catalog/` prefix, so a
1331
+ // mirrored demo's default-open state no longer matches either pattern above
1332
+ // even though it is a byte-for-byte copy of already-exempt source markup.
1333
+ const TEMPLATES_MIRROR_DIR = /^packages\/web-components\/templates\//;
1129
1334
 
1130
1335
 
1131
1336
  RULES.push({
@@ -1137,6 +1342,7 @@ RULES.push({
1137
1342
  const p = (path || '').replace(/\\/g, '/');
1138
1343
  if (EXAMPLES_FILE.test(p)) return [];
1139
1344
  if (CATALOG_CONTENTS_FILE.test(p) && p.split('/')[0] === 'catalog') return [];
1345
+ if (TEMPLATES_MIRROR_DIR.test(p)) return [];
1140
1346
  const out = [];
1141
1347
  text.split('\n').forEach((line, i) => {
1142
1348
  if (RE.OVERLAY_OPEN.test(line)) {
@@ -1343,7 +1549,7 @@ RULES.push({
1343
1549
  }
1344
1550
 
1345
1551
  {
1346
- // GENERATED do not hand-edit. Source: packages/web-components/components/accordion/accordion-item.yaml's a2ui.allowedParents/allowedChildren.
1552
+ // GENERATED: do not hand-edit. Source: packages/web-components/components/accordion/accordion-item.yaml's a2ui.allowedParents/allowedChildren.
1347
1553
  // Rebuild: node scripts/build/gen-composition-rules.mjs
1348
1554
  // Freshness gate: node scripts/verify/check-composition-rules-fresh.mjs --verify
1349
1555
 
@@ -1351,15 +1557,16 @@ RULES.push({
1351
1557
  const TAG = "accordion-item-ui";
1352
1558
  const ALLOWED_PARENTS = ["accordion-ui"];
1353
1559
  const ALLOWED_CHILDREN = [];
1560
+ const ALLOWED_CHILDREN_BY_SLOT = null;
1354
1561
 
1355
1562
 
1356
1563
  RULES.push({
1357
1564
  id: "COMPOSITION-ACCORDION-ITEM-UI",
1358
- severity: 'warn', // LLD-0016 §C4: new, unproven-at-scale matcher (Risk R4) advisory until a corpus-wide rollout promotes it, same posture check-example-ids.mjs's Phase-1 rule started at.
1565
+ severity: 'warn', // LLD-0016 §C4: new, unproven-at-scale matcher (Risk R4): advisory until a corpus-wide rollout promotes it, same posture check-example-ids.mjs's Phase-1 rule started at.
1359
1566
  scope: 'shared',
1360
1567
  fileTypes: MARKUP_EXT,
1361
1568
  match(text) {
1362
- return compositionFindings(text, { tag: TAG, allowedParents: ALLOWED_PARENTS, allowedChildren: ALLOWED_CHILDREN });
1569
+ return compositionFindings(text, { tag: TAG, allowedParents: ALLOWED_PARENTS, allowedChildren: ALLOWED_CHILDREN, allowedChildrenBySlot: ALLOWED_CHILDREN_BY_SLOT });
1363
1570
  },
1364
1571
  fix: null, // moving markup to satisfy a composition constraint is a judgment call, not a mechanical rename (LLD-0016 §Risks R4/R5)
1365
1572
  fixtures: {
@@ -1374,7 +1581,7 @@ RULES.push({
1374
1581
  }
1375
1582
 
1376
1583
  {
1377
- // GENERATED do not hand-edit. Source: packages/web-components/components/accordion/accordion.yaml's a2ui.allowedParents/allowedChildren.
1584
+ // GENERATED: do not hand-edit. Source: packages/web-components/components/accordion/accordion.yaml's a2ui.allowedParents/allowedChildren.
1378
1585
  // Rebuild: node scripts/build/gen-composition-rules.mjs
1379
1586
  // Freshness gate: node scripts/verify/check-composition-rules-fresh.mjs --verify
1380
1587
 
@@ -1382,15 +1589,16 @@ RULES.push({
1382
1589
  const TAG = "accordion-ui";
1383
1590
  const ALLOWED_PARENTS = [];
1384
1591
  const ALLOWED_CHILDREN = ["accordion-item-ui"];
1592
+ const ALLOWED_CHILDREN_BY_SLOT = null;
1385
1593
 
1386
1594
 
1387
1595
  RULES.push({
1388
1596
  id: "COMPOSITION-ACCORDION-UI",
1389
- severity: 'warn', // LLD-0016 §C4: new, unproven-at-scale matcher (Risk R4) advisory until a corpus-wide rollout promotes it, same posture check-example-ids.mjs's Phase-1 rule started at.
1597
+ severity: 'warn', // LLD-0016 §C4: new, unproven-at-scale matcher (Risk R4): advisory until a corpus-wide rollout promotes it, same posture check-example-ids.mjs's Phase-1 rule started at.
1390
1598
  scope: 'shared',
1391
1599
  fileTypes: MARKUP_EXT,
1392
1600
  match(text) {
1393
- return compositionFindings(text, { tag: TAG, allowedParents: ALLOWED_PARENTS, allowedChildren: ALLOWED_CHILDREN });
1601
+ return compositionFindings(text, { tag: TAG, allowedParents: ALLOWED_PARENTS, allowedChildren: ALLOWED_CHILDREN, allowedChildrenBySlot: ALLOWED_CHILDREN_BY_SLOT });
1394
1602
  },
1395
1603
  fix: null, // moving markup to satisfy a composition constraint is a judgment call, not a mechanical rename (LLD-0016 §Risks R4/R5)
1396
1604
  fixtures: {
@@ -1398,14 +1606,15 @@ RULES.push({
1398
1606
  "<accordion-ui><not-an-allowed-child-ui></not-an-allowed-child-ui></accordion-ui>"
1399
1607
  ],
1400
1608
  "clean": [
1401
- "<accordion-ui><accordion-item-ui></accordion-item-ui></accordion-ui>"
1609
+ "<accordion-ui><accordion-item-ui></accordion-item-ui></accordion-ui>",
1610
+ "<accordion-ui><not-an-allowed-child-ui slot=\"arbitrary-slot\"></not-an-allowed-child-ui></accordion-ui>"
1402
1611
  ]
1403
1612
  },
1404
1613
  });
1405
1614
  }
1406
1615
 
1407
1616
  {
1408
- // GENERATED do not hand-edit. Source: packages/web-components/components/action-list/action-item.yaml's a2ui.allowedParents/allowedChildren.
1617
+ // GENERATED: do not hand-edit. Source: packages/web-components/components/action-list/action-item.yaml's a2ui.allowedParents/allowedChildren.
1409
1618
  // Rebuild: node scripts/build/gen-composition-rules.mjs
1410
1619
  // Freshness gate: node scripts/verify/check-composition-rules-fresh.mjs --verify
1411
1620
 
@@ -1413,15 +1622,16 @@ RULES.push({
1413
1622
  const TAG = "action-item-ui";
1414
1623
  const ALLOWED_PARENTS = ["action-list-ui"];
1415
1624
  const ALLOWED_CHILDREN = [];
1625
+ const ALLOWED_CHILDREN_BY_SLOT = null;
1416
1626
 
1417
1627
 
1418
1628
  RULES.push({
1419
1629
  id: "COMPOSITION-ACTION-ITEM-UI",
1420
- severity: 'warn', // LLD-0016 §C4: new, unproven-at-scale matcher (Risk R4) advisory until a corpus-wide rollout promotes it, same posture check-example-ids.mjs's Phase-1 rule started at.
1630
+ severity: 'warn', // LLD-0016 §C4: new, unproven-at-scale matcher (Risk R4): advisory until a corpus-wide rollout promotes it, same posture check-example-ids.mjs's Phase-1 rule started at.
1421
1631
  scope: 'shared',
1422
1632
  fileTypes: MARKUP_EXT,
1423
1633
  match(text) {
1424
- return compositionFindings(text, { tag: TAG, allowedParents: ALLOWED_PARENTS, allowedChildren: ALLOWED_CHILDREN });
1634
+ return compositionFindings(text, { tag: TAG, allowedParents: ALLOWED_PARENTS, allowedChildren: ALLOWED_CHILDREN, allowedChildrenBySlot: ALLOWED_CHILDREN_BY_SLOT });
1425
1635
  },
1426
1636
  fix: null, // moving markup to satisfy a composition constraint is a judgment call, not a mechanical rename (LLD-0016 §Risks R4/R5)
1427
1637
  fixtures: {
@@ -1436,7 +1646,7 @@ RULES.push({
1436
1646
  }
1437
1647
 
1438
1648
  {
1439
- // GENERATED do not hand-edit. Source: packages/web-components/components/action-list/action-list.yaml's a2ui.allowedParents/allowedChildren.
1649
+ // GENERATED: do not hand-edit. Source: packages/web-components/components/action-list/action-list.yaml's a2ui.allowedParents/allowedChildren.
1440
1650
  // Rebuild: node scripts/build/gen-composition-rules.mjs
1441
1651
  // Freshness gate: node scripts/verify/check-composition-rules-fresh.mjs --verify
1442
1652
 
@@ -1444,15 +1654,16 @@ RULES.push({
1444
1654
  const TAG = "action-list-ui";
1445
1655
  const ALLOWED_PARENTS = [];
1446
1656
  const ALLOWED_CHILDREN = ["action-item-ui"];
1657
+ const ALLOWED_CHILDREN_BY_SLOT = null;
1447
1658
 
1448
1659
 
1449
1660
  RULES.push({
1450
1661
  id: "COMPOSITION-ACTION-LIST-UI",
1451
- severity: 'warn', // LLD-0016 §C4: new, unproven-at-scale matcher (Risk R4) advisory until a corpus-wide rollout promotes it, same posture check-example-ids.mjs's Phase-1 rule started at.
1662
+ severity: 'warn', // LLD-0016 §C4: new, unproven-at-scale matcher (Risk R4): advisory until a corpus-wide rollout promotes it, same posture check-example-ids.mjs's Phase-1 rule started at.
1452
1663
  scope: 'shared',
1453
1664
  fileTypes: MARKUP_EXT,
1454
1665
  match(text) {
1455
- return compositionFindings(text, { tag: TAG, allowedParents: ALLOWED_PARENTS, allowedChildren: ALLOWED_CHILDREN });
1666
+ return compositionFindings(text, { tag: TAG, allowedParents: ALLOWED_PARENTS, allowedChildren: ALLOWED_CHILDREN, allowedChildrenBySlot: ALLOWED_CHILDREN_BY_SLOT });
1456
1667
  },
1457
1668
  fix: null, // moving markup to satisfy a composition constraint is a judgment call, not a mechanical rename (LLD-0016 §Risks R4/R5)
1458
1669
  fixtures: {
@@ -1460,14 +1671,15 @@ RULES.push({
1460
1671
  "<action-list-ui><not-an-allowed-child-ui></not-an-allowed-child-ui></action-list-ui>"
1461
1672
  ],
1462
1673
  "clean": [
1463
- "<action-list-ui><action-item-ui></action-item-ui></action-list-ui>"
1674
+ "<action-list-ui><action-item-ui></action-item-ui></action-list-ui>",
1675
+ "<action-list-ui><not-an-allowed-child-ui slot=\"arbitrary-slot\"></not-an-allowed-child-ui></action-list-ui>"
1464
1676
  ]
1465
1677
  },
1466
1678
  });
1467
1679
  }
1468
1680
 
1469
1681
  {
1470
- // GENERATED do not hand-edit. Source: packages/web-modules/shell/admin-command/admin-command.yaml's a2ui.allowedParents/allowedChildren.
1682
+ // GENERATED: do not hand-edit. Source: packages/web-modules/shell/admin-command/admin-command.yaml's a2ui.allowedParents/allowedChildren.
1471
1683
  // Rebuild: node scripts/build/gen-composition-rules.mjs
1472
1684
  // Freshness gate: node scripts/verify/check-composition-rules-fresh.mjs --verify
1473
1685
 
@@ -1475,15 +1687,16 @@ RULES.push({
1475
1687
  const TAG = "admin-command";
1476
1688
  const ALLOWED_PARENTS = ["admin-shell"];
1477
1689
  const ALLOWED_CHILDREN = [];
1690
+ const ALLOWED_CHILDREN_BY_SLOT = null;
1478
1691
 
1479
1692
 
1480
1693
  RULES.push({
1481
1694
  id: "COMPOSITION-ADMIN-COMMAND",
1482
- severity: 'warn', // LLD-0016 §C4: new, unproven-at-scale matcher (Risk R4) advisory until a corpus-wide rollout promotes it, same posture check-example-ids.mjs's Phase-1 rule started at.
1695
+ severity: 'warn', // LLD-0016 §C4: new, unproven-at-scale matcher (Risk R4): advisory until a corpus-wide rollout promotes it, same posture check-example-ids.mjs's Phase-1 rule started at.
1483
1696
  scope: 'shared',
1484
1697
  fileTypes: MARKUP_EXT,
1485
1698
  match(text) {
1486
- return compositionFindings(text, { tag: TAG, allowedParents: ALLOWED_PARENTS, allowedChildren: ALLOWED_CHILDREN });
1699
+ return compositionFindings(text, { tag: TAG, allowedParents: ALLOWED_PARENTS, allowedChildren: ALLOWED_CHILDREN, allowedChildrenBySlot: ALLOWED_CHILDREN_BY_SLOT });
1487
1700
  },
1488
1701
  fix: null, // moving markup to satisfy a composition constraint is a judgment call, not a mechanical rename (LLD-0016 §Risks R4/R5)
1489
1702
  fixtures: {
@@ -1498,7 +1711,7 @@ RULES.push({
1498
1711
  }
1499
1712
 
1500
1713
  {
1501
- // GENERATED do not hand-edit. Source: packages/web-modules/shell/admin-content/admin-content.yaml's a2ui.allowedParents/allowedChildren.
1714
+ // GENERATED: do not hand-edit. Source: packages/web-modules/shell/admin-content/admin-content.yaml's a2ui.allowedParents/allowedChildren.
1502
1715
  // Rebuild: node scripts/build/gen-composition-rules.mjs
1503
1716
  // Freshness gate: node scripts/verify/check-composition-rules-fresh.mjs --verify
1504
1717
 
@@ -1506,15 +1719,16 @@ RULES.push({
1506
1719
  const TAG = "admin-content";
1507
1720
  const ALLOWED_PARENTS = ["admin-shell"];
1508
1721
  const ALLOWED_CHILDREN = [];
1722
+ const ALLOWED_CHILDREN_BY_SLOT = null;
1509
1723
 
1510
1724
 
1511
1725
  RULES.push({
1512
1726
  id: "COMPOSITION-ADMIN-CONTENT",
1513
- severity: 'warn', // LLD-0016 §C4: new, unproven-at-scale matcher (Risk R4) advisory until a corpus-wide rollout promotes it, same posture check-example-ids.mjs's Phase-1 rule started at.
1727
+ severity: 'warn', // LLD-0016 §C4: new, unproven-at-scale matcher (Risk R4): advisory until a corpus-wide rollout promotes it, same posture check-example-ids.mjs's Phase-1 rule started at.
1514
1728
  scope: 'shared',
1515
1729
  fileTypes: MARKUP_EXT,
1516
1730
  match(text) {
1517
- return compositionFindings(text, { tag: TAG, allowedParents: ALLOWED_PARENTS, allowedChildren: ALLOWED_CHILDREN });
1731
+ return compositionFindings(text, { tag: TAG, allowedParents: ALLOWED_PARENTS, allowedChildren: ALLOWED_CHILDREN, allowedChildrenBySlot: ALLOWED_CHILDREN_BY_SLOT });
1518
1732
  },
1519
1733
  fix: null, // moving markup to satisfy a composition constraint is a judgment call, not a mechanical rename (LLD-0016 §Risks R4/R5)
1520
1734
  fixtures: {
@@ -1529,7 +1743,71 @@ RULES.push({
1529
1743
  }
1530
1744
 
1531
1745
  {
1532
- // GENERATED do not hand-edit. Source: packages/web-modules/shell/admin-scroll/admin-scroll.yaml's a2ui.allowedParents/allowedChildren.
1746
+ // GENERATED: do not hand-edit. Source: packages/web-modules/shell/admin-entity-item/admin-entity-item.yaml's a2ui.allowedParents/allowedChildren.
1747
+ // Rebuild: node scripts/build/gen-composition-rules.mjs
1748
+ // Freshness gate: node scripts/verify/check-composition-rules-fresh.mjs --verify
1749
+
1750
+
1751
+ const TAG = "admin-entity-item";
1752
+ const ALLOWED_PARENTS = ["admin-topbar","admin-statusbar"];
1753
+ const ALLOWED_CHILDREN = [];
1754
+ const ALLOWED_CHILDREN_BY_SLOT = null;
1755
+
1756
+
1757
+ RULES.push({
1758
+ id: "COMPOSITION-ADMIN-ENTITY-ITEM",
1759
+ severity: 'warn', // LLD-0016 §C4: new, unproven-at-scale matcher (Risk R4): advisory until a corpus-wide rollout promotes it, same posture check-example-ids.mjs's Phase-1 rule started at.
1760
+ scope: 'shared',
1761
+ fileTypes: MARKUP_EXT,
1762
+ match(text) {
1763
+ return compositionFindings(text, { tag: TAG, allowedParents: ALLOWED_PARENTS, allowedChildren: ALLOWED_CHILDREN, allowedChildrenBySlot: ALLOWED_CHILDREN_BY_SLOT });
1764
+ },
1765
+ fix: null, // moving markup to satisfy a composition constraint is a judgment call, not a mechanical rename (LLD-0016 §Risks R4/R5)
1766
+ fixtures: {
1767
+ "smelly": [
1768
+ "<div><admin-entity-item></admin-entity-item></div>"
1769
+ ],
1770
+ "clean": [
1771
+ "<admin-topbar><admin-entity-item></admin-entity-item></admin-topbar>"
1772
+ ]
1773
+ },
1774
+ });
1775
+ }
1776
+
1777
+ {
1778
+ // GENERATED: do not hand-edit. Source: packages/web-modules/agent-admin/admin-roster/admin-roster.yaml's a2ui.allowedParents/allowedChildren.
1779
+ // Rebuild: node scripts/build/gen-composition-rules.mjs
1780
+ // Freshness gate: node scripts/verify/check-composition-rules-fresh.mjs --verify
1781
+
1782
+
1783
+ const TAG = "admin-roster-ui";
1784
+ const ALLOWED_PARENTS = ["agent-admin-ui"];
1785
+ const ALLOWED_CHILDREN = [];
1786
+ const ALLOWED_CHILDREN_BY_SLOT = null;
1787
+
1788
+
1789
+ RULES.push({
1790
+ id: "COMPOSITION-ADMIN-ROSTER-UI",
1791
+ severity: 'warn', // LLD-0016 §C4: new, unproven-at-scale matcher (Risk R4): advisory until a corpus-wide rollout promotes it, same posture check-example-ids.mjs's Phase-1 rule started at.
1792
+ scope: 'shared',
1793
+ fileTypes: MARKUP_EXT,
1794
+ match(text) {
1795
+ return compositionFindings(text, { tag: TAG, allowedParents: ALLOWED_PARENTS, allowedChildren: ALLOWED_CHILDREN, allowedChildrenBySlot: ALLOWED_CHILDREN_BY_SLOT });
1796
+ },
1797
+ fix: null, // moving markup to satisfy a composition constraint is a judgment call, not a mechanical rename (LLD-0016 §Risks R4/R5)
1798
+ fixtures: {
1799
+ "smelly": [
1800
+ "<div><admin-roster-ui></admin-roster-ui></div>"
1801
+ ],
1802
+ "clean": [
1803
+ "<agent-admin-ui><admin-roster-ui></admin-roster-ui></agent-admin-ui>"
1804
+ ]
1805
+ },
1806
+ });
1807
+ }
1808
+
1809
+ {
1810
+ // GENERATED: do not hand-edit. Source: packages/web-modules/shell/admin-scroll/admin-scroll.yaml's a2ui.allowedParents/allowedChildren.
1533
1811
  // Rebuild: node scripts/build/gen-composition-rules.mjs
1534
1812
  // Freshness gate: node scripts/verify/check-composition-rules-fresh.mjs --verify
1535
1813
 
@@ -1537,15 +1815,16 @@ RULES.push({
1537
1815
  const TAG = "admin-scroll";
1538
1816
  const ALLOWED_PARENTS = ["admin-content"];
1539
1817
  const ALLOWED_CHILDREN = [];
1818
+ const ALLOWED_CHILDREN_BY_SLOT = null;
1540
1819
 
1541
1820
 
1542
1821
  RULES.push({
1543
1822
  id: "COMPOSITION-ADMIN-SCROLL",
1544
- severity: 'warn', // LLD-0016 §C4: new, unproven-at-scale matcher (Risk R4) advisory until a corpus-wide rollout promotes it, same posture check-example-ids.mjs's Phase-1 rule started at.
1823
+ severity: 'warn', // LLD-0016 §C4: new, unproven-at-scale matcher (Risk R4): advisory until a corpus-wide rollout promotes it, same posture check-example-ids.mjs's Phase-1 rule started at.
1545
1824
  scope: 'shared',
1546
1825
  fileTypes: MARKUP_EXT,
1547
1826
  match(text) {
1548
- return compositionFindings(text, { tag: TAG, allowedParents: ALLOWED_PARENTS, allowedChildren: ALLOWED_CHILDREN });
1827
+ return compositionFindings(text, { tag: TAG, allowedParents: ALLOWED_PARENTS, allowedChildren: ALLOWED_CHILDREN, allowedChildrenBySlot: ALLOWED_CHILDREN_BY_SLOT });
1549
1828
  },
1550
1829
  fix: null, // moving markup to satisfy a composition constraint is a judgment call, not a mechanical rename (LLD-0016 §Risks R4/R5)
1551
1830
  fixtures: {
@@ -1560,7 +1839,39 @@ RULES.push({
1560
1839
  }
1561
1840
 
1562
1841
  {
1563
- // GENERATED do not hand-edit. Source: packages/web-modules/shell/admin-shell/admin-shell.yaml's a2ui.allowedParents/allowedChildren.
1842
+ // GENERATED: do not hand-edit. Source: packages/web-modules/agent-admin/admin-settings/admin-settings.yaml's a2ui.allowedParents/allowedChildren.
1843
+ // Rebuild: node scripts/build/gen-composition-rules.mjs
1844
+ // Freshness gate: node scripts/verify/check-composition-rules-fresh.mjs --verify
1845
+
1846
+
1847
+ const TAG = "admin-settings-ui";
1848
+ const ALLOWED_PARENTS = ["agent-admin-ui"];
1849
+ const ALLOWED_CHILDREN = [];
1850
+ const ALLOWED_CHILDREN_BY_SLOT = null;
1851
+
1852
+
1853
+ RULES.push({
1854
+ id: "COMPOSITION-ADMIN-SETTINGS-UI",
1855
+ severity: 'warn', // LLD-0016 §C4: new, unproven-at-scale matcher (Risk R4): advisory until a corpus-wide rollout promotes it, same posture check-example-ids.mjs's Phase-1 rule started at.
1856
+ scope: 'shared',
1857
+ fileTypes: MARKUP_EXT,
1858
+ match(text) {
1859
+ return compositionFindings(text, { tag: TAG, allowedParents: ALLOWED_PARENTS, allowedChildren: ALLOWED_CHILDREN, allowedChildrenBySlot: ALLOWED_CHILDREN_BY_SLOT });
1860
+ },
1861
+ fix: null, // moving markup to satisfy a composition constraint is a judgment call, not a mechanical rename (LLD-0016 §Risks R4/R5)
1862
+ fixtures: {
1863
+ "smelly": [
1864
+ "<div><admin-settings-ui></admin-settings-ui></div>"
1865
+ ],
1866
+ "clean": [
1867
+ "<agent-admin-ui><admin-settings-ui></admin-settings-ui></agent-admin-ui>"
1868
+ ]
1869
+ },
1870
+ });
1871
+ }
1872
+
1873
+ {
1874
+ // GENERATED: do not hand-edit. Source: packages/web-modules/shell/admin-shell/admin-shell.yaml's a2ui.allowedParents/allowedChildren.
1564
1875
  // Rebuild: node scripts/build/gen-composition-rules.mjs
1565
1876
  // Freshness gate: node scripts/verify/check-composition-rules-fresh.mjs --verify
1566
1877
 
@@ -1568,15 +1879,16 @@ RULES.push({
1568
1879
  const TAG = "admin-shell";
1569
1880
  const ALLOWED_PARENTS = ["Surface"];
1570
1881
  const ALLOWED_CHILDREN = [];
1882
+ const ALLOWED_CHILDREN_BY_SLOT = null;
1571
1883
 
1572
1884
 
1573
1885
  RULES.push({
1574
1886
  id: "COMPOSITION-ADMIN-SHELL",
1575
- severity: 'warn', // LLD-0016 §C4: new, unproven-at-scale matcher (Risk R4) advisory until a corpus-wide rollout promotes it, same posture check-example-ids.mjs's Phase-1 rule started at.
1887
+ severity: 'warn', // LLD-0016 §C4: new, unproven-at-scale matcher (Risk R4): advisory until a corpus-wide rollout promotes it, same posture check-example-ids.mjs's Phase-1 rule started at.
1576
1888
  scope: 'shared',
1577
1889
  fileTypes: MARKUP_EXT,
1578
1890
  match(text) {
1579
- return compositionFindings(text, { tag: TAG, allowedParents: ALLOWED_PARENTS, allowedChildren: ALLOWED_CHILDREN });
1891
+ return compositionFindings(text, { tag: TAG, allowedParents: ALLOWED_PARENTS, allowedChildren: ALLOWED_CHILDREN, allowedChildrenBySlot: ALLOWED_CHILDREN_BY_SLOT });
1580
1892
  },
1581
1893
  fix: null, // moving markup to satisfy a composition constraint is a judgment call, not a mechanical rename (LLD-0016 §Risks R4/R5)
1582
1894
  fixtures: {
@@ -1591,7 +1903,7 @@ RULES.push({
1591
1903
  }
1592
1904
 
1593
1905
  {
1594
- // GENERATED do not hand-edit. Source: packages/web-modules/shell/admin-sidebar/admin-sidebar.yaml's a2ui.allowedParents/allowedChildren.
1906
+ // GENERATED: do not hand-edit. Source: packages/web-modules/shell/admin-sidebar/admin-sidebar.yaml's a2ui.allowedParents/allowedChildren.
1595
1907
  // Rebuild: node scripts/build/gen-composition-rules.mjs
1596
1908
  // Freshness gate: node scripts/verify/check-composition-rules-fresh.mjs --verify
1597
1909
 
@@ -1599,15 +1911,16 @@ RULES.push({
1599
1911
  const TAG = "admin-sidebar";
1600
1912
  const ALLOWED_PARENTS = ["admin-shell"];
1601
1913
  const ALLOWED_CHILDREN = [];
1914
+ const ALLOWED_CHILDREN_BY_SLOT = null;
1602
1915
 
1603
1916
 
1604
1917
  RULES.push({
1605
1918
  id: "COMPOSITION-ADMIN-SIDEBAR",
1606
- severity: 'warn', // LLD-0016 §C4: new, unproven-at-scale matcher (Risk R4) advisory until a corpus-wide rollout promotes it, same posture check-example-ids.mjs's Phase-1 rule started at.
1919
+ severity: 'warn', // LLD-0016 §C4: new, unproven-at-scale matcher (Risk R4): advisory until a corpus-wide rollout promotes it, same posture check-example-ids.mjs's Phase-1 rule started at.
1607
1920
  scope: 'shared',
1608
1921
  fileTypes: MARKUP_EXT,
1609
1922
  match(text) {
1610
- return compositionFindings(text, { tag: TAG, allowedParents: ALLOWED_PARENTS, allowedChildren: ALLOWED_CHILDREN });
1923
+ return compositionFindings(text, { tag: TAG, allowedParents: ALLOWED_PARENTS, allowedChildren: ALLOWED_CHILDREN, allowedChildrenBySlot: ALLOWED_CHILDREN_BY_SLOT });
1611
1924
  },
1612
1925
  fix: null, // moving markup to satisfy a composition constraint is a judgment call, not a mechanical rename (LLD-0016 §Risks R4/R5)
1613
1926
  fixtures: {
@@ -1622,7 +1935,7 @@ RULES.push({
1622
1935
  }
1623
1936
 
1624
1937
  {
1625
- // GENERATED do not hand-edit. Source: packages/web-modules/shell/admin-statusbar/admin-statusbar.yaml's a2ui.allowedParents/allowedChildren.
1938
+ // GENERATED: do not hand-edit. Source: packages/web-modules/shell/admin-statusbar/admin-statusbar.yaml's a2ui.allowedParents/allowedChildren.
1626
1939
  // Rebuild: node scripts/build/gen-composition-rules.mjs
1627
1940
  // Freshness gate: node scripts/verify/check-composition-rules-fresh.mjs --verify
1628
1941
 
@@ -1630,15 +1943,16 @@ RULES.push({
1630
1943
  const TAG = "admin-statusbar";
1631
1944
  const ALLOWED_PARENTS = ["admin-shell","admin-content","admin-sidebar"];
1632
1945
  const ALLOWED_CHILDREN = [];
1946
+ const ALLOWED_CHILDREN_BY_SLOT = null;
1633
1947
 
1634
1948
 
1635
1949
  RULES.push({
1636
1950
  id: "COMPOSITION-ADMIN-STATUSBAR",
1637
- severity: 'warn', // LLD-0016 §C4: new, unproven-at-scale matcher (Risk R4) advisory until a corpus-wide rollout promotes it, same posture check-example-ids.mjs's Phase-1 rule started at.
1951
+ severity: 'warn', // LLD-0016 §C4: new, unproven-at-scale matcher (Risk R4): advisory until a corpus-wide rollout promotes it, same posture check-example-ids.mjs's Phase-1 rule started at.
1638
1952
  scope: 'shared',
1639
1953
  fileTypes: MARKUP_EXT,
1640
1954
  match(text) {
1641
- return compositionFindings(text, { tag: TAG, allowedParents: ALLOWED_PARENTS, allowedChildren: ALLOWED_CHILDREN });
1955
+ return compositionFindings(text, { tag: TAG, allowedParents: ALLOWED_PARENTS, allowedChildren: ALLOWED_CHILDREN, allowedChildrenBySlot: ALLOWED_CHILDREN_BY_SLOT });
1642
1956
  },
1643
1957
  fix: null, // moving markup to satisfy a composition constraint is a judgment call, not a mechanical rename (LLD-0016 §Risks R4/R5)
1644
1958
  fixtures: {
@@ -1653,7 +1967,7 @@ RULES.push({
1653
1967
  }
1654
1968
 
1655
1969
  {
1656
- // GENERATED do not hand-edit. Source: packages/web-modules/shell/admin-topbar/admin-topbar.yaml's a2ui.allowedParents/allowedChildren.
1970
+ // GENERATED: do not hand-edit. Source: packages/web-modules/shell/admin-topbar/admin-topbar.yaml's a2ui.allowedParents/allowedChildren.
1657
1971
  // Rebuild: node scripts/build/gen-composition-rules.mjs
1658
1972
  // Freshness gate: node scripts/verify/check-composition-rules-fresh.mjs --verify
1659
1973
 
@@ -1661,15 +1975,16 @@ RULES.push({
1661
1975
  const TAG = "admin-topbar";
1662
1976
  const ALLOWED_PARENTS = ["admin-shell","admin-content","admin-sidebar"];
1663
1977
  const ALLOWED_CHILDREN = [];
1978
+ const ALLOWED_CHILDREN_BY_SLOT = null;
1664
1979
 
1665
1980
 
1666
1981
  RULES.push({
1667
1982
  id: "COMPOSITION-ADMIN-TOPBAR",
1668
- severity: 'warn', // LLD-0016 §C4: new, unproven-at-scale matcher (Risk R4) advisory until a corpus-wide rollout promotes it, same posture check-example-ids.mjs's Phase-1 rule started at.
1983
+ severity: 'warn', // LLD-0016 §C4: new, unproven-at-scale matcher (Risk R4): advisory until a corpus-wide rollout promotes it, same posture check-example-ids.mjs's Phase-1 rule started at.
1669
1984
  scope: 'shared',
1670
1985
  fileTypes: MARKUP_EXT,
1671
1986
  match(text) {
1672
- return compositionFindings(text, { tag: TAG, allowedParents: ALLOWED_PARENTS, allowedChildren: ALLOWED_CHILDREN });
1987
+ return compositionFindings(text, { tag: TAG, allowedParents: ALLOWED_PARENTS, allowedChildren: ALLOWED_CHILDREN, allowedChildrenBySlot: ALLOWED_CHILDREN_BY_SLOT });
1673
1988
  },
1674
1989
  fix: null, // moving markup to satisfy a composition constraint is a judgment call, not a mechanical rename (LLD-0016 §Risks R4/R5)
1675
1990
  fixtures: {
@@ -1684,7 +1999,105 @@ RULES.push({
1684
1999
  }
1685
2000
 
1686
2001
  {
1687
- // GENERATED do not hand-edit. Source: packages/web-modules/chat/chat-empty/chat-empty.yaml's a2ui.allowedParents/allowedChildren.
2002
+ // GENERATED: do not hand-edit. Source: packages/web-modules/agent-admin/agent-admin/agent-admin.yaml's a2ui.allowedParents/allowedChildren.
2003
+ // Rebuild: node scripts/build/gen-composition-rules.mjs
2004
+ // Freshness gate: node scripts/verify/check-composition-rules-fresh.mjs --verify
2005
+
2006
+
2007
+ const TAG = "agent-admin-ui";
2008
+ const ALLOWED_PARENTS = [];
2009
+ const ALLOWED_CHILDREN = ["admin-roster-ui","admin-settings-ui","chat-shell"];
2010
+ const ALLOWED_CHILDREN_BY_SLOT = null;
2011
+
2012
+
2013
+ RULES.push({
2014
+ id: "COMPOSITION-AGENT-ADMIN-UI",
2015
+ severity: 'warn', // LLD-0016 §C4: new, unproven-at-scale matcher (Risk R4): advisory until a corpus-wide rollout promotes it, same posture check-example-ids.mjs's Phase-1 rule started at.
2016
+ scope: 'shared',
2017
+ fileTypes: MARKUP_EXT,
2018
+ match(text) {
2019
+ return compositionFindings(text, { tag: TAG, allowedParents: ALLOWED_PARENTS, allowedChildren: ALLOWED_CHILDREN, allowedChildrenBySlot: ALLOWED_CHILDREN_BY_SLOT });
2020
+ },
2021
+ fix: null, // moving markup to satisfy a composition constraint is a judgment call, not a mechanical rename (LLD-0016 §Risks R4/R5)
2022
+ fixtures: {
2023
+ "smelly": [
2024
+ "<agent-admin-ui><not-an-allowed-child-ui></not-an-allowed-child-ui></agent-admin-ui>"
2025
+ ],
2026
+ "clean": [
2027
+ "<agent-admin-ui><admin-roster-ui></admin-roster-ui></agent-admin-ui>",
2028
+ "<agent-admin-ui><not-an-allowed-child-ui slot=\"arbitrary-slot\"></not-an-allowed-child-ui></agent-admin-ui>"
2029
+ ]
2030
+ },
2031
+ });
2032
+ }
2033
+
2034
+ {
2035
+ // GENERATED: do not hand-edit. Source: packages/web-components/components/avatar/avatar-group.yaml's a2ui.allowedParents/allowedChildren.
2036
+ // Rebuild: node scripts/build/gen-composition-rules.mjs
2037
+ // Freshness gate: node scripts/verify/check-composition-rules-fresh.mjs --verify
2038
+
2039
+
2040
+ const TAG = "avatar-group-ui";
2041
+ const ALLOWED_PARENTS = [];
2042
+ const ALLOWED_CHILDREN = ["avatar-ui"];
2043
+ const ALLOWED_CHILDREN_BY_SLOT = null;
2044
+
2045
+
2046
+ RULES.push({
2047
+ id: "COMPOSITION-AVATAR-GROUP-UI",
2048
+ severity: 'warn', // LLD-0016 §C4: new, unproven-at-scale matcher (Risk R4): advisory until a corpus-wide rollout promotes it, same posture check-example-ids.mjs's Phase-1 rule started at.
2049
+ scope: 'shared',
2050
+ fileTypes: MARKUP_EXT,
2051
+ match(text) {
2052
+ return compositionFindings(text, { tag: TAG, allowedParents: ALLOWED_PARENTS, allowedChildren: ALLOWED_CHILDREN, allowedChildrenBySlot: ALLOWED_CHILDREN_BY_SLOT });
2053
+ },
2054
+ fix: null, // moving markup to satisfy a composition constraint is a judgment call, not a mechanical rename (LLD-0016 §Risks R4/R5)
2055
+ fixtures: {
2056
+ "smelly": [
2057
+ "<avatar-group-ui><not-an-allowed-child-ui></not-an-allowed-child-ui></avatar-group-ui>"
2058
+ ],
2059
+ "clean": [
2060
+ "<avatar-group-ui><avatar-ui></avatar-ui></avatar-group-ui>",
2061
+ "<avatar-group-ui><not-an-allowed-child-ui slot=\"arbitrary-slot\"></not-an-allowed-child-ui></avatar-group-ui>"
2062
+ ]
2063
+ },
2064
+ });
2065
+ }
2066
+
2067
+ {
2068
+ // GENERATED: do not hand-edit. Source: packages/web-modules/chat/chat-composer/chat-composer.yaml's a2ui.allowedParents/allowedChildren.
2069
+ // Rebuild: node scripts/build/gen-composition-rules.mjs
2070
+ // Freshness gate: node scripts/verify/check-composition-rules-fresh.mjs --verify
2071
+
2072
+
2073
+ const TAG = "chat-composer";
2074
+ const ALLOWED_PARENTS = ["chat-shell"];
2075
+ const ALLOWED_CHILDREN = [];
2076
+ const ALLOWED_CHILDREN_BY_SLOT = null;
2077
+
2078
+
2079
+ RULES.push({
2080
+ id: "COMPOSITION-CHAT-COMPOSER",
2081
+ severity: 'warn', // LLD-0016 §C4: new, unproven-at-scale matcher (Risk R4): advisory until a corpus-wide rollout promotes it, same posture check-example-ids.mjs's Phase-1 rule started at.
2082
+ scope: 'shared',
2083
+ fileTypes: MARKUP_EXT,
2084
+ match(text) {
2085
+ return compositionFindings(text, { tag: TAG, allowedParents: ALLOWED_PARENTS, allowedChildren: ALLOWED_CHILDREN, allowedChildrenBySlot: ALLOWED_CHILDREN_BY_SLOT });
2086
+ },
2087
+ fix: null, // moving markup to satisfy a composition constraint is a judgment call, not a mechanical rename (LLD-0016 §Risks R4/R5)
2088
+ fixtures: {
2089
+ "smelly": [
2090
+ "<div><chat-composer></chat-composer></div>"
2091
+ ],
2092
+ "clean": [
2093
+ "<chat-shell><chat-composer></chat-composer></chat-shell>"
2094
+ ]
2095
+ },
2096
+ });
2097
+ }
2098
+
2099
+ {
2100
+ // GENERATED: do not hand-edit. Source: packages/web-modules/chat/chat-empty/chat-empty.yaml's a2ui.allowedParents/allowedChildren.
1688
2101
  // Rebuild: node scripts/build/gen-composition-rules.mjs
1689
2102
  // Freshness gate: node scripts/verify/check-composition-rules-fresh.mjs --verify
1690
2103
 
@@ -1692,15 +2105,16 @@ RULES.push({
1692
2105
  const TAG = "chat-empty";
1693
2106
  const ALLOWED_PARENTS = ["chat-thread"];
1694
2107
  const ALLOWED_CHILDREN = [];
2108
+ const ALLOWED_CHILDREN_BY_SLOT = null;
1695
2109
 
1696
2110
 
1697
2111
  RULES.push({
1698
2112
  id: "COMPOSITION-CHAT-EMPTY",
1699
- severity: 'warn', // LLD-0016 §C4: new, unproven-at-scale matcher (Risk R4) advisory until a corpus-wide rollout promotes it, same posture check-example-ids.mjs's Phase-1 rule started at.
2113
+ severity: 'warn', // LLD-0016 §C4: new, unproven-at-scale matcher (Risk R4): advisory until a corpus-wide rollout promotes it, same posture check-example-ids.mjs's Phase-1 rule started at.
1700
2114
  scope: 'shared',
1701
2115
  fileTypes: MARKUP_EXT,
1702
2116
  match(text) {
1703
- return compositionFindings(text, { tag: TAG, allowedParents: ALLOWED_PARENTS, allowedChildren: ALLOWED_CHILDREN });
2117
+ return compositionFindings(text, { tag: TAG, allowedParents: ALLOWED_PARENTS, allowedChildren: ALLOWED_CHILDREN, allowedChildrenBySlot: ALLOWED_CHILDREN_BY_SLOT });
1704
2118
  },
1705
2119
  fix: null, // moving markup to satisfy a composition constraint is a judgment call, not a mechanical rename (LLD-0016 §Risks R4/R5)
1706
2120
  fixtures: {
@@ -1715,7 +2129,7 @@ RULES.push({
1715
2129
  }
1716
2130
 
1717
2131
  {
1718
- // GENERATED do not hand-edit. Source: packages/web-modules/chat/chat-header/chat-header.yaml's a2ui.allowedParents/allowedChildren.
2132
+ // GENERATED: do not hand-edit. Source: packages/web-modules/chat/chat-header/chat-header.yaml's a2ui.allowedParents/allowedChildren.
1719
2133
  // Rebuild: node scripts/build/gen-composition-rules.mjs
1720
2134
  // Freshness gate: node scripts/verify/check-composition-rules-fresh.mjs --verify
1721
2135
 
@@ -1723,15 +2137,16 @@ RULES.push({
1723
2137
  const TAG = "chat-header";
1724
2138
  const ALLOWED_PARENTS = ["chat-shell","chat-sidebar"];
1725
2139
  const ALLOWED_CHILDREN = [];
2140
+ const ALLOWED_CHILDREN_BY_SLOT = null;
1726
2141
 
1727
2142
 
1728
2143
  RULES.push({
1729
2144
  id: "COMPOSITION-CHAT-HEADER",
1730
- severity: 'warn', // LLD-0016 §C4: new, unproven-at-scale matcher (Risk R4) advisory until a corpus-wide rollout promotes it, same posture check-example-ids.mjs's Phase-1 rule started at.
2145
+ severity: 'warn', // LLD-0016 §C4: new, unproven-at-scale matcher (Risk R4): advisory until a corpus-wide rollout promotes it, same posture check-example-ids.mjs's Phase-1 rule started at.
1731
2146
  scope: 'shared',
1732
2147
  fileTypes: MARKUP_EXT,
1733
2148
  match(text) {
1734
- return compositionFindings(text, { tag: TAG, allowedParents: ALLOWED_PARENTS, allowedChildren: ALLOWED_CHILDREN });
2149
+ return compositionFindings(text, { tag: TAG, allowedParents: ALLOWED_PARENTS, allowedChildren: ALLOWED_CHILDREN, allowedChildrenBySlot: ALLOWED_CHILDREN_BY_SLOT });
1735
2150
  },
1736
2151
  fix: null, // moving markup to satisfy a composition constraint is a judgment call, not a mechanical rename (LLD-0016 §Risks R4/R5)
1737
2152
  fixtures: {
@@ -1746,23 +2161,24 @@ RULES.push({
1746
2161
  }
1747
2162
 
1748
2163
  {
1749
- // GENERATED do not hand-edit. Source: packages/web-modules/chat/chat-shell/chat-shell.yaml's a2ui.allowedParents/allowedChildren.
2164
+ // GENERATED: do not hand-edit. Source: packages/web-modules/chat/chat-shell/chat-shell.yaml's a2ui.allowedParents/allowedChildren.
1750
2165
  // Rebuild: node scripts/build/gen-composition-rules.mjs
1751
2166
  // Freshness gate: node scripts/verify/check-composition-rules-fresh.mjs --verify
1752
2167
 
1753
2168
 
1754
2169
  const TAG = "chat-shell";
1755
- const ALLOWED_PARENTS = ["Surface"];
2170
+ const ALLOWED_PARENTS = ["Surface","agent-admin-ui"];
1756
2171
  const ALLOWED_CHILDREN = [];
2172
+ const ALLOWED_CHILDREN_BY_SLOT = null;
1757
2173
 
1758
2174
 
1759
2175
  RULES.push({
1760
2176
  id: "COMPOSITION-CHAT-SHELL",
1761
- severity: 'warn', // LLD-0016 §C4: new, unproven-at-scale matcher (Risk R4) advisory until a corpus-wide rollout promotes it, same posture check-example-ids.mjs's Phase-1 rule started at.
2177
+ severity: 'warn', // LLD-0016 §C4: new, unproven-at-scale matcher (Risk R4): advisory until a corpus-wide rollout promotes it, same posture check-example-ids.mjs's Phase-1 rule started at.
1762
2178
  scope: 'shared',
1763
2179
  fileTypes: MARKUP_EXT,
1764
2180
  match(text) {
1765
- return compositionFindings(text, { tag: TAG, allowedParents: ALLOWED_PARENTS, allowedChildren: ALLOWED_CHILDREN });
2181
+ return compositionFindings(text, { tag: TAG, allowedParents: ALLOWED_PARENTS, allowedChildren: ALLOWED_CHILDREN, allowedChildrenBySlot: ALLOWED_CHILDREN_BY_SLOT });
1766
2182
  },
1767
2183
  fix: null, // moving markup to satisfy a composition constraint is a judgment call, not a mechanical rename (LLD-0016 §Risks R4/R5)
1768
2184
  fixtures: {
@@ -1777,7 +2193,7 @@ RULES.push({
1777
2193
  }
1778
2194
 
1779
2195
  {
1780
- // GENERATED do not hand-edit. Source: packages/web-modules/chat/chat-sidebar/chat-sidebar.yaml's a2ui.allowedParents/allowedChildren.
2196
+ // GENERATED: do not hand-edit. Source: packages/web-modules/chat/chat-sidebar/chat-sidebar.yaml's a2ui.allowedParents/allowedChildren.
1781
2197
  // Rebuild: node scripts/build/gen-composition-rules.mjs
1782
2198
  // Freshness gate: node scripts/verify/check-composition-rules-fresh.mjs --verify
1783
2199
 
@@ -1785,15 +2201,16 @@ RULES.push({
1785
2201
  const TAG = "chat-sidebar";
1786
2202
  const ALLOWED_PARENTS = ["chat-shell"];
1787
2203
  const ALLOWED_CHILDREN = [];
2204
+ const ALLOWED_CHILDREN_BY_SLOT = null;
1788
2205
 
1789
2206
 
1790
2207
  RULES.push({
1791
2208
  id: "COMPOSITION-CHAT-SIDEBAR",
1792
- severity: 'warn', // LLD-0016 §C4: new, unproven-at-scale matcher (Risk R4) advisory until a corpus-wide rollout promotes it, same posture check-example-ids.mjs's Phase-1 rule started at.
2209
+ severity: 'warn', // LLD-0016 §C4: new, unproven-at-scale matcher (Risk R4): advisory until a corpus-wide rollout promotes it, same posture check-example-ids.mjs's Phase-1 rule started at.
1793
2210
  scope: 'shared',
1794
2211
  fileTypes: MARKUP_EXT,
1795
2212
  match(text) {
1796
- return compositionFindings(text, { tag: TAG, allowedParents: ALLOWED_PARENTS, allowedChildren: ALLOWED_CHILDREN });
2213
+ return compositionFindings(text, { tag: TAG, allowedParents: ALLOWED_PARENTS, allowedChildren: ALLOWED_CHILDREN, allowedChildrenBySlot: ALLOWED_CHILDREN_BY_SLOT });
1797
2214
  },
1798
2215
  fix: null, // moving markup to satisfy a composition constraint is a judgment call, not a mechanical rename (LLD-0016 §Risks R4/R5)
1799
2216
  fixtures: {
@@ -1808,7 +2225,7 @@ RULES.push({
1808
2225
  }
1809
2226
 
1810
2227
  {
1811
- // GENERATED do not hand-edit. Source: packages/web-modules/chat/chat-status/chat-status.yaml's a2ui.allowedParents/allowedChildren.
2228
+ // GENERATED: do not hand-edit. Source: packages/web-modules/chat/chat-status/chat-status.yaml's a2ui.allowedParents/allowedChildren.
1812
2229
  // Rebuild: node scripts/build/gen-composition-rules.mjs
1813
2230
  // Freshness gate: node scripts/verify/check-composition-rules-fresh.mjs --verify
1814
2231
 
@@ -1816,15 +2233,16 @@ RULES.push({
1816
2233
  const TAG = "chat-status";
1817
2234
  const ALLOWED_PARENTS = ["chat-header"];
1818
2235
  const ALLOWED_CHILDREN = [];
2236
+ const ALLOWED_CHILDREN_BY_SLOT = null;
1819
2237
 
1820
2238
 
1821
2239
  RULES.push({
1822
2240
  id: "COMPOSITION-CHAT-STATUS",
1823
- severity: 'warn', // LLD-0016 §C4: new, unproven-at-scale matcher (Risk R4) advisory until a corpus-wide rollout promotes it, same posture check-example-ids.mjs's Phase-1 rule started at.
2241
+ severity: 'warn', // LLD-0016 §C4: new, unproven-at-scale matcher (Risk R4): advisory until a corpus-wide rollout promotes it, same posture check-example-ids.mjs's Phase-1 rule started at.
1824
2242
  scope: 'shared',
1825
2243
  fileTypes: MARKUP_EXT,
1826
2244
  match(text) {
1827
- return compositionFindings(text, { tag: TAG, allowedParents: ALLOWED_PARENTS, allowedChildren: ALLOWED_CHILDREN });
2245
+ return compositionFindings(text, { tag: TAG, allowedParents: ALLOWED_PARENTS, allowedChildren: ALLOWED_CHILDREN, allowedChildrenBySlot: ALLOWED_CHILDREN_BY_SLOT });
1828
2246
  },
1829
2247
  fix: null, // moving markup to satisfy a composition constraint is a judgment call, not a mechanical rename (LLD-0016 §Risks R4/R5)
1830
2248
  fixtures: {
@@ -1839,7 +2257,7 @@ RULES.push({
1839
2257
  }
1840
2258
 
1841
2259
  {
1842
- // GENERATED do not hand-edit. Source: packages/web-modules/chat/chat-thread/chat-thread.yaml's a2ui.allowedParents/allowedChildren.
2260
+ // GENERATED: do not hand-edit. Source: packages/web-modules/chat/chat-thread/chat-thread.yaml's a2ui.allowedParents/allowedChildren.
1843
2261
  // Rebuild: node scripts/build/gen-composition-rules.mjs
1844
2262
  // Freshness gate: node scripts/verify/check-composition-rules-fresh.mjs --verify
1845
2263
 
@@ -1847,15 +2265,16 @@ RULES.push({
1847
2265
  const TAG = "chat-thread";
1848
2266
  const ALLOWED_PARENTS = ["chat-shell"];
1849
2267
  const ALLOWED_CHILDREN = [];
2268
+ const ALLOWED_CHILDREN_BY_SLOT = null;
1850
2269
 
1851
2270
 
1852
2271
  RULES.push({
1853
2272
  id: "COMPOSITION-CHAT-THREAD",
1854
- severity: 'warn', // LLD-0016 §C4: new, unproven-at-scale matcher (Risk R4) advisory until a corpus-wide rollout promotes it, same posture check-example-ids.mjs's Phase-1 rule started at.
2273
+ severity: 'warn', // LLD-0016 §C4: new, unproven-at-scale matcher (Risk R4): advisory until a corpus-wide rollout promotes it, same posture check-example-ids.mjs's Phase-1 rule started at.
1855
2274
  scope: 'shared',
1856
2275
  fileTypes: MARKUP_EXT,
1857
2276
  match(text) {
1858
- return compositionFindings(text, { tag: TAG, allowedParents: ALLOWED_PARENTS, allowedChildren: ALLOWED_CHILDREN });
2277
+ return compositionFindings(text, { tag: TAG, allowedParents: ALLOWED_PARENTS, allowedChildren: ALLOWED_CHILDREN, allowedChildrenBySlot: ALLOWED_CHILDREN_BY_SLOT });
1859
2278
  },
1860
2279
  fix: null, // moving markup to satisfy a composition constraint is a judgment call, not a mechanical rename (LLD-0016 §Risks R4/R5)
1861
2280
  fixtures: {
@@ -1870,7 +2289,7 @@ RULES.push({
1870
2289
  }
1871
2290
 
1872
2291
  {
1873
- // GENERATED do not hand-edit. Source: packages/web-components/components/choice-card/choice-card.yaml's a2ui.allowedParents/allowedChildren.
2292
+ // GENERATED: do not hand-edit. Source: packages/web-components/components/choice-card/choice-card.yaml's a2ui.allowedParents/allowedChildren.
1874
2293
  // Rebuild: node scripts/build/gen-composition-rules.mjs
1875
2294
  // Freshness gate: node scripts/verify/check-composition-rules-fresh.mjs --verify
1876
2295
 
@@ -1878,15 +2297,16 @@ RULES.push({
1878
2297
  const TAG = "choice-card-ui";
1879
2298
  const ALLOWED_PARENTS = [];
1880
2299
  const ALLOWED_CHILDREN = ["choice-ui"];
2300
+ const ALLOWED_CHILDREN_BY_SLOT = null;
1881
2301
 
1882
2302
 
1883
2303
  RULES.push({
1884
2304
  id: "COMPOSITION-CHOICE-CARD-UI",
1885
- severity: 'warn', // LLD-0016 §C4: new, unproven-at-scale matcher (Risk R4) advisory until a corpus-wide rollout promotes it, same posture check-example-ids.mjs's Phase-1 rule started at.
2305
+ severity: 'warn', // LLD-0016 §C4: new, unproven-at-scale matcher (Risk R4): advisory until a corpus-wide rollout promotes it, same posture check-example-ids.mjs's Phase-1 rule started at.
1886
2306
  scope: 'shared',
1887
2307
  fileTypes: MARKUP_EXT,
1888
2308
  match(text) {
1889
- return compositionFindings(text, { tag: TAG, allowedParents: ALLOWED_PARENTS, allowedChildren: ALLOWED_CHILDREN });
2309
+ return compositionFindings(text, { tag: TAG, allowedParents: ALLOWED_PARENTS, allowedChildren: ALLOWED_CHILDREN, allowedChildrenBySlot: ALLOWED_CHILDREN_BY_SLOT });
1890
2310
  },
1891
2311
  fix: null, // moving markup to satisfy a composition constraint is a judgment call, not a mechanical rename (LLD-0016 §Risks R4/R5)
1892
2312
  fixtures: {
@@ -1894,14 +2314,15 @@ RULES.push({
1894
2314
  "<choice-card-ui><not-an-allowed-child-ui></not-an-allowed-child-ui></choice-card-ui>"
1895
2315
  ],
1896
2316
  "clean": [
1897
- "<choice-card-ui><choice-ui></choice-ui></choice-card-ui>"
2317
+ "<choice-card-ui><choice-ui></choice-ui></choice-card-ui>",
2318
+ "<choice-card-ui><not-an-allowed-child-ui slot=\"arbitrary-slot\"></not-an-allowed-child-ui></choice-card-ui>"
1898
2319
  ]
1899
2320
  },
1900
2321
  });
1901
2322
  }
1902
2323
 
1903
2324
  {
1904
- // GENERATED do not hand-edit. Source: packages/web-components/components/choice-card/choice.yaml's a2ui.allowedParents/allowedChildren.
2325
+ // GENERATED: do not hand-edit. Source: packages/web-components/components/choice-card/choice.yaml's a2ui.allowedParents/allowedChildren.
1905
2326
  // Rebuild: node scripts/build/gen-composition-rules.mjs
1906
2327
  // Freshness gate: node scripts/verify/check-composition-rules-fresh.mjs --verify
1907
2328
 
@@ -1909,15 +2330,16 @@ RULES.push({
1909
2330
  const TAG = "choice-ui";
1910
2331
  const ALLOWED_PARENTS = ["choice-card-ui"];
1911
2332
  const ALLOWED_CHILDREN = [];
2333
+ const ALLOWED_CHILDREN_BY_SLOT = null;
1912
2334
 
1913
2335
 
1914
2336
  RULES.push({
1915
2337
  id: "COMPOSITION-CHOICE-UI",
1916
- severity: 'warn', // LLD-0016 §C4: new, unproven-at-scale matcher (Risk R4) advisory until a corpus-wide rollout promotes it, same posture check-example-ids.mjs's Phase-1 rule started at.
2338
+ severity: 'warn', // LLD-0016 §C4: new, unproven-at-scale matcher (Risk R4): advisory until a corpus-wide rollout promotes it, same posture check-example-ids.mjs's Phase-1 rule started at.
1917
2339
  scope: 'shared',
1918
2340
  fileTypes: MARKUP_EXT,
1919
2341
  match(text) {
1920
- return compositionFindings(text, { tag: TAG, allowedParents: ALLOWED_PARENTS, allowedChildren: ALLOWED_CHILDREN });
2342
+ return compositionFindings(text, { tag: TAG, allowedParents: ALLOWED_PARENTS, allowedChildren: ALLOWED_CHILDREN, allowedChildrenBySlot: ALLOWED_CHILDREN_BY_SLOT });
1921
2343
  },
1922
2344
  fix: null, // moving markup to satisfy a composition constraint is a judgment call, not a mechanical rename (LLD-0016 §Risks R4/R5)
1923
2345
  fixtures: {
@@ -1932,7 +2354,7 @@ RULES.push({
1932
2354
  }
1933
2355
 
1934
2356
  {
1935
- // GENERATED do not hand-edit. Source: packages/web-components/components/drilldown/drilldown.yaml's a2ui.allowedParents/allowedChildren.
2357
+ // GENERATED: do not hand-edit. Source: packages/web-components/components/drilldown/drilldown.yaml's a2ui.allowedParents/allowedChildren.
1936
2358
  // Rebuild: node scripts/build/gen-composition-rules.mjs
1937
2359
  // Freshness gate: node scripts/verify/check-composition-rules-fresh.mjs --verify
1938
2360
 
@@ -1940,15 +2362,16 @@ RULES.push({
1940
2362
  const TAG = "drilldown-ui";
1941
2363
  const ALLOWED_PARENTS = [];
1942
2364
  const ALLOWED_CHILDREN = ["breadcrumb-ui"];
2365
+ const ALLOWED_CHILDREN_BY_SLOT = null;
1943
2366
 
1944
2367
 
1945
2368
  RULES.push({
1946
2369
  id: "COMPOSITION-DRILLDOWN-UI",
1947
- severity: 'warn', // LLD-0016 §C4: new, unproven-at-scale matcher (Risk R4) advisory until a corpus-wide rollout promotes it, same posture check-example-ids.mjs's Phase-1 rule started at.
2370
+ severity: 'warn', // LLD-0016 §C4: new, unproven-at-scale matcher (Risk R4): advisory until a corpus-wide rollout promotes it, same posture check-example-ids.mjs's Phase-1 rule started at.
1948
2371
  scope: 'shared',
1949
2372
  fileTypes: MARKUP_EXT,
1950
2373
  match(text) {
1951
- return compositionFindings(text, { tag: TAG, allowedParents: ALLOWED_PARENTS, allowedChildren: ALLOWED_CHILDREN });
2374
+ return compositionFindings(text, { tag: TAG, allowedParents: ALLOWED_PARENTS, allowedChildren: ALLOWED_CHILDREN, allowedChildrenBySlot: ALLOWED_CHILDREN_BY_SLOT });
1952
2375
  },
1953
2376
  fix: null, // moving markup to satisfy a composition constraint is a judgment call, not a mechanical rename (LLD-0016 §Risks R4/R5)
1954
2377
  fixtures: {
@@ -1956,14 +2379,15 @@ RULES.push({
1956
2379
  "<drilldown-ui><not-an-allowed-child-ui></not-an-allowed-child-ui></drilldown-ui>"
1957
2380
  ],
1958
2381
  "clean": [
1959
- "<drilldown-ui><breadcrumb-ui></breadcrumb-ui></drilldown-ui>"
2382
+ "<drilldown-ui><breadcrumb-ui></breadcrumb-ui></drilldown-ui>",
2383
+ "<drilldown-ui><not-an-allowed-child-ui slot=\"arbitrary-slot\"></not-an-allowed-child-ui></drilldown-ui>"
1960
2384
  ]
1961
2385
  },
1962
2386
  });
1963
2387
  }
1964
2388
 
1965
2389
  {
1966
- // GENERATED do not hand-edit. Source: packages/web-modules/editor/editor-canvas-empty/editor-canvas-empty.yaml's a2ui.allowedParents/allowedChildren.
2390
+ // GENERATED: do not hand-edit. Source: packages/web-modules/editor/editor-canvas-empty/editor-canvas-empty.yaml's a2ui.allowedParents/allowedChildren.
1967
2391
  // Rebuild: node scripts/build/gen-composition-rules.mjs
1968
2392
  // Freshness gate: node scripts/verify/check-composition-rules-fresh.mjs --verify
1969
2393
 
@@ -1971,15 +2395,16 @@ RULES.push({
1971
2395
  const TAG = "editor-canvas-empty";
1972
2396
  const ALLOWED_PARENTS = ["editor-canvas"];
1973
2397
  const ALLOWED_CHILDREN = [];
2398
+ const ALLOWED_CHILDREN_BY_SLOT = null;
1974
2399
 
1975
2400
 
1976
2401
  RULES.push({
1977
2402
  id: "COMPOSITION-EDITOR-CANVAS-EMPTY",
1978
- severity: 'warn', // LLD-0016 §C4: new, unproven-at-scale matcher (Risk R4) advisory until a corpus-wide rollout promotes it, same posture check-example-ids.mjs's Phase-1 rule started at.
2403
+ severity: 'warn', // LLD-0016 §C4: new, unproven-at-scale matcher (Risk R4): advisory until a corpus-wide rollout promotes it, same posture check-example-ids.mjs's Phase-1 rule started at.
1979
2404
  scope: 'shared',
1980
2405
  fileTypes: MARKUP_EXT,
1981
2406
  match(text) {
1982
- return compositionFindings(text, { tag: TAG, allowedParents: ALLOWED_PARENTS, allowedChildren: ALLOWED_CHILDREN });
2407
+ return compositionFindings(text, { tag: TAG, allowedParents: ALLOWED_PARENTS, allowedChildren: ALLOWED_CHILDREN, allowedChildrenBySlot: ALLOWED_CHILDREN_BY_SLOT });
1983
2408
  },
1984
2409
  fix: null, // moving markup to satisfy a composition constraint is a judgment call, not a mechanical rename (LLD-0016 §Risks R4/R5)
1985
2410
  fixtures: {
@@ -1994,7 +2419,7 @@ RULES.push({
1994
2419
  }
1995
2420
 
1996
2421
  {
1997
- // GENERATED do not hand-edit. Source: packages/web-modules/editor/editor-canvas-toolbar/editor-canvas-toolbar.yaml's a2ui.allowedParents/allowedChildren.
2422
+ // GENERATED: do not hand-edit. Source: packages/web-modules/editor/editor-canvas-toolbar/editor-canvas-toolbar.yaml's a2ui.allowedParents/allowedChildren.
1998
2423
  // Rebuild: node scripts/build/gen-composition-rules.mjs
1999
2424
  // Freshness gate: node scripts/verify/check-composition-rules-fresh.mjs --verify
2000
2425
 
@@ -2002,15 +2427,16 @@ RULES.push({
2002
2427
  const TAG = "editor-canvas-toolbar";
2003
2428
  const ALLOWED_PARENTS = ["editor-canvas"];
2004
2429
  const ALLOWED_CHILDREN = [];
2430
+ const ALLOWED_CHILDREN_BY_SLOT = null;
2005
2431
 
2006
2432
 
2007
2433
  RULES.push({
2008
2434
  id: "COMPOSITION-EDITOR-CANVAS-TOOLBAR",
2009
- severity: 'warn', // LLD-0016 §C4: new, unproven-at-scale matcher (Risk R4) advisory until a corpus-wide rollout promotes it, same posture check-example-ids.mjs's Phase-1 rule started at.
2435
+ severity: 'warn', // LLD-0016 §C4: new, unproven-at-scale matcher (Risk R4): advisory until a corpus-wide rollout promotes it, same posture check-example-ids.mjs's Phase-1 rule started at.
2010
2436
  scope: 'shared',
2011
2437
  fileTypes: MARKUP_EXT,
2012
2438
  match(text) {
2013
- return compositionFindings(text, { tag: TAG, allowedParents: ALLOWED_PARENTS, allowedChildren: ALLOWED_CHILDREN });
2439
+ return compositionFindings(text, { tag: TAG, allowedParents: ALLOWED_PARENTS, allowedChildren: ALLOWED_CHILDREN, allowedChildrenBySlot: ALLOWED_CHILDREN_BY_SLOT });
2014
2440
  },
2015
2441
  fix: null, // moving markup to satisfy a composition constraint is a judgment call, not a mechanical rename (LLD-0016 §Risks R4/R5)
2016
2442
  fixtures: {
@@ -2018,386 +2444,759 @@ RULES.push({
2018
2444
  "<div><editor-canvas-toolbar></editor-canvas-toolbar></div>"
2019
2445
  ],
2020
2446
  "clean": [
2021
- "<editor-canvas><editor-canvas-toolbar></editor-canvas-toolbar></editor-canvas>"
2447
+ "<editor-canvas><editor-canvas-toolbar></editor-canvas-toolbar></editor-canvas>"
2448
+ ]
2449
+ },
2450
+ });
2451
+ }
2452
+
2453
+ {
2454
+ // GENERATED: do not hand-edit. Source: packages/web-modules/editor/editor-canvas/editor-canvas.yaml's a2ui.allowedParents/allowedChildren.
2455
+ // Rebuild: node scripts/build/gen-composition-rules.mjs
2456
+ // Freshness gate: node scripts/verify/check-composition-rules-fresh.mjs --verify
2457
+
2458
+
2459
+ const TAG = "editor-canvas";
2460
+ const ALLOWED_PARENTS = ["editor-shell"];
2461
+ const ALLOWED_CHILDREN = [];
2462
+ const ALLOWED_CHILDREN_BY_SLOT = null;
2463
+
2464
+
2465
+ RULES.push({
2466
+ id: "COMPOSITION-EDITOR-CANVAS",
2467
+ severity: 'warn', // LLD-0016 §C4: new, unproven-at-scale matcher (Risk R4): advisory until a corpus-wide rollout promotes it, same posture check-example-ids.mjs's Phase-1 rule started at.
2468
+ scope: 'shared',
2469
+ fileTypes: MARKUP_EXT,
2470
+ match(text) {
2471
+ return compositionFindings(text, { tag: TAG, allowedParents: ALLOWED_PARENTS, allowedChildren: ALLOWED_CHILDREN, allowedChildrenBySlot: ALLOWED_CHILDREN_BY_SLOT });
2472
+ },
2473
+ fix: null, // moving markup to satisfy a composition constraint is a judgment call, not a mechanical rename (LLD-0016 §Risks R4/R5)
2474
+ fixtures: {
2475
+ "smelly": [
2476
+ "<div><editor-canvas></editor-canvas></div>"
2477
+ ],
2478
+ "clean": [
2479
+ "<editor-shell><editor-canvas></editor-canvas></editor-shell>"
2480
+ ]
2481
+ },
2482
+ });
2483
+ }
2484
+
2485
+ {
2486
+ // GENERATED: do not hand-edit. Source: packages/web-modules/editor/editor-shell/editor-shell.yaml's a2ui.allowedParents/allowedChildren.
2487
+ // Rebuild: node scripts/build/gen-composition-rules.mjs
2488
+ // Freshness gate: node scripts/verify/check-composition-rules-fresh.mjs --verify
2489
+
2490
+
2491
+ const TAG = "editor-shell";
2492
+ const ALLOWED_PARENTS = ["Surface"];
2493
+ const ALLOWED_CHILDREN = [];
2494
+ const ALLOWED_CHILDREN_BY_SLOT = null;
2495
+
2496
+
2497
+ RULES.push({
2498
+ id: "COMPOSITION-EDITOR-SHELL",
2499
+ severity: 'warn', // LLD-0016 §C4: new, unproven-at-scale matcher (Risk R4): advisory until a corpus-wide rollout promotes it, same posture check-example-ids.mjs's Phase-1 rule started at.
2500
+ scope: 'shared',
2501
+ fileTypes: MARKUP_EXT,
2502
+ match(text) {
2503
+ return compositionFindings(text, { tag: TAG, allowedParents: ALLOWED_PARENTS, allowedChildren: ALLOWED_CHILDREN, allowedChildrenBySlot: ALLOWED_CHILDREN_BY_SLOT });
2504
+ },
2505
+ fix: null, // moving markup to satisfy a composition constraint is a judgment call, not a mechanical rename (LLD-0016 §Risks R4/R5)
2506
+ fixtures: {
2507
+ "smelly": [
2508
+ "<col-ui><editor-shell></editor-shell></col-ui>"
2509
+ ],
2510
+ "clean": [
2511
+ "<editor-shell></editor-shell>"
2512
+ ]
2513
+ },
2514
+ });
2515
+ }
2516
+
2517
+ {
2518
+ // GENERATED: do not hand-edit. Source: packages/web-modules/editor/editor-sidebar/editor-sidebar.yaml's a2ui.allowedParents/allowedChildren.
2519
+ // Rebuild: node scripts/build/gen-composition-rules.mjs
2520
+ // Freshness gate: node scripts/verify/check-composition-rules-fresh.mjs --verify
2521
+
2522
+
2523
+ const TAG = "editor-sidebar";
2524
+ const ALLOWED_PARENTS = ["editor-shell"];
2525
+ const ALLOWED_CHILDREN = [];
2526
+ const ALLOWED_CHILDREN_BY_SLOT = null;
2527
+
2528
+
2529
+ RULES.push({
2530
+ id: "COMPOSITION-EDITOR-SIDEBAR",
2531
+ severity: 'warn', // LLD-0016 §C4: new, unproven-at-scale matcher (Risk R4): advisory until a corpus-wide rollout promotes it, same posture check-example-ids.mjs's Phase-1 rule started at.
2532
+ scope: 'shared',
2533
+ fileTypes: MARKUP_EXT,
2534
+ match(text) {
2535
+ return compositionFindings(text, { tag: TAG, allowedParents: ALLOWED_PARENTS, allowedChildren: ALLOWED_CHILDREN, allowedChildrenBySlot: ALLOWED_CHILDREN_BY_SLOT });
2536
+ },
2537
+ fix: null, // moving markup to satisfy a composition constraint is a judgment call, not a mechanical rename (LLD-0016 §Risks R4/R5)
2538
+ fixtures: {
2539
+ "smelly": [
2540
+ "<div><editor-sidebar></editor-sidebar></div>"
2541
+ ],
2542
+ "clean": [
2543
+ "<editor-shell><editor-sidebar></editor-sidebar></editor-shell>"
2544
+ ]
2545
+ },
2546
+ });
2547
+ }
2548
+
2549
+ {
2550
+ // GENERATED: do not hand-edit. Source: packages/web-modules/editor/editor-statusbar/editor-statusbar.yaml's a2ui.allowedParents/allowedChildren.
2551
+ // Rebuild: node scripts/build/gen-composition-rules.mjs
2552
+ // Freshness gate: node scripts/verify/check-composition-rules-fresh.mjs --verify
2553
+
2554
+
2555
+ const TAG = "editor-statusbar";
2556
+ const ALLOWED_PARENTS = ["editor-shell"];
2557
+ const ALLOWED_CHILDREN = [];
2558
+ const ALLOWED_CHILDREN_BY_SLOT = null;
2559
+
2560
+
2561
+ RULES.push({
2562
+ id: "COMPOSITION-EDITOR-STATUSBAR",
2563
+ severity: 'warn', // LLD-0016 §C4: new, unproven-at-scale matcher (Risk R4): advisory until a corpus-wide rollout promotes it, same posture check-example-ids.mjs's Phase-1 rule started at.
2564
+ scope: 'shared',
2565
+ fileTypes: MARKUP_EXT,
2566
+ match(text) {
2567
+ return compositionFindings(text, { tag: TAG, allowedParents: ALLOWED_PARENTS, allowedChildren: ALLOWED_CHILDREN, allowedChildrenBySlot: ALLOWED_CHILDREN_BY_SLOT });
2568
+ },
2569
+ fix: null, // moving markup to satisfy a composition constraint is a judgment call, not a mechanical rename (LLD-0016 §Risks R4/R5)
2570
+ fixtures: {
2571
+ "smelly": [
2572
+ "<div><editor-statusbar></editor-statusbar></div>"
2573
+ ],
2574
+ "clean": [
2575
+ "<editor-shell><editor-statusbar></editor-statusbar></editor-shell>"
2576
+ ]
2577
+ },
2578
+ });
2579
+ }
2580
+
2581
+ {
2582
+ // GENERATED: do not hand-edit. Source: packages/web-modules/editor/editor-toolbar/editor-toolbar.yaml's a2ui.allowedParents/allowedChildren.
2583
+ // Rebuild: node scripts/build/gen-composition-rules.mjs
2584
+ // Freshness gate: node scripts/verify/check-composition-rules-fresh.mjs --verify
2585
+
2586
+
2587
+ const TAG = "editor-toolbar";
2588
+ const ALLOWED_PARENTS = ["editor-shell"];
2589
+ const ALLOWED_CHILDREN = [];
2590
+ const ALLOWED_CHILDREN_BY_SLOT = null;
2591
+
2592
+
2593
+ RULES.push({
2594
+ id: "COMPOSITION-EDITOR-TOOLBAR",
2595
+ severity: 'warn', // LLD-0016 §C4: new, unproven-at-scale matcher (Risk R4): advisory until a corpus-wide rollout promotes it, same posture check-example-ids.mjs's Phase-1 rule started at.
2596
+ scope: 'shared',
2597
+ fileTypes: MARKUP_EXT,
2598
+ match(text) {
2599
+ return compositionFindings(text, { tag: TAG, allowedParents: ALLOWED_PARENTS, allowedChildren: ALLOWED_CHILDREN, allowedChildrenBySlot: ALLOWED_CHILDREN_BY_SLOT });
2600
+ },
2601
+ fix: null, // moving markup to satisfy a composition constraint is a judgment call, not a mechanical rename (LLD-0016 §Risks R4/R5)
2602
+ fixtures: {
2603
+ "smelly": [
2604
+ "<div><editor-toolbar></editor-toolbar></div>"
2605
+ ],
2606
+ "clean": [
2607
+ "<editor-shell><editor-toolbar></editor-toolbar></editor-shell>"
2608
+ ]
2609
+ },
2610
+ });
2611
+ }
2612
+
2613
+ {
2614
+ // GENERATED: do not hand-edit. Source: packages/web-modules/shell/embed-shell/embed-shell.yaml's a2ui.allowedParents/allowedChildren.
2615
+ // Rebuild: node scripts/build/gen-composition-rules.mjs
2616
+ // Freshness gate: node scripts/verify/check-composition-rules-fresh.mjs --verify
2617
+
2618
+
2619
+ const TAG = "embed-shell";
2620
+ const ALLOWED_PARENTS = ["Surface"];
2621
+ const ALLOWED_CHILDREN = [];
2622
+ const ALLOWED_CHILDREN_BY_SLOT = null;
2623
+
2624
+
2625
+ RULES.push({
2626
+ id: "COMPOSITION-EMBED-SHELL",
2627
+ severity: 'warn', // LLD-0016 §C4: new, unproven-at-scale matcher (Risk R4): advisory until a corpus-wide rollout promotes it, same posture check-example-ids.mjs's Phase-1 rule started at.
2628
+ scope: 'shared',
2629
+ fileTypes: MARKUP_EXT,
2630
+ match(text) {
2631
+ return compositionFindings(text, { tag: TAG, allowedParents: ALLOWED_PARENTS, allowedChildren: ALLOWED_CHILDREN, allowedChildrenBySlot: ALLOWED_CHILDREN_BY_SLOT });
2632
+ },
2633
+ fix: null, // moving markup to satisfy a composition constraint is a judgment call, not a mechanical rename (LLD-0016 §Risks R4/R5)
2634
+ fixtures: {
2635
+ "smelly": [
2636
+ "<col-ui><embed-shell></embed-shell></col-ui>"
2637
+ ],
2638
+ "clean": [
2639
+ "<embed-shell></embed-shell>"
2640
+ ]
2641
+ },
2642
+ });
2643
+ }
2644
+
2645
+ {
2646
+ // GENERATED: do not hand-edit. Source: packages/web-components/components/feed/feed-item.yaml's a2ui.allowedParents/allowedChildren.
2647
+ // Rebuild: node scripts/build/gen-composition-rules.mjs
2648
+ // Freshness gate: node scripts/verify/check-composition-rules-fresh.mjs --verify
2649
+
2650
+
2651
+ const TAG = "feed-item-ui";
2652
+ const ALLOWED_PARENTS = ["feed-ui"];
2653
+ const ALLOWED_CHILDREN = [];
2654
+ const ALLOWED_CHILDREN_BY_SLOT = null;
2655
+
2656
+
2657
+ RULES.push({
2658
+ id: "COMPOSITION-FEED-ITEM-UI",
2659
+ severity: 'warn', // LLD-0016 §C4: new, unproven-at-scale matcher (Risk R4): advisory until a corpus-wide rollout promotes it, same posture check-example-ids.mjs's Phase-1 rule started at.
2660
+ scope: 'shared',
2661
+ fileTypes: MARKUP_EXT,
2662
+ match(text) {
2663
+ return compositionFindings(text, { tag: TAG, allowedParents: ALLOWED_PARENTS, allowedChildren: ALLOWED_CHILDREN, allowedChildrenBySlot: ALLOWED_CHILDREN_BY_SLOT });
2664
+ },
2665
+ fix: null, // moving markup to satisfy a composition constraint is a judgment call, not a mechanical rename (LLD-0016 §Risks R4/R5)
2666
+ fixtures: {
2667
+ "smelly": [
2668
+ "<div><feed-item-ui></feed-item-ui></div>"
2669
+ ],
2670
+ "clean": [
2671
+ "<feed-ui><feed-item-ui></feed-item-ui></feed-ui>"
2672
+ ]
2673
+ },
2674
+ });
2675
+ }
2676
+
2677
+ {
2678
+ // GENERATED: do not hand-edit. Source: packages/web-components/components/feed/feed.yaml's a2ui.allowedParents/allowedChildren.
2679
+ // Rebuild: node scripts/build/gen-composition-rules.mjs
2680
+ // Freshness gate: node scripts/verify/check-composition-rules-fresh.mjs --verify
2681
+
2682
+
2683
+ const TAG = "feed-ui";
2684
+ const ALLOWED_PARENTS = [];
2685
+ const ALLOWED_CHILDREN = ["feed-item-ui"];
2686
+ const ALLOWED_CHILDREN_BY_SLOT = null;
2687
+
2688
+
2689
+ RULES.push({
2690
+ id: "COMPOSITION-FEED-UI",
2691
+ severity: 'warn', // LLD-0016 §C4: new, unproven-at-scale matcher (Risk R4): advisory until a corpus-wide rollout promotes it, same posture check-example-ids.mjs's Phase-1 rule started at.
2692
+ scope: 'shared',
2693
+ fileTypes: MARKUP_EXT,
2694
+ match(text) {
2695
+ return compositionFindings(text, { tag: TAG, allowedParents: ALLOWED_PARENTS, allowedChildren: ALLOWED_CHILDREN, allowedChildrenBySlot: ALLOWED_CHILDREN_BY_SLOT });
2696
+ },
2697
+ fix: null, // moving markup to satisfy a composition constraint is a judgment call, not a mechanical rename (LLD-0016 §Risks R4/R5)
2698
+ fixtures: {
2699
+ "smelly": [
2700
+ "<feed-ui><not-an-allowed-child-ui></not-an-allowed-child-ui></feed-ui>"
2701
+ ],
2702
+ "clean": [
2703
+ "<feed-ui><feed-item-ui></feed-item-ui></feed-ui>",
2704
+ "<feed-ui><not-an-allowed-child-ui slot=\"arbitrary-slot\"></not-an-allowed-child-ui></feed-ui>"
2705
+ ]
2706
+ },
2707
+ });
2708
+ }
2709
+
2710
+ {
2711
+ // GENERATED: do not hand-edit. Source: packages/web-components/components/fields/fields.yaml's a2ui.allowedParents/allowedChildren.
2712
+ // Rebuild: node scripts/build/gen-composition-rules.mjs
2713
+ // Freshness gate: node scripts/verify/check-composition-rules-fresh.mjs --verify
2714
+
2715
+
2716
+ const TAG = "fields-ui";
2717
+ const ALLOWED_PARENTS = [];
2718
+ const ALLOWED_CHILDREN = ["field-ui"];
2719
+ const ALLOWED_CHILDREN_BY_SLOT = null;
2720
+
2721
+
2722
+ RULES.push({
2723
+ id: "COMPOSITION-FIELDS-UI",
2724
+ severity: 'warn', // LLD-0016 §C4: new, unproven-at-scale matcher (Risk R4): advisory until a corpus-wide rollout promotes it, same posture check-example-ids.mjs's Phase-1 rule started at.
2725
+ scope: 'shared',
2726
+ fileTypes: MARKUP_EXT,
2727
+ match(text) {
2728
+ return compositionFindings(text, { tag: TAG, allowedParents: ALLOWED_PARENTS, allowedChildren: ALLOWED_CHILDREN, allowedChildrenBySlot: ALLOWED_CHILDREN_BY_SLOT });
2729
+ },
2730
+ fix: null, // moving markup to satisfy a composition constraint is a judgment call, not a mechanical rename (LLD-0016 §Risks R4/R5)
2731
+ fixtures: {
2732
+ "smelly": [
2733
+ "<fields-ui><not-an-allowed-child-ui></not-an-allowed-child-ui></fields-ui>"
2734
+ ],
2735
+ "clean": [
2736
+ "<fields-ui><field-ui></field-ui></fields-ui>",
2737
+ "<fields-ui><not-an-allowed-child-ui slot=\"arbitrary-slot\"></not-an-allowed-child-ui></fields-ui>"
2738
+ ]
2739
+ },
2740
+ });
2741
+ }
2742
+
2743
+ {
2744
+ // GENERATED: do not hand-edit. Source: packages/web-components/components/footer/footer.yaml's a2ui.allowedParents/allowedChildren.
2745
+ // Rebuild: node scripts/build/gen-composition-rules.mjs
2746
+ // Freshness gate: node scripts/verify/check-composition-rules-fresh.mjs --verify
2747
+
2748
+
2749
+ const TAG = "footer-ui";
2750
+ const ALLOWED_PARENTS = ["page-ui"];
2751
+ const ALLOWED_CHILDREN = [];
2752
+ const ALLOWED_CHILDREN_BY_SLOT = null;
2753
+
2754
+
2755
+ RULES.push({
2756
+ id: "COMPOSITION-FOOTER-UI",
2757
+ severity: 'warn', // LLD-0016 §C4: new, unproven-at-scale matcher (Risk R4): advisory until a corpus-wide rollout promotes it, same posture check-example-ids.mjs's Phase-1 rule started at.
2758
+ scope: 'shared',
2759
+ fileTypes: MARKUP_EXT,
2760
+ match(text) {
2761
+ return compositionFindings(text, { tag: TAG, allowedParents: ALLOWED_PARENTS, allowedChildren: ALLOWED_CHILDREN, allowedChildrenBySlot: ALLOWED_CHILDREN_BY_SLOT });
2762
+ },
2763
+ fix: null, // moving markup to satisfy a composition constraint is a judgment call, not a mechanical rename (LLD-0016 §Risks R4/R5)
2764
+ fixtures: {
2765
+ "smelly": [
2766
+ "<div><footer-ui></footer-ui></div>"
2767
+ ],
2768
+ "clean": [
2769
+ "<page-ui><footer-ui></footer-ui></page-ui>"
2770
+ ]
2771
+ },
2772
+ });
2773
+ }
2774
+
2775
+ {
2776
+ // GENERATED: do not hand-edit. Source: packages/web-modules/form/form-popover/form-popover.yaml's a2ui.allowedParents/allowedChildren.
2777
+ // Rebuild: node scripts/build/gen-composition-rules.mjs
2778
+ // Freshness gate: node scripts/verify/check-composition-rules-fresh.mjs --verify
2779
+
2780
+
2781
+ const TAG = "form-popover-ui";
2782
+ const ALLOWED_PARENTS = [];
2783
+ const ALLOWED_CHILDREN = ["check-ui","radio-ui","input-ui","textarea-ui","divider-ui","field-ui"];
2784
+ const ALLOWED_CHILDREN_BY_SLOT = null;
2785
+
2786
+
2787
+ RULES.push({
2788
+ id: "COMPOSITION-FORM-POPOVER-UI",
2789
+ severity: 'warn', // LLD-0016 §C4: new, unproven-at-scale matcher (Risk R4): advisory until a corpus-wide rollout promotes it, same posture check-example-ids.mjs's Phase-1 rule started at.
2790
+ scope: 'shared',
2791
+ fileTypes: MARKUP_EXT,
2792
+ match(text) {
2793
+ return compositionFindings(text, { tag: TAG, allowedParents: ALLOWED_PARENTS, allowedChildren: ALLOWED_CHILDREN, allowedChildrenBySlot: ALLOWED_CHILDREN_BY_SLOT });
2794
+ },
2795
+ fix: null, // moving markup to satisfy a composition constraint is a judgment call, not a mechanical rename (LLD-0016 §Risks R4/R5)
2796
+ fixtures: {
2797
+ "smelly": [
2798
+ "<form-popover-ui><not-an-allowed-child-ui></not-an-allowed-child-ui></form-popover-ui>"
2799
+ ],
2800
+ "clean": [
2801
+ "<form-popover-ui><check-ui></check-ui></form-popover-ui>",
2802
+ "<form-popover-ui><not-an-allowed-child-ui slot=\"arbitrary-slot\"></not-an-allowed-child-ui></form-popover-ui>"
2022
2803
  ]
2023
2804
  },
2024
2805
  });
2025
2806
  }
2026
2807
 
2027
2808
  {
2028
- // GENERATED do not hand-edit. Source: packages/web-modules/editor/editor-canvas/editor-canvas.yaml's a2ui.allowedParents/allowedChildren.
2809
+ // GENERATED: do not hand-edit. Source: packages/web-components/components/header/header.yaml's a2ui.allowedParents/allowedChildren.
2029
2810
  // Rebuild: node scripts/build/gen-composition-rules.mjs
2030
2811
  // Freshness gate: node scripts/verify/check-composition-rules-fresh.mjs --verify
2031
2812
 
2032
2813
 
2033
- const TAG = "editor-canvas";
2034
- const ALLOWED_PARENTS = ["editor-shell"];
2814
+ const TAG = "header-ui";
2815
+ const ALLOWED_PARENTS = ["page-ui"];
2035
2816
  const ALLOWED_CHILDREN = [];
2817
+ const ALLOWED_CHILDREN_BY_SLOT = null;
2036
2818
 
2037
2819
 
2038
2820
  RULES.push({
2039
- id: "COMPOSITION-EDITOR-CANVAS",
2040
- severity: 'warn', // LLD-0016 §C4: new, unproven-at-scale matcher (Risk R4) advisory until a corpus-wide rollout promotes it, same posture check-example-ids.mjs's Phase-1 rule started at.
2821
+ id: "COMPOSITION-HEADER-UI",
2822
+ severity: 'warn', // LLD-0016 §C4: new, unproven-at-scale matcher (Risk R4): advisory until a corpus-wide rollout promotes it, same posture check-example-ids.mjs's Phase-1 rule started at.
2041
2823
  scope: 'shared',
2042
2824
  fileTypes: MARKUP_EXT,
2043
2825
  match(text) {
2044
- return compositionFindings(text, { tag: TAG, allowedParents: ALLOWED_PARENTS, allowedChildren: ALLOWED_CHILDREN });
2826
+ return compositionFindings(text, { tag: TAG, allowedParents: ALLOWED_PARENTS, allowedChildren: ALLOWED_CHILDREN, allowedChildrenBySlot: ALLOWED_CHILDREN_BY_SLOT });
2045
2827
  },
2046
2828
  fix: null, // moving markup to satisfy a composition constraint is a judgment call, not a mechanical rename (LLD-0016 §Risks R4/R5)
2047
2829
  fixtures: {
2048
2830
  "smelly": [
2049
- "<div><editor-canvas></editor-canvas></div>"
2831
+ "<div><header-ui></header-ui></div>"
2050
2832
  ],
2051
2833
  "clean": [
2052
- "<editor-shell><editor-canvas></editor-canvas></editor-shell>"
2834
+ "<page-ui><header-ui></header-ui></page-ui>"
2053
2835
  ]
2054
2836
  },
2055
2837
  });
2056
2838
  }
2057
2839
 
2058
2840
  {
2059
- // GENERATED do not hand-edit. Source: packages/web-modules/editor/editor-shell/editor-shell.yaml's a2ui.allowedParents/allowedChildren.
2841
+ // GENERATED: do not hand-edit. Source: packages/web-components/components/list/list-item.yaml's a2ui.allowedParents/allowedChildren.
2060
2842
  // Rebuild: node scripts/build/gen-composition-rules.mjs
2061
2843
  // Freshness gate: node scripts/verify/check-composition-rules-fresh.mjs --verify
2062
2844
 
2063
2845
 
2064
- const TAG = "editor-shell";
2065
- const ALLOWED_PARENTS = ["Surface"];
2846
+ const TAG = "list-item-ui";
2847
+ const ALLOWED_PARENTS = ["list-ui"];
2066
2848
  const ALLOWED_CHILDREN = [];
2849
+ const ALLOWED_CHILDREN_BY_SLOT = null;
2067
2850
 
2068
2851
 
2069
2852
  RULES.push({
2070
- id: "COMPOSITION-EDITOR-SHELL",
2071
- severity: 'warn', // LLD-0016 §C4: new, unproven-at-scale matcher (Risk R4) advisory until a corpus-wide rollout promotes it, same posture check-example-ids.mjs's Phase-1 rule started at.
2853
+ id: "COMPOSITION-LIST-ITEM-UI",
2854
+ severity: 'warn', // LLD-0016 §C4: new, unproven-at-scale matcher (Risk R4): advisory until a corpus-wide rollout promotes it, same posture check-example-ids.mjs's Phase-1 rule started at.
2072
2855
  scope: 'shared',
2073
2856
  fileTypes: MARKUP_EXT,
2074
2857
  match(text) {
2075
- return compositionFindings(text, { tag: TAG, allowedParents: ALLOWED_PARENTS, allowedChildren: ALLOWED_CHILDREN });
2858
+ return compositionFindings(text, { tag: TAG, allowedParents: ALLOWED_PARENTS, allowedChildren: ALLOWED_CHILDREN, allowedChildrenBySlot: ALLOWED_CHILDREN_BY_SLOT });
2076
2859
  },
2077
2860
  fix: null, // moving markup to satisfy a composition constraint is a judgment call, not a mechanical rename (LLD-0016 §Risks R4/R5)
2078
2861
  fixtures: {
2079
2862
  "smelly": [
2080
- "<col-ui><editor-shell></editor-shell></col-ui>"
2863
+ "<div><list-item-ui></list-item-ui></div>"
2081
2864
  ],
2082
2865
  "clean": [
2083
- "<editor-shell></editor-shell>"
2866
+ "<list-ui><list-item-ui></list-item-ui></list-ui>"
2084
2867
  ]
2085
2868
  },
2086
2869
  });
2087
2870
  }
2088
2871
 
2089
2872
  {
2090
- // GENERATED do not hand-edit. Source: packages/web-modules/editor/editor-sidebar/editor-sidebar.yaml's a2ui.allowedParents/allowedChildren.
2873
+ // GENERATED: do not hand-edit. Source: packages/web-components/components/menu/menu-divider.yaml's a2ui.allowedParents/allowedChildren.
2091
2874
  // Rebuild: node scripts/build/gen-composition-rules.mjs
2092
2875
  // Freshness gate: node scripts/verify/check-composition-rules-fresh.mjs --verify
2093
2876
 
2094
2877
 
2095
- const TAG = "editor-sidebar";
2096
- const ALLOWED_PARENTS = ["editor-shell"];
2878
+ const TAG = "menu-divider-ui";
2879
+ const ALLOWED_PARENTS = ["menu-ui","context-menu-ui"];
2097
2880
  const ALLOWED_CHILDREN = [];
2881
+ const ALLOWED_CHILDREN_BY_SLOT = null;
2098
2882
 
2099
2883
 
2100
2884
  RULES.push({
2101
- id: "COMPOSITION-EDITOR-SIDEBAR",
2102
- severity: 'warn', // LLD-0016 §C4: new, unproven-at-scale matcher (Risk R4) advisory until a corpus-wide rollout promotes it, same posture check-example-ids.mjs's Phase-1 rule started at.
2885
+ id: "COMPOSITION-MENU-DIVIDER-UI",
2886
+ severity: 'warn', // LLD-0016 §C4: new, unproven-at-scale matcher (Risk R4): advisory until a corpus-wide rollout promotes it, same posture check-example-ids.mjs's Phase-1 rule started at.
2103
2887
  scope: 'shared',
2104
2888
  fileTypes: MARKUP_EXT,
2105
2889
  match(text) {
2106
- return compositionFindings(text, { tag: TAG, allowedParents: ALLOWED_PARENTS, allowedChildren: ALLOWED_CHILDREN });
2890
+ return compositionFindings(text, { tag: TAG, allowedParents: ALLOWED_PARENTS, allowedChildren: ALLOWED_CHILDREN, allowedChildrenBySlot: ALLOWED_CHILDREN_BY_SLOT });
2107
2891
  },
2108
2892
  fix: null, // moving markup to satisfy a composition constraint is a judgment call, not a mechanical rename (LLD-0016 §Risks R4/R5)
2109
2893
  fixtures: {
2110
2894
  "smelly": [
2111
- "<div><editor-sidebar></editor-sidebar></div>"
2895
+ "<div><menu-divider-ui></menu-divider-ui></div>"
2112
2896
  ],
2113
2897
  "clean": [
2114
- "<editor-shell><editor-sidebar></editor-sidebar></editor-shell>"
2898
+ "<menu-ui><menu-divider-ui></menu-divider-ui></menu-ui>"
2115
2899
  ]
2116
2900
  },
2117
2901
  });
2118
2902
  }
2119
2903
 
2120
2904
  {
2121
- // GENERATED do not hand-edit. Source: packages/web-modules/editor/editor-statusbar/editor-statusbar.yaml's a2ui.allowedParents/allowedChildren.
2905
+ // GENERATED: do not hand-edit. Source: packages/web-components/components/menu/menu-item.yaml's a2ui.allowedParents/allowedChildren.
2122
2906
  // Rebuild: node scripts/build/gen-composition-rules.mjs
2123
2907
  // Freshness gate: node scripts/verify/check-composition-rules-fresh.mjs --verify
2124
2908
 
2125
2909
 
2126
- const TAG = "editor-statusbar";
2127
- const ALLOWED_PARENTS = ["editor-shell"];
2910
+ const TAG = "menu-item-ui";
2911
+ const ALLOWED_PARENTS = ["menu-ui","context-menu-ui"];
2128
2912
  const ALLOWED_CHILDREN = [];
2913
+ const ALLOWED_CHILDREN_BY_SLOT = null;
2129
2914
 
2130
2915
 
2131
2916
  RULES.push({
2132
- id: "COMPOSITION-EDITOR-STATUSBAR",
2133
- severity: 'warn', // LLD-0016 §C4: new, unproven-at-scale matcher (Risk R4) advisory until a corpus-wide rollout promotes it, same posture check-example-ids.mjs's Phase-1 rule started at.
2917
+ id: "COMPOSITION-MENU-ITEM-UI",
2918
+ severity: 'warn', // LLD-0016 §C4: new, unproven-at-scale matcher (Risk R4): advisory until a corpus-wide rollout promotes it, same posture check-example-ids.mjs's Phase-1 rule started at.
2134
2919
  scope: 'shared',
2135
2920
  fileTypes: MARKUP_EXT,
2136
2921
  match(text) {
2137
- return compositionFindings(text, { tag: TAG, allowedParents: ALLOWED_PARENTS, allowedChildren: ALLOWED_CHILDREN });
2922
+ return compositionFindings(text, { tag: TAG, allowedParents: ALLOWED_PARENTS, allowedChildren: ALLOWED_CHILDREN, allowedChildrenBySlot: ALLOWED_CHILDREN_BY_SLOT });
2138
2923
  },
2139
2924
  fix: null, // moving markup to satisfy a composition constraint is a judgment call, not a mechanical rename (LLD-0016 §Risks R4/R5)
2140
2925
  fixtures: {
2141
2926
  "smelly": [
2142
- "<div><editor-statusbar></editor-statusbar></div>"
2927
+ "<div><menu-item-ui></menu-item-ui></div>"
2143
2928
  ],
2144
2929
  "clean": [
2145
- "<editor-shell><editor-statusbar></editor-statusbar></editor-shell>"
2930
+ "<menu-ui><menu-item-ui></menu-item-ui></menu-ui>"
2146
2931
  ]
2147
2932
  },
2148
2933
  });
2149
2934
  }
2150
2935
 
2151
2936
  {
2152
- // GENERATED do not hand-edit. Source: packages/web-modules/editor/editor-toolbar/editor-toolbar.yaml's a2ui.allowedParents/allowedChildren.
2937
+ // GENERATED: do not hand-edit. Source: packages/web-components/components/menu/menu-label.yaml's a2ui.allowedParents/allowedChildren.
2153
2938
  // Rebuild: node scripts/build/gen-composition-rules.mjs
2154
2939
  // Freshness gate: node scripts/verify/check-composition-rules-fresh.mjs --verify
2155
2940
 
2156
2941
 
2157
- const TAG = "editor-toolbar";
2158
- const ALLOWED_PARENTS = ["editor-shell"];
2942
+ const TAG = "menu-label-ui";
2943
+ const ALLOWED_PARENTS = ["menu-ui"];
2159
2944
  const ALLOWED_CHILDREN = [];
2945
+ const ALLOWED_CHILDREN_BY_SLOT = null;
2160
2946
 
2161
2947
 
2162
2948
  RULES.push({
2163
- id: "COMPOSITION-EDITOR-TOOLBAR",
2164
- severity: 'warn', // LLD-0016 §C4: new, unproven-at-scale matcher (Risk R4) advisory until a corpus-wide rollout promotes it, same posture check-example-ids.mjs's Phase-1 rule started at.
2949
+ id: "COMPOSITION-MENU-LABEL-UI",
2950
+ severity: 'warn', // LLD-0016 §C4: new, unproven-at-scale matcher (Risk R4): advisory until a corpus-wide rollout promotes it, same posture check-example-ids.mjs's Phase-1 rule started at.
2165
2951
  scope: 'shared',
2166
2952
  fileTypes: MARKUP_EXT,
2167
2953
  match(text) {
2168
- return compositionFindings(text, { tag: TAG, allowedParents: ALLOWED_PARENTS, allowedChildren: ALLOWED_CHILDREN });
2954
+ return compositionFindings(text, { tag: TAG, allowedParents: ALLOWED_PARENTS, allowedChildren: ALLOWED_CHILDREN, allowedChildrenBySlot: ALLOWED_CHILDREN_BY_SLOT });
2169
2955
  },
2170
2956
  fix: null, // moving markup to satisfy a composition constraint is a judgment call, not a mechanical rename (LLD-0016 §Risks R4/R5)
2171
2957
  fixtures: {
2172
2958
  "smelly": [
2173
- "<div><editor-toolbar></editor-toolbar></div>"
2959
+ "<div><menu-label-ui></menu-label-ui></div>"
2174
2960
  ],
2175
2961
  "clean": [
2176
- "<editor-shell><editor-toolbar></editor-toolbar></editor-shell>"
2962
+ "<menu-ui><menu-label-ui></menu-label-ui></menu-ui>"
2177
2963
  ]
2178
2964
  },
2179
2965
  });
2180
2966
  }
2181
2967
 
2182
2968
  {
2183
- // GENERATED do not hand-edit. Source: packages/web-components/components/feed/feed-item.yaml's a2ui.allowedParents/allowedChildren.
2969
+ // GENERATED: do not hand-edit. Source: packages/web-components/components/menu/menu.yaml's a2ui.allowedParents/allowedChildren.
2184
2970
  // Rebuild: node scripts/build/gen-composition-rules.mjs
2185
2971
  // Freshness gate: node scripts/verify/check-composition-rules-fresh.mjs --verify
2186
2972
 
2187
2973
 
2188
- const TAG = "feed-item-ui";
2189
- const ALLOWED_PARENTS = ["feed-ui"];
2190
- const ALLOWED_CHILDREN = [];
2974
+ const TAG = "menu-ui";
2975
+ const ALLOWED_PARENTS = [];
2976
+ const ALLOWED_CHILDREN = ["menu-item-ui","menu-divider-ui","menu-label-ui"];
2977
+ const ALLOWED_CHILDREN_BY_SLOT = null;
2191
2978
 
2192
2979
 
2193
2980
  RULES.push({
2194
- id: "COMPOSITION-FEED-ITEM-UI",
2195
- severity: 'warn', // LLD-0016 §C4: new, unproven-at-scale matcher (Risk R4) advisory until a corpus-wide rollout promotes it, same posture check-example-ids.mjs's Phase-1 rule started at.
2981
+ id: "COMPOSITION-MENU-UI",
2982
+ severity: 'warn', // LLD-0016 §C4: new, unproven-at-scale matcher (Risk R4): advisory until a corpus-wide rollout promotes it, same posture check-example-ids.mjs's Phase-1 rule started at.
2196
2983
  scope: 'shared',
2197
2984
  fileTypes: MARKUP_EXT,
2198
2985
  match(text) {
2199
- return compositionFindings(text, { tag: TAG, allowedParents: ALLOWED_PARENTS, allowedChildren: ALLOWED_CHILDREN });
2986
+ return compositionFindings(text, { tag: TAG, allowedParents: ALLOWED_PARENTS, allowedChildren: ALLOWED_CHILDREN, allowedChildrenBySlot: ALLOWED_CHILDREN_BY_SLOT });
2200
2987
  },
2201
2988
  fix: null, // moving markup to satisfy a composition constraint is a judgment call, not a mechanical rename (LLD-0016 §Risks R4/R5)
2202
2989
  fixtures: {
2203
2990
  "smelly": [
2204
- "<div><feed-item-ui></feed-item-ui></div>"
2991
+ "<menu-ui><not-an-allowed-child-ui></not-an-allowed-child-ui></menu-ui>"
2205
2992
  ],
2206
2993
  "clean": [
2207
- "<feed-ui><feed-item-ui></feed-item-ui></feed-ui>"
2994
+ "<menu-ui><menu-item-ui></menu-item-ui></menu-ui>",
2995
+ "<menu-ui><not-an-allowed-child-ui slot=\"arbitrary-slot\"></not-an-allowed-child-ui></menu-ui>"
2208
2996
  ]
2209
2997
  },
2210
2998
  });
2211
2999
  }
2212
3000
 
2213
3001
  {
2214
- // GENERATED do not hand-edit. Source: packages/web-components/components/feed/feed.yaml's a2ui.allowedParents/allowedChildren.
3002
+ // GENERATED: do not hand-edit. Source: packages/web-components/components/nav-group/nav-group.yaml's a2ui.allowedParents/allowedChildren.
2215
3003
  // Rebuild: node scripts/build/gen-composition-rules.mjs
2216
3004
  // Freshness gate: node scripts/verify/check-composition-rules-fresh.mjs --verify
2217
3005
 
2218
3006
 
2219
- const TAG = "feed-ui";
2220
- const ALLOWED_PARENTS = [];
2221
- const ALLOWED_CHILDREN = ["feed-item-ui"];
3007
+ const TAG = "nav-group-ui";
3008
+ const ALLOWED_PARENTS = ["nav-ui"];
3009
+ const ALLOWED_CHILDREN = ["nav-item-ui"];
3010
+ const ALLOWED_CHILDREN_BY_SLOT = null;
2222
3011
 
2223
3012
 
2224
3013
  RULES.push({
2225
- id: "COMPOSITION-FEED-UI",
2226
- severity: 'warn', // LLD-0016 §C4: new, unproven-at-scale matcher (Risk R4) advisory until a corpus-wide rollout promotes it, same posture check-example-ids.mjs's Phase-1 rule started at.
3014
+ id: "COMPOSITION-NAV-GROUP-UI",
3015
+ severity: 'warn', // LLD-0016 §C4: new, unproven-at-scale matcher (Risk R4): advisory until a corpus-wide rollout promotes it, same posture check-example-ids.mjs's Phase-1 rule started at.
2227
3016
  scope: 'shared',
2228
3017
  fileTypes: MARKUP_EXT,
2229
3018
  match(text) {
2230
- return compositionFindings(text, { tag: TAG, allowedParents: ALLOWED_PARENTS, allowedChildren: ALLOWED_CHILDREN });
3019
+ return compositionFindings(text, { tag: TAG, allowedParents: ALLOWED_PARENTS, allowedChildren: ALLOWED_CHILDREN, allowedChildrenBySlot: ALLOWED_CHILDREN_BY_SLOT });
2231
3020
  },
2232
3021
  fix: null, // moving markup to satisfy a composition constraint is a judgment call, not a mechanical rename (LLD-0016 §Risks R4/R5)
2233
3022
  fixtures: {
2234
3023
  "smelly": [
2235
- "<feed-ui><not-an-allowed-child-ui></not-an-allowed-child-ui></feed-ui>"
3024
+ "<div><nav-group-ui></nav-group-ui></div>",
3025
+ "<nav-group-ui><not-an-allowed-child-ui></not-an-allowed-child-ui></nav-group-ui>"
2236
3026
  ],
2237
3027
  "clean": [
2238
- "<feed-ui><feed-item-ui></feed-item-ui></feed-ui>"
3028
+ "<nav-ui><nav-group-ui></nav-group-ui></nav-ui>",
3029
+ "<nav-ui><nav-group-ui><nav-item-ui></nav-item-ui></nav-group-ui></nav-ui>",
3030
+ "<nav-ui><nav-group-ui><not-an-allowed-child-ui slot=\"arbitrary-slot\"></not-an-allowed-child-ui></nav-group-ui></nav-ui>"
2239
3031
  ]
2240
3032
  },
2241
3033
  });
2242
3034
  }
2243
3035
 
2244
3036
  {
2245
- // GENERATED do not hand-edit. Source: packages/web-components/components/list/list-item.yaml's a2ui.allowedParents/allowedChildren.
3037
+ // GENERATED: do not hand-edit. Source: packages/web-components/components/nav-item/nav-item.yaml's a2ui.allowedParents/allowedChildren.
2246
3038
  // Rebuild: node scripts/build/gen-composition-rules.mjs
2247
3039
  // Freshness gate: node scripts/verify/check-composition-rules-fresh.mjs --verify
2248
3040
 
2249
3041
 
2250
- const TAG = "list-item-ui";
2251
- const ALLOWED_PARENTS = ["list-ui"];
3042
+ const TAG = "nav-item-ui";
3043
+ const ALLOWED_PARENTS = ["nav-ui","nav-group-ui"];
2252
3044
  const ALLOWED_CHILDREN = [];
3045
+ const ALLOWED_CHILDREN_BY_SLOT = null;
2253
3046
 
2254
3047
 
2255
3048
  RULES.push({
2256
- id: "COMPOSITION-LIST-ITEM-UI",
2257
- severity: 'warn', // LLD-0016 §C4: new, unproven-at-scale matcher (Risk R4) advisory until a corpus-wide rollout promotes it, same posture check-example-ids.mjs's Phase-1 rule started at.
3049
+ id: "COMPOSITION-NAV-ITEM-UI",
3050
+ severity: 'warn', // LLD-0016 §C4: new, unproven-at-scale matcher (Risk R4): advisory until a corpus-wide rollout promotes it, same posture check-example-ids.mjs's Phase-1 rule started at.
2258
3051
  scope: 'shared',
2259
3052
  fileTypes: MARKUP_EXT,
2260
3053
  match(text) {
2261
- return compositionFindings(text, { tag: TAG, allowedParents: ALLOWED_PARENTS, allowedChildren: ALLOWED_CHILDREN });
3054
+ return compositionFindings(text, { tag: TAG, allowedParents: ALLOWED_PARENTS, allowedChildren: ALLOWED_CHILDREN, allowedChildrenBySlot: ALLOWED_CHILDREN_BY_SLOT });
2262
3055
  },
2263
3056
  fix: null, // moving markup to satisfy a composition constraint is a judgment call, not a mechanical rename (LLD-0016 §Risks R4/R5)
2264
3057
  fixtures: {
2265
3058
  "smelly": [
2266
- "<div><list-item-ui></list-item-ui></div>"
3059
+ "<div><nav-item-ui></nav-item-ui></div>"
2267
3060
  ],
2268
3061
  "clean": [
2269
- "<list-ui><list-item-ui></list-item-ui></list-ui>"
3062
+ "<nav-ui><nav-item-ui></nav-item-ui></nav-ui>"
2270
3063
  ]
2271
3064
  },
2272
3065
  });
2273
3066
  }
2274
3067
 
2275
3068
  {
2276
- // GENERATED do not hand-edit. Source: packages/web-components/components/menu/menu-divider.yaml's a2ui.allowedParents/allowedChildren.
3069
+ // GENERATED: do not hand-edit. Source: packages/web-modules/shell/page-scroll/page-scroll.yaml's a2ui.allowedParents/allowedChildren.
2277
3070
  // Rebuild: node scripts/build/gen-composition-rules.mjs
2278
3071
  // Freshness gate: node scripts/verify/check-composition-rules-fresh.mjs --verify
2279
3072
 
2280
3073
 
2281
- const TAG = "menu-divider-ui";
2282
- const ALLOWED_PARENTS = ["menu-ui"];
3074
+ const TAG = "page-scroll";
3075
+ const ALLOWED_PARENTS = ["admin-content"];
2283
3076
  const ALLOWED_CHILDREN = [];
3077
+ const ALLOWED_CHILDREN_BY_SLOT = null;
2284
3078
 
2285
3079
 
2286
3080
  RULES.push({
2287
- id: "COMPOSITION-MENU-DIVIDER-UI",
2288
- severity: 'warn', // LLD-0016 §C4: new, unproven-at-scale matcher (Risk R4) advisory until a corpus-wide rollout promotes it, same posture check-example-ids.mjs's Phase-1 rule started at.
3081
+ id: "COMPOSITION-PAGE-SCROLL",
3082
+ severity: 'warn', // LLD-0016 §C4: new, unproven-at-scale matcher (Risk R4): advisory until a corpus-wide rollout promotes it, same posture check-example-ids.mjs's Phase-1 rule started at.
2289
3083
  scope: 'shared',
2290
3084
  fileTypes: MARKUP_EXT,
2291
3085
  match(text) {
2292
- return compositionFindings(text, { tag: TAG, allowedParents: ALLOWED_PARENTS, allowedChildren: ALLOWED_CHILDREN });
3086
+ return compositionFindings(text, { tag: TAG, allowedParents: ALLOWED_PARENTS, allowedChildren: ALLOWED_CHILDREN, allowedChildrenBySlot: ALLOWED_CHILDREN_BY_SLOT });
2293
3087
  },
2294
3088
  fix: null, // moving markup to satisfy a composition constraint is a judgment call, not a mechanical rename (LLD-0016 §Risks R4/R5)
2295
3089
  fixtures: {
2296
3090
  "smelly": [
2297
- "<div><menu-divider-ui></menu-divider-ui></div>"
3091
+ "<div><page-scroll></page-scroll></div>"
2298
3092
  ],
2299
3093
  "clean": [
2300
- "<menu-ui><menu-divider-ui></menu-divider-ui></menu-ui>"
3094
+ "<admin-content><page-scroll></page-scroll></admin-content>"
2301
3095
  ]
2302
3096
  },
2303
3097
  });
2304
3098
  }
2305
3099
 
2306
3100
  {
2307
- // GENERATED do not hand-edit. Source: packages/web-components/components/menu/menu-item.yaml's a2ui.allowedParents/allowedChildren.
3101
+ // GENERATED: do not hand-edit. Source: packages/web-components/components/radio-group/radio-group.yaml's a2ui.allowedParents/allowedChildren.
2308
3102
  // Rebuild: node scripts/build/gen-composition-rules.mjs
2309
3103
  // Freshness gate: node scripts/verify/check-composition-rules-fresh.mjs --verify
2310
3104
 
2311
3105
 
2312
- const TAG = "menu-item-ui";
2313
- const ALLOWED_PARENTS = ["menu-ui"];
2314
- const ALLOWED_CHILDREN = [];
3106
+ const TAG = "radio-group-ui";
3107
+ const ALLOWED_PARENTS = [];
3108
+ const ALLOWED_CHILDREN = ["radio-ui"];
3109
+ const ALLOWED_CHILDREN_BY_SLOT = null;
2315
3110
 
2316
3111
 
2317
3112
  RULES.push({
2318
- id: "COMPOSITION-MENU-ITEM-UI",
2319
- severity: 'warn', // LLD-0016 §C4: new, unproven-at-scale matcher (Risk R4) advisory until a corpus-wide rollout promotes it, same posture check-example-ids.mjs's Phase-1 rule started at.
3113
+ id: "COMPOSITION-RADIO-GROUP-UI",
3114
+ severity: 'warn', // LLD-0016 §C4: new, unproven-at-scale matcher (Risk R4): advisory until a corpus-wide rollout promotes it, same posture check-example-ids.mjs's Phase-1 rule started at.
2320
3115
  scope: 'shared',
2321
3116
  fileTypes: MARKUP_EXT,
2322
3117
  match(text) {
2323
- return compositionFindings(text, { tag: TAG, allowedParents: ALLOWED_PARENTS, allowedChildren: ALLOWED_CHILDREN });
3118
+ return compositionFindings(text, { tag: TAG, allowedParents: ALLOWED_PARENTS, allowedChildren: ALLOWED_CHILDREN, allowedChildrenBySlot: ALLOWED_CHILDREN_BY_SLOT });
2324
3119
  },
2325
3120
  fix: null, // moving markup to satisfy a composition constraint is a judgment call, not a mechanical rename (LLD-0016 §Risks R4/R5)
2326
3121
  fixtures: {
2327
3122
  "smelly": [
2328
- "<div><menu-item-ui></menu-item-ui></div>"
3123
+ "<radio-group-ui><not-an-allowed-child-ui></not-an-allowed-child-ui></radio-group-ui>"
2329
3124
  ],
2330
3125
  "clean": [
2331
- "<menu-ui><menu-item-ui></menu-item-ui></menu-ui>"
3126
+ "<radio-group-ui><radio-ui></radio-ui></radio-group-ui>",
3127
+ "<radio-group-ui><not-an-allowed-child-ui slot=\"arbitrary-slot\"></not-an-allowed-child-ui></radio-group-ui>"
2332
3128
  ]
2333
3129
  },
2334
3130
  });
2335
3131
  }
2336
3132
 
2337
3133
  {
2338
- // GENERATED do not hand-edit. Source: packages/web-components/components/menu/menu-label.yaml's a2ui.allowedParents/allowedChildren.
3134
+ // GENERATED: do not hand-edit. Source: packages/web-components/components/search/search.yaml's a2ui.allowedParents/allowedChildren.
2339
3135
  // Rebuild: node scripts/build/gen-composition-rules.mjs
2340
3136
  // Freshness gate: node scripts/verify/check-composition-rules-fresh.mjs --verify
2341
3137
 
2342
3138
 
2343
- const TAG = "menu-label-ui";
2344
- const ALLOWED_PARENTS = ["menu-ui"];
2345
- const ALLOWED_CHILDREN = [];
3139
+ const TAG = "search-ui";
3140
+ const ALLOWED_PARENTS = [];
3141
+ const ALLOWED_CHILDREN = ["input-ui"];
3142
+ const ALLOWED_CHILDREN_BY_SLOT = null;
2346
3143
 
2347
3144
 
2348
3145
  RULES.push({
2349
- id: "COMPOSITION-MENU-LABEL-UI",
2350
- severity: 'warn', // LLD-0016 §C4: new, unproven-at-scale matcher (Risk R4) advisory until a corpus-wide rollout promotes it, same posture check-example-ids.mjs's Phase-1 rule started at.
3146
+ id: "COMPOSITION-SEARCH-UI",
3147
+ severity: 'warn', // LLD-0016 §C4: new, unproven-at-scale matcher (Risk R4): advisory until a corpus-wide rollout promotes it, same posture check-example-ids.mjs's Phase-1 rule started at.
2351
3148
  scope: 'shared',
2352
3149
  fileTypes: MARKUP_EXT,
2353
3150
  match(text) {
2354
- return compositionFindings(text, { tag: TAG, allowedParents: ALLOWED_PARENTS, allowedChildren: ALLOWED_CHILDREN });
3151
+ return compositionFindings(text, { tag: TAG, allowedParents: ALLOWED_PARENTS, allowedChildren: ALLOWED_CHILDREN, allowedChildrenBySlot: ALLOWED_CHILDREN_BY_SLOT });
2355
3152
  },
2356
3153
  fix: null, // moving markup to satisfy a composition constraint is a judgment call, not a mechanical rename (LLD-0016 §Risks R4/R5)
2357
3154
  fixtures: {
2358
3155
  "smelly": [
2359
- "<div><menu-label-ui></menu-label-ui></div>"
3156
+ "<search-ui><not-an-allowed-child-ui></not-an-allowed-child-ui></search-ui>"
2360
3157
  ],
2361
3158
  "clean": [
2362
- "<menu-ui><menu-label-ui></menu-label-ui></menu-ui>"
3159
+ "<search-ui><input-ui></input-ui></search-ui>",
3160
+ "<search-ui><not-an-allowed-child-ui slot=\"arbitrary-slot\"></not-an-allowed-child-ui></search-ui>"
2363
3161
  ]
2364
3162
  },
2365
3163
  });
2366
3164
  }
2367
3165
 
2368
3166
  {
2369
- // GENERATED do not hand-edit. Source: packages/web-modules/shell/page-scroll/page-scroll.yaml's a2ui.allowedParents/allowedChildren.
3167
+ // GENERATED: do not hand-edit. Source: packages/web-components/components/section/section.yaml's a2ui.allowedParents/allowedChildren.
2370
3168
  // Rebuild: node scripts/build/gen-composition-rules.mjs
2371
3169
  // Freshness gate: node scripts/verify/check-composition-rules-fresh.mjs --verify
2372
3170
 
2373
3171
 
2374
- const TAG = "page-scroll";
2375
- const ALLOWED_PARENTS = ["admin-content"];
3172
+ const TAG = "section-ui";
3173
+ const ALLOWED_PARENTS = ["page-ui","admin-sidebar"];
2376
3174
  const ALLOWED_CHILDREN = [];
3175
+ const ALLOWED_CHILDREN_BY_SLOT = null;
2377
3176
 
2378
3177
 
2379
3178
  RULES.push({
2380
- id: "COMPOSITION-PAGE-SCROLL",
2381
- severity: 'warn', // LLD-0016 §C4: new, unproven-at-scale matcher (Risk R4) advisory until a corpus-wide rollout promotes it, same posture check-example-ids.mjs's Phase-1 rule started at.
3179
+ id: "COMPOSITION-SECTION-UI",
3180
+ severity: 'warn', // LLD-0016 §C4: new, unproven-at-scale matcher (Risk R4): advisory until a corpus-wide rollout promotes it, same posture check-example-ids.mjs's Phase-1 rule started at.
2382
3181
  scope: 'shared',
2383
3182
  fileTypes: MARKUP_EXT,
2384
3183
  match(text) {
2385
- return compositionFindings(text, { tag: TAG, allowedParents: ALLOWED_PARENTS, allowedChildren: ALLOWED_CHILDREN });
3184
+ return compositionFindings(text, { tag: TAG, allowedParents: ALLOWED_PARENTS, allowedChildren: ALLOWED_CHILDREN, allowedChildrenBySlot: ALLOWED_CHILDREN_BY_SLOT });
2386
3185
  },
2387
3186
  fix: null, // moving markup to satisfy a composition constraint is a judgment call, not a mechanical rename (LLD-0016 §Risks R4/R5)
2388
3187
  fixtures: {
2389
3188
  "smelly": [
2390
- "<div><page-scroll></page-scroll></div>"
3189
+ "<div><section-ui></section-ui></div>"
2391
3190
  ],
2392
3191
  "clean": [
2393
- "<admin-content><page-scroll></page-scroll></admin-content>"
3192
+ "<page-ui><section-ui></section-ui></page-ui>"
2394
3193
  ]
2395
3194
  },
2396
3195
  });
2397
3196
  }
2398
3197
 
2399
3198
  {
2400
- // GENERATED do not hand-edit. Source: packages/web-components/components/segment/segment.yaml's a2ui.allowedParents/allowedChildren.
3199
+ // GENERATED: do not hand-edit. Source: packages/web-components/components/segment/segment.yaml's a2ui.allowedParents/allowedChildren.
2401
3200
  // Rebuild: node scripts/build/gen-composition-rules.mjs
2402
3201
  // Freshness gate: node scripts/verify/check-composition-rules-fresh.mjs --verify
2403
3202
 
@@ -2405,15 +3204,16 @@ RULES.push({
2405
3204
  const TAG = "segment-ui";
2406
3205
  const ALLOWED_PARENTS = ["segmented-ui"];
2407
3206
  const ALLOWED_CHILDREN = [];
3207
+ const ALLOWED_CHILDREN_BY_SLOT = null;
2408
3208
 
2409
3209
 
2410
3210
  RULES.push({
2411
3211
  id: "COMPOSITION-SEGMENT-UI",
2412
- severity: 'warn', // LLD-0016 §C4: new, unproven-at-scale matcher (Risk R4) advisory until a corpus-wide rollout promotes it, same posture check-example-ids.mjs's Phase-1 rule started at.
3212
+ severity: 'warn', // LLD-0016 §C4: new, unproven-at-scale matcher (Risk R4): advisory until a corpus-wide rollout promotes it, same posture check-example-ids.mjs's Phase-1 rule started at.
2413
3213
  scope: 'shared',
2414
3214
  fileTypes: MARKUP_EXT,
2415
3215
  match(text) {
2416
- return compositionFindings(text, { tag: TAG, allowedParents: ALLOWED_PARENTS, allowedChildren: ALLOWED_CHILDREN });
3216
+ return compositionFindings(text, { tag: TAG, allowedParents: ALLOWED_PARENTS, allowedChildren: ALLOWED_CHILDREN, allowedChildrenBySlot: ALLOWED_CHILDREN_BY_SLOT });
2417
3217
  },
2418
3218
  fix: null, // moving markup to satisfy a composition constraint is a judgment call, not a mechanical rename (LLD-0016 §Risks R4/R5)
2419
3219
  fixtures: {
@@ -2428,7 +3228,7 @@ RULES.push({
2428
3228
  }
2429
3229
 
2430
3230
  {
2431
- // GENERATED do not hand-edit. Source: packages/web-components/components/segmented/segmented.yaml's a2ui.allowedParents/allowedChildren.
3231
+ // GENERATED: do not hand-edit. Source: packages/web-components/components/segmented/segmented.yaml's a2ui.allowedParents/allowedChildren.
2432
3232
  // Rebuild: node scripts/build/gen-composition-rules.mjs
2433
3233
  // Freshness gate: node scripts/verify/check-composition-rules-fresh.mjs --verify
2434
3234
 
@@ -2436,15 +3236,16 @@ RULES.push({
2436
3236
  const TAG = "segmented-ui";
2437
3237
  const ALLOWED_PARENTS = [];
2438
3238
  const ALLOWED_CHILDREN = ["segment-ui"];
3239
+ const ALLOWED_CHILDREN_BY_SLOT = null;
2439
3240
 
2440
3241
 
2441
3242
  RULES.push({
2442
3243
  id: "COMPOSITION-SEGMENTED-UI",
2443
- severity: 'warn', // LLD-0016 §C4: new, unproven-at-scale matcher (Risk R4) advisory until a corpus-wide rollout promotes it, same posture check-example-ids.mjs's Phase-1 rule started at.
3244
+ severity: 'warn', // LLD-0016 §C4: new, unproven-at-scale matcher (Risk R4): advisory until a corpus-wide rollout promotes it, same posture check-example-ids.mjs's Phase-1 rule started at.
2444
3245
  scope: 'shared',
2445
3246
  fileTypes: MARKUP_EXT,
2446
3247
  match(text) {
2447
- return compositionFindings(text, { tag: TAG, allowedParents: ALLOWED_PARENTS, allowedChildren: ALLOWED_CHILDREN });
3248
+ return compositionFindings(text, { tag: TAG, allowedParents: ALLOWED_PARENTS, allowedChildren: ALLOWED_CHILDREN, allowedChildrenBySlot: ALLOWED_CHILDREN_BY_SLOT });
2448
3249
  },
2449
3250
  fix: null, // moving markup to satisfy a composition constraint is a judgment call, not a mechanical rename (LLD-0016 §Risks R4/R5)
2450
3251
  fixtures: {
@@ -2452,14 +3253,15 @@ RULES.push({
2452
3253
  "<segmented-ui><not-an-allowed-child-ui></not-an-allowed-child-ui></segmented-ui>"
2453
3254
  ],
2454
3255
  "clean": [
2455
- "<segmented-ui><segment-ui></segment-ui></segmented-ui>"
3256
+ "<segmented-ui><segment-ui></segment-ui></segmented-ui>",
3257
+ "<segmented-ui><not-an-allowed-child-ui slot=\"arbitrary-slot\"></not-an-allowed-child-ui></segmented-ui>"
2456
3258
  ]
2457
3259
  },
2458
3260
  });
2459
3261
  }
2460
3262
 
2461
3263
  {
2462
- // GENERATED do not hand-edit. Source: packages/web-modules/simple/simple-content/simple-content.yaml's a2ui.allowedParents/allowedChildren.
3264
+ // GENERATED: do not hand-edit. Source: packages/web-modules/simple/simple-content/simple-content.yaml's a2ui.allowedParents/allowedChildren.
2463
3265
  // Rebuild: node scripts/build/gen-composition-rules.mjs
2464
3266
  // Freshness gate: node scripts/verify/check-composition-rules-fresh.mjs --verify
2465
3267
 
@@ -2467,15 +3269,16 @@ RULES.push({
2467
3269
  const TAG = "simple-content";
2468
3270
  const ALLOWED_PARENTS = ["simple-shell"];
2469
3271
  const ALLOWED_CHILDREN = [];
3272
+ const ALLOWED_CHILDREN_BY_SLOT = null;
2470
3273
 
2471
3274
 
2472
3275
  RULES.push({
2473
3276
  id: "COMPOSITION-SIMPLE-CONTENT",
2474
- severity: 'warn', // LLD-0016 §C4: new, unproven-at-scale matcher (Risk R4) advisory until a corpus-wide rollout promotes it, same posture check-example-ids.mjs's Phase-1 rule started at.
3277
+ severity: 'warn', // LLD-0016 §C4: new, unproven-at-scale matcher (Risk R4): advisory until a corpus-wide rollout promotes it, same posture check-example-ids.mjs's Phase-1 rule started at.
2475
3278
  scope: 'shared',
2476
3279
  fileTypes: MARKUP_EXT,
2477
3280
  match(text) {
2478
- return compositionFindings(text, { tag: TAG, allowedParents: ALLOWED_PARENTS, allowedChildren: ALLOWED_CHILDREN });
3281
+ return compositionFindings(text, { tag: TAG, allowedParents: ALLOWED_PARENTS, allowedChildren: ALLOWED_CHILDREN, allowedChildrenBySlot: ALLOWED_CHILDREN_BY_SLOT });
2479
3282
  },
2480
3283
  fix: null, // moving markup to satisfy a composition constraint is a judgment call, not a mechanical rename (LLD-0016 §Risks R4/R5)
2481
3284
  fixtures: {
@@ -2490,7 +3293,7 @@ RULES.push({
2490
3293
  }
2491
3294
 
2492
3295
  {
2493
- // GENERATED do not hand-edit. Source: packages/web-modules/simple/simple-hero/simple-hero.yaml's a2ui.allowedParents/allowedChildren.
3296
+ // GENERATED: do not hand-edit. Source: packages/web-modules/simple/simple-hero/simple-hero.yaml's a2ui.allowedParents/allowedChildren.
2494
3297
  // Rebuild: node scripts/build/gen-composition-rules.mjs
2495
3298
  // Freshness gate: node scripts/verify/check-composition-rules-fresh.mjs --verify
2496
3299
 
@@ -2498,15 +3301,16 @@ RULES.push({
2498
3301
  const TAG = "simple-hero";
2499
3302
  const ALLOWED_PARENTS = ["simple-shell"];
2500
3303
  const ALLOWED_CHILDREN = [];
3304
+ const ALLOWED_CHILDREN_BY_SLOT = null;
2501
3305
 
2502
3306
 
2503
3307
  RULES.push({
2504
3308
  id: "COMPOSITION-SIMPLE-HERO",
2505
- severity: 'warn', // LLD-0016 §C4: new, unproven-at-scale matcher (Risk R4) advisory until a corpus-wide rollout promotes it, same posture check-example-ids.mjs's Phase-1 rule started at.
3309
+ severity: 'warn', // LLD-0016 §C4: new, unproven-at-scale matcher (Risk R4): advisory until a corpus-wide rollout promotes it, same posture check-example-ids.mjs's Phase-1 rule started at.
2506
3310
  scope: 'shared',
2507
3311
  fileTypes: MARKUP_EXT,
2508
3312
  match(text) {
2509
- return compositionFindings(text, { tag: TAG, allowedParents: ALLOWED_PARENTS, allowedChildren: ALLOWED_CHILDREN });
3313
+ return compositionFindings(text, { tag: TAG, allowedParents: ALLOWED_PARENTS, allowedChildren: ALLOWED_CHILDREN, allowedChildrenBySlot: ALLOWED_CHILDREN_BY_SLOT });
2510
3314
  },
2511
3315
  fix: null, // moving markup to satisfy a composition constraint is a judgment call, not a mechanical rename (LLD-0016 §Risks R4/R5)
2512
3316
  fixtures: {
@@ -2521,7 +3325,7 @@ RULES.push({
2521
3325
  }
2522
3326
 
2523
3327
  {
2524
- // GENERATED do not hand-edit. Source: packages/web-modules/simple/simple-shell/simple-shell.yaml's a2ui.allowedParents/allowedChildren.
3328
+ // GENERATED: do not hand-edit. Source: packages/web-modules/simple/simple-shell/simple-shell.yaml's a2ui.allowedParents/allowedChildren.
2525
3329
  // Rebuild: node scripts/build/gen-composition-rules.mjs
2526
3330
  // Freshness gate: node scripts/verify/check-composition-rules-fresh.mjs --verify
2527
3331
 
@@ -2529,15 +3333,16 @@ RULES.push({
2529
3333
  const TAG = "simple-shell";
2530
3334
  const ALLOWED_PARENTS = ["Surface"];
2531
3335
  const ALLOWED_CHILDREN = [];
3336
+ const ALLOWED_CHILDREN_BY_SLOT = null;
2532
3337
 
2533
3338
 
2534
3339
  RULES.push({
2535
3340
  id: "COMPOSITION-SIMPLE-SHELL",
2536
- severity: 'warn', // LLD-0016 §C4: new, unproven-at-scale matcher (Risk R4) advisory until a corpus-wide rollout promotes it, same posture check-example-ids.mjs's Phase-1 rule started at.
3341
+ severity: 'warn', // LLD-0016 §C4: new, unproven-at-scale matcher (Risk R4): advisory until a corpus-wide rollout promotes it, same posture check-example-ids.mjs's Phase-1 rule started at.
2537
3342
  scope: 'shared',
2538
3343
  fileTypes: MARKUP_EXT,
2539
3344
  match(text) {
2540
- return compositionFindings(text, { tag: TAG, allowedParents: ALLOWED_PARENTS, allowedChildren: ALLOWED_CHILDREN });
3345
+ return compositionFindings(text, { tag: TAG, allowedParents: ALLOWED_PARENTS, allowedChildren: ALLOWED_CHILDREN, allowedChildrenBySlot: ALLOWED_CHILDREN_BY_SLOT });
2541
3346
  },
2542
3347
  fix: null, // moving markup to satisfy a composition constraint is a judgment call, not a mechanical rename (LLD-0016 §Risks R4/R5)
2543
3348
  fixtures: {
@@ -2552,7 +3357,39 @@ RULES.push({
2552
3357
  }
2553
3358
 
2554
3359
  {
2555
- // GENERATED do not hand-edit. Source: packages/web-components/components/stepper/stepper-item.yaml's a2ui.allowedParents/allowedChildren.
3360
+ // GENERATED: do not hand-edit. Source: packages/web-components/components/skip-nav/skip-nav.yaml's a2ui.allowedParents/allowedChildren.
3361
+ // Rebuild: node scripts/build/gen-composition-rules.mjs
3362
+ // Freshness gate: node scripts/verify/check-composition-rules-fresh.mjs --verify
3363
+
3364
+
3365
+ const TAG = "skip-nav-ui";
3366
+ const ALLOWED_PARENTS = ["Surface"];
3367
+ const ALLOWED_CHILDREN = [];
3368
+ const ALLOWED_CHILDREN_BY_SLOT = null;
3369
+
3370
+
3371
+ RULES.push({
3372
+ id: "COMPOSITION-SKIP-NAV-UI",
3373
+ severity: 'warn', // LLD-0016 §C4: new, unproven-at-scale matcher (Risk R4): advisory until a corpus-wide rollout promotes it, same posture check-example-ids.mjs's Phase-1 rule started at.
3374
+ scope: 'shared',
3375
+ fileTypes: MARKUP_EXT,
3376
+ match(text) {
3377
+ return compositionFindings(text, { tag: TAG, allowedParents: ALLOWED_PARENTS, allowedChildren: ALLOWED_CHILDREN, allowedChildrenBySlot: ALLOWED_CHILDREN_BY_SLOT });
3378
+ },
3379
+ fix: null, // moving markup to satisfy a composition constraint is a judgment call, not a mechanical rename (LLD-0016 §Risks R4/R5)
3380
+ fixtures: {
3381
+ "smelly": [
3382
+ "<col-ui><skip-nav-ui></skip-nav-ui></col-ui>"
3383
+ ],
3384
+ "clean": [
3385
+ "<skip-nav-ui></skip-nav-ui>"
3386
+ ]
3387
+ },
3388
+ });
3389
+ }
3390
+
3391
+ {
3392
+ // GENERATED: do not hand-edit. Source: packages/web-components/components/stepper/stepper-item.yaml's a2ui.allowedParents/allowedChildren.
2556
3393
  // Rebuild: node scripts/build/gen-composition-rules.mjs
2557
3394
  // Freshness gate: node scripts/verify/check-composition-rules-fresh.mjs --verify
2558
3395
 
@@ -2560,15 +3397,16 @@ RULES.push({
2560
3397
  const TAG = "stepper-item-ui";
2561
3398
  const ALLOWED_PARENTS = ["stepper-ui"];
2562
3399
  const ALLOWED_CHILDREN = [];
3400
+ const ALLOWED_CHILDREN_BY_SLOT = null;
2563
3401
 
2564
3402
 
2565
3403
  RULES.push({
2566
3404
  id: "COMPOSITION-STEPPER-ITEM-UI",
2567
- severity: 'warn', // LLD-0016 §C4: new, unproven-at-scale matcher (Risk R4) advisory until a corpus-wide rollout promotes it, same posture check-example-ids.mjs's Phase-1 rule started at.
3405
+ severity: 'warn', // LLD-0016 §C4: new, unproven-at-scale matcher (Risk R4): advisory until a corpus-wide rollout promotes it, same posture check-example-ids.mjs's Phase-1 rule started at.
2568
3406
  scope: 'shared',
2569
3407
  fileTypes: MARKUP_EXT,
2570
3408
  match(text) {
2571
- return compositionFindings(text, { tag: TAG, allowedParents: ALLOWED_PARENTS, allowedChildren: ALLOWED_CHILDREN });
3409
+ return compositionFindings(text, { tag: TAG, allowedParents: ALLOWED_PARENTS, allowedChildren: ALLOWED_CHILDREN, allowedChildrenBySlot: ALLOWED_CHILDREN_BY_SLOT });
2572
3410
  },
2573
3411
  fix: null, // moving markup to satisfy a composition constraint is a judgment call, not a mechanical rename (LLD-0016 §Risks R4/R5)
2574
3412
  fixtures: {
@@ -2583,7 +3421,7 @@ RULES.push({
2583
3421
  }
2584
3422
 
2585
3423
  {
2586
- // GENERATED do not hand-edit. Source: packages/web-components/components/stepper/stepper.yaml's a2ui.allowedParents/allowedChildren.
3424
+ // GENERATED: do not hand-edit. Source: packages/web-components/components/stepper/stepper.yaml's a2ui.allowedParents/allowedChildren.
2587
3425
  // Rebuild: node scripts/build/gen-composition-rules.mjs
2588
3426
  // Freshness gate: node scripts/verify/check-composition-rules-fresh.mjs --verify
2589
3427
 
@@ -2591,15 +3429,16 @@ RULES.push({
2591
3429
  const TAG = "stepper-ui";
2592
3430
  const ALLOWED_PARENTS = [];
2593
3431
  const ALLOWED_CHILDREN = ["stepper-item-ui"];
3432
+ const ALLOWED_CHILDREN_BY_SLOT = null;
2594
3433
 
2595
3434
 
2596
3435
  RULES.push({
2597
3436
  id: "COMPOSITION-STEPPER-UI",
2598
- severity: 'warn', // LLD-0016 §C4: new, unproven-at-scale matcher (Risk R4) advisory until a corpus-wide rollout promotes it, same posture check-example-ids.mjs's Phase-1 rule started at.
3437
+ severity: 'warn', // LLD-0016 §C4: new, unproven-at-scale matcher (Risk R4): advisory until a corpus-wide rollout promotes it, same posture check-example-ids.mjs's Phase-1 rule started at.
2599
3438
  scope: 'shared',
2600
3439
  fileTypes: MARKUP_EXT,
2601
3440
  match(text) {
2602
- return compositionFindings(text, { tag: TAG, allowedParents: ALLOWED_PARENTS, allowedChildren: ALLOWED_CHILDREN });
3441
+ return compositionFindings(text, { tag: TAG, allowedParents: ALLOWED_PARENTS, allowedChildren: ALLOWED_CHILDREN, allowedChildrenBySlot: ALLOWED_CHILDREN_BY_SLOT });
2603
3442
  },
2604
3443
  fix: null, // moving markup to satisfy a composition constraint is a judgment call, not a mechanical rename (LLD-0016 §Risks R4/R5)
2605
3444
  fixtures: {
@@ -2607,14 +3446,15 @@ RULES.push({
2607
3446
  "<stepper-ui><not-an-allowed-child-ui></not-an-allowed-child-ui></stepper-ui>"
2608
3447
  ],
2609
3448
  "clean": [
2610
- "<stepper-ui><stepper-item-ui></stepper-item-ui></stepper-ui>"
3449
+ "<stepper-ui><stepper-item-ui></stepper-item-ui></stepper-ui>",
3450
+ "<stepper-ui><not-an-allowed-child-ui slot=\"arbitrary-slot\"></not-an-allowed-child-ui></stepper-ui>"
2611
3451
  ]
2612
3452
  },
2613
3453
  });
2614
3454
  }
2615
3455
 
2616
3456
  {
2617
- // GENERATED do not hand-edit. Source: packages/web-components/components/tabs/tab.yaml's a2ui.allowedParents/allowedChildren.
3457
+ // GENERATED: do not hand-edit. Source: packages/web-components/components/tabs/tab.yaml's a2ui.allowedParents/allowedChildren.
2618
3458
  // Rebuild: node scripts/build/gen-composition-rules.mjs
2619
3459
  // Freshness gate: node scripts/verify/check-composition-rules-fresh.mjs --verify
2620
3460
 
@@ -2622,15 +3462,16 @@ RULES.push({
2622
3462
  const TAG = "tab-ui";
2623
3463
  const ALLOWED_PARENTS = ["tabs-ui"];
2624
3464
  const ALLOWED_CHILDREN = [];
3465
+ const ALLOWED_CHILDREN_BY_SLOT = null;
2625
3466
 
2626
3467
 
2627
3468
  RULES.push({
2628
3469
  id: "COMPOSITION-TAB-UI",
2629
- severity: 'warn', // LLD-0016 §C4: new, unproven-at-scale matcher (Risk R4) advisory until a corpus-wide rollout promotes it, same posture check-example-ids.mjs's Phase-1 rule started at.
3470
+ severity: 'warn', // LLD-0016 §C4: new, unproven-at-scale matcher (Risk R4): advisory until a corpus-wide rollout promotes it, same posture check-example-ids.mjs's Phase-1 rule started at.
2630
3471
  scope: 'shared',
2631
3472
  fileTypes: MARKUP_EXT,
2632
3473
  match(text) {
2633
- return compositionFindings(text, { tag: TAG, allowedParents: ALLOWED_PARENTS, allowedChildren: ALLOWED_CHILDREN });
3474
+ return compositionFindings(text, { tag: TAG, allowedParents: ALLOWED_PARENTS, allowedChildren: ALLOWED_CHILDREN, allowedChildrenBySlot: ALLOWED_CHILDREN_BY_SLOT });
2634
3475
  },
2635
3476
  fix: null, // moving markup to satisfy a composition constraint is a judgment call, not a mechanical rename (LLD-0016 §Risks R4/R5)
2636
3477
  fixtures: {
@@ -2645,7 +3486,7 @@ RULES.push({
2645
3486
  }
2646
3487
 
2647
3488
  {
2648
- // GENERATED do not hand-edit. Source: packages/web-components/components/tabs/tabs.yaml's a2ui.allowedParents/allowedChildren.
3489
+ // GENERATED: do not hand-edit. Source: packages/web-components/components/tabs/tabs.yaml's a2ui.allowedParents/allowedChildren.
2649
3490
  // Rebuild: node scripts/build/gen-composition-rules.mjs
2650
3491
  // Freshness gate: node scripts/verify/check-composition-rules-fresh.mjs --verify
2651
3492
 
@@ -2653,15 +3494,16 @@ RULES.push({
2653
3494
  const TAG = "tabs-ui";
2654
3495
  const ALLOWED_PARENTS = [];
2655
3496
  const ALLOWED_CHILDREN = ["tab-ui"];
3497
+ const ALLOWED_CHILDREN_BY_SLOT = null;
2656
3498
 
2657
3499
 
2658
3500
  RULES.push({
2659
3501
  id: "COMPOSITION-TABS-UI",
2660
- severity: 'warn', // LLD-0016 §C4: new, unproven-at-scale matcher (Risk R4) advisory until a corpus-wide rollout promotes it, same posture check-example-ids.mjs's Phase-1 rule started at.
3502
+ severity: 'warn', // LLD-0016 §C4: new, unproven-at-scale matcher (Risk R4): advisory until a corpus-wide rollout promotes it, same posture check-example-ids.mjs's Phase-1 rule started at.
2661
3503
  scope: 'shared',
2662
3504
  fileTypes: MARKUP_EXT,
2663
3505
  match(text) {
2664
- return compositionFindings(text, { tag: TAG, allowedParents: ALLOWED_PARENTS, allowedChildren: ALLOWED_CHILDREN });
3506
+ return compositionFindings(text, { tag: TAG, allowedParents: ALLOWED_PARENTS, allowedChildren: ALLOWED_CHILDREN, allowedChildrenBySlot: ALLOWED_CHILDREN_BY_SLOT });
2665
3507
  },
2666
3508
  fix: null, // moving markup to satisfy a composition constraint is a judgment call, not a mechanical rename (LLD-0016 §Risks R4/R5)
2667
3509
  fixtures: {
@@ -2669,14 +3511,15 @@ RULES.push({
2669
3511
  "<tabs-ui><not-an-allowed-child-ui></not-an-allowed-child-ui></tabs-ui>"
2670
3512
  ],
2671
3513
  "clean": [
2672
- "<tabs-ui><tab-ui></tab-ui></tabs-ui>"
3514
+ "<tabs-ui><tab-ui></tab-ui></tabs-ui>",
3515
+ "<tabs-ui><not-an-allowed-child-ui slot=\"arbitrary-slot\"></not-an-allowed-child-ui></tabs-ui>"
2673
3516
  ]
2674
3517
  },
2675
3518
  });
2676
3519
  }
2677
3520
 
2678
3521
  {
2679
- // GENERATED do not hand-edit. Source: packages/web-components/components/timeline/timeline-item.yaml's a2ui.allowedParents/allowedChildren.
3522
+ // GENERATED: do not hand-edit. Source: packages/web-components/components/timeline/timeline-item.yaml's a2ui.allowedParents/allowedChildren.
2680
3523
  // Rebuild: node scripts/build/gen-composition-rules.mjs
2681
3524
  // Freshness gate: node scripts/verify/check-composition-rules-fresh.mjs --verify
2682
3525
 
@@ -2684,15 +3527,16 @@ RULES.push({
2684
3527
  const TAG = "timeline-item-ui";
2685
3528
  const ALLOWED_PARENTS = ["timeline-ui"];
2686
3529
  const ALLOWED_CHILDREN = [];
3530
+ const ALLOWED_CHILDREN_BY_SLOT = null;
2687
3531
 
2688
3532
 
2689
3533
  RULES.push({
2690
3534
  id: "COMPOSITION-TIMELINE-ITEM-UI",
2691
- severity: 'warn', // LLD-0016 §C4: new, unproven-at-scale matcher (Risk R4) advisory until a corpus-wide rollout promotes it, same posture check-example-ids.mjs's Phase-1 rule started at.
3535
+ severity: 'warn', // LLD-0016 §C4: new, unproven-at-scale matcher (Risk R4): advisory until a corpus-wide rollout promotes it, same posture check-example-ids.mjs's Phase-1 rule started at.
2692
3536
  scope: 'shared',
2693
3537
  fileTypes: MARKUP_EXT,
2694
3538
  match(text) {
2695
- return compositionFindings(text, { tag: TAG, allowedParents: ALLOWED_PARENTS, allowedChildren: ALLOWED_CHILDREN });
3539
+ return compositionFindings(text, { tag: TAG, allowedParents: ALLOWED_PARENTS, allowedChildren: ALLOWED_CHILDREN, allowedChildrenBySlot: ALLOWED_CHILDREN_BY_SLOT });
2696
3540
  },
2697
3541
  fix: null, // moving markup to satisfy a composition constraint is a judgment call, not a mechanical rename (LLD-0016 §Risks R4/R5)
2698
3542
  fixtures: {
@@ -2707,7 +3551,7 @@ RULES.push({
2707
3551
  }
2708
3552
 
2709
3553
  {
2710
- // GENERATED do not hand-edit. Source: packages/web-components/components/timeline/timeline.yaml's a2ui.allowedParents/allowedChildren.
3554
+ // GENERATED: do not hand-edit. Source: packages/web-components/components/timeline/timeline.yaml's a2ui.allowedParents/allowedChildren.
2711
3555
  // Rebuild: node scripts/build/gen-composition-rules.mjs
2712
3556
  // Freshness gate: node scripts/verify/check-composition-rules-fresh.mjs --verify
2713
3557
 
@@ -2715,15 +3559,16 @@ RULES.push({
2715
3559
  const TAG = "timeline-ui";
2716
3560
  const ALLOWED_PARENTS = [];
2717
3561
  const ALLOWED_CHILDREN = ["timeline-item-ui"];
3562
+ const ALLOWED_CHILDREN_BY_SLOT = null;
2718
3563
 
2719
3564
 
2720
3565
  RULES.push({
2721
3566
  id: "COMPOSITION-TIMELINE-UI",
2722
- severity: 'warn', // LLD-0016 §C4: new, unproven-at-scale matcher (Risk R4) advisory until a corpus-wide rollout promotes it, same posture check-example-ids.mjs's Phase-1 rule started at.
3567
+ severity: 'warn', // LLD-0016 §C4: new, unproven-at-scale matcher (Risk R4): advisory until a corpus-wide rollout promotes it, same posture check-example-ids.mjs's Phase-1 rule started at.
2723
3568
  scope: 'shared',
2724
3569
  fileTypes: MARKUP_EXT,
2725
3570
  match(text) {
2726
- return compositionFindings(text, { tag: TAG, allowedParents: ALLOWED_PARENTS, allowedChildren: ALLOWED_CHILDREN });
3571
+ return compositionFindings(text, { tag: TAG, allowedParents: ALLOWED_PARENTS, allowedChildren: ALLOWED_CHILDREN, allowedChildrenBySlot: ALLOWED_CHILDREN_BY_SLOT });
2727
3572
  },
2728
3573
  fix: null, // moving markup to satisfy a composition constraint is a judgment call, not a mechanical rename (LLD-0016 §Risks R4/R5)
2729
3574
  fixtures: {
@@ -2731,14 +3576,15 @@ RULES.push({
2731
3576
  "<timeline-ui><not-an-allowed-child-ui></not-an-allowed-child-ui></timeline-ui>"
2732
3577
  ],
2733
3578
  "clean": [
2734
- "<timeline-ui><timeline-item-ui></timeline-item-ui></timeline-ui>"
3579
+ "<timeline-ui><timeline-item-ui></timeline-item-ui></timeline-ui>",
3580
+ "<timeline-ui><not-an-allowed-child-ui slot=\"arbitrary-slot\"></not-an-allowed-child-ui></timeline-ui>"
2735
3581
  ]
2736
3582
  },
2737
3583
  });
2738
3584
  }
2739
3585
 
2740
3586
  {
2741
- // GENERATED do not hand-edit. Source: packages/web-components/components/toolbar/toolbar-group.yaml's a2ui.allowedParents/allowedChildren.
3587
+ // GENERATED: do not hand-edit. Source: packages/web-components/components/toolbar/toolbar-group.yaml's a2ui.allowedParents/allowedChildren.
2742
3588
  // Rebuild: node scripts/build/gen-composition-rules.mjs
2743
3589
  // Freshness gate: node scripts/verify/check-composition-rules-fresh.mjs --verify
2744
3590
 
@@ -2746,15 +3592,16 @@ RULES.push({
2746
3592
  const TAG = "toolbar-group-ui";
2747
3593
  const ALLOWED_PARENTS = ["toolbar-ui"];
2748
3594
  const ALLOWED_CHILDREN = [];
3595
+ const ALLOWED_CHILDREN_BY_SLOT = null;
2749
3596
 
2750
3597
 
2751
3598
  RULES.push({
2752
3599
  id: "COMPOSITION-TOOLBAR-GROUP-UI",
2753
- severity: 'warn', // LLD-0016 §C4: new, unproven-at-scale matcher (Risk R4) advisory until a corpus-wide rollout promotes it, same posture check-example-ids.mjs's Phase-1 rule started at.
3600
+ severity: 'warn', // LLD-0016 §C4: new, unproven-at-scale matcher (Risk R4): advisory until a corpus-wide rollout promotes it, same posture check-example-ids.mjs's Phase-1 rule started at.
2754
3601
  scope: 'shared',
2755
3602
  fileTypes: MARKUP_EXT,
2756
3603
  match(text) {
2757
- return compositionFindings(text, { tag: TAG, allowedParents: ALLOWED_PARENTS, allowedChildren: ALLOWED_CHILDREN });
3604
+ return compositionFindings(text, { tag: TAG, allowedParents: ALLOWED_PARENTS, allowedChildren: ALLOWED_CHILDREN, allowedChildrenBySlot: ALLOWED_CHILDREN_BY_SLOT });
2758
3605
  },
2759
3606
  fix: null, // moving markup to satisfy a composition constraint is a judgment call, not a mechanical rename (LLD-0016 §Risks R4/R5)
2760
3607
  fixtures: {
@@ -2769,7 +3616,7 @@ RULES.push({
2769
3616
  }
2770
3617
 
2771
3618
  {
2772
- // GENERATED do not hand-edit. Source: packages/web-components/components/tour/tour-step.yaml's a2ui.allowedParents/allowedChildren.
3619
+ // GENERATED: do not hand-edit. Source: packages/web-components/components/tour/tour-step.yaml's a2ui.allowedParents/allowedChildren.
2773
3620
  // Rebuild: node scripts/build/gen-composition-rules.mjs
2774
3621
  // Freshness gate: node scripts/verify/check-composition-rules-fresh.mjs --verify
2775
3622
 
@@ -2777,15 +3624,16 @@ RULES.push({
2777
3624
  const TAG = "tour-step-ui";
2778
3625
  const ALLOWED_PARENTS = ["tour-ui"];
2779
3626
  const ALLOWED_CHILDREN = [];
3627
+ const ALLOWED_CHILDREN_BY_SLOT = null;
2780
3628
 
2781
3629
 
2782
3630
  RULES.push({
2783
3631
  id: "COMPOSITION-TOUR-STEP-UI",
2784
- severity: 'warn', // LLD-0016 §C4: new, unproven-at-scale matcher (Risk R4) advisory until a corpus-wide rollout promotes it, same posture check-example-ids.mjs's Phase-1 rule started at.
3632
+ severity: 'warn', // LLD-0016 §C4: new, unproven-at-scale matcher (Risk R4): advisory until a corpus-wide rollout promotes it, same posture check-example-ids.mjs's Phase-1 rule started at.
2785
3633
  scope: 'shared',
2786
3634
  fileTypes: MARKUP_EXT,
2787
3635
  match(text) {
2788
- return compositionFindings(text, { tag: TAG, allowedParents: ALLOWED_PARENTS, allowedChildren: ALLOWED_CHILDREN });
3636
+ return compositionFindings(text, { tag: TAG, allowedParents: ALLOWED_PARENTS, allowedChildren: ALLOWED_CHILDREN, allowedChildrenBySlot: ALLOWED_CHILDREN_BY_SLOT });
2789
3637
  },
2790
3638
  fix: null, // moving markup to satisfy a composition constraint is a judgment call, not a mechanical rename (LLD-0016 §Risks R4/R5)
2791
3639
  fixtures: {
@@ -2800,7 +3648,7 @@ RULES.push({
2800
3648
  }
2801
3649
 
2802
3650
  {
2803
- // GENERATED do not hand-edit. Source: packages/web-components/components/tour/tour.yaml's a2ui.allowedParents/allowedChildren.
3651
+ // GENERATED: do not hand-edit. Source: packages/web-components/components/tour/tour.yaml's a2ui.allowedParents/allowedChildren.
2804
3652
  // Rebuild: node scripts/build/gen-composition-rules.mjs
2805
3653
  // Freshness gate: node scripts/verify/check-composition-rules-fresh.mjs --verify
2806
3654
 
@@ -2808,15 +3656,16 @@ RULES.push({
2808
3656
  const TAG = "tour-ui";
2809
3657
  const ALLOWED_PARENTS = [];
2810
3658
  const ALLOWED_CHILDREN = ["tour-step-ui"];
3659
+ const ALLOWED_CHILDREN_BY_SLOT = null;
2811
3660
 
2812
3661
 
2813
3662
  RULES.push({
2814
3663
  id: "COMPOSITION-TOUR-UI",
2815
- severity: 'warn', // LLD-0016 §C4: new, unproven-at-scale matcher (Risk R4) advisory until a corpus-wide rollout promotes it, same posture check-example-ids.mjs's Phase-1 rule started at.
3664
+ severity: 'warn', // LLD-0016 §C4: new, unproven-at-scale matcher (Risk R4): advisory until a corpus-wide rollout promotes it, same posture check-example-ids.mjs's Phase-1 rule started at.
2816
3665
  scope: 'shared',
2817
3666
  fileTypes: MARKUP_EXT,
2818
3667
  match(text) {
2819
- return compositionFindings(text, { tag: TAG, allowedParents: ALLOWED_PARENTS, allowedChildren: ALLOWED_CHILDREN });
3668
+ return compositionFindings(text, { tag: TAG, allowedParents: ALLOWED_PARENTS, allowedChildren: ALLOWED_CHILDREN, allowedChildrenBySlot: ALLOWED_CHILDREN_BY_SLOT });
2820
3669
  },
2821
3670
  fix: null, // moving markup to satisfy a composition constraint is a judgment call, not a mechanical rename (LLD-0016 §Risks R4/R5)
2822
3671
  fixtures: {
@@ -2824,14 +3673,15 @@ RULES.push({
2824
3673
  "<tour-ui><not-an-allowed-child-ui></not-an-allowed-child-ui></tour-ui>"
2825
3674
  ],
2826
3675
  "clean": [
2827
- "<tour-ui><tour-step-ui></tour-step-ui></tour-ui>"
3676
+ "<tour-ui><tour-step-ui></tour-step-ui></tour-ui>",
3677
+ "<tour-ui><not-an-allowed-child-ui slot=\"arbitrary-slot\"></not-an-allowed-child-ui></tour-ui>"
2828
3678
  ]
2829
3679
  },
2830
3680
  });
2831
3681
  }
2832
3682
 
2833
3683
  {
2834
- // GENERATED do not hand-edit. Source: packages/web-components/components/tree/tree-item.yaml's a2ui.allowedParents/allowedChildren.
3684
+ // GENERATED: do not hand-edit. Source: packages/web-components/components/tree/tree-item.yaml's a2ui.allowedParents/allowedChildren.
2835
3685
  // Rebuild: node scripts/build/gen-composition-rules.mjs
2836
3686
  // Freshness gate: node scripts/verify/check-composition-rules-fresh.mjs --verify
2837
3687
 
@@ -2839,15 +3689,16 @@ RULES.push({
2839
3689
  const TAG = "tree-item-ui";
2840
3690
  const ALLOWED_PARENTS = ["tree-ui","tree-item-ui"];
2841
3691
  const ALLOWED_CHILDREN = [];
3692
+ const ALLOWED_CHILDREN_BY_SLOT = null;
2842
3693
 
2843
3694
 
2844
3695
  RULES.push({
2845
3696
  id: "COMPOSITION-TREE-ITEM-UI",
2846
- severity: 'warn', // LLD-0016 §C4: new, unproven-at-scale matcher (Risk R4) advisory until a corpus-wide rollout promotes it, same posture check-example-ids.mjs's Phase-1 rule started at.
3697
+ severity: 'warn', // LLD-0016 §C4: new, unproven-at-scale matcher (Risk R4): advisory until a corpus-wide rollout promotes it, same posture check-example-ids.mjs's Phase-1 rule started at.
2847
3698
  scope: 'shared',
2848
3699
  fileTypes: MARKUP_EXT,
2849
3700
  match(text) {
2850
- return compositionFindings(text, { tag: TAG, allowedParents: ALLOWED_PARENTS, allowedChildren: ALLOWED_CHILDREN });
3701
+ return compositionFindings(text, { tag: TAG, allowedParents: ALLOWED_PARENTS, allowedChildren: ALLOWED_CHILDREN, allowedChildrenBySlot: ALLOWED_CHILDREN_BY_SLOT });
2851
3702
  },
2852
3703
  fix: null, // moving markup to satisfy a composition constraint is a judgment call, not a mechanical rename (LLD-0016 §Risks R4/R5)
2853
3704
  fixtures: {
@@ -2862,7 +3713,7 @@ RULES.push({
2862
3713
  }
2863
3714
 
2864
3715
  {
2865
- // GENERATED do not hand-edit. Source: packages/web-components/components/tree/tree.yaml's a2ui.allowedParents/allowedChildren.
3716
+ // GENERATED: do not hand-edit. Source: packages/web-components/components/tree/tree.yaml's a2ui.allowedParents/allowedChildren.
2866
3717
  // Rebuild: node scripts/build/gen-composition-rules.mjs
2867
3718
  // Freshness gate: node scripts/verify/check-composition-rules-fresh.mjs --verify
2868
3719
 
@@ -2870,15 +3721,16 @@ RULES.push({
2870
3721
  const TAG = "tree-ui";
2871
3722
  const ALLOWED_PARENTS = [];
2872
3723
  const ALLOWED_CHILDREN = ["tree-item-ui"];
3724
+ const ALLOWED_CHILDREN_BY_SLOT = null;
2873
3725
 
2874
3726
 
2875
3727
  RULES.push({
2876
3728
  id: "COMPOSITION-TREE-UI",
2877
- severity: 'warn', // LLD-0016 §C4: new, unproven-at-scale matcher (Risk R4) advisory until a corpus-wide rollout promotes it, same posture check-example-ids.mjs's Phase-1 rule started at.
3729
+ severity: 'warn', // LLD-0016 §C4: new, unproven-at-scale matcher (Risk R4): advisory until a corpus-wide rollout promotes it, same posture check-example-ids.mjs's Phase-1 rule started at.
2878
3730
  scope: 'shared',
2879
3731
  fileTypes: MARKUP_EXT,
2880
3732
  match(text) {
2881
- return compositionFindings(text, { tag: TAG, allowedParents: ALLOWED_PARENTS, allowedChildren: ALLOWED_CHILDREN });
3733
+ return compositionFindings(text, { tag: TAG, allowedParents: ALLOWED_PARENTS, allowedChildren: ALLOWED_CHILDREN, allowedChildrenBySlot: ALLOWED_CHILDREN_BY_SLOT });
2882
3734
  },
2883
3735
  fix: null, // moving markup to satisfy a composition constraint is a judgment call, not a mechanical rename (LLD-0016 §Risks R4/R5)
2884
3736
  fixtures: {
@@ -2886,35 +3738,27 @@ RULES.push({
2886
3738
  "<tree-ui><not-an-allowed-child-ui></not-an-allowed-child-ui></tree-ui>"
2887
3739
  ],
2888
3740
  "clean": [
2889
- "<tree-ui><tree-item-ui></tree-item-ui></tree-ui>"
3741
+ "<tree-ui><tree-item-ui></tree-item-ui></tree-ui>",
3742
+ "<tree-ui><not-an-allowed-child-ui slot=\"arbitrary-slot\"></not-an-allowed-child-ui></tree-ui>"
2890
3743
  ]
2891
3744
  },
2892
3745
  });
2893
3746
  }
2894
3747
 
2895
3748
  {
2896
- // GENERATED do not hand-edit. Source: packages/web-components/**/*.a2ui.json + yaml,
3749
+ // GENERATED, do not hand-edit. Source: packages/web-components/**/*.a2ui.json + yaml,
2897
3750
  // packages/web-modules/**/*.a2ui.json + yaml (ADR-0108 D5 / LLD-0019 C5).
2898
3751
  // Rebuild: node scripts/build/gen-lab-posture-rules.mjs
2899
3752
  // Freshness gate: node scripts/verify/check-lab-posture-rules-fresh.mjs --verify
2900
3753
  //
2901
3754
  // ENUM-VALUE (ADR-0108 D5): a declared enum attribute set to a value outside its manifest-declared enum (default + opt-in + internal).
2902
3755
  //
2903
- // severity: 'info' here governs ONLY `npm run lint`'s bare-repo-shaped
3756
+ // severity: 'error' here governs ONLY `npm run lint`'s bare-repo-shaped
2904
3757
  // advisory bank (ADR-0040 unchanged). The lab-posture write-time hook
2905
3758
  // (packages/plugins/adia-ui-factory/scripts/lab-posture-guard.mjs,
2906
3759
  // LLD-0019 C4) does not read this field — a lab-posture write denies on
2907
3760
  // ANY finding from these same matcher functions regardless of severity
2908
3761
  // (ADR-0108 D5: "PreToolUse deny... error under the lab hook").
2909
- //
2910
- // Demoted warn -> info (gh#2939, Kim-ruled 2026-09-03): gh#2911's G2
2911
- // warn-triage sample found this rule's class overwhelmingly manifest
2912
- // drift, not real authoring bugs (INTERNAL-TIER 594/1413 findings, 42%
2913
- // of the corpus total — almost entirely shipped-and-sanctioned values
2914
- // like button-ui[variant="primary"] the tier manifest hasn't promoted
2915
- // to match reality). The matcher/detection logic is UNCHANGED — this is
2916
- // a severity relabel only. Fixing the underlying manifest drift itself
2917
- // is split out as gh#3044, not this ticket.
2918
3762
 
2919
3763
 
2920
3764
  const MANIFEST_SNAPSHOT = {
@@ -3252,6 +4096,9 @@ const MANIFEST_SNAPSHOT = {
3252
4096
  {
3253
4097
  "name": "multi"
3254
4098
  },
4099
+ {
4100
+ "name": "options"
4101
+ },
3255
4102
  {
3256
4103
  "name": "question"
3257
4104
  },
@@ -3315,6 +4162,9 @@ const MANIFEST_SNAPSHOT = {
3315
4162
  }
3316
4163
  ]
3317
4164
  },
4165
+ {
4166
+ "name": "suggestions"
4167
+ },
3318
4168
  {
3319
4169
  "name": "variant",
3320
4170
  "values": [
@@ -4048,13 +4898,16 @@ const MANIFEST_SNAPSHOT = {
4048
4898
  "name": "precision",
4049
4899
  "values": [
4050
4900
  {
4051
- "value": "date"
4901
+ "value": "date",
4902
+ "tier": "default"
4052
4903
  },
4053
4904
  {
4054
- "value": "minute"
4905
+ "value": "minute",
4906
+ "tier": "opt-in"
4055
4907
  },
4056
4908
  {
4057
- "value": "second"
4909
+ "value": "second",
4910
+ "tier": "opt-in"
4058
4911
  }
4059
4912
  ]
4060
4913
  },
@@ -4578,6 +5431,10 @@ const MANIFEST_SNAPSHOT = {
4578
5431
  },
4579
5432
  {
4580
5433
  "name": "thinking"
5434
+ },
5435
+ {
5436
+ "name": "thinkingBudget",
5437
+ "attribute": "thinking-budget"
4581
5438
  }
4582
5439
  ]
4583
5440
  },
@@ -5270,7 +6127,30 @@ const MANIFEST_SNAPSHOT = {
5270
6127
  "name": "to"
5271
6128
  },
5272
6129
  {
5273
- "name": "value"
6130
+ "name": "value",
6131
+ "values": [
6132
+ {
6133
+ "value": "today"
6134
+ },
6135
+ {
6136
+ "value": "7d"
6137
+ },
6138
+ {
6139
+ "value": "30d"
6140
+ },
6141
+ {
6142
+ "value": "90d"
6143
+ },
6144
+ {
6145
+ "value": "qtd"
6146
+ },
6147
+ {
6148
+ "value": "ytd"
6149
+ },
6150
+ {
6151
+ "value": "custom"
6152
+ }
6153
+ ]
5274
6154
  }
5275
6155
  ]
5276
6156
  },
@@ -5403,16 +6283,19 @@ const MANIFEST_SNAPSHOT = {
5403
6283
  "name": "side",
5404
6284
  "values": [
5405
6285
  {
5406
- "value": "left"
6286
+ "value": "left",
6287
+ "tier": "opt-in"
5407
6288
  },
5408
6289
  {
5409
- "value": "right"
6290
+ "value": "right",
6291
+ "tier": "default"
5410
6292
  },
5411
6293
  {
5412
6294
  "value": "top"
5413
6295
  },
5414
6296
  {
5415
- "value": "bottom"
6297
+ "value": "bottom",
6298
+ "tier": "opt-in"
5416
6299
  }
5417
6300
  ]
5418
6301
  },
@@ -5907,13 +6790,16 @@ const MANIFEST_SNAPSHOT = {
5907
6790
  "name": "scale",
5908
6791
  "values": [
5909
6792
  {
5910
- "value": "linear"
6793
+ "value": "linear",
6794
+ "tier": "default"
5911
6795
  },
5912
6796
  {
5913
- "value": "log"
6797
+ "value": "log",
6798
+ "tier": "opt-in"
5914
6799
  },
5915
6800
  {
5916
- "value": "quantile"
6801
+ "value": "quantile",
6802
+ "tier": "opt-in"
5917
6803
  }
5918
6804
  ]
5919
6805
  },
@@ -6134,7 +7020,29 @@ const MANIFEST_SNAPSHOT = {
6134
7020
  "name": "text"
6135
7021
  },
6136
7022
  {
6137
- "name": "variant"
7023
+ "name": "variant",
7024
+ "values": [
7025
+ {
7026
+ "value": "default",
7027
+ "tier": "default"
7028
+ },
7029
+ {
7030
+ "value": "info",
7031
+ "tier": "opt-in"
7032
+ },
7033
+ {
7034
+ "value": "success",
7035
+ "tier": "opt-in"
7036
+ },
7037
+ {
7038
+ "value": "warning",
7039
+ "tier": "opt-in"
7040
+ },
7041
+ {
7042
+ "value": "danger",
7043
+ "tier": "opt-in"
7044
+ }
7045
+ ]
6138
7046
  }
6139
7047
  ]
6140
7048
  },
@@ -6180,7 +7088,33 @@ const MANIFEST_SNAPSHOT = {
6180
7088
  "name": "error"
6181
7089
  },
6182
7090
  {
6183
- "name": "inputmode"
7091
+ "name": "inputmode",
7092
+ "values": [
7093
+ {
7094
+ "value": "text"
7095
+ },
7096
+ {
7097
+ "value": "decimal"
7098
+ },
7099
+ {
7100
+ "value": "numeric"
7101
+ },
7102
+ {
7103
+ "value": "tel"
7104
+ },
7105
+ {
7106
+ "value": "search"
7107
+ },
7108
+ {
7109
+ "value": "email"
7110
+ },
7111
+ {
7112
+ "value": "url"
7113
+ },
7114
+ {
7115
+ "value": "none"
7116
+ }
7117
+ ]
6184
7118
  },
6185
7119
  {
6186
7120
  "name": "label"
@@ -6281,7 +7215,24 @@ const MANIFEST_SNAPSHOT = {
6281
7215
  "required": true
6282
7216
  },
6283
7217
  {
6284
- "name": "status"
7218
+ "name": "status",
7219
+ "values": [
7220
+ {
7221
+ "value": "available"
7222
+ },
7223
+ {
7224
+ "value": "connected"
7225
+ },
7226
+ {
7227
+ "value": "error"
7228
+ },
7229
+ {
7230
+ "value": "pending"
7231
+ },
7232
+ {
7233
+ "value": "coming-soon"
7234
+ }
7235
+ ]
6285
7236
  }
6286
7237
  ]
6287
7238
  },
@@ -6313,7 +7264,24 @@ const MANIFEST_SNAPSHOT = {
6313
7264
  "name": "searchPlaceholder"
6314
7265
  },
6315
7266
  {
6316
- "name": "statusFilter"
7267
+ "name": "statusFilter",
7268
+ "values": [
7269
+ {
7270
+ "value": "all"
7271
+ },
7272
+ {
7273
+ "value": "available"
7274
+ },
7275
+ {
7276
+ "value": "connected"
7277
+ },
7278
+ {
7279
+ "value": "error"
7280
+ },
7281
+ {
7282
+ "value": "coming-soon"
7283
+ }
7284
+ ]
6317
7285
  }
6318
7286
  ]
6319
7287
  },
@@ -6355,7 +7323,24 @@ const MANIFEST_SNAPSHOT = {
6355
7323
  "name": "printable"
6356
7324
  },
6357
7325
  {
6358
- "name": "status"
7326
+ "name": "status",
7327
+ "values": [
7328
+ {
7329
+ "value": "draft"
7330
+ },
7331
+ {
7332
+ "value": "open"
7333
+ },
7334
+ {
7335
+ "value": "paid"
7336
+ },
7337
+ {
7338
+ "value": "past-due"
7339
+ },
7340
+ {
7341
+ "value": "void"
7342
+ }
7343
+ ]
6359
7344
  }
6360
7345
  ]
6361
7346
  },
@@ -6387,7 +7372,27 @@ const MANIFEST_SNAPSHOT = {
6387
7372
  "name": "exportable"
6388
7373
  },
6389
7374
  {
6390
- "name": "filter"
7375
+ "name": "filter",
7376
+ "values": [
7377
+ {
7378
+ "value": ""
7379
+ },
7380
+ {
7381
+ "value": "draft"
7382
+ },
7383
+ {
7384
+ "value": "open"
7385
+ },
7386
+ {
7387
+ "value": "paid"
7388
+ },
7389
+ {
7390
+ "value": "past-due"
7391
+ },
7392
+ {
7393
+ "value": "void"
7394
+ }
7395
+ ]
6391
7396
  },
6392
7397
  {
6393
7398
  "name": "hrefPattern",
@@ -6600,7 +7605,21 @@ const MANIFEST_SNAPSHOT = {
6600
7605
  "name": "label"
6601
7606
  },
6602
7607
  {
6603
- "name": "variant"
7608
+ "name": "variant",
7609
+ "values": [
7610
+ {
7611
+ "value": "default",
7612
+ "tier": "default"
7613
+ },
7614
+ {
7615
+ "value": "transparent",
7616
+ "tier": "opt-in"
7617
+ },
7618
+ {
7619
+ "value": "blur",
7620
+ "tier": "opt-in"
7621
+ }
7622
+ ]
6604
7623
  }
6605
7624
  ]
6606
7625
  },
@@ -7229,6 +8248,10 @@ const MANIFEST_SNAPSHOT = {
7229
8248
  {
7230
8249
  "tag": "pagination-ui",
7231
8250
  "attrs": [
8251
+ {
8252
+ "name": "noLandmark",
8253
+ "attribute": "no-landmark"
8254
+ },
7232
8255
  {
7233
8256
  "name": "page"
7234
8257
  },
@@ -7434,7 +8457,15 @@ const MANIFEST_SNAPSHOT = {
7434
8457
  "name": "current"
7435
8458
  },
7436
8459
  {
7437
- "name": "cycle"
8460
+ "name": "cycle",
8461
+ "values": [
8462
+ {
8463
+ "value": "monthly"
8464
+ },
8465
+ {
8466
+ "value": "annual"
8467
+ }
8468
+ ]
7438
8469
  },
7439
8470
  {
7440
8471
  "name": "cycleToggle",
@@ -10082,7 +11113,7 @@ const MANIFEST_SNAPSHOT = {
10082
11113
 
10083
11114
  RULES.push({
10084
11115
  id: "ENUM-VALUE",
10085
- severity: "info",
11116
+ severity: "error",
10086
11117
  scope: 'shared',
10087
11118
  fileTypes: MARKUP_EXT,
10088
11119
  match(text, path = '') {
@@ -10103,12 +11134,12 @@ RULES.push({
10103
11134
  }
10104
11135
 
10105
11136
  {
10106
- // GENERATED do not hand-edit. Source: packages/web-components/**/*.a2ui.json + yaml,
11137
+ // GENERATED, do not hand-edit. Source: packages/web-components/**/*.a2ui.json + yaml,
10107
11138
  // packages/web-modules/**/*.a2ui.json + yaml (ADR-0108 D5 / LLD-0019 C5).
10108
11139
  // Rebuild: node scripts/build/gen-lab-posture-rules.mjs
10109
11140
  // Freshness gate: node scripts/verify/check-lab-posture-rules-fresh.mjs --verify
10110
11141
  //
10111
- // INTERNAL-TIER (ADR-0108 D3/D5): a declared enum value present in the manifest but tiered `internal` reachable in source, never the intended answer for a generator or author.
11142
+ // INTERNAL-TIER (ADR-0108 D3/D5): a declared enum value present in the manifest but tiered `internal`, reachable in source, never the intended answer for a generator or author.
10112
11143
  //
10113
11144
  // severity: 'info' here governs ONLY `npm run lint`'s bare-repo-shaped
10114
11145
  // advisory bank (ADR-0040 unchanged). The lab-posture write-time hook
@@ -10462,6 +11493,9 @@ const MANIFEST_SNAPSHOT = {
10462
11493
  {
10463
11494
  "name": "multi"
10464
11495
  },
11496
+ {
11497
+ "name": "options"
11498
+ },
10465
11499
  {
10466
11500
  "name": "question"
10467
11501
  },
@@ -10525,6 +11559,9 @@ const MANIFEST_SNAPSHOT = {
10525
11559
  }
10526
11560
  ]
10527
11561
  },
11562
+ {
11563
+ "name": "suggestions"
11564
+ },
10528
11565
  {
10529
11566
  "name": "variant",
10530
11567
  "values": [
@@ -11258,13 +12295,16 @@ const MANIFEST_SNAPSHOT = {
11258
12295
  "name": "precision",
11259
12296
  "values": [
11260
12297
  {
11261
- "value": "date"
12298
+ "value": "date",
12299
+ "tier": "default"
11262
12300
  },
11263
12301
  {
11264
- "value": "minute"
12302
+ "value": "minute",
12303
+ "tier": "opt-in"
11265
12304
  },
11266
12305
  {
11267
- "value": "second"
12306
+ "value": "second",
12307
+ "tier": "opt-in"
11268
12308
  }
11269
12309
  ]
11270
12310
  },
@@ -11788,6 +12828,10 @@ const MANIFEST_SNAPSHOT = {
11788
12828
  },
11789
12829
  {
11790
12830
  "name": "thinking"
12831
+ },
12832
+ {
12833
+ "name": "thinkingBudget",
12834
+ "attribute": "thinking-budget"
11791
12835
  }
11792
12836
  ]
11793
12837
  },
@@ -12480,7 +13524,30 @@ const MANIFEST_SNAPSHOT = {
12480
13524
  "name": "to"
12481
13525
  },
12482
13526
  {
12483
- "name": "value"
13527
+ "name": "value",
13528
+ "values": [
13529
+ {
13530
+ "value": "today"
13531
+ },
13532
+ {
13533
+ "value": "7d"
13534
+ },
13535
+ {
13536
+ "value": "30d"
13537
+ },
13538
+ {
13539
+ "value": "90d"
13540
+ },
13541
+ {
13542
+ "value": "qtd"
13543
+ },
13544
+ {
13545
+ "value": "ytd"
13546
+ },
13547
+ {
13548
+ "value": "custom"
13549
+ }
13550
+ ]
12484
13551
  }
12485
13552
  ]
12486
13553
  },
@@ -12613,16 +13680,19 @@ const MANIFEST_SNAPSHOT = {
12613
13680
  "name": "side",
12614
13681
  "values": [
12615
13682
  {
12616
- "value": "left"
13683
+ "value": "left",
13684
+ "tier": "opt-in"
12617
13685
  },
12618
13686
  {
12619
- "value": "right"
13687
+ "value": "right",
13688
+ "tier": "default"
12620
13689
  },
12621
13690
  {
12622
13691
  "value": "top"
12623
13692
  },
12624
13693
  {
12625
- "value": "bottom"
13694
+ "value": "bottom",
13695
+ "tier": "opt-in"
12626
13696
  }
12627
13697
  ]
12628
13698
  },
@@ -13117,13 +14187,16 @@ const MANIFEST_SNAPSHOT = {
13117
14187
  "name": "scale",
13118
14188
  "values": [
13119
14189
  {
13120
- "value": "linear"
14190
+ "value": "linear",
14191
+ "tier": "default"
13121
14192
  },
13122
14193
  {
13123
- "value": "log"
14194
+ "value": "log",
14195
+ "tier": "opt-in"
13124
14196
  },
13125
14197
  {
13126
- "value": "quantile"
14198
+ "value": "quantile",
14199
+ "tier": "opt-in"
13127
14200
  }
13128
14201
  ]
13129
14202
  },
@@ -13344,7 +14417,29 @@ const MANIFEST_SNAPSHOT = {
13344
14417
  "name": "text"
13345
14418
  },
13346
14419
  {
13347
- "name": "variant"
14420
+ "name": "variant",
14421
+ "values": [
14422
+ {
14423
+ "value": "default",
14424
+ "tier": "default"
14425
+ },
14426
+ {
14427
+ "value": "info",
14428
+ "tier": "opt-in"
14429
+ },
14430
+ {
14431
+ "value": "success",
14432
+ "tier": "opt-in"
14433
+ },
14434
+ {
14435
+ "value": "warning",
14436
+ "tier": "opt-in"
14437
+ },
14438
+ {
14439
+ "value": "danger",
14440
+ "tier": "opt-in"
14441
+ }
14442
+ ]
13348
14443
  }
13349
14444
  ]
13350
14445
  },
@@ -13390,7 +14485,33 @@ const MANIFEST_SNAPSHOT = {
13390
14485
  "name": "error"
13391
14486
  },
13392
14487
  {
13393
- "name": "inputmode"
14488
+ "name": "inputmode",
14489
+ "values": [
14490
+ {
14491
+ "value": "text"
14492
+ },
14493
+ {
14494
+ "value": "decimal"
14495
+ },
14496
+ {
14497
+ "value": "numeric"
14498
+ },
14499
+ {
14500
+ "value": "tel"
14501
+ },
14502
+ {
14503
+ "value": "search"
14504
+ },
14505
+ {
14506
+ "value": "email"
14507
+ },
14508
+ {
14509
+ "value": "url"
14510
+ },
14511
+ {
14512
+ "value": "none"
14513
+ }
14514
+ ]
13394
14515
  },
13395
14516
  {
13396
14517
  "name": "label"
@@ -13491,7 +14612,24 @@ const MANIFEST_SNAPSHOT = {
13491
14612
  "required": true
13492
14613
  },
13493
14614
  {
13494
- "name": "status"
14615
+ "name": "status",
14616
+ "values": [
14617
+ {
14618
+ "value": "available"
14619
+ },
14620
+ {
14621
+ "value": "connected"
14622
+ },
14623
+ {
14624
+ "value": "error"
14625
+ },
14626
+ {
14627
+ "value": "pending"
14628
+ },
14629
+ {
14630
+ "value": "coming-soon"
14631
+ }
14632
+ ]
13495
14633
  }
13496
14634
  ]
13497
14635
  },
@@ -13523,7 +14661,24 @@ const MANIFEST_SNAPSHOT = {
13523
14661
  "name": "searchPlaceholder"
13524
14662
  },
13525
14663
  {
13526
- "name": "statusFilter"
14664
+ "name": "statusFilter",
14665
+ "values": [
14666
+ {
14667
+ "value": "all"
14668
+ },
14669
+ {
14670
+ "value": "available"
14671
+ },
14672
+ {
14673
+ "value": "connected"
14674
+ },
14675
+ {
14676
+ "value": "error"
14677
+ },
14678
+ {
14679
+ "value": "coming-soon"
14680
+ }
14681
+ ]
13527
14682
  }
13528
14683
  ]
13529
14684
  },
@@ -13565,7 +14720,24 @@ const MANIFEST_SNAPSHOT = {
13565
14720
  "name": "printable"
13566
14721
  },
13567
14722
  {
13568
- "name": "status"
14723
+ "name": "status",
14724
+ "values": [
14725
+ {
14726
+ "value": "draft"
14727
+ },
14728
+ {
14729
+ "value": "open"
14730
+ },
14731
+ {
14732
+ "value": "paid"
14733
+ },
14734
+ {
14735
+ "value": "past-due"
14736
+ },
14737
+ {
14738
+ "value": "void"
14739
+ }
14740
+ ]
13569
14741
  }
13570
14742
  ]
13571
14743
  },
@@ -13597,7 +14769,27 @@ const MANIFEST_SNAPSHOT = {
13597
14769
  "name": "exportable"
13598
14770
  },
13599
14771
  {
13600
- "name": "filter"
14772
+ "name": "filter",
14773
+ "values": [
14774
+ {
14775
+ "value": ""
14776
+ },
14777
+ {
14778
+ "value": "draft"
14779
+ },
14780
+ {
14781
+ "value": "open"
14782
+ },
14783
+ {
14784
+ "value": "paid"
14785
+ },
14786
+ {
14787
+ "value": "past-due"
14788
+ },
14789
+ {
14790
+ "value": "void"
14791
+ }
14792
+ ]
13601
14793
  },
13602
14794
  {
13603
14795
  "name": "hrefPattern",
@@ -13810,7 +15002,21 @@ const MANIFEST_SNAPSHOT = {
13810
15002
  "name": "label"
13811
15003
  },
13812
15004
  {
13813
- "name": "variant"
15005
+ "name": "variant",
15006
+ "values": [
15007
+ {
15008
+ "value": "default",
15009
+ "tier": "default"
15010
+ },
15011
+ {
15012
+ "value": "transparent",
15013
+ "tier": "opt-in"
15014
+ },
15015
+ {
15016
+ "value": "blur",
15017
+ "tier": "opt-in"
15018
+ }
15019
+ ]
13814
15020
  }
13815
15021
  ]
13816
15022
  },
@@ -14439,6 +15645,10 @@ const MANIFEST_SNAPSHOT = {
14439
15645
  {
14440
15646
  "tag": "pagination-ui",
14441
15647
  "attrs": [
15648
+ {
15649
+ "name": "noLandmark",
15650
+ "attribute": "no-landmark"
15651
+ },
14442
15652
  {
14443
15653
  "name": "page"
14444
15654
  },
@@ -14644,7 +15854,15 @@ const MANIFEST_SNAPSHOT = {
14644
15854
  "name": "current"
14645
15855
  },
14646
15856
  {
14647
- "name": "cycle"
15857
+ "name": "cycle",
15858
+ "values": [
15859
+ {
15860
+ "value": "monthly"
15861
+ },
15862
+ {
15863
+ "value": "annual"
15864
+ }
15865
+ ]
14648
15866
  },
14649
15867
  {
14650
15868
  "name": "cycleToggle",
@@ -17313,18 +18531,23 @@ RULES.push({
17313
18531
  }
17314
18532
 
17315
18533
  {
17316
- // GENERATED do not hand-edit. Source: packages/web-components/**/*.a2ui.json + yaml,
18534
+ // GENERATED, do not hand-edit. Source: packages/web-components/**/*.a2ui.json + yaml,
17317
18535
  // packages/web-modules/**/*.a2ui.json + yaml (ADR-0108 D5 / LLD-0019 C5).
17318
18536
  // Rebuild: node scripts/build/gen-lab-posture-rules.mjs
17319
18537
  // Freshness gate: node scripts/verify/check-lab-posture-rules-fresh.mjs --verify
17320
18538
  //
17321
18539
  // REQUIRED-ATTR (ADR-0108 D5 / gh#3221): a manifest-declared `required: true` prop with no matching attribute set on the occurrence at all.
17322
18540
  //
17323
- // severity: 'warn' here governs ONLY `npm run lint`'s bare-repo-shaped
17324
- // advisory bank (ADR-0040 unchanged). The lab-posture write-time hook
18541
+ // severity: 'warn' here governs `npm run lint`'s bare-repo-shaped
18542
+ // advisory bank (ADR-0040 unchanged) AND the lab-posture write-time hook
17325
18543
  // (packages/plugins/adia-ui-factory/scripts/lab-posture-guard.mjs,
17326
- // LLD-0019 C4) does not read this field a lab-posture write denies on
17327
- // ANY finding from these same matcher functions regardless of severity
18544
+ // LLD-0019 C4 amendment, gh#3236) unlike every sibling rule in this
18545
+ // family, this one IS wired into the hook's write-time pass but never
18546
+ // denies: a finding surfaces as a non-blocking `hookSpecificOutput.
18547
+ // additionalContext` on a "allow" decision instead (conductor ruling,
18548
+ // gh#3221, 2026-09-04: "a false-positive rule never blocks authoring at
18549
+ // the keystroke"). The other four rules in this family stay severity-
18550
+ // blind at write time — ANY of their findings still denies unconditionally
17328
18551
  // (ADR-0108 D5: "PreToolUse deny... error under the lab hook").
17329
18552
 
17330
18553
 
@@ -17663,6 +18886,9 @@ const MANIFEST_SNAPSHOT = {
17663
18886
  {
17664
18887
  "name": "multi"
17665
18888
  },
18889
+ {
18890
+ "name": "options"
18891
+ },
17666
18892
  {
17667
18893
  "name": "question"
17668
18894
  },
@@ -17726,6 +18952,9 @@ const MANIFEST_SNAPSHOT = {
17726
18952
  }
17727
18953
  ]
17728
18954
  },
18955
+ {
18956
+ "name": "suggestions"
18957
+ },
17729
18958
  {
17730
18959
  "name": "variant",
17731
18960
  "values": [
@@ -18459,13 +19688,16 @@ const MANIFEST_SNAPSHOT = {
18459
19688
  "name": "precision",
18460
19689
  "values": [
18461
19690
  {
18462
- "value": "date"
19691
+ "value": "date",
19692
+ "tier": "default"
18463
19693
  },
18464
19694
  {
18465
- "value": "minute"
19695
+ "value": "minute",
19696
+ "tier": "opt-in"
18466
19697
  },
18467
19698
  {
18468
- "value": "second"
19699
+ "value": "second",
19700
+ "tier": "opt-in"
18469
19701
  }
18470
19702
  ]
18471
19703
  },
@@ -18989,6 +20221,10 @@ const MANIFEST_SNAPSHOT = {
18989
20221
  },
18990
20222
  {
18991
20223
  "name": "thinking"
20224
+ },
20225
+ {
20226
+ "name": "thinkingBudget",
20227
+ "attribute": "thinking-budget"
18992
20228
  }
18993
20229
  ]
18994
20230
  },
@@ -19681,7 +20917,30 @@ const MANIFEST_SNAPSHOT = {
19681
20917
  "name": "to"
19682
20918
  },
19683
20919
  {
19684
- "name": "value"
20920
+ "name": "value",
20921
+ "values": [
20922
+ {
20923
+ "value": "today"
20924
+ },
20925
+ {
20926
+ "value": "7d"
20927
+ },
20928
+ {
20929
+ "value": "30d"
20930
+ },
20931
+ {
20932
+ "value": "90d"
20933
+ },
20934
+ {
20935
+ "value": "qtd"
20936
+ },
20937
+ {
20938
+ "value": "ytd"
20939
+ },
20940
+ {
20941
+ "value": "custom"
20942
+ }
20943
+ ]
19685
20944
  }
19686
20945
  ]
19687
20946
  },
@@ -19814,16 +21073,19 @@ const MANIFEST_SNAPSHOT = {
19814
21073
  "name": "side",
19815
21074
  "values": [
19816
21075
  {
19817
- "value": "left"
21076
+ "value": "left",
21077
+ "tier": "opt-in"
19818
21078
  },
19819
21079
  {
19820
- "value": "right"
21080
+ "value": "right",
21081
+ "tier": "default"
19821
21082
  },
19822
21083
  {
19823
21084
  "value": "top"
19824
21085
  },
19825
21086
  {
19826
- "value": "bottom"
21087
+ "value": "bottom",
21088
+ "tier": "opt-in"
19827
21089
  }
19828
21090
  ]
19829
21091
  },
@@ -20318,13 +21580,16 @@ const MANIFEST_SNAPSHOT = {
20318
21580
  "name": "scale",
20319
21581
  "values": [
20320
21582
  {
20321
- "value": "linear"
21583
+ "value": "linear",
21584
+ "tier": "default"
20322
21585
  },
20323
21586
  {
20324
- "value": "log"
21587
+ "value": "log",
21588
+ "tier": "opt-in"
20325
21589
  },
20326
21590
  {
20327
- "value": "quantile"
21591
+ "value": "quantile",
21592
+ "tier": "opt-in"
20328
21593
  }
20329
21594
  ]
20330
21595
  },
@@ -20545,7 +21810,29 @@ const MANIFEST_SNAPSHOT = {
20545
21810
  "name": "text"
20546
21811
  },
20547
21812
  {
20548
- "name": "variant"
21813
+ "name": "variant",
21814
+ "values": [
21815
+ {
21816
+ "value": "default",
21817
+ "tier": "default"
21818
+ },
21819
+ {
21820
+ "value": "info",
21821
+ "tier": "opt-in"
21822
+ },
21823
+ {
21824
+ "value": "success",
21825
+ "tier": "opt-in"
21826
+ },
21827
+ {
21828
+ "value": "warning",
21829
+ "tier": "opt-in"
21830
+ },
21831
+ {
21832
+ "value": "danger",
21833
+ "tier": "opt-in"
21834
+ }
21835
+ ]
20549
21836
  }
20550
21837
  ]
20551
21838
  },
@@ -20591,7 +21878,33 @@ const MANIFEST_SNAPSHOT = {
20591
21878
  "name": "error"
20592
21879
  },
20593
21880
  {
20594
- "name": "inputmode"
21881
+ "name": "inputmode",
21882
+ "values": [
21883
+ {
21884
+ "value": "text"
21885
+ },
21886
+ {
21887
+ "value": "decimal"
21888
+ },
21889
+ {
21890
+ "value": "numeric"
21891
+ },
21892
+ {
21893
+ "value": "tel"
21894
+ },
21895
+ {
21896
+ "value": "search"
21897
+ },
21898
+ {
21899
+ "value": "email"
21900
+ },
21901
+ {
21902
+ "value": "url"
21903
+ },
21904
+ {
21905
+ "value": "none"
21906
+ }
21907
+ ]
20595
21908
  },
20596
21909
  {
20597
21910
  "name": "label"
@@ -20692,7 +22005,24 @@ const MANIFEST_SNAPSHOT = {
20692
22005
  "required": true
20693
22006
  },
20694
22007
  {
20695
- "name": "status"
22008
+ "name": "status",
22009
+ "values": [
22010
+ {
22011
+ "value": "available"
22012
+ },
22013
+ {
22014
+ "value": "connected"
22015
+ },
22016
+ {
22017
+ "value": "error"
22018
+ },
22019
+ {
22020
+ "value": "pending"
22021
+ },
22022
+ {
22023
+ "value": "coming-soon"
22024
+ }
22025
+ ]
20696
22026
  }
20697
22027
  ]
20698
22028
  },
@@ -20724,7 +22054,24 @@ const MANIFEST_SNAPSHOT = {
20724
22054
  "name": "searchPlaceholder"
20725
22055
  },
20726
22056
  {
20727
- "name": "statusFilter"
22057
+ "name": "statusFilter",
22058
+ "values": [
22059
+ {
22060
+ "value": "all"
22061
+ },
22062
+ {
22063
+ "value": "available"
22064
+ },
22065
+ {
22066
+ "value": "connected"
22067
+ },
22068
+ {
22069
+ "value": "error"
22070
+ },
22071
+ {
22072
+ "value": "coming-soon"
22073
+ }
22074
+ ]
20728
22075
  }
20729
22076
  ]
20730
22077
  },
@@ -20766,7 +22113,24 @@ const MANIFEST_SNAPSHOT = {
20766
22113
  "name": "printable"
20767
22114
  },
20768
22115
  {
20769
- "name": "status"
22116
+ "name": "status",
22117
+ "values": [
22118
+ {
22119
+ "value": "draft"
22120
+ },
22121
+ {
22122
+ "value": "open"
22123
+ },
22124
+ {
22125
+ "value": "paid"
22126
+ },
22127
+ {
22128
+ "value": "past-due"
22129
+ },
22130
+ {
22131
+ "value": "void"
22132
+ }
22133
+ ]
20770
22134
  }
20771
22135
  ]
20772
22136
  },
@@ -20798,7 +22162,27 @@ const MANIFEST_SNAPSHOT = {
20798
22162
  "name": "exportable"
20799
22163
  },
20800
22164
  {
20801
- "name": "filter"
22165
+ "name": "filter",
22166
+ "values": [
22167
+ {
22168
+ "value": ""
22169
+ },
22170
+ {
22171
+ "value": "draft"
22172
+ },
22173
+ {
22174
+ "value": "open"
22175
+ },
22176
+ {
22177
+ "value": "paid"
22178
+ },
22179
+ {
22180
+ "value": "past-due"
22181
+ },
22182
+ {
22183
+ "value": "void"
22184
+ }
22185
+ ]
20802
22186
  },
20803
22187
  {
20804
22188
  "name": "hrefPattern",
@@ -21011,7 +22395,21 @@ const MANIFEST_SNAPSHOT = {
21011
22395
  "name": "label"
21012
22396
  },
21013
22397
  {
21014
- "name": "variant"
22398
+ "name": "variant",
22399
+ "values": [
22400
+ {
22401
+ "value": "default",
22402
+ "tier": "default"
22403
+ },
22404
+ {
22405
+ "value": "transparent",
22406
+ "tier": "opt-in"
22407
+ },
22408
+ {
22409
+ "value": "blur",
22410
+ "tier": "opt-in"
22411
+ }
22412
+ ]
21015
22413
  }
21016
22414
  ]
21017
22415
  },
@@ -21640,6 +23038,10 @@ const MANIFEST_SNAPSHOT = {
21640
23038
  {
21641
23039
  "tag": "pagination-ui",
21642
23040
  "attrs": [
23041
+ {
23042
+ "name": "noLandmark",
23043
+ "attribute": "no-landmark"
23044
+ },
21643
23045
  {
21644
23046
  "name": "page"
21645
23047
  },
@@ -21845,7 +23247,15 @@ const MANIFEST_SNAPSHOT = {
21845
23247
  "name": "current"
21846
23248
  },
21847
23249
  {
21848
- "name": "cycle"
23250
+ "name": "cycle",
23251
+ "values": [
23252
+ {
23253
+ "value": "monthly"
23254
+ },
23255
+ {
23256
+ "value": "annual"
23257
+ }
23258
+ ]
21849
23259
  },
21850
23260
  {
21851
23261
  "name": "cycleToggle",
@@ -24513,7 +25923,7 @@ RULES.push({
24513
25923
  }
24514
25924
 
24515
25925
  {
24516
- // GENERATED do not hand-edit. Source: packages/web-components/**/*.a2ui.json + yaml,
25926
+ // GENERATED, do not hand-edit. Source: packages/web-components/**/*.a2ui.json + yaml,
24517
25927
  // packages/web-modules/**/*.a2ui.json + yaml (ADR-0108 D5 / LLD-0019 C5).
24518
25928
  // Rebuild: node scripts/build/gen-lab-posture-rules.mjs
24519
25929
  // Freshness gate: node scripts/verify/check-lab-posture-rules-fresh.mjs --verify
@@ -24788,6 +26198,9 @@ const MANIFEST_SNAPSHOT = {
24788
26198
  {
24789
26199
  "name": "multi"
24790
26200
  },
26201
+ {
26202
+ "name": "options"
26203
+ },
24791
26204
  {
24792
26205
  "name": "question"
24793
26206
  },
@@ -24827,6 +26240,9 @@ const MANIFEST_SNAPSHOT = {
24827
26240
  {
24828
26241
  "name": "size"
24829
26242
  },
26243
+ {
26244
+ "name": "suggestions"
26245
+ },
24830
26246
  {
24831
26247
  "name": "variant"
24832
26248
  }
@@ -25380,6 +26796,10 @@ const MANIFEST_SNAPSHOT = {
25380
26796
  },
25381
26797
  {
25382
26798
  "name": "thinking"
26799
+ },
26800
+ {
26801
+ "name": "thinkingBudget",
26802
+ "attribute": "thinking-budget"
25383
26803
  }
25384
26804
  ]
25385
26805
  },
@@ -27129,6 +28549,10 @@ const MANIFEST_SNAPSHOT = {
27129
28549
  {
27130
28550
  "tag": "pagination-ui",
27131
28551
  "attrs": [
28552
+ {
28553
+ "name": "noLandmark",
28554
+ "attribute": "no-landmark"
28555
+ },
27132
28556
  {
27133
28557
  "name": "page"
27134
28558
  },
@@ -28963,7 +30387,131 @@ RULES.push({
28963
30387
  }
28964
30388
 
28965
30389
  {
28966
- // GENERATED do not hand-edit. Source: packages/web-components/**/*.a2ui.json + yaml,
30390
+ // GENERATED, do not hand-edit. Source: packages/web-components/**/*.a2ui.json + yaml,
30391
+ // packages/web-modules/**/*.a2ui.json + yaml (ADR-0108 D5 / LLD-0019 C5).
30392
+ // Rebuild: node scripts/build/gen-lab-posture-rules.mjs
30393
+ // Freshness gate: node scripts/verify/check-lab-posture-rules-fresh.mjs --verify
30394
+ //
30395
+ // UNKNOWN-SLOT (gh#3222): a `slot="…"` value that is not a slot name any component in the installed manifest declares. Name only, never placement: see trimForEmbed's own `slot-names` branch for why there is no per-tag/nearest-ancestor check.
30396
+ //
30397
+ // severity: 'error' here governs ONLY `npm run lint`'s bare-repo-shaped
30398
+ // advisory bank (ADR-0040 unchanged). The lab-posture write-time hook
30399
+ // (packages/plugins/adia-ui-factory/scripts/lab-posture-guard.mjs,
30400
+ // LLD-0019 C4) does not read this field — a lab-posture write denies on
30401
+ // ANY finding from these same matcher functions regardless of severity
30402
+ // (ADR-0108 D5: "PreToolUse deny... error under the lab hook").
30403
+
30404
+
30405
+ const MANIFEST_SNAPSHOT = {
30406
+ "slotNames": [
30407
+ "action",
30408
+ "action-leading",
30409
+ "actions",
30410
+ "actions-leading",
30411
+ "add",
30412
+ "after",
30413
+ "after-invoice-history",
30414
+ "aside",
30415
+ "attach",
30416
+ "badge",
30417
+ "bar",
30418
+ "before",
30419
+ "before-plan-picker",
30420
+ "body",
30421
+ "breadcrumb",
30422
+ "canvas",
30423
+ "caption",
30424
+ "caret",
30425
+ "change",
30426
+ "chart",
30427
+ "charts",
30428
+ "chip",
30429
+ "chrome",
30430
+ "cite",
30431
+ "close",
30432
+ "complete",
30433
+ "content",
30434
+ "copy",
30435
+ "cursor",
30436
+ "customer-block",
30437
+ "default",
30438
+ "description",
30439
+ "digit",
30440
+ "empty",
30441
+ "error",
30442
+ "eyebrow",
30443
+ "footer",
30444
+ "header",
30445
+ "header-actions",
30446
+ "heading",
30447
+ "hint",
30448
+ "icon",
30449
+ "icon-trailing",
30450
+ "image",
30451
+ "kpis",
30452
+ "label",
30453
+ "leading",
30454
+ "lede",
30455
+ "legal",
30456
+ "loading",
30457
+ "media",
30458
+ "meta",
30459
+ "model",
30460
+ "name",
30461
+ "off",
30462
+ "on",
30463
+ "panel",
30464
+ "popover",
30465
+ "prefix",
30466
+ "presets",
30467
+ "primary",
30468
+ "remit-to-block",
30469
+ "scope",
30470
+ "secondary",
30471
+ "send",
30472
+ "skeleton",
30473
+ "status",
30474
+ "subtitle",
30475
+ "suffix",
30476
+ "summary",
30477
+ "table",
30478
+ "text",
30479
+ "time",
30480
+ "title",
30481
+ "toolbar",
30482
+ "track",
30483
+ "trailing",
30484
+ "trigger",
30485
+ "value",
30486
+ "zoom"
30487
+ ]
30488
+ };
30489
+
30490
+
30491
+ RULES.push({
30492
+ id: "UNKNOWN-SLOT",
30493
+ severity: "error",
30494
+ scope: 'shared',
30495
+ fileTypes: MARKUP_EXT,
30496
+ match(text, path = '') {
30497
+ return slotNameFindings(text, MANIFEST_SNAPSHOT, path).map((f) => ({ line: f.line, snippet: f.snippet, why: f.why }));
30498
+ },
30499
+ fix: null, // a manifest-drift violation names the correction in its own diagnostic; applying it is a judgment call the agent makes, not a mechanical rewrite
30500
+ fixtures: {
30501
+ "smelly": [
30502
+ "<span slot=\"not-a-real-slot-name\"></span>"
30503
+ ],
30504
+ "clean": [
30505
+ "<span slot=\"action\"></span>",
30506
+ "<span slot=\"${s.section}\"></span>",
30507
+ "<span slot=\"{s.section}\"></span>"
30508
+ ]
30509
+ },
30510
+ });
30511
+ }
30512
+
30513
+ {
30514
+ // GENERATED, do not hand-edit. Source: packages/web-components/**/*.a2ui.json + yaml,
28967
30515
  // packages/web-modules/**/*.a2ui.json + yaml (ADR-0108 D5 / LLD-0019 C5).
28968
30516
  // Rebuild: node scripts/build/gen-lab-posture-rules.mjs
28969
30517
  // Freshness gate: node scripts/verify/check-lab-posture-rules-fresh.mjs --verify
@@ -30580,6 +32128,99 @@ RULES.push({
30580
32128
  {
30581
32129
 
30582
32130
 
32131
+ // gh#3627 (follow-up to gh#3604): select-ui's avatar `<img>` shipped with no
32132
+ // width/height HTML attributes, sizing purely dependent on select.css's own
32133
+ // rule loading before first paint. select.css already carried explicit
32134
+ // width/height on that selector (packages/web-components/components/select/
32135
+ // select.css's `img[data-option-avatar]` rule), nothing was wrong with the
32136
+ // CSS. The gap was the OTHER half of the contract: an `<img>` stamped by a
32137
+ // component's own render logic needs its own width/height (or an inline
32138
+ // aspect-ratio) so the box is reserved from HTML parse time, independent of
32139
+ // when that component's stylesheet actually applies (a per-route CSS bundle
32140
+ // can arrive after first paint, gh#3357). gh#3604's fix added exactly that
32141
+ // to the three template-literal `<img>` sites in select.class.js; this rule
32142
+ // keeps a fourth one from shipping the same way.
32143
+ //
32144
+ // Scope, deliberately narrow: ONLY a literal `<img ...>` tag authored
32145
+ // inside a JS template-literal/string in packages/web-components or
32146
+ // packages/web-modules, the shape that actually regressed. Three things
32147
+ // this rule does NOT catch, on purpose:
32148
+ // 1. `document.createElement('img')` call sites (avatar.class.js,
32149
+ // image.class.js, integration-card.class.js), each of those adopts
32150
+ // the img into a host element that already carries its own explicit
32151
+ // size (avatar-ui's :host sizing tokens, image-ui's own #applySize(),
32152
+ // a fixed-size logo slot), so the box is reserved by the PARENT
32153
+ // regardless of the img's own attributes. Flagging every
32154
+ // createElement('img') would nag on a legitimate, already-reserved
32155
+ // pattern this framework uses on purpose, exactly the "sized by a
32156
+ // parent's grid cell" false positive this rule is written to avoid.
32157
+ // 2. Demo/example/gallery markup (`.html`, `.yaml` examples, `.a2ui.json`),
32158
+ // illustrative content already exempt from render-timing concerns
32159
+ // (HARDCODED-OPEN's `.examples.html` precedent is the same reasoning).
32160
+ // 3. `apps/`, `playgrounds/`, `catalog/`, consumer/demo surfaces, not
32161
+ // framework source. NO-LOCAL-ESCAPE-HTML (gh#3641/gh#3678) is the
32162
+ // precedent for widening a framework-scoped rule to a consumer tree
32163
+ // only once a ticket finds and migrates a real instance there; no such
32164
+ // instance exists for this rule yet.
32165
+ // An author who has a real reason an img here doesn't need its own box
32166
+ // (e.g. deliberately sized by an ancestor CSS grid/flex cell) can still
32167
+ // suppress a specific finding with the standard engine-wide
32168
+ // adia-lint-disable comment (SUPPRESS_RE/suppressionFor, primitives.mjs).
32169
+ //
32170
+ // Known imprecision (documented, not fixed here): like every other
32171
+ // CODE_EXT rule in this bank, comment-stripping is line-based and doesn't
32172
+ // understand string literals, so a hardcoded `src="https://..."` URL on
32173
+ // the SAME source line as `width=`/`height=` would truncate the line at
32174
+ // `//` and could false-positive. Every real instance in this corpus today
32175
+ // interpolates `src` from a variable (`src="${escapeHTML(x)}"`), not a
32176
+ // literal URL, so this hasn't triggered in practice; a literal `//` URL
32177
+ // sharing a line with the dimension attributes is the one shape to watch
32178
+ // for in review.
32179
+ const IMG_TAG_RE = /<img\b[^>]*?>/gis;
32180
+ const HAS_WIDTH = /\bwidth\s*=/i;
32181
+ const HAS_HEIGHT = /\bheight\s*=/i;
32182
+ const HAS_ASPECT_RATIO = /aspect-ratio\s*:/i;
32183
+ const CORPUS_PATH_RE = /packages[\\/](web-components|web-modules)[\\/]/;
32184
+
32185
+
32186
+ RULES.push({
32187
+ id: 'IMG-DIMENSION-RESERVE',
32188
+ severity: 'error',
32189
+ scope: 'shared',
32190
+ fileTypes: CODE_EXT,
32191
+ match(text, path) {
32192
+ const out = [];
32193
+ const normalized = (path || '').replace(/\\/g, '/');
32194
+ if (!CORPUS_PATH_RE.test(normalized)) return out;
32195
+ if (normalized.endsWith('.test.js')) return out;
32196
+
32197
+ const rawLines = text.split('\n');
32198
+ const blanked = stripCommentLines(text, ext(path))
32199
+ .map((l) => l.stripped)
32200
+ .join('\n');
32201
+
32202
+ IMG_TAG_RE.lastIndex = 0;
32203
+ let m;
32204
+ while ((m = IMG_TAG_RE.exec(blanked))) {
32205
+ const tag = m[0];
32206
+ if ((HAS_WIDTH.test(tag) && HAS_HEIGHT.test(tag)) || HAS_ASPECT_RATIO.test(tag)) continue;
32207
+ const lineNo = lineOf(blanked, m.index);
32208
+ out.push({
32209
+ line: lineNo,
32210
+ snippet: (rawLines[lineNo - 1] || tag).trim().slice(0, 90),
32211
+ why: 'an <img> stamped by component render logic needs its own width/height (or an inline aspect-ratio) so the box is reserved before CSS applies (gh#3604 CLS)',
32212
+ });
32213
+ }
32214
+ return out;
32215
+ },
32216
+ });
32217
+ }
32218
+
32219
+ {
32220
+
32221
+
32222
+ const SHELLS = new Set(['admin-shell', 'chat-shell', 'editor-shell', 'app-shell-ui', 'adia-chat-ui', 'adia-editor-ui']);
32223
+
30583
32224
 
30584
32225
  RULES.push({
30585
32226
  id: 'LEGACY-SHELL',
@@ -30587,18 +32228,50 @@ RULES.push({
30587
32228
  scope: 'shared',
30588
32229
  fileTypes: [],
30589
32230
  match(text, path) {
30590
- const out = [];
30591
- for (const { lineNo, raw, stripped } of stripCommentLines(text, ext(path))) {
30592
- if (!stripped.trim()) continue;
30593
- if (RE.LEGACY_SHELL.test(stripped)) {
30594
- out.push({
30595
- line: lineNo,
30596
- snippet: raw.trim().slice(0, 90),
30597
- why: 'retired shell shape (ADR-0024, v0.4.0) use the bespoke tag (chat-thread / chat-composer / chat-empty · admin-sidebar / admin-command · editor-canvas · pane-ui)',
30598
- });
32231
+ // Component yaml contains contract prose and A2UI JSON, not live HTML.
32232
+ // Match syntax in source rather than retirement examples or name prefixes.
32233
+ const fileExt = ext(path);
32234
+ if (YAML_EXT.includes(fileExt)) return [];
32235
+ const lines = stripCommentLines(text, fileExt);
32236
+ const source = markupScanSurface(lines.map(({ stripped }) => stripped).join('\n'));
32237
+ const found = new Set();
32238
+ for (const { attrs, tag, line } of tagOccurrences(source, path)) {
32239
+ if (Object.keys(attrs).some((name) => RE.LEGACY_SHELL.test(name)) ||
32240
+ (tag === 'dialog' && Object.hasOwn(attrs, 'data-command'))) found.add(line);
32241
+ }
32242
+ // aside-ui remains a supported in-page slot stub. Only its use as a
32243
+ // shell region is retired; native wrappers preserve that shell context.
32244
+ for (const { tag, parentTag, line } of tagTree(source, path)) {
32245
+ if (tag === 'aside-ui' && SHELLS.has(parentTag)) found.add(line);
32246
+ }
32247
+ const referenceSurfaces = [];
32248
+ if (CODE_EXT.includes(fileExt) || STYLE_EXT.includes(fileExt)) {
32249
+ referenceSurfaces.push({ text: source, line: 1 });
32250
+ } else {
32251
+ // Inline executable blocks need the same coverage as separate files.
32252
+ // Scan their bodies only, so selectors quoted in page prose stay clean.
32253
+ for (const block of source.matchAll(/<(script|style)\b[^>]*>([\s\S]*?)<\/\1\s*>/gi)) {
32254
+ const start = block.index + block[0].indexOf('>') + 1;
32255
+ const body = stripCommentLines(block[2], block[1].toLowerCase() === 'script' ? '.js' : '.css')
32256
+ .map(({ stripped }) => stripped).join('\n');
32257
+ referenceSurfaces.push({ text: body, line: lineOf(source, start) });
30599
32258
  }
30600
32259
  }
30601
- return out;
32260
+ // Keep selector reads and DOM attribute writes covered as well as
32261
+ // markup. Exact attribute names preserve unrelated namespaced hooks.
32262
+ const references = /\[\s*([\w-]+)(?=[\s\]=~|^$*])|\b(?:setAttribute|getAttribute|hasAttribute|removeAttribute|toggleAttribute)\s*\(\s*['"]([\w-]+)['"]/g;
32263
+ for (const surface of referenceSurfaces) {
32264
+ for (const match of surface.text.matchAll(references)) {
32265
+ if (RE.LEGACY_SHELL.test(match[1] || match[2])) {
32266
+ found.add(surface.line + lineOf(surface.text, match.index) - 1);
32267
+ }
32268
+ }
32269
+ }
32270
+ return [...found].sort((a, b) => a - b).map((line) => ({
32271
+ line,
32272
+ snippet: lines[line - 1].raw.trim().slice(0, 90),
32273
+ why: 'retired shell shape (ADR-0024, v0.4.0): use the bespoke tag (chat-thread / chat-composer / chat-empty · admin-sidebar / admin-command · editor-canvas · pane-ui)',
32274
+ }));
30602
32275
  },
30603
32276
  });
30604
32277
  }
@@ -30682,6 +32355,66 @@ RULES.push({
30682
32355
  {
30683
32356
 
30684
32357
 
32358
+ // gh#3641: escapeHTML was independently defined seven times across the
32359
+ // framework corpus (six components plus chat-shell, one of the seven
32360
+ // spelled `escapeHtml`, case varies, tour.class.js, three of the seven
32361
+ // leaving quotes unescaped (an attribute-breakout XSS vector). The
32362
+ // shared, quote-safe implementation now lives at
32363
+ // packages/web-components/core/html-escape.js; this rule refuses a new
32364
+ // local `function escapeHtml(`/`escapeHTML(` (any casing) inside the
32365
+ // framework corpus (packages/web-components, packages/web-modules) so
32366
+ // the fix cannot re-fragment the way it already did once (twice: the
32367
+ // original 5-variant fragmentation, then a 7th instance under a
32368
+ // different casing that a case-sensitive first version of this very
32369
+ // rule could not see). Case-insensitive on purpose: the defect class is
32370
+ // "a local escapeHTML-shaped helper", not one exact spelling.
32371
+ // gh#3678: five more local copies turned up in apps/ (construct-canvas,
32372
+ // genui), two of them quote-unsafe, the same attribute-breakout defect
32373
+ // class this rule was written for. This scope note previously said
32374
+ // consumer app code was exempt because it "owns its own copy of a value
32375
+ // this small", that call was reversed by conductor ruling (gh#3678
32376
+ // resolution 2: migrate, not wontfix), so CORPUS_PATH_RE now also
32377
+ // matches apps/. playgrounds/ and catalog/ remain out of scope until a
32378
+ // ticket similarly finds and migrates a local copy there.
32379
+ // `declare function` is a .d.ts ambient signature, not a re-implementation:
32380
+ // html-escape.d.ts's own `export declare function escapeHTML(...)` must
32381
+ // not flag itself. Only a real function body is the defect this rule
32382
+ // exists for. The lookbehind requires `\s+` (one or more), not `\s`
32383
+ // (exactly one), so `declare function` (extra space) or a line break
32384
+ // between the two keywords still exempts the ambient signature.
32385
+ const LOCAL_DEF_RE = /(?<!declare\s+)\bfunction\s+escapeHtml\s*\(/i;
32386
+ const OWNER_PATH_RE = /packages[\\/]web-components[\\/]core[\\/]html-escape\.(js|d\.ts)$/;
32387
+ const CORPUS_PATH_RE = /(?:packages[\\/](web-components|web-modules)|(?:^|[\\/])apps)[\\/]/;
32388
+
32389
+
32390
+ RULES.push({
32391
+ id: 'NO-LOCAL-ESCAPE-HTML',
32392
+ severity: 'error',
32393
+ scope: 'shared',
32394
+ fileTypes: CODE_EXT,
32395
+ match(text, path) {
32396
+ const out = [];
32397
+ const normalized = path.replace(/\\/g, '/');
32398
+ if (!CORPUS_PATH_RE.test(normalized)) return out;
32399
+ if (OWNER_PATH_RE.test(normalized)) return out;
32400
+ for (const { lineNo, raw, stripped } of stripCommentLines(text, ext(path))) {
32401
+ if (!stripped.trim()) continue;
32402
+ if (LOCAL_DEF_RE.test(stripped)) {
32403
+ out.push({
32404
+ line: lineNo,
32405
+ snippet: raw.trim().slice(0, 90),
32406
+ why: 'do not redefine escapeHTML locally, import { escapeHTML } from the core barrel (packages/web-components/core/html-escape.js), gh#3641',
32407
+ });
32408
+ }
32409
+ }
32410
+ return out;
32411
+ },
32412
+ });
32413
+ }
32414
+
32415
+ {
32416
+
32417
+
30685
32418
  // Parity with the two retired scripts: forge-lint recognized only
30686
32419
  // `forge-lint: foundation`, adia-lint only `adia-lint: foundation` — never
30687
32420
  // either tag under the other script. Since this rule is shared, the active