designesy
Score a site

Contract history

Contract Changelog

Every contract change, organized by design dimension. Track what was added, modified, adopted, and deprecated across versions, from the initial v0.1.0 contract through the current v0.4.7 contract and its 45-check engine.

Pattern from Artificial Analysis: changelog organized by modality (dimension) instead of by version. Each entry shows the version, date, what changed, which checks were affected, and the rationale.

01
The sound switch plays its whole cue when it mutes

Turning sound off plays the toggle cue and then turns the cuelume sound engine off. From cuelume 0.2.6, turning the engine off fades whatever is still sounding within 15 ms, and the site turned it off in the same click, so on cuelume 0.2.8 the cue that confirms a mute was cut to a click. The site now waits for the cue before it turns the engine off. The wait is 39 ms: the end of the longest layer in the recipe cuelume ships for the cue, 38.5 ms, rounded up to a whole millisecond. The cue as the site plays it, at normal emphasis, lasts 34.9 ms. Turning sound back on inside the wait cancels the mute, so the engine stays on and the switch says on. The switch, the html data-audio attribute and the stored preference change in the click, as before. For those 39 ms the engine is still on, so another cue that starts inside them, such as a hover cue, can still sound.

A sound switch confirms each change with a cue, and the mute cue was cut short. No check, scoring rule, weight or ceiling changed, no score moves and no version moves. A new gate, check-sound-mute, runs the real sound preference hook with cuelume, React and the clock stood in for.

Source: sound mute cue entry in CHANGELOG.md; cuelume 0.2.8 (src/audio/output.ts and src/sounds/recipes.ts)

02
Audio starts without a cue

Browsers start Web Audio only after a user gesture, so the site starts the cuelume sound engine during one, and a cue played later from a hover or a timer can sound. It did that by playing the tick cue on the first pointerdown, a cue of its own: with sound on, the tick played alone, or on a press control together with that control's press cue. The site now calls cuelume's unlock(), added in cuelume 0.2.6, which starts the engine and plays nothing. Unlike a cue, unlock() starts the engine whether or not sound is on, so the site skips it while the html data-audio attribute says off. It counts as done only once unlock() reports that audio has started. Before, the first pointerdown used it up even when the tick played nothing: with sound off, or on a first touch, which the browser does not yet count as a user gesture. A touch or a pen first becomes one at its pointerup, so the site now tries there too.

Starting the sound engine should make no sound of its own, and a page with sound off should start no audio from it. No check, scoring rule, weight or ceiling changed, no score moves and no version moves. Acoustic mapping rule 8, on /acoustic-tokens, in /acoustic-tokens.json, on /labs/acoustics and in docs/acoustic-tokens.md, now describes unlock(), and the acoustic token document stays 0.2.0. The extended cues keep a sound engine of their own, which this change does not touch, and the error cue on the 404 and error pages and the copy button's cues can still sound while sound is off, as before. A new gate, check-audio-unlock, runs the real cuelume binder with cuelume, React and the page stood in for.

Source: audio unlock entry in CHANGELOG.md; cuelume 0.2.8 (src/audio/engine.ts)

03
Fetch bounds: a finished read lets go of its signal, and every URL the MCP route reads for itself ends at 15 s

Three changes to how the site's server reads a URL. A read removes the abort listener it adds to its caller's signal once it resolves, fails or its request errors. It left the listener there, and Node keeps an AbortSignal.timeout that has a listener alive until its timer fires, so the read's request and body stayed in memory until then; readiness r04 and the MCP route's reads pass such a signal. Every URL the MCP route reads for itself now ends 15 s after it starts, DNS checks and redirects included, with the error "Fetch timed out after 15 s": the url of designesy_tokens_score and designesy_motion_score, and the designesy.org documents the seven read-only tools serve. The URL guard's own 15 s timeout fires only when the socket goes quiet, so a server sending one byte a second kept a call open with nothing to end it before the function's 300 s limit; these reads keep that 15 s idle timeout as well, so a server that pauses is waited for as long as before. The guard now joins a body's chunks once, into a buffer of the body's own size, and hands a reader that buffer, where the Response copied the bytes it was given: on Node 24.15.0, one read of an 8 MiB body peaks at 16 MiB with the score route's reader, down from 32, and at 24 MiB with an arrayBuffer() read, down from 32.

A read that has settled leaves nothing on its caller's signal, and no URL the MCP route reads for itself can hold a call open past 15 s. No check, rule, weight or ceiling changed, no score moves and no version moves; each tool keeps its result and error shapes. A new gate, check-fetch-bounds, runs the real URL guard and MCP route against a local server, with hosts that send one byte a second, and the fetch-layer gate now times the 204, 205 and 304 reads and a 999 status on a connection held open.

Source: fetch bounds entry in CHANGELOG.md

04
Read limits: each URL the MCP route reads for itself and each URL the readiness checks read holds 4 MiB, or 16 MiB for a Lottie file

Each URL the hosted MCP route reads for itself, and each URL the readiness checks read, now passes the URL guard a byte limit of its own, counted after decoding when a 2xx body is compressed and as sent for any other body, and the guard ends the request one byte past it. The url of designesy_motion_score is held to 16 MiB. The url of designesy_tokens_score, the seven documents the read-only tools read from this site, every readiness probe and r04's read of a tools/list answer are held to 4 MiB. Past its limit, an MCP read fails with "Fetch failed: the response is over the 16 MiB read limit" (4 MiB for the others), and a readiness check reports WARN with a detail that names the file and says it is larger than the 4 MiB read limit and was not read. The status is read first, so a 404 with a large body still fails as "Fetch failed: 404" in the MCP tools and is still judged as a 404 by the readiness checks that need an ok response. An error or redirect body is held to the same limit: of a 500 or a 302 whose body is 20 MiB, a read with a 4 MiB limit now receives 4,259,833 bytes, and designesy_motion_score, whose limit is 16 MiB, receives 16,842,745 of such a 500 (Node 24.15.0 on Windows), where all 20,971,520 arrived before. The MCP tools' errors, the verdicts of the readiness checks that need an ok response, and the next hop are as before. r10, which reads the page scanned whatever its status, is WARN for an error page past the limit. Before, a body sent with no content coding was read whole however long it was, and a compressed body that decoded past 4 MiB failed: in the MCP tools with an error that named no limit, and in readiness as a file not found or, for the page scanned, a scan that could not fetch it. So a gzip, deflate or br Lottie file that decodes to more than 4 MiB and at most 16 MiB, which failed before, is now read and scored.

