@starci/hfs 4.7.47 → 4.9.0

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 (153) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/README.md +4 -9
  3. package/emit/operation-schemas.mjs +3 -0
  4. package/lint/bound-sys.cjs +2 -2
  5. package/package.json +11 -5
  6. package/runtime/engine/admission.mjs +1 -1
  7. package/runtime/engine/config.mjs +2 -2
  8. package/runtime/engine/db/machine.mjs +2 -3
  9. package/runtime/engine/invalid-config.mjs +1 -1
  10. package/runtime/knowledge/grammars/{starci → core}/playbook.yaml +3 -3
  11. package/runtime/knowledge/grammars/index.yaml +14 -23
  12. package/runtime/knowledge/grammars/offset-pop/playbook.yaml +2 -2
  13. package/runtime/knowledge/hfs/canon-pins.yaml +23 -23
  14. package/runtime/knowledge/hfs/fe-stack.yaml +1 -1
  15. package/runtime/knowledge/hfs/rules.yaml +83 -60
  16. package/runtime/modules/kernel/failure-codes.yaml +23 -13
  17. package/runtime/scripts/guards/git-policy.mjs +2 -3
  18. package/runtime/scripts/hfs/rule-catalog.mjs +2 -2
  19. package/runtime/scripts/hfs/rules/pipeline.mjs +5 -5
  20. package/runtime/scripts/lib/example-refs.mjs +10 -3
  21. package/runtime/scripts/lib/grammar-lint.mjs +16 -3
  22. package/runtime/scripts/lib/package-at.mjs +5 -6
  23. package/runtime/scripts/lib/roots.mjs +2 -2
  24. package/runtime/scripts/work/draw/draw-dna-findings.mjs +23 -12
  25. package/runtime/scripts/work/draw/draw-dna.mjs +14 -8
  26. package/scaffold/app.mjs +6 -6
  27. package/src/main.mjs +3 -3
  28. package/sync/hygiene.mjs +1 -1
  29. package/sync/index.mjs +15 -2
  30. package/sync/managed.mjs +3 -2
  31. package/templates/app/codegen-graphql.mjs.partial +4 -4
  32. package/templates/app/quality-config/sonar-project.properties +4 -2
  33. package/runtime/engine/canonical-json.mjs +0 -14
  34. package/runtime/engine/db/ledger-open.mjs +0 -38
  35. package/runtime/engine/db/ledger-paths.mjs +0 -87
  36. package/runtime/engine/db/ledger.mjs +0 -1068
  37. package/runtime/engine/db/provision-authority.mjs +0 -76
  38. package/runtime/engine/db/provision-operations.mjs +0 -146
  39. package/runtime/packages/grammar/scripts/build-stamp.mjs +0 -98
  40. package/runtime/scripts/agent/codex-app-server.mjs +0 -79
  41. package/runtime/scripts/agent/codex-mirror-source.mjs +0 -34
  42. package/runtime/scripts/agent/host-agents.mjs +0 -80
  43. package/runtime/scripts/agent/launch-trust-policy.mjs +0 -53
  44. package/runtime/scripts/agent/trust-launch.mjs +0 -191
  45. package/runtime/scripts/agent/trust.mjs +0 -523
  46. package/runtime/scripts/api/fs/temp-path.mjs +0 -8
  47. package/runtime/scripts/api/git/diff-names.mjs +0 -8
  48. package/runtime/scripts/api/git/head-time.mjs +0 -10
  49. package/runtime/scripts/api/git/index-lock.mjs +0 -78
  50. package/runtime/scripts/api/git/log.mjs +0 -5
  51. package/runtime/scripts/api/git/merge-tree.mjs +0 -5
  52. package/runtime/scripts/api/git/rev-list.mjs +0 -5
  53. package/runtime/scripts/api/git/rev-parse.mjs +0 -13
  54. package/runtime/scripts/api/git/status-query.mjs +0 -5
  55. package/runtime/scripts/api/git/worktree-list-query.mjs +0 -5
  56. package/runtime/scripts/api/node/spawn-node.mjs +0 -6
  57. package/runtime/scripts/api/npm/dist-tag.mjs +0 -8
  58. package/runtime/scripts/api/npm/lib.mjs +0 -32
  59. package/runtime/scripts/api/npm/pack-dry-run.mjs +0 -9
  60. package/runtime/scripts/api/npm/run-npm.mjs +0 -6
  61. package/runtime/scripts/api/npm/view.mjs +0 -30
  62. package/runtime/scripts/api/npm/whoami.mjs +0 -8
  63. package/runtime/scripts/api/process/hide-child-windows.mjs +0 -31
  64. package/runtime/scripts/api/process/kill-tree.mjs +0 -22
  65. package/runtime/scripts/api/process/lib.mjs +0 -125
  66. package/runtime/scripts/api/process/probe-guard-command.mjs +0 -74
  67. package/runtime/scripts/api/process/process-list.mjs +0 -28
  68. package/runtime/scripts/api/process/system-tool.mjs +0 -37
  69. package/runtime/scripts/gates/canon-digest.mjs +0 -81
  70. package/runtime/scripts/gates/canon-pins.mjs +0 -119
  71. package/runtime/scripts/gates/gate-input.mjs +0 -98
  72. package/runtime/scripts/gates/gate.mjs +0 -636
  73. package/runtime/scripts/gates/grammar-dist.mjs +0 -206
  74. package/runtime/scripts/gates/output.mjs +0 -40
  75. package/runtime/scripts/gates/runtime-package-selection.mjs +0 -27
  76. package/runtime/scripts/gates/test-world-run.mjs +0 -252
  77. package/runtime/scripts/gates/type-impact.mjs +0 -277
  78. package/runtime/scripts/gates/type-program.mjs +0 -113
  79. package/runtime/scripts/guards/assigned-command.mjs +0 -12
  80. package/runtime/scripts/guards/call-rights.mjs +0 -47
  81. package/runtime/scripts/guards/command-guard.mjs +0 -468
  82. package/runtime/scripts/guards/command-policy.mjs +0 -342
  83. package/runtime/scripts/guards/critic-reach.mjs +0 -82
  84. package/runtime/scripts/guards/deps-guard.mjs +0 -150
  85. package/runtime/scripts/guards/env-dump-verdict.mjs +0 -89
  86. package/runtime/scripts/guards/guards-root.mjs +0 -27
  87. package/runtime/scripts/guards/hook-install.mjs +0 -343
  88. package/runtime/scripts/guards/hook-verdict.mjs +0 -12
  89. package/runtime/scripts/guards/install-verdict.mjs +0 -41
  90. package/runtime/scripts/guards/kernel-seat.mjs +0 -63
  91. package/runtime/scripts/guards/launch-verdict.mjs +0 -74
  92. package/runtime/scripts/guards/op-starci.mjs +0 -16
  93. package/runtime/scripts/guards/op-write-scope.mjs +0 -27
  94. package/runtime/scripts/guards/orca-self-lifecycle.mjs +0 -39
  95. package/runtime/scripts/guards/process-kill-verdict.mjs +0 -106
  96. package/runtime/scripts/guards/protected-zone.mjs +0 -56
  97. package/runtime/scripts/guards/refusals.mjs +0 -27
  98. package/runtime/scripts/guards/rights.mjs +0 -268
  99. package/runtime/scripts/guards/seat-tools.mjs +0 -47
  100. package/runtime/scripts/guards/shell-commands.mjs +0 -328
  101. package/runtime/scripts/guards/supervisor-seat.mjs +0 -80
  102. package/runtime/scripts/guards/verdict-process.mjs +0 -81
  103. package/runtime/scripts/lib/app-data.mjs +0 -11
  104. package/runtime/scripts/lib/canon-binding-text.mjs +0 -129
  105. package/runtime/scripts/lib/check-format.mjs +0 -7
  106. package/runtime/scripts/lib/failure-code-reads.mjs +0 -100
  107. package/runtime/scripts/lib/failure-code-template-errors.mjs +0 -161
  108. package/runtime/scripts/lib/git-dir.mjs +0 -120
  109. package/runtime/scripts/lib/guard-command.mjs +0 -24
  110. package/runtime/scripts/lib/interrupt-cleanup.mjs +0 -38
  111. package/runtime/scripts/lib/json-formats.mjs +0 -34
  112. package/runtime/scripts/lib/managed-json.mjs +0 -51
  113. package/runtime/scripts/lib/menu-parts.mjs +0 -11
  114. package/runtime/scripts/lib/op-gate.mjs +0 -15
  115. package/runtime/scripts/lib/provision-control-failure.mjs +0 -32
  116. package/runtime/scripts/lib/release-version.mjs +0 -134
  117. package/runtime/scripts/lib/runtime-location.mjs +0 -21
  118. package/runtime/scripts/lib/runtime-package-inventory.mjs +0 -21
  119. package/runtime/scripts/lib/runtime-package-manifests.mjs +0 -84
  120. package/runtime/scripts/lib/runtime-publication-tags.mjs +0 -56
  121. package/runtime/scripts/lib/seat-env.mjs +0 -43
  122. package/runtime/scripts/lib/sonar-new-code.mjs +0 -58
  123. package/runtime/scripts/lib/source-package-imports.mjs +0 -111
  124. package/runtime/scripts/lib/tar-files.mjs +0 -39
  125. package/runtime/scripts/lib/uat-run-folder.mjs +0 -118
  126. package/runtime/scripts/lib/worktree-record.mjs +0 -14
  127. package/runtime/scripts/machine/ask-receipts.mjs +0 -113
  128. package/runtime/scripts/machine/evidence-store.mjs +0 -223
  129. package/runtime/scripts/machine/home.mjs +0 -216
  130. package/runtime/scripts/machine/host-lock.mjs +0 -184
  131. package/runtime/scripts/machine/lock-recovery.mjs +0 -55
  132. package/runtime/scripts/machine/roles-contract.mjs +0 -90
  133. package/runtime/scripts/machine/runtime-change.mjs +0 -20
  134. package/runtime/scripts/machine/workflow-tree.mjs +0 -122
  135. package/runtime/scripts/reconciler/checklist-items.mjs +0 -7
  136. package/runtime/scripts/reconciler/guard-row.mjs +0 -25
  137. package/runtime/scripts/work/brand/brand-colour.mjs +0 -125
  138. package/runtime/scripts/work/brand/brand-tokens.mjs +0 -167
  139. package/runtime/scripts/work/brand/brand-value-source.mjs +0 -106
  140. package/runtime/scripts/work/brand/brand.mjs +0 -892
  141. package/runtime/scripts/work/draw/draw-layer.mjs +0 -306
  142. package/runtime/scripts/work/draw/draw-rationale-page.mjs +0 -237
  143. package/runtime/scripts/work/draw/draw-rationale-ref.mjs +0 -14
  144. package/runtime/scripts/work/draw/draw-rationale.mjs +0 -353
  145. package/runtime/scripts/work/draw/draw-source.mjs +0 -412
  146. package/runtime/scripts/work/draw/draw-taste.mjs +0 -278
  147. package/runtime/scripts/work/draw/draw-typecheck.mjs +0 -72
  148. package/runtime/scripts/work/draw/rationale-findings.mjs +0 -205
  149. package/runtime/scripts/work/draw-grammar.mjs +0 -175
  150. package/runtime/scripts/work/draw-render-page.mjs +0 -188
  151. package/runtime/scripts/work/draw-render.mjs +0 -626
  152. package/runtime/scripts/work/png.mjs +0 -237
  153. package/runtime/scripts/work/render-tools.mjs +0 -64
