@starci/eslint-canon-fe 9.16.0 → 9.16.2

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 CHANGED
@@ -1,5 +1,13 @@
1
1
  # Changelog
2
2
 
3
+ ## 9.16.2 - 2026-11-07
4
+
5
+ - A patch: peers `@starci/hfs` ~6.0.0. Comments, rule docs and messages cite rules by their ids and carry no ruling history; the counting cohort entries carry no ruling field.
6
+
7
+ ## 9.16.1 - 2026-11-07
8
+
9
+ - A patch: `starci-fe/control-height` no longer names `SegmentedControl` (removed from `@starci/grammar` 0.24.0); the controls it holds to the one 40px height are Button, IconButton, Switch, Input, SearchField, Select, Tabs, Textarea, NumberField and ComboBox. Its docs follow.
10
+
3
11
  ## 9.16.0 - 2026-11-06
4
12
 
5
13
  - Added: `starci-fe/renderer-presentation-only` (R384, `FE_RENDERER_LOGIC`, RENDERER-PURITY-1) at error: in a client renderer of a root workspace package (`packages/<pkg>/src/client/**/*.tsx`) data computation (arithmetic between two data values, `+=` accumulation), aggregation (`reduce`, a chain of `filter`/`sort`/`flatMap`, `Math.max/min(...spread)`), date math (`Date.now()`/`getTime()` arithmetic, Date setters, date-fns add/sub/diff/compare/round), a relational comparison of two data values and a mutation outside a declared action (a write to a prop or an outer value, an in-place array mutator on data, `fetch`, storage, a beacon) are refused; they belong in a measured `.ts` module the renderer calls. Mapping, display filters, ternaries that pick a view, comparisons and arithmetic with a literal and `handle.run(...)` stay allowed. A front-end package (`fe/packages/*`) is not judged by it.
@@ -10,11 +18,11 @@
10
18
 
11
19
  ## 9.15.0 - 2026-11-05
12
20
 
13
- - Changed (decision release-only-what-changed): the canon reads the @starci/hfs runtime from the installed hfs at run time, which it peers by `~5.13.0`, and bundles no copy; `runtime/` keeps only the project graph rule, the jsdoc, sonar and next helpers and the package-scripts template, and the stale forks (slots 3.13.0) are gone.
21
+ - Changed: the canon reads the @starci/hfs runtime from the installed hfs at run time, which it peers by `~5.13.0`, and bundles no copy; `runtime/` keeps only the project graph rule, the jsdoc, sonar and next helpers and the package-scripts template, and the stale forks (slots 3.13.0) are gone.
14
22
 
15
23
  ## 9.14.4 - 2026-11-05
16
24
 
17
- - Changed: the runtime copy of the canon pins gives the Grammar family its same-minor range (decision grammar-patch-range) and names `@starci/hfs` 5.12.0 and the Grammar family 0.22.0.
25
+ - Changed: the runtime copy of the canon pins gives the Grammar family its same-minor range and names `@starci/hfs` 5.12.0 and the Grammar family 0.22.0.
18
26
 
19
27
  ## 9.14.3 - 2026-11-05
20
28
 
@@ -245,8 +253,8 @@
245
253
  ## 9.6.3 - 2026-10-31
246
254
 
247
255
  - Changed: the bundled canon pins name the 0.16.3 cohort (@starci/grammar, eslint-grammar-core and eslint-grammar-offset-pop 0.16.3, eslint-canon-fe 9.6.3, eslint-canon-be 3.9.3, stylelint-canon 2.3.0, jest-preset 2.6.0, hfs 4.13.0); ChatWorkspace and PaneLayout are removed with no alias; PaneGrid and Pane are the one generic pane grid: grammar names are generic. The surface-rules spec uses PaneGrid.
248
- - Added: lib/freestyle (`exemptFreestyle`, `freestyleContext`): no-arbitrary-value, no-app-surface-paint, no-raw-brand-value, no-list-panel-padding, no-inline-class-name and no-native-img do not report the raw elements inside a `<Freestyle>` subtree of the same file; a Grammar component inside it is judged as before (owner ruling grammar-freestyle-region). Specs: src/freestyle.spec.ts.
249
- - Added: the lint result cache of `starci app check` (ruling app-check-cache): `crossFileInputs`, the files and folders each rule reads beyond the linted file (an fs-audit spec proves every rule declares what it reads), and the `projectGraph` export the cache keys a file's lint record on.
256
+ - Added: lib/freestyle (`exemptFreestyle`, `freestyleContext`): no-arbitrary-value, no-app-surface-paint, no-raw-brand-value, no-list-panel-padding, no-inline-class-name and no-native-img do not report the raw elements inside a `<Freestyle>` subtree of the same file; a Grammar component inside it is judged as before. Specs: src/freestyle.spec.ts.
257
+ - Added: the lint result cache of `starci app check`: `crossFileInputs`, the files and folders each rule reads beyond the linted file (an fs-audit spec proves every rule declares what it reads), and the `projectGraph` export the cache keys a file's lint record on.
250
258
 
