Alpha — breaking changes ship without a deprecation cycle. What is built vs. planned
Weird things & diagnostics
Transtyle prefers surprising you loudly over failing silently. This page lists every diagnostic code and every behavior that looks wrong until you know why it’s right.
How a diagnostic is printed#
Two lines, never one:
✖ TST1301 Target "bootstrp" is not configured in transtyle.config.json
↳ Did you mean "bootstrap"? Configured targets: bootstrap, primeng
The first line says what is wrong; the ↳ hint says what to change. They’re separate fields (message and hint) in report.json too, so editors and CI annotations can place them independently. The “What to do” column below gives the same advice. The hint exists so you get it at the moment of failure, without coming here.
Two behaviors to know:
- Identical diagnostics are printed once. Derivation runs once per mode combination, so a single authoring mistake used to be reported once per combination. A two-token alias cycle printed twelve lines. Anything per-mode still says which mode in its message.
- Consequences are suppressed in favor of causes. A dangling alias makes
semantic.color.primary.solidunresolvable, but you’re shown the dangling alias (TST1105), not the missing token (TST1201), because fixing the symptom wouldn’t have helped. Likewise an alias cycle reportsTST1104alone, not a “dangling alias” for each token in the loop. And a role whose.solidfailed to resolve (TST1105,TST1104,TST1106) draws no dark-mode carry-over note (TST1204), because there is no light-mode colour to carry over. A role bound to a slot derived too late drawsTST1205only when its alias resolves in the end; a dangling or looping one reportsTST1105orTST1104alone.
Diagnostic code reference#
| Code | Severity | Meaning | What to do |
|---|---|---|---|
TST1001 |
warning | A token glob matched no files | Check the path in tokens |
TST1002 |
error | A token file failed to parse | Fix the JSON; the message includes the parser error |
TST1003 |
error | A Tokens Studio export can’t be read: the path doesn’t exist, $metadata.json (or $metadata) has no tokenSetOrder, a listed set has no file, $themes isn’t a list, or a theme uses a set the order doesn’t list |
Point tokensStudio at the synced folder or the single-file export; re-export from Tokens Studio |
TST1004 |
error | A Tokens Studio theme group isn’t mapped, or its mapping is wrong: a theme left out of map, a theme or group name the export doesn’t have, two themes on one mode value, no theme on the dimension’s default, two groups on one dimension |
Map every theme of the group to a mode value (map), or compile one theme (fixed); the hint names the group’s themes |
TST1005 |
warning | A Tokens Studio set file is in the legacy format (value/type without $); it is read as DTCG |
Nothing to fix; switch Tokens Studio’s token format to W3C DTCG to silence it |
TST1006 |
error | A Tokens Studio expression can’t be evaluated: a function or operator outside the subset, two units in one expression, a non-number operand, division by zero, or a reference only derivation fills | Use the subset (+ - * /, parentheses, roundTo, min, max, floor, ceil, round, rgba(<color>, <alpha>)), one unit per expression, or author the computed value |
TST1007 |
error | A Tokens Studio token has a color modifier ($extensions["studio.tokens"].modify), which Transtyle doesn’t apply |
Remove the modifier and let derivation produce the state color, or author the resulting color |
TST1008 |
error | A Tokens Studio export can’t be lowered to a base layer plus mode layers: a token only a non-default theme defines, a type that differs between themes, two theme groups whose combination differs from their separate overrides, a path two sets place under different tiers, or a token that is a group in another set | Define the token in a set the default theme uses; keep one type; move tokens two groups both change into one group’s sets, or fixed one group; place both sets under one tier |
TST1009 |
warning | A Tokens Studio value is read with a loss: a font weight named with Italic (the style is dropped), or a token a non-default theme leaves out (the default theme’s value carries over) |
Put the italic in a typography token; add the token to a set the theme uses if it should differ |
TST1010 |
error | transtyle.config.json doesn’t match its schema: unknown key, wrong type, missing tokens, or a bad check.failOn/contrast.standard/derivation.contrast value |
Fix the flagged path; a typo’d key is an error, never silently ignored, and near-miss keys get a “did you mean” suggestion |
TST1011 |
error | A target’s options are invalid for its exporter: unknown option, wrong type, or a value outside the allowed set (for example an unknown shadcn era) |
Check the exporter’s page for its options; an exporter that takes none rejects any |
TST1012 |
info | A check.suppress entry silenced nothing: no diagnostic matched it, or it matched only an error, which cannot be suppressed |
Remove or fix the entry. When you build a single target, an entry for another target’s diagnostic reads the same way |
TST1013 |
error | check.contrast.standard (or derivation.contrast) is apca, but the apca-w3 package can’t be loaded from the project or the Transtyle install |
npm install --save-dev apca-w3 in the project (it is an optional peer dependency, see WCAG 2.1 or APCA), or go back to a WCAG standard |
TST1014 |
error | A declarative mapping (a target’s exporter pointing at a .json file, or a package whose manifest names one) can’t be read, isn’t JSON, or is malformed: a variable that doesn’t fit its template (--x, $x, @x), a variable written twice in one file, blocks outside a CSS file, a typography slot without a part, a mode dimension the design system doesn’t declare. One per problem, with the row’s path (files[0].rows[7].variable); nothing is written for that target |
|
TST1015 |
error | A declarative mapping row names a slot that is neither in the catalog nor in your design system (usually a typo); the hint gives the nearest slot | |
TST1103 |
warning | Token defined more than once across base layers (last wins). Not raised for a layer marked "override" |
Mark the layer that redefines on purpose "override": true in tokens, or remove the duplicate |
TST1104 |
error | Alias cycle (the loop only, in traversal order; a token that aliases into the loop is not listed) | Break the cycle |
TST1105 |
error | Dangling alias: {path} points at nothing (inside a composite, the message names the member’s path) |
Fix the path; check tier prefixes (option. vs semantic.) |
TST1106 |
error | Unparseable value (for example unsupported color syntax, a DTCG dimension object with no unit), or a malformed composite member, named by its own path (semantic.color.elevation.1.shadow.color) |
Colors: a CSS color or a DTCG color object (fourteen colorSpaces, three components, alpha 0–1, six-digit hex). DTCG objects need a number value and a px/rem (ms/s) unit; the hint lists every accepted form |
TST1107 |
warning | Mode-scoped file provides a value for a token with no default value | Add the token to a base layer first |
TST1108 |
warning | A mode value was overridden by a later layer | Confirm the layer order is intentional |
TST1109 |
error | Mode-scoped layer targets a mode not declared in modes |
Declare it, or fix the typo |
TST1110 |
error | Mode-scoped layer names no dimension ("mode": {}). A layer naming several dimensions is a combo layer, not an error |
Name the dimension and value the layer is for, or every dimension of the combination |
TST1111 |
warning | $extensions.transtyle.role.archetype isn’t brand/status/neutral |
The role still joins the grid regardless. Fix the value, or ignore it if intentional |
TST1112 |
error | color-scheme is declared (with more than one value) but isn’t the first mode dimension |
List it first. Only the first dimension carries light/dark polarity, so a later color-scheme would ship a dark block filled with light values, so the build stops rather than emit it |
TST1113 |
error | A semantic.* token aliases a component.* token: the alias points up the tiers, the wrong way (only the direct edge is reported: a chain names the token that points into the component tier) |
Alias the component token’s own source instead, or move the token under component.. Tiers layer option → semantic → component; the semantic tier is the stable surface the component tier reads from |
TST1114 |
info | option.* tokens that no alias resolves to (reported once per build, with the count and the first paths; the full list is in check --json) |
Alias them from a semantic or component token, or delete them. Severity is check.hygiene.unusedOption (info default, warning, off) |
TST1115 |
info | Several option.* tokens of the same type resolve to the same value (colors compared in OKLCH within a tiny tolerance); one diagnostic per group |
Keep one and alias the others to it, or give each its own value. Severity is check.hygiene.duplicateOption (info default, warning, off) |
TST1116 |
warning | A layer marked "override": true defines a token no earlier layer defines (usually a typo in the path), or is the first token layer and so overrides nothing |
Fix the path, or mark the layer "override": "extend" if it may add tokens |
TST1117 |
error | A bindings rule is malformed: an unknown placeholder (only {role}, {rung}, {level} exist), a from that is not one alias, a from placeholder the slot lacks, or roles without {role} or naming an unknown role |
Fix the rule; the hint names the placeholders and the known roles |
TST1118 |
error | A bindings rule marked required has slots whose target token does not exist (the message lists the first three) |
Author the missing tokens, narrow the rule with roles, or drop required |
TST1119 |
info | Two bindings rules bind the same slot; the earlier rule in the array wins |
Delete the later rule’s overlap, or reorder the rules if the later one should win |
TST1120 |
info | An authored colour that a semantic or component slot reaches is outside sRGB. Reported once per source token, naming the slots and the hex fallback | Nothing breaks: targets that write oklch() keep your colour, targets that write hex or HSL (Bootstrap, Storybook, ECharts, shadcn tailwind-v3) ship the clamped hex the hint names. Author an in-gamut value to pick the fallback yourself |
TST1121 |
warning | A partially authored scale (space, type.size, size.control, border-width, breakpoint, duration) ships out of order: a catalog default is out of order with an authored neighbour, or every authored token is outside the catalog’s rung names |
Author the whole scale, or rescale the authored rungs to fit between the defaults. For a renamed scale, author the catalog’s names or alias them to yours. One tuned rung that stays in order is silent |
TST1122 |
warning | A semantic.* or component.* slot takes its value from a token marked $deprecated: the slot itself, a hop of its alias chain, or a composite member’s alias. Once per slot and deprecated token, in any mode. A deprecated option.* token nothing reaches stays silent |
Point the slot at the replacement (the hint is the $deprecated reason, when it gives one), or remove the binding. Every target’s usage.md lists the variables still fed by it; check.suppress with the slot’s path keeps a planned deprecation from failing failOn: "warning" |
TST1123 |
warning | A DTCG srgb color object’s hex differs from its components by more than 0.01 per channel: the components are compiled, and the message names both |
Fix whichever is wrong in the token file, or drop hex. Within 0.01 per channel (a two-decimal export) the hex wins silently, as the color the design tool showed |
TST1124 |
info | A false-friend binding: secondary.solid (or accent.solid) is bound to a token named secondary (accent) whose colour is within ΔEOK 0.05 of neutral.tint (for accent, primary.tint or neutral.tint): shadcn’s meaning of the word, a subtle gray surface or a hover wash, not a brand colour. Once per word |
Bind neutral.tint (accent.tint) to that token instead and leave the role derived, or bind the role to your real second brand (emphasis) colour. See false friends |
TST1125 |
warning | A token has values on two non-default dimensions (say color-scheme: dark and contrast: more) and no combo layer for that combination, so the later-declared dimension’s value applies there; the message names the combinations |
Add a mode-scoped layer naming both dimensions with the combination’s value ("mode": { "color-scheme": "dark", "contrast": "more" }). If the later dimension’s value is meant for every scheme, nothing is wrong |
TST1126 |
error | A token sits at a catalog path that was renamed in place before the first stable release: today semantic.color.border, now the border ladder’s semantic.color.border.base. The old path would otherwise compile as a custom token nothing reads |
Move the token to the new path (turn the leaf into a group: "border": { "base": { "$value": … } }) and update every {semantic.color.border} reference |
TST1201 |
error | semantic.color.primary.solid missing. It’s the one token derivation can’t invent |
Author your brand color at that exact path; a bare semantic.color.primary is a different slot. Silent when an upstream error already explains the absence |
TST1202 |
error | A token in derivation.require was derived, defaulted or absent, not authored (an alias counts as authored). A completeness:<level> entry reports each item of that level left, dark neutrals included |
Author it, or remove it from require. transtyle check --completeness <level> lists a level’s items in order |
TST1203 |
warning | A role archetype has no authored .solid in a given mode |
Author <name>.solid for that mode, or drop the archetype extension |
TST1204 |
info | An authored or bound role’s .solid resolves to the same colour in a non-default color-scheme value as in the default one, so the whole derived grid carries over unchanged |
Author <role>.solid for that scheme value if it should differ. Default behavior, not a mistake. With derivation.autoDark: true, the carry-over is at least classified derived in coverage, but it still doesn’t compute a distinct color |
TST1205 |
warning | A role’s .solid (or text.base) aliases a slot derived after it is read: the alias resolves, but the role’s grid (or the content ladder under text.base) is not derived |
Alias an authored token or another role’s .solid or grid cell instead, or author the slot as a colour. A role bound to ring, link.*, palette.categorical.* or the content ladder hits this |
TST1206 |
info | text.base has no value of its own for a color-scheme value of the other polarity (dark under a light default, or the reverse) and elevation.0.surface is not authored, so that mode’s page and text are the default mode’s pair swapped (rule swap-neutrals). Once per scheme value; the hint gives the ratio the carried-over text would have had |
Nothing is broken. Author elevation.0.surface and text.base for that scheme value to choose them yourself |
TST1301 |
error | Requested target instance isn’t in the config | The hint distinguishes a typo (suggests the near name) from a real exporter you haven’t configured yet |
TST1302 |
error | A token declares $type but has neither $value nor child tokens |
Add the missing $value, or remove the leftover node |
TST1304 |
info | An $extensions namespace outside transtyle.* |
Nothing to fix. It’s carried through untouched, informational only |
TST1305 |
warning | A top-level group isn’t option/semantic/component |
Move the tokens under the right tier, or fix the typo |
TST1306 |
warning | A token’s $value has an unrecognized $type |
Use a DTCG type the IR understands, or accept it’s carried opaque |
TST1307 |
error | A token file looks like Style Dictionary v3 (value/type without $), so it has no DTCG tokens |
Convert it to DTCG ($value/$type/$description, references without .value); transtyle migrate --from style-dictionary does this for you |
TST1308 |
error | A target’s modes subset names a dimension or value the project doesn’t declare, or leaves out a dimension’s default |
Use declared names, and keep the default value (or change modes.<dimension>.default). See targets.<t>.modes |
TST1309 |
error | An exporter’s transtyle manifest declares an irSpec or a pluginApi this core doesn’t provide (one line per field, with the package, its version, what it declares and what core has). Every target is still checked, and nothing is written |
Install a release of the exporter built for this core (irSpec: "v0-draft", a pluginApi range accepting 0.0.0 such as "0"), or a core release that matches the exporter. See Write an exporter |
TST1310 |
warning | An exporter package has no transtyle manifest in its package.json (or it lacks irSpec or pluginApi), so its compatibility couldn’t be checked |
Add the manifest to the exporter’s package.json; the exporter still loads |
TST1311 |
warning | A token’s or group’s $description isn’t a string, or its $deprecated isn’t true, false or a string. The field is ignored; the token still compiles |
Write the description as a string; use true or a reason string for $deprecated (false opts a token out of its group’s deprecation). See Describing and deprecating tokens |
TST1312 |
warning | A generated file was changed or removed since the last build: its content no longer matches the sha256 in its output directory’s transtyle-manifest.json, or it is gone. Also fires once for a manifest that is not valid JSON or doesn’t match its schema. Only build and check look; a build warns, then overwrites |
Rebuild to get the generated file back, or move the change into the tokens or the config so it survives a build. If a formatter or linter rewrote it, exclude the output directory from that tool. See A generated file I didn’t touch is reported as changed |
TST1313 |
error | A target’s version is outside every range its exporter declares ("version": "4.6.2" on Bootstrap, >=5.3 <6), or the exporter declares no version ranges at all. The message lists the ranges; nothing is written for that target |
|
TST1314 |
error | A token has both a $value and child tokens. DTCG 2025.10 §6.1 makes that invalid: a token can’t also be a group, and the children were ignored |
Move the $value into a child (often base) so the node is a group, or move the children elsewhere |
TST1315 |
warning | The generated files still match their transtyle-manifest.json (nobody edited them), but a fresh compile writes something else: the tokens, the config or transtyle changed since the last build. One warning per target, naming the first files. Only check raises it; a build rewrites the files at once |
Run transtyle build to bring the output up to date; commit it if the output is committed, or have CI fail on check.failOn: "warning" to catch a forgotten rebuild |
TST2101 |
warning | Contrast below the configured standard: a WCAG ratio (4.4:1), or a signed APCA Lc (Lc -43) under apca. Checked on text.base/text.muted against the page surfaces, on every role’s on-solid and on-tint, authored or derived, and on the focus ring against the page surfaces (a non-text pair: 3:1 under WCAG, Lc 30 under APCA); measured in every combination of modes, and one level up in a contrast: more one (7:1, or APCA Lc 90 / Lc 75 for text, 4.5:1 or Lc 45 for the ring) |
Adjust the color, or accept the warning knowingly. When a color carried over from the default mode unchanged, the hint says so. That’s usually the real cause of a dark-mode warning. On a derived on-color, no candidate reached the level: author it or move its fill’s lightness. Under contrast: more, author the more value the hint names: authored values are never re-derived |
TST2102 |
warning | Two colors of palette.categorical.* are closer than ΔEOK 0.05 in a mode (clusters named once, closest distance printed) |
Author one of the entries as semantic.palette.categorical.N. Today’s derived palette never triggers it (its closest pair is 0.082); an authored palette can |
TST2103 |
warning | Two or more of success/warning/danger/info (and roles archetyped status) have .solid colors closer than ΔEOK 0.05 in a mode, or identical (one warning per cluster) |
Fix the source colors: when they are authored or bound that way Transtyle carries them through as written. Two roles bound to the very same token are intentional and skipped |
TST2104 |
info | shadcn: radius.md is above 0 but at most 4px, so shadcn’s own offsets bring --radius-sm (and --radius-md at 2px or less) to 0 or below; browsers clamp them to 0. Once per shadcn instance, named in the message |
Author radius.md above 0.25rem (4px) to keep every rung rounded, or 0 for a square design. radius.md: 0 never raises it |
TST2105 |
warning | shadcn: the target sets both options.era and a Tailwind version whose profile is the other era; the explicit era wins |
|
TST3001 |
error | An exporter threw while emitting. The message names the target instance and the exporter’s own error; the other targets still run, so every crash is reported in one go, but nothing is written to disk until all of them succeed | This is an exporter bug, not a design-system mistake. Re-run with --verbose (or TRANSTYLE_DEBUG=1) to print the stack, then report it or fix your plugin. Exits 1, like any error |
TST3002 |
error | An exporter could not be loaded (package not installed, or the exporter field is wrong). The message names the target instance; the other targets still run, and nothing is written |
Install the package in this project (npm install <package>), or fix the target’s exporter field |
TST1303 isn’t a separate code. An alias to a non-existent path is TST1105 above, part of the same “authoring mistake” family the DTCG validation pass (T10) documents together.
Aliasing a derived slot is fine and won’t raise TST1105: component.button.radius: "{semantic.radius.full}" works even though nothing authors radius.full, because such aliases resolve right after derivation. TST1105 means the target never exists, at any stage.
Surprising-but-correct behaviors#
A three-token design system is valid, and a target variable just goes missing#
Nothing obliges you to author a radius scale, a font stack, or a border color. If you don’t, the slots that derive from them don’t exist, and an exporter that has a binding for them emits nothing rather than a broken declaration. You’ll see the variable in report.json classed dropped, with a note naming the slot to author if you want it driven:
$btn-border-radius dropped nothing to bind: this design system has no
component.button.radius. The binding exists, its
source does not — author that slot (or the scale it
derives from) and this variable starts being driven.
The target’s own default then applies, which is what “we have nothing to say about this” should mean. A Bootstrap theme map is the one place an entry can’t go missing, because the exporter replaces Bootstrap’s whole map. The entry keeps Bootstrap’s own variable ("dark": $dark-text-emphasis) and is reported as $theme-colors-text.dark, dropped. check:minimal-ds compiles three design systems against every exporter on each CI run: a one-token one (only primary.solid, whose page and text the engine defaults), a three-token one (primary.solid, the page background elevation.0.surface and text.base), and one whose text.base is bound to a role cell (so neutral.text-strong and the content ladder stay empty). It asserts that none of them crashes and none writes a JavaScript value into a stylesheet.
My dark-native system comes out light-first#
modes.default declares your native mode; it doesn’t reorder exporter output. Exporters bind mode names. shadcn’s structure is always :root = light, .dark = dark, because that’s what shadcn consumers expect. Your native look is intact, just addressed by name. (Found by the Cathode example, now an IR rule.)
My brand color is identical in dark mode#
You didn’t author a dark value, so it falls back to the light one. That’s by design, and TST1204 (info) surfaces it in the report, not only here. The test is the resolved colour, not the token text: if you bound the role to your own vocabulary and that token carries a dark value, nothing carried over and no note is raised. Transtyle doesn’t invent brand decisions. Author primary.solid a dark-mode value (one line), or set derivation.autoDark: true so the carry-over is at least classified derived in coverage instead of authored. Either way the color itself stays the light one. autoDark doesn’t yet compute a distinct dark color, and that transform is still an open question (roadmap).
My dark page is my light text color#
You authored text.base with no dark value and left the page (elevation.0.surface) to the default, so dark mode got your light pair swapped: the page is your text color, the text is the light page. Before, your dark text carried over onto the default dark page at about 1:1. A page and its text, unlike a brand color, are not a brand decision, and the swap keeps your light mode’s exact contrast ratio. TST1206 (info) says it happened. transtyle explain semantic.color.text.base --mode dark shows the rule and the two light-mode values it read. Author both for color-scheme: dark to choose them yourself. An authored page is never swapped, even with no dark value: then the light pair carries over as written.
--secondary doesn’t look like my secondary color#
shadcn’s --secondary is a subtle surface (think of a secondary button background), not a brand-secondary. The exporter maps it from neutral.tint on purpose. Your brand secondary role exists in the IR and will map to targets that actually mean “second brand color”. The mistake in the other direction, porting a shadcn theme and binding its near-white --secondary gray to secondary.solid, is what TST1124 notes.
A variable is classified approximated#
Three current causes: --input (shadcn distinguishes input borders; the catalog doesn’t yet); gamut clamping where a target writes hex or HSL (shadcn’s tailwind-v3 era, Radix’s step scales, ECharts; the note says so); unit conversions. Approximation is information, not an error. The report exists so you can decide if you care.
Bootstrap and Storybook also write hex, but their reports do not class a clamped colour approximated yet. When the colour you authored is outside sRGB, TST1120 says so whatever the target, with the hex every hex-writing target ships.
Negative radius in the output#
shadcn derives its smaller rungs with fixed offsets: --radius-sm: calc(var(--radius) - 4px) and --radius-md: calc(var(--radius) - 2px). With radius.md: 0rem both are negative, and browsers clamp a negative calc() radius to 0, which is exactly what a square design asked for: nothing is reported. With a small non-zero radius (0.125rem, 2px), the same clamp turns rounded-sm and rounded-md square while you asked for rounded corners. That case is TST2104 (info), once per shadcn instance; author radius.md above 4px to keep every rung rounded.
Contrast warning on a color I like#
TST2101 prints the measured contrast: a WCAG ratio, or under check.contrast.standard: "apca" an APCA Lc whose sign gives the polarity (negative for light text on a dark background). Both are rounded toward zero, so a pair just under the level never prints as the level itself. It’s a warning, not a veto: set check.failOn to decide whether your CI cares. The number is real, though, and near misses (4.4:1) are the ones eyes don’t catch.
Two colors that can’t be told apart#
TST2102 and TST2103 measure the distance in OKLab (ΔEOK, the Euclidean distance CSS Color 4 uses for gamut mapping, where 0.02 is the just-noticeable difference). They warn under 0.05, and they report a cluster once per mode: four status roles that all resolve to the same color give one warning naming the four, not six pairs. Two slots bound to one token (warning and a custom crt-amber role both bound to {semantic.color.crt.amber}) are a stated intent, so that pair is skipped. Equal colors in different tokens are the accident the check exists for. Both are warnings, so check.failOn decides whether CI cares. The derived palette and derived status roles never trip them (closest pairs: 0.082 and 0.12); they guard authored values.
Part of my scale went backwards#
The catalog fills every rung you don’t author with its default (space steps by 0.25rem, type.size is a 1.25 modular scale), and authored tokens always win. Tuning one rung is fine. Authoring an 8px space.1 to space.4 (0.5, 1, 1.5, 2rem) is not: space.4 is 2rem while the default space.5 is 1.25rem, so the shipped scale goes backwards. Authoring a scale under your own names (space.sm/md/lg) replaces nothing, because targets read the catalog’s rung names. Both are TST1121 (warning), once per scale. Units are compared in px (rem at units.remBase, 16px by default) or ms; em and calc() values are skipped.
Suppressing a diagnostic#
A warning or info you have looked at and accept can be silenced in transtyle.config.json, with the reason written next to it:
"check": {
"suppress": [
{ "code": "TST1305", "path": "scratch", "reason": "scratch is a throwaway group for a spike" }
]
}
reason is required (an empty or blank one fails config load as TST1010). path is optional: an exact token path, or a prefix ending in .* (component.button.* matches the group’s children, not the group). Without path, the entry matches every diagnostic with that code, the only way to silence one that isn’t about a token, such as an exporter’s own TST2104. A suppressed diagnostic is silenced, not downgraded. It’s no longer printed and no longer counts for check.failOn. It stays auditable, listed with its reason under suppressed in report.json and check --json. Errors can’t be suppressed. An entry that matches nothing raises TST1012 (an info).
Where a diagnostic points#
A diagnostic about something you authored names the file, line and column of its key (✖ TST1105 tokens/brand.tokens.json:17:9 …), and report.json carries path, file, line and column. A diagnostic about a value Transtyle derived (a contrast ratio of a computed on-solid, a missing primary.solid) has no source line, because the value is in no file: it prints without one. Config-file errors name the file but not the line yet.
A generated file I didn’t touch is reported as changed#
TST1312 compares each generated file with the hash its last build recorded in transtyle-manifest.json. Something other than you can change a file. A formatter or a linter run over the whole repository (Prettier, Stylelint --fix) can, and so can an editor that trims trailing whitespace on save, or a merge that resolved a conflict inside dist/. Exclude the output directories from those tools (.prettierignore, the linter’s ignore file), then rebuild. Line endings are not a cause: hashes are taken with CRLF turned into LF, so a Windows checkout with core.autocrlf is not reported.
Two builds, byte-identical output#
Not a bug, a promise. No timestamps, no randomness, sorted file loading, fixed number formatting. If two builds of the same inputs ever differ, that is a bug, so please report it.