@@ -29,7 +29,7 @@ gates:
29
29
  enforcerKinds:
30
30
  eslint-be: a rule of the plugin @starci/eslint-canon-be (id without the plugin prefix)
31
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
+ eslint-grammar-core: a selected Grammar family rule sharing the common component API, resolved through the family canon binding (id without the plugin prefix; FE-RULE-OWNERSHIP)
33
33
  stylelint: a rule of the @starci/stylelint-canon package
34
34
  machine: a check of the architecture machine (scripts/hfs/architecture), which reads the import graph
35
35
  hfs: a check of the hfs CLI that reads the repository tree, configuration, contracts or catalogs
@@ -1273,49 +1273,49 @@ rules:
1273
1273
  - {kind: stylelint, id: breakpoint-scale}
1274
1274
  - {kind: stylelint, id: source-resolves}
1275
1275
  - {kind: eslint-fe, id: no-raw-brand-value}
1276
- - {kind: eslint-grammar-starci, id: no-fractional-step}
1276
+ - {kind: eslint-grammar-core, id: no-fractional-step}
1277
1277
  - {kind: eslint-fe, id: no-arbitrary-value}
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}
1278
+ - {kind: eslint-grammar-core, id: no-hand-rolled-heading}
1279
+ - {kind: eslint-grammar-core, id: no-unresolved-token-class}
1280
+ - {kind: eslint-grammar-core, id: no-heading-tag-outside-heading-component}
1281
+ - {kind: eslint-grammar-core, id: status-text-uses-soft-foreground}
1282
1282
  proves:
1283
1283
  - {path: packages/stylelint/source-resolves.spec.mjs, editions: [lite, full], codes: [FE_STYLE_SOURCE_UNRESOLVED]}
1284
1284
  - {path: packages/eslint/fe/brand-values.spec.mjs, editions: [lite, full], codes: [FE_STYLE_TOKEN_ONLY]}
1285
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]}
1286
+ - {path: packages/eslint/grammar-core/status-colors.spec.mjs, editions: [lite, full], codes: [FE_STYLE_TOKEN_ONLY]}
1287
+ - {path: packages/eslint/grammar-core/typography.spec.mjs, editions: [lite, full], codes: [FE_STYLE_TOKEN_ONLY]}
1288
+ - {path: packages/eslint/grammar-core/tokens.spec.mjs, editions: [lite, full], codes: [FE_STYLE_TOKEN_ONLY]}
1289
1289
  exemplifiedBy:
1290
1290
  - {path: packages/hfs/templates/fe/skeleton-lite/apps/web/src/app/globals.css, edition: lite}
1291
1291
  - {path: packages/hfs/templates/fe/skeleton/apps/app/src/app/globals.css, edition: full}
1292
1292
  - {path: packages/stylelint/source-resolves.spec.mjs, editions: [lite, full], codes: [FE_STYLE_SOURCE_UNRESOLVED]}
1293
1293
  - {path: packages/eslint/fe/brand-values.spec.mjs, editions: [lite, full], codes: [FE_STYLE_TOKEN_ONLY]}
1294
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]}
1295
+ - {path: packages/eslint/grammar-core/status-colors.spec.mjs, editions: [lite, full], codes: [FE_STYLE_TOKEN_ONLY]}
1296
+ - {path: packages/eslint/grammar-core/typography.spec.mjs, editions: [lite, full], codes: [FE_STYLE_TOKEN_ONLY]}
1297
+ - {path: packages/eslint/grammar-core/tokens.spec.mjs, editions: [lite, full], codes: [FE_STYLE_TOKEN_ONLY]}
1298
1298
  witness:
1299
1299
  - {path: packages/stylelint/source-resolves.spec.mjs, editions: [lite, full], codes: [FE_STYLE_SOURCE_UNRESOLVED]}
1300
1300
  - {path: packages/eslint/fe/brand-values.spec.mjs, editions: [lite, full], codes: [FE_STYLE_TOKEN_ONLY]}
1301
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]}
1302
+ - {path: packages/eslint/grammar-core/status-colors.spec.mjs, editions: [lite, full], codes: [FE_STYLE_TOKEN_ONLY]}
1303
+ - {path: packages/eslint/grammar-core/typography.spec.mjs, editions: [lite, full], codes: [FE_STYLE_TOKEN_ONLY]}
1304
+ - {path: packages/eslint/grammar-core/tokens.spec.mjs, editions: [lite, full], codes: [FE_STYLE_TOKEN_ONLY]}
1305
1305
  - id: R62
1306
1306
  code: "FE_NATIVE_FORM_CONTROL"
1307
1307
  editions: [lite, full]
1308
1308
  docs: [docs/architecture.md#r62, knowledge/patterns/fe/index.yaml#FE-RULE-OWNERSHIP]
1309
1309
  proves:
1310
- - {path: packages/eslint/grammar-starci/r62-structural-elements-coverage.spec.mjs, editions: [lite, full], codes: [FE_NATIVE_FORM_CONTROL]}
1310
+ - {path: packages/eslint/grammar-core/r62-structural-elements-coverage.spec.mjs, editions: [lite, full], codes: [FE_NATIVE_FORM_CONTROL]}
1311
1311
  - {path: packages/eslint/fe/r62-native-controls-coverage.spec.mjs, editions: [lite, full]}
1312
1312
  exemplifiedBy:
1313
- - {path: packages/eslint/grammar-starci/r62-structural-elements-coverage.spec.mjs, editions: [lite, full], codes: [FE_NATIVE_FORM_CONTROL]}
1313
+ - {path: packages/eslint/grammar-core/r62-structural-elements-coverage.spec.mjs, editions: [lite, full], codes: [FE_NATIVE_FORM_CONTROL]}
1314
1314
  - {path: packages/hfs/templates/fe/skeleton-lite/apps/web/src/features/pages/AppHomePage/component.tsx, edition: lite}
1315
1315
  - {path: packages/hfs/templates/fe/skeleton/apps/__app__/src/components/blocks/SignInForm/component.tsx, edition: full}
1316
1316
  - {path: packages/eslint/fe/r62-native-controls-coverage.spec.mjs, editions: [lite, full]}
1317
1317
  witness:
1318
- - {path: packages/eslint/grammar-starci/r62-structural-elements-coverage.spec.mjs, editions: [lite, full], codes: [FE_NATIVE_FORM_CONTROL]}
1318
+ - {path: packages/eslint/grammar-core/r62-structural-elements-coverage.spec.mjs, editions: [lite, full], codes: [FE_NATIVE_FORM_CONTROL]}
1319
1319
  - {path: packages/eslint/fe/r62-native-controls-coverage.spec.mjs, edition: lite, codes: [FE_NATIVE_FORM_CONTROL, FE_NATIVE_IMAGE]}
1320
1320
  - {path: packages/eslint/fe/r62-native-controls-coverage.spec.mjs, edition: full, codes: [FE_NATIVE_FORM_CONTROL, FE_NATIVE_IMAGE]}
1321
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."
@@ -1325,7 +1325,7 @@ rules:
1325
1325
  enforcers:
1326
1326
  - {kind: eslint-fe, id: no-native-form-control}
1327
1327
  - {kind: eslint-fe, id: no-native-img}
1328
- - {kind: eslint-grammar-starci, id: no-raw-structural-element}
1328
+ - {kind: eslint-grammar-core, id: no-raw-structural-element}
1329
1329
  - {kind: eslint-fe, id: image-has-size}
1330
1330
 
1331
1331
  - id: R63
@@ -1878,7 +1878,7 @@ rules:
1878
1878
  - {kind: eslint-fe, id: base-props-atom}
1879
1879
  - {kind: eslint-fe, id: base-import-pair}
1880
1880
  - {kind: eslint-fe, id: no-data-status-shape}
1881
- - {kind: eslint-grammar-starci, id: slot-status-through-slotview}
1881
+ - {kind: eslint-grammar-core, id: slot-status-through-slotview}
1882
1882
  - {kind: eslint-fe, id: presentational-purity}
1883
1883
  - {kind: eslint-fe, id: connected-block-has-presentational-twin}
1884
1884
  - {kind: eslint-fe, id: no-resting-twin-component}
@@ -1891,18 +1891,18 @@ rules:
1891
1891
  editions: [lite, full]
1892
1892
  docs: [docs/architecture.md#r92, knowledge/patterns/fe/index.yaml#FE-RULE-OWNERSHIP]
1893
1893
  proves:
1894
- - {path: packages/eslint/grammar-starci/r92-slot-status-coverage.spec.mjs, editions: [lite, full], codes: [FE_COMPONENT_API]}
1894
+ - {path: packages/eslint/grammar-core/r92-slot-status-coverage.spec.mjs, editions: [lite, full], codes: [FE_COMPONENT_API]}
1895
1895
  - {path: packages/eslint/fe/r92-fetch-barrel.spec.mjs, editions: [lite, full]}
1896
1896
  - {path: packages/eslint/fe/r92-component-surface-coverage.spec.mjs, editions: [lite, full]}
1897
1897
  - {path: packages/eslint/fe/r56-r92-graph-coverage.spec.mjs, editions: [lite, full]}
1898
1898
  exemplifiedBy:
1899
- - {path: packages/eslint/grammar-starci/r92-slot-status-coverage.spec.mjs, editions: [lite, full], codes: [FE_COMPONENT_API]}
1899
+ - {path: packages/eslint/grammar-core/r92-slot-status-coverage.spec.mjs, editions: [lite, full], codes: [FE_COMPONENT_API]}
1900
1900
  - {path: packages/hfs/templates/fe/skeleton/apps/__app__/src/components/blocks/SignInForm/component.tsx, editions: [lite, full]}
1901
1901
  - {path: packages/eslint/fe/r92-fetch-barrel.spec.mjs, editions: [lite, full]}
1902
1902
  - {path: packages/eslint/fe/r92-component-surface-coverage.spec.mjs, editions: [lite, full]}
1903
1903
  - {path: packages/eslint/fe/r56-r92-graph-coverage.spec.mjs, editions: [lite, full]}
1904
1904
  witness:
1905
- - {path: packages/eslint/grammar-starci/r92-slot-status-coverage.spec.mjs, editions: [lite, full], codes: [FE_COMPONENT_API]}
1905
+ - {path: packages/eslint/grammar-core/r92-slot-status-coverage.spec.mjs, editions: [lite, full], codes: [FE_COMPONENT_API]}
1906
1906
  - {path: packages/eslint/fe/r92-fetch-barrel.spec.mjs, editions: [lite, full]}
1907
1907
  - {path: packages/eslint/fe/r92-component-surface-coverage.spec.mjs, editions: [lite, full]}
1908
1908
  - {path: packages/eslint/fe/r56-r92-graph-coverage.spec.mjs, editions: [lite, full]}
@@ -1913,29 +1913,29 @@ rules:
1913
1913
  gates: [pre-commit, settle, land, ci]
1914
1914
  failureCodes: ["FE_VENDOR_BOUNDARY", "ARCH_GRAMMAR_CONTRACT_INVALID", "ARCH_GRAMMAR_EXPORT_BYPASS"]
1915
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}
1916
+ - {kind: eslint-grammar-core, id: no-vendor-icon-outside-icon-leaf}
1917
+ - {kind: eslint-grammar-core, id: heroicons-is-the-glyph-vendor}
1918
+ - {kind: eslint-grammar-core, id: no-off-scale-glyph-size}
1919
+ - {kind: eslint-grammar-core, id: no-icon-size-class}
1920
+ - {kind: eslint-grammar-core, id: destructive-menu-entry-needs-danger-tone}
1921
+ - {kind: eslint-grammar-core, id: no-decorative-icon-in-metric-cell}
1922
+ - {kind: eslint-grammar-core, id: vendor-primitive-has-named-owner}
1923
1923
  - {kind: eslint-fe, id: grammar-entry}
1924
1924
  - {kind: machine, id: grammar, at: scripts/hfs/architecture/frontend-grammar.mjs}
1925
1925
  editions: [lite, full]
1926
1926
  docs: ["docs/code-pattern-enforcement.md#r93-vendor-and-grammar-ownership", knowledge/patterns/fe/index.yaml#FE-RULE-OWNERSHIP]
1927
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."
1928
1928
  proves:
1929
- - packages/eslint/grammar-starci/r93-vendor-coverage.spec.mjs
1929
+ - packages/eslint/grammar-core/r93-vendor-coverage.spec.mjs
1930
1930
  - packages/eslint/fe/r93-grammar-ownership.spec.mjs
1931
- - packages/eslint/grammar-starci/menu-entries.spec.mjs
1931
+ - packages/eslint/grammar-core/menu-entries.spec.mjs
1932
1932
  exemplifiedBy:
1933
- - {path: packages/eslint/grammar-starci/r93-vendor-coverage.spec.mjs, editions: [lite, full]}
1933
+ - {path: packages/eslint/grammar-core/r93-vendor-coverage.spec.mjs, editions: [lite, full]}
1934
1934
  - {path: packages/eslint/fe/r93-grammar-ownership.spec.mjs, editions: [lite, full]}
1935
- - {path: packages/eslint/grammar-starci/menu-entries.spec.mjs, editions: [lite, full]}
1935
+ - {path: packages/eslint/grammar-core/menu-entries.spec.mjs, editions: [lite, full]}
1936
1936
  witness:
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]}
1937
+ - {path: packages/eslint/grammar-core/menu-entries.spec.mjs, editions: [lite, full], codes: [FE_VENDOR_BOUNDARY]}
1938
+ - {path: packages/eslint/grammar-core/r93-vendor-coverage.spec.mjs, editions: [lite, full], codes: [FE_VENDOR_BOUNDARY]}
1939
1939
  - {path: packages/eslint/fe/r93-grammar-ownership.spec.mjs, editions: [lite, full], codes: [ARCH_GRAMMAR_CONTRACT_INVALID, ARCH_GRAMMAR_EXPORT_BYPASS]}