251
259
  ## 9.6.2 - 2026-10-31
252
260
 
@@ -339,7 +347,7 @@
339
347
 
340
348
  ## 9.5.4 - 2026-10-29
341
349
 
342
- - Changed: the bundled slot manifest 3.13.0 admits `pgmq` in `ruleParams.db.extensions` (the lite event bus, ruling lite-pgmq-bus-bullmq-jobs), retires `ruleParams.db.queueOutbox` and `sides.be.queueOutbox` with the pg_cron half of R258, lists `public.event_bus_send`, `public.event_bus_read`, `public.event_bus_archive`, `public.event_bus_bury`, `public.event_bus_dead_letters` and `public.event_bus_requeue` in place of `public.event_bus_write` in `ruleParams.be.dbFunctions`, and moves slot `app.db.image` to `.starcistacks/images/db/Dockerfile` (ruling lite-db-image-in-stacks, admitted by the lite `app.starcistacks` allows); the bundled rule catalog keeps R258 `DB_PGMQ_DECLARED` as the event-bus law, retires `DB_CRON_OWNED` and adds R336 `BE_EVENT_BUS_LITE_SHAPE`; the bundled canon pins name hfs 4.11.3, eslint-canon-be 3.8.2, eslint-canon-fe 9.5.4 and the Grammar family 0.15.15. No front-end rule changed.
350
+ - Changed: the bundled slot manifest 3.13.0 admits `pgmq` in `ruleParams.db.extensions` (the lite event bus), retires `ruleParams.db.queueOutbox` and `sides.be.queueOutbox` with the pg_cron half of R258, lists `public.event_bus_send`, `public.event_bus_read`, `public.event_bus_archive`, `public.event_bus_bury`, `public.event_bus_dead_letters` and `public.event_bus_requeue` in place of `public.event_bus_write` in `ruleParams.be.dbFunctions`, and moves slot `app.db.image` to `.starcistacks/images/db/Dockerfile` (admitted by the lite `app.starcistacks` allows); the bundled rule catalog keeps R258 `DB_PGMQ_DECLARED` as the event-bus law, retires `DB_CRON_OWNED` and adds R336 `BE_EVENT_BUS_LITE_SHAPE`; the bundled canon pins name hfs 4.11.3, eslint-canon-be 3.8.2, eslint-canon-fe 9.5.4 and the Grammar family 0.15.15. No front-end rule changed.
343
351
 
344
352
  ## 9.5.3 - 2026-10-29
345
353
 
@@ -411,12 +419,12 @@
411
419
 
412
420
  ## 9.3.0 - 2026-10-28
413
421
 
414
- - Changed (breaking for apps): owner ruling fe-shape-not-state. A pure half takes `{ shape?, props, on? }`; `base-props-atom` refuses the retired `state` key with a message naming the rename, and `no-data-status-shape` reads `XShape` unions (and still the old `XState` names, so a status word is caught during the rename).
422
+ - Changed (breaking for apps): a pure half takes `{ shape?, props, on? }`; `base-props-atom` refuses the retired `state` key with a message naming the rename, and `no-data-status-shape` reads `XShape` unions (and still the old `XState` names, so a status word is caught during the rename).
415
423
  - Changed: the bundled runtime copies follow the retirement of `@starci/cli`: the bundled canon pins replace the retired `@starci/cli` with `starci-harness` 1.1.0-alpha.1 (`source: cli/package.json`), the one command line a product installs for `starci app`, and follow the harness packages (Grammar family 0.14.0, hfs 4.9.0, canon-fe 9.3.0, canon-be 3.5.0); the runtime finds an app's `starci` bin in its installed `starci-harness`.
416
424
 
417
425
  ## 9.2.0 - 2026-10-27
418
426
 
