@starci/hfs 4.7.33 → 4.7.35

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (48) hide show
  1. package/CHANGELOG.md +8 -1
  2. package/README.md +8 -11
  3. package/lint/run.mjs +70 -29
  4. package/package.json +2 -2
  5. package/runtime/knowledge/grammars/index.yaml +102 -0
  6. package/runtime/knowledge/grammars/offset-pop/playbook.yaml +302 -0
  7. package/runtime/knowledge/grammars/starci/playbook.yaml +1159 -0
  8. package/runtime/knowledge/hfs/canon-pins.yaml +22 -8
  9. package/runtime/knowledge/hfs/fe-stack.yaml +7 -0
  10. package/runtime/knowledge/hfs/rules.yaml +133 -83
  11. package/runtime/knowledge/hfs/slots.yaml +3 -3
  12. package/runtime/knowledge/ui/presentation/font.yaml +101 -0
  13. package/runtime/knowledge/ui/presentation/padding.yaml +216 -0
  14. package/runtime/modules/kernel/failure-codes.yaml +40 -20
  15. package/runtime/modules/kernel/removed-vocabulary.yaml +29 -0
  16. package/runtime/packages/cli/src/catalog.generated.mjs +7 -7
  17. package/runtime/scripts/gates/canon-pins.mjs +103 -0
  18. package/runtime/scripts/gates/gate.mjs +3 -36
  19. package/runtime/scripts/gates/output.mjs +40 -0
  20. package/runtime/scripts/gates/test-world-run.mjs +2 -4
  21. package/runtime/scripts/hfs/architecture/config.mjs +8 -8
  22. package/runtime/scripts/hfs/check.mjs +1 -1
  23. package/runtime/scripts/hfs/db-restamp-verb.mjs +2 -2
  24. package/runtime/scripts/hfs/declaration-shape.mjs +8 -2
  25. package/runtime/scripts/hfs/grammar-presentation.mjs +152 -0
  26. package/runtime/scripts/hfs/rule-catalog.mjs +2 -2
  27. package/runtime/scripts/hfs/rules/a15-findings.mjs +1 -0
  28. package/runtime/scripts/hfs/rules/fe-stack.mjs +44 -1
  29. package/runtime/scripts/hfs/slots.mjs +1 -0
  30. package/runtime/scripts/hfs/view.mjs +1 -0
  31. package/runtime/scripts/lib/canon-binding-text.mjs +129 -0
  32. package/runtime/scripts/lib/example-refs.mjs +1 -1
  33. package/runtime/scripts/lib/grammar-lint.mjs +48 -0
  34. package/runtime/scripts/lib/grammar-vendor-parity.mjs +31 -111
  35. package/runtime/scripts/lib/grammar-vendor-source.mjs +345 -0
  36. package/runtime/scripts/lib/numeric-match.mjs +5 -0
  37. package/runtime/scripts/lib/source-package-imports.mjs +111 -0
  38. package/runtime/scripts/work/draw/draw-layer.mjs +5 -4
  39. package/scaffold/app.mjs +7 -5
  40. package/src/main.mjs +26 -13
  41. package/stack/config.mjs +2 -1
  42. package/stack/render.mjs +24 -3
  43. package/sync/index.mjs +8 -2
  44. package/templates/app/skeleton/.starcistacks/dev/infra/compose/stack.yaml +0 -1
  45. package/templates/app/skeleton/.starcistacks/production/infra/swarm/stack.yaml +0 -1
  46. package/templates/app/skeleton-lite/.starcistacks/dev/infra/swarm/stack.yaml +0 -1
  47. package/templates/app/skeleton-lite/.starcistacks/production/infra/swarm/stack.yaml +0 -1
  48. package/templates/fe/tool-config/eslint.config.mjs +4 -1