A tool or a check reads a file whole or says it did not read it. The limits sit above the largest files measured: Lottie files of 8,873,709 and 4,713,147 bytes, token files of 1,674,878 bytes (@primer/primitives 11.10.0, dist/styleLint/functional/themes/light.json) and 1,039,520 bytes (@adobe/spectrum-tokens 15.6.0, dist/json/variables.json), the seven documents the read-only tools read from this site at 100,907 bytes or less, and this site's home page at 392,045 bytes. No check, rule, weight or grade boundary changed and no version moves. A result changes only for a file past its limit, and for a compressed Lottie file that decodes to more than 4 MiB and at most 16 MiB, which is now scored. Readiness results and reports are cached under new keys, so none made before the limit is served.

Source: read limits entry in CHANGELOG.md

05
Requests and deadlines: a POST through the URL guard carries its body, and a quiet server no longer ends a read before its deadline

The URL guard ended each request without writing the body its caller passed. Readiness r04 is the only caller that passes one, so its tools/list POST reached every endpoint empty, and an endpoint that reads the request, as one built with mcp-handler does, answered 400: r04 reported WARN for an endpoint that lists its tools. The guard now sends a string or byte body with its length, and on such an endpoint r04 moves from WARN to PASS, reached directly or through a 307 or 308, which raises the readiness score by 5. A 301, 302, 303, 307 or 308 is followed with the method and body fetch would use: a 303 to any method but GET or HEAD, or a 301 or 302 to a POST, becomes a GET with no body, which such an endpoint answers 405, so r04 stays WARN there. A quiet server no longer ends a read before its deadline. Node's global agent gives each socket an idle timeout of 5 s, or on a connection kept alive from an earlier answer, 1 s less than the Keep-Alive timeout that answer gave when that is 2 to 5 s. For a socket a read is using, the agent only sets it, and the URL guard ended the read when it fired, so a readiness probe, r04, a page or stylesheet read by the score, drift, guardrails, monitor or compare route, and a contract URL in contract mode, each with an 8 s deadline, failed early when its server went quiet. For a read given a signal, the guard now turns that idle timeout off. Such a file or page is now read: a check that reported it as not found judges it, and a page that was unreachable is scored. When the URL given is that slow and a later candidate URL answers, the page read is now the URL given's, so a score can move either way. One whose server stays quiet past 8 s still fails, and the score route now says the request timed out, where it said the request failed at the network level. The drift, guardrails, monitor and compare routes read a page's stylesheets one after another, and now ask for none once 20 s have passed since the first, as the score route's stylesheet phase ends at 20 s, so a page of many quiet stylesheets cannot hold them past their 60 s limit. A compare run, which then scores both URLs, can still reach its 60 s limit, as it could before. A report's composite moves with its score, drift and readiness results: r04 moving from WARN to PASS raises it by 1 when all three engines return a score (by 2 in a few cases, from floating-point rounding), and by 1, 2 or 5 when an engine returns no score and the report weighs the others again. Against a server that stays quiet or answers late, a run can now take longer than the published designesy-mcp package waits for it (20 s for a score, 30 s for the others), and that package then returns its timeout error: a readiness scan of a site that answers its page at once and is quiet for every other file took 40.1 s, where it took 25.2 s. Against a server that sends one byte a second, runs already took that long, and a drift, guardrails or monitor run of a site whose URL does so, and whose page at its www. host links 8 stylesheets that do so, now takes 28.0 s, where it took 72.0 s. Readiness, report, drift, guardrails, monitor and compare results are cached under new keys, so none made before this change is served.

r04 asks an endpoint for its tool list, so the request has to carry the question, and a quiet server no longer ends a read before the deadline its caller set. No check, rule, weight or grade boundary changed and no version moves. The score route's /DESIGN.md read has a deadline of its own of 5 s, so it moves only on a connection kept alive from an answer that gave a Keep-Alive timeout of 2 to 5 s, and only when it is asked for before the agent ends that connection unused, and the MCP route's reads, which had a 15 s idle timeout of their own, end at their 15 s deadline as before. This site's own r04 is answered in-process, as before.

Source: requests and deadlines entry in CHANGELOG.md

06
Engine 1.5.4: the engine reads the page the site served, decoded

Three fixes to how a page and its stylesheets are fetched, in every copy of the fetch code. A stylesheet href resolves against the URL that answered, after a redirect or a fallback www. or http:// address. It resolved against the URL given, so a page that had moved had its sheets asked of the host it moved away from. A body sent with Content-Encoding gzip, deflate or br is decoded before it is read, within the read's byte cap and a byte budget a page's stylesheets share, and the site's and the npm engine's requests name those three codings in Accept-Encoding. The offline Python engine asks for identity and decodes gzip and deflate only. A body that does not decode is left unread, and an error page keeps its status. A link that writes its href before rel=stylesheet is read.

A score describes the page a browser shows. Compressed bytes, or an HTML page fetched in place of a stylesheet, gave the checks nothing to read. No check, rule, weight or ceiling changed: a score moves only for a page reached through a redirect or a fallback address, served compressed, or linking a stylesheet with its href first.

Source: engine 1.5.4 entry in CHANGELOG.md; RFC 9110 section 12.5.3

07
Monitor contract 0.1.4: alert email is off unless the server switches it on

alert_delivery adds a condition: a server sends an alert email only when MONITOR_EMAIL_ENABLED is exactly "true" and, as before, an alert fires, the request names an email and RESEND_API_KEY is set. The switch is off unless set to exactly "true", because nothing confirms that an address belongs to the person who asked for the mail. m10 and the open questions name the switch. With it off and an alert fired, m10 says the alert was surfaced in-UI and that email alerts are off on the server. The m10 row now matches the engine: it passes when an alert is delivered, held back by the cooldown or surfaced in-UI, warns when a send fails, and never fails.

Rules changed: when an alert email is sent. No check is added. m10 stays PASS when an alert is only surfaced in-UI, so the one score change is a request whose send would have failed (WARN) that now sends nothing (PASS).

Source: Designesy monitor contract v0.1.4

08
Monitor contract 0.1.5: alert email is retired, and m10 is not scored

alert_delivery changed: alerts come back in the result (alerts[]), and the monitor sends no email under any setting. An email field in a request, of any type, is accepted and ignored, and no address is returned. m10 (alert delivered) is N/A on every run and is not scored; the ids m01 to m10 stay. The history a request carries is checked for shape and bounds (a score from 0 to 100, a grade from A to F, drift check ids d01 to d12, PASS, FAIL, WARN or SKIP, string lengths, at most 12 checks a run, at most 1000 runs, and a body of at most 512 KB), and a malformed history is refused with a 400 that names the field. Only what a check reads is required (each run's score, token count and checks, and each check's id and status), so a run trimmed to those is still answered. Before, a history of [{}] crashed the route, and a non-numeric score such as "x" broke the m03, m04 and m07 deltas.