1940
1940
  - id: R94
1941
1941
  code: "FE_SLOT_FILE_ROLE"
@@ -5006,20 +5006,20 @@ rules:
5006
5006
  enforcers:
5007
5007
  - {kind: eslint-fe, id: no-copy-in-call}
5008
5008
  - {kind: eslint-fe, id: no-alert}
5009
- - {kind: eslint-grammar-starci, id: no-inline-svg-outside-brand-mark-leaf}
5009
+ - {kind: eslint-grammar-core, id: no-inline-svg-outside-brand-mark-leaf}
5010
5010
  editions: [lite, full]
5011
5011
  docs: [docs/quality-bar.md#r286, knowledge/patterns/fe/index.yaml#FE-RULE-OWNERSHIP]
5012
5012
  exemplifiedBy:
5013
5013
  - {path: packages/eslint/fe/translation.spec.mjs, editions: [lite, full], codes: [FE_COPY_IN_CALL, FE_NO_ALERT]}
5014
- - {path: packages/eslint/grammar-starci/icon.spec.mjs, editions: [lite, full], codes: [FE_ICON_INLINE_SVG]}
5014
+ - {path: packages/eslint/grammar-core/icon.spec.mjs, editions: [lite, full], codes: [FE_ICON_INLINE_SVG]}
5015
5015
  - {path: packages/hfs/templates/fe/skeleton/apps/__app__/src/components/leaves/Icon/index.tsx, editions: [lite, full]}
5016
5016
  - {path: packages/hfs/templates/fe/skeleton/apps/__app__/src/modules/toast, editions: [lite, full]}
5017
5017
  proves:
5018
5018
  - {path: packages/eslint/fe/translation.spec.mjs, editions: [lite, full], codes: [FE_COPY_IN_CALL, FE_NO_ALERT]}
5019
- - {path: packages/eslint/grammar-starci/icon.spec.mjs, editions: [lite, full], codes: [FE_ICON_INLINE_SVG]}
5019
+ - {path: packages/eslint/grammar-core/icon.spec.mjs, editions: [lite, full], codes: [FE_ICON_INLINE_SVG]}
5020
5020
  witness:
5021
5021
  - {path: packages/eslint/fe/translation.spec.mjs, editions: [lite, full], codes: [FE_COPY_IN_CALL, FE_NO_ALERT]}
5022
- - {path: packages/eslint/grammar-starci/icon.spec.mjs, editions: [lite, full], codes: [FE_ICON_INLINE_SVG]}
5022
+ - {path: packages/eslint/grammar-core/icon.spec.mjs, editions: [lite, full], codes: [FE_ICON_INLINE_SVG]}
5023
5023
 
5024
5024
  - id: R287
5025
5025
  code: "FE_CALLBACK_SHAPE"
@@ -5476,19 +5476,19 @@ rules:
5476
5476
  gates: [pre-commit, settle, land, ci]
5477
5477
  failureCodes: ["FE_APP_SHELL_FRAME"]
5478
5478
  enforcers:
5479
- - {kind: eslint-grammar-starci, id: app-shell-frame}
5479
+ - {kind: eslint-grammar-core, id: app-shell-frame}
5480
5480
  editions: [lite, full]
5481
5481
  docs:
5482
5482
  - knowledge/patterns/fe/index.yaml#FE-RULE-OWNERSHIP
5483
5483
  - {path: knowledge/ui/composition/app-shell.yaml, editions: [lite, full]}
5484
5484
  proves:
5485
- - {path: packages/eslint/grammar-starci/app-shell.spec.mjs, editions: [lite, full], codes: [FE_APP_SHELL_FRAME]}
5485
+ - {path: packages/eslint/grammar-core/app-shell.spec.mjs, editions: [lite, full], codes: [FE_APP_SHELL_FRAME]}
5486
5486
  exemplifiedBy:
5487
- - {path: packages/eslint/grammar-starci/app-shell.spec.mjs, editions: [lite, full], codes: [FE_APP_SHELL_FRAME]}
5487
+ - {path: packages/eslint/grammar-core/app-shell.spec.mjs, editions: [lite, full], codes: [FE_APP_SHELL_FRAME]}
5488
5488
  - {path: examples/full-app/fe/apps/app/src/features/layouts/ShopLayout/component.tsx, edition: full}
5489
5489
  - {path: examples/lite-app/fe/apps/web/src/features/layouts/WorkspaceLayout/component.tsx, edition: lite}
5490
5490
  witness:
5491
- - {path: packages/eslint/grammar-starci/app-shell.spec.mjs, editions: [lite, full], codes: [FE_APP_SHELL_FRAME]}
5491
+ - {path: packages/eslint/grammar-core/app-shell.spec.mjs, editions: [lite, full], codes: [FE_APP_SHELL_FRAME]}
5492
5492
  templateNa: "The app composes its shell from product destinations and identity; full and lite example shells provide the reference."
5493
5493
  - id: R314
5494
5494
  code: "FE_NAVBAR_CONTROL_SIZE"
@@ -5497,19 +5497,19 @@ rules:
5497
5497
  gates: [pre-commit, settle, land, ci]
5498
5498
  failureCodes: ["FE_NAVBAR_CONTROL_SIZE"]
5499
5499
  enforcers:
5500
- - {kind: eslint-grammar-starci, id: navbar-control-size}
5500
+ - {kind: eslint-grammar-core, id: navbar-control-size}
5501
5501
  editions: [lite, full]
5502
5502
  docs:
5503
5503
  - knowledge/patterns/fe/index.yaml#FE-RULE-OWNERSHIP
5504
5504
  - {path: knowledge/ui/composition/app-shell.yaml, editions: [lite, full]}
5505
5505
  proves:
5506
- - {path: packages/eslint/grammar-starci/app-shell.spec.mjs, editions: [lite, full], codes: [FE_NAVBAR_CONTROL_SIZE]}
5506
+ - {path: packages/eslint/grammar-core/app-shell.spec.mjs, editions: [lite, full], codes: [FE_NAVBAR_CONTROL_SIZE]}
5507
5507
  exemplifiedBy:
5508
- - {path: packages/eslint/grammar-starci/app-shell.spec.mjs, editions: [lite, full], codes: [FE_NAVBAR_CONTROL_SIZE]}
5508
+ - {path: packages/eslint/grammar-core/app-shell.spec.mjs, editions: [lite, full], codes: [FE_NAVBAR_CONTROL_SIZE]}
5509
5509
  - {path: examples/full-app/fe/packages/ecommerce-ui/src/branches/WorkspaceNavbar/component.tsx, edition: full}
5510
5510
  - {path: examples/lite-app/fe/apps/web/src/components/branches/Navbar/component.tsx, edition: lite}
5511
5511
  witness:
5512
- - {path: packages/eslint/grammar-starci/app-shell.spec.mjs, editions: [lite, full], codes: [FE_NAVBAR_CONTROL_SIZE]}
5512
+ - {path: packages/eslint/grammar-core/app-shell.spec.mjs, editions: [lite, full], codes: [FE_NAVBAR_CONTROL_SIZE]}
5513
5513
  templateNa: "The app composes its shell from product destinations and identity; full and lite example shells provide the reference."
5514
5514
  - id: R315
5515
5515
  code: "FE_NAVBAR_CLUSTER"
@@ -5518,19 +5518,19 @@ rules:
5518
5518
  gates: [pre-commit, settle, land, ci]
5519
5519
  failureCodes: ["FE_NAVBAR_CLUSTER"]
5520
5520
  enforcers:
5521
- - {kind: eslint-grammar-starci, id: navbar-cluster}
5521
+ - {kind: eslint-grammar-core, id: navbar-cluster}
5522
5522
  editions: [lite, full]
5523
5523
  docs:
5524
5524
  - knowledge/patterns/fe/index.yaml#FE-RULE-OWNERSHIP
5525
5525
  - {path: knowledge/ui/composition/app-shell.yaml, editions: [lite, full]}
5526
5526
  proves:
5527
- - {path: packages/eslint/grammar-starci/app-shell.spec.mjs, editions: [lite, full], codes: [FE_NAVBAR_CLUSTER]}
5527
+ - {path: packages/eslint/grammar-core/app-shell.spec.mjs, editions: [lite, full], codes: [FE_NAVBAR_CLUSTER]}
5528
5528
  exemplifiedBy:
5529
- - {path: packages/eslint/grammar-starci/app-shell.spec.mjs, editions: [lite, full], codes: [FE_NAVBAR_CLUSTER]}
5529
+ - {path: packages/eslint/grammar-core/app-shell.spec.mjs, editions: [lite, full], codes: [FE_NAVBAR_CLUSTER]}
5530
5530
  - {path: examples/full-app/fe/packages/ecommerce-ui/src/branches/WorkspaceNavbar/component.tsx, edition: full}
5531
5531
  - {path: examples/lite-app/fe/apps/web/src/components/branches/Navbar/component.tsx, edition: lite}
5532
5532
  witness:
5533
- - {path: packages/eslint/grammar-starci/app-shell.spec.mjs, editions: [lite, full], codes: [FE_NAVBAR_CLUSTER]}
5533
+ - {path: packages/eslint/grammar-core/app-shell.spec.mjs, editions: [lite, full], codes: [FE_NAVBAR_CLUSTER]}
5534
5534
  templateNa: "The app composes its shell from product destinations and identity; full and lite example shells provide the reference."
5535
5535
  - id: R316
5536
5536
  code: "FE_APP_SHELL_BOTTOM_TABS"
@@ -5539,19 +5539,19 @@ rules:
5539
5539
  gates: [pre-commit, settle, land, ci]
5540
5540
  failureCodes: ["FE_APP_SHELL_BOTTOM_TABS"]
5541
5541
  enforcers:
5542
- - {kind: eslint-grammar-starci, id: no-shell-bottom-tabs}
5542
+ - {kind: eslint-grammar-core, id: no-shell-bottom-tabs}
5543
5543
  editions: [lite, full]
5544
5544
  docs:
5545
5545
  - knowledge/patterns/fe/index.yaml#FE-RULE-OWNERSHIP
5546
5546
  - {path: knowledge/ui/composition/app-shell.yaml, editions: [lite, full]}
5547
5547
  proves:
5548
- - {path: packages/eslint/grammar-starci/app-shell.spec.mjs, editions: [lite, full], codes: [FE_APP_SHELL_BOTTOM_TABS]}
5548
+ - {path: packages/eslint/grammar-core/app-shell.spec.mjs, editions: [lite, full], codes: [FE_APP_SHELL_BOTTOM_TABS]}
5549
5549
  exemplifiedBy:
5550
- - {path: packages/eslint/grammar-starci/app-shell.spec.mjs, editions: [lite, full], codes: [FE_APP_SHELL_BOTTOM_TABS]}
5550
+ - {path: packages/eslint/grammar-core/app-shell.spec.mjs, editions: [lite, full], codes: [FE_APP_SHELL_BOTTOM_TABS]}
5551
5551
  - {path: examples/full-app/fe/apps/app/src/features/layouts/ShopLayout/component.tsx, edition: full}
5552
5552
  - {path: examples/lite-app/fe/apps/web/src/features/layouts/WorkspaceLayout/component.tsx, edition: lite}
5553
5553
  witness:
5554
- - {path: packages/eslint/grammar-starci/app-shell.spec.mjs, editions: [lite, full], codes: [FE_APP_SHELL_BOTTOM_TABS]}
5554
+ - {path: packages/eslint/grammar-core/app-shell.spec.mjs, editions: [lite, full], codes: [FE_APP_SHELL_BOTTOM_TABS]}
5555
5555
  templateNa: "The app composes its shell from product destinations and identity; full and lite example shells provide the reference."
5556
5556
  - id: R317
5557
5557
  code: "FE_NAVBAR_CREATE"
@@ -5560,19 +5560,19 @@ rules:
5560
5560
  gates: [pre-commit, settle, land, ci]
5561
5561
  failureCodes: ["FE_NAVBAR_CREATE"]
5562
5562
  enforcers:
5563
- - {kind: eslint-grammar-starci, id: no-navbar-create}
5563
+ - {kind: eslint-grammar-core, id: no-navbar-create}
5564
5564
  editions: [lite, full]
5565
5565
  docs:
5566
5566
  - knowledge/patterns/fe/index.yaml#FE-RULE-OWNERSHIP
5567
5567
  - {path: knowledge/ui/composition/app-shell.yaml, editions: [lite, full]}
5568
5568
  proves:
5569
- - {path: packages/eslint/grammar-starci/app-shell.spec.mjs, editions: [lite, full], codes: [FE_NAVBAR_CREATE]}
5569
+ - {path: packages/eslint/grammar-core/app-shell.spec.mjs, editions: [lite, full], codes: [FE_NAVBAR_CREATE]}
5570
5570
  exemplifiedBy:
5571
- - {path: packages/eslint/grammar-starci/app-shell.spec.mjs, editions: [lite, full], codes: [FE_NAVBAR_CREATE]}
5571
+ - {path: packages/eslint/grammar-core/app-shell.spec.mjs, editions: [lite, full], codes: [FE_NAVBAR_CREATE]}
5572
5572
  - {path: examples/full-app/fe/packages/ecommerce-ui/src/branches/WorkspaceNavbar/component.tsx, edition: full}
5573
5573
  - {path: examples/lite-app/fe/apps/web/src/components/branches/Navbar/component.tsx, edition: lite}
5574
5574
  witness:
5575
- - {path: packages/eslint/grammar-starci/app-shell.spec.mjs, editions: [lite, full], codes: [FE_NAVBAR_CREATE]}
5575
+ - {path: packages/eslint/grammar-core/app-shell.spec.mjs, editions: [lite, full], codes: [FE_NAVBAR_CREATE]}
5576
5576
  templateNa: "The app composes its shell from product destinations and identity; full and lite example shells provide the reference."
5577
5577
  - id: R318
5578
5578
  code: "FE_NESTED_VARIANT"
@@ -5664,3 +5664,26 @@ rules:
5664
5664
  source: owner
5665
5665
  quote: "The size of the buttons and controls is uneven; the teacher thinks height = 40px (h-10) should be fixed for every button, switch, input, tabs and so on, what do you think? (translated from Vietnamese)"
5666
5666
  ruling: "One 40px control height is the default of every standalone control (owner ruling control-height-40): Grammar draws it, an app omits size, sm is for a nested item or dense toolbar row, lg only for a landing hero call to action, and controls of one row share one size."
5667
+ - id: R322
5668
+ code: "FE_CHIP_LABEL_CASE"
5669
+ law: "The label of a status chip (a StatusDot with text, a Badge) starts with an uppercase letter, so every chip of an app reads in one vocabulary."
5670
+ kinds: [lint, codemod]
5671
+ gates: [pre-commit, settle, land, ci]
5672
+ failureCodes: ["FE_CHIP_LABEL_CASE"]
5673
+ enforcers:
5674
+ - {kind: eslint-grammar-core, id: chip-label-starts-uppercase}
5675
+ editions: [lite, full]
5676
+ docs: [knowledge/patterns/fe/index.yaml#FE-RULE-OWNERSHIP]
5677
+ templateNa: "A template states no chip label; the words are the app's."
5678
+ proves:
5679
+ - packages/eslint/grammar-core/chip-label.spec.mjs
5680
+ exemplifiedBy:
5681
+ - {path: packages/eslint/grammar-core/chip-label.spec.mjs, editions: [lite, full], codes: [FE_CHIP_LABEL_CASE]}
5682
+ witness:
5683
+ - {path: packages/eslint/grammar-core/chip-label.spec.mjs, editions: [lite, full], codes: [FE_CHIP_LABEL_CASE]}
5684
+ cases:
5685
+ - id: case-1
5686
+ date: "2026-10-27"
5687
+ source: owner
5688
+ quote: "A chip label starts uppercase."
5689
+ ruling: "The label of a status chip starts with an uppercase letter (owner ruling chip-label-uppercase); StatusDot capitalises a text label it renders, and the lint refuses a lowercase literal label at its source."
@@ -2130,7 +2130,7 @@ 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\" (R316; FE-RULE-OWNERSHIP: knowledge/patterns/fe/index.yaml; packages/eslint/grammar-starci/README.md)."
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-core/README.md)."
2134
2134
  owner: op-retry
2135
2135
  kind: check-finding
2136
2136
 
@@ -2140,7 +2140,7 @@ FE_APP_SHELL_FRAME:
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\" (R313; FE-RULE-OWNERSHIP: knowledge/patterns/fe/index.yaml; packages/eslint/grammar-starci/README.md)."
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-core/README.md)."
2144
2144
  owner: op-retry
