@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.
- package/CHANGELOG.md +8 -1
- package/README.md +8 -11
- package/lint/run.mjs +70 -29
- package/package.json +2 -2
- package/runtime/knowledge/grammars/index.yaml +102 -0
- package/runtime/knowledge/grammars/offset-pop/playbook.yaml +302 -0
- package/runtime/knowledge/grammars/starci/playbook.yaml +1159 -0
- package/runtime/knowledge/hfs/canon-pins.yaml +22 -8
- package/runtime/knowledge/hfs/fe-stack.yaml +7 -0
- package/runtime/knowledge/hfs/rules.yaml +133 -83
- package/runtime/knowledge/hfs/slots.yaml +3 -3
- package/runtime/knowledge/ui/presentation/font.yaml +101 -0
- package/runtime/knowledge/ui/presentation/padding.yaml +216 -0
- package/runtime/modules/kernel/failure-codes.yaml +40 -20
- package/runtime/modules/kernel/removed-vocabulary.yaml +29 -0
- package/runtime/packages/cli/src/catalog.generated.mjs +7 -7
- package/runtime/scripts/gates/canon-pins.mjs +103 -0
- package/runtime/scripts/gates/gate.mjs +3 -36
- package/runtime/scripts/gates/output.mjs +40 -0
- package/runtime/scripts/gates/test-world-run.mjs +2 -4
- package/runtime/scripts/hfs/architecture/config.mjs +8 -8
- package/runtime/scripts/hfs/check.mjs +1 -1
- package/runtime/scripts/hfs/db-restamp-verb.mjs +2 -2
- package/runtime/scripts/hfs/declaration-shape.mjs +8 -2
- package/runtime/scripts/hfs/grammar-presentation.mjs +152 -0
- package/runtime/scripts/hfs/rule-catalog.mjs +2 -2
- package/runtime/scripts/hfs/rules/a15-findings.mjs +1 -0
- package/runtime/scripts/hfs/rules/fe-stack.mjs +44 -1
- package/runtime/scripts/hfs/slots.mjs +1 -0
- package/runtime/scripts/hfs/view.mjs +1 -0
- package/runtime/scripts/lib/canon-binding-text.mjs +129 -0
- package/runtime/scripts/lib/example-refs.mjs +1 -1
- package/runtime/scripts/lib/grammar-lint.mjs +48 -0
- package/runtime/scripts/lib/grammar-vendor-parity.mjs +31 -111
- package/runtime/scripts/lib/grammar-vendor-source.mjs +345 -0
- package/runtime/scripts/lib/numeric-match.mjs +5 -0
- package/runtime/scripts/lib/source-package-imports.mjs +111 -0
- package/runtime/scripts/work/draw/draw-layer.mjs +5 -4
- package/scaffold/app.mjs +7 -5
- package/src/main.mjs +26 -13
- package/stack/config.mjs +2 -1
- package/stack/render.mjs +24 -3
- package/sync/index.mjs +8 -2
- package/templates/app/skeleton/.starcistacks/dev/infra/compose/stack.yaml +0 -1
- package/templates/app/skeleton/.starcistacks/production/infra/swarm/stack.yaml +0 -1
- package/templates/app/skeleton-lite/.starcistacks/dev/infra/swarm/stack.yaml +0 -1
- package/templates/app/skeleton-lite/.starcistacks/production/infra/swarm/stack.yaml +0 -1
- package/templates/fe/tool-config/eslint.config.mjs +4 -1
|
@@ -21,30 +21,44 @@ pins:
|
|
|
21
21
|
install: registry
|
|
22
22
|
side: fe
|
|
23
23
|
source: packages/heroicons/package.json
|
|
24
|
-
why: 'StarCi custom Heroicons-compatible cuts; eslint-
|
|
24
|
+
why: 'StarCi custom Heroicons-compatible cuts; eslint-grammar-starci (icon.mjs) admits @starci/heroicons/24/outline and /16/solid as icon sources, so an app that uses them gets this exact version.'
|
|
25
25
|
'@starci/grammar':
|
|
26
|
-
version: 0.12.
|
|
26
|
+
version: 0.12.3
|
|
27
27
|
group: starci
|
|
28
28
|
install: registry
|
|
29
29
|
side: fe
|
|
30
30
|
source: packages/grammar/package.json
|
|
31
31
|
why: 'the grammar front ends read: the brand layer sets `--font-sans` and `--font-mono` and the grammar reads them; it carries the Input tel kind, the copyable and read-only Input, the IconButton disclosure props and count badge, ChatBubble, FillViewport, Textarea mentions and Enter-to-send, the leading PrimaryRailLayout rail, the plate-less Image, ListRow, the soft Alert, Progress steps, the floating primary IconButton, FlowGraph, the STATE-8 loading views and the bordered selectable TagGroup chips. The runtime source version wins for a @starci package.'
|
|
32
32
|
'@starci/eslint-canon-be':
|
|
33
|
-
version: 3.4.
|
|
33
|
+
version: 3.4.44
|
|
34
34
|
group: starci
|
|
35
35
|
install: registry
|
|
36
36
|
side: be
|
|
37
37
|
source: packages/eslint/be/package.json
|
|
38
38
|
why: 'the back-end ESLint canon: `loadHfs(import.meta.url)` of be/eslint.config.mjs finds the app-root hfs.json (kind app) and gives every linted file the view of the be side, and the project graph is built per side; its bundled runtime copies (slots, canon-pins, failure codes, the architecture machine) put .starcistacks and .sops.yaml at the app root; `starciBeConfig({ hfs: loadHfs(import.meta.url) })` is the typed factory and the BE-CONVENTION laws are its rules.'
|
|
39
39
|
'@starci/eslint-canon-fe':
|
|
40
|
-
version:
|
|
40
|
+
version: 9.0.0
|
|
41
41
|
group: starci
|
|
42
42
|
install: registry
|
|
43
43
|
side: fe
|
|
44
44
|
source: packages/eslint/fe/package.json
|
|
45
45
|
why: 'the front-end ESLint canon: `loadHfs(import.meta.url)` of fe/eslint.config.mjs finds the app-root hfs.json (kind app) and gives every linted file the view of the fe side, and the project graph is built per side; its bundled runtime copies (slots, canon-pins, failure codes, the architecture machine) put .starcistacks and .sops.yaml at the app root; the front end has no tests (FE_NO_TESTS R97 in hfs) and no-vietnamese-in-source (R91) applies.'
|
|
46
|
+
'@starci/eslint-grammar-starci':
|
|
47
|
+
version: 0.12.3
|
|
48
|
+
group: starci
|
|
49
|
+
install: registry
|
|
50
|
+
side: fe
|
|
51
|
+
source: packages/eslint/grammar-starci/package.json
|
|
52
|
+
why: 'the StarCi Grammar component API lint, versioned with @starci/grammar; front ends compose this family package with the universal FE canon.'
|
|
53
|
+
'@starci/eslint-grammar-offset-pop':
|
|
54
|
+
version: 0.12.3
|
|
55
|
+
group: starci
|
|
56
|
+
install: registry
|
|
57
|
+
side: fe
|
|
58
|
+
source: packages/eslint/grammar-offset-pop/package.json
|
|
59
|
+
why: 'the Offset Pop Grammar component API lint, versioned with @starci/grammar; its shared component contract comes from the StarCi family lint without copying rules.'
|
|
46
60
|
'@starci/stylelint-canon':
|
|
47
|
-
version: 2.0.
|
|
61
|
+
version: 2.0.12
|
|
48
62
|
group: starci
|
|
49
63
|
install: registry
|
|
50
64
|
side: fe
|
|
@@ -77,14 +91,14 @@ pins:
|
|
|
77
91
|
source: packages/test-world/package.json
|
|
78
92
|
why: 'the shared e2e library of every back end (R47, R48), a devDependency of every back end: the warm stack behind toxiproxy, the network-edge fakes, the Nest boot, the typed useTestWorld handle, useSandbox for contract specs and the outage lock. Kafka is real own infra (the one digest-pinned apache/kafka KRaft image, a broker listener and proxy per slot, slot-prefixed topics, consumer groups and client ids) and Postgres is schema-per-context (a schema and a login role per context in a shared database). Each worker has its own data slot (<ns>_w<k>) with its own databases, Keycloak realm, leased Redis DB, bucket/collection/topic prefixes, fakes host, toxiproxy proxies and outage lock; a run provisions min(jest workers, workers cap, default 2) slots, and state file protocol 2 pairs exactly with @starci/jest-preset (TEST_WORLD_PAIR_MISMATCH otherwise). A modules world boots real peer apps beside its modules, world.apps.<name>.during(fn) is the outage of a peer app, w.keycloak.clientSecret(client) answers the run-generated secret of a confidential realm client, world.keycloak.events/sessions read the realm user events and live sessions, world.infra.postgresql.connection(name) takes one database connection down while the others serve, and world.resolve and scope.resolve take any Nest token. Every path a declaration names (`stack`, seeds, the realm, Dockerfiles) resolves from the app root (the directory of hfs.json); the globalSetup registers the path aliases as TypeScript resolves them. Its CLI main is exported at ./cli for starci app stack.'
|
|
79
93
|
'@starci/cli':
|
|
80
|
-
version: 1.7.
|
|
94
|
+
version: 1.7.35
|
|
81
95
|
group: starci
|
|
82
96
|
install: registry
|
|
83
97
|
side: both
|
|
84
98
|
source: packages/cli/package.json
|
|
85
99
|
why: 'the only StarCi command package; product repositories install it for starci app, while @starci/hfs remains its pinned transitive implementation.'
|
|
86
100
|
'@starci/hfs':
|
|
87
|
-
version: 4.7.
|
|
101
|
+
version: 4.7.35
|
|
88
102
|
group: starci
|
|
89
103
|
install: registry
|
|
90
104
|
side: both
|
|
@@ -380,7 +394,7 @@ pins:
|
|
|
380
394
|
version: 2.2.0
|
|
381
395
|
group: ui
|
|
382
396
|
side: fe
|
|
383
|
-
why: 'the base of the one application icon set (fe-stack icons, with @starci/heroicons for the glyphs it lacks); eslint-
|
|
397
|
+
why: 'the base of the one application icon set (fe-stack icons, with @starci/heroicons for the glyphs it lacks); eslint-grammar-starci (icon.mjs) admits @heroicons/react/24/outline and /16/solid.'
|
|
384
398
|
'@dicebear/core':
|
|
385
399
|
version: 10.4.0
|
|
386
400
|
group: ui
|
|
@@ -237,6 +237,13 @@ concerns:
|
|
|
237
237
|
pattern: FE-LINT
|
|
238
238
|
forbids: []
|
|
239
239
|
why: the canon lint and format configuration.
|
|
240
|
+
- id: grammar-lint
|
|
241
|
+
tier: opt
|
|
242
|
+
packages: ['@starci/eslint-grammar-starci', '@starci/eslint-grammar-offset-pop']
|
|
243
|
+
home: [fe.source-root-pinned]
|
|
244
|
+
pattern: FE-RULE-OWNERSHIP
|
|
245
|
+
forbids: []
|
|
246
|
+
why: The selected Grammar family's lint package runs beside the universal front-end canon; the family catalog declares the package and factory.
|
|
240
247
|
- id: auth-supabase
|
|
241
248
|
tier: opt
|
|
242
249
|
packages: ['@supabase/supabase-js', '@supabase/ssr']
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
# An enforcer is a check that exists or one still owed. `status: planned` marks one owed: the architecture machine, the
|
|
9
9
|
# hfs CLI, stylelint and Sonar lanes fill them, and the entry's `status` is removed the day the check ships (the check
|
|
10
10
|
# refuses a planned enforcer that already exists). An existing eslint enforcer is a rule id of the plugin
|
|
11
|
-
#
|
|
11
|
+
# the backend, universal frontend or selected Grammar family lint package; an existing machine, hfs or work-validate enforcer names the file
|
|
12
12
|
# (`at`) that emits one of the rule's codes. scripts/checks/check-hfs-rules.mjs holds all of this to the packages, the
|
|
13
13
|
# scripts and modules/kernel/failure-codes.yaml.
|
|
14
14
|
#
|
|
@@ -19,8 +19,8 @@
|
|
|
19
19
|
schema: starci/hfs-rules@3
|
|
20
20
|
version: 3.1.0
|
|
21
21
|
gates:
|
|
22
|
-
pre-commit: the managed
|
|
23
|
-
pre-push:
|
|
22
|
+
pre-commit: the managed L0 hook runs app hygiene, managed-file drift, ESLint per side and stylelint on staged source, and prettier on staged files; typecheck and targeted specs belong to the op gate under R225
|
|
23
|
+
pre-push: the managed app hook validates an annotated release tag and the recorded L4 evidence for HEAD, permitting the release refs and backup namespace under R225; it starts no source check, build or test
|
|
24
24
|
settle: the op gate `starci gate run` over the op's changed files (merge guard, starci app lint --changed, codegen, tsc, the slice's specs; only findings new against the workflow's previous checkpoint block), re-read at starci kernel settle, which refuses a red done; a green settle commits the op's checkpoint on wf-<workflowId>
|
|
25
25
|
land: the workflow's finish, the only time main is touched - gate.mjs over the whole workflow branch against its merge-base with main, the merge guard, review.verify of the exact head that lands, the branch rebased onto main, then main fast-forwarded and pushed
|
|
26
26
|
ci: GitHub Actions runs the same pinned starci app lint, format:check, typecheck, unit with the per-file coverage threshold, build:be and build:fe, then the Sonar scan and gate
|
|
@@ -28,7 +28,8 @@ gates:
|
|
|
28
28
|
runtime: "`starci runtime check` (npm run check) of the StarCi runtime repository itself: scripts/checks/check-runtime.mjs runs node --check, scripts/hfs/runtime-check.mjs with knowledge/hfs/runtime-slots.yaml, and the retained self-checks"
|
|
29
29
|
enforcerKinds:
|
|
30
30
|
eslint-be: a rule of the plugin @starci/eslint-canon-be (id without the plugin prefix)
|
|
31
|
-
eslint-fe: a rule of
|
|
31
|
+
eslint-fe: a universal rule of @starci/eslint-canon-fe (id without the plugin prefix)
|
|
32
|
+
eslint-grammar-starci: a selected Grammar family rule sharing the common component API, resolved through the family canon binding (id without the plugin prefix; FE-RULE-OWNERSHIP)
|
|
32
33
|
stylelint: a rule of the @starci/stylelint-canon package
|
|
33
34
|
machine: a check of the architecture machine (scripts/hfs/architecture), which reads the import graph
|
|
34
35
|
hfs: a check of the hfs CLI that reads the repository tree, configuration, contracts or catalogs
|
|
@@ -1141,7 +1142,7 @@ rules:
|
|
|
1141
1142
|
|
|
1142
1143
|
- id: R56
|
|
1143
1144
|
code: "FE_HOOKS_ARE_HOOKS"
|
|
1144
|
-
law: "`hooks/` hold hooks only: `hooks/swr` (one SWR wrapper per modules/api operation), `hooks/rhf` (forms), `hooks/zustand/<store>`, `hooks/socketio`, `hooks/effects`, `hooks/reuseables` and `hooks/<domain>` with one shared file per domain; a product hook is defined only there and imported through its index. A function in `hooks/` is a hook when it calls a hook: a React, SWR or Redux hook, a `use*` of the app's own `hooks/` folders (a `hooks/swr` wrapper, a sibling domain hook; resolved by TypeScript symbol resolution), or a listed library hook (next-intl, next/navigation, react-hook-form, zustand); a file that exports a non-hook still fails (owner ruling 2026-10-16 \"Theo y tro\")."
|
|
1145
|
+
law: "`hooks/` hold hooks only: `hooks/swr` (one SWR wrapper per modules/api operation), `hooks/rhf` (forms), `hooks/zustand/<store>`, `hooks/socketio`, `hooks/effects`, `hooks/reuseables` and `hooks/<domain>` with one shared file per domain; a product hook is defined only there and imported through its index. A function in `hooks/` is a hook when it calls a hook: a React, SWR or Redux hook, a `use*` of the app's own `hooks/` folders (a `hooks/swr` wrapper, a sibling domain hook; resolved by TypeScript symbol resolution), or a listed library hook (next-intl, next/navigation, next-themes useTheme, react-hook-form, zustand); a file that exports a non-hook still fails (owner ruling 2026-10-16 \"Theo y tro\")."
|
|
1145
1146
|
kinds: [lint, codemod]
|
|
1146
1147
|
gates: [settle, land, ci]
|
|
1147
1148
|
failureCodes: ["FE_HOOKS_ARE_HOOKS", "FE_CUSTOM_HOOK_LOCATION", "FE_BLOCK_PRODUCT_HOOK_DEFINITION", "FE_COMPONENT_DEEP_HOOK_IMPORT"]
|
|
@@ -1209,7 +1210,7 @@ rules:
|
|
|
1209
1210
|
code: "FE_I18N_PLACEMENT"
|
|
1210
1211
|
editions: [lite, full]
|
|
1211
1212
|
docs: [docs/architecture.md#r59]
|
|
1212
|
-
law: "`next-intl` with `[locale]`;
|
|
1213
|
+
law: "`next-intl` with `[locale]`; multiple apps share one `fe/packages/<family>-i18n` stack through `createAppI18n`. A single app keeps routing and request configuration in `modules/i18n` and `createNavigation` in the `modules/routes` public entry. The proxy imports routing or a routing-only shared proxy export without evaluating navigation runtime."
|
|
1213
1214
|
kinds: [check, codemod, lint]
|
|
1214
1215
|
gates: [settle, land, ci]
|
|
1215
1216
|
failureCodes: ["FE_I18N_PLACEMENT", "FE_I18N_NAVIGATION", "FE_I18N_FORMATTER"]
|
|
@@ -1252,9 +1253,10 @@ rules:
|
|
|
1252
1253
|
- {path: packages/hfs/src/hfs-i18n-catalog-coverage.spec.mjs, editions: [lite, full]}
|
|
1253
1254
|
- id: R61
|
|
1254
1255
|
code: "FE_STYLE_TOKEN_ONLY"
|
|
1255
|
-
law: "
|
|
1256
|
+
law: "Application CSS uses the selected Grammar tokens for layout and the declared brand owner for brand values; every source declaration resolves. Status foregrounds reach 3:1 against their tinted surface and page background in each theme, body text reaches 4.5:1, and an insufficiently contrasting solid tone is never text. The selected Grammar owns the concrete token pairs, typography, scale and visual values."
|
|
1257
|
+
docs: [knowledge/patterns/fe/index.yaml#FE-RULE-OWNERSHIP, packages/stylelint/README.md, packages/eslint/fe/docs/brand-values.md, docs/source-process.md#the-test-ladder, knowledge/hfs/rules.yaml#R225]
|
|
1256
1258
|
kinds: [lint, design]
|
|
1257
|
-
gates: [pre-commit,
|
|
1259
|
+
gates: [pre-commit, settle, land, ci]
|
|
1258
1260
|
failureCodes: ["FE_STYLE_TOKEN_ONLY", "FE_STYLE_SOURCE_UNRESOLVED"]
|
|
1259
1261
|
enforcers:
|
|
1260
1262
|
- {kind: stylelint, id: token-only}
|
|
@@ -1271,33 +1273,59 @@ rules:
|
|
|
1271
1273
|
- {kind: stylelint, id: breakpoint-scale}
|
|
1272
1274
|
- {kind: stylelint, id: source-resolves}
|
|
1273
1275
|
- {kind: eslint-fe, id: no-raw-brand-value}
|
|
1274
|
-
- {kind: eslint-
|
|
1276
|
+
- {kind: eslint-grammar-starci, id: no-fractional-step}
|
|
1275
1277
|
- {kind: eslint-fe, id: no-arbitrary-value}
|
|
1276
|
-
- {kind: eslint-
|
|
1277
|
-
- {kind: eslint-
|
|
1278
|
-
- {kind: eslint-
|
|
1279
|
-
- {kind: eslint-
|
|
1278
|
+
- {kind: eslint-grammar-starci, id: no-hand-rolled-heading}
|
|
1279
|
+
- {kind: eslint-grammar-starci, id: no-unresolved-token-class}
|
|
1280
|
+
- {kind: eslint-grammar-starci, id: no-heading-tag-outside-heading-component}
|
|
1281
|
+
- {kind: eslint-grammar-starci, id: status-text-uses-soft-foreground}
|
|
1282
|
+
proves:
|
|
1283
|
+
- {path: packages/stylelint/source-resolves.spec.mjs, editions: [lite, full], codes: [FE_STYLE_SOURCE_UNRESOLVED]}
|
|
1284
|
+
- {path: packages/eslint/fe/brand-values.spec.mjs, editions: [lite, full], codes: [FE_STYLE_TOKEN_ONLY]}
|
|
1285
|
+
- {path: packages/eslint/fe/tokens.spec.mjs, editions: [lite, full], codes: [FE_STYLE_TOKEN_ONLY]}
|
|
1286
|
+
- {path: packages/eslint/grammar-starci/status-colors.spec.mjs, editions: [lite, full], codes: [FE_STYLE_TOKEN_ONLY]}
|
|
1287
|
+
- {path: packages/eslint/grammar-starci/typography.spec.mjs, editions: [lite, full], codes: [FE_STYLE_TOKEN_ONLY]}
|
|
1288
|
+
- {path: packages/eslint/grammar-starci/tokens.spec.mjs, editions: [lite, full], codes: [FE_STYLE_TOKEN_ONLY]}
|
|
1289
|
+
exemplifiedBy:
|
|
1290
|
+
- {path: packages/hfs/templates/fe/skeleton-lite/apps/web/src/app/globals.css, edition: lite}
|
|
1291
|
+
- {path: packages/hfs/templates/fe/skeleton/apps/app/src/app/globals.css, edition: full}
|
|
1292
|
+
- {path: packages/stylelint/source-resolves.spec.mjs, editions: [lite, full], codes: [FE_STYLE_SOURCE_UNRESOLVED]}
|
|
1293
|
+
- {path: packages/eslint/fe/brand-values.spec.mjs, editions: [lite, full], codes: [FE_STYLE_TOKEN_ONLY]}
|
|
1294
|
+
- {path: packages/eslint/fe/tokens.spec.mjs, editions: [lite, full], codes: [FE_STYLE_TOKEN_ONLY]}
|
|
1295
|
+
- {path: packages/eslint/grammar-starci/status-colors.spec.mjs, editions: [lite, full], codes: [FE_STYLE_TOKEN_ONLY]}
|
|
1296
|
+
- {path: packages/eslint/grammar-starci/typography.spec.mjs, editions: [lite, full], codes: [FE_STYLE_TOKEN_ONLY]}
|
|
1297
|
+
- {path: packages/eslint/grammar-starci/tokens.spec.mjs, editions: [lite, full], codes: [FE_STYLE_TOKEN_ONLY]}
|
|
1298
|
+
witness:
|
|
1299
|
+
- {path: packages/stylelint/source-resolves.spec.mjs, editions: [lite, full], codes: [FE_STYLE_SOURCE_UNRESOLVED]}
|
|
1300
|
+
- {path: packages/eslint/fe/brand-values.spec.mjs, editions: [lite, full], codes: [FE_STYLE_TOKEN_ONLY]}
|
|
1301
|
+
- {path: packages/eslint/fe/tokens.spec.mjs, editions: [lite, full], codes: [FE_STYLE_TOKEN_ONLY]}
|
|
1302
|
+
- {path: packages/eslint/grammar-starci/status-colors.spec.mjs, editions: [lite, full], codes: [FE_STYLE_TOKEN_ONLY]}
|
|
1303
|
+
- {path: packages/eslint/grammar-starci/typography.spec.mjs, editions: [lite, full], codes: [FE_STYLE_TOKEN_ONLY]}
|
|
1304
|
+
- {path: packages/eslint/grammar-starci/tokens.spec.mjs, editions: [lite, full], codes: [FE_STYLE_TOKEN_ONLY]}
|
|
1280
1305
|
- id: R62
|
|
1281
1306
|
code: "FE_NATIVE_FORM_CONTROL"
|
|
1282
1307
|
editions: [lite, full]
|
|
1283
|
-
docs: [docs/architecture.md#r62]
|
|
1308
|
+
docs: [docs/architecture.md#r62, knowledge/patterns/fe/index.yaml#FE-RULE-OWNERSHIP]
|
|
1284
1309
|
proves:
|
|
1310
|
+
- {path: packages/eslint/grammar-starci/r62-structural-elements-coverage.spec.mjs, editions: [lite, full], codes: [FE_NATIVE_FORM_CONTROL]}
|
|
1285
1311
|
- {path: packages/eslint/fe/r62-native-controls-coverage.spec.mjs, editions: [lite, full]}
|
|
1286
1312
|
exemplifiedBy:
|
|
1313
|
+
- {path: packages/eslint/grammar-starci/r62-structural-elements-coverage.spec.mjs, editions: [lite, full], codes: [FE_NATIVE_FORM_CONTROL]}
|
|
1287
1314
|
- {path: packages/hfs/templates/fe/skeleton-lite/apps/web/src/features/pages/AppHomePage/component.tsx, edition: lite}
|
|
1288
1315
|
- {path: packages/hfs/templates/fe/skeleton/apps/__app__/src/components/blocks/SignInForm/component.tsx, edition: full}
|
|
1289
1316
|
- {path: packages/eslint/fe/r62-native-controls-coverage.spec.mjs, editions: [lite, full]}
|
|
1290
1317
|
witness:
|
|
1318
|
+
- {path: packages/eslint/grammar-starci/r62-structural-elements-coverage.spec.mjs, editions: [lite, full], codes: [FE_NATIVE_FORM_CONTROL]}
|
|
1291
1319
|
- {path: packages/eslint/fe/r62-native-controls-coverage.spec.mjs, edition: lite, codes: [FE_NATIVE_FORM_CONTROL, FE_NATIVE_IMAGE]}
|
|
1292
1320
|
- {path: packages/eslint/fe/r62-native-controls-coverage.spec.mjs, edition: full, codes: [FE_NATIVE_FORM_CONTROL, FE_NATIVE_IMAGE]}
|
|
1293
|
-
law: "
|
|
1321
|
+
law: "Product tiers compose the selected Grammar renderers for form controls, images and structural elements that the Grammar owns; they never reproduce those renderers with raw HTML."
|
|
1294
1322
|
kinds: [lint, design]
|
|
1295
1323
|
gates: ["pre-commit", "settle", "land", "ci"]
|
|
1296
1324
|
failureCodes: ["FE_NATIVE_FORM_CONTROL", "FE_NATIVE_IMAGE"]
|
|
1297
1325
|
enforcers:
|
|
1298
1326
|
- {kind: eslint-fe, id: no-native-form-control}
|
|
1299
1327
|
- {kind: eslint-fe, id: no-native-img}
|
|
1300
|
-
- {kind: eslint-
|
|
1328
|
+
- {kind: eslint-grammar-starci, id: no-raw-structural-element}
|
|
1301
1329
|
- {kind: eslint-fe, id: image-has-size}
|
|
1302
1330
|
|
|
1303
1331
|
- id: R63
|
|
@@ -1836,7 +1864,7 @@ rules:
|
|
|
1836
1864
|
gates: ["pre-commit","settle","land","ci"]
|
|
1837
1865
|
- id: R92
|
|
1838
1866
|
code: "FE_COMPONENT_API"
|
|
1839
|
-
law: "A component exposes the canon surface: typed named props and slots, an exact sibling XBase presentational twin for every connected block, status through the
|
|
1867
|
+
law: "A component exposes the canon surface: typed named props and slots, an exact sibling XBase presentational twin for every connected block, status through the selected Grammar state renderer, no className or CSS doors, no resting twin or placeholder prop, class names in the colocated file; a pure component reaches no hook, router, locale or API, but may render a list of blocks supplied through render props without importing blocks or owning their data."
|
|
1840
1868
|
kinds: [lint, design]
|
|
1841
1869
|
gates: [pre-commit, settle, land, ci]
|
|
1842
1870
|
failureCodes: ["FE_COMPONENT_API", "FE_COMPONENT_WORLD_OWNERSHIP", "FE_WORLD_OWNER_RENDER_BOUNDARY", "FE_CONNECTED_BLOCK_RENDER_PAIR", "FE_PURE_REACHES_DATA", "FE_PURE_WORLD_HOOK", "FE_PURE_WORLD_IMPORT"]
|
|
@@ -1850,7 +1878,7 @@ rules:
|
|
|
1850
1878
|
- {kind: eslint-fe, id: base-props-atom}
|
|
1851
1879
|
- {kind: eslint-fe, id: base-import-pair}
|
|
1852
1880
|
- {kind: eslint-fe, id: no-data-status-shape}
|
|
1853
|
-
- {kind: eslint-
|
|
1881
|
+
- {kind: eslint-grammar-starci, id: slot-status-through-slotview}
|
|
1854
1882
|
- {kind: eslint-fe, id: presentational-purity}
|
|
1855
1883
|
- {kind: eslint-fe, id: connected-block-has-presentational-twin}
|
|
1856
1884
|
- {kind: eslint-fe, id: no-resting-twin-component}
|
|
@@ -1861,62 +1889,54 @@ rules:
|
|
|
1861
1889
|
- {kind: eslint-fe, id: cn-arguments-are-single-tokens}
|
|
1862
1890
|
- {kind: eslint-fe, id: component-purity}
|
|
1863
1891
|
editions: [lite, full]
|
|
1864
|
-
docs: [docs/architecture.md#r92]
|
|
1892
|
+
docs: [docs/architecture.md#r92, knowledge/patterns/fe/index.yaml#FE-RULE-OWNERSHIP]
|
|
1865
1893
|
proves:
|
|
1894
|
+
- {path: packages/eslint/grammar-starci/r92-slot-status-coverage.spec.mjs, editions: [lite, full], codes: [FE_COMPONENT_API]}
|
|
1866
1895
|
- {path: packages/eslint/fe/r92-fetch-barrel.spec.mjs, editions: [lite, full]}
|
|
1867
1896
|
- {path: packages/eslint/fe/r92-component-surface-coverage.spec.mjs, editions: [lite, full]}
|
|
1868
1897
|
- {path: packages/eslint/fe/r56-r92-graph-coverage.spec.mjs, editions: [lite, full]}
|
|
1869
1898
|
exemplifiedBy:
|
|
1899
|
+
- {path: packages/eslint/grammar-starci/r92-slot-status-coverage.spec.mjs, editions: [lite, full], codes: [FE_COMPONENT_API]}
|
|
1870
1900
|
- {path: packages/hfs/templates/fe/skeleton/apps/__app__/src/components/blocks/SignInForm/component.tsx, editions: [lite, full]}
|
|
1871
1901
|
- {path: packages/eslint/fe/r92-fetch-barrel.spec.mjs, editions: [lite, full]}
|
|
1872
1902
|
- {path: packages/eslint/fe/r92-component-surface-coverage.spec.mjs, editions: [lite, full]}
|
|
1873
1903
|
- {path: packages/eslint/fe/r56-r92-graph-coverage.spec.mjs, editions: [lite, full]}
|
|
1874
1904
|
witness:
|
|
1905
|
+
- {path: packages/eslint/grammar-starci/r92-slot-status-coverage.spec.mjs, editions: [lite, full], codes: [FE_COMPONENT_API]}
|
|
1875
1906
|
- {path: packages/eslint/fe/r92-fetch-barrel.spec.mjs, editions: [lite, full]}
|
|
1876
1907
|
- {path: packages/eslint/fe/r92-component-surface-coverage.spec.mjs, editions: [lite, full]}
|
|
1877
1908
|
- {path: packages/eslint/fe/r56-r92-graph-coverage.spec.mjs, editions: [lite, full]}
|
|
1878
1909
|
- id: R93
|
|
1879
1910
|
code: "FE_VENDOR_BOUNDARY"
|
|
1880
|
-
law: "Vendor primitives and icons reach components only through their named owner:
|
|
1911
|
+
law: "Vendor primitives and icons reach components only through their named owner: one declared icon set through its icon owner, one icon size per region chosen from the selected Grammar scale, and every vendor primitive behind a named owner. The Grammar package is imported through its selected public code and style entries and keeps its declared contract. The Grammar owns the visual values and component API that realize these requirements."
|
|
1881
1912
|
kinds: [lint, codemod]
|
|
1882
1913
|
gates: [pre-commit, settle, land, ci]
|
|
1883
|
-
failureCodes: ["FE_VENDOR_BOUNDARY", "ARCH_GRAMMAR_CONTRACT_INVALID", "ARCH_GRAMMAR_EXPORT_BYPASS"
|
|
1884
|
-
enforcers:
|
|
1885
|
-
- {kind: eslint-
|
|
1886
|
-
- {kind: eslint-
|
|
1887
|
-
- {kind: eslint-
|
|
1888
|
-
- {kind: eslint-
|
|
1889
|
-
- {kind: eslint-
|
|
1890
|
-
- {kind: eslint-
|
|
1891
|
-
- {kind: eslint-
|
|
1914
|
+
failureCodes: ["FE_VENDOR_BOUNDARY", "ARCH_GRAMMAR_CONTRACT_INVALID", "ARCH_GRAMMAR_EXPORT_BYPASS"]
|
|
1915
|
+
enforcers:
|
|
1916
|
+
- {kind: eslint-grammar-starci, id: no-vendor-icon-outside-icon-leaf}
|
|
1917
|
+
- {kind: eslint-grammar-starci, id: heroicons-is-the-glyph-vendor}
|
|
1918
|
+
- {kind: eslint-grammar-starci, id: no-off-scale-glyph-size}
|
|
1919
|
+
- {kind: eslint-grammar-starci, id: no-icon-size-class}
|
|
1920
|
+
- {kind: eslint-grammar-starci, id: destructive-menu-entry-needs-danger-tone}
|
|
1921
|
+
- {kind: eslint-grammar-starci, id: no-decorative-icon-in-metric-cell}
|
|
1922
|
+
- {kind: eslint-grammar-starci, id: vendor-primitive-has-named-owner}
|
|
1892
1923
|
- {kind: eslint-fe, id: grammar-entry}
|
|
1893
|
-
- {kind: eslint-fe, id: nested-control-variant}
|
|
1894
|
-
- {kind: eslint-fe, id: no-list-panel-padding}
|
|
1895
1924
|
- {kind: machine, id: grammar, at: scripts/hfs/architecture/frontend-grammar.mjs}
|
|
1896
1925
|
editions: [lite, full]
|
|
1897
|
-
docs: ["docs/code-pattern-enforcement.md#r93-vendor-and-grammar-ownership"]
|
|
1926
|
+
docs: ["docs/code-pattern-enforcement.md#r93-vendor-and-grammar-ownership", knowledge/patterns/fe/index.yaml#FE-RULE-OWNERSHIP]
|
|
1898
1927
|
templateNa: "Vendor boundary violations and installed Grammar package contracts are checked against consumer ownership; no managed template scaffolds a vendor install or a forbidden import."
|
|
1899
1928
|
proves:
|
|
1900
|
-
- packages/eslint/
|
|
1929
|
+
- packages/eslint/grammar-starci/r93-vendor-coverage.spec.mjs
|
|
1901
1930
|
- packages/eslint/fe/r93-grammar-ownership.spec.mjs
|
|
1902
|
-
- packages/eslint/
|
|
1903
|
-
- packages/eslint/fe/surface-rules.spec.mjs
|
|
1931
|
+
- packages/eslint/grammar-starci/menu-entries.spec.mjs
|
|
1904
1932
|
exemplifiedBy:
|
|
1905
|
-
- {path: packages/eslint/
|
|
1933
|
+
- {path: packages/eslint/grammar-starci/r93-vendor-coverage.spec.mjs, editions: [lite, full]}
|
|
1906
1934
|
- {path: packages/eslint/fe/r93-grammar-ownership.spec.mjs, editions: [lite, full]}
|
|
1907
|
-
- {path: packages/eslint/
|
|
1908
|
-
- {path: packages/eslint/fe/surface-rules.spec.mjs, editions: [lite, full]}
|
|
1935
|
+
- {path: packages/eslint/grammar-starci/menu-entries.spec.mjs, editions: [lite, full]}
|
|
1909
1936
|
witness:
|
|
1910
|
-
- {path: packages/eslint/
|
|
1911
|
-
- {path: packages/eslint/
|
|
1937
|
+
- {path: packages/eslint/grammar-starci/menu-entries.spec.mjs, editions: [lite, full], codes: [FE_VENDOR_BOUNDARY]}
|
|
1938
|
+
- {path: packages/eslint/grammar-starci/r93-vendor-coverage.spec.mjs, editions: [lite, full], codes: [FE_VENDOR_BOUNDARY]}
|
|
1912
1939
|
- {path: packages/eslint/fe/r93-grammar-ownership.spec.mjs, editions: [lite, full], codes: [ARCH_GRAMMAR_CONTRACT_INVALID, ARCH_GRAMMAR_EXPORT_BYPASS]}
|
|
1913
|
-
- {path: packages/eslint/fe/surface-rules.spec.mjs, editions: [lite, full], codes: [FE_NESTED_VARIANT, FE_LIST_PANEL_PADDING]}
|
|
1914
|
-
cases:
|
|
1915
|
-
- id: case-1
|
|
1916
|
-
date: "2026-10-25"
|
|
1917
|
-
source: owner
|
|
1918
|
-
quote: "apps on Grammar write layout-only CSS; every visual element lives in @starci/grammar"
|
|
1919
|
-
ruling: "ANATOMY-2 owns contextual field defaults, PADDING-0 owns panel list alignment, and COLLECTION-3 owns composite member avatars for conversation and group identity. Grammar supplies these capabilities; the FE canon rejects explicit primary fields inside surfaces, raw app surface paint and stacked horizontal list-wrapper padding."
|
|
1920
1940
|
- id: R94
|
|
1921
1941
|
code: "FE_SLOT_FILE_ROLE"
|
|
1922
1942
|
law: "A front-end file is owned by a slot and named by it: a slot that owns a directory (route, feature, components, hooks, api module) holds only the files its `allows` list names, and holds them inside a folder of its own."
|
|
@@ -4978,27 +4998,27 @@ rules:
|
|
|
4978
4998
|
|
|
4979
4999
|
- id: R286
|
|
4980
5000
|
code: "FE_COPY_IN_CALL"
|
|
4981
|
-
law: "
|
|
5001
|
+
law: "Validation and toast copy comes from the translation catalog, including validation messages, titles and descriptions. Browser alert calls are forbidden. Inline vector glyphs belong only to declared brand-mark owners; ordinary icons use the selected Grammar icon owner and its declared glyph family."
|
|
4982
5002
|
kinds: [lint]
|
|
4983
5003
|
gates: [pre-commit, settle, land, ci]
|
|
4984
5004
|
failureCodes: ["FE_COPY_IN_CALL", "FE_NO_ALERT", "FE_ICON_INLINE_SVG"]
|
|
4985
5005
|
enforcers:
|
|
4986
5006
|
- {kind: eslint-fe, id: no-copy-in-call}
|
|
4987
5007
|
- {kind: eslint-fe, id: no-alert}
|
|
4988
|
-
- {kind: eslint-
|
|
5008
|
+
- {kind: eslint-grammar-starci, id: no-inline-svg-outside-brand-mark-leaf}
|
|
4989
5009
|
editions: [lite, full]
|
|
4990
|
-
docs: [docs/quality-bar.md#r286]
|
|
5010
|
+
docs: [docs/quality-bar.md#r286, knowledge/patterns/fe/index.yaml#FE-RULE-OWNERSHIP]
|
|
4991
5011
|
exemplifiedBy:
|
|
4992
5012
|
- {path: packages/eslint/fe/translation.spec.mjs, editions: [lite, full], codes: [FE_COPY_IN_CALL, FE_NO_ALERT]}
|
|
4993
|
-
- {path: packages/eslint/
|
|
5013
|
+
- {path: packages/eslint/grammar-starci/icon.spec.mjs, editions: [lite, full], codes: [FE_ICON_INLINE_SVG]}
|
|
4994
5014
|
- {path: packages/hfs/templates/fe/skeleton/apps/__app__/src/components/leaves/Icon/index.tsx, editions: [lite, full]}
|
|
4995
5015
|
- {path: packages/hfs/templates/fe/skeleton/apps/__app__/src/modules/toast, editions: [lite, full]}
|
|
4996
5016
|
proves:
|
|
4997
5017
|
- {path: packages/eslint/fe/translation.spec.mjs, editions: [lite, full], codes: [FE_COPY_IN_CALL, FE_NO_ALERT]}
|
|
4998
|
-
- {path: packages/eslint/
|
|
5018
|
+
- {path: packages/eslint/grammar-starci/icon.spec.mjs, editions: [lite, full], codes: [FE_ICON_INLINE_SVG]}
|
|
4999
5019
|
witness:
|
|
5000
5020
|
- {path: packages/eslint/fe/translation.spec.mjs, editions: [lite, full], codes: [FE_COPY_IN_CALL, FE_NO_ALERT]}
|
|
5001
|
-
- {path: packages/eslint/
|
|
5021
|
+
- {path: packages/eslint/grammar-starci/icon.spec.mjs, editions: [lite, full], codes: [FE_ICON_INLINE_SVG]}
|
|
5002
5022
|
|
|
5003
5023
|
- id: R287
|
|
5004
5024
|
code: "FE_CALLBACK_SHAPE"
|
|
@@ -5021,21 +5041,21 @@ rules:
|
|
|
5021
5041
|
|
|
5022
5042
|
- id: R288
|
|
5023
5043
|
code: "FE_STACK_UNLISTED"
|
|
5024
|
-
law: "Every direct FE workspace dependency belongs to knowledge/hfs/fe-stack.yaml or is declared in hfs.json fe.extraPackages with its name and a nonempty reason. Installed runtime dependencies carried by a listed Grammar package are not app declarations and raise no FE_STACK_UNLISTED; direct forbidden dependencies still raise FE_STACK_FORBIDDEN. Every product Next app declares the catalog's core runtime packages; codegen, lint, TypeScript and Tailwind tools may be installed once at the app root. The marketing landing app is exempt (lite and full) from core presence. GraphQL documents, including gql templates, match the back-end contracts, and SWR keys carry fetcher identities without an opt-in declaration."
|
|
5044
|
+
law: "Every direct FE workspace dependency belongs to knowledge/hfs/fe-stack.yaml or is declared in hfs.json fe.extraPackages with its name and a nonempty reason. Installed runtime dependencies carried by a listed Grammar package are not app declarations and raise no FE_STACK_UNLISTED; direct forbidden dependencies still raise FE_STACK_FORBIDDEN. Every product Next app declares the catalog's core runtime packages; codegen, lint, TypeScript and Tailwind tools may be installed once at the app root. The marketing landing app is exempt (lite and full) from core presence. A front end that selects sides.fe.grammar and declares @starci/eslint-canon-fe 9 or later also declares that family's lint package from knowledge/grammars/index.yaml, which carries its Grammar component rules (FE_STACK_FAMILY_LINT_MISSING). GraphQL documents, including gql templates, match the back-end contracts, and SWR keys carry fetcher identities without an opt-in declaration."
|
|
5025
5045
|
kinds: [check]
|
|
5026
5046
|
gates: [settle, land, ci]
|
|
5027
|
-
failureCodes: ["FE_STACK_UNLISTED", "FE_STACK_CORE_MISSING"]
|
|
5047
|
+
failureCodes: ["FE_STACK_UNLISTED", "FE_STACK_CORE_MISSING", "FE_STACK_FAMILY_LINT_MISSING"]
|
|
5028
5048
|
enforcers:
|
|
5029
5049
|
- {kind: hfs, id: fe-stack-allowlist, at: scripts/hfs/rules/fe-stack.mjs}
|
|
5030
5050
|
editions: [lite, full]
|
|
5031
5051
|
docs: [docs/quality-bar.md#r288]
|
|
5032
5052
|
proves:
|
|
5033
|
-
- {path: packages/hfs/src/hfs-fe-stack.spec.mjs, editions: [lite, full], codes: [FE_STACK_UNLISTED, FE_STACK_CORE_MISSING]}
|
|
5053
|
+
- {path: packages/hfs/src/hfs-fe-stack.spec.mjs, editions: [lite, full], codes: [FE_STACK_UNLISTED, FE_STACK_CORE_MISSING, FE_STACK_FAMILY_LINT_MISSING]}
|
|
5034
5054
|
exemplifiedBy:
|
|
5035
5055
|
- {path: packages/hfs/templates/fe/app/package.json.tpl, editions: [lite, full]}
|
|
5036
|
-
- {path: packages/hfs/src/hfs-fe-stack.spec.mjs, editions: [lite, full], codes: [FE_STACK_UNLISTED, FE_STACK_CORE_MISSING]}
|
|
5056
|
+
- {path: packages/hfs/src/hfs-fe-stack.spec.mjs, editions: [lite, full], codes: [FE_STACK_UNLISTED, FE_STACK_CORE_MISSING, FE_STACK_FAMILY_LINT_MISSING]}
|
|
5037
5057
|
witness:
|
|
5038
|
-
- {path: packages/hfs/src/hfs-fe-stack.spec.mjs, editions: [lite, full], codes: [FE_STACK_UNLISTED, FE_STACK_CORE_MISSING]}
|
|
5058
|
+
- {path: packages/hfs/src/hfs-fe-stack.spec.mjs, editions: [lite, full], codes: [FE_STACK_UNLISTED, FE_STACK_CORE_MISSING, FE_STACK_FAMILY_LINT_MISSING]}
|
|
5039
5059
|
- id: R289
|
|
5040
5060
|
code: "BE_APP_ENV_REQUIRED"
|
|
5041
5061
|
law: "Every declared back-end app owns a tracked apps/<app>/src/<app>.env.ts exporting its typed environment interface and read<App>Env(env: EnvSource). main.ts constructs EnvSource once and delegates its reads to that reader, with no inline parsing. app.module.ts composes module lists only by spreading compose/<area>.ts groups; its own providers are limited to app-wide guards and filters."
|
|
@@ -5450,101 +5470,131 @@ rules:
|
|
|
5450
5470
|
templateNa: "A storage grant is declared per integration; the canon scaffolds none, and the presigned-upload examples of both editions are the reference."
|
|
5451
5471
|
- id: R313
|
|
5452
5472
|
code: "FE_APP_SHELL_FRAME"
|
|
5453
|
-
law: "FE-APP-SHELL-1 requires WorkspaceShell viewport=fixed to
|
|
5473
|
+
law: "FE-APP-SHELL-1 gives the selected Grammar shell ownership of the fixed application frame, navbar, subnav and sidebar, with independent navigation and content scroll; StarCi requires WorkspaceShell viewport=fixed with navigation resolving visibility to wide and navigationDrawer or a compactHeader containing a left Drawer with Sidebar presentation=drawer; application layout does not recreate this frame."
|
|
5454
5474
|
kinds: [lint, design]
|
|
5455
5475
|
gates: [pre-commit, settle, land, ci]
|
|
5456
5476
|
failureCodes: ["FE_APP_SHELL_FRAME"]
|
|
5457
5477
|
enforcers:
|
|
5458
|
-
- {kind: eslint-
|
|
5478
|
+
- {kind: eslint-grammar-starci, id: app-shell-frame}
|
|
5459
5479
|
editions: [lite, full]
|
|
5460
5480
|
docs:
|
|
5481
|
+
- knowledge/patterns/fe/index.yaml#FE-RULE-OWNERSHIP
|
|
5461
5482
|
- {path: knowledge/ui/composition/app-shell.yaml, editions: [lite, full]}
|
|
5462
5483
|
proves:
|
|
5463
|
-
- {path: packages/eslint/
|
|
5484
|
+
- {path: packages/eslint/grammar-starci/app-shell.spec.mjs, editions: [lite, full], codes: [FE_APP_SHELL_FRAME]}
|
|
5464
5485
|
exemplifiedBy:
|
|
5465
|
-
- {path: packages/eslint/
|
|
5486
|
+
- {path: packages/eslint/grammar-starci/app-shell.spec.mjs, editions: [lite, full], codes: [FE_APP_SHELL_FRAME]}
|
|
5466
5487
|
- {path: examples/full-app/fe/apps/app/src/features/layouts/ShopLayout/component.tsx, edition: full}
|
|
5467
5488
|
- {path: examples/lite-app/fe/apps/web/src/features/layouts/WorkspaceLayout/component.tsx, edition: lite}
|
|
5468
5489
|
witness:
|
|
5469
|
-
- {path: packages/eslint/
|
|
5490
|
+
- {path: packages/eslint/grammar-starci/app-shell.spec.mjs, editions: [lite, full], codes: [FE_APP_SHELL_FRAME]}
|
|
5470
5491
|
templateNa: "The app composes its shell from product destinations and identity; full and lite example shells provide the reference."
|
|
5471
5492
|
- id: R314
|
|
5472
5493
|
code: "FE_NAVBAR_CONTROL_SIZE"
|
|
5473
|
-
law: "FE-APP-SHELL-2
|
|
5494
|
+
law: "FE-APP-SHELL-2 keeps navbar controls at one common height and icons at one size per region from the selected Grammar scale; the Grammar owns their concrete values."
|
|
5474
5495
|
kinds: [lint, design]
|
|
5475
5496
|
gates: [pre-commit, settle, land, ci]
|
|
5476
5497
|
failureCodes: ["FE_NAVBAR_CONTROL_SIZE"]
|
|
5477
5498
|
enforcers:
|
|
5478
|
-
- {kind: eslint-
|
|
5499
|
+
- {kind: eslint-grammar-starci, id: navbar-control-size}
|
|
5479
5500
|
editions: [lite, full]
|
|
5480
5501
|
docs:
|
|
5502
|
+
- knowledge/patterns/fe/index.yaml#FE-RULE-OWNERSHIP
|
|
5481
5503
|
- {path: knowledge/ui/composition/app-shell.yaml, editions: [lite, full]}
|
|
5482
5504
|
proves:
|
|
5483
|
-
- {path: packages/eslint/
|
|
5505
|
+
- {path: packages/eslint/grammar-starci/app-shell.spec.mjs, editions: [lite, full], codes: [FE_NAVBAR_CONTROL_SIZE]}
|
|
5484
5506
|
exemplifiedBy:
|
|
5485
|
-
- {path: packages/eslint/
|
|
5507
|
+
- {path: packages/eslint/grammar-starci/app-shell.spec.mjs, editions: [lite, full], codes: [FE_NAVBAR_CONTROL_SIZE]}
|
|
5486
5508
|
- {path: examples/full-app/fe/packages/ecommerce-ui/src/branches/WorkspaceNavbar/component.tsx, edition: full}
|
|
5487
5509
|
- {path: examples/lite-app/fe/apps/web/src/components/branches/Navbar/component.tsx, edition: lite}
|
|
5488
5510
|
witness:
|
|
5489
|
-
- {path: packages/eslint/
|
|
5511
|
+
- {path: packages/eslint/grammar-starci/app-shell.spec.mjs, editions: [lite, full], codes: [FE_NAVBAR_CONTROL_SIZE]}
|
|
5490
5512
|
templateNa: "The app composes its shell from product destinations and identity; full and lite example shells provide the reference."
|
|
5491
5513
|
- id: R315
|
|
5492
5514
|
code: "FE_NAVBAR_CLUSTER"
|
|
5493
|
-
law: "FE-APP-SHELL-3
|
|
5515
|
+
law: "FE-APP-SHELL-3 orders the navbar controls as language, theme, notifications and account, with each control and its overlay supplied by the selected Grammar."
|
|
5494
5516
|
kinds: [lint, design]
|
|
5495
5517
|
gates: [pre-commit, settle, land, ci]
|
|
5496
5518
|
failureCodes: ["FE_NAVBAR_CLUSTER"]
|
|
5497
5519
|
enforcers:
|
|
5498
|
-
- {kind: eslint-
|
|
5520
|
+
- {kind: eslint-grammar-starci, id: navbar-cluster}
|
|
5499
5521
|
editions: [lite, full]
|
|
5500
5522
|
docs:
|
|
5523
|
+
- knowledge/patterns/fe/index.yaml#FE-RULE-OWNERSHIP
|
|
5501
5524
|
- {path: knowledge/ui/composition/app-shell.yaml, editions: [lite, full]}
|
|
5502
5525
|
proves:
|
|
5503
|
-
- {path: packages/eslint/
|
|
5526
|
+
- {path: packages/eslint/grammar-starci/app-shell.spec.mjs, editions: [lite, full], codes: [FE_NAVBAR_CLUSTER]}
|
|
5504
5527
|
exemplifiedBy:
|
|
5505
|
-
- {path: packages/eslint/
|
|
5528
|
+
- {path: packages/eslint/grammar-starci/app-shell.spec.mjs, editions: [lite, full], codes: [FE_NAVBAR_CLUSTER]}
|
|
5506
5529
|
- {path: examples/full-app/fe/packages/ecommerce-ui/src/branches/WorkspaceNavbar/component.tsx, edition: full}
|
|
5507
5530
|
- {path: examples/lite-app/fe/apps/web/src/components/branches/Navbar/component.tsx, edition: lite}
|
|
5508
5531
|
witness:
|
|
5509
|
-
- {path: packages/eslint/
|
|
5532
|
+
- {path: packages/eslint/grammar-starci/app-shell.spec.mjs, editions: [lite, full], codes: [FE_NAVBAR_CLUSTER]}
|
|
5510
5533
|
templateNa: "The app composes its shell from product destinations and identity; full and lite example shells provide the reference."
|
|
5511
5534
|
- id: R316
|
|
5512
5535
|
code: "FE_APP_SHELL_BOTTOM_TABS"
|
|
5513
|
-
law: "FE-APP-SHELL-4
|
|
5536
|
+
law: "FE-APP-SHELL-4 preserves the selected Grammar shell navigation model across viewports; an application does not replace its sidebar-derived mobile drawer with an incompatible bottom tab bar."
|
|
5514
5537
|
kinds: [lint, design]
|
|
5515
5538
|
gates: [pre-commit, settle, land, ci]
|
|
5516
5539
|
failureCodes: ["FE_APP_SHELL_BOTTOM_TABS"]
|
|
5517
5540
|
enforcers:
|
|
5518
|
-
- {kind: eslint-
|
|
5541
|
+
- {kind: eslint-grammar-starci, id: no-shell-bottom-tabs}
|
|
5519
5542
|
editions: [lite, full]
|
|
5520
5543
|
docs:
|
|
5544
|
+
- knowledge/patterns/fe/index.yaml#FE-RULE-OWNERSHIP
|
|
5521
5545
|
- {path: knowledge/ui/composition/app-shell.yaml, editions: [lite, full]}
|
|
5522
5546
|
proves:
|
|
5523
|
-
- {path: packages/eslint/
|
|
5547
|
+
- {path: packages/eslint/grammar-starci/app-shell.spec.mjs, editions: [lite, full], codes: [FE_APP_SHELL_BOTTOM_TABS]}
|
|
5524
5548
|
exemplifiedBy:
|
|
5525
|
-
- {path: packages/eslint/
|
|
5549
|
+
- {path: packages/eslint/grammar-starci/app-shell.spec.mjs, editions: [lite, full], codes: [FE_APP_SHELL_BOTTOM_TABS]}
|
|
5526
5550
|
- {path: examples/full-app/fe/apps/app/src/features/layouts/ShopLayout/component.tsx, edition: full}
|
|
5527
5551
|
- {path: examples/lite-app/fe/apps/web/src/features/layouts/WorkspaceLayout/component.tsx, edition: lite}
|
|
5528
5552
|
witness:
|
|
5529
|
-
- {path: packages/eslint/
|
|
5553
|
+
- {path: packages/eslint/grammar-starci/app-shell.spec.mjs, editions: [lite, full], codes: [FE_APP_SHELL_BOTTOM_TABS]}
|
|
5530
5554
|
templateNa: "The app composes its shell from product destinations and identity; full and lite example shells provide the reference."
|
|
5531
5555
|
- id: R317
|
|
5532
5556
|
code: "FE_NAVBAR_CREATE"
|
|
5533
|
-
law: "FE-APP-SHELL-5 places create actions on
|
|
5557
|
+
law: "FE-APP-SHELL-5 places create actions on the page that owns them and keeps them out of the global navbar."
|
|
5534
5558
|
kinds: [lint, design]
|
|
5535
5559
|
gates: [pre-commit, settle, land, ci]
|
|
5536
5560
|
failureCodes: ["FE_NAVBAR_CREATE"]
|
|
5537
5561
|
enforcers:
|
|
5538
|
-
- {kind: eslint-
|
|
5562
|
+
- {kind: eslint-grammar-starci, id: no-navbar-create}
|
|
5539
5563
|
editions: [lite, full]
|
|
5540
5564
|
docs:
|
|
5565
|
+
- knowledge/patterns/fe/index.yaml#FE-RULE-OWNERSHIP
|
|
5541
5566
|
- {path: knowledge/ui/composition/app-shell.yaml, editions: [lite, full]}
|
|
5542
5567
|
proves:
|
|
5543
|
-
- {path: packages/eslint/
|
|
5568
|
+
- {path: packages/eslint/grammar-starci/app-shell.spec.mjs, editions: [lite, full], codes: [FE_NAVBAR_CREATE]}
|
|
5544
5569
|
exemplifiedBy:
|
|
5545
|
-
- {path: packages/eslint/
|
|
5570
|
+
- {path: packages/eslint/grammar-starci/app-shell.spec.mjs, editions: [lite, full], codes: [FE_NAVBAR_CREATE]}
|
|
5546
5571
|
- {path: examples/full-app/fe/packages/ecommerce-ui/src/branches/WorkspaceNavbar/component.tsx, edition: full}
|
|
5547
5572
|
- {path: examples/lite-app/fe/apps/web/src/components/branches/Navbar/component.tsx, edition: lite}
|
|
5548
5573
|
witness:
|
|
5549
|
-
- {path: packages/eslint/
|
|
5574
|
+
- {path: packages/eslint/grammar-starci/app-shell.spec.mjs, editions: [lite, full], codes: [FE_NAVBAR_CREATE]}
|
|
5550
5575
|
templateNa: "The app composes its shell from product destinations and identity; full and lite example shells provide the reference."
|
|
5576
|
+
- id: R318
|
|
5577
|
+
code: "FE_NESTED_VARIANT"
|
|
5578
|
+
law: "Apps compose Grammar with layout-only CSS; paint utilities, arbitrary paint properties and inline style paint belong to Grammar. Grammar context owns all layer-aware field variants, nested Tabs defaults and the content edge of panel lists; apps omit static field variants, do not force primary Tabs inside a painted surface, do not paint raw surfaces, and add no horizontal list-wrapper padding within the nearest painted Grammar surface."
|
|
5579
|
+
kinds: [lint, design]
|
|
5580
|
+
gates: [pre-commit, settle, land, ci]
|
|
5581
|
+
failureCodes: ["FE_NESTED_VARIANT", "FE_LIST_PANEL_PADDING", "FE_GRAMMAR_LAYOUT_ONLY"]
|
|
5582
|
+
enforcers:
|
|
5583
|
+
- {kind: eslint-fe, id: nested-control-variant}
|
|
5584
|
+
- {kind: eslint-fe, id: no-list-panel-padding}
|
|
5585
|
+
- {kind: eslint-fe, id: no-app-surface-paint}
|
|
5586
|
+
editions: [lite, full]
|
|
5587
|
+
docs: ["docs/code-pattern-enforcement.md#r318-app-grammar-composition"]
|
|
5588
|
+
templateNa: "Product composition is proved by the FE canon's Grammar import and surface fixtures; a template cannot choose product slots or lists."
|
|
5589
|
+
proves:
|
|
5590
|
+
- {path: packages/eslint/fe/surface-rules.spec.mjs, editions: [lite, full], codes: [FE_NESTED_VARIANT, FE_LIST_PANEL_PADDING, FE_GRAMMAR_LAYOUT_ONLY]}
|
|
5591
|
+
exemplifiedBy:
|
|
5592
|
+
- {path: packages/eslint/fe/surface-rules.spec.mjs, editions: [lite, full], codes: [FE_NESTED_VARIANT, FE_LIST_PANEL_PADDING, FE_GRAMMAR_LAYOUT_ONLY]}
|
|
5593
|
+
witness:
|
|
5594
|
+
- {path: packages/eslint/fe/surface-rules.spec.mjs, editions: [lite, full], codes: [FE_NESTED_VARIANT, FE_LIST_PANEL_PADDING, FE_GRAMMAR_LAYOUT_ONLY]}
|
|
5595
|
+
cases:
|
|
5596
|
+
- id: case-1
|
|
5597
|
+
date: "2026-10-25"
|
|
5598
|
+
source: owner
|
|
5599
|
+
quote: "apps on Grammar write layout-only CSS; every visual element lives in @starci/grammar"
|
|
5600
|
+
ruling: "ANATOMY-2 owns contextual field defaults, PADDING-0 owns panel list alignment, and COLLECTION-3 owns composite member avatars for conversation and group identity. Grammar supplies these capabilities; the FE canon rejects static field variants on either layer, primary Tabs inside painted surfaces, raw app surface paint and stacked horizontal list-wrapper padding inside painted surfaces."
|
|
@@ -2396,9 +2396,9 @@ slots:
|
|
|
2396
2396
|
presence: required
|
|
2397
2397
|
tracked: tracked
|
|
2398
2398
|
tier: foundation
|
|
2399
|
-
# The app's
|
|
2400
|
-
#
|
|
2401
|
-
#
|
|
2399
|
+
# The app's routing, request config and catalogs, or its adapter to the shared i18n factory. A single app
|
|
2400
|
+
# owns createNavigation in fe.modules.routes, keeping this public entry safe for its proxy. Shared stacks
|
|
2401
|
+
# belong to fe.package.i18n and expose a routing-only proxy entry separately from navigation.
|
|
2402
2402
|
requires: [index.ts]
|
|
2403
2403
|
tests: none
|
|
2404
2404
|
rules: [FE_I18N_PLACEMENT, FE_I18N_CATALOG]
|