@@ -0,0 +1,101 @@
1
+ schema: starci/knowledge-source@1
2
+ id: ui.presentation.font
3
+ title: Font presentation
4
+ appliesTo:
5
+ - ui
6
+ family: presentation
7
+ purpose: Choose information rank and document semantics before typography. A heading establishes structure;
8
+ ordinary copy does not. The selected Grammar owns the concrete type scale, renderers, props, weights, line
9
+ heights and tracking under FE-RULE-OWNERSHIP. Applications compose that public contract and write
10
+ layout-only CSS.
11
+ ownerVocabulary:
12
+ owners:
13
+ - name: The selected text renderer
14
+ meaning: Ordinary copy has no heading semantics
15
+ applicationWrites: The published semantic rank through the selected Grammar API
16
+ - name: The selected heading renderer
17
+ meaning: A heading declares its actual document position
18
+ applicationWrites: Its semantic level and any published emphasis treatment
19
+ notes: Information rank belongs to the application; its visual realization belongs to the selected Grammar. A
20
+ missing typography capability is a Grammar gap, never permission to override a component with application
21
+ typography CSS.
22
+ guidance:
23
+ - id: weight
24
+ title: Weight
25
+ requirement: Weight refines an already chosen information rank. It does not create a hierarchy level or
26
+ substitute for a heading. Use only the selected Grammar's published weight treatment; its concrete
27
+ weights, defaults and renderer props belong to that family. Document structure remains meaningful when
28
+ weight or colour is removed.
29
+ rules:
30
+ - id: FONT-1
31
+ title: Lowest supporting rank
32
+ governs: Supporting metadata remains subordinate while staying readable. The selected Grammar chooses its
33
+ exact size and treatment.
34
+ cases:
35
+ - id: case-1
36
+ when: Brief metadata remains understandable at the lowest supporting rank
37
+ owner: The selected text renderer
38
+ render: Compose its published supporting-copy treatment.
39
+ - id: case-2
40
+ when: A nested region has a label within an already titled section
41
+ owner: The selected heading renderer
42
+ render: Declare the nested region's actual document position; use the selected Grammar's corresponding recipe.
43
+ notThisRule: Ordinary sentences and important facts must not be demoted to the lowest supporting rank.
44
+ - id: FONT-2
45
+ title: Supporting reading rank
46
+ governs: A complete supporting line remains readable and visibly below ordinary reading copy.
47
+ cases:
48
+ - id: case-1
49
+ when: A complete supporting line such as a timestamp or short fact sits below normal body copy
50
+ owner: The selected text renderer
51
+ render: Compose the published supporting reading rank without reducing readability.
52
+ - id: case-2
53
+ when: A subordinate region is nested within a section
54
+ owner: The selected heading renderer
55
+ render: Keep its document nesting and published heading treatment aligned.
56
+ notThisRule: Do not shrink body copy to fit an undersized container; repair its layout.
57
+ - id: FONT-3
58
+ title: Ordinary reading rank
59
+ governs: Explanatory copy has the normal reading priority of its region. Its visual recipe comes from the
60
+ selected Grammar.
61
+ cases:
62
+ - id: case-1
63
+ when: Ordinary explanatory copy has normal reading priority
64
+ owner: The selected text renderer
65
+ render: Use the normal reading treatment supplied by the selected Grammar.
66
+ - id: case-2
67
+ when: A section has its own heading inside a page
68
+ owner: The selected heading renderer
69
+ render: Declare the section's structural position independently of its size.
70
+ - id: FONT-4
71
+ title: Page-heading rank
72
+ governs: The heading that names a page carries the primary structural rank of that document.
73
+ cases:
74
+ - id: case-1
75
+ when: The single heading names the whole page or route
76
+ owner: The selected heading renderer
77
+ render: Use the page-heading role and its published family treatment.
78
+ notThisRule: One document has one top-level page heading. A second page-heading role is a structural conflict.
79
+ - id: FONT-5
80
+ title: Leading-value emphasis
81
+ governs: The principal numeric value or short fact of a region may carry emphasis without acquiring heading
82
+ semantics.
83
+ cases:
84
+ - id: case-1
85
+ when: A leading metric or short value is the main fact of its region
86
+ owner: The selected text renderer
87
+ render: Use the family's published value-emphasis treatment while retaining text semantics.
88
+ notThisRule: Value emphasis is not decoration, sentence styling or an imitation of a heading.
89
+ - id: FONT-6
90
+ title: Display emphasis preserves structure
91
+ governs: A page introduction may use the selected Grammar's display treatment while preserving the heading's
92
+ actual semantic position.
93
+ cases:
94
+ - id: case-1
95
+ when: A page introduction needs marketing or landing emphasis
96
+ owner: The selected heading renderer
97
+ render: Apply the published display treatment while keeping the document outline unchanged.
98
+ notThisRule: A nested heading never gains a different outline position merely to obtain visual emphasis.
99
+ doesNotDecide: |-
100
+ Which colour expresses the rank is [Tone](tone.yaml). How the line wraps, aligns, or truncates is
101
+ [Text flow](text-flow.yaml). How much room the text region gets is [Measure](measure.yaml).
@@ -0,0 +1,216 @@
1
+ schema: starci/knowledge-source@1
2
+ id: ui.presentation.padding
3
+ title: Padding presentation
4
+ appliesTo:
5
+ - ui
6
+ family: presentation
7
+ purpose: Resolve one owned content edge per boundary. Applications write layout insets only for boundaries
8
+ they own; a selected Grammar owns its components' internal insets and the values of its published scale.
9
+ FE-RULE-OWNERSHIP keeps these universal requirements separate from family recipes.
10
+ ownerVocabulary:
11
+ owners:
12
+ - name: Application layout
13
+ meaning: The application owns this layout boundary
14
+ applicationWrites: Its one layout inset from the selected Grammar scale
15
+ - name: Selected Grammar component
16
+ meaning: The published component owns this boundary
17
+ applicationWrites: Compose its published API
18
+ notes: Every boundary has one inset owner. Reimplementing an owned component inset or overriding its internal
19
+ geometry violates that ownership. A missing component capability is repaired in the Grammar.
20
+ guidance:
21
+ - id: side-contact
22
+ title: Side contact
23
+ requirement: Resolve each side from the boundary it meets. An outer edge takes the published content
24
+ clearance; a separator-facing side takes the published separator clearance; a side already owned by a
25
+ child adds no inset. Inline sides of peer bands align. The selected Grammar owns the exact values and
26
+ flush-band API.
27
+ - id: composite-insets
28
+ title: Composite insets
29
+ requirement: An asymmetric inset recipe composes published scale values. Each side has an explicit boundary
30
+ reason; the recipe introduces no new value. Preserve an existing recipe identity when its purpose is
31
+ unchanged, and declare a new recipe only for a distinct boundary relationship.
32
+ - id: axis-variants
33
+ title: Axis variants
34
+ requirement: An inset may apply to logical inline sides, block sides or one side independently. A narrower
35
+ declaration on the same element replaces its selected sides; padding on nested elements adds. Do not
36
+ introduce a wrapper merely to change a side that its owner already controls.
37
+ rules:
38
+ - id: PADDING-0
39
+ title: No duplicate inset
40
+ governs: A boundary contributes no extra space when content or a child already owns its edge.
41
+ cases:
42
+ - id: case-1
43
+ when: A container only groups children that each carry their own boundary
44
+ owner: Application layout
45
+ render: Group without adding another inset.
46
+ - id: case-2
47
+ when: Surface bands run flush to the surface edge
48
+ owner: The surface component
49
+ render: Compose its published flush-band treatment.
50
+ - id: case-3
51
+ when: A list sits inside a panel or its rows own their own inset
52
+ owner: The list component
53
+ render: "Owner ruling 2026-10-25 (ruling:R318/case-1): row content, section captions and headers align with the
54
+ panel content edge while row backgrounds may extend into the panel gutter. Compose without padding
55
+ wrappers. The selected Grammar supplies the panel-alignment API; the universal FE canon reports
56
+ stacked padding as FE_LIST_PANEL_PADDING."
57
+ notThisRule: The boundary protecting readable content keeps its one owned inset from the selected Grammar scale.
58
+ - id: PADDING-1
59
+ title: Minimal clearance
60
+ governs: Use the selected Grammar's smallest published inset where a deliberately tiny boundary nearly fits
61
+ its content.
62
+ cases:
63
+ - id: case-1
64
+ when: A compact marker or key floats over an application-owned canvas
65
+ owner: Application layout
66
+ render: Choose the smallest published inset that clears the marker content.
67
+ - id: case-2
68
+ when: A scroll region reserves room for focus visibility
69
+ owner: The scroll-region component
70
+ render: Compose the region; its focus clearance owns this inset.
71
+ - id: case-3
72
+ when: A short hint is attached to a control
73
+ owner: The hint component
74
+ render: Compose the hint; its internal inset stays with the component.
75
+ - id: PADDING-2
76
+ title: Compact clearance
77
+ governs: Use the published compact inset for an auxiliary boundary that needs clear but economical edge space.
78
+ cases:
79
+ - id: case-1
80
+ when: An auxiliary strip shares one inset on all sides
81
+ owner: Application layout
82
+ render: Apply the published compact inset once.
83
+ - id: case-2
84
+ when: A compact control bar sits above application-owned content
85
+ owner: Application layout
86
+ render: Keep its edge clearance and sibling gap as separate decisions.
87
+ notThisRule: Space between siblings belongs to the parent gap, not the boundary inset.
88
+ - id: PADDING-3
89
+ title: Dense content clearance
90
+ governs: Use the published dense inset for readable nested content and separator-facing band edges.
91
+ cases:
92
+ - id: case-1
93
+ when: A nested container owns a boundary distinct from its parent
94
+ owner: Application layout
95
+ render: Apply the published dense inset to that distinct boundary.
96
+ - id: case-2
97
+ when: A tab strip or secondary navigation needs inline clearance
98
+ owner: The navigation component
99
+ render: Compose its published inset API.
100
+ - id: case-3
101
+ when: A band side meets a separator inside a flush surface
102
+ owner: The selected Grammar recipe
103
+ render: Use its separator-facing clearance while retaining inline alignment.
104
+ - id: case-4
105
+ when: A metric cell or list row meets a separator
106
+ owner: The metric or list component
107
+ render: The separator-facing side uses its published dense clearance.
108
+ notThisRule: Repeating the same inset for the same boundary doubles it along the path from outer edge to content.
109
+ - id: PADDING-4
110
+ title: Readable content clearance
111
+ governs: Use the published content inset once at the boundary that protects readable content.
112
+ cases:
113
+ - id: case-1
114
+ when: An application section owns the distance from its border to its content
115
+ owner: Application layout
116
+ render: Apply the published content inset once.
117
+ - id: case-2
118
+ when: Content sits inside a card
119
+ owner: The card component
120
+ render: Compose the card; its content inset remains component-owned.
121
+ - id: case-3
122
+ when: A disclosure has a trigger and expanded panel
123
+ owner: The disclosure component
124
+ render: Compose the disclosure; its trigger and panel own their insets.
125
+ - id: case-4
126
+ when: An empty-state notice occupies a region
127
+ owner: The notice component
128
+ render: Compose the notice without adding its internal inset again.
129
+ - id: case-5
130
+ when: A fenced code block is displayed
131
+ owner: The code-block component
132
+ render: Compose the block without duplicating its content inset.
133
+ - id: case-6
134
+ when: A band side meets the outer edge of a flush surface
135
+ owner: The selected Grammar recipe
136
+ render: Use the published outer-edge content clearance.
137
+ - id: case-7
138
+ when: Inline sides of bands meet the same surface boundary
139
+ owner: The selected Grammar recipe
140
+ render: Use the same published inline inset on every band.
141
+ - id: PADDING-5
142
+ title: Generous section clearance
143
+ governs: A deliberately more spacious section uses its selected Grammar's published generous inset.
144
+ cases:
145
+ - id: case-1
146
+ when: A section deliberately uses equal generous clearance
147
+ owner: Application layout
148
+ render: Choose the published generous inset for that density.
149
+ - id: case-2
150
+ when: A tab frame owns page-level inline clearance
151
+ owner: The navigation component
152
+ render: Compose its published page-inset API.
153
+ notThisRule: Space between child sections is a gap, not a boundary inset.
154
+ - id: PADDING-6
155
+ title: Low-density region clearance
156
+ governs: A large, low-density region may use the selected Grammar's larger frame inset where its content
157
+ density calls for it.
158
+ cases:
159
+ - id: case-1
160
+ when: A large page region needs equal generous clearance
161
+ owner: Application layout
162
+ render: Choose its published larger frame inset.
163
+ - id: case-2
164
+ when: An empty or waiting region occupies most of the viewport
165
+ owner: Application layout
166
+ render: Give the region its own published frame clearance while its notice retains internal ownership.
167
+ notThisRule: A large frame inset is not the default for ordinary content boundaries.
168
+ - id: PADDING-7
169
+ title: Responsive inset follows its boundary
170
+ governs: A boundary keeps its meaning across widths. Its responsive inset follows adjacent published scale
171
+ steps. Separator-facing sides retain their separator clearance; block sides change only when the
172
+ boundary owns them.
173
+ cases:
174
+ - id: case-1
175
+ when: A decision surface gains room at a wider viewport
176
+ owner: The selected Grammar recipe
177
+ render: Step inline clearance to the adjacent published inset.
178
+ - id: case-2
179
+ when: That surface's outer-edge block sides gain room with it
180
+ owner: The selected Grammar recipe
181
+ render: Step only the block sides owned by the outer boundary.
182
+ - id: case-3
183
+ when: A side meets an internal separator
184
+ owner: The selected Grammar recipe
185
+ render: Keep the separator-facing clearance at both widths.
186
+ notThisRule: A separator-facing side does not step merely because the viewport widens.
187
+ - id: PADDING-8
188
+ title: Subordinate content indents at the inline start
189
+ governs: An inset that expresses nested hierarchy applies at logical inline start. The end edge remains
190
+ aligned with its parent so the reading measure stays available. The selected Grammar supplies the
191
+ indentation step and disclosure recipe.
192
+ cases:
193
+ - id: case-1
194
+ when: A disclosure body belongs under its trigger
195
+ owner: The disclosure component
196
+ render: Use its published leading indentation and unchanged trailing edge.
197
+ - id: case-2
198
+ when: A nested group belongs to a named parent row
199
+ owner: The group component
200
+ render: Use the selected Grammar's per-level leading indentation.
201
+ notThisRule: Indenting both sides reads as an inset block rather than subordinate content. A missing
202
+ disclosure capability is repaired in the Grammar.
203
+ - id: PADDING-9
204
+ title: Routed content owns its block inset
205
+ governs: A routed content region may step its block inset with the viewport while the page container retains
206
+ inline inset ownership. Its responsive values use adjacent published steps and never duplicate the page
207
+ edge.
208
+ cases:
209
+ - id: case-1
210
+ when: Routed content sits directly beneath the page shell
211
+ owner: Application layout
212
+ render: Apply its published responsive block inset; leave inline clearance with the page container.
213
+ notThisRule: Inline clearance on routed content duplicates the page-container edge and is refused.
214
+ doesNotDecide: Space between siblings is Gap (gap.yaml), and external offsets are Margin (margin.yaml). The
215
+ selected Grammar owns page-container geometry, its closed inset scale and component recipes under
216
+ FE-RULE-OWNERSHIP; its playbook supplies the concrete values used in proof.
@@ -2130,17 +2130,17 @@ FE_APP_SHELL_BOTTOM_TABS:
2130
2130
  meaning_vi: "Khung ứng dụng tại <file> đặt điều hướng trong thanh tab dưới thay vì Sidebar drawer."
