mirror of
https://github.com/garrytan/gstack.git
synced 2026-10-31 22:14:25 +01:00
design-lint: document the third-cycle limits and waiver scope
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
This commit is contained in:
1 parent
fc2685b528
commit
9bb348df77
3 files changed
+29
-5
No files matched your search
+1
-1
@@ -2,7 +2,7 @@
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
**A free, deterministic design lint ships with gstack: `bin/gstack-design-lint` checks a page's HTML, CSS and components for the tells that make it read as machine-made, in under a second, and with `--render` measures what only a browser can.** Until now gstack's only mechanical design check was the opt-in impeccable engine most users never install, plus `gstack-design-craft`'s seventeen copy and ship-floor regexes; everything else in the Slop Gate was prose the model judged itself. The lint ports the roughly fifty-five machine-checkable gates of [Nutlope/hallmark](https://github.com/Nutlope/hallmark)'s `sloplint` (MIT; see NOTICE.md) into TypeScript under `lib/design-lint/`, rewritten in gstack's voice and mapped onto gstack's severity words. This release is the tool alone (Phase 1 of plans/absorb-hallmark.md, approved by Garry on 2026-10-26); /design-html and /design-review start calling it in Phase 2, so no skill prose changes here.
|
||||
**A free, deterministic design lint ships with gstack: `bin/gstack-design-lint` checks a page's HTML, CSS and components for the tells that make it read as machine-made, in under a second, and with `--render` measures what only a browser can.** Until now gstack's only mechanical design check was the opt-in impeccable engine most users never install, plus `gstack-design-craft`'s seventeen copy and ship-floor regexes; everything else in the Slop Gate was prose the model judged itself. The lint ports the roughly fifty-five machine-checkable gates of [Nutlope/hallmark](https://github.com/Nutlope/hallmark)'s `sloplint` (MIT; see NOTICE.md) into TypeScript under `lib/design-lint/`, rewritten in gstack's voice and mapped onto gstack's severity words. This release is the tool alone (Phase 1 of the hallmark absorption plan, approved by Garry on 2026-10-26); /design-html and /design-review start calling it in Phase 2, so no skill prose changes here.
|
||||
|
||||
### Added
|
||||
- **`bin/gstack-design-lint <file-or-dir ...> [--render] [--url] [--scope page|component] [--job <job>] [--json] [--rules]`**: reads `.html`, `.css`, `.jsx`, `.tsx`, `.vue`, `.svelte` and `.astro` (Tailwind class strings included, `cn()`/`clsx()`/`cva()` calls too), links each page to the stylesheets it reaches through `<link>` and `@import`, resolves CSS variables, converts colours to OKLCH and computes contrast, and prints one line per finding: `LINT: <blocks|ask|polish|waived> <rule-id> <file>:<line> <evidence> | fix: <fix>`, then `LINT_SUMMARY: blocks=N ask=N waived=N polish=N render=<ran|skipped: reason>`. Exit 2 on blocks, 1 on an unanswered ask, 0 otherwise. `docs/design-lint.md` is the contract and lists every rule.
|
||||
|
||||
+27
-3
@@ -26,7 +26,8 @@ gstack-design-lint <file-or-dir ...> [--render] [--url <http://…>] [--scope pa
|
||||
- Reads `.html`, `.css`, `.jsx`, `.tsx`, `.vue`, `.svelte` and `.astro`.
|
||||
Tailwind class strings in components are read too, including `cn()`,
|
||||
`clsx()`, `cva()` and their kin. `node_modules`, dot folders and build
|
||||
output below the top level are skipped.
|
||||
output below the top level are skipped; a symlink is followed once; a file
|
||||
over 2 MB is a bundle, not a page, and is skipped with a warning on stderr.
|
||||
- A page is linted with the stylesheets it links (`<link rel=stylesheet>`,
|
||||
`@import`, and anything they reach); a directory of components shares the
|
||||
project's tokens and global state styles, so a focus ring declared once in
|
||||
@@ -92,7 +93,9 @@ about this page:
|
||||
`impeccable-disable <rule>: <reason>` is accepted as an alias, so a comment
|
||||
that already silences the impeccable engine answers the same tell here. The
|
||||
lint refuses, each as its own `waiver` finding at ask: a rule it does not
|
||||
know; a **blocking** rule (the Floor is never waivable; the one exception is a
|
||||
know; the lint's own rules (`render`, `waiver`, `house-style`,
|
||||
`internal-error`: a fallback face or a failed measurement is never signed off);
|
||||
a **blocking** rule (the Floor is never waivable; the one exception is a
|
||||
blocking rule the lint could only *suspect* on this page, which it reports at
|
||||
ask and which a waiver answers like any ask); a reason under 24 characters,
|
||||
boilerplate ("by design", "intentional", "looks better"), reused word for
|
||||
@@ -101,6 +104,14 @@ page's own text; a second waiver of one rule. More than three waivers
|
||||
on one page is a house style and belongs in DESIGN.md: reported once at polish
|
||||
as `house-style`.
|
||||
|
||||
A claim written in a stylesheet answers for that stylesheet on every page
|
||||
that links it, and only for findings located in it: the shared-word check does
|
||||
not apply (a stylesheet has no prose), so the claim cannot reach a finding in
|
||||
the page's own markup. Two claims on one line are both read. A blocking copy
|
||||
tell (`generic-hero-copy`) is the Floor inside the hero, the section or header
|
||||
that holds the h1; the same line in body copy further down is suspected and
|
||||
reported at ask, so a waiver can answer it.
|
||||
|
||||
## Rules
|
||||
|
||||
| Rule | Tier | Source gate | The tell | The fix |
|
||||
@@ -267,7 +278,20 @@ reports at the document's first line with a count, because
|
||||
patterns into the lint with lines. Where a rule id is shared with
|
||||
`lib/design-catalog.ts`, the tier here follows hallmark's gate (several
|
||||
catalog `ask` rows are `blocks` here); Phase 2 reconciles the two before a
|
||||
catalog row is marked `detect: lint`.
|
||||
catalog row is marked `detect: lint`. Also outside the lint: `system-ui` or
|
||||
`-apple-system` as the body's first face (`system-font-primary`; the
|
||||
`overused-font` rule reads display tokens and heading selectors, as hallmark's
|
||||
gate does), a gradient fill on the primary button (`gradient-cta`;
|
||||
`purple-blue-gradient` reports the banned hue pairs only, and an
|
||||
indigo-to-violet ramp needs stops 12° or more apart), `text-align: center`
|
||||
density, one large radius on everything, and backdrop blur on more than one
|
||||
container (`glow-wash` reports a blur over a translucent near-white or
|
||||
near-black fill; the zero-offset coloured glow is read from 8px in a Tailwind
|
||||
class and past 20px in a stylesheet, hallmark's two thresholds). The render
|
||||
tier's probes run in the page's own JavaScript, so a page that redefines them
|
||||
is caught only when it hands back a rule or grade the lint does not know; a
|
||||
page that answers every probe with nothing passes the render tier, which is why
|
||||
the static tier stands on its own and a URL target is measured, never trusted.
|
||||
|
||||
## What is deliberately not ported
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
* the page annotates that the lint has a rule for is reported, the clean
|
||||
* fixture is not, and both agree with hallmark's own sloplint on the same
|
||||
* files (checked by hand at hallmark 7ec8682; the gate set is identical).
|
||||
* Phase 1 of plans/absorb-hallmark.md, item D7: the free regression that a
|
||||
* Phase 1 of the hallmark absorption plan, item D7: the free regression that a
|
||||
* recorded output keeps linting the same way.
|
||||
*/
|
||||
import { describe, expect, test } from 'bun:test';
|
||||
|
||||
Reference in new issue
Block a user