419
- - Changed: owner ruling two-grammars: the bundled Grammar catalog declares exactly two families, `core` (`@starci/eslint-grammar-core`, `coreGrammarConfig`) and `offset-pop`; `starci`, `starci-core` and `heritage` are refused. The Grammar entry checks (button intent, control height, surface rules, UI rulings) accept `@starci/grammar/<common|core|offset-pop>`. The bundled canon pins follow the harness packages (Grammar family 0.13.0, hfs 4.8.0, canon-fe 9.2.0, canon-be 3.4.57, stylelint-canon 2.1.0).
427
+ - Changed: the bundled Grammar catalog declares exactly two families, `core` (`@starci/eslint-grammar-core`, `coreGrammarConfig`) and `offset-pop`; `starci`, `starci-core` and `heritage` are refused. The Grammar entry checks (button intent, control height, surface rules, UI rulings) accept `@starci/grammar/<common|core|offset-pop>`. The bundled canon pins follow the harness packages (Grammar family 0.13.0, hfs 4.8.0, canon-fe 9.2.0, canon-be 3.4.57, stylelint-canon 2.1.0).
420
428
  - Changed: the doc comment of `lint-escape-hatch.mjs` names the three patterns that own the refused spellings instead of spelling them again. No rule or behaviour changed.
421
429
 
422
430
  ## 9.1.11 - 2026-10-27
@@ -430,7 +438,7 @@
430
438
  ## 9.1.9 - 2026-10-26
431
439
 
432
440
  - Added: starci-fe/control-height (R320 FE_CONTROL_HEIGHT), selection-fill-no-check and no-grammar-internal-selector.
433
- - Changed: the bundled runtime copies carry the light push gate and the owner rulings of 2026-10-26.
441
+ - Changed: the bundled runtime copies carry the light push gate.
434
442
 
435
443
  ## 9.1.8 - 2026-10-26
436
444
 
@@ -523,7 +531,7 @@
523
531
  ## 8.4.30 - 2026-10-23
524
532
  - Changed: the bundled canon pins select @starci/hfs 4.7.24 and @starci/cli 1.7.24.
525
533
  - Added: the type-aware rules the back end already borrowed, at error: `@typescript-eslint/no-floating-promises`, `no-misused-promises`, `switch-exhaustiveness-check` and the `no-unsafe-assignment`, `-member-access`, `-call`, `-return`, `-argument` family.
526
- - Changed: no Sonar way rule is left to the server (owner ruling 2026-10-22, no loosening): S3403, S3800, S3782 and S6582 run at error, `unicorn/consistent-function-scoping` runs with its default options, and S7785 (`unicorn/prefer-top-level-await`) runs in the front end (ESM).
534
+ - Changed: no Sonar way rule is left to the server (no loosening): S3403, S3800, S3782 and S6582 run at error, `unicorn/consistent-function-scoping` runs with its default options, and S7785 (`unicorn/prefer-top-level-await`) runs in the front end (ESM).
527
535
  - Added: `starciPlainSourceConfig({ root })` for a TypeScript front-end tree that is no HFS app (a runtime package, the harness UI): typed linting, the inline-directive fence, the React Hooks, type-aware and Sonar way rules and every canon rule that needs no slot view (`SLOT_FREE_RULES`), all at error.
528
536
 
529
537
  ## 8.4.29 - 2026-10-22
@@ -612,9 +620,9 @@
612
620
 
613
621
  ## 8.4.1 - 2026-10-17
614
622
 