Rules changed: m10 and the scoring. m10 passed on every run unless a send was tried and failed, so leaving it out takes a PASS out of the score: a stable site moves from 90 (A) to 89 (B) on its third run or later and from 95 to 94 on its second, and a first run stays at 100. No check is added or removed.

Source: Designesy monitor contract v0.1.5

09
Tokens contract 0.1.3: a token takes the type of its group, and $schema is Designesy policy

A token with no $type of its own takes the type of the token it references, else the closest $type on the groups above it, a group's $extends included, as the 2025.10 Format Module assigns it. Until 0.1.3 only a $type written on the token counted, so 13 of the 93 valid files in the DTCG 2025.10 test suite failed t03 and scored 50 to 71; none of the 93 now fails t03 or t06. A token written { $type, $ref } is counted, and a $ref that is a JSON Pointer is no longer a deprecated pattern; t10 reports a $ref that is not one. t04 fails a token with both $value and $ref, or a JSON Pointer that names nothing in the file or loops. The whole file is read, where a top-level group named tokens was scored alone. A missing $schema is a t01 WARN named as Designesy policy, where it was a FAIL that said DTCG requires it. t08 expects { value, unit } in px or rem and reports a string such as "16px" as the legacy form, which t10 also lists. With no tokens, t03 is N/A.

Rules changed: how a token's type is found, what counts as a token and as its value, the t01 verdict on a missing $schema, the dimension form t08 accepts and the $ref that t10 reports. The checks misread valid DTCG files and stated requirements the format does not make.

Source: tokens contract 0.1.3 entry in CHANGELOG.md; Design Tokens Format Module 2025.10, sections 5.2.2, 6.7.3, 7.1.2, 7.2.3, 7.5.1 and 8.2

10
Engine 1.5.1: scoring time grows in step with the page

The patterns that read a page's CSS and HTML now read each run of text once. Some retried from every place a match could start, so a long run of the right characters could hold a scoring request for many seconds. Each rewrite returns exactly what its pattern returned. v27 now finds the rule each font-size declaration sits in from one index of the sheet, where it read backwards once per declaration. The CSS rule parser reads at most 16 levels of nesting and closes at most 4 blocks left open at the end of a sheet, and the hosted engine reads at most 8 MiB of a page's HTML and 16 MiB of its stylesheets.

A scoring request should take time in proportion to the page it reads. Re-scored on the same bytes before release, every leaderboard result is identical. The parser bounds sit well above the deepest nesting in the cohort, so only a malformed or hostile sheet reaches them. No check, weight or ceiling moved.

Source: engine 1.5.1 entry in CHANGELOG.md

11
Engine 1.5.2: v46 reads the font shorthand

v46 read only font-size, so a size set through the font shorthand, such as font: 500 0.66rem/1 var(--mono), sat outside the check. It now takes the size from the shorthand: the first length, size keyword or size function ahead of the line-height slash and the family. A weight has no unit and a family is no length, so neither is read as a size. System font keywords (caption, menu) and inherit set no measurable size and are skipped. font-size is read exactly as before. The scan, the size test and the selector of each finding read the sheet once, so v46 takes time in step with the sheet.

This site's own hero console was sized through the shorthand, down to 8.8px under a 12.8px floor, and v46 never saw it: measuring the rendered page found the gap. Re-scored on the leaderboard cohort on the same bytes, no score or grade moves (v46 WARNs, it never FAILs); v46 measures more sizes on three sites, this one included, fewer on none, and finds new sub-floor or off-scale sizes on two.

Source: engine 1.5.2 entry in CHANGELOG.md; CSS Fonts 4 (the font shorthand); the design-system contract type scale (12.8px floor)

v46
12
Engine 1.5.0: score a page against your own contract

POST /api/score takes an optional contract: your DESIGN.md or DTCG token file, pasted or linked. The answer is two numbers that are never blended. Contract fidelity reads your contract: palette, type scale, line heights, radius, spacing, contrast pairs, aliases and token use (f01 to f14). The baseline reads no contract: focus rings, reduced motion, headings, inputs, button and link copy, identity. A contract the engine cannot read answers with each problem, its path and line. The formula is published at /api/score/checks/own-contract.

A team's own design system is the contract its pages are meant to follow, and the Designesy score measures Designesy's. Fidelity answers how closely a page follows the team's own; the baseline keeps the universal checks every site is held to, without Designesy's own taste checks, slop or originality. Requests without a contract are unchanged: no legacy verdict, detail or score moves, measured on the calibration corpus and on every legacy request the gate replays.

Source: engine 1.5.0 entry in CHANGELOG.md; W3C Design Tokens Format Module 2025.10; the DESIGN.md format (alpha); WCAG 2.2 SC 1.4.3 and 2.5.8

13
This site's accessibility gate now runs its axe rules

The accessibility sweep that runs on each change to designesy.org filtered axe-core by the tag wcag2a2a, which axe does not have. Given an unknown tag, axe runs no rules and reports no violations, so from its first run on 2026-10-04 to 2026-10-13 the axe half of the gate could not fail; its heading and landmark checks still ran. The sweep now runs the five tags the accessibility contract names (wcag2a, wcag2aa, wcag21a, wcag21aa, wcag22aa) and fails any page where axe runs no rules. Re-run on 2026-10-13 on all 70 routes, light theme at 1440px: no violations at any impact level.

A sweep that runs no rules reports the same result as one that passes, so a run with no rules is now a failure. Scores of other sites are untouched: the engine does not use this sweep. The 0 violations figure on /docs/mcp comes from a separate sweep on 2026-10-11 with the five tags, 140 page scans in the light and dark themes, so it stands.

Source: designesy-org pull request 316; axe-core 4.12.1 (runOnly with an unknown tag evaluates no rules)

14
Guardrails contract 0.1.1: the adoption figures and the DESIGN.md wording

Two edits shipped under 0.1.0 without a version. On 2026-10-12 the adoption signal moved to the 2026 zeroheight report for the hand-synced figure (60%, where it had said 40%: 40% is the share of teams with a token pipeline), and the designMd bundle line named the open DESIGN.md format without the vendor. On 2026-10-13 token adoption moved to the 2026 report's 86% (84% is the 2025 report's figure, and the 2025 report does not date the 56% it rose from).