2145
2145
  kind: check-finding
2146
2146
 
@@ -2237,7 +2237,7 @@ FE_COMPONENT_API:
2237
2237
  - "Component nhận className từ ngoài"
2238
2238
  - "Khối kết nối không có bản trình bày thuần"
2239
2239
  - "Trạng thái dữ liệu tự chế thay vì qua SlotView"
2240
- 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)."
2240
+ 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-core/README.md)."
2241
2241
  owner: op-retry
2242
2242
  kind: check-finding
2243
2243
 
@@ -2284,6 +2284,16 @@ FE_CONSOLE_CALL:
2284
2284
  owner: op-retry
2285
2285
  kind: check-finding
2286
2286
 
2287
+ FE_CHIP_LABEL_CASE:
2288
+ title: "A status chip label starts with a lowercase letter"
2289
+ title_vi: "Nhãn chip trạng thái bắt đầu bằng chữ thường"
2290
+ meaning_vi: "Nhãn chữ của một StatusDot hoặc Badge tại <file> bắt đầu bằng chữ cái thường, nên các chip trong cùng một màn hình đọc thành hai lối viết."
2291
+ causes_vi:
2292
+ - "Viết nhãn chip như `running` thay vì `Running`."
2293
+ nextStep_vi: "Viết hoa chữ cái đầu của nhãn chip; luật tự sửa nhãn viết thẳng trong mã (quy định chip-label-uppercase)."
2294
+ owner: op-retry
2295
+ kind: check-finding
2296
+
2287
2297
  FE_CONTROL_HEIGHT:
2288
2298
  title: "A control picks a larger size or mixes sizes in one row"
2289
2299
  title_vi: "Điều khiển chọn cỡ lớn hơn hoặc trộn nhiều cỡ trong một hàng"
@@ -2530,7 +2540,7 @@ FE_ICON_INLINE_SVG:
2530
2540
  causes_vi:
2531
2541
  - "Leaf Icon tự vẽ path hoặc SVG thay vì dùng Heroicons"
2532
2542
  - "Component vẽ SVG trực tiếp mà không phải leaf nhãn hiệu được khai báo"
2533
- 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)."
2543
+ 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-core/README.md)."
2534
2544
  owner: op-retry
2535
2545
  kind: check-finding
2536
2546
 
@@ -2561,7 +2571,7 @@ FE_NATIVE_FORM_CONTROL:
2561
2571
  meaning_vi: "`<tag>` thô ở `<file>`. Dùng renderer của grammar."
2562
2572
  causes_vi:
2563
2573
  - "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."
2564
- 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)."
2574
+ 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-core/README.md)."
2565
2575
  owner: op-retry
2566
2576
  kind: check-finding
2567
2577
 
@@ -2581,7 +2591,7 @@ FE_NAVBAR_CLUSTER:
2581
2591
  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."
2582
2592
  causes_vi:
2583
2593
  - "Cấu trúc shell không theo canon ứng dụng."
2584
- 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)."
2594
+ 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-core/README.md)."
2585
2595
  owner: op-retry
2586
2596
  kind: check-finding
2587
2597
 
@@ -2591,7 +2601,7 @@ FE_NAVBAR_CONTROL_SIZE:
2591
2601
  meaning_vi: "Điều khiển trong navbar tại <file> không khai báo cùng cỡ control của Grammar."
2592
2602
  causes_vi:
2593
2603
  - "Cấu trúc shell không theo canon ứng dụng."
2594
- 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)."
2604
+ 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-core/README.md)."
2595
2605
  owner: op-retry
2596
2606
  kind: check-finding
2597
2607
 
@@ -2601,7 +2611,7 @@ FE_NAVBAR_CREATE:
2601
2611
  meaning_vi: "Navbar tại <file> chứa thao tác tạo mới thuộc nội dung trang."
2602
2612
  causes_vi:
2603
2613
  - "Cấu trúc shell không theo canon ứng dụng."
2604
- 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)."
2614
+ 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-core/README.md)."
2605
2615
  owner: op-retry
2606
2616
  kind: check-finding
2607
2617
 
@@ -2953,8 +2963,8 @@ FE_STACK_FAMILY_LINT_MISSING:
2953
2963
  title_vi: "Front end dùng canon-fe 9 nhưng thiếu gói lint của họ Grammar đã chọn"
2954
2964
  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."
2955
2965
  causes_vi:
2956
- - "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)."
2957
- 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."
2966
+ - "Nâng @starci/eslint-canon-fe lên 9 mà chưa thêm @starci/eslint-grammar-core (Grammar StarCi) hoặc @starci/eslint-grammar-offset-pop (Grammar Offset Pop)."
2967
+ nextStep_vi: "Thêm @starci/eslint-grammar-core (hoặc @starci/eslint-grammar-offset-pop) cạnh @starci/eslint-canon-fe, ghép coreGrammarConfig({ hfs }) (hoặc offsetPopGrammarConfig({ hfs })) sau starciFeConfig({ hfs }) trong fe/eslint.config.mjs, hoặc chạy starci app sync."
2958
2968
  owner: op-retry
2959
2969
  kind: check-finding
2960
2970
 
@@ -3011,7 +3021,7 @@ FE_STYLE_TOKEN_ONLY:
3011
3021
  - "@media dùng breakpoint ngoài thang của grammar"
3012
3022
  - "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"
3013
3023
  - "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"
3014
- 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)."
3024
+ 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-core/README.md)."
3015
3025
  owner: other-op:interface.implement
3016
3026
  kind: check-finding
3017
3027
 
@@ -3130,7 +3140,7 @@ FE_VENDOR_BOUNDARY:
3130
3140
  - "Dùng bộ glyph thứ hai ngoài họ heroicons (Phosphor, Lucide, Iconify...)"
3131
3141
  - "Dùng kích thước biểu tượng ngoài thang"
3132
3142
  - "Primitive thư viện ngoài dùng trực tiếp ở nhiều nơi"
3133
- 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)."
3143
+ 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-core/README.md)."
3134
3144
  owner: op-retry
3135
3145
  kind: check-finding
3136
3146
 
@@ -5007,7 +5017,7 @@ RT_GENERATED_BLOCK_STALE:
5007
5017
  RT_GENERATED_DRIFT:
5008
5018
  title: "Generated copy drifted"
5009
5019
  title_vi: "Bản sao sinh tự động bị lệch"
5010
- 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."
5020
+ 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-core/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."
5011
5021
  causes_vi:
5012
5022
  - "Sửa một tệp nguồn được đóng gói mà quên chạy sync-runtime"
5013
5023
  - "Sửa tay một tệp trong thư mục runtime/ của gói"
@@ -1,7 +1,6 @@
1
1
  // git-policy.mjs — which git commands an op worker may run in a checkout it
2
- // shares with other workflows. Pure: argv in, verdict out; scripts/guards/command-guard.mjs
3
- // (a PreToolUse hook) applies it to the agent's shell command before it runs, and the
4
- // reference-transaction hook git itself runs backs it (scripts/guards/hook-install.mjs).
2
+ // shares with other workflows. Pure: argv in, verdict out; a caller applies it to a
3
+ // shell command before it runs.
5
4
  //
6
5
  // Several workflows of one product ledger build in ONE checkout on ONE branch.
7
6
  // Their workers damaged each other with commands that are harmless alone:
@@ -12,7 +12,7 @@ import { fail } from './slot-errors.mjs';
12
12
 
13
13
  const HFS_RULES_FILE = 'knowledge/hfs/rules.yaml';
14
14
  const RULE_GATES = Object.freeze(['pre-commit', 'pre-push', 'settle', 'land', 'ci', 'sonar', 'runtime']);
15
- const ENFORCER_FAMILIES = Object.freeze(['eslint-be', 'eslint-fe', 'eslint-grammar-starci', 'stylelint', 'machine', 'hfs', 'work-validate', 'sonar', 'runtime']);
15
+ const ENFORCER_FAMILIES = Object.freeze(['eslint-be', 'eslint-fe', 'eslint-grammar-core', 'stylelint', 'machine', 'hfs', 'work-validate', 'sonar', 'runtime']);
16
16
  const RULE_KINDS = Object.freeze(['codemod', 'lint', 'check', 'design']);
17
17
  const FINDING_CODE = /^[A-Z][A-Z0-9]*(_[A-Z0-9]+)+$/;
18
18
  const ENFORCER_ID = /^[a-z][a-z0-9]*(-[a-z0-9]+)*$/;