615
- - Changed: the bundled runtime copies follow the runtime of 1.0.0-alpha.19 (owner ruling no-runtime-specs, 2026-10-17): the failure codes, the slot manifest (`exampleNa`) and the rule catalog (`specNa`, `exampleNa`) carry the removal of the runtime's own specs; package behavior is unchanged.
616
- - Changed (R287 `FE_CALLBACK_SHAPE`, a18.1 NIVO request F2, owner ruling `auth-callback-pure-helpers`): the auth callback may call pure text helpers of the app's `modules/routes` or `modules/auth` (`requestOrigin`, `safeNextPath`; resolved by TypeScript symbol: synchronous, no await, no I/O global, only owner helpers and `modules/config` readers), use static route tables (`AUTH_ROUTES`), and read the exchange outcome's `success` or `ok` flag. An impure, async or non-text helper, a helper outside those owners and a credential passed to a helper are still refused.
617
- - Changed (R287 `FE_CALLBACK_SHAPE`, a18.1 NIVO request F, owner ruling `auth-callback-email-link`): the auth callback may await one `verifyOtp({ token_hash, type })` of the auth owner (`auth.verifyOtp` or `verifyOtp` from `modules/auth/server`), built from exactly the query values `token_hash` and `type`, beside the one `exchangeAuthCode(code)`; the token hash never reaches a redirect.
623
+ - Changed: the bundled runtime copies follow the runtime of 1.0.0-alpha.19: the failure codes, the slot manifest (`exampleNa`) and the rule catalog (`specNa`, `exampleNa`) carry the removal of the runtime's own specs; package behavior is unchanged.
624
+ - Changed (R287 `FE_CALLBACK_SHAPE`, a18.1 NIVO request F2): the auth callback may call pure text helpers of the app's `modules/routes` or `modules/auth` (`requestOrigin`, `safeNextPath`; resolved by TypeScript symbol: synchronous, no await, no I/O global, only owner helpers and `modules/config` readers), use static route tables (`AUTH_ROUTES`), and read the exchange outcome's `success` or `ok` flag. An impure, async or non-text helper, a helper outside those owners and a credential passed to a helper are still refused.
625
+ - Changed (R287 `FE_CALLBACK_SHAPE`, a18.1 NIVO request F): the auth callback may await one `verifyOtp({ token_hash, type })` of the auth owner (`auth.verifyOtp` or `verifyOtp` from `modules/auth/server`), built from exactly the query values `token_hash` and `type`, beside the one `exchangeAuthCode(code)`; the token hash never reaches a redirect.
618
626
  - Fixed (R55 `FE_CLIENT_BOUNDARY`, a18.1 NIVO request I): the finding on a page or layout owner now says the owner stays a server component that renders the client block or overlay carrying the directive. The rule is unchanged.
619
627
 
620
628
  ## 8.3.0 - 2026-10-15
@@ -635,11 +643,11 @@
635
643
 
636
644
  ## 8.2.16 - 2026-10-13
637
645
 
638
- - Changed: the heroicons family is the one application icon set again (owner ruling 2026-10-13): `heroicons-is-the-glyph-vendor` admits exactly `@heroicons/react/24/outline`, `@heroicons/react/16/solid` and the matching `@starci/heroicons` subpaths (read from the fe-stack `icons` concern), and refuses Phosphor and every other glyph catalogue, a package the catalog forbids included; `one-icon-set` (8.2.15) is gone. Only the Icon leaf and the toast module import a glyph. The bundled runtime mirror carries the fe-stack catalog and the canon pins with `@heroicons/react` 2.2.0 and `@starci/heroicons` 0.3.3.
646
+ - Changed: the heroicons family is the one application icon set again: `heroicons-is-the-glyph-vendor` admits exactly `@heroicons/react/24/outline`, `@heroicons/react/16/solid` and the matching `@starci/heroicons` subpaths (read from the fe-stack `icons` concern), and refuses Phosphor and every other glyph catalogue, a package the catalog forbids included; `one-icon-set` (8.2.15) is gone. Only the Icon leaf and the toast module import a glyph. The bundled runtime mirror carries the fe-stack catalog and the canon pins with `@heroicons/react` 2.2.0 and `@starci/heroicons` 0.3.3.
639
647
 
640
648
  ## 8.2.15 - 2026-10-13
641
649
 
642
- - Changed: carry the runtime mirror of HFS manifest 3.0.0 (one front-end standard for the lite and the full edition, owner ruling 2026-10-13) and the canon pins for Grammar 0.9.14, HFS 4.2.14, jest-preset 2.2.7 and CLI 1.2.14.
650
+ - Changed: carry the runtime mirror of HFS manifest 3.0.0 (one front-end standard for the lite and the full edition) and the canon pins for Grammar 0.9.14, HFS 4.2.14, jest-preset 2.2.7 and CLI 1.2.14.
643
651
  - Added: `fe-stack-import` (law `fe-stack`, finding code `FE_STACK_FORBIDDEN`): an import (static, re-export, dynamic, `require`, type-only included) of a package any concern of the fe-stack catalog (`runtime/knowledge/hfs/fe-stack.yaml`) forbids, and `@supabase/*` outside `modules/auth` (slot `fe.modules.auth`), are refused. The catalog is read from the runtime copy; a missing copy stops the lint run with the fix.