Every contract change is versioned and dated in this changelog. These two were not, so 0.1.1 records them. No rule, threshold or weight changed.

Source: Designesy guardrails contract v0.1.1; zeroheight Design Systems Report 2026 (report.zeroheight.com)

15
Readiness contract 0.1.1: the DESIGN.md format named without the vendor

r05 and the readiness signal list now say "the DESIGN.md format" where they said "the @google/design.md standard" and "Google design.md standard". The readiness check reports r05 under the same new name. The package name stays where it is an install command, a code sample or a source citation.

Wording only: the DESIGN.md format is the thing a site serves, and the package is one tool that lints it. No rule, threshold or weight changed.

Source: Designesy AI readiness contract v0.1.1

16
Guardrails contract 0.1.2: the DESIGN.md format, named once

The method line now says the bundle generates "a file in the open DESIGN.md format", where 0.1.1 read "the DESIGN.md file (the open DESIGN.md format)".

Wording only: the name appeared twice in one phrase. No rule, threshold or weight changed.

Source: Designesy guardrails contract v0.1.2

17
Guardrails contract 0.1.3: g06 names the DESIGN.md format

The g06 check now reads "DESIGN.md emitted: the open DESIGN.md format (google-labs-code/design.md)", where it read "DESIGN.md emitted: Google open spec (google-labs-code/design.md)". The guardrails report shows the new name.

Wording only: the DESIGN.md format is the thing the bundle emits, and the repository stays as its source. No rule, threshold or weight changed.

Source: Designesy guardrails contract v0.1.3

18
Review-findings schema: description wording

The schema description and the token-path field description name the DESIGN.md format where they said "Google design.md".

review-findings schema: description wording; schemaVersion 1.0 unchanged, no field or constraint changed.

Source: Designesy review-findings schema (/specs/review-findings.json)

19
Compare contract 0.1.1: the 2026-09-28 editorial pass, versioned

One edit shipped under 0.1.0 without a version. On 2026-09-28 em dashes became colons or parentheses in source_authority, the diff dimensions, every check, the scoring note, the validation tools, relationship_to_core and open_questions. The purpose says "instead of file uploads", the scoring note says the score reflects diff completeness "rather than design quality, which is the /score surface", and token-value-changed is "the core drift indicator" where it said signal.

Every contract change is versioned and dated in this changelog. This one was not, so 0.1.1 records it. No rule, threshold or weight changed.

Source: Designesy compare contract v0.1.1; designesy-org pull request 153 (3d62df0)

20
Components contract 0.1.1: the card hover obligation, punctuated

One edit shipped under 0.1.0 without a version. On 2026-09-28 the Card / pillar hover obligation became "fine pointer only: gated on (hover: hover) and (pointer: fine)", with a colon where it had an em dash. This export also reads the design-system contract: its contract_version, component list, press scales and accessibility list follow that contract, and this changelog records those changes under the design-system versions.

Punctuation only. No rule, binding, threshold or weight changed.

Source: Designesy components contract v0.1.1; designesy-org pull request 153 (3d62df0)

21
Drift contract 0.1.1: the purpose, two citations and the editorial pass

Two edits shipped under 0.1.0 without a version. On 2026-09-28 em dashes became colons or parentheses across the drift modes, the twelve checks, the validation tools and open_questions, and silent_breaking_changes says consumers inherit the change "without notice" where it said signal. On 2026-10-12 the purpose dropped the line calling drift "the named 2026 design-system crisis" and now says AI-generated UI can drift off the tokens a site declares, and source_authority dropped two entries: the attribution of the four-mode taxonomy, and a drift-rate figure (23% in 8 weeks without formal review, 4% with it). The DRIFT_CHECK_COUNT export added on 2026-09-24 changed no served text.

Wording and citations only: the four drift modes, the twelve checks, their thresholds and the scoring are unchanged. No rule, threshold or weight changed.

Source: Designesy drift contract v0.1.1; designesy-org pull requests 153 (3d62df0) and 283 (6d75289)

22
Motion contract 0.1.1: an internal name and path out, and the editorial pass

Three edits shipped under 0.1.0 without a version. On 2026-08-03 an open question that named an internal rule ID now names the HyperFrames quality gate in plain words, and the full_contract_path field, which carried an internal file path, left the export. On 2026-09-28 the purpose dropped the words "not ornament", standard 1 says to use contract cubicBezier tokens "instead of bare CSS keywords", and em dashes became colons across the Lottie fields, the version notes, the reduced-motion notes and relationship_to_core.

Wording, and one field removed from the export. The ten motion standards, the checks, their thresholds and the scoring are unchanged. No rule, threshold or weight changed.

Source: Designesy motion contract v0.1.1; commits fb550a4 and 7f6d098, designesy-org pull request 153 (3d62df0)

23
Report contract 0.1.1: the score engine count, read from the engine

Three edits shipped under 0.1.0 without a version. On 2026-08-30 the composition, the score dimension, rp02 and relationship_to_core moved from a 40-check to a 42-check score engine. On 2026-09-24 those four places began reading the engine's check count instead of a typed number, with the same served text, and the count has since followed engine releases. On 2026-09-28 em dashes became colons or parentheses throughout, the rp08 warn band reads "20 to 30 points" where it used a dash, and "clearer signal" became "clearer result". This version also drops the "2026 crisis" claim from the weighting rationale, as drift's purpose did in #283: drift is second because it measures how far AI-generated UI departs from its declared system.

The weights (score 0.5, drift 0.3, readiness 0.2), the eight synthesis checks, the coherence thresholds (20 and 30 points) and the grade bands are unchanged. The check count states the size of the score engine, which the engine entries above record. No rule, threshold or weight changed.

Source: Designesy report contract v0.1.1; commit fe77f42, designesy-org pull requests 119 (d53eeae) and 153 (3d62df0)

24
Engine 1.4.0: type sizes come from the scale (v46)

A new check, v46, reads the type scale from a page's own :root type tokens (their values plus their median ratio) and judges every static rem or px font-size against it: off the scale when it sits more than 2.5% from every step, under the floor when it is smaller than the smallest type token. Deliberate fluid type, a clamp(), min() or max() that moves with a viewport or container unit, is accepted as written; only its lower bound is held to the floor. It WARNs, it never FAILs. The registry grows to 45 checks, 42 scored.