2131
2131
  causes_vi:
2132
2132
  - "Cấu trúc shell không theo canon ứng dụng."
2133
- nextStep_vi: "Dùng hàng mở drawer bên dưới navbar và Sidebar presentation=\"drawer\"."
2133
+ nextStep_vi: "Dùng hàng mở drawer bên dưới navbar và Sidebar presentation=\"drawer\" (R316; FE-RULE-OWNERSHIP: knowledge/patterns/fe/index.yaml; packages/eslint/grammar-starci/README.md)."
2134
2134
  owner: op-retry
2135
2135
  kind: check-finding
2136
2136
 
2137
2137
  FE_APP_SHELL_FRAME:
2138
- title: "The application frame is not a fixed WorkspaceShell"
2138
+ title: "The application frame bypasses the selected Grammar shell"
2139
2139
  title_vi: "Khung ứng dụng không dùng WorkspaceShell cố định"
2140
2140
  meaning_vi: "Khung ứng dụng tại <file> không giao bố cục và cuộn cho WorkspaceShell."
2141
2141
  causes_vi:
2142
2142
  - "Cấu trúc shell không theo canon ứng dụng."
2143
- nextStep_vi: "Ghép khung ứng dụng bằng WorkspaceShell viewport=\"fixed\"."
2143
+ nextStep_vi: "Ghép khung ứng dụng bằng WorkspaceShell viewport=\"fixed\" (R313; FE-RULE-OWNERSHIP: knowledge/patterns/fe/index.yaml; packages/eslint/grammar-starci/README.md)."
2144
2144
  owner: op-retry