644
652
  - Changed: the transport law follows the Apollo GraphQL + axios API layer. `fetch` (and `Request`, `EventSource`, `sendBeacon`) is legal in every file of the API layer (`modules/api`, the shared api package), `@apollo/client` only there, `axios` only in its REST calls (`modules/api/rest/`), `socket.io-client` only in `hooks/socketio/` (`fetch-only-in-api-client`, message `placed`); `client-fetch-has-signal` and `no-shared-transport-state` judge the whole layer (the generated `graphql/__generated__/` excepted); `no-hand-typed-wire` admits GraphQL documents in the API layer (one file per operation) and refuses them elsewhere; `one-outcome-union` names `GraphQLResponse` in `modules/api/graphql/types.ts` as the one vocabulary and also reads a `success` discriminant. The `modules/db` outcome home and the server reader role are gone.
645
653
  - Changed: `hooks-folder-holds-hooks-only` judges the hooks families `hooks/{swr,rhf,zustand,socketio,effects,reuseables}` by the files their slots name (message `family`); `SwrSideEffects.tsx` and `SocketIoSideEffects.tsx` are legal `.tsx` files of `hooks/`.
@@ -3,7 +3,7 @@ import { attributeValue, stringOf } from "./lib/ast.js";
3
3
  import { importOf } from "./lib/bindings.js";
4
4
  import { defineRule } from "./lib/rule.js";
5
5
  const GRAMMAR_ENTRY = /^@starci\/grammar(?:\/(?:common|core|offset-pop))?$/;
6
- const CONTROLS = new Set(["Button", "IconButton", "Switch", "Input", "SearchField", "Select", "Tabs", "SegmentedControl", "Textarea", "NumberField", "ComboBox"]);
6
+ const CONTROLS = new Set(["Button", "IconButton", "Switch", "Input", "SearchField", "Select", "Tabs", "Textarea", "NumberField", "ComboBox"]);
7
7
  /** A marketing hero call to action on a landing page is the one place the 48px step is allowed. */
8
8
  const LANDING_PATH = /[\\/](?:landing|hero|marketing)[\\/]|(?:Landing|Hero)[^\\/]*[\\/]/;
9
9
  /** The default size and its two spellings: the vendor `md` and Grammar's `control` are the same 40px height. */
package/dist/drawing.js CHANGED
@@ -94,7 +94,7 @@ export const basePropsAtom = defineRule({
94
94
  action: "`{{path}}` is a function inside `props`. Actions live in `on`; feature composition may receive named `render` callbacks that take atoms and return rendered blocks.",
95
95
  onData: "`on.{{key}}` is not an action. `on` holds functions only; data belongs in `props`.",
96
96
  member: "`{{key}}` is not part of the pure contract. A pure half takes `shape`, `props` and `on`{{children}}.",
97
- renamed: "`state` is the retired name of the drawn shape: rename it `shape` (owner ruling fe-shape-not-state).",
97
+ renamed: "The drawn shape is named `shape`, never `state`: rename it `shape`.",
98
98
  },
99
99
  },