v16 asks for rem and cannot tell a rem on the scale from one between steps, so a page could pass it while its sizes drifted off the scale its own tokens declare. Measured on this site the day it shipped: v46 WARNs on 7 sizes under the 12.8px floor and 7 between steps, the display numerals and home rules this site's own type gate lists as deliberate exceptions. Fluid section titles pass as written.

Source: The design-system contract type scale (a Major Third on a 16px root, 12.8px floor), CSS Values 4 (clamp, min, max, viewport and container units), engine 1.4.0 entry in CHANGELOG.md

v16v46
25
Engine 1.4.1: v27 reads a field only in its own rule

v27 found the word input, textarea or select and then the next rule, across a closing brace, so "select" in user-select: none made the following rule a field rule and a 12px caption failed the page. It now reads each font-size against the selector of the rule it sits in. A class that names a field still counts, and select { font-size: 14px } still fails. v37 is renamed "DESIGN.md spec-layer validation (DESIGN.md format lint)", and its fix text names the format's linter; the install and run commands are unchanged.

A FAIL on a page whose fields are right is a wrong reading, and it caps the grade. Removing it raises the affected scores: measured on the leaderboard cohort on the same bytes, two sites move up, one by a full grade where the false FAIL had pulled its accessibility checks under the 60% cap. No score goes down. The leaderboard showed the new scores from its next re-score. This site stays 100 A, and a real field under 16px still fails.

Source: engine 1.4.1 entry in CHANGELOG.md

v27v37
26
Atkinson Hyperlegible Mono and the type scale

Atkinson Hyperlegible Mono replaces Geist Mono for labels, URLs, timestamps, score units and code. The type scale becomes six tokens on a Major Third over a 16px root: --text-label 0.8rem, the floor for all text, --text-body 1rem, --text-lead 1.25rem, --text-h3 1.563rem, --text-h2 1.953rem and --text-h1 2.441rem, no two adjacent steps closer than 25%.

The mono text on this site is the text a reader cannot guess from context: hosts, check IDs, scores and dates. Atkinson Hyperlegible Mono is the Braille Institute's face for low-vision readers, and it draws every confusable pair (0 and O, 1, l and I, 5 and S, 8 and B) distinct. Named sizes replace one-off values, so a page cannot drift off the scale. No check, weight or verdict changed.

Source: Designesy design system contract v0.4.5, adoption history; Atkinson Hyperlegible Mono 2.001 (SIL Open Font License 1.1)

27
Engine 1.3.1: four checks read what the page renders

v26 no longer counts a face named with the word fallback, such as a metric-matched stand-in drawn only until the real face loads, as a typeface choice. v27 reads font-size: var(--token) in a field rule through the :root tokens, so a field set to a 1rem token is the 16px floor it renders as, and one set to a 0.875rem token fails. v38 drops the keycaps a button marks up as kbd, and plain ctrl+s style hints in any case, from button labels, and accepts Get, Set, Try and a short list of call-to-action verbs (Flip, Learn, Sign, Join, Expand, Select, Read). v43 counts --destructive, the error role in shadcn/ui, as an error colour. The npm engine stops after three redirects instead of following a loop.

Each defect was a warning on a page that was right, this site among them: four families counted where three render, a 16px input read as unset, and a keycap button read as the words ctrl and i. A warning on correct work teaches readers to ignore warnings. v42 is unchanged: Tailwind v4 writes only the theme variables a project uses, so a sheet full of hue-named tokens is using them.

Source: engine 1.3.1 entry in CHANGELOG.md; Tailwind CSS v4 theme documentation (only used CSS variables are generated); shadcn/ui theming (--destructive)

v26v27v38v43
28
Accessibility contract 0.1.2: the five axe-core tags a WCAG 2.2 AA run needs

axe_tag and a01 now list wcag2a, wcag2aa, wcag21a, wcag21aa and wcag22aa, and the Playwright and CLI commands pass all five. 0.1.1 named wcag22aa as if it included the others, and its commands passed wcag2a, wcag21aa and wcag22aa. axe-core tags are not cumulative: wcag22aa alone marks only the WCAG 2.2 AA additions. rules_in_scope changed from "~75+ rules" to a count: 70 axe-core 4.13.0 rules carry one of the five tags (counted on 2026-10-11).

This changed what a01 measures: a run with the 0.1.1 tags left out the rules tagged wcag2aa and wcag21a. The pass and fail conditions (0 violations, any violation) did not change.

Source: Designesy a11y contract v0.1.2; designesy-org pull request 281 (83d1bcf)

29
Monitor contract 0.1.2: m01 asks for history, and a first run is not scored on it

m01 changed from "Schedule registered: URL + cadence recorded" to "History supplied": the request carries earlier runs to compare against, and nothing is scheduled or stored on the server. With no history m01 is N/A, because a first run sets the baseline. Scoring does not count that SKIP: the score is points over scored checks, where it divided by 10.

Rules changed: m01 checks what the engine does, which is compare against history passed in, and the scoring denominator.

Source: Designesy monitor contract v0.1.2; designesy-org pull request 281 (83d1bcf)

30
Monitor contract 0.1.3: m02 measures freshness against the cadence

m02 changed. It passes when the newest supplied run is within one cadence window (daily, weekly or monthly; weekly by default), warns between one and two windows, fails past two, and is N/A with no history or no usable timestamp. In 0.1.2 it said only that the last run fell within the cadence window. A SKIP of m02 on a first run is not scored. Earlier the same day, pull request 283 corrected how the contract describes monitor: each call re-runs the drift checks and compares the result with the history the caller passes in, nothing is scheduled, and the server keeps no history. In the same edit two quoted sources were re-quoted and re-attributed, a third was removed, and the competitor line became a description of the method.

Rules changed: the m02 thresholds, and the scoring of a first run. The description edit from pull request 283 changed no check.

Source: Designesy monitor contract v0.1.3; designesy-org pull requests 297 (7190efc) and 283 (6d75289)

31
Engine 1.3.0: no A while any check fails

A page with a failing check can no longer score an A: any FAIL caps the score at 89.9, a B, and every cap applies after the originality lift, which can carry a score up to a cap but never past it. v44, status colors used as text, caps at 65 as v06 does. v34 fails only a chat surface that names itself a chatbot or an AI assistant; a live-chat widget, an ad tag or page text about AI is at most a review item, and its text cites California SB 1001 and Colorado SB 26-189 and names Article 50(1) as a duty on the provider of the AI system. v06 and v22 read oklch(), space-syntax rgb() and hsl(), 8-digit hex, and tokens declared as :root, :host. v42 and v43 follow var() aliases, and hue-named primitives that role tokens alias form the palette layer, which sits outside the role share.