2145
2145
  kind: check-finding
2146
2146
 
@@ -2205,7 +2205,7 @@ FE_COMPONENT_API:
2205
2205
  - "Component nhận className từ ngoài"
2206
2206
  - "Khối kết nối không có bản trình bày thuần"
2207
2207
  - "Trạng thái dữ liệu tự chế thay vì qua SlotView"
2208
- nextStep_vi: "Sửa chữ ký component theo luật drawing và tách phần trình bày; op vừa tạo ra bản này sẽ được chạy lại để sửa theo lời nhắn của bộ kiểm tra."
2208
+ nextStep_vi: "Sửa chữ ký component theo luật drawing và tách phần trình bày; op vừa tạo ra bản này sẽ được chạy lại để sửa theo lời nhắn của bộ kiểm tra (R92; FE-RULE-OWNERSHIP: knowledge/patterns/fe/index.yaml; packages/eslint/grammar-starci/README.md)."
2209
2209
  owner: op-retry
2210
2210
  kind: check-finding
2211
2211
 
@@ -2348,6 +2348,16 @@ FE_ERROR_BOUNDARY_MISSING:
2348
2348
  owner: op-retry
2349
2349
  kind: check-finding
2350
2350
 
2351
+ FE_GRAMMAR_LAYOUT_ONLY:
2352
+ title: "App surface paint violates layout-only composition"
2353
+ title_vi: "Ứng dụng tự tô surface thay vì chỉ viết CSS bố cục"
2354
+ meaning_vi: "Ứng dụng thêm lớp bg-surface thay vì dùng surface có nền của Grammar."
2355
+ causes_vi:
2356
+ - "Thêm lớp bg-surface vào phần tử do ứng dụng dựng"
2357
+ nextStep_vi: "Giữ CSS ứng dụng chỉ lo bố cục và dùng SurfaceCard hoặc surface có nền khác của Grammar."
2358
+ owner: "op-retry"
2359
+ kind: "check-finding"
2360
+
2351
2361
  FE_GRAPHQL_CONTRACT:
2352
2362
  title: "A front-end GraphQL document is one its back end serves"
2353
2363
  title_vi: "Tài liệu GraphQL của front end không khớp hợp đồng của back end"
@@ -2457,7 +2467,7 @@ FE_ICON_INLINE_SVG:
2457
2467
  causes_vi:
2458
2468
  - "Leaf Icon tự vẽ path hoặc SVG thay vì dùng Heroicons"
2459
2469
  - "Component vẽ SVG trực tiếp mà không phải leaf nhãn hiệu được khai báo"
2460
- nextStep_vi: "Thay glyph bằng Heroicons qua leaf Icon; nếu là nhãn hiệu, đặt nó trong leaf nhãn hiệu và khai báo đúng chủ của leaf."
2470
+ nextStep_vi: "Thay glyph bằng Heroicons qua leaf Icon; nếu là nhãn hiệu, đặt nó trong leaf nhãn hiệu và khai báo đúng chủ của leaf (R286; FE-RULE-OWNERSHIP: knowledge/patterns/fe/index.yaml; packages/eslint/grammar-starci/README.md)."
2461
2471
  owner: op-retry
2462
2472
  kind: check-finding
2463
2473
 
@@ -2474,7 +2484,7 @@ FE_LIST_KEY:
2474
2484
  FE_LIST_PANEL_PADDING:
2475
2485
  title: "Panel list wrapper stacks horizontal content padding"
2476
2486
  title_vi: "Phần tử bọc danh sách trong panel cộng dồn padding ngang"
2477
- meaning_vi: "Ứng dụng thêm px-*, ps-* hoặc pe-* vào phần tử bọc ListBox của Grammar hoặc nhãn nhóm, khiến nội dung lệch khỏi mép panel."
2487
+ meaning_vi: "Ứng dụng thêm padding ngang vào phần tử bọc ListBox của Grammar hoặc nhãn nhóm bên trong surface có nền, khiến nội dung lệch khỏi mép panel."
2478
2488
  causes_vi:
2479
2489
  - "Bọc ListBox bằng phần tử có padding ngang"
2480
2490
  - "Thêm padding ngang quanh nhãn nhóm của danh sách"
@@ -2488,7 +2498,7 @@ FE_NATIVE_FORM_CONTROL:
2488
2498
  meaning_vi: "`<tag>` thô ở `<file>`. Dùng renderer của grammar."
2489
2499
  causes_vi:
2490
2500
  - "Vi phạm luật R62: Không `<select>/<input>/<textarea>/<button>`, `<img>` thô và không thẻ cấu trúc thô (`<section>`, `<p>`, `<ul>`, `<h1>`...) ở tầng sản phẩm; dùng renderer grammar."
2491
- nextStep_vi: "Op vừa tạo ra bản này sẽ được chạy lại để sửa theo lời nhắn của bộ kiểm tra và mục của luật trong tiêu chuẩn HFS; nợ cũ cần quyết định thiết kế nên op không thêm ngoại lệ, chỉ tách hoặc chuyển về đúng chủ."
2501
+ nextStep_vi: "Op vừa tạo ra bản này sẽ được chạy lại để sửa theo lời nhắn của bộ kiểm tra và mục của luật trong tiêu chuẩn HFS; nợ cũ cần quyết định thiết kế nên op không thêm ngoại lệ, chỉ tách hoặc chuyển về đúng chủ (R62; FE-RULE-OWNERSHIP: knowledge/patterns/fe/index.yaml; packages/eslint/grammar-starci/README.md)."
2492
2502
  owner: op-retry
