fix(tools): parse UI source with the TypeScript compiler in the font gate (RIG-3855) - #1274
Open
rigel-mintaka wants to merge 1 commit into
Open
rigel-mintaka wants to merge 1 commit into
rigel-mintaka wants to merge 1 commit into
Conversation
…gate (RIG-3855)
The font-coverage gate located rendered characters with a hand-rolled
comment/string lexer. It had no JSX or regex-literal awareness, so an
apostrophe in JSX text opened a string state that never closed on that
line and swallowed everything after it until the next matching quote.
Measured on `apps/ui/src`: three files and 42 lines sat inside such a
fake quote state, invisible to the scan. `RightSidebar.tsx` shows both
directions of the bug — the apostrophe in `{handle}'s workspace` hid the
following lines, and when the state closed on a later quote the em-dash
inside a doc comment was reported as a rendered character. The sibling
gap had the same cause: a `//` inside a regex literal blanked its line.
The gate is WARN-only today, so the false positive is harmless. The
suppression is not: RIG-3742 makes the gate fail-closed, at which point
an uncovered glyph written into any of those lines passes green, which
is the failure the gate exists to prevent. The file's own header claimed
these gaps did not fire on the current tree; that claim was wrong and is
removed.
`scanSource` now parses with the TypeScript compiler and reads only leaf
tokens, so comment bodies drop out as trivia and JSX text, regex
literals, and template spans are located as the parser tokenizes them.
JSDoc subtrees are skipped explicitly: they are the one comment form
surfaced as real nodes, and without the skip every doc-comment em-dash
becomes a finding. `typescript` was already a declared devDependency of
this tool, so no dependency is added. `stripComments` is deleted; it had
no remaining references.
Verification. Old and new scanners were compared over 163 files keyed
`path:line:codepoint`: 94 findings before, 93 after, the single dropped
one being the doc-comment false positive, and nothing newly missed. A
span oracle marking every byte reached at a leaf or inside a skipped
JSDoc subtree, against comment trivia from `getLeadingCommentRanges`,
found no non-ASCII byte in neither set — no fail-open path. Every
finding's reported line and column round-trips back to its own
character. Malformed input (a hard parse error, an unterminated string,
JSX in a `.ts` file) still yields findings rather than silently
returning none.
Three tests pin the defect classes and genuinely fail against the old
implementation. Three more pin positions on tokens with leading trivia:
mutating the offset base to `getFullStart` previously survived the whole
suite, so a class of location bug was unpinned on a gate whose entire
output is `path:line:column`. `Finding.column` is now documented as a
UTF-16 code-unit offset and pinned by a test, since the old loop counted
codepoints.
One assumption is recorded rather than fixed: a `.ts` file containing
JSX would be parsed as non-JSX and its JSX text unscanned. It cannot
fire while JSX lives in `.tsx`, and parsing everything as TSX would
change how type-assertion casts parse.
RIG-3855
Co-authored-by: Matt Wilkinson <matt@rigel.build>
|
Merging to
After your PR is submitted to the merge queue, this comment will be automatically updated with its status. If the PR fails, failure details will also be posted here |
rigel-mintaka
marked this pull request as ready for review
September 17, 2026 03:00
|
Compass engineering docs preview: https://compass-ux-3855-font-gate-pa.compass-eng-docs.pages.dev Deployed from |
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.
The font-coverage gate located rendered characters with a hand-rolled
comment/string lexer. It had no JSX or regex-literal awareness, so an
apostrophe in JSX text opened a string state that never closed on that
line and swallowed everything after it until the next matching quote.
Measured on
apps/ui/src: three files and 42 lines sat inside such afake quote state, invisible to the scan.
RightSidebar.tsxshows bothdirections of the bug — the apostrophe in
{handle}'s workspacehid thefollowing lines, and when the state closed on a later quote the em-dash
inside a doc comment was reported as a rendered character. The sibling
gap had the same cause: a
//inside a regex literal blanked its line.The gate is WARN-only today, so the false positive is harmless. The
suppression is not: RIG-3742 makes the gate fail-closed, at which point
an uncovered glyph written into any of those lines passes green, which
is the failure the gate exists to prevent. The file's own header claimed
these gaps did not fire on the current tree; that claim was wrong and is
removed.
scanSourcenow parses with the TypeScript compiler and reads only leaftokens, so comment bodies drop out as trivia and JSX text, regex
literals, and template spans are located as the parser tokenizes them.
JSDoc subtrees are skipped explicitly: they are the one comment form
surfaced as real nodes, and without the skip every doc-comment em-dash
becomes a finding.
typescriptwas already a declared devDependency ofthis tool, so no dependency is added.
stripCommentsis deleted; it hadno remaining references.
Verification. Old and new scanners were compared over 163 files keyed
path:line:codepoint: 94 findings before, 93 after, the single droppedone being the doc-comment false positive, and nothing newly missed. A
span oracle marking every byte reached at a leaf or inside a skipped
JSDoc subtree, against comment trivia from
getLeadingCommentRanges,found no non-ASCII byte in neither set — no fail-open path. Every
finding's reported line and column round-trips back to its own
character. Malformed input (a hard parse error, an unterminated string,
JSX in a
.tsfile) still yields findings rather than silentlyreturning none.
Three tests pin the defect classes and genuinely fail against the old
implementation. Three more pin positions on tokens with leading trivia:
mutating the offset base to
getFullStartpreviously survived the wholesuite, so a class of location bug was unpinned on a gate whose entire
output is
path:line:column.Finding.columnis now documented as aUTF-16 code-unit offset and pinned by a test, since the old loop counted
codepoints.
One assumption is recorded rather than fixed: a
.tsfile containingJSX would be parsed as non-JSX and its JSX text unscanned. It cannot
fire while JSX lives in
.tsx, and parsing everything as TSX wouldchange how type-assertion casts parse.
RIG-3855
Co-authored-by: Matt Wilkinson matt@rigel.build