The engine could report its own failing WCAG contrast check and an A for the same page, and its review printed Block and Grade A together. A grade beside its own failing verdict says two things at once, so the engine takes the stricter reading.

Source: WCAG 2.2 SC 1.4.3 and 1.4.11, EU AI Act Article 50, California Bus. & Prof. Code §17940-17943, Colorado SB 26-189, CSS Color 4, engine 1.3.0 entry in CHANGELOG.md

v06v22v34v42v43v44
32
Identity v1 colour system

Azure #0A94FF replaces the previous blue as --signal. In the light theme, text, links, focus and selected states take Deep Azure #016ABB (--signal-access, --signal-deep), and text on an Azure fill is ink #010102 (--paper-on-signal, 6.65 to 1). Activated Orange #F56B00 replaces the previous yellow (light text #B04D00), and grade D moves to rose. New tokens: --signal-deep, --signal-teal, --action, --on-action, --action-pressed and --paper-white.

The contract states the identity v1 colour system that designesy.org serves. It changes token values only: no check, weight or verdict changed.

Source: Designesy design system contract v0.4.4, adoption history

33
Tokens contract 0.1.2: a WARN counts half, and t08 reads aliases

Scoring counts a WARN as 0.5 where 0.1.1 counted it 0: score = (PASS + 0.5 × WARN) / scored checks × 100, as in the motion contract, the score engine and the npm validator. t08 resolves a {group.token} alias to the dimension it points at, and a $root token is checked like any other. The open item on aliases now says t08 resolves them on dimension tokens and that checking every alias target type is not wired. live_export states 9 PASS, 0 WARN, 0 FAIL and t07 SKIP, and describes the export's DTCG values.

Rules changed: the WARN weight in the scoring formula, and how t08 reads aliases.

Source: Designesy tokens contract v0.1.2; designesy-org pull request 258 (e10ed5f)

34
Monitor contract 0.1.1: m09 reads the contract version a run is scored against

m09 changed: it compares the design contract version the run is scored against (the version designesy_score reports), where 0.1.0 read the scanned site's own DTCG or agent.json version, which on designesy.org is the catalog version. Snapshots do not record that version yet, so a change between runs is stated rather than compared. An edit that shipped under 0.1.0 without a version is recorded here too: on 2026-08-02 m10 changed from a webhook, email or Slack alert to an email alert, and an alert_delivery section says when email is sent and that alerts show on the page when it is not. On 2026-09-28 an editorial pass replaced em dashes.

Rules changed: what m09 compares, and the delivery channel m10 checks.

Source: Designesy monitor contract v0.1.1; designesy-org pull request 254 (f4f9a51), with commit b1e1e66 and pull request 153 (3d62df0)

35
Tokens contract 0.1.1: the checks match the engine, and a SKIP is not scored

Edits that shipped under 0.1.0 without a version come first. On 2026-08-30 the ten checks were replaced with the ten that designesy_tokens_score runs: t01 $schema declared, t02 token groups, t03 $type, t04 $value, t05 structured colour, t06 standard types, t07 namespaced custom types, t08 dimension units, t09 nested groups, t10 no deprecated patterns. $schema moved from SHOULD to MUST, scoring counted a WARN as 0 where it had counted 0.5, and the five rules the engine does not check moved to documented_not_engine_wired. Before that, on 2026-08-03 the full_contract_path field, which carried an internal file path, left the export, and on 2026-08-09 a live_export line was added. On 2026-09-28 an editorial pass replaced em dashes. The 0.1.1 edit itself: a SKIP is not scored (it had counted in the denominator, so a clean file with no custom types scored 90), and live_export reports the DTCG export at 100 with t07 SKIP.

Rules changed: the check list, the $schema requirement and the scoring formula. Each edit is recorded here because none had a version or a changelog line when it shipped.

Source: Designesy tokens contract v0.1.1; designesy-org pull request 254 (f4f9a51), with commits 7f6d098, ed99914, 7f8e7d4 and pull request 153 (3d62df0)

36
Text tokens for every status and grade colour

Each status, grade and activation hue gains a text token, --<hue>-ink: the hue itself in the dark theme, and in the light theme the hue mixed toward ink until it reads at 4.5 to 1 or better on every surface. Light --muted-dim darkens from #70707a to #686872. Dots, bars, borders and tints keep the hue.

A rendered sweep of every public page found 230 text elements under WCAG AA in the light theme and 11 in the dark. Nearly all were one mistake repeated: a colour chosen to mark a state (3 to 1 is enough for an icon) used to write the word for it (text needs 4.5 to 1). A text token per hue makes the right choice the default, and the site build now fails on a bare hue used as text.

Source: WCAG 2.2 SC 1.4.3 and 1.4.11, rendered contrast sweep of designesy.org (2026-10-08), CSS Color 5 color-mix()

37
Engine 1.2.0: status text contrast and paused entrances

v44 measures every status color a stylesheet uses as text, in every theme it declares, and fails a status-named color with a hue that reads under 4.5 to 1 (3 to 1 for large text, an icon or a bar) on a surface the stylesheet attests; where it cannot attest the surface, or the text is white or grey, it warns. v45 fails an entrance that starts at opacity 0 and stays held invisible when a visitor pauses motion. Every score gains both, so the engine runs 44 checks. The S2 and S8 anti-slop rules stop deducting for components and prose, and the npm engine caps scores by the same accessibility floor as the site.

Both defects shipped on this site and passed every check the engine had: the CSS was valid and the default view looked right. The light warning color wrote status words at 3.51 to 1, and the pause control emptied whole pages for the visitors who had asked for less motion. A check that catches its own author is the one worth publishing.

Source: WCAG 2.2 SC 1.4.3 and 2.2.2, CSS Animations Level 1 (animation-play-state), engine 1.2.0 entry in CHANGELOG.md

v44v45
38
Engine 1.1.0: four baseline fixes

v05 passes a site that declares its motion only inside prefers-reduced-motion: no-preference, provided the block opts into motion; an empty block, or one that only switches motion off, still warns. v27 reads N/A on a page with no text input, textarea or select when its CSS sets no input font size. v14 and v18 join the optional tier, so an external site that does not adopt the Cadence rules is skipped on them. The MCP token validator checks against the 13 types DTCG 2025.10 defines. Scored on pages captured from the 30 leaderboard sites on 2026-10-08, 21 change at least one verdict.