2493
2503
  kind: check-finding
2494
2504
 
@@ -2508,17 +2518,17 @@ FE_NAVBAR_CLUSTER:
2508
2518
  meaning_vi: "Cụm navbar tại <file> không giữ thứ tự ngôn ngữ, giao diện, thông báo và tài khoản."
2509
2519
  causes_vi:
2510
2520
  - "Cấu trúc shell không theo canon ứng dụng."
2511
- nextStep_vi: "Ghép IconButton ngôn ngữ, Switch giao diện, IconButton chuông và AvatarButton theo đúng thứ tự."
2521
+ nextStep_vi: "Ghép IconButton ngôn ngữ, Switch giao diện, IconButton chuông và AvatarButton theo đúng thứ tự (R315; FE-RULE-OWNERSHIP: knowledge/patterns/fe/index.yaml; packages/eslint/grammar-starci/README.md)."
2512
2522
  owner: op-retry
2513
2523
  kind: check-finding
2514
2524
 
2515
2525
  FE_NAVBAR_CONTROL_SIZE:
2516
- title: "A navbar control does not use the control size"
2526
+ title: "A navbar control bypasses the selected Grammar control scale"
2517
2527
  title_vi: "Điều khiển navbar không dùng cỡ control"
2518
2528
  meaning_vi: "Điều khiển trong navbar tại <file> không khai báo cùng cỡ control của Grammar."
2519
2529
  causes_vi:
2520
2530
  - "Cấu trúc shell không theo canon ứng dụng."
2521
- nextStep_vi: "Đặt size=\"control\" trên từng điều khiển trong thanh."
2531
+ nextStep_vi: "Đặt size=\"control\" trên từng điều khiển trong thanh (R314; FE-RULE-OWNERSHIP: knowledge/patterns/fe/index.yaml; packages/eslint/grammar-starci/README.md)."
2522
2532
  owner: op-retry
2523
2533
  kind: check-finding
2524
2534
 
@@ -2528,18 +2538,18 @@ FE_NAVBAR_CREATE:
2528
2538
  meaning_vi: "Navbar tại <file> chứa thao tác tạo mới thuộc nội dung trang."
2529
2539
  causes_vi:
2530
2540
  - "Cấu trúc shell không theo canon ứng dụng."
2531
- nextStep_vi: "Đưa thao tác tạo mới về trang sở hữu nó."
2541
+ nextStep_vi: "Đưa thao tác tạo mới về trang sở hữu nó (R317; FE-RULE-OWNERSHIP: knowledge/patterns/fe/index.yaml; packages/eslint/grammar-starci/README.md)."
2532
2542
  owner: op-retry
2533
2543
  kind: check-finding
2534
2544
 
2535
2545
  FE_NESTED_VARIANT:
2536
- title: "Nested control or surface paint bypasses Grammar ownership"
2537
- title_vi: "Trường lồng hoặc nền surface vượt quyền sở hữu của Grammar"
2538
- meaning_vi: "Trường bên trong surface Grammar ép variant primary, hoặc ứng dụng tự tô nền bằng bg-surface thay vì dùng composition của Grammar."
2546
+ title: "App variants bypass Grammar surface context"
2547
+ title_vi: "Variant ứng dụng vượt qua context surface của Grammar"
2548
+ meaning_vi: "Ứng dụng đặt variant tĩnh cho trường Grammar trên bất kỳ lớp nào, hoặc ép Tabs dùng primary trong surface có nền."
2539
2549
  causes_vi:
2540
- - "Truyền variant primary cho trường bên trong một surface"
2541
- - "Thêm lớp bg-surface vào phần tử do ứng dụng dựng"
2542
- nextStep_vi: "Dùng surface của Grammar và bỏ variant của trường lồng bên trong để Grammar tự cấp secondary."
2550
+ - "Truyền variant tĩnh cho trường Grammar"
2551
+ - "Ép Tabs dùng primary bên trong surface có nền"
2552
+ nextStep_vi: "Bỏ variant để Grammar tự cấp mặc định theo context surface."
2543
2553
  owner: "op-retry"
2544
2554
  kind: "check-finding"
2545
2555
 
@@ -2855,6 +2865,16 @@ FE_STACK_CORE_MISSING:
2855
2865
  owner: op-retry
2856
2866
  kind: check-finding
2857
2867
 
2868
+ FE_STACK_FAMILY_LINT_MISSING:
2869
+ title: "The front end installs canon-fe 9 without the selected Grammar family's lint package"
2870
+ title_vi: "Front end dùng canon-fe 9 nhưng thiếu gói lint của họ Grammar đã chọn"
2871
+ meaning_vi: "hfs.json chọn sides.fe.grammar (starci hoặc offset-pop) và front end khai báo @starci/eslint-canon-fe 9 trở lên, nhưng không manifest nào khai báo gói lint của họ đó; từ canon-fe 9 các luật component Grammar nằm trong gói này, thiếu gói thì các luật ấy không chạy."
2872
+ causes_vi:
2873
+ - "Nâng @starci/eslint-canon-fe lên 9 mà chưa thêm @starci/eslint-grammar-starci (Grammar StarCi) hoặc @starci/eslint-grammar-offset-pop (Grammar Offset Pop)."
2874
+ nextStep_vi: "Thêm @starci/eslint-grammar-starci (hoặc @starci/eslint-grammar-offset-pop) cạnh @starci/eslint-canon-fe, ghép starciGrammarConfig({ hfs }) (hoặc offsetPopGrammarConfig({ hfs })) sau starciFeConfig({ hfs }) trong fe/eslint.config.mjs, hoặc chạy starci app sync."
2875
+ owner: op-retry
2876
+ kind: check-finding
2877
+
2858
2878
  FE_STACK_FORBIDDEN:
2859
2879
  title: "A front end declares or imports a package or scoped package family forbidden by the stack"
2860
2880
  title_vi: "Front end dùng thư viện hoặc họ package bị fe-stack cấm"
@@ -2908,7 +2928,7 @@ FE_STYLE_TOKEN_ONLY:
2908
2928
  - "@media dùng breakpoint ngoài thang của grammar"
2909
2929
  - "brand.css thiếu cặp mềm của một tông trạng thái ở sáng hoặc tối, chữ mềm dưới 3:1 trên nền nhạt hoặc nền trang, --foreground dưới 4.5:1, hoặc giá trị màu không phân giải được"
2910
2930
  - "Component tô chữ hoặc icon bằng text-success, text-danger, fill-warning, stroke-info (tông đặc) thay vì text-<tông>-soft-foreground"
2911
- nextStep_vi: "Op interface.implement bỏ CSS riêng, dùng component và token của grammar; giá trị màu thương hiệu chỉ khai ở modules/brand/brand.css cho cả sáng và tối, đủ cặp mềm cho mọi tông trạng thái; chữ và icon trạng thái dùng text-<tông>-soft-foreground."
2931
+ nextStep_vi: "Op interface.implement bỏ CSS riêng, dùng component và token của grammar; giá trị màu thương hiệu chỉ khai ở modules/brand/brand.css cho cả sáng và tối, đủ cặp mềm cho mọi tông trạng thái; chữ và icon trạng thái dùng text-<tông>-soft-foreground (R61; FE-RULE-OWNERSHIP: knowledge/patterns/fe/index.yaml; packages/eslint/grammar-starci/README.md)."
2912
2932
  owner: other-op:interface.implement
2913
2933
  kind: check-finding
2914
2934
 
@@ -3027,7 +3047,7 @@ FE_VENDOR_BOUNDARY:
3027
3047
  - "Dùng bộ glyph thứ hai ngoài họ heroicons (Phosphor, Lucide, Iconify...)"
3028
3048
  - "Dùng kích thước biểu tượng ngoài thang"
3029
3049
  - "Primitive thư viện ngoài dùng trực tiếp ở nhiều nơi"
3030
- nextStep_vi: "Dùng lá icon và chủ sở hữu primitive có sẵn; op vừa tạo ra bản này sẽ được chạy lại để sửa theo lời nhắn của bộ kiểm tra."
3050
+ nextStep_vi: "Dùng lá icon và chủ sở hữu primitive có sẵn; op vừa tạo ra bản này sẽ được chạy lại để sửa theo lời nhắn của bộ kiểm tra (R93; FE-RULE-OWNERSHIP: knowledge/patterns/fe/index.yaml; packages/eslint/grammar-starci/README.md)."
3031
3051
  owner: op-retry
3032
3052
  kind: check-finding
3033
3053
 
@@ -4903,7 +4923,7 @@ RT_GENERATED_BLOCK_STALE:
4903
4923
  RT_GENERATED_DRIFT:
4904
4924
  title: "Generated copy drifted"
4905
4925
  title_vi: "Bản sao sinh tự động bị lệch"
4906
- meaning_vi: "Một bản sao sinh tự động trong packages/hfs/runtime, packages/eslint/be/runtime hoặc packages/eslint/fe/runtime khác với nội dung mà scripts/hfs/sync-runtime.mjs ghi ra từ nguồn duy nhất: thiếu, cũ, hoặc thừa tệp."
4926
+ meaning_vi: "Một bản sao sinh tự động trong packages/hfs/runtime, packages/eslint/be/runtime hoặc packages/eslint/fe/runtime, packages/eslint/grammar-starci/runtime, packages/eslint/grammar-offset-pop/runtime khác với nội dung mà scripts/hfs/sync-runtime.mjs ghi ra từ nguồn duy nhất: thiếu, cũ, hoặc thừa tệp."
4907
4927
  causes_vi:
4908
4928
  - "Sửa một tệp nguồn được đóng gói mà quên chạy sync-runtime"
4909
4929
  - "Sửa tay một tệp trong thư mục runtime/ của gói"
@@ -8,6 +8,22 @@
8
8
  # a word to scan for).
9
9
  kinds: [config-key, bias-field, verb, flag, code, vocabulary, file]
10
10
  removed:
