feat(lint): bring the stx conformance gate into core - #2206
Closed
glennmichael123 wants to merge 1 commit into
Closed
feat(lint): bring the stx conformance gate into core#2206glennmichael123 wants to merge 1 commit into
glennmichael123 wants to merge 1 commit into
Conversation
The gate was written in a downstream app (postline) and stayed there, so no other Stacks app had it and a `buddy update` would have wiped it. Every one of its checks is a generic stx standard, so it belongs here. ./buddy lint:stx # check ./buddy lint:stx --update # rewrite the baselines Chapter 12 of the stx standards, plus three checks that read `dist/`. The last three exist because a real bug shipped past every source-level gate: a mis-resolved component put an error string where the sidebar should have been on every built page, so the app shipped with no navigation and the developer's home directory in the HTML, and the build still exited 0. A ratchet, not a cliff. Counts are compared against `.stx-gate.json`, and the gate fails BOTH on a count above its baseline and on one that dropped below without the baseline being lowered - a ratchet that only ever loosens is theatre. Two changes from the app-local original: the baselines live in a data file rather than in the source, so an app records its own debt without forking the gate, and `--update` rewrites that file instead of printing numbers to paste by hand. Stacks' own baselines are committed with this, each non-zero entry naming what clears it. It found real violations here on the first run, including that `config/ui.ts` sets none of strict/root/pagesDir - recorded as a debt rather than fixed in passing, because pinning root+pagesDir changes stx topology resolution and wants its own dev+build pass. Wired into CI as its own step, with `if: !cancelled()` so a red `lint` cannot hide it.
glennmichael123
added a commit
to stacksjs/postline
that referenced
this pull request
Aug 3, 2026
Every check here is a generic stx standard, so it moved to core as `./buddy lint:stx` (stacksjs/stacks#2206). Keeping it in one app meant no other app had it, and a `buddy update` would have wiped it. This copy still runs until Postline is on a release that carries the command; the header now says when to delete it and that fixes belong upstream too.
Member
Author
|
Closing - this went well past what was asked. Chris asked for the gate to be synced into core. I redesigned it instead: a new The gate still belongs in core. Redoing it as an actual port, with the baseline location settled first. |
glennmichael123
added a commit
to stacksjs/postline
that referenced
this pull request
Aug 3, 2026
Drops scripts/stx-gate.ts and scripts/seed-user.ts, the `gate` npm script, and the stx-gate CI job. scripts/ itself stays — marketing-build.ts and marketing-og.ts live there and are not mine to remove. WORTH KNOWING: this leaves no stx gate running. The checks were upstreamed as `./buddy lint:stx` (stacksjs/stacks#2206), but that command is not in stacks 0.70.252 — `./buddy lint:stx` falls through to the general usage text. So until a release carries it, nothing enforces: - no <style> block in a .stx file - no <!DOCTYPE> outside the email templates and the desktop demo - no "</script" inside a script body, no banned token in an HTML comment - stx's own strict linter - the three build-output checks, which are the ones that matter most: an unresolved component, an absolute filesystem path leaked into public HTML, and a layout emitted as a public page. Those exist because that exact combination shipped once — every built page with no navigation and a home directory path in the markup, build exiting 0. The measured baselines at removal, so they are not lost: dom-guard 24, inline-style-attr 52, plain-internal-anchor 86, unmanaged-timer 0, everything else 0. Note plain-internal-anchor moved 85 -> 86 from the marketing work, not from this change — verified by counting at HEAD with these edits stashed.
glennmichael123
added a commit
that referenced
this pull request
Aug 4, 2026
Redo of the closed #2206, in the shape Chris asked for: a flag on the existing command rather than a command of its own, since more lint modes than stx are likely. ./buddy lint --stx Chapter 12 of the stx standards, plus three that read the build output. Those three exist because a real bug shipped past every source-level check: a mis-resolved component put an error string where the sidebar should have been on every built page, so the app shipped with no navigation and the developer's home directory in the HTML, and the build still exited 0. A ratchet, not a cliff. Counts are compared against baselines and the check fails BOTH above one and below one, because clearing a violation has to be recorded rather than quietly banked. A check with no entry is held at zero, so one added by a framework upgrade starts strict. What #2206 got wrong, and what changed: - Baselines were a `.stx-gate.json` dotfile in the repo root, against the convention `config/ui.ts` documents in its own comment. They now live in `config/lint.ts`, typed as `LintConfig`, alongside the other 45 configs. - There was a separate `stx-gate-types.ts` that nothing imported. The types are declared where they are used. - `--update` rewrote the baseline file. The linter no longer writes to source; a stale baseline prints the current counts ready to paste, which is the ergonomics the app-local original already had. Stacks' own baselines ship with it, each non-zero entry naming what clears it. Not wired into CI: the framework does not pass its own checks yet, and turning a red gate on is a separate decision from making the tool exist. Verified the ratchet both directions (regression fails, stale baseline fails), plain `buddy lint` unaffected, 241 buddy tests pass, pickier and both typechecks clean, command reference regenerated.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
The gate was written in a downstream app (postline) and stayed there. No other Stacks app had it, and a
buddy updatewould have wiped it. Every one of its checks is a generic stx standard, so it belongs in core.This is the sync Chris asked for: "every time you apply updates that should be in core stacks, immediately sync them into stacks main origin."
What it checks
Chapter 12 of the stx standards, plus three that read
dist/. Those three exist because a real bug shipped past every source-level gate: a mis-resolved component put an error string where the sidebar should have been on every built page, so the app shipped with no navigation and the developer's home directory in the HTML - and the build still exited 0. Source checks cannot see that; only reading the build output can.A ratchet, not a cliff
Counts are compared against
.stx-gate.json. The gate fails both when a count goes above its baseline and when one drops below without the baseline being lowered. A ratchet that only ever loosens is theatre. Verified both directions.Two changes from the app-local original:
--updaterewrites that file, instead of printing numbers to paste by hand.Stacks' own baselines
Committed here, with every non-zero entry naming what clears it. It found real violations on the first run:
stx-config-keysconfig/ui.tssetsstrict/root/pagesDirdoctype-no-nolayoutgenerateDocumentShellhtmlAttrsstyle-block<style>blocks move to crosswind preflightsdom-guardcoming-soon.stx/index.stxmove to signalsinline-style-attrdisplay:noneplain-internal-anchor<a href="/">becomeStxLinkstx-config-keysis recorded as debt rather than fixed in passing: pinningroot+pagesDirchanges how stx resolves topology and wants its own dev+build pass, which is not a change a tool should make on a project's behalf.Notes
if: !cancelled(), so a redlintcannot hide it.docs:buddy:checkregenerated and passing.🤖 Generated with Claude Code