Each fix removes a verdict the engine could not defend. Gating motion behind no-preference is a recommended way to honour reduced motion; a page with no field gives iOS nothing to zoom into; and v14 and v18 judged external sites on Designesy taste under the scope meant to be fair to them. The engine version moves so a score from before the fix and one from after it can be told apart.

Source: Media Queries Level 5 (prefers-reduced-motion), DTCG Format Module 2025.10, engine 1.1.0 entry in CHANGELOG.md

v05v14v18v27
39
One shell edge, a 12-column grid, and the accessibility tint tokens

The header, the page wrappers and the footer now share the content edges at every width, so nothing sits on a different gutter than the thing above it. A 12-column grid with a named 7|5 seam replaces the per-page split rules. The material, elevation and floor recipes became tokens rather than values repeated per component. The WCAG 2.2 AA pass added the accessibility tint tokens, including --signal-text as the text-safe role for the brand blue. The reduced-motion tiering is stated as it now behaves: movement stops, opacity fades and transitions of 200ms or less stay.

The site described one alignment system and implemented four, and the disagreement was invisible to every automated check because none of them compared one region's edge to another's. The accessibility tokens close a measured contrast failure: the brand blue as text read 2.0 to 2.3 to 1 in dark mode against a 4.5 to 1 minimum. Naming the motion tiering settles a documented conflict between two readings of the same clause.

Source: Designesy a11y contract v0.1.1, WCAG 2.2 AA (2.4.11, 1.4.3, 2.5.8), edge-contract measurements

40
Accessibility contract 0.1.1: a10 tests what moves under reduced motion

a10 changed. Under 0.1.0 it read "prefers-reduced-motion disables animations" and passed when a reduced-motion rule was present, failing when it was missing. Under 0.1.1 it passes only when nothing translates, rotates, scales or pans for longer than 200 ms or in a loop under reduce, and fails when movement continues. Opacity-only fades may continue, and demos whose motion is the content play on request. Edits that shipped under 0.1.0 without a version are recorded here too: on 2026-08-03 a11 named internal control-plane names where it said internal naming, and the full_contract_path field, which carried an internal file path, left the export; on 2026-08-30 the named axe-core version moved from 4.12.1 to 4.13.0; on 2026-09-28 an editorial pass replaced em dashes.

This version changed a rule: a10 used to pass on the presence of a reduced-motion block and now passes on what moves under reduce, as the motion contract requires.

Source: Designesy a11y contract v0.1.1; designesy-org pull request 173 (66f51e5), with commits fb550a4, 7f6d098, d2cc52e and pull request 153 (3d62df0)

41
Editorial revision: the contract text follows the public-copy rules

The contract modules and the /contracts pages were revised together. A colon or parentheses replaces the em dash, the positive claim replaces rhetorical negation pivots, and number ranges read "to". No rule, value, token or check changed. The sibling contracts took the same pass and keep their versions.

The contract asks product copy to state its claim plainly and to write ranges a screen reader can read: an unspaced en dash is skipped, so a range written with one is heard as two bare numbers. A patch version marks text that changed while every rule stayed the same.

Source: Designesy public-copy rules, GOV.UK style guide, plainlanguage.gov, NVDA symbol handling

42
Semantic category wired: v42 + v43

The semantic category carried a reserved weight (12) with zero checks since v0.3.0. Two deterministic checks now score it: v42 measures the role-named vs hue-named share of :root color tokens; v43 checks status-state coverage (ok/warn/error/info). Engine grows 40 → 42 checks.

The contract's own palette is fully role-named (--ink, --paper, --surface, --signal, --ok/--warn/--error): color named by meaning rather than wavelength. Role-based naming is the documented best practice (zeroheight naming guide, Material 3), but nothing scored it. Both checks are WARN-only (style craft with no user harm) and self-SKIP when a site has no color tokens.

Source: Designesy contract colors section, zeroheight naming guide 2026, Material 3 design tokens

v42v43
43
UX copy principles adopted

Four heuristic checks: button verb phrases (no "Click Here"), no trailing periods on interactive elements, descriptive link text (WCAG 2.4.4), no ALL CAPS in body copy. Grounded in NN/g, Microsoft Fluent, IBM Carbon, and WCAG.

Copy is design: "Click Here" is an accessibility failure and a usability smell. Weight 8 of 117 (6.8% of the score). New in v0.4.0.

Source: NN/g, Microsoft Fluent, IBM Carbon, WCAG 2.4.4

v38v39v40v41
44
Engine upgraded to 40 checks

Engine expanded from 36 to 40 checks. Copywriting category added (4 checks). Accessibility floor enforced: if accessibility scores below 60%, overall grade capped at C. Twelve anti-slop rules now subtract up to 20 points. Seven originality signals add up to 8 points.

The engine must evolve with the contract. Each version bump adds precision: the anti-slop rules catch generic AI-generated patterns that pass individual checks but fail as a composition.

Source: Designesy engine v1.0, contract v0.4.0

45
Spec-layer integration (DESIGN.md)

New check: validates the DESIGN.md spec file with the DESIGN.md format's linter. Integrates the spec layer beneath designesy's own contract verification.

DESIGN.md is the AI-agent-facing spec file. With it, AI coding tools build from your system instead of around it. The check validates its presence and structure.

Source: Google @google/design.md CLI linter

v37
46
Independence firewall + compliance_index_version

Public commitment: Designesy does not accept payment for scores, methodology changes, or leaderboard placement. API responses now include compliance_index_version field (currently "1.0") for machine-consumable CI pipeline integration.

The trust asset must be structurally non-monetizable. Pattern from Artificial Analysis (independence firewall) and Arena (structural neutrality). The compliance_index_version field makes scores machine-consumable for CI pipelines.

Source: Artificial Analysis independence firewall, Arena structural neutrality

47
Acoustic mapping rules adopted

Lab Four acoustic mapping rules promoted to contract: interaction sound synthesis via Web Audio API, acoustic tokens for press/hover/settle sounds, sound-toggle aria-pressed, reduced-motion tiering for acoustic events.

Acoustics is the frontier: most design systems have no acoustic layer at all. The contract defines acoustic tokens the same way it defines motion tokens: named, typed, and tiered for reduced-motion.

Source: Lab Four · Acoustic mapping, Cuelume v0.2.2 engine

48
Cadence typography rules adopted

Lab Three typography rules promoted to contract: font-smoothing, rem-based sizes, line-height, text-wrap (balance/pretty), tabular-nums, selection styling, font-synthesis, underline-position, skip-ink. 12 checks, the largest category.