11
+ - id: fe-landmark-branch-inventory
12
+ kind: vocabulary
13
+ name: LANDMARK_BRANCHES
14
+ use: 'the selected Grammar lint package owns its component vocabulary; the universal FE canon exposes no component inventory'
15
+ since: 1.0.0-alpha.31
16
+ - id: fe-grammar-rule-namespace
17
+ kind: vocabulary
18
+ name: starci-fe Grammar component rules
19
+ match: 'starci-fe/(?:app-shell-frame|no-shell-bottom-tabs|navbar-control-size|navbar-cluster|no-navbar-create|no-raw-structural-element|no-heading-tag-outside-heading-component|status-text-uses-soft-foreground|vendor-primitive-has-named-owner|no-vendor-icon-outside-icon-leaf|heroicons-is-the-glyph-vendor|no-off-scale-glyph-size|no-icon-size-class|destructive-menu-entry-needs-danger-tone|no-decorative-icon-in-metric-cell|no-inline-svg-outside-brand-mark-leaf|no-fractional-step|no-hand-rolled-heading|no-unresolved-token-class|slot-status-through-slotview)\b'
20
+ use: 'the same rule id under starci-grammar/ from the selected Grammar lint package; FE-RULE-OWNERSHIP governs placement'
21
+ since: 1.0.0-alpha.31
22
+ - id: offset-pop-toaster-content-guidance
23
+ kind: vocabulary
24
+ name: toaster-clear-of-the-dock
25
+ use: 'toaster-clear-of-content in the Offset Pop playbook'
26
+ since: 1.0.0-alpha.31
11
27
  - id: cut-seam-command
12
28
  kind: flag
13
29
  name: cut-seam --command
@@ -401,3 +417,16 @@ removed:
401
417
  use: 'the release tag is always <release.tagPrefix><package.json version>; delete the key'
402
418
  since: 1.0.0-alpha.31
403
419
  match: '\btagMatchesVersion\b'
420
+
421
+ - id: grammar-surfacecard-manual-layer
422
+ kind: vocabulary
423
+ name: SurfaceCard manual depth and unpainted frame
424
+ use: 'SurfaceCard derives its depth from the painted parent surface; use an unpainted layout container for grouping and a bounded SurfaceCard for a painted face'
425
+ since: 1.0.0-alpha.31
426
+ match: 'SurfaceCard[^\r\n>]*\s(?:depth=|frame="frameless")'
427
+ - id: grammar-dropdown-negative-tone
428
+ kind: vocabulary
429
+ name: DropdownMenuItem negative tone
430
+ use: 'DropdownMenuItem.tone uses neutral or danger; destructive commands use danger'
431
+ since: 1.0.0-alpha.31
432
+ match: 'DropdownMenuItem(?:Tone|\.tone)[^\r\n]*["'']negative["'']'
@@ -1,7 +1,7 @@
1
1
  // GENERATED by scripts/cli/gen-catalog.mjs — do not edit
2
2
  export const CATALOG = {
3
3
  "schema": "starci/cli-catalog@1",
4
- "hash": "22aaaddc27f0ed4d795adfbd63deba5f0071f15dcab2a8456f852a20798b622b",
4
+ "hash": "4ab7076e241f09f78dcd0009085eb283a16132f623b508015e0ef805f2f6845b",
5
5
  "global": [
6
6
  {
7
7
  "name": "json",
@@ -634,7 +634,7 @@ export const CATALOG = {
634
634
  "runtimeSide": "host"
635
635
  },
636
636
  "check": {
637
- "summary": "judge the app tree, managed output, contracts, formatting and architecture",
637
+ "summary": "run the app ESLint canons and judge the tree, managed output, contracts, formatting and architecture",
638
638
  "owner": "@starci/hfs",
639
639
  "flags": [
640
640
  {
@@ -661,7 +661,7 @@ export const CATALOG = {
661
661
  "exit": {
662
662
  "0": "clean",
663
663
  "1": "findings",
664
- "2": "refusal or bad usage"
664
+ "2": "a tool could not run, refusal or bad usage"
665
665
  },
666
666
  "json": "flag",
667
667
  "examples": [
@@ -3124,7 +3124,7 @@ export const CATALOG = {
3124
3124
  "json": "always",
3125
3125
  "examples": [
3126
3126
  "starci gate unit --root <app> --out unit-run.json",
3127
- "starci gate unit --root <app> --tests orders --subjects 'be/src/modules/orders/' --out unit-run.json"
3127
+ "starci gate unit --root <app> --tests orders --subjects '<subject-path>' --out unit-run.json"
3128
3128
  ],
3129
3129
  "editions": [
3130
3130
  "full"
@@ -3269,7 +3269,7 @@ export const CATALOG = {
3269
3269
  "full"
3270
3270
  ],
3271
3271
  "impl": {
3272
- "module": "scripts/machine/git-commit.mjs",
3272
+ "module": "scripts/guards/git-commit.mjs",
3273
3273
  "export": "gitCommit"
3274
3274
  },
3275
3275
  "effect": "local-write",
@@ -14919,7 +14919,7 @@ export const CATALOG = {
14919
14919
  {
14920
14920
  "name": "family",
14921
14921
  "type": "string",
14922
- "summary": "grammar family to use instead of the detected one (a registered grammar family id)"
14922
+ "summary": "explicit registered Grammar family; otherwise read sides.fe.grammar from the app declaration"
14923
14923
  },
14924
14924
  {
14925
14925
  "name": "elements",
@@ -14941,7 +14941,7 @@ export const CATALOG = {
14941
14941
  "exit": {
14942
14942
  "0": "brief printed or the score is clean",
14943
14943
  "1": "a scoring finding",
14944
- "2": "bad usage"
14944
+ "2": "bad usage or unavailable presentation source"
14945
14945
  },
14946
14946
  "json": "flag",
14947
14947
  "examples": [