@@ -346,7 +346,7 @@ export function loadRuleCatalog({ root = skillRoot, file = path.join(root, HFS_R
346
346
  /** The catalogued why code of a lint finding's rule id (`starci-be/<id>`, `starci-fe/<id>`), or undefined. */
347
347
  lintCode: (ruleId) => {
348
348
  const [plugin, id] = String(ruleId ?? '').split('/');
349
- const kind = (plugin === 'starci-be' && 'eslint-be') || (plugin === 'starci-fe' && 'eslint-fe') || (plugin === 'starci-grammar' && 'eslint-grammar-starci') || null;
349
+ const kind = (plugin === 'starci-be' && 'eslint-be') || (plugin === 'starci-fe' && 'eslint-fe') || (plugin === 'starci-grammar' && 'eslint-grammar-core') || null;
350
350
  return kind ? list.find((rule) => rule.enforcers.some((enforcer) => enforcer.kind === kind && enforcer.id === id))?.code : undefined;
351
351
  },
352
352
  /** The rules one enforcer judges, e.g. forEnforcer('eslint-be', 'error-home'). */
@@ -1,7 +1,7 @@
1
1
  // pipeline.mjs - HFS_CI_MISSING_CANON (R13): CI runs the pinned `starci app lint`.
2
2
  // .github/workflows/ci.yml a `run:` step that runs the one lint entry: `starci app lint`,
3
- // `npx @starci/cli[@<version>] app lint`, or `npm run <script>` whose command runs `starci app lint`
4
- // (`npm run lint`, arguments after `--` allowed); a version named in the step is the @starci/cli pin of
3
+ // `npx starci-harness[@<version>] app lint`, or `npm run <script>` whose command runs `starci app lint`
4
+ // (`npm run lint`, arguments after `--` allowed); a version named in the step is the starci-harness pin of
5
5
  // canon-pins.yaml (an installed one is pinned by the pin check, R15)
6
6
  // (the push hook is no lint or typecheck step: it checks the release gate, scripts/hfs/runtime-rules/hook-shape.mjs keeps its shape)
7
7
  // A missing file is the slot manifest's finding (HFS_SLOT_REQUIRED_MISSING); a file that is present and lacks the step is this rule's.
@@ -11,10 +11,10 @@ import { isRuntimeExampleApp } from '../../lib/runtime-example.mjs';
11
11
 
12
12
  const CI_MISSING_CANON = 'HFS_CI_MISSING_CANON';
13
13
  const CI_FILE = '.github/workflows/ci.yml';
14
- const hfsPackage = '@starci/cli';
14
+ const hfsPackage = 'starci-harness';
15
15
  const RUN_PREFIX = /^\s*(?:-\s+)?run:/;
16
16
  const NPX_PREFIX = /^npx\s+(?:(?:--no-install|-y)\s+)?/;
17
- const LINT_COMMAND = /^(?:@starci\/cli(?:@(\S+))?|starci)\s+app\s+lint/;
17
+ const LINT_COMMAND = /^(?:starci-harness(?:@(\S+))?|starci)\s+app\s+lint/;
18
18
  const NPM_RUN_PREFIX = 'npm run ';
19
19
  const EXAMPLE_RUN_PREFIX = 'node node_modules/@starci/hfs/runtime/scripts/hfs/example-secrets.mjs --run . -- ';
20
20
  const SCRIPT_NAME = /^[\w:.-]+/;
@@ -57,7 +57,7 @@ function parseNpmRun(command) {
57
57
  return args !== null && !LINE_TERMINATOR.test(args) ? { script, args } : null;
58
58
  }
59
59
 
60
- /** { version } of a `starci app lint` command (`version` undefined when no @starci/cli version is named), else null. */
60
+ /** { version } of a `starci app lint` command (`version` undefined when no starci-harness version is named), else null. */
61
61
  function lintCommandOf(command) {
62
62
  const rest = command.replace(NPX_PREFIX, '');
63
63
  const match = LINT_COMMAND.exec(rest);
@@ -10,6 +10,7 @@ import path from 'node:path';
10
10
  import { parseYaml } from '../../engine/yaml.mjs';
11
11
  import { validateAgainstSchema } from './json-schema.mjs';
12
12
  import { insidePath, samePath, slash } from './path-key.mjs';
13
+ import { resolveGrammarFamily } from './grammar-lint.mjs';
13
14
  import { byCodeUnit } from './list.mjs';
14
15
  import { isLiteWorkRoot, workPathAllowed } from './work-edition.mjs';
15
16
  import { WORK_DIR_NAME } from './roots.mjs';
@@ -49,9 +50,15 @@ export const REFERENCE_APP_MANIFEST = `${EXAMPLES_ROOT}/full-app/hfs.json`;
49
50
  /** The example app whose installed tree an fe-kit peer link points at by default. */
50
51
  export const REFERENCE_EXAMPLE_APP = 'full-app';
51
52
 
52
- /** The grammar css families a product repository may declare (`[data-grammar-family="<id>"]`); the
53
- * runtime's own product maps to the core sheet. */
54
- export const GRAMMAR_FAMILIES = Object.freeze({ starci: 'core', nivo: 'nivo', 'offset-pop': 'offset-pop' });
53
+ /** The grammar css families a product repository may declare (`[data-grammar-family="<id>"]`), keyed by the
54
+ * canonical catalog id; the runtime's own product maps to the core sheet. */
55
+ export const GRAMMAR_FAMILIES = Object.freeze({ core: 'core', nivo: 'nivo', 'offset-pop': 'offset-pop' });
56
+
57
+ /** A css family key through the Grammar catalog's alias table (`starci` reads as `core`); an id the catalog does not declare is kept. */
58
+ export function grammarCssFamilyKey(family) {
59
+ if (typeof family !== 'string' || !family) return family;
60
+ try { return resolveGrammarFamily(family).id; } catch { return family; }
61
+ }
55
62
 
56
63
  /** A feature-folder segment that is only the product's own name - no useful leaf (display-names pathLabel). */
57
64
  export const PRODUCT_NAME_SEGMENT = /^(nivo|starci|mia)[-\w]*$/i;
@@ -4,14 +4,27 @@ import { parseYamlCached } from './yaml-cached.mjs';
4
4
 
5
5
  const CATALOG_FILE = new URL('../../knowledge/grammars/index.yaml', import.meta.url);
6
6
 
7
+ function readCatalog() {
8
+ return parseYamlCached(fs.readFileSync(CATALOG_FILE, 'utf8'));
9
+ }
10
+
7
11
  function selectedFamily(family) {
8
12
  if (typeof family !== 'string' || !family.trim()) throw new Error('sides.fe.grammar must explicitly name the selected Grammar family');
9
- const catalog = parseYamlCached(fs.readFileSync(CATALOG_FILE, 'utf8'));
13
+ const catalog = readCatalog();
10
14
  const matches = (catalog.families ?? []).filter(entry => entry.id === family);
11
15
  if (matches.length !== 1) throw new Error(`Grammar family ${family} has no declared lint contract in knowledge/grammars/index.yaml`);
12
16
  return { catalog, selected: matches[0] };
13
17
  }
14
18
 
19
+ /**
20
+ * Resolve a selection to its declared family id; only a catalog family id resolves, there are no aliases.
21
+ * @param {string} family - The id an app or caller names (sides.fe.grammar).
22
+ * @returns {{ id: string }} The declared family id.
23
+ */
24
+ export function resolveGrammarFamily(family) {
25
+ return Object.freeze({ id: selectedFamily(family).selected.id });
26
+ }
27
+
15
28
  /** The explicitly selected authored family entry; callers share the catalog lookup rather than inferring a family. */
16
29
  export function grammarFamilyFor(family) {
17
30
  return Object.freeze(selectedFamily(family).selected);
@@ -24,13 +37,13 @@ export function grammarLintFor(family) {
24
37
  throw new Error(`Grammar family ${family} has no declared lint contract in knowledge/grammars/index.yaml`);
25
38
  }
26
39
  const lint = selected.lint;
27
- if (lint.package === null) return Object.freeze({ family, package: null });
40
+ if (lint.package === null) return Object.freeze({ family: selected.id, package: null });
28
41
  if (typeof lint.package !== 'string' || !lint.package.startsWith('@starci/eslint-grammar-')
29
42
  || typeof lint.factory !== 'string' || !/^[a-zA-Z][a-zA-Z0-9]*$/.test(lint.factory)
30
43
  || typeof lint.prefix !== 'string' || !/^[a-z][a-z0-9-]*$/.test(lint.prefix)) {
31
44
  throw new Error(`Grammar family ${family} has an invalid lint contract in knowledge/grammars/index.yaml`);
32
45
  }
33
- return Object.freeze({ family, package: lint.package, factory: lint.factory, prefix: lint.prefix });
46
+ return Object.freeze({ family: selected.id, package: lint.package, factory: lint.factory, prefix: lint.prefix });
34
47
  }
35
48
 
36
49
  /** The selected family's shared component/export contract, resolved through its catalog reference. */