Cadence is typography rendering discipline: the difference between type that looks crisp and type that looks fuzzy. Weight 18 of 117 (15.4% of the score), the heaviest category. Most sites fail here because font-synthesis and text-wrap are rarely declared.

Source: Lab Three · Cadence typography experiments, NY Times editorial reference

v14v15v16v17v18v19v20v26v28x01x02x03
49
Takt interface-feel rules adopted

Lab Two interface-feel rules promoted to contract: stagger enter animation-delays, soften exit transforms with ease-out, concentric border-radius sets. Named after the German word for precise, musical timing.

Takt is the musicality of interaction: the timing and scaling that makes a press feel intentional. Press scales above the 0.95 floor: 0.96 cells, 0.985 cards, 0.995 surfaces.

Source: Lab Two · Takt interface-feel experiments

v19v20
50
Poise interaction rules adopted

Lab One interaction rules promoted to contract: hover lifts with @media (hover: hover) guards, press settle scales, keyboard-path documentation, sound-toggle aria-pressed.

Poise is interaction poise: the difference between a site that feels considered and one that feels janky. Hover guards prevent touch-device flash; press scales provide tactile feedback.

Source: Lab One · Poise interaction experiments

v09v10
51
Initial token architecture checks

Two scored checks for token presence: --paper foundation variable at :root, and token layer depth (primitive → semantic → component).

Token architecture is the substrate: without a root surface variable and layered tokens, every other dimension is ad-hoc. Weight 9 of 117 (7.7% of the score).

Source: Designesy design system contract v0.1.0

v01v02
52
Initial motion hygiene checks

Four checks: no transition:all, will-change restricted to transform/opacity, prefers-reduced-motion block present, duration tokens declared.

Motion hygiene is the most violated dimension in the cohort. transition:all causes layout thrashing; missing reduced-motion is an accessibility failure.

Source: Designesy design system contract v0.1.0

v05v06v07v08
53
WCAG 2.2 AA primitives

Six checks: contrast ratios, touch targets (44px), heading hierarchy, input font floor (16px), button-text contrast, forced-colors readiness.

Accessibility carries the a11y floor: if this category scores below 60%, the overall grade is capped at C. Weight 15 of 117 (12.8% of the score).

Source: WCAG 2.2 AA, APCA contrast model

v11v12v13v14v15v16
54
Document identity checks

Two checks: semantic HTML landmarks (h1, title, meta description, main/header/nav) and AI-disclosure readiness per EU AI Act Art 50.

Document identity is the machine-readable surface: without landmarks and meta, the page is opaque to both screen readers and AI agents.

Source: EU AI Act Article 50, HTML landmark spec

v07v34
55
Unicode security check (UTS #39)

One check: UTS #39 confusable detection in token names and CSS identifiers. Prevents Cyrillic/Greek homoglyph shadowing attacks.

Homoglyph attacks in CSS identifiers can spoof brand colors and redirect trust, and a linter that reads values does not read names.

Source: Unicode Technical Standard #39

v36
56
Deterministic 40-check engine

The scoring engine itself: CSS extraction, :root custom property parsing, 40 checks across 14 weighted categories, A-F grade bands.

The engine is the moat: deterministic, open, and reproducible. No LLM, no human judgment, no survey. The same engine scores every site identically.

Source: Designesy engine v1.0

Version summary

01
Initial contract

Tokens, motion, accessibility, identity, security. Deterministic engine.

02
Poise adopted

Interaction rules adopted from Lab One.

03
Takt adopted

Interface-feel rules adopted from Lab Two.

04
Cadence adopted

Typography rules adopted from Lab Three. 12 checks, the largest category. Weight 18 of 117 (15.4% of the score), the heaviest category.

05
Acoustics adopted

Mapping rules adopted from Lab Four. Cuelume v0.2.2 sound engine.

06
Copywriting adopted

4 copywriting checks. Spec-layer integration (DESIGN.md). Independence firewall + compliance_index_version.

07
Semantic category wired

v42 color vocabulary + v43 status colors. Reserved weight 12 now scored.

08
Editorial revision

The contract text follows the public-copy rules. No rule, value, token or check changed.

09
Alignment pass

One shell edge at every width, a 12-column grid with its 7|5 seam, material and elevation recipes as tokens, the accessibility tint tokens, and the reduced-motion tiering stated as it now behaves. Adds public tokens.

10
Text-contrast pass

Every status, grade and activation colour gains a text token that reads at 4.5 to 1 or better in both themes; light --muted-dim darkens. No check or verdict changed.

11
Engine baseline fixes

v05 accepts opt-in motion, v27 skips pages with no field, v14 and v18 become optional for external sites, and the token validator uses the 13 DTCG types. The contract is unchanged.

12
Status text and paused entrances

v44 status colors used as text meet contrast in every theme; v45 pausing motion keeps content visible. S2 and S8 stop firing on components and prose. The contract is unchanged.

13
No A beside a failing check

Any FAIL caps the score at 89.9 and a v44 FAIL at 65; v34 fails only a named AI chat surface; v06 and v22 read CSS Color 4; v42 and v43 follow aliases. The contract is unchanged.

14
Identity v1 colour system

Azure replaces the old blue as --signal, with Deep Azure for light-theme text and new action tokens. Token values only: no check, weight or verdict changed.

15
Mono face and type scale

Atkinson Hyperlegible Mono replaces Geist Mono, and the six --text-* steps of the Major Third join the contract. No check, weight or verdict changed.

16
Four checks read what renders

v26 skips fallback faces, v27 reads var() font sizes, v38 reads kbd keycaps as hints and knows Get, Set and Try, v43 counts --destructive. The contract is unchanged.

17
v27 reads its own rule

v27 stops carrying "select" from user-select into the next rule; v37 is named for the DESIGN.md format. The contract is unchanged.

18
Your own contract

POST /api/score takes your own DESIGN.md or DTCG file and answers with contract fidelity and a baseline, never blended. Requests without a contract are unchanged. The contract is unchanged.

19
Linear-time matching

Every pattern that read a page now reads each run once and returns what it returned, so scoring time grows in step with the page. The rule parser and the hosted reads are bounded. The contract is unchanged.

20
v46 reads the font shorthand

v46 takes the size from font: as well as font-size, so a sub-floor size set through the shorthand is listed, and it reads a sheet in linear time. No score moves. The contract is unchanged.

21
Pages read as served

Stylesheet links resolve against the URL that answered, compressed bodies are decoded within the read caps and a page budget, and links that write href first are read. No check, weight or ceiling moved. The contract is unchanged.