100
100
  create(context) {
@@ -11,7 +11,7 @@ export const functionLineBudget = defineRule({
11
11
  },
12
12
  },
13
13
  create(context) {
14
- // C08 adds this common parameter to the shipped manifest; keep the owner-decided cap while it lands.
14
+ // A manifest without `ruleParams.functionLines` gets the cap of 80 lines.
15
15
  const max = hfsOf(context).ruleParams.functionLines ?? 80;
16
16
  if (!Number.isInteger(max) || max < 1)
17
17
  throw new RangeError("ruleParams.functionLines must be a positive integer");
package/dist/index.d.ts CHANGED
@@ -38,7 +38,7 @@ export declare const rules: Record<string, Rule>;
38
38
  *
39
39
  * Every FE canon rule is an error. Existing debt is fixed before adoption; lowering architecture
40
40
  * to warn teaches every later author that the boundary is optional and is not a supported rollout. The one
41
- * exception is the closed counting cohort of lib/config.ts (`COUNTING`), an owner-ruled warn for one release.
41
+ * exception is the closed counting cohort of lib/config.ts (`COUNTING`), a warn for one release.
42
42
  */
43
43
  export declare const recommended: Record<string, "error" | "warn">;
44
44
  /** Flat-config options that make inline directives ineffective rather than merely forbidden. */
package/dist/index.js CHANGED
@@ -132,7 +132,7 @@ export const rules = Object.fromEntries(CONTRIBUTIONS.flatMap((entry) => Object.
132
132
  *
133
133
  * Every FE canon rule is an error. Existing debt is fixed before adoption; lowering architecture
134
134
  * to warn teaches every later author that the boundary is optional and is not a supported rollout. The one
135
- * exception is the closed counting cohort of lib/config.ts (`COUNTING`), an owner-ruled warn for one release.
135
+ * exception is the closed counting cohort of lib/config.ts (`COUNTING`), a warn for one release.
136
136
  */
137
137
  export const recommended = Object.fromEntries(CONTRIBUTIONS.flatMap((entry) => Object.entries(entry.recommended)));
138
138
  /** Flat-config options that make inline directives ineffective rather than merely forbidden. */
@@ -28,13 +28,12 @@ export declare const IGNORED: readonly string[];
28
28
  */
29
29
  export declare const BORROWED: Readonly<Record<string, "error">>;
30
30
  /**
31
- * The counting cohort: a rule the owner ruled to ship at `warn` for one release while a codemod moves apps onto the API
31
+ * The counting cohort: a rule that ships at `warn` for one release while a codemod moves apps onto the API
32
32
  * it asks for, each with the HFS rule id it enforces. `starci app check --gate lint` reports and counts its findings and never fails
33
33
  * on them; the next cohort moves the rule to error and deletes its entry. No other rule may be below error.
34
34
  */
35
35
  export declare const COUNTING: Readonly<Record<string, {
36
36
  readonly rule: string;
37
- readonly ruling: string;
38
37
  }>>;
39
38
  /**
40
39
  * The flat config of one front-end repository.
@@ -41,12 +41,12 @@ export const BORROWED = Object.freeze({
41
41
  });
42
42
  const levelOf = (setting) => (Array.isArray(setting) ? setting[0] : setting);
43
43
  /**
44
- * The counting cohort: a rule the owner ruled to ship at `warn` for one release while a codemod moves apps onto the API
44
+ * The counting cohort: a rule that ships at `warn` for one release while a codemod moves apps onto the API
45
45
  * it asks for, each with the HFS rule id it enforces. `starci app check --gate lint` reports and counts its findings and never fails
46
46
  * on them; the next cohort moves the rule to error and deletes its entry. No other rule may be below error.
47
47
  */
48
48
  export const COUNTING = Object.freeze({
49
- "starci-fe/no-spacing-utility": { rule: "R350", ruling: "spacing-roles" },
49
+ "starci-fe/no-spacing-utility": { rule: "R350" },
50
50
  });
51
51
  /**
52
52
  * The flat config of one front-end repository.
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * Resolve a `use*` import that comes from the app's own hooks folders (`hooks/swr`, `hooks/<domain>`, `hooks/zustand/<store>`...) by
3
- * TypeScript symbol resolution, never by the spelling of the name (R56 `FE_HOOKS_ARE_HOOKS`, owner ruling 2026-10-16 "Theo y tro").
3
+ * TypeScript symbol resolution, never by the spelling of the name (R56 `FE_HOOKS_ARE_HOOKS`).
4
4
  *
5
5
  * A composite product hook is built from the hooks beneath it: `hooks/<domain>/use<Name>.ts` composes the `use{Query,Mutate}<X>Swr`
6
6
  * wrappers of `hooks/swr`. The import is followed through barrels and re-exports to the declaration, and counts only when that declaration
@@ -2,7 +2,7 @@
2
2
  export declare const PACKAGE_ROOT: string;
3
3
  /**
4
4
  * The runtime of the installed @starci/hfs (its peer, a same-minor range): the slot manifest, the architecture machine and its catalogs are read from it
5
- * at run time, never from a copy bundled here, so an hfs data change releases hfs alone (decision release-only-what-changed).
5
+ * at run time, never from a copy bundled here, so an hfs data change releases hfs alone.
6
6
  */
7
7
  export declare const RUNTIME_ROOT: string;
8
8
  /** The files this package keeps of its own in runtime/ (the project graph rule, the jsdoc, sonar and next helpers, the package-scripts template). */
@@ -9,7 +9,7 @@ import { fileURLToPath } from "node:url";
9
9
  export const PACKAGE_ROOT = fileURLToPath(new URL("../..", import.meta.url));
10
10
  /**
11
11
  * The runtime of the installed @starci/hfs (its peer, a same-minor range): the slot manifest, the architecture machine and its catalogs are read from it
12
- * at run time, never from a copy bundled here, so an hfs data change releases hfs alone (decision release-only-what-changed).
12
+ * at run time, never from a copy bundled here, so an hfs data change releases hfs alone.
13
13
  */
14
14
  export const RUNTIME_ROOT = join(dirname(createRequire(import.meta.url).resolve("@starci/hfs/package.json")), "runtime");
15
15
  /** The files this package keeps of its own in runtime/ (the project graph rule, the jsdoc, sonar and next helpers, the package-scripts template). */
@@ -7,5 +7,5 @@ export declare const rules: {
7
7
  "selection-fill-no-check": import("./lib/rule.js").Rule<"indicator", []>;
8
8
  "no-grammar-internal-selector": import("./lib/rule.js").Rule<"internal", []>;
9
9
  };
10
- /** Both owner rulings are universal errors in the frontend canon. */
10
+ /** Both rules are universal errors in the frontend canon. */
11
11
  export declare const recommended: Recommended;
@@ -117,5 +117,5 @@ export const rules = {
117
117
  "selection-fill-no-check": selectionFillNoCheck,
118
118
  "no-grammar-internal-selector": noGrammarInternalSelector,
119
119
  };
120
- /** Both owner rulings are universal errors in the frontend canon. */
120
+ /** Both rules are universal errors in the frontend canon. */
121
121
  export const recommended = Object.fromEntries(Object.keys(rules).map((name) => [`starci-fe/${name}`, "error"]));
@@ -1,6 +1,6 @@
1
1
  # Control height (CONTROL-HEIGHT-1)
2
2
 
3
- Owner ruling `control-height-40` (2026-10-26). One control height, 40px (HeroUI's own `h-10`), is the default of every standalone Grammar control: Button, IconButton, Input, SearchField, Select, Tabs, SegmentedControl, Switch, the chrome Avatar, Textarea and the composer send button. Grammar draws it; an app never states it.
3
+ One control height, 40px (HeroUI's own `h-10`), is the default of every standalone Grammar control: Button, IconButton, Input, SearchField, Select, Tabs, Switch, the chrome Avatar, Textarea and the composer send button. Grammar draws it; an app never states it.
4
4
 
5
5
  | Rule | Finding code | Required behavior |
6
6
  | --- | --- | --- |
@@ -1,6 +1,6 @@
1
1
  # Grammar shims (R321)
2
2
 
3
- Law module: `grammar-shim.mjs`. HFS rule: R321. Knowledge: `contexts/code/fe/ui.md` FE-UI-1 (the app makes no visual choice; the Grammar owns every visual element) and the Grammar follow-up C-7 in `contexts/decisions/open-grammar.md`.
3
+ Law module: `grammar-shim.mjs`. HFS rule: R321. Knowledge: `contexts/code/fe/ui.md` FE-UI-1 (the app makes no visual choice; the Grammar owns every visual element).
4
4
 
5
5
  An app imports a Grammar component where it renders it. It never hands one on from an app path under its own name: such a shim makes one app green while the defect it works around (a missing `"use client"`, a wrong prop, a broken export) stays in the Grammar for every other app. The defect is reported to the Grammar instead; an op files `blocked` naming the package, the component and the error.
6
6
 
@@ -8,7 +8,7 @@ Every rule below is an error in `starciFeConfig`; none can be switched off or su
8
8
 
9
9
  ## `starci-fe/hooks-folder-holds-hooks-only`
10
10
 
11
- `hooks/` holds `use*.ts` hooks under the names their family slot gives and, per domain, one `<domain>.shared.ts`; nothing else. A hook file exports one hook; `server-only` and `next/headers` are never imported there. A hook is a function that calls a hook: a React, SWR or Redux hook, a `use*` imported from the app's own `hooks/` folders (a `hooks/swr` wrapper or a sibling domain hook, resolved by TypeScript symbol resolution through barrels; that hook's own file is judged when it is linted), or a library hook from an explicit list (`next-intl` `useTranslations`/`useLocale`/`useFormatter`/`useNow`/`useTimeZone`/`useMessages`, `next/navigation`, `next-themes` `useTheme`, `react-hook-form`, `zustand`). A `use*` from outside every `hooks/` folder or an unlisted library is not a hook by its spelling, and a file that exports a helper, a constant or a component still fails (owner ruling 2026-10-16).
11
+ `hooks/` holds `use*.ts` hooks under the names their family slot gives and, per domain, one `<domain>.shared.ts`; nothing else. A hook file exports one hook; `server-only` and `next/headers` are never imported there. A hook is a function that calls a hook: a React, SWR or Redux hook, a `use*` imported from the app's own `hooks/` folders (a `hooks/swr` wrapper or a sibling domain hook, resolved by TypeScript symbol resolution through barrels; that hook's own file is judged when it is linted), or a library hook from an explicit list (`next-intl` `useTranslations`/`useLocale`/`useFormatter`/`useNow`/`useTimeZone`/`useMessages`, `next/navigation`, `next-themes` `useTheme`, `react-hook-form`, `zustand`). A `use*` from outside every `hooks/` folder or an unlisted library is not a hook by its spelling, and a file that exports a helper, a constant or a component still fails.
12
12
 
13
13
  **Invalid** (`src/hooks/course/readCourse.ts`)
14
14
 
@@ -59,7 +59,7 @@ const Frame = () => (
59
59
 
60
60
  ## `starci-fe/no-table-in-card`
61
61
 
62
- Finding code: `FE_TABLE_IN_CARD` (R351). A `DataTable` is not placed in a `SurfaceCard`. Plain rows with a few facts are a `SurfaceCard kind="list"` with the label outside and the note in its `footer`; a table that compares records across many columns sits in its section with no card around it. The rule reads the file: a Grammar `DataTable` enclosed by a Grammar `SurfaceCard` element is a finding, and so is a `DataTable` rendered by a component of the same file (a declaration, a variable's function, a `memo` or `forwardRef` wrapper, followed through other components of the file) that a `SurfaceCard` encloses. A card in another file that renders a table component is judged where the card is written. There is no inline exemption; a table the owner rules complex enough to sit in a card is named in this rule.
62
+ Finding code: `FE_TABLE_IN_CARD` (R351). A `DataTable` is not placed in a `SurfaceCard`. Plain rows with a few facts are a `SurfaceCard kind="list"` with the label outside and the note in its `footer`; a table that compares records across many columns sits in its section with no card around it. The rule reads the file: a Grammar `DataTable` enclosed by a Grammar `SurfaceCard` element is a finding, and so is a `DataTable` rendered by a component of the same file (a declaration, a variable's function, a `memo` or `forwardRef` wrapper, followed through other components of the file) that a `SurfaceCard` encloses. A card in another file that renders a table component is judged where the card is written. There is no inline exemption; a table complex enough to sit in a card is named in this rule.
63
63
 
64
64
  Invalid:
65
65
 
@@ -127,7 +127,7 @@ const Filter = () => <FilterButtonGroup label="Team" options={options} value={te
127
127
 
128
128
  ## `starci-fe/no-heading-above-card`
129
129
 
130
- Finding code: `FE_HEADING_ABOVE_CARD` (R354). A card has a label by design (ruling `card-carries-its-own-label`), so a heading over it is wrong. A Grammar `Section` (not `kind="list"`) whose only child is one `SurfaceCard` is refused, and so is a card whose `ariaLabel` is the `Section`'s `title`. Several cards under one `Section` stay legal, and a `Section` holding anything else is not judged. The fix moves the title to the card's `label`, the count to `fact`, the action to `labelEnd` and the note to `footer`.
130
+ Finding code: `FE_HEADING_ABOVE_CARD` (R354). A card carries its own label, so a heading over it is wrong. A Grammar `Section` (not `kind="list"`) whose only child is one `SurfaceCard` is refused, and so is a card whose `ariaLabel` is the `Section`'s `title`. Several cards under one `Section` stay legal, and a `Section` holding anything else is not judged. The fix moves the title to the card's `label`, the count to `fact`, the action to `labelEnd` and the note to `footer`.
131
131
 
132
132
  Invalid:
133
133
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@starci/eslint-canon-fe",
3
- "version": "9.16.0",
3
+ "version": "9.16.2",
4
4
  "description": "Universal front-end lint laws for TypeScript and Next.js, independent of the selected Grammar family.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -51,7 +51,7 @@
51
51
  "node": ">=22.13.0"
52
52
  },
53
53
  "peerDependencies": {
54
- "@starci/hfs": "~5.13.0",
54
+ "@starci/hfs": "~6.0.0",
55
55
  "eslint": ">=9",
56
56
  "eslint-plugin-react-hooks": ">=7",
57
57
  "typescript": ">=5.9"